From d9d4dba3fe590a2da2e421a337c3f6e29a5465b2 Mon Sep 17 00:00:00 2001 From: fsmoke Date: Sat, 5 Oct 2019 20:37:31 +0300 Subject: [PATCH] --- Distrib/ESPressif/RTOS/1.5.0/LICENSE | 63 + Distrib/ESPressif/RTOS/1.5.0/Makefile | 411 + Distrib/ESPressif/RTOS/1.5.0/README.md | 55 + Distrib/ESPressif/RTOS/1.5.0/bin/blank.bin | 1 + .../ESPressif/RTOS/1.5.0/bin/boot_v1.6.bin | Bin 0 -> 3856 bytes .../RTOS/1.5.0/bin/esp_init_data_default.bin | Bin 0 -> 128 bytes .../RTOS/1.5.0/bin/upgrade/readme.txt | 0 .../20B-ESP8266__RTOS_SDK_API Reference.pdf | Bin 0 -> 1311276 bytes .../documents/html/airkiss_8h_source.html | 186 + .../RTOS/1.5.0/documents/html/annotated.html | 134 + .../RTOS/1.5.0/documents/html/arrowdown.png | Bin 0 -> 246 bytes .../RTOS/1.5.0/documents/html/arrowright.png | Bin 0 -> 229 bytes .../RTOS/1.5.0/documents/html/bc_s.png | Bin 0 -> 676 bytes .../RTOS/1.5.0/documents/html/bdwn.png | Bin 0 -> 147 bytes .../documents/html/c__types_8h_source.html | 209 + .../RTOS/1.5.0/documents/html/classes.html | 132 + .../RTOS/1.5.0/documents/html/closed.png | Bin 0 -> 132 bytes .../dir_5f1d40343f59d40d6b0768ec5b4dc5c7.html | 105 + .../dir_997368f752113e5dcdcd9718596161d3.html | 101 + .../dir_cf4dbf1328d2cf10d3f3933741525dc7.html | 141 + .../dir_d28a4824dc47e487b107a5db32ef43c4.html | 101 + .../dir_d44c64559bbebec7f509842c48db8b23.html | 101 + .../RTOS/1.5.0/documents/html/doc.png | Bin 0 -> 746 bytes .../RTOS/1.5.0/documents/html/doxygen.css | 1454 ++++ .../RTOS/1.5.0/documents/html/doxygen.png | Bin 0 -> 3779 bytes .../RTOS/1.5.0/documents/html/dynsections.js | 97 + .../documents/html/esp__common_8h_source.html | 145 + .../documents/html/esp__libc_8h_source.html | 185 + .../documents/html/esp__misc_8h_source.html | 185 + .../documents/html/esp__softap_8h_source.html | 219 + .../documents/html/esp__spiffs_8h_source.html | 162 + .../documents/html/esp__ssc_8h_source.html | 177 + .../documents/html/esp__sta_8h_source.html | 273 + .../documents/html/esp__system_8h_source.html | 295 + .../documents/html/esp__timer_8h_source.html | 159 + .../documents/html/esp__wifi_8h_source.html | 583 ++ .../documents/html/esp__wps_8h_source.html | 173 + .../documents/html/espconn_8h_source.html | 388 + .../documents/html/espnow_8h_source.html | 212 + .../RTOS/1.5.0/documents/html/files.html | 129 + .../1.5.0/documents/html/folderclosed.png | Bin 0 -> 616 bytes .../RTOS/1.5.0/documents/html/folderopen.png | Bin 0 -> 597 bytes .../RTOS/1.5.0/documents/html/functions.html | 451 + .../1.5.0/documents/html/functions_func.html | 107 + .../1.5.0/documents/html/functions_vars.html | 447 + .../1.5.0/documents/html/gpio_8h_source.html | 274 + .../documents/html/group__AirKiss__APIs.html | 326 + .../documents/html/group__Driver__APIs.html | 117 + .../documents/html/group__ESPNow__APIs.html | 960 ++ .../documents/html/group__Espconn__APIs.html | 1977 +++++ .../html/group__GPIO__Driver__APIs.html | 638 ++ .../html/group__HW__Timer__APIs.html | 197 + .../documents/html/group__Mesh__APIs.html | 731 ++ .../documents/html/group__Misc__APIs.html | 287 + .../html/group__PWM__Driver__APIs.html | 326 + .../html/group__SPI__Driver__APIs.html | 428 + .../documents/html/group__SSC__APIs.html | 273 + .../html/group__Smartconfig__APIs.html | 382 + .../documents/html/group__SoftAP__APIs.html | 623 ++ .../documents/html/group__Spiffs__APIs.html | 168 + .../documents/html/group__Station__APIs.html | 888 ++ .../documents/html/group__System__APIs.html | 975 +++ .../html/group__System__boot__APIs.html | 447 + .../documents/html/group__Timer__APIs.html | 230 + .../html/group__UART__Driver__APIs.html | 651 ++ .../documents/html/group__Upgrade__APIs.html | 509 ++ .../documents/html/group__WPS__APIs.html | 317 + .../documents/html/group__WiFi__APIs.html | 132 + .../html/group__WiFi__Common__APIs.html | 1219 +++ .../html/group__WiFi__Force__Sleep__APIs.html | 326 + .../group__WiFi__Rate__Control__APIs.html | 496 ++ .../html/group__WiFi__Sniffer__APIs.html | 291 + .../html/group__WiFi__User__IE__APIs.html | 277 + .../documents/html/hw__timer_8h_source.html | 145 + .../RTOS/1.5.0/documents/html/index.html | 151 + .../RTOS/1.5.0/documents/html/jquery.js | 68 + .../1.5.0/documents/html/mesh_8h_source.html | 220 + .../RTOS/1.5.0/documents/html/modules.html | 122 + .../RTOS/1.5.0/documents/html/nav_f.png | Bin 0 -> 153 bytes .../RTOS/1.5.0/documents/html/nav_g.png | Bin 0 -> 95 bytes .../RTOS/1.5.0/documents/html/nav_h.png | Bin 0 -> 98 bytes .../RTOS/1.5.0/documents/html/open.png | Bin 0 -> 123 bytes .../1.5.0/documents/html/pwm_8h_source.html | 166 + .../1.5.0/documents/html/queue_8h_source.html | 336 + .../1.5.0/documents/html/search/all_0.html | 26 + .../RTOS/1.5.0/documents/html/search/all_0.js | 8 + .../1.5.0/documents/html/search/all_1.html | 26 + .../RTOS/1.5.0/documents/html/search/all_1.js | 27 + .../1.5.0/documents/html/search/all_10.html | 26 + .../1.5.0/documents/html/search/all_10.js | 118 + .../1.5.0/documents/html/search/all_11.html | 26 + .../1.5.0/documents/html/search/all_11.js | 4 + .../1.5.0/documents/html/search/all_12.html | 26 + .../1.5.0/documents/html/search/all_12.js | 37 + .../1.5.0/documents/html/search/all_13.html | 26 + .../1.5.0/documents/html/search/all_13.js | 103 + .../1.5.0/documents/html/search/all_2.html | 26 + .../RTOS/1.5.0/documents/html/search/all_2.js | 9 + .../1.5.0/documents/html/search/all_3.html | 26 + .../RTOS/1.5.0/documents/html/search/all_3.js | 11 + .../1.5.0/documents/html/search/all_4.html | 26 + .../RTOS/1.5.0/documents/html/search/all_4.js | 13 + .../1.5.0/documents/html/search/all_5.html | 26 + .../RTOS/1.5.0/documents/html/search/all_5.js | 140 + .../1.5.0/documents/html/search/all_6.html | 26 + .../RTOS/1.5.0/documents/html/search/all_6.js | 16 + .../1.5.0/documents/html/search/all_7.html | 26 + .../RTOS/1.5.0/documents/html/search/all_7.js | 26 + .../1.5.0/documents/html/search/all_8.html | 26 + .../RTOS/1.5.0/documents/html/search/all_8.js | 7 + .../1.5.0/documents/html/search/all_9.html | 26 + .../RTOS/1.5.0/documents/html/search/all_9.js | 6 + .../1.5.0/documents/html/search/all_a.html | 26 + .../RTOS/1.5.0/documents/html/search/all_a.js | 8 + .../1.5.0/documents/html/search/all_b.html | 26 + .../RTOS/1.5.0/documents/html/search/all_b.js | 18 + .../1.5.0/documents/html/search/all_c.html | 26 + .../RTOS/1.5.0/documents/html/search/all_c.js | 7 + .../1.5.0/documents/html/search/all_d.html | 26 + .../RTOS/1.5.0/documents/html/search/all_d.js | 13 + .../1.5.0/documents/html/search/all_e.html | 26 + .../RTOS/1.5.0/documents/html/search/all_e.js | 20 + .../1.5.0/documents/html/search/all_f.html | 26 + .../RTOS/1.5.0/documents/html/search/all_f.js | 21 + .../documents/html/search/classes_0.html | 26 + .../1.5.0/documents/html/search/classes_0.js | 8 + .../documents/html/search/classes_1.html | 26 + .../1.5.0/documents/html/search/classes_1.js | 4 + .../documents/html/search/classes_2.html | 26 + .../1.5.0/documents/html/search/classes_2.js | 4 + .../documents/html/search/classes_3.html | 26 + .../1.5.0/documents/html/search/classes_3.js | 4 + .../documents/html/search/classes_4.html | 26 + .../1.5.0/documents/html/search/classes_4.js | 4 + .../documents/html/search/classes_5.html | 26 + .../1.5.0/documents/html/search/classes_5.js | 14 + .../documents/html/search/classes_6.html | 26 + .../1.5.0/documents/html/search/classes_6.js | 4 + .../documents/html/search/classes_7.html | 26 + .../1.5.0/documents/html/search/classes_7.js | 4 + .../documents/html/search/classes_8.html | 26 + .../1.5.0/documents/html/search/classes_8.js | 4 + .../documents/html/search/classes_9.html | 26 + .../1.5.0/documents/html/search/classes_9.js | 4 + .../documents/html/search/classes_a.html | 26 + .../1.5.0/documents/html/search/classes_a.js | 8 + .../documents/html/search/classes_b.html | 26 + .../1.5.0/documents/html/search/classes_b.js | 6 + .../1.5.0/documents/html/search/close.png | Bin 0 -> 273 bytes .../1.5.0/documents/html/search/enums_0.html | 26 + .../1.5.0/documents/html/search/enums_0.js | 5 + .../1.5.0/documents/html/search/enums_1.html | 26 + .../1.5.0/documents/html/search/enums_1.js | 5 + .../1.5.0/documents/html/search/enums_2.html | 26 + .../1.5.0/documents/html/search/enums_2.js | 7 + .../1.5.0/documents/html/search/enums_3.html | 26 + .../1.5.0/documents/html/search/enums_3.js | 4 + .../1.5.0/documents/html/search/enums_4.html | 26 + .../1.5.0/documents/html/search/enums_4.js | 5 + .../1.5.0/documents/html/search/enums_5.html | 26 + .../1.5.0/documents/html/search/enums_5.js | 4 + .../1.5.0/documents/html/search/enums_6.html | 26 + .../1.5.0/documents/html/search/enums_6.js | 8 + .../1.5.0/documents/html/search/enums_7.html | 26 + .../1.5.0/documents/html/search/enums_7.js | 7 + .../documents/html/search/enumvalues_0.html | 26 + .../documents/html/search/enumvalues_0.js | 16 + .../documents/html/search/enumvalues_1.html | 26 + .../documents/html/search/enumvalues_1.js | 5 + .../documents/html/search/enumvalues_2.html | 26 + .../documents/html/search/enumvalues_2.js | 31 + .../documents/html/search/enumvalues_3.html | 26 + .../documents/html/search/enumvalues_3.js | 10 + .../documents/html/search/enumvalues_4.html | 26 + .../documents/html/search/enumvalues_4.js | 11 + .../documents/html/search/enumvalues_5.html | 26 + .../documents/html/search/enumvalues_5.js | 4 + .../documents/html/search/enumvalues_6.html | 26 + .../documents/html/search/enumvalues_6.js | 6 + .../documents/html/search/enumvalues_7.html | 26 + .../documents/html/search/enumvalues_7.js | 6 + .../documents/html/search/enumvalues_8.html | 26 + .../documents/html/search/enumvalues_8.js | 10 + .../documents/html/search/enumvalues_9.html | 26 + .../documents/html/search/enumvalues_9.js | 25 + .../documents/html/search/enumvalues_a.html | 26 + .../documents/html/search/enumvalues_a.js | 8 + .../documents/html/search/functions_0.html | 26 + .../documents/html/search/functions_0.js | 6 + .../documents/html/search/functions_1.html | 26 + .../documents/html/search/functions_1.js | 74 + .../documents/html/search/functions_2.html | 26 + .../documents/html/search/functions_2.js | 13 + .../documents/html/search/functions_3.html | 26 + .../documents/html/search/functions_3.js | 6 + .../documents/html/search/functions_4.html | 26 + .../documents/html/search/functions_4.js | 9 + .../documents/html/search/functions_5.html | 26 + .../documents/html/search/functions_5.js | 9 + .../documents/html/search/functions_6.html | 26 + .../documents/html/search/functions_6.js | 58 + .../documents/html/search/functions_7.html | 26 + .../documents/html/search/functions_7.js | 18 + .../documents/html/search/functions_8.html | 26 + .../documents/html/search/functions_8.js | 88 + .../1.5.0/documents/html/search/groups_0.html | 26 + .../1.5.0/documents/html/search/groups_0.js | 4 + .../1.5.0/documents/html/search/groups_1.html | 26 + .../1.5.0/documents/html/search/groups_1.js | 4 + .../1.5.0/documents/html/search/groups_2.html | 26 + .../1.5.0/documents/html/search/groups_2.js | 4 + .../1.5.0/documents/html/search/groups_3.html | 26 + .../1.5.0/documents/html/search/groups_3.js | 4 + .../1.5.0/documents/html/search/groups_4.html | 26 + .../1.5.0/documents/html/search/groups_4.js | 4 + .../1.5.0/documents/html/search/groups_5.html | 26 + .../1.5.0/documents/html/search/groups_5.js | 4 + .../1.5.0/documents/html/search/groups_6.html | 26 + .../1.5.0/documents/html/search/groups_6.js | 4 + .../1.5.0/documents/html/search/groups_7.html | 26 + .../1.5.0/documents/html/search/groups_7.js | 4 + .../1.5.0/documents/html/search/groups_8.html | 26 + .../1.5.0/documents/html/search/groups_8.js | 5 + .../1.5.0/documents/html/search/groups_9.html | 26 + .../1.5.0/documents/html/search/groups_9.js | 4 + .../1.5.0/documents/html/search/groups_a.html | 26 + .../1.5.0/documents/html/search/groups_a.js | 4 + .../1.5.0/documents/html/search/groups_b.html | 26 + .../1.5.0/documents/html/search/groups_b.js | 4 + .../1.5.0/documents/html/search/groups_c.html | 26 + .../1.5.0/documents/html/search/groups_c.js | 12 + .../1.5.0/documents/html/search/groups_d.html | 26 + .../1.5.0/documents/html/search/groups_d.js | 6 + .../1.5.0/documents/html/search/groups_e.html | 26 + .../1.5.0/documents/html/search/groups_e.js | 5 + .../1.5.0/documents/html/search/mag_sel.png | Bin 0 -> 563 bytes .../documents/html/search/nomatches.html | 12 + .../1.5.0/documents/html/search/pages_0.html | 26 + .../1.5.0/documents/html/search/pages_0.js | 4 + .../1.5.0/documents/html/search/search.css | 271 + .../1.5.0/documents/html/search/search.js | 791 ++ .../1.5.0/documents/html/search/search_l.png | Bin 0 -> 604 bytes .../1.5.0/documents/html/search/search_m.png | Bin 0 -> 158 bytes .../1.5.0/documents/html/search/search_r.png | Bin 0 -> 612 bytes .../1.5.0/documents/html/search/searchdata.js | 39 + .../documents/html/search/typedefs_0.html | 26 + .../1.5.0/documents/html/search/typedefs_0.js | 4 + .../documents/html/search/typedefs_1.html | 26 + .../1.5.0/documents/html/search/typedefs_1.js | 8 + .../documents/html/search/typedefs_2.html | 26 + .../1.5.0/documents/html/search/typedefs_2.js | 4 + .../documents/html/search/typedefs_3.html | 26 + .../1.5.0/documents/html/search/typedefs_3.js | 4 + .../documents/html/search/typedefs_4.html | 26 + .../1.5.0/documents/html/search/typedefs_4.js | 5 + .../documents/html/search/typedefs_5.html | 26 + .../1.5.0/documents/html/search/typedefs_5.js | 6 + .../documents/html/search/typedefs_6.html | 26 + .../1.5.0/documents/html/search/typedefs_6.js | 6 + .../documents/html/search/variables_0.html | 26 + .../documents/html/search/variables_0.js | 7 + .../documents/html/search/variables_1.html | 26 + .../documents/html/search/variables_1.js | 7 + .../documents/html/search/variables_10.html | 26 + .../documents/html/search/variables_10.js | 6 + .../documents/html/search/variables_11.html | 26 + .../documents/html/search/variables_11.js | 4 + .../documents/html/search/variables_2.html | 26 + .../documents/html/search/variables_2.js | 9 + .../documents/html/search/variables_3.html | 26 + .../documents/html/search/variables_3.js | 6 + .../documents/html/search/variables_4.html | 26 + .../documents/html/search/variables_4.js | 7 + .../documents/html/search/variables_5.html | 26 + .../documents/html/search/variables_5.js | 6 + .../documents/html/search/variables_6.html | 26 + .../documents/html/search/variables_6.js | 9 + .../documents/html/search/variables_7.html | 26 + .../documents/html/search/variables_7.js | 5 + .../documents/html/search/variables_8.html | 26 + .../documents/html/search/variables_8.js | 8 + .../documents/html/search/variables_9.html | 26 + .../documents/html/search/variables_9.js | 6 + .../documents/html/search/variables_a.html | 26 + .../documents/html/search/variables_a.js | 5 + .../documents/html/search/variables_b.html | 26 + .../documents/html/search/variables_b.js | 4 + .../documents/html/search/variables_c.html | 26 + .../documents/html/search/variables_c.js | 9 + .../documents/html/search/variables_d.html | 26 + .../documents/html/search/variables_d.js | 10 + .../documents/html/search/variables_e.html | 26 + .../documents/html/search/variables_e.js | 15 + .../documents/html/search/variables_f.html | 26 + .../documents/html/search/variables_f.js | 4 + .../documents/html/smartconfig_8h_source.html | 178 + .../documents/html/spi__flash_8h_source.html | 184 + .../RTOS/1.5.0/documents/html/splitbar.png | Bin 0 -> 314 bytes ...tEvent__SoftAPMode__ProbeReqRecved__t.html | 138 + ...uctEvent__SoftAPMode__StaConnected__t.html | 138 + ...Event__SoftAPMode__StaDisconnected__t.html | 138 + ...ctEvent__StaMode__AuthMode__Change__t.html | 138 + .../structEvent__StaMode__Connected__t.html | 168 + ...structEvent__StaMode__Disconnected__t.html | 168 + .../structEvent__StaMode__Got__IP__t.html | 153 + .../structEvent__StaMode__ScanDone__t.html | 138 + .../html/structGPIO__ConfigTypeDef.html | 168 + .../documents/html/structSpiFlashChip.html | 125 + .../html/structUART__ConfigTypeDef.html | 128 + .../html/structUART__IntrConfTypeDef.html | 119 + .../documents/html/struct__esp__event.html | 138 + .../documents/html/struct__esp__tcp.html | 228 + .../documents/html/struct__esp__udp.html | 168 + .../documents/html/struct__os__timer__t.html | 128 + .../documents/html/struct__remot__info.html | 153 + .../html/structairkiss__config__t.html | 119 + .../1.5.0/documents/html/structbss__info.html | 258 + .../1.5.0/documents/html/structcmd__s.html | 122 + .../documents/html/structdhcps__lease.html | 153 + .../html/structesp__spiffs__config.html | 213 + .../1.5.0/documents/html/structespconn.html | 212 + .../1.5.0/documents/html/structip__info.html | 153 + .../documents/html/structpwm__param.html | 153 + .../1.5.0/documents/html/structrst__info.html | 144 + .../documents/html/structscan__config.html | 168 + .../documents/html/structsoftap__config.html | 228 + .../documents/html/structstation__config.html | 168 + .../documents/html/structstation__info.html | 162 + .../html/structupgrade__server__info.html | 216 + .../RTOS/1.5.0/documents/html/sync_off.png | Bin 0 -> 853 bytes .../RTOS/1.5.0/documents/html/sync_on.png | Bin 0 -> 845 bytes .../RTOS/1.5.0/documents/html/tab_a.png | Bin 0 -> 142 bytes .../RTOS/1.5.0/documents/html/tab_b.png | Bin 0 -> 169 bytes .../RTOS/1.5.0/documents/html/tab_h.png | Bin 0 -> 177 bytes .../RTOS/1.5.0/documents/html/tab_s.png | Bin 0 -> 184 bytes .../RTOS/1.5.0/documents/html/tabs.css | 60 + .../1.5.0/documents/html/uart_8h_source.html | 270 + .../documents/html/unionEvent__Info__u.html | 228 + .../documents/html/upgrade_8h_source.html | 188 + .../ESPressif/RTOS/1.5.0/driver_lib/Makefile | 124 + .../ESPressif/RTOS/1.5.0/driver_lib/README.md | 22 + .../RTOS/1.5.0/driver_lib/driver/Makefile | 43 + .../RTOS/1.5.0/driver_lib/driver/gpio.c | 213 + .../RTOS/1.5.0/driver_lib/driver/hw_timer.c | 116 + .../RTOS/1.5.0/driver_lib/driver/i2c_master.c | 319 + .../1.5.0/driver_lib/driver/spi_interface.c | 509 ++ .../RTOS/1.5.0/driver_lib/driver/uart.c | 435 + .../RTOS/1.5.0/driver_lib/include/gpio.h | 307 + .../RTOS/1.5.0/driver_lib/include/hw_timer.h | 85 + .../1.5.0/driver_lib/include/i2c_master.h | 169 + .../1.5.0/driver_lib/include/spi_interface.h | 328 + .../1.5.0/driver_lib/include/spi_register.h | 203 + .../RTOS/1.5.0/driver_lib/include/uart.h | 294 + .../RTOS/1.5.0/driver_lib/make_lib.sh | 11 + .../RTOS/1.5.0/examples/openssl_demo/Makefile | 123 + .../1.5.0/examples/openssl_demo/gen_misc.sh | 165 + .../openssl_demo/include/openssl_demo.h | 6 + .../openssl_demo/include/user_config.h | 34 + .../examples/openssl_demo/programs/Makefile | 47 + .../openssl_demo/programs/openssl_demo.c | 174 + .../1.5.0/examples/openssl_demo/user/Makefile | 44 + .../examples/openssl_demo/user/user_main.c | 108 + .../1.5.0/examples/project_template/Makefile | 132 + .../examples/project_template/gen_misc.bat | 172 + .../examples/project_template/gen_misc.sh | 176 + .../project_template/include/user_config.h | 29 + .../examples/project_template/readme.txt | 56 + .../project_template/sample_lib/Makefile | 47 + .../sample_lib/folder1/Makefile | 44 + .../sample_lib/folder1/file1.c | 0 .../sample_lib/folder2/Makefile | 44 + .../sample_lib/folder2/file2.c | 0 .../examples/project_template/user/Makefile | 44 + .../project_template/user/user_main.c | 81 + .../RTOS/1.5.0/examples/smart_config/Makefile | 122 + .../1.5.0/examples/smart_config/airkiss.txt | 8 + .../1.5.0/examples/smart_config/gen_misc.bat | 172 + .../1.5.0/examples/smart_config/gen_misc.sh | 176 + .../smart_config/include/user_config.h | 29 + .../smart_config/model two-dimension code.rar | Bin 0 -> 15386 bytes .../1.5.0/examples/smart_config/readme.txt | 40 + .../1.5.0/examples/smart_config/user/Makefile | 44 + .../examples/smart_config/user/user_main.c | 267 + .../RTOS/1.5.0/examples/spiffs_test/Makefile | 121 + .../1.5.0/examples/spiffs_test/gen_misc.bat | 172 + .../1.5.0/examples/spiffs_test/gen_misc.sh | 176 + .../spiffs_test/include/spiffs_test_params.h | 22 + .../1.5.0/examples/spiffs_test/user/Makefile | 44 + .../spiffs_test/user/test_bugreports.c | 331 + .../examples/spiffs_test/user/test_check.c | 419 + .../examples/spiffs_test/user/test_dev.c | 122 + .../examples/spiffs_test/user/test_hydrogen.c | 1471 ++++ .../examples/spiffs_test/user/test_main.c | 103 + .../examples/spiffs_test/user/test_spiffs.c | 907 ++ .../examples/spiffs_test/user/test_spiffs.h | 94 + .../examples/spiffs_test/user/testrunner.c | 215 + .../examples/spiffs_test/user/testrunner.h | 151 + .../examples/spiffs_test/user/testsuites.c | 15 + .../1.5.0/examples/websocket_demo/Makefile | 124 + .../examples/websocket_demo/gen_misc.bat | 172 + .../1.5.0/examples/websocket_demo/gen_misc.sh | 176 + .../examples/websocket_demo/user/Makefile | 44 + .../examples/websocket_demo/user/user_main.c | 84 + .../websocket_demo/websocket/Makefile | 44 + .../websocket_demo/websocket/websocket.c | 716 ++ .../wifi_station_machine_demo/Makefile | 132 + .../wifi_station_machine_demo/gen_misc.bat | 172 + .../wifi_station_machine_demo/gen_misc.sh | 176 + .../include/user_config.h | 32 + .../include/wifi_state_machine.h | 50 + .../wifi_station_machine_demo/readme.txt | 56 + .../wifi_station_machine_demo/user/Makefile | 51 + .../user/user_main.c | 111 + .../user/wifi_state_machine.c | 247 + .../RTOS/1.5.0/examples/wps_demo/Makefile | 132 + .../RTOS/1.5.0/examples/wps_demo/gen_misc.bat | 172 + .../RTOS/1.5.0/examples/wps_demo/gen_misc.sh | 176 + .../examples/wps_demo/include/user_config.h | 29 + .../RTOS/1.5.0/examples/wps_demo/readme.txt | 56 + .../1.5.0/examples/wps_demo/user/Makefile | 51 + .../1.5.0/examples/wps_demo/user/user_main.c | 99 + .../1.5.0/extra_include/xtensa/cacheasm.h | 807 ++ .../1.5.0/extra_include/xtensa/cacheattrasm.h | 436 + .../extra_include/xtensa/config/core-isa.h | 459 + .../extra_include/xtensa/config/core-matmap.h | 316 + .../1.5.0/extra_include/xtensa/config/core.h | 1328 +++ .../1.5.0/extra_include/xtensa/config/defs.h | 37 + .../extra_include/xtensa/config/specreg.h | 80 + .../extra_include/xtensa/config/system.h | 252 + .../extra_include/xtensa/config/tie-asm.h | 77 + .../1.5.0/extra_include/xtensa/config/tie.h | 119 + .../RTOS/1.5.0/extra_include/xtensa/coreasm.h | 914 ++ .../1.5.0/extra_include/xtensa/corebits.h | 164 + .../RTOS/1.5.0/extra_include/xtensa/hal.h | 925 ++ .../RTOS/1.5.0/extra_include/xtensa/sim.h | 60 + .../extra_include/xtensa/simcall-errno.h | 139 + .../extra_include/xtensa/simcall-fcntl.h | 21 + .../RTOS/1.5.0/extra_include/xtensa/simcall.h | 188 + .../RTOS/1.5.0/extra_include/xtensa/specreg.h | 138 + .../1.5.0/extra_include/xtensa/tie/xt_MUL32.h | 24 + .../1.5.0/extra_include/xtensa/tie/xt_core.h | 254 + .../1.5.0/extra_include/xtensa/tie/xt_debug.h | 93 + .../extra_include/xtensa/tie/xt_density.h | 57 + .../extra_include/xtensa/tie/xt_exceptions.h | 46 + .../xtensa/tie/xt_externalregisters.h | 44 + .../extra_include/xtensa/tie/xt_interrupt.h | 55 + .../1.5.0/extra_include/xtensa/tie/xt_misc.h | 45 + .../1.5.0/extra_include/xtensa/tie/xt_mmu.h | 61 + .../1.5.0/extra_include/xtensa/tie/xt_mul.h | 47 + .../1.5.0/extra_include/xtensa/tie/xt_timer.h | 53 + .../1.5.0/extra_include/xtensa/tie/xt_trace.h | 43 + .../xtensa/xtensa-libdb-macros.h | 165 + .../1.5.0/extra_include/xtensa/xtensa-xer.h | 149 + .../extra_include/xtensa/xtruntime-frames.h | 160 + .../1.5.0/extra_include/xtensa/xtruntime.h | 184 + .../RTOS/1.5.0/include/espressif/airkiss.h | 150 + .../RTOS/1.5.0/include/espressif/c_types.h | 114 + .../include/espressif/esp8266/eagle_soc.h | 126 + .../1.5.0/include/espressif/esp8266/esp8266.h | 37 + .../1.5.0/include/espressif/esp8266/ets_sys.h | 63 + .../include/espressif/esp8266/gpio_register.h | 338 + .../espressif/esp8266/pin_mux_register.h | 152 + .../include/espressif/esp8266/spi_register.h | 193 + .../espressif/esp8266/timer_register.h | 93 + .../include/espressif/esp8266/uart_register.h | 154 + .../RTOS/1.5.0/include/espressif/esp_common.h | 111 + .../RTOS/1.5.0/include/espressif/esp_libc.h | 137 + .../RTOS/1.5.0/include/espressif/esp_misc.h | 108 + .../RTOS/1.5.0/include/espressif/esp_softap.h | 290 + .../RTOS/1.5.0/include/espressif/esp_spiffs.h | 84 + .../RTOS/1.5.0/include/espressif/esp_ssc.h | 125 + .../RTOS/1.5.0/include/espressif/esp_sta.h | 393 + .../RTOS/1.5.0/include/espressif/esp_system.h | 586 ++ .../RTOS/1.5.0/include/espressif/esp_timer.h | 101 + .../RTOS/1.5.0/include/espressif/esp_wifi.h | 989 +++ .../RTOS/1.5.0/include/espressif/esp_wps.h | 139 + .../RTOS/1.5.0/include/espressif/espconn.h | 704 ++ .../RTOS/1.5.0/include/espressif/espnow.h | 351 + .../RTOS/1.5.0/include/espressif/mesh.h | 274 + .../RTOS/1.5.0/include/espressif/pwm.h | 142 + .../RTOS/1.5.0/include/espressif/queue.h | 236 + .../1.5.0/include/espressif/smartconfig.h | 165 + .../RTOS/1.5.0/include/espressif/spi_flash.h | 165 + .../RTOS/1.5.0/include/espressif/upgrade.h | 149 + .../RTOS/1.5.0/include/freertos/FreeRTOS.h | 612 ++ .../1.5.0/include/freertos/FreeRTOSConfig.h | 144 + .../RTOS/1.5.0/include/freertos/StackMacros.h | 179 + .../RTOS/1.5.0/include/freertos/croutine.h | 757 ++ .../RTOS/1.5.0/include/freertos/list.h | 378 + .../1.5.0/include/freertos/mpu_wrappers.h | 152 + .../RTOS/1.5.0/include/freertos/portable.h | 408 + .../RTOS/1.5.0/include/freertos/portmacro.h | 199 + .../RTOS/1.5.0/include/freertos/projdefs.h | 88 + .../RTOS/1.5.0/include/freertos/queue.h | 1667 ++++ .../RTOS/1.5.0/include/freertos/semphr.h | 785 ++ .../RTOS/1.5.0/include/freertos/task.h | 1521 ++++ .../RTOS/1.5.0/include/freertos/timers.h | 959 ++ .../1.5.0/include/freertos/xtensa_context.h | 278 + .../RTOS/1.5.0/include/freertos/xtensa_rtos.h | 175 + .../1.5.0/include/freertos/xtensa_timer.h | 146 + .../ESPressif/RTOS/1.5.0/include/json/cJSON.h | 149 + .../RTOS/1.5.0/include/lwip/apps/sntp.h | 71 + .../RTOS/1.5.0/include/lwip/apps/sntp_opts.h | 159 + .../RTOS/1.5.0/include/lwip/apps/sntp_time.h | 61 + .../RTOS/1.5.0/include/lwip/apps/time.h | 57 + .../RTOS/1.5.0/include/lwip/arch/cc.h | 93 + .../RTOS/1.5.0/include/lwip/arch/perf.h | 40 + .../RTOS/1.5.0/include/lwip/arch/sys_arch.h | 54 + .../1.5.0/include/lwip/ipv4/lwip/autoip.h | 118 + .../RTOS/1.5.0/include/lwip/ipv4/lwip/icmp.h | 125 + .../RTOS/1.5.0/include/lwip/ipv4/lwip/igmp.h | 106 + .../RTOS/1.5.0/include/lwip/ipv4/lwip/inet.h | 112 + .../RTOS/1.5.0/include/lwip/ipv4/lwip/ip4.h | 146 + .../1.5.0/include/lwip/ipv4/lwip/ip4_addr.h | 244 + .../1.5.0/include/lwip/ipv4/lwip/ip_frag.h | 91 + .../RTOS/1.5.0/include/lwip/ipv6/lwip/dhcp6.h | 58 + .../1.5.0/include/lwip/ipv6/lwip/ethip6.h | 68 + .../RTOS/1.5.0/include/lwip/ipv6/lwip/icmp6.h | 152 + .../RTOS/1.5.0/include/lwip/ipv6/lwip/inet6.h | 92 + .../RTOS/1.5.0/include/lwip/ipv6/lwip/ip6.h | 196 + .../1.5.0/include/lwip/ipv6/lwip/ip6_addr.h | 286 + .../1.5.0/include/lwip/ipv6/lwip/ip6_frag.h | 102 + .../RTOS/1.5.0/include/lwip/ipv6/lwip/mld6.h | 118 + .../RTOS/1.5.0/include/lwip/ipv6/lwip/nd6.h | 369 + .../RTOS/1.5.0/include/lwip/lwip/api.h | 440 + .../RTOS/1.5.0/include/lwip/lwip/api_msg.h | 177 + .../RTOS/1.5.0/include/lwip/lwip/arch.h | 217 + .../RTOS/1.5.0/include/lwip/lwip/debug.h | 99 + .../RTOS/1.5.0/include/lwip/lwip/def.h | 127 + .../RTOS/1.5.0/include/lwip/lwip/dhcp.h | 254 + .../RTOS/1.5.0/include/lwip/lwip/dhcpserver.h | 102 + .../RTOS/1.5.0/include/lwip/lwip/dns.h | 125 + .../RTOS/1.5.0/include/lwip/lwip/err.h | 101 + .../1.5.0/include/lwip/lwip/inet_chksum.h | 112 + .../RTOS/1.5.0/include/lwip/lwip/init.h | 72 + .../RTOS/1.5.0/include/lwip/lwip/ip.h | 254 + .../RTOS/1.5.0/include/lwip/lwip/ip_addr.h | 130 + .../RTOS/1.5.0/include/lwip/lwip/mem.h | 159 + .../RTOS/1.5.0/include/lwip/lwip/memp.h | 116 + .../RTOS/1.5.0/include/lwip/lwip/memp_std.h | 135 + .../lwip/lwip/multi-threads/sockets_mt.h | 98 + .../RTOS/1.5.0/include/lwip/lwip/netbuf.h | 112 + .../RTOS/1.5.0/include/lwip/lwip/netdb.h | 124 + .../RTOS/1.5.0/include/lwip/lwip/netif.h | 393 + .../RTOS/1.5.0/include/lwip/lwip/netifapi.h | 108 + .../RTOS/1.5.0/include/lwip/lwip/opt.h | 2422 ++++++ .../RTOS/1.5.0/include/lwip/lwip/pbuf.h | 192 + .../RTOS/1.5.0/include/lwip/lwip/raw.h | 131 + .../RTOS/1.5.0/include/lwip/lwip/sio.h | 141 + .../RTOS/1.5.0/include/lwip/lwip/snmp.h | 367 + .../RTOS/1.5.0/include/lwip/lwip/snmp_asn1.h | 101 + .../RTOS/1.5.0/include/lwip/lwip/snmp_msg.h | 315 + .../1.5.0/include/lwip/lwip/snmp_structs.h | 268 + .../RTOS/1.5.0/include/lwip/lwip/sockets.h | 463 + .../RTOS/1.5.0/include/lwip/lwip/stats.h | 347 + .../RTOS/1.5.0/include/lwip/lwip/sys.h | 336 + .../RTOS/1.5.0/include/lwip/lwip/tcp.h | 397 + .../RTOS/1.5.0/include/lwip/lwip/tcp_impl.h | 508 ++ .../RTOS/1.5.0/include/lwip/lwip/tcpip.h | 181 + .../RTOS/1.5.0/include/lwip/lwip/timers.h | 100 + .../RTOS/1.5.0/include/lwip/lwip/udp.h | 215 + .../RTOS/1.5.0/include/lwip/lwipopts.h | 502 ++ .../RTOS/1.5.0/include/lwip/netif/etharp.h | 224 + .../RTOS/1.5.0/include/lwip/netif/if_llc.h | 173 + .../RTOS/1.5.0/include/lwip/netif/ppp_oe.h | 190 + .../RTOS/1.5.0/include/lwip/netif/slipif.h | 81 + .../1.5.0/include/lwip/netif/wlan_lwip_if.h | 20 + .../RTOS/1.5.0/include/lwip/posix/netdb.h | 33 + .../1.5.0/include/lwip/posix/sys/socket.h | 33 + .../RTOS/1.5.0/include/mbedtls/aes.h | 297 + .../RTOS/1.5.0/include/mbedtls/aesni.h | 111 + .../RTOS/1.5.0/include/mbedtls/arc4.h | 113 + .../RTOS/1.5.0/include/mbedtls/asn1.h | 342 + .../RTOS/1.5.0/include/mbedtls/asn1write.h | 239 + .../RTOS/1.5.0/include/mbedtls/base64.h | 88 + .../RTOS/1.5.0/include/mbedtls/bignum.h | 717 ++ .../RTOS/1.5.0/include/mbedtls/blowfish.h | 203 + .../RTOS/1.5.0/include/mbedtls/bn_mul.h | 876 ++ .../RTOS/1.5.0/include/mbedtls/camellia.h | 235 + .../RTOS/1.5.0/include/mbedtls/ccm.h | 141 + .../RTOS/1.5.0/include/mbedtls/certs.h | 103 + .../RTOS/1.5.0/include/mbedtls/check_config.h | 540 ++ .../RTOS/1.5.0/include/mbedtls/cipher.h | 698 ++ .../1.5.0/include/mbedtls/cipher_internal.h | 109 + .../RTOS/1.5.0/include/mbedtls/compat-1.3.h | 2634 ++++++ .../RTOS/1.5.0/include/mbedtls/config.h | 2511 ++++++ .../RTOS/1.5.0/include/mbedtls/config_esp.h | 2524 ++++++ .../RTOS/1.5.0/include/mbedtls/ctr_drbg.h | 290 + .../RTOS/1.5.0/include/mbedtls/debug.h | 125 + .../RTOS/1.5.0/include/mbedtls/des.h | 306 + .../RTOS/1.5.0/include/mbedtls/dhm.h | 305 + .../RTOS/1.5.0/include/mbedtls/ecdh.h | 214 + .../RTOS/1.5.0/include/mbedtls/ecdsa.h | 248 + .../RTOS/1.5.0/include/mbedtls/ecjpake.h | 238 + .../RTOS/1.5.0/include/mbedtls/ecp.h | 669 ++ .../RTOS/1.5.0/include/mbedtls/entropy.h | 252 + .../RTOS/1.5.0/include/mbedtls/entropy_poll.h | 89 + .../RTOS/1.5.0/include/mbedtls/error.h | 107 + .../RTOS/1.5.0/include/mbedtls/gcm.h | 220 + .../RTOS/1.5.0/include/mbedtls/havege.h | 74 + .../RTOS/1.5.0/include/mbedtls/hmac_drbg.h | 299 + .../ESPressif/RTOS/1.5.0/include/mbedtls/md.h | 353 + .../RTOS/1.5.0/include/mbedtls/md2.h | 136 + .../RTOS/1.5.0/include/mbedtls/md4.h | 136 + .../RTOS/1.5.0/include/mbedtls/md5.h | 136 + .../RTOS/1.5.0/include/mbedtls/md_internal.h | 114 + .../include/mbedtls/memory_buffer_alloc.h | 146 + .../RTOS/1.5.0/include/mbedtls/net.h | 225 + .../RTOS/1.5.0/include/mbedtls/oid.h | 570 ++ .../RTOS/1.5.0/include/mbedtls/padlock.h | 107 + .../RTOS/1.5.0/include/mbedtls/pem.h | 129 + .../ESPressif/RTOS/1.5.0/include/mbedtls/pk.h | 615 ++ .../RTOS/1.5.0/include/mbedtls/pk_internal.h | 114 + .../RTOS/1.5.0/include/mbedtls/pkcs11.h | 173 + .../RTOS/1.5.0/include/mbedtls/pkcs12.h | 119 + .../RTOS/1.5.0/include/mbedtls/pkcs5.h | 94 + .../RTOS/1.5.0/include/mbedtls/platform.h | 214 + .../RTOS/1.5.0/include/mbedtls/ripemd160.h | 138 + .../RTOS/1.5.0/include/mbedtls/rsa.h | 652 ++ .../RTOS/1.5.0/include/mbedtls/sha1.h | 136 + .../RTOS/1.5.0/include/mbedtls/sha256.h | 141 + .../RTOS/1.5.0/include/mbedtls/sha512.h | 141 + .../RTOS/1.5.0/include/mbedtls/ssl.h | 2393 +++++ .../RTOS/1.5.0/include/mbedtls/ssl_cache.h | 143 + .../1.5.0/include/mbedtls/ssl_ciphersuites.h | 321 + .../RTOS/1.5.0/include/mbedtls/ssl_cookie.h | 108 + .../RTOS/1.5.0/include/mbedtls/ssl_internal.h | 499 ++ .../RTOS/1.5.0/include/mbedtls/ssl_ticket.h | 135 + .../RTOS/1.5.0/include/mbedtls/threading.h | 104 + .../RTOS/1.5.0/include/mbedtls/timing.h | 141 + .../RTOS/1.5.0/include/mbedtls/version.h | 111 + .../RTOS/1.5.0/include/mbedtls/x509.h | 331 + .../RTOS/1.5.0/include/mbedtls/x509_crl.h | 173 + .../RTOS/1.5.0/include/mbedtls/x509_crt.h | 645 ++ .../RTOS/1.5.0/include/mbedtls/x509_csr.h | 292 + .../RTOS/1.5.0/include/mbedtls/xtea.h | 139 + .../RTOS/1.5.0/include/nopoll/nopoll.h | 135 + .../RTOS/1.5.0/include/nopoll/nopoll_config.h | 67 + .../RTOS/1.5.0/include/nopoll/nopoll_conn.h | 198 + .../1.5.0/include/nopoll/nopoll_conn_opts.h | 73 + .../RTOS/1.5.0/include/nopoll/nopoll_ctx.h | 106 + .../RTOS/1.5.0/include/nopoll/nopoll_decl.h | 469 + .../1.5.0/include/nopoll/nopoll_handlers.h | 329 + .../RTOS/1.5.0/include/nopoll/nopoll_io.h | 52 + .../1.5.0/include/nopoll/nopoll_listener.h | 80 + .../RTOS/1.5.0/include/nopoll/nopoll_log.h | 113 + .../RTOS/1.5.0/include/nopoll/nopoll_loop.h | 52 + .../RTOS/1.5.0/include/nopoll/nopoll_msg.h | 68 + .../1.5.0/include/nopoll/nopoll_private.h | 386 + .../RTOS/1.5.0/include/nopoll/nopoll_win32.h | 66 + .../1.5.0/include/openssl/internal/ssl3.h | 44 + .../1.5.0/include/openssl/internal/ssl_cert.h | 55 + .../1.5.0/include/openssl/internal/ssl_code.h | 124 + .../1.5.0/include/openssl/internal/ssl_dbg.h | 191 + .../1.5.0/include/openssl/internal/ssl_lib.h | 28 + .../include/openssl/internal/ssl_methods.h | 121 + .../1.5.0/include/openssl/internal/ssl_pkey.h | 86 + .../include/openssl/internal/ssl_stack.h | 52 + .../include/openssl/internal/ssl_types.h | 288 + .../1.5.0/include/openssl/internal/ssl_x509.h | 108 + .../1.5.0/include/openssl/internal/tls1.h | 55 + .../1.5.0/include/openssl/internal/x509_vfy.h | 111 + .../RTOS/1.5.0/include/openssl/openssl/ssl.h | 1755 ++++ .../1.5.0/include/openssl/platform/ssl_opt.h | 89 + .../1.5.0/include/openssl/platform/ssl_pm.h | 59 + .../1.5.0/include/openssl/platform/ssl_port.h | 81 + .../RTOS/1.5.0/include/spiffs/spiffs.h | 560 ++ .../RTOS/1.5.0/include/spiffs/spiffs_config.h | 218 + .../1.5.0/include/spiffs/spiffs_nucleus.h | 718 ++ .../RTOS/1.5.0/include/ssl/ssl_bigint.h | 99 + .../RTOS/1.5.0/include/ssl/ssl_bigint_impl.h | 131 + .../RTOS/1.5.0/include/ssl/ssl_compat-1.0.h | 100 + .../RTOS/1.5.0/include/ssl/ssl_config.h | 147 + .../RTOS/1.5.0/include/ssl/ssl_crypto.h | 266 + .../RTOS/1.5.0/include/ssl/ssl_crypto_misc.h | 177 + .../RTOS/1.5.0/include/ssl/ssl_os_port.h | 146 + .../RTOS/1.5.0/include/ssl/ssl_platform.h | 53 + .../RTOS/1.5.0/include/ssl/ssl_ssl.h | 500 ++ .../RTOS/1.5.0/include/ssl/ssl_tls1.h | 313 + .../RTOS/1.5.0/include/ssl/ssl_version.h | 1 + .../RTOS/1.5.0/ld/eagle.app.v6.common.ld | 219 + .../ESPressif/RTOS/1.5.0/ld/eagle.app.v6.ld | 32 + .../1.5.0/ld/eagle.app.v6.new.1024.app1.ld | 23 + .../1.5.0/ld/eagle.app.v6.new.1024.app2.ld | 23 + .../RTOS/1.5.0/ld/eagle.app.v6.new.2048.ld | 25 + .../1.5.0/ld/eagle.app.v6.new.512.app1.ld | 23 + .../1.5.0/ld/eagle.app.v6.new.512.app2.ld | 23 + .../RTOS/1.5.0/ld/eagle.rom.addr.v6.ld | 58 + Distrib/ESPressif/RTOS/1.5.0/lib/libairkiss.a | Bin 0 -> 11298 bytes Distrib/ESPressif/RTOS/1.5.0/lib/libcirom.a | Bin 0 -> 5159208 bytes Distrib/ESPressif/RTOS/1.5.0/lib/libcrypto.a | Bin 0 -> 119932 bytes Distrib/ESPressif/RTOS/1.5.0/lib/libdriver.a | Bin 0 -> 23320 bytes Distrib/ESPressif/RTOS/1.5.0/lib/libespconn.a | Bin 0 -> 119444 bytes Distrib/ESPressif/RTOS/1.5.0/lib/libespnow.a | Bin 0 -> 45608 bytes .../ESPressif/RTOS/1.5.0/lib/libfreertos.a | Bin 0 -> 82114 bytes Distrib/ESPressif/RTOS/1.5.0/lib/libgcc.a | Bin 0 -> 600904 bytes Distrib/ESPressif/RTOS/1.5.0/lib/libjson.a | Bin 0 -> 51898 bytes Distrib/ESPressif/RTOS/1.5.0/lib/liblwip.a | Bin 0 -> 516372 bytes Distrib/ESPressif/RTOS/1.5.0/lib/libmain.a | Bin 0 -> 199374 bytes Distrib/ESPressif/RTOS/1.5.0/lib/libmbedtls.a | Bin 0 -> 597746 bytes Distrib/ESPressif/RTOS/1.5.0/lib/libmesh.a | Bin 0 -> 179444 bytes Distrib/ESPressif/RTOS/1.5.0/lib/libminic.a | Bin 0 -> 22322 bytes Distrib/ESPressif/RTOS/1.5.0/lib/libmirom.a | Bin 0 -> 2255754 bytes .../ESPressif/RTOS/1.5.0/lib/libnet80211.a | Bin 0 -> 264628 bytes Distrib/ESPressif/RTOS/1.5.0/lib/libnopoll.a | Bin 0 -> 255842 bytes Distrib/ESPressif/RTOS/1.5.0/lib/libopenssl.a | Bin 0 -> 98086 bytes Distrib/ESPressif/RTOS/1.5.0/lib/libphy.a | Bin 0 -> 200966 bytes Distrib/ESPressif/RTOS/1.5.0/lib/libpp.a | Bin 0 -> 264046 bytes Distrib/ESPressif/RTOS/1.5.0/lib/libpwm.a | Bin 0 -> 10558 bytes .../ESPressif/RTOS/1.5.0/lib/libsmartconfig.a | Bin 0 -> 115704 bytes Distrib/ESPressif/RTOS/1.5.0/lib/libspiffs.a | Bin 0 -> 136952 bytes Distrib/ESPressif/RTOS/1.5.0/lib/libssc.a | Bin 0 -> 39138 bytes Distrib/ESPressif/RTOS/1.5.0/lib/libssl.a | Bin 0 -> 224262 bytes Distrib/ESPressif/RTOS/1.5.0/lib/libwpa.a | Bin 0 -> 163858 bytes Distrib/ESPressif/RTOS/1.5.0/lib/libwps.a | Bin 0 -> 341366 bytes .../ESPressif/RTOS/1.5.0/third_party/Makefile | 120 + .../RTOS/1.5.0/third_party/freertos/Makefile | 50 + .../1.5.0/third_party/freertos/croutine.c | 393 + .../RTOS/1.5.0/third_party/freertos/heap_4.c | 707 ++ .../RTOS/1.5.0/third_party/freertos/list.c | 208 + .../RTOS/1.5.0/third_party/freertos/port.c | 401 + .../RTOS/1.5.0/third_party/freertos/queue.c | 2130 +++++ .../1.5.0/third_party/freertos/readme.txt | 17 + .../RTOS/1.5.0/third_party/freertos/tasks.c | 3000 +++++++ .../RTOS/1.5.0/third_party/freertos/timers.c | 718 ++ .../RTOS/1.5.0/third_party/json/Makefile | 46 + .../RTOS/1.5.0/third_party/json/cJSON.c | 750 ++ .../RTOS/1.5.0/third_party/lwip/FILES | 13 + .../RTOS/1.5.0/third_party/lwip/Makefile | 56 + .../RTOS/1.5.0/third_party/lwip/api/Makefile | 46 + .../RTOS/1.5.0/third_party/lwip/api/api_lib.c | 802 ++ .../RTOS/1.5.0/third_party/lwip/api/api_msg.c | 1712 ++++ .../RTOS/1.5.0/third_party/lwip/api/err.c | 75 + .../lwip/api/multi-threads/sockets_mt.c | 829 ++ .../RTOS/1.5.0/third_party/lwip/api/netbuf.c | 249 + .../RTOS/1.5.0/third_party/lwip/api/netdb.c | 357 + .../1.5.0/third_party/lwip/api/netifapi.c | 160 + .../RTOS/1.5.0/third_party/lwip/api/sockets.c | 2711 ++++++ .../RTOS/1.5.0/third_party/lwip/api/tcpip.c | 527 ++ .../RTOS/1.5.0/third_party/lwip/apps/Makefile | 46 + .../RTOS/1.5.0/third_party/lwip/apps/sntp.c | 717 ++ .../1.5.0/third_party/lwip/apps/sntp_time.c | 326 + .../RTOS/1.5.0/third_party/lwip/apps/time.c | 121 + .../RTOS/1.5.0/third_party/lwip/arch/Makefile | 46 + .../1.5.0/third_party/lwip/arch/sys_arch.c | 426 + .../RTOS/1.5.0/third_party/lwip/core/Makefile | 46 + .../RTOS/1.5.0/third_party/lwip/core/def.c | 108 + .../RTOS/1.5.0/third_party/lwip/core/dhcp.c | 2010 +++++ .../1.5.0/third_party/lwip/core/dhcpserver.c | 1128 +++ .../RTOS/1.5.0/third_party/lwip/core/dns.c | 1007 +++ .../1.5.0/third_party/lwip/core/inet_chksum.c | 545 ++ .../RTOS/1.5.0/third_party/lwip/core/init.c | 349 + .../1.5.0/third_party/lwip/core/ipv4/Makefile | 46 + .../1.5.0/third_party/lwip/core/ipv4/autoip.c | 532 ++ .../1.5.0/third_party/lwip/core/ipv4/icmp.c | 342 + .../1.5.0/third_party/lwip/core/ipv4/igmp.c | 809 ++ .../1.5.0/third_party/lwip/core/ipv4/ip4.c | 926 ++ .../third_party/lwip/core/ipv4/ip4_addr.c | 434 + .../third_party/lwip/core/ipv4/ip_frag.c | 867 ++ .../1.5.0/third_party/lwip/core/ipv6/Makefile | 46 + .../1.5.0/third_party/lwip/core/ipv6/README | 1 + .../1.5.0/third_party/lwip/core/ipv6/dhcp6.c | 50 + .../1.5.0/third_party/lwip/core/ipv6/ethip6.c | 193 + .../1.5.0/third_party/lwip/core/ipv6/icmp6.c | 342 + .../1.5.0/third_party/lwip/core/ipv6/inet6.c | 51 + .../1.5.0/third_party/lwip/core/ipv6/ip6.c | 1031 +++ .../third_party/lwip/core/ipv6/ip6_addr.c | 251 + .../third_party/lwip/core/ipv6/ip6_frag.c | 702 ++ .../1.5.0/third_party/lwip/core/ipv6/mld6.c | 584 ++ .../1.5.0/third_party/lwip/core/ipv6/nd6.c | 1789 ++++ .../RTOS/1.5.0/third_party/lwip/core/mem.c | 664 ++ .../RTOS/1.5.0/third_party/lwip/core/memp.c | 489 ++ .../RTOS/1.5.0/third_party/lwip/core/netif.c | 942 ++ .../RTOS/1.5.0/third_party/lwip/core/pbuf.c | 1242 +++ .../RTOS/1.5.0/third_party/lwip/core/raw.c | 426 + .../third_party/lwip/core/snmp/asn1_dec.c | 657 ++ .../third_party/lwip/core/snmp/asn1_enc.c | 611 ++ .../1.5.0/third_party/lwip/core/snmp/mib2.c | 4146 +++++++++ .../third_party/lwip/core/snmp/mib_structs.c | 1178 +++ .../1.5.0/third_party/lwip/core/snmp/msg_in.c | 1457 ++++ .../third_party/lwip/core/snmp/msg_out.c | 682 ++ .../RTOS/1.5.0/third_party/lwip/core/stats.c | 186 + .../RTOS/1.5.0/third_party/lwip/core/sys.c | 68 + .../RTOS/1.5.0/third_party/lwip/core/tcp.c | 1945 +++++ .../RTOS/1.5.0/third_party/lwip/core/tcp_in.c | 1669 ++++ .../1.5.0/third_party/lwip/core/tcp_out.c | 1504 ++++ .../RTOS/1.5.0/third_party/lwip/core/timers.c | 561 ++ .../RTOS/1.5.0/third_party/lwip/core/udp.c | 1164 +++ .../RTOS/1.5.0/third_party/lwip/netif/FILES | 29 + .../1.5.0/third_party/lwip/netif/Makefile | 46 + .../1.5.0/third_party/lwip/netif/etharp.c | 1433 +++ .../1.5.0/third_party/lwip/netif/ethernetif.c | 274 + .../1.5.0/third_party/lwip/netif/ppp/auth.c | 1334 +++ .../1.5.0/third_party/lwip/netif/ppp/auth.h | 111 + .../1.5.0/third_party/lwip/netif/ppp/chap.c | 908 ++ .../1.5.0/third_party/lwip/netif/ppp/chap.h | 150 + .../1.5.0/third_party/lwip/netif/ppp/chpms.c | 396 + .../1.5.0/third_party/lwip/netif/ppp/chpms.h | 64 + .../1.5.0/third_party/lwip/netif/ppp/fsm.c | 890 ++ .../1.5.0/third_party/lwip/netif/ppp/fsm.h | 157 + .../1.5.0/third_party/lwip/netif/ppp/ipcp.c | 1411 +++ .../1.5.0/third_party/lwip/netif/ppp/ipcp.h | 106 + .../1.5.0/third_party/lwip/netif/ppp/lcp.c | 2066 +++++ .../1.5.0/third_party/lwip/netif/ppp/lcp.h | 151 + .../1.5.0/third_party/lwip/netif/ppp/magic.c | 80 + .../1.5.0/third_party/lwip/netif/ppp/magic.h | 63 + .../1.5.0/third_party/lwip/netif/ppp/md5.c | 320 + .../1.5.0/third_party/lwip/netif/ppp/md5.h | 55 + .../1.5.0/third_party/lwip/netif/ppp/pap.c | 628 ++ .../1.5.0/third_party/lwip/netif/ppp/pap.h | 118 + .../1.5.0/third_party/lwip/netif/ppp/ppp.c | 2052 +++++ .../1.5.0/third_party/lwip/netif/ppp/ppp.h | 201 + .../third_party/lwip/netif/ppp/ppp_impl.h | 363 + .../1.5.0/third_party/lwip/netif/ppp/ppp_oe.c | 1132 +++ .../third_party/lwip/netif/ppp/pppdebug.h | 73 + .../1.5.0/third_party/lwip/netif/ppp/randm.c | 249 + .../1.5.0/third_party/lwip/netif/ppp/randm.h | 81 + .../third_party/lwip/netif/ppp/readme.txt | 21 + .../1.5.0/third_party/lwip/netif/ppp/vj.c | 652 ++ .../1.5.0/third_party/lwip/netif/ppp/vj.h | 156 + .../1.5.0/third_party/lwip/netif/slipif.c | 546 ++ .../RTOS/1.5.0/third_party/make_all_lib.sh | 25 + .../RTOS/1.5.0/third_party/make_lib.sh | 23 + .../RTOS/1.5.0/third_party/mbedtls/Makefile | 48 + .../third_party/mbedtls/library/Makefile | 46 + .../1.5.0/third_party/mbedtls/library/aes.c | 1491 ++++ .../1.5.0/third_party/mbedtls/library/aesni.c | 464 + .../1.5.0/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 +++ .../1.5.0/third_party/mbedtls/library/ccm.c | 464 + .../1.5.0/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 ++ .../1.5.0/third_party/mbedtls/library/debug.c | 367 + .../1.5.0/third_party/mbedtls/library/des.c | 1061 +++ .../1.5.0/third_party/mbedtls/library/dhm.c | 624 ++ .../1.5.0/third_party/mbedtls/library/ecdh.c | 264 + .../1.5.0/third_party/mbedtls/library/ecdsa.c | 448 + .../third_party/mbedtls/library/ecjpake.c | 1103 +++ .../1.5.0/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 + .../1.5.0/third_party/mbedtls/library/error.c | 700 ++ .../1.5.0/third_party/mbedtls/library/gcm.c | 953 ++ .../third_party/mbedtls/library/havege.c | 243 + .../third_party/mbedtls/library/hmac_drbg.c | 529 ++ .../1.5.0/third_party/mbedtls/library/md.c | 471 + .../1.5.0/third_party/mbedtls/library/md2.c | 288 + .../1.5.0/third_party/mbedtls/library/md4.c | 384 + .../1.5.0/third_party/mbedtls/library/md5.c | 407 + .../third_party/mbedtls/library/md_wrap.c | 575 ++ .../mbedtls/library/memory_buffer_alloc.c | 750 ++ .../1.5.0/third_party/mbedtls/library/net.c | 575 ++ .../1.5.0/third_party/mbedtls/library/oid.c | 650 ++ .../third_party/mbedtls/library/padlock.c | 170 + .../1.5.0/third_party/mbedtls/library/pem.c | 447 + .../1.5.0/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 + .../1.5.0/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 + .../1.5.0/third_party/mbedtls/library/rsa.c | 1705 ++++ .../1.5.0/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 | 7735 +++++++++++++++++ .../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 ++ .../1.5.0/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 | 2398 +++++ .../third_party/mbedtls/library/x509_csr.c | 417 + .../mbedtls/library/x509write_crt.c | 456 + .../mbedtls/library/x509write_csr.c | 256 + .../1.5.0/third_party/mbedtls/library/xtea.c | 281 + .../third_party/mbedtls/platform/Makefile | 46 + .../mbedtls/platform/esp_hardware.c | 26 + .../1.5.0/third_party/mbedtls/platform/net.c | 516 ++ .../RTOS/1.5.0/third_party/nopoll/Makefile | 44 + .../nopoll/nopoll-regression-client.c | 3080 +++++++ .../RTOS/1.5.0/third_party/nopoll/nopoll.c | 1729 ++++ .../1.5.0/third_party/nopoll/nopoll_conn.c | 4157 +++++++++ .../third_party/nopoll/nopoll_conn_opts.c | 325 + .../1.5.0/third_party/nopoll/nopoll_ctx.c | 802 ++ .../1.5.0/third_party/nopoll/nopoll_decl.c | 94 + .../RTOS/1.5.0/third_party/nopoll/nopoll_io.c | 233 + .../third_party/nopoll/nopoll_listener.c | 441 + .../1.5.0/third_party/nopoll/nopoll_log.c | 245 + .../1.5.0/third_party/nopoll/nopoll_loop.c | 269 + .../1.5.0/third_party/nopoll/nopoll_msg.c | 320 + .../1.5.0/third_party/nopoll/nopoll_win32.c | 136 + .../RTOS/1.5.0/third_party/openssl/Makefile | 54 + .../third_party/openssl/OpenSSL-APIs.rst | 1797 ++++ .../third_party/openssl/library/Makefile | 46 + .../third_party/openssl/library/ssl_cert.c | 87 + .../third_party/openssl/library/ssl_lib.c | 1556 ++++ .../third_party/openssl/library/ssl_methods.c | 81 + .../third_party/openssl/library/ssl_pkey.c | 239 + .../third_party/openssl/library/ssl_stack.c | 74 + .../third_party/openssl/library/ssl_x509.c | 285 + .../third_party/openssl/platform/Makefile | 46 + .../third_party/openssl/platform/ssl_pm.c | 667 ++ .../RTOS/1.5.0/third_party/spiffs/Makefile | 44 + .../1.5.0/third_party/spiffs/esp_spiffs.c | 292 + .../1.5.0/third_party/spiffs/spiffs_cache.c | 303 + .../1.5.0/third_party/spiffs/spiffs_check.c | 973 +++ .../RTOS/1.5.0/third_party/spiffs/spiffs_gc.c | 568 ++ .../third_party/spiffs/spiffs_hydrogen.c | 960 ++ .../1.5.0/third_party/spiffs/spiffs_nucleus.c | 1899 ++++ .../RTOS/1.5.0/third_party/ssl/Makefile | 47 + .../1.5.0/third_party/ssl/crypto/Makefile | 46 + .../1.5.0/third_party/ssl/crypto/sha256.c | 287 + .../1.5.0/third_party/ssl/crypto/sha384.c | 80 + .../1.5.0/third_party/ssl/crypto/sha512.c | 233 + .../1.5.0/third_party/ssl/crypto/ssl_aes.c | 466 + .../1.5.0/third_party/ssl/crypto/ssl_bigint.c | 1520 ++++ .../third_party/ssl/crypto/ssl_crypto_misc.c | 418 + .../1.5.0/third_party/ssl/crypto/ssl_hmac.c | 113 + .../1.5.0/third_party/ssl/crypto/ssl_md5.c | 293 + .../1.5.0/third_party/ssl/crypto/ssl_rc4.c | 91 + .../1.5.0/third_party/ssl/crypto/ssl_rsa.c | 288 + .../1.5.0/third_party/ssl/crypto/ssl_sha1.c | 248 + .../RTOS/1.5.0/third_party/ssl/ssl/Makefile | 46 + .../RTOS/1.5.0/third_party/ssl/ssl/ssl_asn1.c | 697 ++ .../1.5.0/third_party/ssl/ssl/ssl_gen_cert.c | 374 + .../1.5.0/third_party/ssl/ssl/ssl_loader.c | 519 ++ .../1.5.0/third_party/ssl/ssl/ssl_openssl.c | 326 + .../1.5.0/third_party/ssl/ssl/ssl_os_port.c | 341 + .../RTOS/1.5.0/third_party/ssl/ssl/ssl_p12.c | 484 ++ .../1.5.0/third_party/ssl/ssl/ssl_platform.c | 1114 +++ .../RTOS/1.5.0/third_party/ssl/ssl/ssl_tls1.c | 2316 +++++ .../1.5.0/third_party/ssl/ssl/ssl_tls1_clnt.c | 397 + .../1.5.0/third_party/ssl/ssl/ssl_tls1_svr.c | 495 ++ .../RTOS/1.5.0/third_party/ssl/ssl/ssl_x509.c | 621 ++ .../ESPressif/RTOS/1.5.0/tools/gen_appbin.py | 272 + .../ESPressif/RTOS/1.5.0/tools/make_cacert.py | 41 + .../ESPressif/RTOS/1.5.0/tools/make_cert.py | 53 + .../ESPressif/RTOS/1.5.0/tools/makefile.sh | 92 + 958 files changed, 281713 insertions(+) create mode 100644 Distrib/ESPressif/RTOS/1.5.0/LICENSE create mode 100644 Distrib/ESPressif/RTOS/1.5.0/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/README.md create mode 100644 Distrib/ESPressif/RTOS/1.5.0/bin/blank.bin create mode 100644 Distrib/ESPressif/RTOS/1.5.0/bin/boot_v1.6.bin create mode 100644 Distrib/ESPressif/RTOS/1.5.0/bin/esp_init_data_default.bin create mode 100644 Distrib/ESPressif/RTOS/1.5.0/bin/upgrade/readme.txt create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/20B-ESP8266__RTOS_SDK_API Reference.pdf create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/airkiss_8h_source.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/annotated.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/arrowdown.png create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/arrowright.png create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/bc_s.png create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/bdwn.png create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/c__types_8h_source.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/classes.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/closed.png create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/dir_5f1d40343f59d40d6b0768ec5b4dc5c7.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/dir_997368f752113e5dcdcd9718596161d3.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/dir_cf4dbf1328d2cf10d3f3933741525dc7.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/dir_d28a4824dc47e487b107a5db32ef43c4.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/dir_d44c64559bbebec7f509842c48db8b23.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/doc.png create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/doxygen.css create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/doxygen.png create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/dynsections.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__common_8h_source.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__libc_8h_source.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__misc_8h_source.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__softap_8h_source.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__spiffs_8h_source.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__ssc_8h_source.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__sta_8h_source.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__system_8h_source.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__timer_8h_source.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__wifi_8h_source.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__wps_8h_source.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/espconn_8h_source.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/espnow_8h_source.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/files.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/folderclosed.png create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/folderopen.png create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/functions.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/functions_func.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/functions_vars.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/gpio_8h_source.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/group__AirKiss__APIs.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Driver__APIs.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/group__ESPNow__APIs.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Espconn__APIs.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/group__GPIO__Driver__APIs.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/group__HW__Timer__APIs.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Mesh__APIs.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Misc__APIs.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/group__PWM__Driver__APIs.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/group__SPI__Driver__APIs.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/group__SSC__APIs.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Smartconfig__APIs.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/group__SoftAP__APIs.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Spiffs__APIs.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Station__APIs.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/group__System__APIs.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/group__System__boot__APIs.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Timer__APIs.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/group__UART__Driver__APIs.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Upgrade__APIs.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/group__WPS__APIs.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/group__WiFi__APIs.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/group__WiFi__Common__APIs.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/group__WiFi__Force__Sleep__APIs.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/group__WiFi__Rate__Control__APIs.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/group__WiFi__Sniffer__APIs.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/group__WiFi__User__IE__APIs.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/hw__timer_8h_source.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/index.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/jquery.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/mesh_8h_source.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/modules.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/nav_f.png create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/nav_g.png create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/nav_h.png create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/open.png create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/pwm_8h_source.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/queue_8h_source.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_0.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_0.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_1.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_1.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_10.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_10.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_11.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_11.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_12.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_12.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_13.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_13.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_2.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_2.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_3.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_3.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_4.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_4.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_5.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_5.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_6.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_6.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_7.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_7.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_8.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_8.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_9.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_9.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_a.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_a.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_b.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_b.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_c.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_c.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_d.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_d.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_e.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_e.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_f.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_f.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_0.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_0.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_1.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_1.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_2.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_2.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_3.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_3.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_4.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_4.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_5.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_5.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_6.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_6.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_7.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_7.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_8.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_8.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_9.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_9.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_a.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_a.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_b.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_b.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/close.png create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_0.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_0.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_1.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_1.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_2.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_2.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_3.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_3.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_4.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_4.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_5.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_5.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_6.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_6.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_7.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_7.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_0.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_0.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_1.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_1.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_2.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_2.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_3.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_3.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_4.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_4.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_5.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_5.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_6.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_6.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_7.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_7.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_8.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_8.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_9.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_9.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_a.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_a.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_0.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_0.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_1.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_1.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_2.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_2.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_3.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_3.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_4.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_4.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_5.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_5.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_6.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_6.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_7.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_7.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_8.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_8.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_0.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_0.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_1.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_1.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_2.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_2.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_3.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_3.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_4.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_4.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_5.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_5.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_6.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_6.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_7.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_7.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_8.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_8.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_9.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_9.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_a.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_a.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_b.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_b.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_c.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_c.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_d.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_d.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_e.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_e.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/mag_sel.png create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/nomatches.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/pages_0.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/pages_0.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/search.css create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/search.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/search_l.png create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/search_m.png create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/search_r.png create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/searchdata.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_0.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_0.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_1.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_1.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_2.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_2.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_3.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_3.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_4.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_4.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_5.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_5.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_6.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_6.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_0.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_0.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_1.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_1.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_10.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_10.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_11.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_11.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_2.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_2.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_3.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_3.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_4.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_4.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_5.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_5.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_6.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_6.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_7.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_7.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_8.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_8.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_9.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_9.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_a.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_a.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_b.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_b.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_c.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_c.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_d.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_d.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_e.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_e.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_f.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_f.js create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/smartconfig_8h_source.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/spi__flash_8h_source.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/splitbar.png create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__SoftAPMode__ProbeReqRecved__t.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__SoftAPMode__StaConnected__t.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__SoftAPMode__StaDisconnected__t.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__StaMode__AuthMode__Change__t.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__StaMode__Connected__t.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__StaMode__Disconnected__t.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__StaMode__Got__IP__t.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__StaMode__ScanDone__t.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/structGPIO__ConfigTypeDef.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/structSpiFlashChip.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/structUART__ConfigTypeDef.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/structUART__IntrConfTypeDef.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/struct__esp__event.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/struct__esp__tcp.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/struct__esp__udp.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/struct__os__timer__t.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/struct__remot__info.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/structairkiss__config__t.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/structbss__info.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/structcmd__s.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/structdhcps__lease.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/structesp__spiffs__config.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/structespconn.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/structip__info.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/structpwm__param.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/structrst__info.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/structscan__config.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/structsoftap__config.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/structstation__config.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/structstation__info.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/structupgrade__server__info.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/sync_off.png create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/sync_on.png create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/tab_a.png create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/tab_b.png create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/tab_h.png create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/tab_s.png create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/tabs.css create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/uart_8h_source.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/unionEvent__Info__u.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/documents/html/upgrade_8h_source.html create mode 100644 Distrib/ESPressif/RTOS/1.5.0/driver_lib/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/driver_lib/README.md create mode 100644 Distrib/ESPressif/RTOS/1.5.0/driver_lib/driver/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/driver_lib/driver/gpio.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/driver_lib/driver/hw_timer.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/driver_lib/driver/i2c_master.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/driver_lib/driver/spi_interface.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/driver_lib/driver/uart.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/driver_lib/include/gpio.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/driver_lib/include/hw_timer.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/driver_lib/include/i2c_master.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/driver_lib/include/spi_interface.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/driver_lib/include/spi_register.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/driver_lib/include/uart.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/driver_lib/make_lib.sh create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/gen_misc.sh create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/include/openssl_demo.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/include/user_config.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/programs/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/programs/openssl_demo.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/user/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/user/user_main.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/project_template/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/project_template/gen_misc.bat create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/project_template/gen_misc.sh create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/project_template/include/user_config.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/project_template/readme.txt create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/project_template/sample_lib/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/project_template/sample_lib/folder1/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/project_template/sample_lib/folder1/file1.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/project_template/sample_lib/folder2/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/project_template/sample_lib/folder2/file2.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/project_template/user/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/project_template/user/user_main.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/airkiss.txt create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/gen_misc.bat create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/gen_misc.sh create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/include/user_config.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/model two-dimension code.rar create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/readme.txt create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/user/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/user/user_main.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/gen_misc.bat create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/gen_misc.sh create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/include/spiffs_test_params.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/test_bugreports.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/test_check.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/test_dev.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/test_hydrogen.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/test_main.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/test_spiffs.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/test_spiffs.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/testrunner.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/testrunner.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/testsuites.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/websocket_demo/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/websocket_demo/gen_misc.bat create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/websocket_demo/gen_misc.sh create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/websocket_demo/user/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/websocket_demo/user/user_main.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/websocket_demo/websocket/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/websocket_demo/websocket/websocket.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/gen_misc.bat create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/gen_misc.sh create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/include/user_config.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/include/wifi_state_machine.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/readme.txt create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/user/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/user/user_main.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/user/wifi_state_machine.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/wps_demo/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/wps_demo/gen_misc.bat create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/wps_demo/gen_misc.sh create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/wps_demo/include/user_config.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/wps_demo/readme.txt create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/wps_demo/user/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/examples/wps_demo/user/user_main.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/cacheasm.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/cacheattrasm.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/core-isa.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/core-matmap.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/core.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/defs.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/specreg.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/system.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/tie-asm.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/tie.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/coreasm.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/corebits.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/hal.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/sim.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/simcall-errno.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/simcall-fcntl.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/simcall.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/specreg.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_MUL32.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_core.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_debug.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_density.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_exceptions.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_externalregisters.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_interrupt.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_misc.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_mmu.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_mul.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_timer.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_trace.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/xtensa-libdb-macros.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/xtensa-xer.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/xtruntime-frames.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/xtruntime.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/espressif/airkiss.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/espressif/c_types.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/eagle_soc.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/esp8266.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/ets_sys.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/gpio_register.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/pin_mux_register.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/spi_register.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/timer_register.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/uart_register.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_common.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_libc.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_misc.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_softap.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_spiffs.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_ssc.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_sta.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_system.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_timer.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_wifi.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_wps.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/espressif/espconn.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/espressif/espnow.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/espressif/mesh.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/espressif/pwm.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/espressif/queue.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/espressif/smartconfig.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/espressif/spi_flash.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/espressif/upgrade.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/freertos/FreeRTOS.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/freertos/FreeRTOSConfig.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/freertos/StackMacros.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/freertos/croutine.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/freertos/list.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/freertos/mpu_wrappers.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/freertos/portable.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/freertos/portmacro.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/freertos/projdefs.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/freertos/queue.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/freertos/semphr.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/freertos/task.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/freertos/timers.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/freertos/xtensa_context.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/freertos/xtensa_rtos.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/freertos/xtensa_timer.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/json/cJSON.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/apps/sntp.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/apps/sntp_opts.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/apps/sntp_time.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/apps/time.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/arch/cc.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/arch/perf.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/arch/sys_arch.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv4/lwip/autoip.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv4/lwip/icmp.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv4/lwip/igmp.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv4/lwip/inet.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv4/lwip/ip4.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv4/lwip/ip4_addr.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv4/lwip/ip_frag.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/dhcp6.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/ethip6.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/icmp6.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/inet6.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/ip6.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/ip6_addr.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/ip6_frag.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/mld6.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/nd6.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/api.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/api_msg.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/arch.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/debug.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/def.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/dhcp.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/dhcpserver.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/dns.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/err.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/inet_chksum.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/init.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/ip.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/ip_addr.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/mem.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/memp.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/memp_std.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/multi-threads/sockets_mt.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/netbuf.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/netdb.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/netif.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/netifapi.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/opt.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/pbuf.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/raw.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/sio.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/snmp.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/snmp_asn1.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/snmp_msg.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/snmp_structs.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/sockets.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/stats.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/sys.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/tcp.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/tcp_impl.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/tcpip.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/timers.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/udp.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwipopts.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/netif/etharp.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/netif/if_llc.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/netif/ppp_oe.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/netif/slipif.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/netif/wlan_lwip_if.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/posix/netdb.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/lwip/posix/sys/socket.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/aes.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/aesni.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/arc4.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/asn1.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/asn1write.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/base64.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/bignum.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/blowfish.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/bn_mul.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/camellia.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ccm.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/certs.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/check_config.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/cipher.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/cipher_internal.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/compat-1.3.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/config.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/config_esp.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ctr_drbg.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/debug.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/des.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/dhm.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ecdh.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ecdsa.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ecjpake.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ecp.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/entropy.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/entropy_poll.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/error.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/gcm.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/havege.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/hmac_drbg.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/md.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/md2.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/md4.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/md5.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/md_internal.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/memory_buffer_alloc.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/net.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/oid.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/padlock.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/pem.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/pk.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/pk_internal.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/pkcs11.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/pkcs12.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/pkcs5.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/platform.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ripemd160.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/rsa.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/sha1.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/sha256.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/sha512.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ssl.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ssl_cache.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ssl_ciphersuites.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ssl_cookie.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ssl_internal.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ssl_ticket.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/threading.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/timing.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/version.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/x509.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/x509_crl.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/x509_crt.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/x509_csr.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/xtea.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_config.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_conn.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_conn_opts.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_ctx.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_decl.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_handlers.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_io.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_listener.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_log.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_loop.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_msg.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_private.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_win32.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl3.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_cert.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_code.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_dbg.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_lib.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_methods.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_pkey.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_stack.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_types.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_x509.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/tls1.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/x509_vfy.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/openssl/openssl/ssl.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/openssl/platform/ssl_opt.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/openssl/platform/ssl_pm.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/openssl/platform/ssl_port.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/spiffs/spiffs.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/spiffs/spiffs_config.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/spiffs/spiffs_nucleus.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_bigint.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_bigint_impl.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_compat-1.0.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_config.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_crypto.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_crypto_misc.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_os_port.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_platform.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_ssl.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_tls1.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_version.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/ld/eagle.app.v6.common.ld create mode 100644 Distrib/ESPressif/RTOS/1.5.0/ld/eagle.app.v6.ld create mode 100644 Distrib/ESPressif/RTOS/1.5.0/ld/eagle.app.v6.new.1024.app1.ld create mode 100644 Distrib/ESPressif/RTOS/1.5.0/ld/eagle.app.v6.new.1024.app2.ld create mode 100644 Distrib/ESPressif/RTOS/1.5.0/ld/eagle.app.v6.new.2048.ld create mode 100644 Distrib/ESPressif/RTOS/1.5.0/ld/eagle.app.v6.new.512.app1.ld create mode 100644 Distrib/ESPressif/RTOS/1.5.0/ld/eagle.app.v6.new.512.app2.ld create mode 100644 Distrib/ESPressif/RTOS/1.5.0/ld/eagle.rom.addr.v6.ld create mode 100644 Distrib/ESPressif/RTOS/1.5.0/lib/libairkiss.a create mode 100644 Distrib/ESPressif/RTOS/1.5.0/lib/libcirom.a create mode 100644 Distrib/ESPressif/RTOS/1.5.0/lib/libcrypto.a create mode 100644 Distrib/ESPressif/RTOS/1.5.0/lib/libdriver.a create mode 100644 Distrib/ESPressif/RTOS/1.5.0/lib/libespconn.a create mode 100644 Distrib/ESPressif/RTOS/1.5.0/lib/libespnow.a create mode 100644 Distrib/ESPressif/RTOS/1.5.0/lib/libfreertos.a create mode 100644 Distrib/ESPressif/RTOS/1.5.0/lib/libgcc.a create mode 100644 Distrib/ESPressif/RTOS/1.5.0/lib/libjson.a create mode 100644 Distrib/ESPressif/RTOS/1.5.0/lib/liblwip.a create mode 100644 Distrib/ESPressif/RTOS/1.5.0/lib/libmain.a create mode 100644 Distrib/ESPressif/RTOS/1.5.0/lib/libmbedtls.a create mode 100644 Distrib/ESPressif/RTOS/1.5.0/lib/libmesh.a create mode 100644 Distrib/ESPressif/RTOS/1.5.0/lib/libminic.a create mode 100644 Distrib/ESPressif/RTOS/1.5.0/lib/libmirom.a create mode 100644 Distrib/ESPressif/RTOS/1.5.0/lib/libnet80211.a create mode 100644 Distrib/ESPressif/RTOS/1.5.0/lib/libnopoll.a create mode 100644 Distrib/ESPressif/RTOS/1.5.0/lib/libopenssl.a create mode 100644 Distrib/ESPressif/RTOS/1.5.0/lib/libphy.a create mode 100644 Distrib/ESPressif/RTOS/1.5.0/lib/libpp.a create mode 100644 Distrib/ESPressif/RTOS/1.5.0/lib/libpwm.a create mode 100644 Distrib/ESPressif/RTOS/1.5.0/lib/libsmartconfig.a create mode 100644 Distrib/ESPressif/RTOS/1.5.0/lib/libspiffs.a create mode 100644 Distrib/ESPressif/RTOS/1.5.0/lib/libssc.a create mode 100644 Distrib/ESPressif/RTOS/1.5.0/lib/libssl.a create mode 100644 Distrib/ESPressif/RTOS/1.5.0/lib/libwpa.a create mode 100644 Distrib/ESPressif/RTOS/1.5.0/lib/libwps.a create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/freertos/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/freertos/croutine.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/freertos/heap_4.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/freertos/list.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/freertos/port.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/freertos/queue.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/freertos/readme.txt create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/freertos/tasks.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/freertos/timers.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/json/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/json/cJSON.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/FILES create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/api_lib.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/api_msg.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/err.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/multi-threads/sockets_mt.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/netbuf.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/netdb.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/netifapi.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/sockets.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/tcpip.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/apps/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/apps/sntp.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/apps/sntp_time.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/apps/time.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/arch/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/arch/sys_arch.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/def.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/dhcp.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/dhcpserver.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/dns.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/inet_chksum.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/init.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv4/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv4/autoip.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv4/icmp.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv4/igmp.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv4/ip4.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv4/ip4_addr.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv4/ip_frag.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/README create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/dhcp6.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/ethip6.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/icmp6.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/inet6.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/ip6.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/ip6_addr.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/ip6_frag.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/mld6.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/nd6.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/mem.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/memp.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/netif.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/pbuf.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/raw.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/snmp/asn1_dec.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/snmp/asn1_enc.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/snmp/mib2.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/snmp/mib_structs.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/snmp/msg_in.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/snmp/msg_out.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/stats.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/sys.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/tcp.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/tcp_in.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/tcp_out.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/timers.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/udp.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/FILES create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/etharp.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ethernetif.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/auth.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/auth.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/chap.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/chap.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/chpms.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/chpms.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/fsm.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/fsm.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/ipcp.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/ipcp.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/lcp.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/lcp.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/magic.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/magic.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/md5.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/md5.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/pap.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/pap.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/ppp.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/ppp.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/ppp_impl.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/ppp_oe.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/pppdebug.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/randm.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/randm.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/readme.txt create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/vj.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/vj.h create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/slipif.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/make_all_lib.sh create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/make_lib.sh create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/aes.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/aesni.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/arc4.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/asn1parse.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/asn1write.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/base64.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/bignum.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/blowfish.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/camellia.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ccm.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/certs.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/cipher.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/cipher_wrap.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ctr_drbg.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/debug.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/des.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/dhm.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ecdh.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ecdsa.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ecjpake.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ecp.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ecp_curves.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/entropy.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/entropy_poll.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/error.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/gcm.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/havege.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/hmac_drbg.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/md.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/md2.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/md4.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/md5.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/md_wrap.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/memory_buffer_alloc.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/net.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/oid.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/padlock.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/pem.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/pk.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/pk_wrap.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/pkcs11.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/pkcs12.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/pkcs5.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/pkparse.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/pkwrite.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/platform.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ripemd160.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/rsa.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/sha1.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/sha256.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/sha512.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ssl_cache.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ssl_ciphersuites.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ssl_cli.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ssl_cookie.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ssl_srv.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ssl_ticket.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ssl_tls.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/threading.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/timing.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/version.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/version_features.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/x509.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/x509_create.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/x509_crl.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/x509_crt.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/x509_csr.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/x509write_crt.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/x509write_csr.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/xtea.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/platform/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/platform/esp_hardware.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/platform/net.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll-regression-client.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_conn.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_conn_opts.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_ctx.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_decl.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_io.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_listener.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_log.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_loop.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_msg.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_win32.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/OpenSSL-APIs.rst create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/library/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/library/ssl_cert.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/library/ssl_lib.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/library/ssl_methods.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/library/ssl_pkey.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/library/ssl_stack.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/library/ssl_x509.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/platform/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/platform/ssl_pm.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/spiffs/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/spiffs/esp_spiffs.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/spiffs/spiffs_cache.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/spiffs/spiffs_check.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/spiffs/spiffs_gc.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/spiffs/spiffs_hydrogen.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/spiffs/spiffs_nucleus.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/sha256.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/sha384.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/sha512.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_aes.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_bigint.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_crypto_misc.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_hmac.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_md5.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_rc4.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_rsa.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_sha1.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/Makefile create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_asn1.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_gen_cert.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_loader.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_openssl.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_os_port.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_p12.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_platform.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_tls1.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_tls1_clnt.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_tls1_svr.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_x509.c create mode 100644 Distrib/ESPressif/RTOS/1.5.0/tools/gen_appbin.py create mode 100644 Distrib/ESPressif/RTOS/1.5.0/tools/make_cacert.py create mode 100644 Distrib/ESPressif/RTOS/1.5.0/tools/make_cert.py create mode 100644 Distrib/ESPressif/RTOS/1.5.0/tools/makefile.sh diff --git a/Distrib/ESPressif/RTOS/1.5.0/LICENSE b/Distrib/ESPressif/RTOS/1.5.0/LICENSE new file mode 100644 index 0000000..9919b11 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/LICENSE @@ -0,0 +1,63 @@ +ESPRSSIF 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һÌض¨ÓÃ; +ºÍ·ÇÇÖȨµÄ±£Ö¤¡£×÷ÕߺͰæȨ³ÖÓÐÈËÔÚÈκÎÇé¿öϾù²»¾ÍÓÉÈí¼þ»òÈí¼þʹÓÃÒýÆðµÄÒÔºÏͬÐÎʽ¡¢ÃñÊÂÇÖȨ +»òÆäËü·½Ê½Ìá³öµÄÈκÎË÷Åâ¡¢Ë𺦻òÆäËüÔðÈθºÔð¡£ + +Exception vectors include code relicensed from the following: +Original vector contents Copyright (C) 2014-2015 Espressif Systems +Additions Copyright (C) Superhouse Automation Pty Ltd and Angus Gratton +Redistribution and use in source and binary forms, with or without modification, are +permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce 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. + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/Makefile b/Distrib/ESPressif/RTOS/1.5.0/Makefile new file mode 100644 index 0000000..553c652 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/Makefile @@ -0,0 +1,411 @@ +# copyright (c) 2010 Espressif System +# +ifndef PDIR + +endif + +ifeq ($(COMPILE), xcc) + AR = xt-ar + CC = xt-xcc + NM = xt-nm + CPP = xt-xt++ + OBJCOPY = xt-objcopy + OBJDUMP = xt-objdump +else + AR = xtensa-lx106-elf-ar + CC = xtensa-lx106-elf-gcc + NM = xtensa-lx106-elf-nm + CPP = xtensa-lx106-elf-g++ + OBJCOPY = xtensa-lx106-elf-objcopy + OBJDUMP = xtensa-lx106-elf-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 + size_map = 0 + flash = 512 + ifeq ($(app), 2) + addr = 0x41000 + endif + endif + endif + endif + endif + endif +endif + +LD_FILE = $(LDDIR)/eagle.app.v6.ld + +ifneq ($(boot), none) +ifneq ($(app),0) + ifeq ($(size_map), 6) + 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) +CPPSRCS ?= $(wildcard *.cpp) +ASRCs ?= $(wildcard *.s) +ASRCS ?= $(wildcard *.S) +SUBDIRS ?= $(patsubst %/,%,$(dir $(wildcard */Makefile))) + +ODIR := .output +OBJODIR := $(ODIR)/$(TARGET)/$(FLAVOR)/obj + +OBJS := $(CSRCS:%.c=$(OBJODIR)/%.o) \ + $(CPPSRCS:%.cpp=$(OBJODIR)/%.o) \ + $(ASRCs:%.s=$(OBJODIR)/%.o) \ + $(ASRCS:%.S=$(OBJODIR)/%.o) + +DEPS := $(CSRCS:%.c=$(OBJODIR)/%.d) \ + $(CPPSRCS:%.cpp=$(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 \ + -fno-jump-tables +# -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 $(BIN_PATH) + @mkdir -p $(BINODIR) + +ifeq ($(APP), 0) + @$(RM) -r $(BIN_PATH)/eagle.S $(BIN_PATH)/eagle.dump + @$(OBJDUMP) -x -s $< > $(BIN_PATH)/eagle.dump + @$(OBJDUMP) -S $< > $(BIN_PATH)/eagle.S +else + @mkdir -p $(BIN_PATH)/upgrade + @$(RM) -r $(BIN_PATH)/upgrade/$(BIN_NAME).S $(BIN_PATH)/upgrade/$(BIN_NAME).dump + @$(OBJDUMP) -x -s $< > $(BIN_PATH)/upgrade/$(BIN_NAME).dump + @$(OBJDUMP) -S $< > $(BIN_PATH)/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 "!!!" + @echo "SDK_PATH: $(SDK_PATH)" + +ifeq ($(app), 0) + @python $(SDK_PATH)/tools/gen_appbin.py $< 0 $(mode) $(freqdiv) $(size_map) + @mv eagle.app.flash.bin $(BIN_PATH)/eagle.flash.bin + @mv eagle.app.v6.irom0text.bin $(BIN_PATH)/eagle.irom0text.bin + @rm eagle.app.v6.* + @echo "BIN_PATH: $(BIN_PATH)" + @echo "" + @echo "No boot needed." + @echo "Generate eagle.flash.bin and eagle.irom0text.bin successully in BIN_PATH" + @echo "eagle.flash.bin-------->0x00000" + @echo "eagle.irom0text.bin---->0x20000" +else + @echo "BIN_PATH: $(BIN_PATH)/upgrade" + @echo "" + + ifneq ($(boot), new) + @python $(SDK_PATH)/tools/gen_appbin.py $< 1 $(mode) $(freqdiv) $(size_map) + @echo "Support boot_v1.1 and +" + else + @python $(SDK_PATH)/tools/gen_appbin.py $< 2 $(mode) $(freqdiv) $(size_map) + + 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_PATH)/upgrade/$(BIN_NAME).bin + @rm eagle.app.v6.* + @echo "Generate $(BIN_NAME).bin successully in BIN_PATH" + @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: %.cpp + @mkdir -p $(OBJODIR); + $(CPP) $(if $(findstring $<,$(DSRCS)),$(DFLAGS),$(CFLAGS)) $(COPTS_$(*F)) -o $@ -c $< + +$(OBJODIR)/%.d: %.cpp + @mkdir -p $(OBJODIR); + @echo DEPEND: $(CPP) -M $(CFLAGS) $< + @set -e; rm -f $@; \ + $(CPP) -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 $(SDK_PATH)/include -I $(SDK_PATH)/extra_include +INCLUDES += -I $(SDK_PATH)/driver_lib/include +INCLUDES += -I $(SDK_PATH)/include/espressif +INCLUDES += -I $(SDK_PATH)/include/lwip +INCLUDES += -I $(SDK_PATH)/include/lwip/ipv4 +INCLUDES += -I $(SDK_PATH)/include/lwip/ipv6 +INCLUDES += -I $(SDK_PATH)/include/nopoll +INCLUDES += -I $(SDK_PATH)/include/spiffs +INCLUDES += -I $(SDK_PATH)/include/ssl +INCLUDES += -I $(SDK_PATH)/include/json +INCLUDES += -I $(SDK_PATH)/include/openssl diff --git a/Distrib/ESPressif/RTOS/1.5.0/README.md b/Distrib/ESPressif/RTOS/1.5.0/README.md new file mode 100644 index 0000000..8b81c66 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/README.md @@ -0,0 +1,55 @@ +# ESP8266_RTOS_SDK # + +---------- + +ESP8266 SDK based on FreeRTOS. + +## Note ## + +APIs of "ESP8266_RTOS_SDK" are same as "ESP8266_NONOS_SDK" + +More details in "Wiki" ! + +## Requrements ## + +You can use both xcc and gcc to compile your project, gcc is recommended. +For gcc, please refer to [esp-open-sdk](https://github.com/pfalcon/esp-open-sdk). + + +## Compile ## + +Clone ESP8266_RTOS_SDK, e.g., to ~/ESP8266_RTOS_SDK. + + $git clone https://github.com/espressif/ESP8266_RTOS_SDK.git + +Modify gen_misc.sh or gen_misc.bat: +For Linux: + + $export SDK_PATH=~/ESP8266_RTOS_SDK + $export BIN_PATH=~/ESP8266_BIN + +For Windows: + + set SDK_PATH=/c/ESP8266_RTOS_SDK + set BIN_PATH=/c/ESP8266_BIN + +ESP8266_RTOS_SDK/examples/project_template is a project template, you can copy this to anywhere, e.g., to ~/workspace/project_template. + +Generate bin: +For Linux: + + ./gen_misc.sh + +For Windows: + + gen_misc.bat + +Just follow the tips and steps. + +## Download ## + +eagle.app.v6.flash.bin, downloads to flash 0x00000 + +eagle.app.v6.irom0text.bin, downloads to flash 0x40000 + +blank.bin, downloads to flash 0x7E000 diff --git a/Distrib/ESPressif/RTOS/1.5.0/bin/blank.bin b/Distrib/ESPressif/RTOS/1.5.0/bin/blank.bin new file mode 100644 index 0000000..7de9e36 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/bin/blank.bin @@ -0,0 +1 @@ +ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ \ No newline at end of file diff --git a/Distrib/ESPressif/RTOS/1.5.0/bin/boot_v1.6.bin b/Distrib/ESPressif/RTOS/1.5.0/bin/boot_v1.6.bin new file mode 100644 index 0000000000000000000000000000000000000000..6b11db7d52b17e364a78e19f9b2580fc3d83bc01 GIT binary patch literal 3856 zcmb7G4RBP|6+ZVRSvH%u?%RZ}#iZkX5A#FF(wE1Nk&^OuSr!nH5H!?|GrnEeO`?#5 zO^~0Vb+bv<0D>|7K|0V`QcE3%p^7MUpw3H#jA&Gnapb3D1nO9Wh=E!P5^{U)E>Jpc zXWBP&?mhQA=bn3h?!E60r2&+sOFDq0*JQ%~{n3`unR)X;?|T6By!7nuv*jeyLvAn= zKp>zbh6+23D#U;ApB)!R~`lU(&R=uxHbc@-F2jV#4dt#dA0i|0KTg!p`nd_ZCgBH(m z4o&E8r{@eC=$B4zCW9RNK?ym{`*I@s-1eS+>D}dA`V;aAN9E&8=$EV&#ZDdyfCUWt zC_vvN;JL{pVkTzBq|h1cp3#ndL@}eQDQAMFID7psk@G61;gc$S9Q7iagT0`bDsVsu zn({?PF7mZ{M_3u=y#^_1TS$XK<34ZVh7OW23)(I+`5GhbTs7kwvtZr+#z-q4-pREl zfL9O{thdh@Rh+s)>3A$B?f@`=0zk9~8(t6~H~_2&i2g;_cnEV>8A%`Kt#So33bLOl zP@XK%o{II1th~%bAzIk-(lEO^KBIIqi>HGc@MO)3`kYx|GwgiY_weMb$+U%bwDXuY zS3uN%yojnR%|Pkjr!w~np!Kk5fMSzgt@<6sZHW6 z(VOuVyOr%I)@eIZAJS_`A0vH%WNjUtxgSZ2j?M%;L+3Ii{VP52DRsq%!1>V1ErsNB%LSR;1-f7w3Zh3ZAdwM?hB+ zuTiJj6DS@COq5SBAuxg57&QU(b^_xod5~t`>0!7MzO8&@EFR}6~ z1aFV`OU2gI-En{mDv7DOS=*yokWZfdn|D_ zx>`zXlR7=3ScAtq;;|ongO#>3xt)368J?R?j&YlcT%>hVZz4*5&4&Wn>Y}z8Y0BP@ zDt~YMxB}CA_08!k*RzUH$GULB0`V2}V36E%8^L7u@qTg=tm_MXrw|#UkzjVSm zLV@&P9~>SpPhrH*r}W6h1M)=N@`5~p-_i0UMszNShnZZ$NO@A}HzSrcY*3UZFjB^W z>Z--DX5S(Gg6IOe6T z)F-K_zm3uAzs|u*yqoXbY(|Ua8x96(jD{sObpaZ&-b);e&}OpjH5PPzp>7^K+3ASLIS(#PLXRWaA~m(B-rls;o}vxqz`zMfV6g{CQDw~DP}xeqw7t<-eJR-(lGmH-hi{Arlq!dSI#4% zJu{%l+2w@nVR`91DkT%gBH&vQW6D)8P(=V0no^#HU%OZoK;^EKa_*oNXG?-9Wd=@k zzE!p|GqC-Ql)0Bv8rDEnb~++ANy=bNvpAV&p+&I#5O%p-|0Vpgoq4u!&Nwe|m_E~W zBnuy`-6#9MICt%`_4Vv-!#*s?PMZZzo5zngy|vlj>9A-HA?6sPIMSl+{AHyo{IR1s z2=bkd3SkQrU(w zs?+>6HXDR%BaKZoSYO{n!-3l6p=BjB5=su6>S jQHrD?rS=a;lS_q{2dYabZ)rK-NYIY&T~2%sekcC{gue$S literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/bin/esp_init_data_default.bin b/Distrib/ESPressif/RTOS/1.5.0/bin/esp_init_data_default.bin new file mode 100644 index 0000000000000000000000000000000000000000..0df65445ba1c4d08d13a2f683b7619fc22a8c05c GIT binary patch literal 128 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

reu-FQcQ2CN<#RF12>tQ0M6ePZAeANd|Fj=CU~2 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

y0bk~K2 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

>$*C`2*Bnn%>PYjr@_)7BbNzBBl36l7 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 z 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

SoBJI#nWep1RHh>go8sST{>=rlrw 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

ZhS?jgm#roLL*r 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 N{oxOP{+ECH^uGcey=MRb literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/airkiss_8h_source.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/airkiss_8h_source.html new file mode 100644 index 0000000..1d58531 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/airkiss_8h_source.html @@ -0,0 +1,186 @@ + + + + + + +ESP8266_RTOS_SDK: include/espressif/airkiss.h Source File + + + + + + + + + + +

+
+
+
airkiss.h
+
+
+
1 /*
+
2  * airkiss.h
+
3  *
+
4  * Created on: 2015-1-26
+
5  * Author: peterfan
+
6  */
+
7 
+
8 #ifndef AIRKISS_H_
+
9 #define AIRKISS_H_
+
10 
+
11 #ifdef __cplusplus
+
12 extern "C" {
+
13 #endif
+
14 
+
15 
+
16 typedef void* (*airkiss_memset_fn) (void* ptr, int value, unsigned int num);
+
17 typedef void* (*airkiss_memcpy_fn) (void* dst, const void* src, unsigned int num);
+
18 typedef int (*airkiss_memcmp_fn) (const void* ptr1, const void* ptr2, unsigned int num);
+
19 typedef int (*airkiss_printf_fn) (const char* format, ...);
+
20 
+
21 
+
22 
+
23 typedef struct
+
24 {
+
25  airkiss_memset_fn memset;
+
26  airkiss_memcpy_fn memcpy;
+
27  airkiss_memcmp_fn memcmp;
+
28  airkiss_printf_fn printf;
+
29 
+ +
31 
+
66 const char* airkiss_version(void);
+
67 
+
68 
+
69 typedef enum
+
70 {
+ +
73 
+ +
76 
+ +
79 
+ +
82 
+ +
85 
+ +
88 
+ +
91 
+ +
94 
+
95 
+ +
97 
+
98 
+
99 typedef enum
+
100 {
+
101  AIRKISS_LAN_SSDP_REQ_CMD = 0x1,
+
102  AIRKISS_LAN_SSDP_RESP_CMD = 0x1001,
+
103  AIRKISS_LAN_SSDP_NOTIFY_CMD = 0x1002
+
104 } airkiss_lan_cmdid_t;
+
105 
+
117 int airkiss_lan_recv(const void* body, unsigned short length, const airkiss_config_t* config);
+
118 
+
119 
+
136 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);
+
137 
+
146 #ifdef __cplusplus
+
147 }
+
148 #endif
+
149 
+
150 #endif /* AIRKISS_H_ */
+
Definition: airkiss.h:81
+
int airkiss_lan_recv(const void *body, unsigned short length, const airkiss_config_t *config)
Parse the UDP packet sent by AirKiss.
+
const char * airkiss_version(void)
Get the version information of AirKiss lib.
+
Definition: airkiss.h:90
+
Definition: airkiss.h:87
+
Definition: airkiss.h:93
+
Definition: airkiss.h:72
+
Definition: airkiss.h:75
+
Definition: airkiss.h:23
+
Definition: airkiss.h:84
+
Definition: airkiss.h:78
+
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)
Packaging the UDP packet.
+
airkiss_lan_ret_t
Definition: airkiss.h:69
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/annotated.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/annotated.html new file mode 100644 index 0000000..74cee1a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/annotated.html @@ -0,0 +1,134 @@ + + + + + + +ESP8266_RTOS_SDK: Data Structures + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + +
+ +
+
+ + +
+ +
+ +
+
+
Data Structures
+
+ + + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/arrowdown.png b/Distrib/ESPressif/RTOS/1.5.0/documents/html/arrowdown.png new file mode 100644 index 0000000000000000000000000000000000000000..0b63f6d38c4b9ec907b820192ebe9724ed6eca22 GIT binary patch literal 246 zcmVkw!R34#Lv2LOS^S2tZA31X++9RY}n zChwn@Z)Wz*WWHH{)HDtJnq&A2hk$b-y(>?@z0iHr41EKCGp#T5?07*qoM6N<$f(V3Pvj6}9 literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/arrowright.png b/Distrib/ESPressif/RTOS/1.5.0/documents/html/arrowright.png new file mode 100644 index 0000000000000000000000000000000000000000..c6ee22f937a07d1dbfc27c669d11f8ed13e2f152 GIT binary patch literal 229 zcmV^P)R?RzRoKvklcaQ%HF6%rK2&ZgO(-ihJ_C zzrKgp4jgO( fd_(yg|3PpEQb#9`a?Pz_00000NkvXXu0mjftR`5K literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/bc_s.png b/Distrib/ESPressif/RTOS/1.5.0/documents/html/bc_s.png new file mode 100644 index 0000000000000000000000000000000000000000..224b29aa9847d5a4b3902efd602b7ddf7d33e6c2 GIT binary patch literal 676 zcmV;V0$crwP)y__>=_9%My z{n931IS})GlGUF8K#6VIbs%684A^L3@%PlP2>_sk`UWPq@f;rU*V%rPy_ekbhXT&s z(GN{DxFv}*vZp`F>S!r||M`I*nOwwKX+BC~3P5N3-)Y{65c;ywYiAh-1*hZcToLHK ztpl1xomJ+Yb}K(cfbJr2=GNOnT!UFA7Vy~fBz8?J>XHsbZoDad^8PxfSa0GDgENZS zuLCEqzb*xWX2CG*b&5IiO#NzrW*;`VC9455M`o1NBh+(k8~`XCEEoC1Ybwf;vr4K3 zg|EB<07?SOqHp9DhLpS&bzgo70I+ghB_#)K7H%AMU3v}xuyQq9&Bm~++VYhF09a+U zl7>n7Jjm$K#b*FONz~fj;I->Bf;ule1prFN9FovcDGBkpg>)O*-}eLnC{6oZHZ$o% zXKW$;0_{8hxHQ>l;_*HATI(`7t#^{$(zLe}h*mqwOc*nRY9=?Sx4OOeVIfI|0V(V2 zBrW#G7Ss9wvzr@>H*`r>zE z+e8bOBgqIgldUJlG(YUDviMB`9+DH8n-s9SXRLyJHO1!=wY^79WYZMTa(wiZ!zP66 zA~!21vmF3H2{ngD;+`6j#~6j;$*f*G_2ZD1E;9(yaw7d-QnSCpK(cR1zU3qU0000< KMNUMnLSTYoA~SLT literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/bdwn.png b/Distrib/ESPressif/RTOS/1.5.0/documents/html/bdwn.png new file mode 100644 index 0000000000000000000000000000000000000000..940a0b950443a0bb1b216ac03c45b8a16c955452 GIT binary patch literal 147 zcmeAS@N?(olHy`uVBq!ia0vp^>_E)H!3HEvS)PKZC{Gv1kP61Pb5HX&C2wk~_T + + + + + +ESP8266_RTOS_SDK: include/espressif/c_types.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
c_types.h
+
+
+
1 /*
+
2  * ESPRSSIF MIT License
+
3  *
+
4  * Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+
5  *
+
6  * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+
7  * it is free of charge, to any person obtaining a copy of this software and associated
+
8  * documentation files (the "Software"), to deal in the Software without restriction, including
+
9  * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+
10  * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
+
11  * to do so, subject to the following conditions:
+
12  *
+
13  * The above copyright notice and this permission notice shall be included in all copies or
+
14  * substantial portions of the Software.
+
15  *
+
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
22  *
+
23  */
+
24 
+
25 #ifndef _C_TYPES_H_
+
26 #define _C_TYPES_H_
+
27 
+
28 #include <stdint.h>
+
29 #include <stdbool.h>
+
30 #include <stddef.h>
+
31 
+
32 #ifdef __cplusplus
+
33 extern "C" {
+
34 #endif
+
35 
+
36 typedef uint8_t u8_t;
+
37 typedef int8_t s8_t;
+
38 typedef uint16_t u16_t;
+
39 typedef int16_t s16_t;
+
40 typedef uint32_t u32_t;
+
41 typedef int32_t s32_t;
+
42 
+
43 typedef uint8_t uint8;
+
44 typedef uint8_t u8;
+
45 typedef int8_t sint8;
+
46 typedef int8_t int8;
+
47 typedef int8_t s8;
+
48 typedef uint16_t uint16;
+
49 typedef uint16_t u16;
+
50 typedef int16_t sint16;
+
51 typedef int16_t s16;
+
52 typedef uint32_t uint32;
+
53 typedef uint32_t u_int;
+
54 typedef uint32_t u32;
+
55 typedef int32_t sint32;
+
56 typedef int32_t s32;
+
57 typedef int32_t int32;
+
58 typedef int64_t sint64;
+
59 typedef uint64_t uint64;
+
60 typedef uint64_t u64;
+
61 typedef float real32;
+
62 typedef double real64;
+
63 
+
64 #define __le16 u16
+
65 
+
66 #define LOCAL static
+
67 
+
68 #ifndef NULL
+
69 #define NULL (void *)0
+
70 #endif /* NULL */
+
71 
+
72 /* probably should not put STATUS here */
+
73 typedef enum {
+
74  OK = 0,
+
75  FAIL,
+
76  PENDING,
+
77  BUSY,
+
78  CANCEL,
+
79 } STATUS;
+
80 
+
81 #define BIT(nr) (1UL << (nr))
+
82 
+
83 #define REG_WRITE(_r, _v) (*(volatile uint32 *)(_r)) = (_v)
+
84 #define REG_READ(_r) (*(volatile uint32 *)(_r))
+
85 
+
86 #define REG_SET_BIT(_r, _b) (*(volatile uint32 *)(_r) |= (_b))
+
87 #define REG_CLR_BIT(_r, _b) (*(volatile uint32 *)(_r) &= ~(_b))
+
88 
+
89 #define __packed __attribute__((packed))
+
90 #define STORE_ATTR __attribute__((aligned(4)))
+
91 
+
92 #define SHMEM_ATTR
+
93 #define ICACHE_FLASH_ATTR
+
94 
+
95 #define DMEM_ATTR __attribute__((section(".bss")))
+
96 #define IRAM_ATTR __attribute__((section(".text")))
+
97 #define ICACHE_RODATA_ATTR __attribute__((section(".irom.text")))
+
98 
+
99 #ifndef __cplusplus
+
100 #define BOOL bool
+
101 #define TRUE true
+
102 #define FALSE false
+
103 #endif /* !__cplusplus */
+
104 
+
105 #ifdef __cplusplus
+
106 }
+
107 #endif
+
108 
+
109 #endif /* _C_TYPES_H_ */
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/classes.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/classes.html new file mode 100644 index 0000000..d897621 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/classes.html @@ -0,0 +1,132 @@ + + + + + + +ESP8266_RTOS_SDK: Data Structure Index + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + +
+ +
+
+ + +
+ +
+ +
+
+
Data Structure Index
+
+
+
A | B | C | D | E | G | I | P | R | S | U | _
+ + + + + + + + + + + + + + + + +
  E  
+
  S  
+
_os_timer_t   
  e  
+
  s  
+
_remot_info   
Event_Info_u   SpiFlashChip   
  a  
+
esp_spiffs_config   scan_config   
Event_SoftAPMode_ProbeReqRecved_t   
  U  
+
espconn   softap_config   
Event_SoftAPMode_StaConnected_t   airkiss_config_t   
  i  
+
station_config   
Event_SoftAPMode_StaDisconnected_t   UART_ConfigTypeDef   
  b  
+
station_info   
Event_StaMode_AuthMode_Change_t   UART_IntrConfTypeDef   ip_info   
  u  
+
Event_StaMode_Connected_t   
  _  
+
bss_info   
  p  
+
Event_StaMode_Disconnected_t   
  c  
+
upgrade_server_info   
Event_StaMode_Got_IP_t   _esp_event   pwm_param   
Event_StaMode_ScanDone_t   _esp_tcp   cmd_s   
  r  
+
  G  
+
_esp_udp   
  d  
+
rst_info   
GPIO_ConfigTypeDef   dhcps_lease   
+
A | B | C | D | E | G | I | P | R | S | U | _
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/closed.png b/Distrib/ESPressif/RTOS/1.5.0/documents/html/closed.png new file mode 100644 index 0000000000000000000000000000000000000000..98cc2c909da37a6df914fbf67780eebd99c597f5 GIT binary patch literal 132 zcmeAS@N?(olHy`uVBq!ia0vp^oFL4>1|%O$WD@{V-kvUwAr*{o@8{^CZMh(5KoB^r_<4^zF@3)Cp&&t3hdujKf f*?bjBoY!V+E))@{xMcbjXe@)LtDnm{r-UW|*e5JT literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/dir_5f1d40343f59d40d6b0768ec5b4dc5c7.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/dir_5f1d40343f59d40d6b0768ec5b4dc5c7.html new file mode 100644 index 0000000..eb76b82 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/dir_5f1d40343f59d40d6b0768ec5b4dc5c7.html @@ -0,0 +1,105 @@ + + + + + + +ESP8266_RTOS_SDK: examples/driver_lib/include Directory Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + +
+
+ + +
+ +
+ + +
+
+
+
include Directory Reference
+
+
+ + + + + + + + +

+Files

file  gpio.h [code]
 
file  hw_timer.h [code]
 
file  uart.h [code]
 
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/dir_997368f752113e5dcdcd9718596161d3.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/dir_997368f752113e5dcdcd9718596161d3.html new file mode 100644 index 0000000..2f954ab --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/dir_997368f752113e5dcdcd9718596161d3.html @@ -0,0 +1,101 @@ + + + + + + +ESP8266_RTOS_SDK: examples/driver_lib Directory Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + +
+
+ + +
+ +
+ + +
+
+
+
driver_lib Directory Reference
+
+
+ + + + +

+Directories

directory  include
 
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/dir_cf4dbf1328d2cf10d3f3933741525dc7.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/dir_cf4dbf1328d2cf10d3f3933741525dc7.html new file mode 100644 index 0000000..601f1f5 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/dir_cf4dbf1328d2cf10d3f3933741525dc7.html @@ -0,0 +1,141 @@ + + + + + + +ESP8266_RTOS_SDK: include/espressif Directory Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + +
+
+ + +
+ +
+ + +
+
+
+
espressif Directory Reference
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Files

file  airkiss.h [code]
 
file  c_types.h [code]
 
file  esp_common.h [code]
 
file  esp_libc.h [code]
 
file  esp_misc.h [code]
 
file  esp_softap.h [code]
 
file  esp_spiffs.h [code]
 
file  esp_ssc.h [code]
 
file  esp_sta.h [code]
 
file  esp_system.h [code]
 
file  esp_timer.h [code]
 
file  esp_wifi.h [code]
 
file  esp_wps.h [code]
 
file  espconn.h [code]
 
file  espnow.h [code]
 
file  mesh.h [code]
 
file  pwm.h [code]
 
file  queue.h [code]
 
file  smartconfig.h [code]
 
file  spi_flash.h [code]
 
file  upgrade.h [code]
 
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/dir_d28a4824dc47e487b107a5db32ef43c4.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/dir_d28a4824dc47e487b107a5db32ef43c4.html new file mode 100644 index 0000000..8994b21 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/dir_d28a4824dc47e487b107a5db32ef43c4.html @@ -0,0 +1,101 @@ + + + + + + +ESP8266_RTOS_SDK: examples Directory Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + +
+
+ + +
+ +
+ + +
+
+
+
examples Directory Reference
+
+
+ + + + +

+Directories

directory  driver_lib
 
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/dir_d44c64559bbebec7f509842c48db8b23.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/dir_d44c64559bbebec7f509842c48db8b23.html new file mode 100644 index 0000000..2d2f550 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/dir_d44c64559bbebec7f509842c48db8b23.html @@ -0,0 +1,101 @@ + + + + + + +ESP8266_RTOS_SDK: include Directory Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + +
+
+ + +
+ +
+ + +
+
+
+
include Directory Reference
+
+
+ + + + +

+Directories

directory  espressif
 
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/doc.png b/Distrib/ESPressif/RTOS/1.5.0/documents/html/doc.png new file mode 100644 index 0000000000000000000000000000000000000000..17edabff95f7b8da13c9516a04efe05493c29501 GIT binary patch literal 746 zcmV7=@pnbNXRFEm&G8P!&WHG=d)>K?YZ1bzou)2{$)) zumDct!>4SyxL;zgaG>wy`^Hv*+}0kUfCrz~BCOViSb$_*&;{TGGn2^x9K*!Sf0=lV zpP=7O;GA0*Jm*tTYj$IoXvimpnV4S1Z5f$p*f$Db2iq2zrVGQUz~yq`ahn7ck(|CE z7Gz;%OP~J6)tEZWDzjhL9h2hdfoU2)Nd%T<5Kt;Y0XLt&<@6pQx!nw*5`@bq#?l*?3z{Hlzoc=Pr>oB5(9i6~_&-}A(4{Q$>c>%rV&E|a(r&;?i5cQB=} zYSDU5nXG)NS4HEs0it2AHe2>shCyr7`6@4*6{r@8fXRbTA?=IFVWAQJL&H5H{)DpM#{W(GL+Idzf^)uRV@oB8u$ z8v{MfJbTiiRg4bza<41NAzrl{=3fl_D+$t+^!xlQ8S}{UtY`e z;;&9UhyZqQRN%2pot{*Ei0*4~hSF_3AH2@fKU!$NSflS>{@tZpDT4`M2WRTTVH+D? z)GFlEGGHe?koB}i|1w45!BF}N_q&^HJ&-tyR{(afC6H7|aml|tBBbv}55C5DNP8p3 z)~jLEO4Z&2hZmP^i-e%(@d!(E|KRafiU8Q5u(wU((j8un3OR*Hvj+t literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/doxygen.css b/Distrib/ESPressif/RTOS/1.5.0/documents/html/doxygen.css new file mode 100644 index 0000000..b2c94ac --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/doxygen.css @@ -0,0 +1,1454 @@ +/* The standard CSS for doxygen 1.8.10 */ + +body, table, div, p, dl { + font: 400 14px/22px Roboto,sans-serif; +} + +/* @group Heading Levels */ + +h1.groupheader { + font-size: 150%; +} + +.title { + font: 400 14px/28px Roboto,sans-serif; + font-size: 150%; + font-weight: bold; + margin: 10px 2px; +} + +h2.groupheader { + border-bottom: 1px solid #879ECB; + color: #354C7B; + font-size: 150%; + font-weight: normal; + margin-top: 1.75em; + padding-top: 8px; + padding-bottom: 4px; + width: 100%; +} + +h3.groupheader { + font-size: 100%; +} + +h1, h2, h3, h4, h5, h6 { + -webkit-transition: text-shadow 0.5s linear; + -moz-transition: text-shadow 0.5s linear; + -ms-transition: text-shadow 0.5s linear; + -o-transition: text-shadow 0.5s linear; + transition: text-shadow 0.5s linear; + margin-right: 15px; +} + +h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow { + text-shadow: 0 0 15px cyan; +} + +dt { + font-weight: bold; +} + +div.multicol { + -moz-column-gap: 1em; + -webkit-column-gap: 1em; + -moz-column-count: 3; + -webkit-column-count: 3; +} + +p.startli, p.startdd { + margin-top: 2px; +} + +p.starttd { + margin-top: 0px; +} + +p.endli { + margin-bottom: 0px; +} + +p.enddd { + margin-bottom: 4px; +} + +p.endtd { + margin-bottom: 2px; +} + +/* @end */ + +caption { + font-weight: bold; +} + +span.legend { + font-size: 70%; + text-align: center; +} + +h3.version { + font-size: 90%; + text-align: center; +} + +div.qindex, div.navtab{ + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; +} + +div.qindex, div.navpath { + width: 100%; + line-height: 140%; +} + +div.navtab { + margin-right: 15px; +} + +/* @group Link Styling */ + +a { + color: #3D578C; + font-weight: normal; + text-decoration: none; +} + +.contents a:visited { + color: #4665A2; +} + +a:hover { + text-decoration: underline; +} + +a.qindex { + font-weight: bold; +} + +a.qindexHL { + font-weight: bold; + background-color: #9CAFD4; + color: #ffffff; + border: 1px double #869DCA; +} + +.contents a.qindexHL:visited { + color: #ffffff; +} + +a.el { + font-weight: bold; +} + +a.elRef { +} + +a.code, a.code:visited, a.line, a.line:visited { + color: #4665A2; +} + +a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited { + color: #4665A2; +} + +/* @end */ + +dl.el { + margin-left: -1cm; +} + +pre.fragment { + border: 1px solid #C4CFE5; + background-color: #FBFCFD; + padding: 4px 6px; + margin: 4px 8px 4px 2px; + overflow: auto; + word-wrap: break-word; + font-size: 9pt; + line-height: 125%; + font-family: monospace, fixed; + font-size: 105%; +} + +div.fragment { + padding: 4px 6px; + margin: 4px 8px 4px 2px; + background-color: #FBFCFD; + border: 1px solid #C4CFE5; +} + +div.line { + font-family: monospace, fixed; + font-size: 13px; + min-height: 13px; + line-height: 1.0; + text-wrap: unrestricted; + white-space: -moz-pre-wrap; /* Moz */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: pre-wrap; /* CSS3 */ + word-wrap: break-word; /* IE 5.5+ */ + text-indent: -53px; + padding-left: 53px; + padding-bottom: 0px; + margin: 0px; + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; +} + +div.line.glow { + background-color: cyan; + box-shadow: 0 0 10px cyan; +} + + +span.lineno { + padding-right: 4px; + text-align: right; + border-right: 2px solid #0F0; + background-color: #E8E8E8; + white-space: pre; +} +span.lineno a { + background-color: #D8D8D8; +} + +span.lineno a:hover { + background-color: #C8C8C8; +} + +div.ah, span.ah { + background-color: black; + font-weight: bold; + color: #ffffff; + margin-bottom: 3px; + margin-top: 3px; + padding: 0.2em; + border: solid thin #333; + border-radius: 0.5em; + -webkit-border-radius: .5em; + -moz-border-radius: .5em; + box-shadow: 2px 2px 3px #999; + -webkit-box-shadow: 2px 2px 3px #999; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); + background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000); +} + +div.classindex ul { + list-style: none; + padding-left: 0; +} + +div.classindex span.ai { + display: inline-block; +} + +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + font-weight: bold; +} + +div.groupText { + margin-left: 16px; + font-style: italic; +} + +body { + background-color: white; + color: black; + margin: 0; +} + +div.contents { + margin-top: 10px; + margin-left: 12px; + margin-right: 8px; +} + +td.indexkey { + background-color: #EBEFF6; + font-weight: bold; + border: 1px solid #C4CFE5; + margin: 2px 0px 2px 0; + padding: 2px 10px; + white-space: nowrap; + vertical-align: top; +} + +td.indexvalue { + background-color: #EBEFF6; + border: 1px solid #C4CFE5; + padding: 2px 10px; + margin: 2px 0px; +} + +tr.memlist { + background-color: #EEF1F7; +} + +p.formulaDsp { + text-align: center; +} + +img.formulaDsp { + +} + +img.formulaInl { + vertical-align: middle; +} + +div.center { + text-align: center; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; +} + +div.center img { + border: 0px; +} + +address.footer { + text-align: right; + padding-right: 12px; +} + +img.footer { + border: 0px; + vertical-align: middle; +} + +/* @group Code Colorization */ + +span.keyword { + color: #008000 +} + +span.keywordtype { + color: #604020 +} + +span.keywordflow { + color: #e08000 +} + +span.comment { + color: #800000 +} + +span.preprocessor { + color: #806020 +} + +span.stringliteral { + color: #002080 +} + +span.charliteral { + color: #008080 +} + +span.vhdldigit { + color: #ff00ff +} + +span.vhdlchar { + color: #000000 +} + +span.vhdlkeyword { + color: #700070 +} + +span.vhdllogic { + color: #ff0000 +} + +blockquote { + background-color: #F7F8FB; + border-left: 2px solid #9CAFD4; + margin: 0 24px 0 4px; + padding: 0 12px 0 16px; +} + +/* @end */ + +/* +.search { + color: #003399; + font-weight: bold; +} + +form.search { + margin-bottom: 0px; + margin-top: 0px; +} + +input.search { + font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} +*/ + +td.tiny { + font-size: 75%; +} + +.dirtab { + padding: 4px; + border-collapse: collapse; + border: 1px solid #A3B4D7; +} + +th.dirtab { + background: #EBEFF6; + font-weight: bold; +} + +hr { + height: 0px; + border: none; + border-top: 1px solid #4A6AAA; +} + +hr.footer { + height: 1px; +} + +/* @group Member Descriptions */ + +table.memberdecls { + border-spacing: 0px; + padding: 0px; +} + +.memberdecls td, .fieldtable tr { + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; +} + +.memberdecls td.glow, .fieldtable tr.glow { + background-color: cyan; + box-shadow: 0 0 15px cyan; +} + +.mdescLeft, .mdescRight, +.memItemLeft, .memItemRight, +.memTemplItemLeft, .memTemplItemRight, .memTemplParams { + background-color: #F9FAFC; + border: none; + margin: 4px; + padding: 1px 0 0 8px; +} + +.mdescLeft, .mdescRight { + padding: 0px 8px 4px 8px; + color: #555; +} + +.memSeparator { + border-bottom: 1px solid #DEE4F0; + line-height: 1px; + margin: 0px; + padding: 0px; +} + +.memItemLeft, .memTemplItemLeft { + white-space: nowrap; +} + +.memItemRight { + width: 100%; +} + +.memTemplParams { + color: #4665A2; + white-space: nowrap; + font-size: 80%; +} + +/* @end */ + +/* @group Member Details */ + +/* Styles for detailed member documentation */ + +.memtemplate { + font-size: 80%; + color: #4665A2; + font-weight: normal; + margin-left: 9px; +} + +.memnav { + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} + +.mempage { + width: 100%; +} + +.memitem { + padding: 0; + margin-bottom: 10px; + margin-right: 5px; + -webkit-transition: box-shadow 0.5s linear; + -moz-transition: box-shadow 0.5s linear; + -ms-transition: box-shadow 0.5s linear; + -o-transition: box-shadow 0.5s linear; + transition: box-shadow 0.5s linear; + display: table !important; + width: 100%; +} + +.memitem.glow { + box-shadow: 0 0 15px cyan; +} + +.memname { + font-weight: bold; + margin-left: 6px; +} + +.memname td { + vertical-align: bottom; +} + +.memproto, dl.reflist dt { + border-top: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + padding: 6px 0px 6px 0px; + color: #253555; + font-weight: bold; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #E2E8F2; + /* opera specific markup */ + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + border-top-right-radius: 4px; + border-top-left-radius: 4px; + /* firefox specific markup */ + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + -moz-border-radius-topright: 4px; + -moz-border-radius-topleft: 4px; + /* webkit specific markup */ + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + -webkit-border-top-right-radius: 4px; + -webkit-border-top-left-radius: 4px; + +} + +.memdoc, dl.reflist dd { + border-bottom: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + padding: 6px 10px 2px 10px; + background-color: #FBFCFD; + border-top-width: 0; + background-image:url('nav_g.png'); + background-repeat:repeat-x; + background-color: #FFFFFF; + /* opera specific markup */ + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + /* firefox specific markup */ + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-bottomright: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + /* webkit specific markup */ + -webkit-border-bottom-left-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); +} + +dl.reflist dt { + padding: 5px; +} + +dl.reflist dd { + margin: 0px 0px 10px 0px; + padding: 5px; +} + +.paramkey { + text-align: right; +} + +.paramtype { + white-space: nowrap; +} + +.paramname { + color: #602020; + white-space: nowrap; +} +.paramname em { + font-style: normal; +} +.paramname code { + line-height: 14px; +} + +.params, .retval, .exception, .tparams { + margin-left: 0px; + padding-left: 0px; +} + +.params .paramname, .retval .paramname { + font-weight: bold; + vertical-align: top; +} + +.params .paramtype { + font-style: italic; + vertical-align: top; +} + +.params .paramdir { + font-family: "courier new",courier,monospace; + vertical-align: top; +} + +table.mlabels { + border-spacing: 0px; +} + +td.mlabels-left { + width: 100%; + padding: 0px; +} + +td.mlabels-right { + vertical-align: bottom; + padding: 0px; + white-space: nowrap; +} + +span.mlabels { + margin-left: 8px; +} + +span.mlabel { + background-color: #728DC1; + border-top:1px solid #5373B4; + border-left:1px solid #5373B4; + border-right:1px solid #C4CFE5; + border-bottom:1px solid #C4CFE5; + text-shadow: none; + color: white; + margin-right: 4px; + padding: 2px 3px; + border-radius: 3px; + font-size: 7pt; + white-space: nowrap; + vertical-align: middle; +} + + + +/* @end */ + +/* these are for tree view inside a (index) page */ + +div.directory { + margin: 10px 0px; + border-top: 1px solid #9CAFD4; + border-bottom: 1px solid #9CAFD4; + width: 100%; +} + +.directory table { + border-collapse:collapse; +} + +.directory td { + margin: 0px; + padding: 0px; + vertical-align: top; +} + +.directory td.entry { + white-space: nowrap; + padding-right: 6px; + padding-top: 3px; +} + +.directory td.entry a { + outline:none; +} + +.directory td.entry a img { + border: none; +} + +.directory td.desc { + width: 100%; + padding-left: 6px; + padding-right: 6px; + padding-top: 3px; + border-left: 1px solid rgba(0,0,0,0.05); +} + +.directory tr.even { + padding-left: 6px; + background-color: #F7F8FB; +} + +.directory img { + vertical-align: -30%; +} + +.directory .levels { + white-space: nowrap; + width: 100%; + text-align: right; + font-size: 9pt; +} + +.directory .levels span { + cursor: pointer; + padding-left: 2px; + padding-right: 2px; + color: #3D578C; +} + +.arrow { + color: #9CAFD4; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + cursor: pointer; + font-size: 80%; + display: inline-block; + width: 16px; + height: 22px; +} + +.icon { + font-family: Arial, Helvetica; + font-weight: bold; + font-size: 12px; + height: 14px; + width: 16px; + display: inline-block; + background-color: #728DC1; + color: white; + text-align: center; + border-radius: 4px; + margin-left: 2px; + margin-right: 2px; +} + +.icona { + width: 24px; + height: 22px; + display: inline-block; +} + +.iconfopen { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:url('folderopen.png'); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +.iconfclosed { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:url('folderclosed.png'); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +.icondoc { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:url('doc.png'); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +table.directory { + font: 400 14px Roboto,sans-serif; +} + +/* @end */ + +div.dynheader { + margin-top: 8px; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +address { + font-style: normal; + color: #2A3D61; +} + +table.doxtable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.doxtable td, table.doxtable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +table.doxtable th { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +table.fieldtable { + /*width: 100%;*/ + margin-bottom: 10px; + border: 1px solid #A8B8D9; + border-spacing: 0px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); + box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); +} + +.fieldtable td, .fieldtable th { + padding: 3px 7px 2px; +} + +.fieldtable td.fieldtype, .fieldtable td.fieldname { + white-space: nowrap; + border-right: 1px solid #A8B8D9; + border-bottom: 1px solid #A8B8D9; + vertical-align: top; +} + +.fieldtable td.fieldname { + padding-top: 3px; +} + +.fieldtable td.fielddoc { + border-bottom: 1px solid #A8B8D9; + /*width: 100%;*/ +} + +.fieldtable td.fielddoc p:first-child { + margin-top: 0px; +} + +.fieldtable td.fielddoc p:last-child { + margin-bottom: 2px; +} + +.fieldtable tr:last-child td { + border-bottom: none; +} + +.fieldtable th { + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #E2E8F2; + font-size: 90%; + color: #253555; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; + -moz-border-radius-topleft: 4px; + -moz-border-radius-topright: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom: 1px solid #A8B8D9; +} + + +.tabsearch { + top: 0px; + left: 10px; + height: 36px; + background-image: url('tab_b.png'); + z-index: 101; + overflow: hidden; + font-size: 13px; +} + +.navpath ul +{ + font-size: 11px; + background-image:url('tab_b.png'); + background-repeat:repeat-x; + background-position: 0 -5px; + height:30px; + line-height:30px; + color:#8AA0CC; + border:solid 1px #C2CDE4; + overflow:hidden; + margin:0px; + padding:0px; +} + +.navpath li +{ + list-style-type:none; + float:left; + padding-left:10px; + padding-right:15px; + background-image:url('bc_s.png'); + background-repeat:no-repeat; + background-position:right; + color:#364D7C; +} + +.navpath li.navelem a +{ + height:32px; + display:block; + text-decoration: none; + outline: none; + color: #283A5D; + font-family: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + text-decoration: none; +} + +.navpath li.navelem a:hover +{ + color:#6884BD; +} + +.navpath li.footer +{ + list-style-type:none; + float:right; + padding-left:10px; + padding-right:15px; + background-image:none; + background-repeat:no-repeat; + background-position:right; + color:#364D7C; + font-size: 8pt; +} + + +div.summary +{ + float: right; + font-size: 8pt; + padding-right: 5px; + width: 50%; + text-align: right; +} + +div.summary a +{ + white-space: nowrap; +} + +div.ingroups +{ + font-size: 8pt; + width: 50%; + text-align: left; +} + +div.ingroups a +{ + white-space: nowrap; +} + +div.header +{ + background-image:url('nav_h.png'); + background-repeat:repeat-x; + background-color: #F9FAFC; + margin: 0px; + border-bottom: 1px solid #C4CFE5; +} + +div.headertitle +{ + padding: 5px 5px 5px 10px; +} + +dl +{ + padding: 0 0 0 10px; +} + +/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug */ +dl.section +{ + margin-left: 0px; + padding-left: 0px; +} + +dl.note +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #D0C000; +} + +dl.warning, dl.attention +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #FF0000; +} + +dl.pre, dl.post, dl.invariant +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #00D000; +} + +dl.deprecated +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #505050; +} + +dl.todo +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #00C0E0; +} + +dl.test +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #3030E0; +} + +dl.bug +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #C08050; +} + +dl.section dd { + margin-bottom: 6px; +} + + +#projectlogo +{ + text-align: center; + vertical-align: bottom; + border-collapse: separate; +} + +#projectlogo img +{ + border: 0px none; +} + +#projectalign +{ + vertical-align: middle; +} + +#projectname +{ + font: 300% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 2px 0px; +} + +#projectbrief +{ + font: 120% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#projectnumber +{ + font: 50% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#titlearea +{ + padding: 0px; + margin: 0px; + width: 100%; + border-bottom: 1px solid #5373B4; +} + +.image +{ + text-align: center; +} + +.dotgraph +{ + text-align: center; +} + +.mscgraph +{ + text-align: center; +} + +.diagraph +{ + text-align: center; +} + +.caption +{ + font-weight: bold; +} + +div.zoom +{ + border: 1px solid #90A5CE; +} + +dl.citelist { + margin-bottom:50px; +} + +dl.citelist dt { + color:#334975; + float:left; + font-weight:bold; + margin-right:10px; + padding:5px; +} + +dl.citelist dd { + margin:2px 0; + padding:5px 0; +} + +div.toc { + padding: 14px 25px; + background-color: #F4F6FA; + border: 1px solid #D8DFEE; + border-radius: 7px 7px 7px 7px; + float: right; + height: auto; + margin: 0 20px 10px 10px; + width: 200px; +} + +div.toc li { + background: url("bdwn.png") no-repeat scroll 0 5px transparent; + font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif; + margin-top: 5px; + padding-left: 10px; + padding-top: 2px; +} + +div.toc h3 { + font: bold 12px/1.2 Arial,FreeSans,sans-serif; + color: #4665A2; + border-bottom: 0 none; + margin: 0; +} + +div.toc ul { + list-style: none outside none; + border: medium none; + padding: 0px; +} + +div.toc li.level1 { + margin-left: 0px; +} + +div.toc li.level2 { + margin-left: 15px; +} + +div.toc li.level3 { + margin-left: 30px; +} + +div.toc li.level4 { + margin-left: 45px; +} + +.inherit_header { + font-weight: bold; + color: gray; + cursor: pointer; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.inherit_header td { + padding: 6px 0px 2px 5px; +} + +.inherit { + display: none; +} + +tr.heading h2 { + margin-top: 12px; + margin-bottom: 4px; +} + +/* tooltip related style info */ + +.ttc { + position: absolute; + display: none; +} + +#powerTip { + cursor: default; + white-space: nowrap; + background-color: white; + border: 1px solid gray; + border-radius: 4px 4px 4px 4px; + box-shadow: 1px 1px 7px gray; + display: none; + font-size: smaller; + max-width: 80%; + opacity: 0.9; + padding: 1ex 1em 1em; + position: absolute; + z-index: 2147483647; +} + +#powerTip div.ttdoc { + color: grey; + font-style: italic; +} + +#powerTip div.ttname a { + font-weight: bold; +} + +#powerTip div.ttname { + font-weight: bold; +} + +#powerTip div.ttdeci { + color: #006318; +} + +#powerTip div { + margin: 0px; + padding: 0px; + font: 12px/16px Roboto,sans-serif; +} + +#powerTip:before, #powerTip:after { + content: ""; + position: absolute; + margin: 0px; +} + +#powerTip.n:after, #powerTip.n:before, +#powerTip.s:after, #powerTip.s:before, +#powerTip.w:after, #powerTip.w:before, +#powerTip.e:after, #powerTip.e:before, +#powerTip.ne:after, #powerTip.ne:before, +#powerTip.se:after, #powerTip.se:before, +#powerTip.nw:after, #powerTip.nw:before, +#powerTip.sw:after, #powerTip.sw:before { + border: solid transparent; + content: " "; + height: 0; + width: 0; + position: absolute; +} + +#powerTip.n:after, #powerTip.s:after, +#powerTip.w:after, #powerTip.e:after, +#powerTip.nw:after, #powerTip.ne:after, +#powerTip.sw:after, #powerTip.se:after { + border-color: rgba(255, 255, 255, 0); +} + +#powerTip.n:before, #powerTip.s:before, +#powerTip.w:before, #powerTip.e:before, +#powerTip.nw:before, #powerTip.ne:before, +#powerTip.sw:before, #powerTip.se:before { + border-color: rgba(128, 128, 128, 0); +} + +#powerTip.n:after, #powerTip.n:before, +#powerTip.ne:after, #powerTip.ne:before, +#powerTip.nw:after, #powerTip.nw:before { + top: 100%; +} + +#powerTip.n:after, #powerTip.ne:after, #powerTip.nw:after { + border-top-color: #ffffff; + border-width: 10px; + margin: 0px -10px; +} +#powerTip.n:before { + border-top-color: #808080; + border-width: 11px; + margin: 0px -11px; +} +#powerTip.n:after, #powerTip.n:before { + left: 50%; +} + +#powerTip.nw:after, #powerTip.nw:before { + right: 14px; +} + +#powerTip.ne:after, #powerTip.ne:before { + left: 14px; +} + +#powerTip.s:after, #powerTip.s:before, +#powerTip.se:after, #powerTip.se:before, +#powerTip.sw:after, #powerTip.sw:before { + bottom: 100%; +} + +#powerTip.s:after, #powerTip.se:after, #powerTip.sw:after { + border-bottom-color: #ffffff; + border-width: 10px; + margin: 0px -10px; +} + +#powerTip.s:before, #powerTip.se:before, #powerTip.sw:before { + border-bottom-color: #808080; + border-width: 11px; + margin: 0px -11px; +} + +#powerTip.s:after, #powerTip.s:before { + left: 50%; +} + +#powerTip.sw:after, #powerTip.sw:before { + right: 14px; +} + +#powerTip.se:after, #powerTip.se:before { + left: 14px; +} + +#powerTip.e:after, #powerTip.e:before { + left: 100%; +} +#powerTip.e:after { + border-left-color: #ffffff; + border-width: 10px; + top: 50%; + margin-top: -10px; +} +#powerTip.e:before { + border-left-color: #808080; + border-width: 11px; + top: 50%; + margin-top: -11px; +} + +#powerTip.w:after, #powerTip.w:before { + right: 100%; +} +#powerTip.w:after { + border-right-color: #ffffff; + border-width: 10px; + top: 50%; + margin-top: -10px; +} +#powerTip.w:before { + border-right-color: #808080; + border-width: 11px; + top: 50%; + margin-top: -11px; +} + +@media print +{ + #top { display: none; } + #side-nav { display: none; } + #nav-path { display: none; } + body { overflow:visible; } + h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } + .summary { display: none; } + .memitem { page-break-inside: avoid; } + #doc-content + { + margin-left:0 !important; + height:auto !important; + width:auto !important; + overflow:inherit; + display:inline; + } +} + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/doxygen.png b/Distrib/ESPressif/RTOS/1.5.0/documents/html/doxygen.png new file mode 100644 index 0000000000000000000000000000000000000000..3ff17d807fd8aa003bed8bb2a69e8f0909592fd1 GIT binary patch literal 3779 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 literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/dynsections.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/dynsections.js new file mode 100644 index 0000000..85e1836 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/dynsections.js @@ -0,0 +1,97 @@ +function toggleVisibility(linkObj) +{ + var base = $(linkObj).attr('id'); + var summary = $('#'+base+'-summary'); + var content = $('#'+base+'-content'); + var trigger = $('#'+base+'-trigger'); + var src=$(trigger).attr('src'); + if (content.is(':visible')===true) { + content.hide(); + summary.show(); + $(linkObj).addClass('closed').removeClass('opened'); + $(trigger).attr('src',src.substring(0,src.length-8)+'closed.png'); + } else { + content.show(); + summary.hide(); + $(linkObj).removeClass('closed').addClass('opened'); + $(trigger).attr('src',src.substring(0,src.length-10)+'open.png'); + } + return false; +} + +function updateStripes() +{ + $('table.directory tr'). + removeClass('even').filter(':visible:even').addClass('even'); +} + +function toggleLevel(level) +{ + $('table.directory tr').each(function() { + var l = this.id.split('_').length-1; + var i = $('#img'+this.id.substring(3)); + var a = $('#arr'+this.id.substring(3)); + if (l + + + + + +ESP8266_RTOS_SDK: include/espressif/esp_common.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
esp_common.h
+
+
+
1 /*
+
2  * ESPRSSIF MIT License
+
3  *
+
4  * Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+
5  *
+
6  * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+
7  * it is free of charge, to any person obtaining a copy of this software and associated
+
8  * documentation files (the "Software"), to deal in the Software without restriction, including
+
9  * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+
10  * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
+
11  * to do so, subject to the following conditions:
+
12  *
+
13  * The above copyright notice and this permission notice shall be included in all copies or
+
14  * substantial portions of the Software.
+
15  *
+
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
22  *
+
23  */
+
24 
+
25 #ifndef __ESP_COMMON_H__
+
26 #define __ESP_COMMON_H__
+
27 
+
94 #include "c_types.h"
+
95 #include "esp_libc.h"
+
96 #include "esp_misc.h"
+
97 #include "esp_wifi.h"
+
98 #include "esp_softap.h"
+
99 #include "esp_sta.h"
+
100 #include "esp_system.h"
+
101 #include "esp_timer.h"
+
102 #include "esp_ssc.h"
+
103 #include "esp_spiffs.h"
+
104 
+
105 #include "esp8266/esp8266.h"
+
106 
+
107 #include "smartconfig.h"
+
108 #include "spi_flash.h"
+
109 #include "pwm.h"
+
110 
+
111 #endif
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__libc_8h_source.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__libc_8h_source.html new file mode 100644 index 0000000..a78936b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__libc_8h_source.html @@ -0,0 +1,185 @@ + + + + + + +ESP8266_RTOS_SDK: include/espressif/esp_libc.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
esp_libc.h
+
+
+
1 /*
+
2  * ESPRSSIF MIT License
+
3  *
+
4  * Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+
5  *
+
6  * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+
7  * it is free of charge, to any person obtaining a copy of this software and associated
+
8  * documentation files (the "Software"), to deal in the Software without restriction, including
+
9  * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+
10  * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
+
11  * to do so, subject to the following conditions:
+
12  *
+
13  * The above copyright notice and this permission notice shall be included in all copies or
+
14  * substantial portions of the Software.
+
15  *
+
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
22  *
+
23  */
+
24 
+
25 #ifndef __ESP_LIBC_H__
+
26 #define __ESP_LIBC_H__
+
27 
+
28 #ifdef __cplusplus
+
29 extern "C" {
+
30 #endif
+
31 
+
32 char *strcpy(char *dst, const char *src);
+
33 char *strncpy(char *dst, const char *src, size_t n);
+
34 int strcmp(const char *s1, const char *s2);
+
35 int strncmp(const char *s1, const char *s2, size_t n);
+
36 size_t strlen(const char *s);
+
37 char *strstr(const char *s1, const char *s2);
+
38 char *strcat(char *dst, const char *src);
+
39 char *strncat(char *dst, const char *src, size_t count);
+
40 size_t strspn(const char *s, const char *accept);
+
41 size_t strcspn(const char *s, const char *reject);
+
42 char *strtok_r(char *s, const char *delim, char **ptrptr);
+
43 char *strtok(char *s, const char *delim);
+
44 char *strrchr(const char *s, int c);
+
45 char *strdup(const char *s);
+
46 char *strchr(const char *s, int c);
+
47 long strtol(const char *str, char **endptr, int base);
+
48 
+
49 void bzero(void *s, size_t n);
+
50 
+
51 void *memcpy(void *dst, const void *src, size_t n);
+
52 void *memset(void *dst, int c, size_t n);
+
53 int memcmp(const void *m1, const void *m2, size_t n);
+
54 void *memmove(void *dst, const void *src, size_t n);
+
55 
+
56 int rand(void);
+
57 
+
58 int printf(const char *format, ...);
+
59 int sprintf(char *out, const char *format, ...);
+
60 int snprintf(char *buf, unsigned int count, const char *format, ...);
+
61 int puts(const char *str);
+
62 
+
63 void *malloc(size_t n);
+
64 void free(void *p);
+
65 void *calloc(size_t c, size_t n);
+
66 void *zalloc(size_t n);
+
67 void *realloc(void *p, size_t n);
+
68 
+
69 int atoi(const char *s);
+
70 long atol(const char *s);
+
71 
+
72 unsigned long os_random(void);
+
73 int os_get_random(unsigned char *buf, size_t len);
+
74 
+
75 /* NOTE: don't use printf_opt in irq handler, for test */
+
76 #define os_printf(fmt, ...) do { \
+
77  static const char flash_str[] ICACHE_RODATA_ATTR STORE_ATTR = fmt; \
+
78  printf(flash_str, ##__VA_ARGS__); \
+
79  } while(0)
+
80 
+
81 #ifdef __cplusplus
+
82 }
+
83 #endif
+
84 
+
85 #endif /* __LIBC_H__ */
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__misc_8h_source.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__misc_8h_source.html new file mode 100644 index 0000000..bfb983d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__misc_8h_source.html @@ -0,0 +1,185 @@ + + + + + + +ESP8266_RTOS_SDK: include/espressif/esp_misc.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
esp_misc.h
+
+
+
1 /*
+
2  * ESPRSSIF MIT License
+
3  *
+
4  * Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+
5  *
+
6  * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+
7  * it is free of charge, to any person obtaining a copy of this software and associated
+
8  * documentation files (the "Software"), to deal in the Software without restriction, including
+
9  * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+
10  * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
+
11  * to do so, subject to the following conditions:
+
12  *
+
13  * The above copyright notice and this permission notice shall be included in all copies or
+
14  * substantial portions of the Software.
+
15  *
+
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
22  *
+
23  */
+
24 
+
25 #ifndef __ESP_MISC_H__
+
26 #define __ESP_MISC_H__
+
27 
+
28 #include "lwip/ip_addr.h"
+
29 
+
30 #ifdef __cplusplus
+
31 extern "C" {
+
32 #endif
+
33 
+
42 #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
+
43 #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
+
44 
+
45 #define IP2STR(ipaddr) ip4_addr1_16(ipaddr), \
+
46  ip4_addr2_16(ipaddr), \
+
47  ip4_addr3_16(ipaddr), \
+
48  ip4_addr4_16(ipaddr)
+
49 
+
50 #define IPSTR "%d.%d.%d.%d"
+
51 
+
59 void os_delay_us(uint16 us);
+
60 
+
72 void os_install_putc1(void (*p)(char c));
+
73 
+
81 void os_putc(char c);
+
82 
+ + + +
86 };
+
87 
+
88 struct dhcps_lease {
+
89  bool enable;
+
90  struct ip_addr start_ip;
+
91  struct ip_addr end_ip;
+
92 };
+
93 
+ +
95  OFFER_START = 0x00,
+
96  OFFER_ROUTER = 0x01,
+ +
98 };
+
99 
+
104 #ifdef __cplusplus
+
105 }
+
106 #endif
+
107 
+
108 #endif
+
void os_putc(char c)
Print a character. Start from from UART0 by default.
+
Definition: esp_misc.h:88
+
Definition: esp_misc.h:96
+
bool enable
Definition: esp_misc.h:89
+
Definition: esp_misc.h:97
+
Definition: esp_misc.h:84
+
struct ip_addr end_ip
Definition: esp_misc.h:91
+
struct ip_addr start_ip
Definition: esp_misc.h:90
+
dhcp_status
Definition: esp_misc.h:83
+
Definition: esp_misc.h:85
+
Definition: esp_misc.h:95
+
void os_delay_us(uint16 us)
Delay function, maximum value: 65535 us.
+
dhcps_offer_option
Definition: esp_misc.h:94
+
void os_install_putc1(void(*p)(char c))
Register the print output function.
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__softap_8h_source.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__softap_8h_source.html new file mode 100644 index 0000000..4c1d09f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__softap_8h_source.html @@ -0,0 +1,219 @@ + + + + + + +ESP8266_RTOS_SDK: include/espressif/esp_softap.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
esp_softap.h
+
+
+
1 /*
+
2  * ESPRSSIF MIT License
+
3  *
+
4  * Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+
5  *
+
6  * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+
7  * it is free of charge, to any person obtaining a copy of this software and associated
+
8  * documentation files (the "Software"), to deal in the Software without restriction, including
+
9  * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+
10  * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
+
11  * to do so, subject to the following conditions:
+
12  *
+
13  * The above copyright notice and this permission notice shall be included in all copies or
+
14  * substantial portions of the Software.
+
15  *
+
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
22  *
+
23  */
+
24 
+
25 #ifndef __ESP_SOFTAP_H__
+
26 #define __ESP_SOFTAP_H__
+
27 
+
28 #include "queue.h"
+
29 
+
30 #ifdef __cplusplus
+
31 extern "C" {
+
32 #endif
+
33 
+
51 struct softap_config {
+
52  uint8 ssid[32];
+
53  uint8 password[64];
+
54  uint8 ssid_len;
+
55  uint8 channel;
+ +
57  uint8 ssid_hidden;
+ +
59  uint16 beacon_interval;
+
60 };
+
61 
+
62 struct station_info {
+ +
65  uint8 bssid[6];
+
66  struct ip_addr ip;
+
67 };
+
68 
+
77 bool wifi_softap_get_config(struct softap_config *config);
+
78 
+ +
88 
+
102 bool wifi_softap_set_config(struct softap_config *config);
+
103 
+
117 bool wifi_softap_set_config_current(struct softap_config *config);
+
118 
+
130 uint8 wifi_softap_get_station_num(void);
+
131 
+ +
144 
+ +
157 
+
172 bool wifi_softap_dhcps_start(void);
+
173 
+
182 bool wifi_softap_dhcps_stop(void);
+
183 
+ +
192 
+
203 bool wifi_softap_get_dhcps_lease(struct dhcps_lease *please);
+
204 
+
222 bool wifi_softap_set_dhcps_lease(struct dhcps_lease *please);
+
223 
+ +
234 
+
245 bool wifi_softap_set_dhcps_lease_time(uint32 minute);
+
246 
+ +
258 
+
276 bool wifi_softap_set_dhcps_offer_option(uint8 level, void *optarg);
+
277 
+
286 #ifdef __cplusplus
+
287 }
+
288 #endif
+
289 
+
290 #endif
+
bool wifi_softap_dhcps_start(void)
Enable the ESP8266 soft-AP DHCP server.
+
bool wifi_softap_set_config(struct softap_config *config)
Set the configuration of the WiFi soft-AP and save it to the Flash.
+
bool wifi_softap_dhcps_stop(void)
Disable the ESP8266 soft-AP DHCP server. The DHCP is enabled by default.
+
AUTH_MODE
Definition: esp_wifi.h:59
+
uint32 wifi_softap_get_dhcps_lease_time(void)
Get ESP8266 soft-AP DHCP server lease time.
+
uint8 ssid[32]
Definition: esp_softap.h:52
+
uint8 password[64]
Definition: esp_softap.h:53
+
Definition: esp_misc.h:88
+
uint8 ssid_hidden
Definition: esp_softap.h:57
+
uint8 channel
Definition: esp_softap.h:55
+
Definition: esp_softap.h:51
+
bool wifi_softap_get_config_default(struct softap_config *config)
Get the configuration of the ESP8266 WiFi soft-AP saved in the flash.
+
bool wifi_softap_set_config_current(struct softap_config *config)
Set the configuration of the WiFi soft-AP; the configuration will not be saved to the Flash...
+
struct station_info * wifi_softap_get_station_info(void)
Get the information of stations connected to the ESP8266 soft-AP, including MAC and IP...
+
uint8 ssid_len
Definition: esp_softap.h:54
+
bool wifi_softap_set_dhcps_lease(struct dhcps_lease *please)
Set the IP range of the ESP8266 soft-AP DHCP server.
+
AUTH_MODE authmode
Definition: esp_softap.h:56
+
bool wifi_softap_get_config(struct softap_config *config)
Get the current configuration of the ESP8266 WiFi soft-AP.
+
dhcp_status
Definition: esp_misc.h:83
+
struct ip_addr ip
Definition: esp_softap.h:66
+
bool wifi_softap_set_dhcps_offer_option(uint8 level, void *optarg)
Set the ESP8266 soft-AP DHCP server option.
+
bool wifi_softap_get_dhcps_lease(struct dhcps_lease *please)
Query the IP range that can be got from the ESP8266 soft-AP DHCP server.
+
uint8 max_connection
Definition: esp_softap.h:58
+
STAILQ_ENTRY(station_info) next
+
bool wifi_softap_set_dhcps_lease_time(uint32 minute)
Set ESP8266 soft-AP DHCP server lease time, default is 120 minutes.
+
uint8 bssid[6]
Definition: esp_softap.h:65
+
uint16 beacon_interval
Definition: esp_softap.h:59
+
enum dhcp_status wifi_softap_dhcps_status(void)
Get the ESP8266 soft-AP DHCP server status.
+
bool wifi_softap_reset_dhcps_lease_time(void)
Reset ESP8266 soft-AP DHCP server lease time which is 120 minutes by default.
+
Definition: esp_softap.h:62
+
void wifi_softap_free_station_info(void)
Free the space occupied by station_info when wifi_softap_get_station_info is called.
+
uint8 wifi_softap_get_station_num(void)
Get the number of stations connected to the ESP8266 soft-AP.
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__spiffs_8h_source.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__spiffs_8h_source.html new file mode 100644 index 0000000..a733932 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__spiffs_8h_source.html @@ -0,0 +1,162 @@ + + + + + + +ESP8266_RTOS_SDK: include/espressif/esp_spiffs.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
esp_spiffs.h
+
+
+
1 /*
+
2  * ESPRSSIF MIT License
+
3  *
+
4  * Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+
5  *
+
6  * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+
7  * it is free of charge, to any person obtaining a copy of this software and associated
+
8  * documentation files (the "Software"), to deal in the Software without restriction, including
+
9  * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+
10  * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
+
11  * to do so, subject to the following conditions:
+
12  *
+
13  * The above copyright notice and this permission notice shall be included in all copies or
+
14  * substantial portions of the Software.
+
15  *
+
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
22  *
+
23  */
+
24 
+
25 #ifndef __ESP_SPIFFS_H__
+
26 #define __ESP_SPIFFS_H__
+
27 
+
28 #include "spiffs/spiffs.h"
+
29 
+
30 #ifdef __cplusplus
+
31 extern "C" {
+
32 #endif
+
33 
+ +
46  uint32 phys_size;
+
47  uint32 phys_addr;
+ +
50  uint32 log_block_size;
+
51  uint32 log_page_size;
+
53  uint32 fd_buf_size;
+
54  uint32 cache_buf_size;
+
55 };
+
56 
+
65 sint32 esp_spiffs_init(struct esp_spiffs_config *config);
+
66 
+
74 void esp_spiffs_deinit(uint8 format);
+
75 
+
80 #ifdef __cplusplus
+
81 }
+
82 #endif
+
83 
+
84 #endif /* __ESP_SPIFFS_H__ */
+
uint32 phys_addr
Definition: esp_spiffs.h:47
+
sint32 esp_spiffs_init(struct esp_spiffs_config *config)
Initialize spiffs.
+
uint32 log_block_size
Definition: esp_spiffs.h:50
+
uint32 phys_erase_block
Definition: esp_spiffs.h:48
+
uint32 fd_buf_size
Definition: esp_spiffs.h:53
+
void esp_spiffs_deinit(uint8 format)
Deinitialize spiffs.
+
uint32 cache_buf_size
Definition: esp_spiffs.h:54
+
uint32 log_page_size
Definition: esp_spiffs.h:51
+
uint32 phys_size
Definition: esp_spiffs.h:46
+
Definition: esp_spiffs.h:45
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__ssc_8h_source.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__ssc_8h_source.html new file mode 100644 index 0000000..31e92e1 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__ssc_8h_source.html @@ -0,0 +1,177 @@ + + + + + + +ESP8266_RTOS_SDK: include/espressif/esp_ssc.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
esp_ssc.h
+
+
+
1 /*
+
2  * ESPRSSIF MIT License
+
3  *
+
4  * Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+
5  *
+
6  * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+
7  * it is free of charge, to any person obtaining a copy of this software and associated
+
8  * documentation files (the "Software"), to deal in the Software without restriction, including
+
9  * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+
10  * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
+
11  * to do so, subject to the following conditions:
+
12  *
+
13  * The above copyright notice and this permission notice shall be included in all copies or
+
14  * substantial portions of the Software.
+
15  *
+
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
22  *
+
23  */
+
24 
+
25 #ifndef __ESP_SSC_H__
+
26 #define __ESP_SSC_H__
+
27 
+
28 #ifdef __cplusplus
+
29 extern "C" {
+
30 #endif
+
31 
+
32 #define CMD_T_ASYNC 0x01
+
33 #define CMD_T_SYNC 0x02
+
34 
+
35 typedef struct cmd_s {
+
36  char *cmd_str;
+
37  uint8 flag;
+
38  uint8 id;
+
39  void (* cmd_func)(void);
+
40  void (* cmd_callback)(void *arg);
+
41 } ssc_cmd_t;
+
42 
+
43 #define MAX_LINE_N 127
+
44 
+
45 typedef enum {
+
46  SSC_BR_9600 = 9600,
+
47  SSC_BR_19200 = 19200,
+
48  SSC_BR_38400 = 38400,
+
49  SSC_BR_57600 = 57600,
+
50  SSC_BR_74880 = 74880,
+
51  SSC_BR_115200 = 115200,
+
52  SSC_BR_230400 = 230400,
+
53  SSC_BR_460800 = 460800,
+
54  SSC_BR_921600 = 921600
+
55 } SscBaudRate;
+
56 
+
76 void ssc_attach(SscBaudRate bandrate);
+
77 
+
85 int ssc_param_len(void);
+
86 
+
94 char *ssc_param_str(void);
+
95 
+
104 int ssc_parse_param(char *pLine, char *argv[]);
+
105 
+
115 void ssc_register(ssc_cmd_t *cmdset, uint8 cmdnum, void (* help)(void));
+
116 
+
121 #ifdef __cplusplus
+
122 }
+
123 #endif
+
124 
+
125 #endif /* __ESP_SSC_H__ */
+
int ssc_parse_param(char *pLine, char *argv[])
Parse the simple serial command (ssc).
+
int ssc_param_len(void)
Get the length of the simple serial command.
+
char * ssc_param_str(void)
Get the simple serial command string.
+
void ssc_register(ssc_cmd_t *cmdset, uint8 cmdnum, void(*help)(void))
Register the user-defined simple serial command (ssc) set.
+
Definition: esp_ssc.h:35
+
void ssc_attach(SscBaudRate bandrate)
Initial the ssc function.
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__sta_8h_source.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__sta_8h_source.html new file mode 100644 index 0000000..1d151e8 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__sta_8h_source.html @@ -0,0 +1,273 @@ + + + + + + +ESP8266_RTOS_SDK: include/espressif/esp_sta.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
esp_sta.h
+
+
+
1 /*
+
2  * ESPRSSIF MIT License
+
3  *
+
4  * Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+
5  *
+
6  * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+
7  * it is free of charge, to any person obtaining a copy of this software and associated
+
8  * documentation files (the "Software"), to deal in the Software without restriction, including
+
9  * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+
10  * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
+
11  * to do so, subject to the following conditions:
+
12  *
+
13  * The above copyright notice and this permission notice shall be included in all copies or
+
14  * substantial portions of the Software.
+
15  *
+
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
22  *
+
23  */
+
24 
+
25 #ifndef __ESP_STA_H__
+
26 #define __ESP_STA_H__
+
27 
+
28 #include "queue.h"
+
29 
+
30 #ifdef __cplusplus
+
31 extern "C" {
+
32 #endif
+
33 
+ +
53  uint8 ssid[32];
+
54  uint8 password[64];
+
55  uint8 bssid_set;
+
56  uint8 bssid[6];
+
57 };
+
58 
+
67 bool wifi_station_get_config(struct station_config *config);
+
68 
+ +
78 
+
96 bool wifi_station_set_config(struct station_config *config);
+
97 
+ +
117 
+
130 bool wifi_station_connect(void);
+
131 
+
143 bool wifi_station_disconnect(void);
+
144 
+
145 struct scan_config {
+
146  uint8 *ssid;
+
147  uint8 *bssid;
+
148  uint8 channel;
+
149  uint8 show_hidden;
+
150 };
+
151 
+
152 struct bss_info {
+
153  STAILQ_ENTRY(bss_info) next;
+
155  uint8 bssid[6];
+
156  uint8 ssid[32];
+
157  uint8 ssid_len;
+
158  uint8 channel;
+
159  sint8 rssi;
+ +
161  uint8 is_hidden;
+
162  sint16 freq_offset;
+
163  sint16 freqcal_val;
+
164  uint8 *esp_mesh_ie;
+
165 };
+
166 
+
176 typedef void (* scan_done_cb_t)(void *arg, STATUS status);
+
177 
+
190 bool wifi_station_scan(struct scan_config *config, scan_done_cb_t cb);
+
191 
+ +
202 
+
219 bool wifi_station_set_auto_connect(bool set);
+
220 
+ +
230 
+
243 bool wifi_station_set_reconnect_policy(bool set);
+
244 
+
245 typedef enum {
+ + + + + + + +
253 
+ +
262 
+ +
271 
+
280 bool wifi_station_ap_change(uint8 current_ap_id);
+
281 
+
294 bool wifi_station_ap_number_set(uint8 ap_number);
+
295 
+
309 uint8 wifi_station_get_ap_info(struct station_config config[]);
+
310 
+
319 sint8 wifi_station_get_rssi(void);
+
320 
+
335 bool wifi_station_dhcpc_start(void);
+
336 
+
351 bool wifi_station_dhcpc_stop(void);
+
352 
+ +
361 
+
370 bool wifi_station_set_hostname(char *name);
+
371 
+
379 char* wifi_station_get_hostname(void);
+
380 
+
389 #ifdef __cplusplus
+
390 }
+
391 #endif
+
392 
+
393 #endif
+
bool wifi_station_get_auto_connect(void)
Check if the ESP8266 station will connect to the recorded AP automatically when the power is on...
+
uint8 channel
Definition: esp_sta.h:148
+
uint8 wifi_station_get_ap_info(struct station_config config[])
Get the information of APs (5 at most) recorded by ESP8266 station.
+
bool wifi_station_connect(void)
Connect the ESP8266 WiFi station to the AP.
+
AUTH_MODE
Definition: esp_wifi.h:59
+
uint8 show_hidden
Definition: esp_sta.h:149
+
bool wifi_station_get_config_default(struct station_config *config)
Get the configuration parameters saved in the Flash of the ESP8266 WiFi station.
+
AUTH_MODE authmode
Definition: esp_sta.h:160
+
bool wifi_station_set_auto_connect(bool set)
Set whether the ESP8266 station will connect to the recorded AP automatically when the power is on...
+
Definition: esp_sta.h:52
+
bool wifi_station_dhcpc_start(void)
Enable the ESP8266 station DHCP client.
+
uint8 channel
Definition: esp_sta.h:158
+
bool wifi_station_set_config_current(struct station_config *config)
Set the configuration of the ESP8266 station. And the configuration will not be saved to the Flash...
+
Definition: esp_sta.h:145
+
uint8 ssid[32]
Definition: esp_sta.h:53
+
Definition: esp_sta.h:250
+
uint8 * bssid
Definition: esp_sta.h:147
+
bool wifi_station_set_reconnect_policy(bool set)
Set whether the ESP8266 station will reconnect to the AP after disconnection. It will do so by defaul...
+
uint8 bssid[6]
Definition: esp_sta.h:56
+
bool wifi_station_scan(struct scan_config *config, scan_done_cb_t cb)
Scan all available APs.
+
STATION_STATUS wifi_station_get_connect_status(void)
Get the connection status of the ESP8266 WiFi station.
+
sint8 rssi
Definition: esp_sta.h:159
+
Definition: esp_sta.h:248
+
uint8 ssid_len
Definition: esp_sta.h:157
+
uint8 * ssid
Definition: esp_sta.h:146
+
uint8 wifi_station_get_current_ap_id(void)
Get the information of APs (5 at most) recorded by ESP8266 station.
+
void(* scan_done_cb_t)(void *arg, STATUS status)
Callback function for wifi_station_scan.
Definition: esp_sta.h:176
+
Definition: esp_sta.h:249
+
bool wifi_station_get_config(struct station_config *config)
Get the current configuration of the ESP8266 WiFi station.
+
bool wifi_station_get_reconnect_policy(void)
Check whether the ESP8266 station will reconnect to the AP after disconnection.
+
Definition: esp_sta.h:246
+
uint8 is_hidden
Definition: esp_sta.h:161
+
char * wifi_station_get_hostname(void)
Get ESP8266 station DHCP hostname.
+
dhcp_status
Definition: esp_misc.h:83
+
STAILQ_ENTRY(bss_info) next
+
uint8 bssid[6]
Definition: esp_sta.h:155
+
bool wifi_station_ap_number_set(uint8 ap_number)
Set the number of APs that can be recorded in the ESP8266 station. When the ESP8266 station is connec...
+
sint16 freq_offset
Definition: esp_sta.h:162
+
Definition: esp_sta.h:247
+
bool wifi_station_set_config(struct station_config *config)
Set the configuration of the ESP8266 station and save it to the Flash.
+
uint8 password[64]
Definition: esp_sta.h:54
+
STATION_STATUS
Definition: esp_sta.h:245
+
enum dhcp_status wifi_station_dhcpc_status(void)
Get the ESP8266 station DHCP client status.
+
Definition: esp_sta.h:251
+
bool wifi_station_disconnect(void)
Disconnect the ESP8266 WiFi station from the AP.
+
bool wifi_station_set_hostname(char *name)
Set ESP8266 station DHCP hostname.
+
uint8 ssid[32]
Definition: esp_sta.h:156
+
sint8 wifi_station_get_rssi(void)
Get rssi of the AP which ESP8266 station connected to.
+
bool wifi_station_dhcpc_stop(void)
Disable the ESP8266 station DHCP client.
+
uint8 bssid_set
Definition: esp_sta.h:55
+
bool wifi_station_ap_change(uint8 current_ap_id)
Switch the ESP8266 station connection to a recorded AP.
+
Definition: esp_sta.h:152
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__system_8h_source.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__system_8h_source.html new file mode 100644 index 0000000..05fbffd --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__system_8h_source.html @@ -0,0 +1,295 @@ + + + + + + +ESP8266_RTOS_SDK: include/espressif/esp_system.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
esp_system.h
+
+
+
1 /*
+
2  * ESPRSSIF MIT License
+
3  *
+
4  * Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+
5  *
+
6  * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+
7  * it is free of charge, to any person obtaining a copy of this software and associated
+
8  * documentation files (the "Software"), to deal in the Software without restriction, including
+
9  * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+
10  * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
+
11  * to do so, subject to the following conditions:
+
12  *
+
13  * The above copyright notice and this permission notice shall be included in all copies or
+
14  * substantial portions of the Software.
+
15  *
+
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
22  *
+
23  */
+
24 
+
25 #ifndef __ESP_SYSTEM_H__
+
26 #define __ESP_SYSTEM_H__
+
27 
+
28 #include "c_types.h"
+
29 
+
30 #ifdef __cplusplus
+
31 extern "C" {
+
32 #endif
+
33 
+
42 typedef enum {
+ + + + + + + +
50 } rst_reason;
+
51 
+
52 struct rst_info {
+ +
54  uint32 exccause;
+
55  uint32 epc1;
+
56  uint32 epc2;
+
57  uint32 epc3;
+
58  uint32 excvaddr;
+
59  uint32 depc;
+
60  uint32 rtn_addr;
+
61 };
+
62 
+
70 struct rst_info *system_get_rst_info(void);
+
71 
+
79 const char *system_get_sdk_version(void);
+
80 
+
92 void system_restore(void);
+
93 
+
101 void system_restart(void);
+
102 
+
119 void system_deep_sleep(uint32 time_in_us);
+
120 
+
141 bool system_deep_sleep_set_option(uint8 option);
+
142 
+
150 uint32 system_get_time(void);
+
151 
+
159 void system_print_meminfo(void);
+
160 
+
168 uint32 system_get_free_heap_size(void);
+
169 
+
177 uint32 system_get_chip_id(void);
+
178 
+
190 uint32 system_rtc_clock_cali_proc(void);
+
191 
+
213 uint32 system_get_rtc_time(void);
+
214 
+
234 bool system_rtc_mem_read(uint8 src, void *dst, uint16 n);
+
235 
+
257 bool system_rtc_mem_write(uint8 dst, const void *src, uint16 n);
+
258 
+
269 void system_uart_swap(void);
+
270 
+
280 void system_uart_de_swap(void);
+
281 
+
298 uint16 system_adc_read(void);
+
299 
+
313 uint16 system_get_vdd33(void);
+
314 
+
336 bool system_param_save_with_protect(uint16 start_sec, void *param, uint16 len);
+
337 
+
361 bool system_param_load(uint16 start_sec, uint16 offset, void *param, uint16 len);
+
362 
+
372 void system_phy_set_max_tpw(uint8 max_tpw);
+
373 
+
385 void system_phy_set_tpw_via_vdd33(uint16 vdd33);
+
386 
+
409 void system_phy_set_rfoption(uint8 option);
+
410 
+
423 uint8 system_upgrade_userbin_check(void);
+
424 
+
432 void system_upgrade_reboot(void);
+
433 
+ +
444 
+
459 void system_upgrade_flag_set(uint8 flag);
+
460 
+
473 #define SYS_BOOT_ENHANCE_MODE 0
+
474 #define SYS_BOOT_NORMAL_MODE 1
+
476 #define SYS_BOOT_NORMAL_BIN 0
+
477 #define SYS_BOOT_TEST_BIN 1
+
489 uint8 system_get_boot_version(void);
+
490 
+
498 uint32 system_get_userbin_addr(void);
+
499 
+
508 uint8 system_get_boot_mode(void);
+
509 
+
524 bool system_restart_enhance(uint8 bin_type, uint32 bin_addr);
+
525 
+
526 typedef enum {
+ + + + + + + + +
535 
+ +
547 
+
548 #define SYS_CPU_80MHZ 80
+
549 #define SYS_CPU_160MHZ 160
+
550 
+
563 bool system_update_cpu_freq(uint8 freq);
+
564 
+
572 uint8 system_get_cpu_freq(void);
+
573 
+
582 #ifdef __cplusplus
+
583 }
+
584 #endif
+
585 
+
586 #endif
+
uint16 system_get_vdd33(void)
Measure the power voltage of VDD3P3 pin 3 and 4, unit : 1/1024 V.
+
uint32 system_get_chip_id(void)
Get the chip ID.
+
void system_uart_swap(void)
UART0 swap.
+
struct rst_info * system_get_rst_info(void)
Get the reason of restart.
+
Definition: esp_system.h:46
+
void system_phy_set_rfoption(uint8 option)
Enable RF or not when wakeup from deep-sleep.
+
void system_print_meminfo(void)
Print the system memory distribution, including data/rodata/bss/heap.
+
Definition: esp_system.h:528
+
Definition: esp_system.h:49
+
Definition: esp_system.h:47
+
Definition: esp_system.h:530
+
void system_upgrade_flag_set(uint8 flag)
Set the upgrade status flag.
+
Definition: esp_system.h:533
+
void system_restore(void)
Reset to default settings.
+
Definition: esp_system.h:48
+
uint8 system_get_cpu_freq(void)
Get CPU frequency.
+
uint8 system_get_boot_mode(void)
Get the boot mode.
+
uint8 system_upgrade_flag_check()
Check the upgrade status flag.
+
Definition: esp_system.h:52
+
uint32 system_get_free_heap_size(void)
Get the size of available heap.
+
Definition: esp_system.h:44
+
bool system_param_save_with_protect(uint16 start_sec, void *param, uint16 len)
Write data into flash with protection.
+
Definition: esp_system.h:529
+
void system_phy_set_tpw_via_vdd33(uint16 vdd33)
Adjust the RF TX Power according to VDD33, unit : 1/1024 V.
+
Definition: esp_system.h:532
+
uint16 system_adc_read(void)
Measure the input voltage of TOUT pin 6, unit : 1/1024 V.
+
uint32 system_get_userbin_addr(void)
Get the address of the current running user bin (user1.bin or user2.bin).
+
flash_size_map
Definition: esp_system.h:526
+
void system_restart(void)
Restart system.
+
void system_deep_sleep(uint32 time_in_us)
Set the chip to deep-sleep mode.
+
rst_reason reason
Definition: esp_system.h:53
+
bool system_param_load(uint16 start_sec, uint16 offset, void *param, uint16 len)
Read the data saved into flash with the read/write protection.
+
bool system_restart_enhance(uint8 bin_type, uint32 bin_addr)
Restarts the system, and enters the enhanced boot mode.
+
uint32 system_get_rtc_time(void)
Get RTC time, unit: RTC clock cycle.
+
bool system_deep_sleep_set_option(uint8 option)
Call this API before system_deep_sleep to set the activity after the next deep-sleep wakeup...
+
uint32 system_get_time(void)
Get system time, unit: microsecond.
+
bool system_rtc_mem_write(uint8 dst, const void *src, uint16 n)
Write user data to the RTC memory.
+
bool system_update_cpu_freq(uint8 freq)
Set CPU frequency. Default is 80MHz.
+
Definition: esp_system.h:43
+
rst_reason
Definition: esp_system.h:42
+
Definition: esp_system.h:531
+
Definition: esp_system.h:527
+
void system_upgrade_reboot(void)
Reboot system to use the new software.
+
bool system_rtc_mem_read(uint8 src, void *dst, uint16 n)
Read user data from the RTC memory.
+
void system_phy_set_max_tpw(uint8 max_tpw)
Set the maximum value of RF TX Power, unit : 0.25dBm.
+
flash_size_map system_get_flash_size_map(void)
Get the current Flash size and Flash map.
+
Definition: esp_system.h:45
+
const char * system_get_sdk_version(void)
Get information of the SDK version.
+
uint32 system_rtc_clock_cali_proc(void)
Get the RTC clock cycle.
+
uint8 system_upgrade_userbin_check(void)
Check the user bin.
+
void system_uart_de_swap(void)
Disable UART0 swap.
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__timer_8h_source.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__timer_8h_source.html new file mode 100644 index 0000000..1a2f61a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__timer_8h_source.html @@ -0,0 +1,159 @@ + + + + + + +ESP8266_RTOS_SDK: include/espressif/esp_timer.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
esp_timer.h
+
+
+
1 /*
+
2  * ESPRSSIF MIT License
+
3  *
+
4  * Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+
5  *
+
6  * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+
7  * it is free of charge, to any person obtaining a copy of this software and associated
+
8  * documentation files (the "Software"), to deal in the Software without restriction, including
+
9  * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+
10  * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
+
11  * to do so, subject to the following conditions:
+
12  *
+
13  * The above copyright notice and this permission notice shall be included in all copies or
+
14  * substantial portions of the Software.
+
15  *
+
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
22  *
+
23  */
+
24 
+
25 #ifndef __ESP_TIMER_H__
+
26 #define __ESP_TIMER_H__
+
27 
+
28 #ifdef __cplusplus
+
29 extern "C" {
+
30 #endif
+
31 
+
32 /* timer related */
+
33 typedef void os_timer_func_t(void *timer_arg);
+
34 
+
35 typedef struct _os_timer_t {
+
36  struct _os_timer_t *timer_next;
+
37  void *timer_handle;
+
38  uint32 timer_expire;
+
39  uint32 timer_period;
+
40  os_timer_func_t *timer_func;
+
41  bool timer_repeat_flag;
+
42  void *timer_arg;
+
43 } os_timer_t;
+
44 
+
71 void os_timer_setfn(os_timer_t *ptimer, os_timer_func_t *pfunction, void *parg);
+
72 
+
82 void os_timer_arm(os_timer_t *ptimer, uint32 msec, bool repeat_flag);
+
83 
+
91 void os_timer_disarm(os_timer_t *ptimer);
+
92 
+
97 #ifdef __cplusplus
+
98 }
+
99 #endif
+
100 
+
101 #endif
+
void os_timer_setfn(os_timer_t *ptimer, os_timer_func_t *pfunction, void *parg)
Set the timer callback function.
+
Definition: esp_timer.h:35
+
void os_timer_arm(os_timer_t *ptimer, uint32 msec, bool repeat_flag)
Enable the millisecond timer.
+
void os_timer_disarm(os_timer_t *ptimer)
Disarm the timer.
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__wifi_8h_source.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__wifi_8h_source.html new file mode 100644 index 0000000..db19753 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__wifi_8h_source.html @@ -0,0 +1,583 @@ + + + + + + +ESP8266_RTOS_SDK: include/espressif/esp_wifi.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
esp_wifi.h
+
+
+
1 /*
+
2  * ESPRSSIF MIT License
+
3  *
+
4  * Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+
5  *
+
6  * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+
7  * it is free of charge, to any person obtaining a copy of this software and associated
+
8  * documentation files (the "Software"), to deal in the Software without restriction, including
+
9  * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+
10  * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
+
11  * to do so, subject to the following conditions:
+
12  *
+
13  * The above copyright notice and this permission notice shall be included in all copies or
+
14  * substantial portions of the Software.
+
15  *
+
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
22  *
+
23  */
+
24 
+
25 #ifndef __ESP_WIFI_H__
+
26 #define __ESP_WIFI_H__
+
27 
+
28 #ifdef __cplusplus
+
29 extern "C" {
+
30 #endif
+
31 
+
51 typedef enum {
+
52  NULL_MODE = 0,
+ + + +
56  MAX_MODE
+
57 } WIFI_MODE;
+
58 
+
59 typedef enum {
+
60  AUTH_OPEN = 0,
+ + + + +
65  AUTH_MAX
+
66 } AUTH_MODE;
+
67 
+ +
79 
+ +
91 
+
108 bool wifi_set_opmode(WIFI_MODE opmode);
+
109 
+ +
125 
+
126 typedef enum {
+ + +
129  MAX_IF
+ +
131 
+
132 struct ip_info {
+
133  struct ip_addr ip;
+
134  struct ip_addr netmask;
+
135  struct ip_addr gw;
+
136 };
+
137 
+
150 bool wifi_get_ip_info(WIFI_INTERFACE if_index, struct ip_info *info);
+
151 
+
169 bool wifi_set_ip_info(WIFI_INTERFACE if_index, struct ip_info *info);
+
170 
+
181 bool wifi_get_macaddr(WIFI_INTERFACE if_index, uint8 *macaddr);
+
182 
+
199 bool wifi_set_macaddr(WIFI_INTERFACE if_index, uint8 *macaddr);
+
200 
+
210 void wifi_status_led_install(uint8 gpio_id, uint32 gpio_name, uint8 gpio_func);
+
211 
+
219 void wifi_status_led_uninstall(void);
+
220 
+
221 typedef enum {
+ + + +
225 } WIFI_PHY_MODE;
+
226 
+ +
235 
+ +
247 
+
248 typedef enum {
+ + + + + + + + + +
258  EVENT_MAX
+
259 } SYSTEM_EVENT;
+
260 
+
261 enum {
+
262  REASON_UNSPECIFIED = 1,
+
263  REASON_AUTH_EXPIRE = 2,
+
264  REASON_AUTH_LEAVE = 3,
+
265  REASON_ASSOC_EXPIRE = 4,
+
266  REASON_ASSOC_TOOMANY = 5,
+
267  REASON_NOT_AUTHED = 6,
+
268  REASON_NOT_ASSOCED = 7,
+
269  REASON_ASSOC_LEAVE = 8,
+
270  REASON_ASSOC_NOT_AUTHED = 9,
+
271  REASON_DISASSOC_PWRCAP_BAD = 10,
+
272  REASON_DISASSOC_SUPCHAN_BAD = 11,
+
273  REASON_IE_INVALID = 13,
+
274  REASON_MIC_FAILURE = 14,
+
275  REASON_4WAY_HANDSHAKE_TIMEOUT = 15,
+
276  REASON_GROUP_KEY_UPDATE_TIMEOUT = 16,
+
277  REASON_IE_IN_4WAY_DIFFERS = 17,
+
278  REASON_GROUP_CIPHER_INVALID = 18,
+
279  REASON_PAIRWISE_CIPHER_INVALID = 19,
+
280  REASON_AKMP_INVALID = 20,
+
281  REASON_UNSUPP_RSN_IE_VERSION = 21,
+
282  REASON_INVALID_RSN_IE_CAP = 22,
+
283  REASON_802_1X_AUTH_FAILED = 23,
+
284  REASON_CIPHER_SUITE_REJECTED = 24,
+
285 
+
286  REASON_BEACON_TIMEOUT = 200,
+
287  REASON_NO_AP_FOUND = 201,
+
288  REASON_AUTH_FAIL = 202,
+
289  REASON_ASSOC_FAIL = 203,
+
290  REASON_HANDSHAKE_TIMEOUT = 204,
+
291 };
+
292 
+
293 typedef struct {
+
294  uint32 status;
+
295  struct bss_info *bss;
+ +
297 
+
298 typedef struct {
+
299  uint8 ssid[32];
+
300  uint8 ssid_len;
+
301  uint8 bssid[6];
+
302  uint8 channel;
+ +
304 
+
305 typedef struct {
+
306  uint8 ssid[32];
+
307  uint8 ssid_len;
+
308  uint8 bssid[6];
+
309  uint8 reason;
+ +
311 
+
312 typedef struct {
+
313  uint8 old_mode;
+
314  uint8 new_mode;
+ +
316 
+
317 typedef struct {
+
318  struct ip_addr ip;
+
319  struct ip_addr mask;
+
320  struct ip_addr gw;
+ +
322 
+
323 typedef struct {
+
324  uint8 mac[6];
+
325  uint8 aid;
+ +
327 
+
328 typedef struct {
+
329  uint8 mac[6];
+
330  uint8 aid;
+ +
332 
+
333 typedef struct {
+
334  int rssi;
+
335  uint8 mac[6];
+ +
337 
+
338 typedef union {
+ + + + + + + + +
347 } Event_Info_u;
+
348 
+
349 typedef struct _esp_event {
+ + + +
353 
+
364 typedef void (* wifi_event_handler_cb_t)(System_Event_t *event);
+
365 
+ +
375 
+
383 typedef void (*freedom_outside_cb_t)(uint8 status);
+
384 
+ +
397 
+ +
406 
+
429 sint32 wifi_send_pkt_freedom(uint8 *buf, uint16 len, bool sys_seq);
+
430 
+
439 sint32 wifi_rfid_locp_recv_open(void);
+
440 
+
448 void wifi_rfid_locp_recv_close(void);
+
449 
+
459 typedef void (*rfid_locp_cb_t)(uint8 *frm, int len, sint8 rssi);
+
460 
+ +
473 
+ +
482 
+
483 typedef enum {
+
484  NONE_SLEEP_T = 0,
+
485  LIGHT_SLEEP_T,
+
486  MODEM_SLEEP_T
+
487 } sleep_type;
+
488 
+
501 bool wifi_set_sleep_type(sleep_type type);
+
502 
+
510 sleep_type wifi_get_sleep_type(void);
+
511 
+
534 void wifi_fpm_open(void);
+
535 
+
543 void wifi_fpm_close(void);
+
544 
+
556 void wifi_fpm_do_wakeup(void);
+
557 
+
558 typedef void (*fpm_wakeup_cb)(void);
+
559 
+
575 void wifi_fpm_set_wakeup_cb(fpm_wakeup_cb cb);
+
576 
+
597 sint8 wifi_fpm_do_sleep(uint32 sleep_time_in_us);
+
598 
+
608 void wifi_fpm_set_sleep_type(sleep_type type);
+
609 
+
617 sleep_type wifi_fpm_get_sleep_type(void);
+
618 
+
631 enum FIXED_RATE {
+
632  PHY_RATE_48 = 0x8,
+
633  PHY_RATE_24 = 0x9,
+
634  PHY_RATE_12 = 0xA,
+
635  PHY_RATE_6 = 0xB,
+
636  PHY_RATE_54 = 0xC,
+
637  PHY_RATE_36 = 0xD,
+
638  PHY_RATE_18 = 0xE,
+
639  PHY_RATE_9 = 0xF
+
640 };
+
641 
+
642 #define FIXED_RATE_MASK_NONE 0x00
+
643 #define FIXED_RATE_MASK_STA 0x01
+
644 #define FIXED_RATE_MASK_AP 0x02
+
645 #define FIXED_RATE_MASK_ALL 0x03
+
646 
+
666 sint32 wifi_set_user_fixed_rate(uint8 enable_mask, uint8 rate);
+
667 
+
677 int wifi_get_user_fixed_rate(uint8 *enable_mask, uint8 *rate);
+
678 
+
679 enum support_rate {
+
680  RATE_11B5M = 0,
+
681  RATE_11B11M = 1,
+
682  RATE_11B1M = 2,
+
683  RATE_11B2M = 3,
+
684  RATE_11G6M = 4,
+
685  RATE_11G12M = 5,
+
686  RATE_11G24M = 6,
+
687  RATE_11G48M = 7,
+
688  RATE_11G54M = 8,
+
689  RATE_11G9M = 9,
+
690  RATE_11G18M = 10,
+
691  RATE_11G36M = 11
+
692 };
+
693 
+
711 sint32 wifi_set_user_sup_rate(uint8 min, uint8 max);
+
712 
+
713 enum RATE_11B_ID {
+
714  RATE_11B_B11M = 0,
+
715  RATE_11B_B5M = 1,
+
716  RATE_11B_B2M = 2,
+
717  RATE_11B_B1M = 3
+
718 };
+
719 
+
720 enum RATE_11G_ID {
+
721  RATE_11G_G54M = 0,
+
722  RATE_11G_G48M = 1,
+
723  RATE_11G_G36M = 2,
+
724  RATE_11G_G24M = 3,
+
725  RATE_11G_G18M = 4,
+
726  RATE_11G_G12M = 5,
+
727  RATE_11G_G9M = 6,
+
728  RATE_11G_G6M = 7,
+
729  RATE_11G_B5M = 8,
+
730  RATE_11G_B2M = 9,
+
731  RATE_11G_B1M = 10
+
732 };
+
733 
+
734 enum RATE_11N_ID {
+
735  RATE_11N_MCS7S = 0,
+
736  RATE_11N_MCS7 = 1,
+
737  RATE_11N_MCS6 = 2,
+
738  RATE_11N_MCS5 = 3,
+
739  RATE_11N_MCS4 = 4,
+
740  RATE_11N_MCS3 = 5,
+
741  RATE_11N_MCS2 = 6,
+
742  RATE_11N_MCS1 = 7,
+
743  RATE_11N_MCS0 = 8,
+
744  RATE_11N_B5M = 9,
+
745  RATE_11N_B2M = 10,
+
746  RATE_11N_B1M = 11
+
747 };
+
748 
+
749 #define RC_LIMIT_11B 0
+
750 #define RC_LIMIT_11G 1
+
751 #define RC_LIMIT_11N 2
+
752 #define RC_LIMIT_P2P_11G 3
+
753 #define RC_LIMIT_P2P_11N 4
+
754 #define RC_LIMIT_NUM 5
+
755 
+
756 #define LIMIT_RATE_MASK_NONE 0x00
+
757 #define LIMIT_RATE_MASK_STA 0x01
+
758 #define LIMIT_RATE_MASK_AP 0x02
+
759 #define LIMIT_RATE_MASK_ALL 0x03
+
760 
+
784 bool wifi_set_user_rate_limit(uint8 mode, uint8 ifidx, uint8 max, uint8 min);
+
785 
+ +
798 
+
812 bool wifi_set_user_limit_rate_mask(uint8 enable_mask);
+
813 
+
827 typedef enum {
+
828  USER_IE_BEACON = 0,
+
829  USER_IE_PROBE_REQ,
+
830  USER_IE_PROBE_RESP,
+
831  USER_IE_ASSOC_REQ,
+
832  USER_IE_ASSOC_RESP,
+
833  USER_IE_MAX
+
834 } user_ie_type;
+
835 
+
848 typedef void (*user_ie_manufacturer_recv_cb_t)(user_ie_type type, const uint8 sa[6], const uint8 m_oui[3], uint8 *ie, uint8 ie_len, sint32 rssi);
+
849 
+
871 bool wifi_set_user_ie(bool enable, uint8 *m_oui, user_ie_type type, uint8 *user_ie, uint8 len);
+
872 
+ +
882 
+ +
891 
+
914 typedef void (* wifi_promiscuous_cb_t)(uint8 *buf, uint16 len);
+
915 
+ +
926 
+
934 uint8 wifi_get_channel(void);
+
935 
+
944 bool wifi_set_channel(uint8 channel);
+
945 
+
958 bool wifi_promiscuous_set_mac(const uint8_t *address);
+
959 
+
975 void wifi_promiscuous_enable(uint8 promiscuous);
+
976 
+
985 #ifdef __cplusplus
+
986 }
+
987 #endif
+
988 
+
989 #endif
+
void(* user_ie_manufacturer_recv_cb_t)(user_ie_type type, const uint8 sa[6], const uint8 m_oui[3], uint8 *ie, uint8 ie_len, sint32 rssi)
User IE received callback.
Definition: esp_wifi.h:848
+
void wifi_fpm_close(void)
Disable force sleep function.
+
bool wifi_set_opmode_current(WIFI_MODE opmode)
Set the WiFi operating mode, and will not save it to Flash.
+
Definition: esp_wifi.h:132
+
Definition: esp_wifi.h:64
+
int rssi
Definition: esp_wifi.h:334
+
WIFI_MODE
Definition: esp_wifi.h:51
+
Definition: esp_wifi.h:298
+
Definition: esp_wifi.h:293
+
bool wifi_set_phy_mode(WIFI_PHY_MODE mode)
Set the ESP8266 physical mode (802.11b/g/n).
+
void wifi_promiscuous_enable(uint8 promiscuous)
Enable the promiscuous mode.
+
Definition: esp_wifi.h:256
+
Definition: esp_wifi.h:349
+
void wifi_status_led_install(uint8 gpio_id, uint32 gpio_name, uint8 gpio_func)
Install the WiFi status LED.
+
Definition: esp_wifi.h:250
+
struct bss_info * bss
Definition: esp_wifi.h:295
+
Definition: esp_wifi.h:323
+
Definition: esp_wifi.h:257
+
uint8 reason
Definition: esp_wifi.h:309
+
sint32 wifi_set_user_sup_rate(uint8 min, uint8 max)
Set the support rate of ESP8266.
+
AUTH_MODE
Definition: esp_wifi.h:59
+
void wifi_rfid_locp_recv_close(void)
Disable RFID LOCP (Location Control Protocol) .
+
Definition: esp_wifi.h:128
+
Definition: esp_wifi.h:252
+
struct ip_addr ip
Definition: esp_wifi.h:133
+
bool wifi_set_user_rate_limit(uint8 mode, uint8 ifidx, uint8 max, uint8 min)
Limit the initial rate of sending data from ESP8266.
+
void(* rfid_locp_cb_t)(uint8 *frm, int len, sint8 rssi)
RFID LOCP (Location Control Protocol) receive callback .
Definition: esp_wifi.h:459
+
uint8 new_mode
Definition: esp_wifi.h:314
+
void wifi_status_led_uninstall(void)
Uninstall the WiFi status LED.
+
uint8 channel
Definition: esp_wifi.h:302
+
sint32 wifi_set_user_fixed_rate(uint8 enable_mask, uint8 rate)
Set the fixed rate and mask of sending data from ESP8266.
+
Definition: esp_wifi.h:255
+
uint32 status
Definition: esp_wifi.h:294
+
struct ip_addr gw
Definition: esp_wifi.h:135
+
Definition: esp_wifi.h:54
+
Definition: esp_wifi.h:253
+
WIFI_MODE wifi_get_opmode(void)
Get the current operating mode of the WiFi.
+
bool wifi_set_sleep_type(sleep_type type)
Sets sleep type.
+
sint32 wifi_register_rfid_locp_recv_cb(rfid_locp_cb_t cb)
Register a callback of receiving WDS packets.
+
Definition: esp_wifi.h:251
+
Definition: esp_wifi.h:305
+
sint32 wifi_register_send_pkt_freedom_cb(freedom_outside_cb_t cb)
Register a callback for sending user-define 802.11 packets.
+
bool wifi_set_ip_info(WIFI_INTERFACE if_index, struct ip_info *info)
Set the IP address of the ESP8266 WiFi station or the soft-AP interface.
+
sleep_type wifi_fpm_get_sleep_type(void)
Get sleep type of force sleep function.
+
void(* wifi_promiscuous_cb_t)(uint8 *buf, uint16 len)
The RX callback function in the promiscuous mode.
Definition: esp_wifi.h:914
+
Definition: esp_wifi.h:53
+
void wifi_unregister_send_pkt_freedom_cb(void)
Unregister the callback for sending user-define 802.11 packets.
+
Definition: esp_wifi.h:60
+
bool wifi_set_channel(uint8 channel)
Set the channel number for sniffer functions.
+
bool wifi_set_event_handler_cb(wifi_event_handler_cb_t cb)
Register the Wi-Fi event handler.
+
bool wifi_promiscuous_set_mac(const uint8_t *address)
Set the MAC address filter for the sniffer mode.
+
Event_StaMode_Disconnected_t disconnected
Definition: esp_wifi.h:341
+
bool wifi_set_opmode(WIFI_MODE opmode)
Set the WiFi operating mode, and save it to Flash.
+
Event_Info_u event_info
Definition: esp_wifi.h:351
+
bool wifi_set_user_limit_rate_mask(uint8 enable_mask)
Set the interfaces of ESP8266 whose rate of sending packets is limited by wifi_set_user_rate_limit.
+
WIFI_PHY_MODE wifi_get_phy_mode(void)
Get the ESP8266 physical mode (802.11b/g/n).
+
uint8 ssid_len
Definition: esp_wifi.h:307
+
Event_StaMode_Got_IP_t got_ip
Definition: esp_wifi.h:343
+
void(* freedom_outside_cb_t)(uint8 status)
Callback of sending user-define 802.11 packets.
Definition: esp_wifi.h:383
+
uint8 wifi_get_channel(void)
Get the channel number for sniffer functions.
+
void wifi_unregister_user_ie_manufacturer_recv_cb(void)
Unregister user IE received callback.
+
uint8 wifi_get_user_limit_rate_mask(void)
Get the interfaces of ESP8266 whose rate of sending data is limited by wifi_set_user_rate_limit.
+
Event_SoftAPMode_ProbeReqRecved_t ap_probereqrecved
Definition: esp_wifi.h:346
+
void wifi_fpm_set_sleep_type(sleep_type type)
Set sleep type for force sleep function.
+
bool wifi_set_macaddr(WIFI_INTERFACE if_index, uint8 *macaddr)
Set MAC address of the ESP8266 WiFi station or the soft-AP interface.
+
Definition: esp_wifi.h:338
+
Definition: esp_wifi.h:249
+
void wifi_fpm_do_wakeup(void)
Wake ESP8266 up from MODEM_SLEEP_T force sleep.
+
Definition: esp_wifi.h:222
+
Event_SoftAPMode_StaDisconnected_t sta_disconnected
Definition: esp_wifi.h:345
+
void wifi_unregister_rfid_locp_recv_cb(void)
Unregister the callback of receiving WDS packets.
+
uint8 bssid[6]
Definition: esp_sta.h:155
+
sint32 wifi_register_user_ie_manufacturer_recv_cb(user_ie_manufacturer_recv_cb_t cb)
Register user IE received callback.
+
sleep_type wifi_get_sleep_type(void)
Gets sleep type.
+
Definition: esp_wifi.h:317
+
Definition: esp_wifi.h:254
+
void wifi_fpm_open(void)
Enable force sleep function.
+
bool wifi_get_ip_info(WIFI_INTERFACE if_index, struct ip_info *info)
Get the IP address of the ESP8266 WiFi station or the soft-AP interface.
+
Definition: esp_wifi.h:52
+
uint8 old_mode
Definition: esp_wifi.h:313
+
WIFI_INTERFACE
Definition: esp_wifi.h:126
+
uint8 aid
Definition: esp_wifi.h:330
+
WIFI_MODE wifi_get_opmode_default(void)
Get the operating mode of the WiFi saved in the Flash.
+
void wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb)
Register the RX callback function in the promiscuous mode.
+
Definition: esp_wifi.h:127
+
bool wifi_set_user_ie(bool enable, uint8 *m_oui, user_ie_type type, uint8 *user_ie, uint8 len)
Set user IE of ESP8266.
+
void(* wifi_event_handler_cb_t)(System_Event_t *event)
The Wi-Fi event handler.
Definition: esp_wifi.h:364
+
Definition: esp_wifi.h:55
+
uint8 aid
Definition: esp_wifi.h:325
+
int wifi_get_user_fixed_rate(uint8 *enable_mask, uint8 *rate)
Get the fixed rate and mask of ESP8266.
+
sint32 wifi_rfid_locp_recv_open(void)
Enable RFID LOCP (Location Control Protocol) to receive WDS packets.
+
void wifi_fpm_set_wakeup_cb(fpm_wakeup_cb cb)
Set a callback of waken up from force sleep because of time out.
+
Definition: esp_wifi.h:62
+
Event_StaMode_Connected_t connected
Definition: esp_wifi.h:340
+
Event_StaMode_AuthMode_Change_t auth_change
Definition: esp_wifi.h:342
+
Definition: esp_wifi.h:224
+
Definition: esp_wifi.h:61
+
Definition: esp_wifi.h:312
+
Event_SoftAPMode_StaConnected_t sta_connected
Definition: esp_wifi.h:344
+
sint32 wifi_send_pkt_freedom(uint8 *buf, uint16 len, bool sys_seq)
Send user-define 802.11 packets.
+
uint8 ssid[32]
Definition: esp_sta.h:156
+
Definition: esp_wifi.h:333
+
Definition: esp_wifi.h:223
+
Definition: esp_wifi.h:63
+
SYSTEM_EVENT event_id
Definition: esp_wifi.h:350
+
WIFI_PHY_MODE
Definition: esp_wifi.h:221
+
Event_StaMode_ScanDone_t scan_done
Definition: esp_wifi.h:339
+
Definition: esp_wifi.h:328
+
Definition: esp_sta.h:152
+
sint8 wifi_fpm_do_sleep(uint32 sleep_time_in_us)
Force ESP8266 enter sleep mode, and it will wake up automatically when time out.
+
SYSTEM_EVENT
Definition: esp_wifi.h:248
+
bool wifi_get_macaddr(WIFI_INTERFACE if_index, uint8 *macaddr)
Get MAC address of the ESP8266 WiFi station or the soft-AP interface.
+
uint8 ssid_len
Definition: esp_wifi.h:300
+
struct ip_addr netmask
Definition: esp_wifi.h:134
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__wps_8h_source.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__wps_8h_source.html new file mode 100644 index 0000000..48e5d58 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/esp__wps_8h_source.html @@ -0,0 +1,173 @@ + + + + + + +ESP8266_RTOS_SDK: include/espressif/esp_wps.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
esp_wps.h
+
+
+
1 /*
+
2  * ESPRSSIF MIT License
+
3  *
+
4  * Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+
5  *
+
6  * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+
7  * it is free of charge, to any person obtaining a copy of this software and associated
+
8  * documentation files (the "Software"), to deal in the Software without restriction, including
+
9  * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+
10  * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
+
11  * to do so, subject to the following conditions:
+
12  *
+
13  * The above copyright notice and this permission notice shall be included in all copies or
+
14  * substantial portions of the Software.
+
15  *
+
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
22  *
+
23  */
+
24 
+
25 #ifndef __ESPWPS_H__
+
26 #define __ESPWPS_H__
+
27 
+
28 #ifdef __cplusplus
+
29 extern "C" {
+
30 #endif
+
31 
+
51 typedef enum wps_type {
+
52  WPS_TYPE_DISABLE = 0,
+
53  WPS_TYPE_PBC,
+
54  WPS_TYPE_PIN,
+
55  WPS_TYPE_DISPLAY,
+
56  WPS_TYPE_MAX,
+
57 } WPS_TYPE_t;
+
58 
+ + + + + + +
65 };
+
66 
+
77 bool wifi_wps_enable(WPS_TYPE_t wps_type);
+
78 
+
87 bool wifi_wps_disable(void);
+
88 
+
99 bool wifi_wps_start(void);
+
100 
+
113 typedef void (*wps_st_cb_t)(int status);
+
114 
+ +
126 
+
135 #ifdef __cplusplus
+
136 }
+
137 #endif
+
138 
+
139 #endif
+
Definition: esp_wps.h:64
+
Definition: esp_wps.h:62
+
Definition: esp_wps.h:61
+
bool wifi_wps_start(void)
WPS starts to work.
+
void(* wps_st_cb_t)(int status)
WPS callback.
Definition: esp_wps.h:113
+
Definition: esp_wps.h:63
+
bool wifi_wps_enable(WPS_TYPE_t wps_type)
Enable Wi-Fi WPS function.
+
bool wifi_wps_disable(void)
Disable Wi-Fi WPS function and release resource it taken.
+
Definition: esp_wps.h:60
+
wps_cb_status
Definition: esp_wps.h:59
+
bool wifi_set_wps_cb(wps_st_cb_t cb)
Set WPS callback.
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/espconn_8h_source.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/espconn_8h_source.html new file mode 100644 index 0000000..79b3832 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/espconn_8h_source.html @@ -0,0 +1,388 @@ + + + + + + +ESP8266_RTOS_SDK: include/espressif/espconn.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
espconn.h
+
+
+
1 /*
+
2  * ESPRSSIF MIT License
+
3  *
+
4  * Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+
5  *
+
6  * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+
7  * it is free of charge, to any person obtaining a copy of this software and associated
+
8  * documentation files (the "Software"), to deal in the Software without restriction, including
+
9  * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+
10  * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
+
11  * to do so, subject to the following conditions:
+
12  *
+
13  * The above copyright notice and this permission notice shall be included in all copies or
+
14  * substantial portions of the Software.
+
15  *
+
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
22  *
+
23  */
+
24 
+
25 #ifndef __ESPCONN_H__
+
26 #define __ESPCONN_H__
+
27 
+
28 #ifdef __cplusplus
+
29 extern "C" {
+
30 #endif
+
31 
+
32 typedef sint8 err_t;
+
33 
+
34 typedef void *espconn_handle;
+
35 
+
59 typedef void (* espconn_connect_callback)(void *arg);
+
60 
+
83 typedef void (* espconn_reconnect_callback)(void *arg, sint8 err);
+
84 
+
85 /* Definitions for error constants. */
+
86 
+
87 #define ESPCONN_OK 0
+
88 #define ESPCONN_MEM -1
+
89 #define ESPCONN_TIMEOUT -3
+
90 #define ESPCONN_RTE -4
+
91 #define ESPCONN_INPROGRESS -5
+
92 #define ESPCONN_MAXNUM -7
+
94 #define ESPCONN_ABRT -8
+
95 #define ESPCONN_RST -9
+
96 #define ESPCONN_CLSD -10
+
97 #define ESPCONN_CONN -11
+
99 #define ESPCONN_ARG -12
+
100 #define ESPCONN_IF -14
+
101 #define ESPCONN_ISCONN -15
+
104 enum espconn_type {
+ +
106  ESPCONN_TCP = 0x10,
+
107  ESPCONN_UDP = 0x20,
+
108 };
+
109 
+ + + + + + + + +
119 };
+
120 
+
121 typedef struct _esp_tcp {
+ + +
124  uint8 local_ip[4];
+
125  uint8 remote_ip[4];
+ + + + +
130 } esp_tcp;
+
131 
+
132 typedef struct _esp_udp {
+ + +
135  uint8 local_ip[4];
+
136  uint8 remote_ip[4];
+
137 } esp_udp;
+
138 
+
139 typedef struct _remot_info {
+ + +
142  uint8 remote_ip[4];
+
143 } remot_info;
+
144 
+
146 typedef void (* espconn_recv_callback)(void *arg, char *pdata, unsigned short len);
+
147 typedef void (* espconn_sent_callback)(void *arg);
+
148 
+
150 struct espconn {
+ + +
153  union {
+
154  esp_tcp *tcp;
+
155  esp_udp *udp;
+
156  } proto;
+ +
158  espconn_sent_callback sent_callback;
+
159  uint8 link_cnt;
+
160  void *reserve;
+
161 };
+
162 
+ +
164  ESPCONN_START = 0x00,
+ + +
167  ESPCONN_COPY = 0x04,
+ + +
170 };
+
171 
+ + + + +
176 };
+
177 
+
178 enum {
+
179  ESPCONN_IDLE = 0,
+
180  ESPCONN_CLIENT,
+
181  ESPCONN_SERVER,
+
182  ESPCONN_BOTH,
+
183  ESPCONN_MAX
+
184 };
+
185 
+
195 void espconn_init(void);
+
196 
+
214 sint8 espconn_connect(struct espconn *espconn);
+
215 
+
229 sint8 espconn_disconnect(struct espconn *espconn);
+
230 
+
247 sint8 espconn_delete(struct espconn *espconn);
+
248 
+
261 sint8 espconn_accept(struct espconn *espconn);
+
262 
+
277 sint8 espconn_create(struct espconn *espconn);
+
278 
+
286 uint8 espconn_tcp_get_max_con(void);
+
287 
+
298 sint8 espconn_tcp_set_max_con(uint8 num);
+
299 
+ +
311 
+
323 sint8 espconn_tcp_set_max_con_allow(struct espconn *espconn, uint8 num);
+
324 
+
345 sint8 espconn_regist_time(struct espconn *espconn, uint32 interval, uint8 type_flag);
+
346 
+
359 sint8 espconn_get_connection_info(struct espconn *pespconn, remot_info **pcon_info, uint8 typeflags);
+
360 
+
373 sint8 espconn_regist_sentcb(struct espconn *espconn, espconn_sent_callback sent_cb);
+
374 
+ +
399 
+
419 sint8 espconn_send(struct espconn *espconn, uint8 *psent, uint16 length);
+
420 
+
442 sint8 espconn_sent(struct espconn *espconn, uint8 *psent, uint16 length);
+
443 
+
457 sint16 espconn_sendto(struct espconn *espconn, uint8 *psent, uint16 length);
+
458 
+ +
471 
+ +
484 
+ +
502 
+ +
516 
+
524 uint32 espconn_port(void);
+
525 
+
546 sint8 espconn_set_opt(struct espconn *espconn, uint8 opt);
+
547 
+
559 sint8 espconn_clear_opt(struct espconn *espconn, uint8 opt);
+
560 
+
580 sint8 espconn_set_keepalive(struct espconn *espconn, uint8 level, void *optarg);
+
581 
+
594 sint8 espconn_get_keepalive(struct espconn *espconn, uint8 level, void *optarg);
+
595 
+
606 typedef void (*dns_found_callback)(const char *name, ip_addr_t *ipaddr, void *callback_arg);
+
607 
+
624 err_t espconn_gethostbyname(struct espconn *pespconn, const char *hostname, ip_addr_t *addr, dns_found_callback found);
+
625 
+
638 sint8 espconn_igmp_join(ip_addr_t *host_ip, ip_addr_t *multicast_ip);
+
639 
+
652 sint8 espconn_igmp_leave(ip_addr_t *host_ip, ip_addr_t *multicast_ip);
+
653 
+
667 sint8 espconn_recv_hold(struct espconn *pespconn);
+
668 
+
681 sint8 espconn_recv_unhold(struct espconn *pespconn);
+
682 
+
694 void espconn_dns_setserver(char numdns, ip_addr_t *dnsserver);
+
695 
+
700 #ifdef __cplusplus
+
701 }
+
702 #endif
+
703 
+
704 #endif
+
void(* espconn_recv_callback)(void *arg, char *pdata, unsigned short len)
Definition: espconn.h:146
+
sint8 espconn_regist_sentcb(struct espconn *espconn, espconn_sent_callback sent_cb)
Register data sent callback which will be called back when data are successfully sent.
+
void(* espconn_connect_callback)(void *arg)
Connect callback.
Definition: espconn.h:59
+
Definition: espconn.h:106
+
espconn_connect_callback connect_callback
Definition: espconn.h:126
+
Definition: espconn.h:132
+
sint8 espconn_tcp_set_max_con(uint8 num)
Set the maximum number of how many TCP connection is allowed.
+
sint8 espconn_recv_unhold(struct espconn *pespconn)
Unblock TCP receiving data (i.e. undo espconn_recv_hold).
+
void espconn_dns_setserver(char numdns, ip_addr_t *dnsserver)
Set default DNS server. Two DNS server is allowed to be set.
+
sint8 espconn_create(struct espconn *espconn)
Create UDP transmission.
+
int local_port
Definition: espconn.h:134
+
sint8 espconn_regist_recvcb(struct espconn *espconn, espconn_recv_callback recv_cb)
register data receive function which will be called back when data are received.
+
sint8 espconn_disconnect(struct espconn *espconn)
Disconnect a TCP connection.
+
Definition: espconn.h:175
+
sint8 espconn_tcp_get_max_con_allow(struct espconn *espconn)
Get the maximum number of TCP clients which are allowed to connect to ESP8266 TCP server...
+
sint8 espconn_igmp_join(ip_addr_t *host_ip, ip_addr_t *multicast_ip)
Join a multicast group.
+
sint8 espconn_regist_disconcb(struct espconn *espconn, espconn_connect_callback discon_cb)
Register disconnection function which will be called back under successful TCP disconnection.
+
Definition: espconn.h:173
+
Definition: espconn.h:116
+
sint8 espconn_regist_reconcb(struct espconn *espconn, espconn_reconnect_callback recon_cb)
Register reconnect callback.
+
espconn_sent_callback sent_callback
Definition: espconn.h:158
+
uint8 local_ip[4]
Definition: espconn.h:124
+
Definition: espconn.h:118
+
Definition: espconn.h:139
+
void * reserve
Definition: espconn.h:160
+
sint16 espconn_sendto(struct espconn *espconn, uint8 *psent, uint16 length)
Send UDP data.
+
Definition: espconn.h:107
+
int remote_port
Definition: espconn.h:141
+
enum espconn_type type
Definition: espconn.h:151
+
Definition: espconn.h:165
+
Definition: espconn.h:164
+
void(* espconn_reconnect_callback)(void *arg, sint8 err)
Reconnect callback.
Definition: espconn.h:83
+
sint8 espconn_regist_connectcb(struct espconn *espconn, espconn_connect_callback connect_cb)
Register connection function which will be called back under successful TCP connection.
+
sint8 espconn_send(struct espconn *espconn, uint8 *psent, uint16 length)
Send data through network.
+
Definition: espconn.h:168
+
espconn_reconnect_callback reconnect_callback
Definition: espconn.h:127
+
espconn_option
Definition: espconn.h:163
+
Definition: espconn.h:114
+
sint8 espconn_set_opt(struct espconn *espconn, uint8 opt)
Set option of TCP connection.
+
Definition: espconn.h:169
+
espconn_type
Definition: espconn.h:104
+
espconn_recv_callback recv_callback
Definition: espconn.h:157
+
Definition: espconn.h:121
+
espconn_connect_callback write_finish_fn
Definition: espconn.h:129
+
sint8 espconn_accept(struct espconn *espconn)
Creates a TCP server (i.e. accepts connections).
+
uint8 remote_ip[4]
Definition: espconn.h:142
+
Definition: espconn.h:105
+
sint8 espconn_regist_write_finish(struct espconn *espconn, espconn_connect_callback write_finish_fn)
Register a callback which will be called when all sending TCP data is completely write into write-buf...
+
void(* dns_found_callback)(const char *name, ip_addr_t *ipaddr, void *callback_arg)
Callback which is invoked when a hostname is found.
Definition: espconn.h:606
+
Definition: espconn.h:174
+
Definition: espconn.h:115
+
Definition: espconn.h:112
+
uint8 remote_ip[4]
Definition: espconn.h:136
+
sint8 espconn_sent(struct espconn *espconn, uint8 *psent, uint16 length)
Send data through network.
+
sint8 espconn_regist_time(struct espconn *espconn, uint32 interval, uint8 type_flag)
Register timeout interval of ESP8266 TCP server.
+
int remote_port
Definition: espconn.h:133
+
Definition: espconn.h:113
+
uint8 remote_ip[4]
Definition: espconn.h:125
+
sint8 espconn_get_keepalive(struct espconn *espconn, uint8 level, void *optarg)
Get configuration of TCP keep alive.
+
enum espconn_state state
Definition: espconn.h:152
+
Definition: espconn.h:166
+
Definition: espconn.h:150
+
espconn_connect_callback disconnect_callback
Definition: espconn.h:128
+
sint8 espconn_connect(struct espconn *espconn)
Connect to a TCP server (ESP8266 acting as TCP client).
+
uint8 espconn_tcp_get_max_con(void)
Get maximum number of how many TCP connections are allowed.
+
Definition: espconn.h:167
+
uint8 local_ip[4]
Definition: espconn.h:135
+
int local_port
Definition: espconn.h:123
+
Definition: espconn.h:117
+
sint8 espconn_igmp_leave(ip_addr_t *host_ip, ip_addr_t *multicast_ip)
Leave a multicast group.
+
uint32 espconn_port(void)
Get an available port for network.
+
int remote_port
Definition: espconn.h:122
+
sint8 espconn_clear_opt(struct espconn *espconn, uint8 opt)
Clear option of TCP connection.
+
void espconn_init(void)
espconn initialization.
+
sint8 espconn_set_keepalive(struct espconn *espconn, uint8 level, void *optarg)
Set configuration of TCP keep alive.
+
espconn_state
Definition: espconn.h:111
+
uint8 link_cnt
Definition: espconn.h:159
+
sint8 espconn_get_connection_info(struct espconn *pespconn, remot_info **pcon_info, uint8 typeflags)
Get the information about a TCP connection or UDP transmission.
+
sint8 espconn_recv_hold(struct espconn *pespconn)
Puts in a request to block the TCP receive function.
+
sint8 espconn_tcp_set_max_con_allow(struct espconn *espconn, uint8 num)
Set the maximum number of TCP clients allowed to connect to ESP8266 TCP server.
+
espconn_level
Definition: espconn.h:172
+
sint8 espconn_delete(struct espconn *espconn)
Delete a transmission.
+
err_t espconn_gethostbyname(struct espconn *pespconn, const char *hostname, ip_addr_t *addr, dns_found_callback found)
DNS function.
+
enum espconn_state state
Definition: espconn.h:140
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/espnow_8h_source.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/espnow_8h_source.html new file mode 100644 index 0000000..2dfbde1 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/espnow_8h_source.html @@ -0,0 +1,212 @@ + + + + + + +ESP8266_RTOS_SDK: include/espressif/espnow.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
espnow.h
+
+
+
1 /*
+
2  * ESPRSSIF MIT License
+
3  *
+
4  * Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+
5  *
+
6  * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+
7  * it is free of charge, to any person obtaining a copy of this software and associated
+
8  * documentation files (the "Software"), to deal in the Software without restriction, including
+
9  * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+
10  * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
+
11  * to do so, subject to the following conditions:
+
12  *
+
13  * The above copyright notice and this permission notice shall be included in all copies or
+
14  * substantial portions of the Software.
+
15  *
+
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
22  *
+
23  */
+
24 
+
25 #ifndef __ESPNOW_H__
+
26 #define __ESPNOW_H__
+
27 
+
28 #ifdef __cplusplus
+
29 extern "C" {
+
30 #endif
+
31 
+
56 enum esp_now_role {
+
57  ESP_NOW_ROLE_IDLE = 0,
+
58  ESP_NOW_ROLE_CONTROLLER,
+
59  ESP_NOW_ROLE_SLAVE,
+
60  ESP_NOW_ROLE_MAX,
+
61 };
+
62 
+
75 typedef void (*esp_now_recv_cb_t)(uint8 *mac_addr, uint8 *data, uint8 len);
+
76 
+
88 typedef void (*esp_now_send_cb_t)(uint8 *mac_addr, uint8 status);
+
89 
+
98 sint32 esp_now_init(void);
+
99 
+
108 sint32 esp_now_deinit(void);
+
109 
+ +
119 
+
128 sint32 esp_now_unregister_send_cb(void);
+
129 
+ +
139 
+
148 sint32 esp_now_unregister_recv_cb(void);
+
149 
+
162 sint32 esp_now_send(uint8 *da, uint8 *data, uint8 len);
+
163 
+
176 sint32 esp_now_add_peer(uint8 *mac_addr, uint8 role, uint8 channel, uint8 *key, uint8 key_len);
+
177 
+
186 sint32 esp_now_del_peer(uint8 *mac_addr);
+
187 
+
196 sint32 esp_now_set_self_role(uint8 role);
+
197 
+
206 sint32 esp_now_get_self_role(void);
+
207 
+
218 sint32 esp_now_set_peer_role(uint8 *mac_addr, uint8 role);
+
219 
+
229 sint32 esp_now_get_peer_role(uint8 *mac_addr);
+
230 
+
244 sint32 esp_now_set_peer_channel(uint8 *mac_addr, uint8 channel);
+
245 
+
256 sint32 esp_now_get_peer_channel(uint8 *mac_addr);
+
257 
+
271 sint32 esp_now_set_peer_key(uint8 *mac_addr, uint8 *key, uint8 key_len);
+
272 
+
286 sint32 esp_now_get_peer_key(uint8 *mac_addr, uint8 *key, uint8 *key_len);
+
287 
+
304 uint8 *esp_now_fetch_peer(bool restart);
+
305 
+
315 sint32 esp_now_is_peer_exist(uint8 *mac_addr);
+
316 
+
327 sint32 esp_now_get_cnt_info(uint8 *all_cnt, uint8 *encrypt_cnt);
+
328 
+
341 sint32 esp_now_set_kok(uint8 *key, uint8 len);
+
342 
+
347 #ifdef __cplusplus
+
348 }
+
349 #endif
+
350 
+
351 #endif
+
sint32 esp_now_set_peer_role(uint8 *mac_addr, uint8 role)
Set ESP-NOW role for a target device. If it is set multiple times, new role will cover the old one...
+
sint32 esp_now_del_peer(uint8 *mac_addr)
Delete an ESP-NOW peer, delete MAC address of the device from ESP-NOW MAC list.
+
sint32 esp_now_get_peer_role(uint8 *mac_addr)
Get ESP-NOW role of a target device.
+
void(* esp_now_send_cb_t)(uint8 *mac_addr, uint8 status)
ESP-NOW send callback.
Definition: espnow.h:88
+
sint32 esp_now_get_cnt_info(uint8 *all_cnt, uint8 *encrypt_cnt)
Get the total number of ESP-NOW devices which are associated, and the number count of encrypted devic...
+
sint32 esp_now_register_send_cb(esp_now_send_cb_t cb)
Register ESP-NOW send callback.
+
sint32 esp_now_register_recv_cb(esp_now_recv_cb_t cb)
Register ESP-NOW receive callback.
+
sint32 esp_now_set_peer_channel(uint8 *mac_addr, uint8 channel)
Record channel information of a ESP-NOW device.
+
sint32 esp_now_set_self_role(uint8 role)
Set ESP-NOW role of device itself.
+
sint32 esp_now_unregister_send_cb(void)
Unregister ESP-NOW send callback.
+
sint32 esp_now_init(void)
ESP-NOW initialization.
+
uint8 * esp_now_fetch_peer(bool restart)
Get MAC address of ESP-NOW device.
+
sint32 esp_now_set_peer_key(uint8 *mac_addr, uint8 *key, uint8 key_len)
Set ESP-NOW key for a target device.
+
sint32 esp_now_is_peer_exist(uint8 *mac_addr)
Check if target device exists or not.
+
sint32 esp_now_add_peer(uint8 *mac_addr, uint8 role, uint8 channel, uint8 *key, uint8 key_len)
Add an ESP-NOW peer, store MAC address of target device into ESP-NOW MAC list.
+
sint32 esp_now_deinit(void)
Deinitialize ESP-NOW.
+
sint32 esp_now_get_peer_key(uint8 *mac_addr, uint8 *key, uint8 *key_len)
Get ESP-NOW key of a target device.
+
sint32 esp_now_get_self_role(void)
Get ESP-NOW role of device itself.
+
sint32 esp_now_unregister_recv_cb(void)
Unregister ESP-NOW receive callback.
+
void(* esp_now_recv_cb_t)(uint8 *mac_addr, uint8 *data, uint8 len)
ESP-NOW send callback.
Definition: espnow.h:75
+
sint32 esp_now_send(uint8 *da, uint8 *data, uint8 len)
Send ESP-NOW packet.
+
sint32 esp_now_get_peer_channel(uint8 *mac_addr)
Get channel information of a ESP-NOW device.
+
sint32 esp_now_set_kok(uint8 *key, uint8 len)
Set the encrypt key of communication key.
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/files.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/files.html new file mode 100644 index 0000000..2132f6f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/files.html @@ -0,0 +1,129 @@ + + + + + + +ESP8266_RTOS_SDK: File List + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + +
+ +
+
+ + +
+ +
+ +
+
+
File List
+
+
+
Here is a list of all documented files with brief descriptions:
+
[detail level 1234]
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  examples
  driver_lib
  include
 gpio.h
 hw_timer.h
 uart.h
  include
  espressif
 airkiss.h
 c_types.h
 esp_common.h
 esp_libc.h
 esp_misc.h
 esp_softap.h
 esp_spiffs.h
 esp_ssc.h
 esp_sta.h
 esp_system.h
 esp_timer.h
 esp_wifi.h
 esp_wps.h
 espconn.h
 espnow.h
 mesh.h
 pwm.h
 queue.h
 smartconfig.h
 spi_flash.h
 upgrade.h
+
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/folderclosed.png b/Distrib/ESPressif/RTOS/1.5.0/documents/html/folderclosed.png new file mode 100644 index 0000000000000000000000000000000000000000..bb8ab35edce8e97554e360005ee9fc5bffb36e66 GIT binary patch literal 616 zcmV-u0+;=XP)a9#ETzayK)T~Jw&MMH>OIr#&;dC}is*2Mqdf&akCc=O@`qC+4i z5Iu3w#1M@KqXCz8TIZd1wli&kkl2HVcAiZ8PUn5z_kG@-y;?yK06=cA0U%H0PH+kU zl6dp}OR(|r8-RG+YLu`zbI}5TlOU6ToR41{9=uz^?dGTNL;wIMf|V3`d1Wj3y!#6` zBLZ?xpKR~^2x}?~zA(_NUu3IaDB$tKma*XUdOZN~c=dLt_h_k!dbxm_*ibDM zlFX`g{k$X}yIe%$N)cn1LNu=q9_CS)*>A zsX_mM4L@`(cSNQKMFc$RtYbx{79#j-J7hk*>*+ZZhM4Hw?I?rsXCi#mRWJ=-0LGV5a-WR0Qgt<|Nqf)C-@80`5gIz45^_20000IqP)X=#(TiCT&PiIIVc55T}TU}EUh*{q$|`3@{d>{Tc9Bo>e= zfmF3!f>fbI9#GoEHh0f`i5)wkLpva0ztf%HpZneK?w-7AK@b4Itw{y|Zd3k!fH?q2 zlhckHd_V2M_X7+)U&_Xcfvtw60l;--DgZmLSw-Y?S>)zIqMyJ1#FwLU*%bl38ok+! zh78H87n`ZTS;uhzAR$M`zZ`bVhq=+%u9^$5jDplgxd44}9;IRqUH1YHH|@6oFe%z( zo4)_>E$F&^P-f(#)>(TrnbE>Pefs9~@iN=|)Rz|V`sGfHNrJ)0gJb8xx+SBmRf@1l zvuzt=vGfI)<-F9!o&3l?>9~0QbUDT(wFdnQPv%xdD)m*g%!20>Bc9iYmGAp<9YAa( z0QgYgTWqf1qN++Gqp z8@AYPTB3E|6s=WLG?xw0tm|U!o=&zd+H0oRYE;Dbx+Na9s^STqX|Gnq%H8s(nGDGJ j8vwW|`Ts`)fSK|Kx=IK@RG@g200000NkvXXu0mjfauFEA literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/functions.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/functions.html new file mode 100644 index 0000000..2c1e426 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/functions.html @@ -0,0 +1,451 @@ + + + + + + +ESP8266_RTOS_SDK: Data Fields + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:
+ +

- a -

+ + +

- b -

+ + +

- c -

+ + +

- d -

+ + +

- e -

+ + +

- f -

+ + +

- g -

+ + +

- i -

+ + +

- l -

+ + +

- m -

+ + +

- n -

+ + +

- o -

+ + +

- p -

+ + +

- r -

+ + +

- s -

+ + +

- t -

+ + +

- u -

+ + +

- w -

+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/functions_func.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/functions_func.html new file mode 100644 index 0000000..2ba0ab3 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/functions_func.html @@ -0,0 +1,107 @@ + + + + + + +ESP8266_RTOS_SDK: Data Fields - Functions + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+ +
+
+ + +
+ +
+ +
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/functions_vars.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/functions_vars.html new file mode 100644 index 0000000..a4a013b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/functions_vars.html @@ -0,0 +1,447 @@ + + + + + + +ESP8266_RTOS_SDK: Data Fields - Variables + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+  + +

- a -

+ + +

- b -

+ + +

- c -

+ + +

- d -

+ + +

- e -

+ + +

- f -

+ + +

- g -

+ + +

- i -

+ + +

- l -

+ + +

- m -

+ + +

- n -

+ + +

- o -

+ + +

- p -

+ + +

- r -

+ + +

- s -

+ + +

- t -

+ + +

- u -

+ + +

- w -

+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/gpio_8h_source.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/gpio_8h_source.html new file mode 100644 index 0000000..0703e8f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/gpio_8h_source.html @@ -0,0 +1,274 @@ + + + + + + +ESP8266_RTOS_SDK: examples/driver_lib/include/gpio.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
gpio.h
+
+
+
1 /*
+
2  * ESPRSSIF MIT License
+
3  *
+
4  * Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+
5  *
+
6  * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+
7  * it is free of charge, to any person obtaining a copy of this software and associated
+
8  * documentation files (the "Software"), to deal in the Software without restriction, including
+
9  * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+
10  * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
+
11  * to do so, subject to the following conditions:
+
12  *
+
13  * The above copyright notice and this permission notice shall be included in all copies or
+
14  * substantial portions of the Software.
+
15  *
+
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
22  *
+
23  */
+
24 
+
25 #ifndef __GPIO_H__
+
26 #define __GPIO_H__
+
27 
+
28 #ifdef __cplusplus
+
29 extern "C" {
+
30 #endif
+
31 
+
32 #define GPIO_Pin_0 (BIT(0)) /* Pin 0 selected */
+
33 #define GPIO_Pin_1 (BIT(1)) /* Pin 1 selected */
+
34 #define GPIO_Pin_2 (BIT(2)) /* Pin 2 selected */
+
35 #define GPIO_Pin_3 (BIT(3)) /* Pin 3 selected */
+
36 #define GPIO_Pin_4 (BIT(4)) /* Pin 4 selected */
+
37 #define GPIO_Pin_5 (BIT(5)) /* Pin 5 selected */
+
38 #define GPIO_Pin_6 (BIT(6)) /* Pin 6 selected */
+
39 #define GPIO_Pin_7 (BIT(7)) /* Pin 7 selected */
+
40 #define GPIO_Pin_8 (BIT(8)) /* Pin 8 selected */
+
41 #define GPIO_Pin_9 (BIT(9)) /* Pin 9 selected */
+
42 #define GPIO_Pin_10 (BIT(10)) /* Pin 10 selected */
+
43 #define GPIO_Pin_11 (BIT(11)) /* Pin 11 selected */
+
44 #define GPIO_Pin_12 (BIT(12)) /* Pin 12 selected */
+
45 #define GPIO_Pin_13 (BIT(13)) /* Pin 13 selected */
+
46 #define GPIO_Pin_14 (BIT(14)) /* Pin 14 selected */
+
47 #define GPIO_Pin_15 (BIT(15)) /* Pin 15 selected */
+
48 #define GPIO_Pin_All (0xFFFF) /* All pins selected */
+
49 
+
50 #define GPIO_PIN_REG_0 PERIPHS_IO_MUX_GPIO0_U
+
51 #define GPIO_PIN_REG_1 PERIPHS_IO_MUX_U0TXD_U
+
52 #define GPIO_PIN_REG_2 PERIPHS_IO_MUX_GPIO2_U
+
53 #define GPIO_PIN_REG_3 PERIPHS_IO_MUX_U0RXD_U
+
54 #define GPIO_PIN_REG_4 PERIPHS_IO_MUX_GPIO4_U
+
55 #define GPIO_PIN_REG_5 PERIPHS_IO_MUX_GPIO5_U
+
56 #define GPIO_PIN_REG_6 PERIPHS_IO_MUX_SD_CLK_U
+
57 #define GPIO_PIN_REG_7 PERIPHS_IO_MUX_SD_DATA0_U
+
58 #define GPIO_PIN_REG_8 PERIPHS_IO_MUX_SD_DATA1_U
+
59 #define GPIO_PIN_REG_9 PERIPHS_IO_MUX_SD_DATA2_U
+
60 #define GPIO_PIN_REG_10 PERIPHS_IO_MUX_SD_DATA3_U
+
61 #define GPIO_PIN_REG_11 PERIPHS_IO_MUX_SD_CMD_U
+
62 #define GPIO_PIN_REG_12 PERIPHS_IO_MUX_MTDI_U
+
63 #define GPIO_PIN_REG_13 PERIPHS_IO_MUX_MTCK_U
+
64 #define GPIO_PIN_REG_14 PERIPHS_IO_MUX_MTMS_U
+
65 #define GPIO_PIN_REG_15 PERIPHS_IO_MUX_MTDO_U
+
66 
+
67 #define GPIO_PIN_REG(i) \
+
68  (i==0) ? GPIO_PIN_REG_0: \
+
69  (i==1) ? GPIO_PIN_REG_1: \
+
70  (i==2) ? GPIO_PIN_REG_2: \
+
71  (i==3) ? GPIO_PIN_REG_3: \
+
72  (i==4) ? GPIO_PIN_REG_4: \
+
73  (i==5) ? GPIO_PIN_REG_5: \
+
74  (i==6) ? GPIO_PIN_REG_6: \
+
75  (i==7) ? GPIO_PIN_REG_7: \
+
76  (i==8) ? GPIO_PIN_REG_8: \
+
77  (i==9) ? GPIO_PIN_REG_9: \
+
78  (i==10)? GPIO_PIN_REG_10: \
+
79  (i==11)? GPIO_PIN_REG_11: \
+
80  (i==12)? GPIO_PIN_REG_12: \
+
81  (i==13)? GPIO_PIN_REG_13: \
+
82  (i==14)? GPIO_PIN_REG_14: \
+
83  GPIO_PIN_REG_15
+
84 
+
85 #define GPIO_PIN_ADDR(i) (GPIO_PIN0_ADDRESS + i*4)
+
86 
+
87 #define GPIO_ID_IS_PIN_REGISTER(reg_id) \
+
88  ((reg_id >= GPIO_ID_PIN0) && (reg_id <= GPIO_ID_PIN(GPIO_PIN_COUNT-1)))
+
89 
+
90 #define GPIO_REGID_TO_PINIDX(reg_id) ((reg_id) - GPIO_ID_PIN0)
+
91 
+
92 typedef enum {
+
93  GPIO_PIN_INTR_DISABLE = 0,
+
94  GPIO_PIN_INTR_POSEDGE = 1,
+
95  GPIO_PIN_INTR_NEGEDGE = 2,
+
96  GPIO_PIN_INTR_ANYEDGE = 3,
+
97  GPIO_PIN_INTR_LOLEVEL = 4,
+
98  GPIO_PIN_INTR_HILEVEL = 5
+
99 } GPIO_INT_TYPE;
+
100 
+
101 typedef enum {
+
102  GPIO_Mode_Input = 0x0,
+
103  GPIO_Mode_Out_OD,
+
104  GPIO_Mode_Output ,
+
105  GPIO_Mode_Sigma_Delta ,
+
106 } GPIOMode_TypeDef;
+
107 
+
108 typedef enum {
+
109  GPIO_PullUp_DIS = 0x0,
+
110  GPIO_PullUp_EN = 0x1,
+
111 } GPIO_Pullup_IF;
+
112 
+
113 typedef struct {
+
114  uint16 GPIO_Pin;
+
115  GPIOMode_TypeDef GPIO_Mode;
+
116  GPIO_Pullup_IF GPIO_Pullup;
+
117  GPIO_INT_TYPE GPIO_IntrType;
+ +
119 
+
144 #define GPIO_OUTPUT_SET(gpio_no, bit_value) \
+
145  gpio_output_conf(bit_value<<gpio_no, ((~bit_value)&0x01)<<gpio_no, 1<<gpio_no, 0)
+
146 
+
155 #define GPIO_OUTPUT(gpio_bits, bit_value) \
+
156  if(bit_value) gpio_output_conf(gpio_bits, 0, gpio_bits, 0);\
+
157  else gpio_output_conf(0, gpio_bits, gpio_bits, 0)
+
158 
+
166 #define GPIO_DIS_OUTPUT(gpio_no) gpio_output_conf(0, 0, 0, 1<<gpio_no)
+
167 
+
175 #define GPIO_AS_INPUT(gpio_bits) gpio_output_conf(0, 0, 0, gpio_bits)
+
176 
+
184 #define GPIO_AS_OUTPUT(gpio_bits) gpio_output_conf(0, 0, gpio_bits, 0)
+
185 
+
193 #define GPIO_INPUT_GET(gpio_no) ((gpio_input_get()>>gpio_no)&BIT0)
+
194 
+
202 void gpio16_output_conf(void);
+
203 
+
211 void gpio16_output_set(uint8 value);
+
212 
+
220 void gpio16_input_conf(void);
+
221 
+
229 uint8 gpio16_input_get(void);
+
230 
+
245 void gpio_output_conf(uint32 set_mask, uint32 clear_mask, uint32 enable_mask, uint32 disable_mask);
+
246 
+
255 void gpio_intr_handler_register(void *fn, void *arg);
+
256 
+
265 void gpio_pin_wakeup_enable(uint32 i, GPIO_INT_TYPE intr_state);
+
266 
+ +
275 
+
284 void gpio_pin_intr_state_set(uint32 i, GPIO_INT_TYPE intr_state);
+
285 
+
293 uint32 gpio_input_get(void);
+
294 
+
303 #ifdef __cplusplus
+
304 }
+
305 #endif
+
306 
+
307 #endif
+
void gpio16_output_set(uint8 value)
Set GPIO16 output level.
+
uint32 gpio_input_get(void)
Sample the value of GPIO input pins and returns a bitmask.
+
uint16 GPIO_Pin
Definition: gpio.h:114
+
GPIO_Pullup_IF GPIO_Pullup
Definition: gpio.h:116
+
void gpio_pin_wakeup_enable(uint32 i, GPIO_INT_TYPE intr_state)
Configure GPIO wake up to light sleep,Only level way is effective.
+
void gpio16_output_conf(void)
Enable GPIO16 output.
+
uint8 gpio16_input_get(void)
Sample the value of GPIO16 input.
+
Definition: gpio.h:113
+
void gpio_pin_intr_state_set(uint32 i, GPIO_INT_TYPE intr_state)
Config interrupt types of GPIO pin.
+
GPIO_INT_TYPE GPIO_IntrType
Definition: gpio.h:117
+
GPIOMode_TypeDef GPIO_Mode
Definition: gpio.h:115
+
void gpio16_input_conf(void)
Enable GPIO pin intput.
+
void gpio_output_conf(uint32 set_mask, uint32 clear_mask, uint32 enable_mask, uint32 disable_mask)
Configure Gpio pins out or input.
+
void gpio_pin_wakeup_disable()
Disable GPIO wake up to light sleep.
+
void gpio_intr_handler_register(void *fn, void *arg)
Register an application-specific interrupt handler for GPIO pin interrupts.
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__AirKiss__APIs.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__AirKiss__APIs.html new file mode 100644 index 0000000..20c39a6 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__AirKiss__APIs.html @@ -0,0 +1,326 @@ + + + + + + +ESP8266_RTOS_SDK: AirKiss APIs + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + +
+ +
+
+ + +
+ +
+ +
+ +
+
AirKiss APIs
+
+
+ +

AirKiss APIs. +More...

+ + + + + + +

+Enumerations

enum  airkiss_lan_ret_t {
+  AIRKISS_LAN_ERR_OVERFLOW = -5, +AIRKISS_LAN_ERR_CMD = -4, +AIRKISS_LAN_ERR_PAKE = -3, +AIRKISS_LAN_ERR_PARA = -2, +
+  AIRKISS_LAN_ERR_PKG = -1, +AIRKISS_LAN_CONTINUE = 0, +AIRKISS_LAN_SSDP_REQ = 1, +AIRKISS_LAN_PAKE_READY = 2 +
+ }
 
enum  airkiss_lan_cmdid_t { AIRKISS_LAN_SSDP_REQ_CMD = 0x1, +AIRKISS_LAN_SSDP_RESP_CMD = 0x1001, +AIRKISS_LAN_SSDP_NOTIFY_CMD = 0x1002 + }
 
+ + + + + + + + + + +

+Functions

const char * airkiss_version (void)
 Get the version information of AirKiss lib. More...
 
int airkiss_lan_recv (const void *body, unsigned short length, const airkiss_config_t *config)
 Parse the UDP packet sent by AirKiss. More...
 
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)
 Packaging the UDP packet. More...
 
+

Detailed Description

+

AirKiss APIs.

+

API airkiss_lan_recv and airkiss_lan_pack are provided for the function that AirKiss can detect the ESP8266 devices in LAN, more details about AirKiss please refer to WeChat : http://iot.weixin.qq.com.

+

Workflow : Create a UDP transmission. When UDP data is received, call API airkiss_lan_recv and input the UDP data, if the airkiss_lan_recv returns AIRKISS_LAN_SSDP_REQ, airkiss_lan_pack can be called to make a response packet.

+

Enumeration Type Documentation

+ +
+
+ + + + +
enum airkiss_lan_ret_t
+
+ + + + + + + + + +
Enumerator
AIRKISS_LAN_ERR_OVERFLOW  +

the length of the data buffer is lack

+
AIRKISS_LAN_ERR_CMD  +

Do not support the type of instruction

+
AIRKISS_LAN_ERR_PAKE  +

Error reading data package

+
AIRKISS_LAN_ERR_PARA  +

Error function passing parameters

+
AIRKISS_LAN_ERR_PKG  +

Packet data error

+
AIRKISS_LAN_CONTINUE  +

Message format is correct

+
AIRKISS_LAN_SSDP_REQ  +

Find equipment request packet is received

+
AIRKISS_LAN_PAKE_READY  +

Packet packaging complete

+
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
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_tconfig 
)
+
+ +

Packaging the UDP packet.

+
Parameters
+ + + + + + + + + +
airkiss_lan_cmdid_tak_lan_cmdid : type of the packet.
void*appid : Vendor's Wechat public number id, got from WeChat.
void*deviceid : device model id, got from WeChat.
void*_datain : user data waiting for packet assembly.
unsignedshort inlength : the lenth of user data.
void*_dataout : data buffer addr, to store the packet got by _datain packet assembly.
unsignedshort* outlength : the size of data buffer.
constairkiss_config_t* config : input struct airkiss_config_t
+
+
+
Returns
>=0 : succeed (reference airkiss_lan_ret_t)
+
+<0 : error code (reference airkiss_lan_ret_t)
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int airkiss_lan_recv (const void * body,
unsigned short length,
const airkiss_config_tconfig 
)
+
+ +

Parse the UDP packet sent by AirKiss.

+
Parameters
+ + + + +
constvoid* body : the start of the UDP message body data pointer.
unsignedshort length : the effective length of data.
constairkiss_config_t* config : input struct airkiss_config_t
+
+
+
Returns
>=0 : succeed (reference airkiss_lan_ret_t)
+
+<0 : error code (reference airkiss_lan_ret_t)
+ +
+
+ +
+
+ + + + + + + + +
const char* airkiss_version (void )
+
+ +

Get the version information of AirKiss lib.

+
Attention
The lenth of version is unknown
+
Parameters
+ + +
null.
+
+
+
Returns
the version information of AirKiss lib
+ +
+
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Driver__APIs.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Driver__APIs.html new file mode 100644 index 0000000..a11362f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Driver__APIs.html @@ -0,0 +1,117 @@ + + + + + + +ESP8266_RTOS_SDK: Driver APIs + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + +
+ +
+
+ + +
+ +
+ +
+ +
+
Driver APIs
+
+
+ +

Driver APIs. +More...

+ + + + + + + + + + + + + + + + + +

+Modules

 PWM Driver APIs
 PWM driver APIs.
 
 SPI Driver APIs
 SPI Flash APIs.
 
 GPIO Driver APIs
 GPIO APIs.
 
 Hardware timer APIs
 Hardware timer APIs.
 
 UART Driver APIs
 UART driver APIs.
 
+

Detailed Description

+

Driver APIs.

+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__ESPNow__APIs.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__ESPNow__APIs.html new file mode 100644 index 0000000..6d19524 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__ESPNow__APIs.html @@ -0,0 +1,960 @@ + + + + + + +ESP8266_RTOS_SDK: ESP-NOW APIs + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + +
+ +
+
+ + +
+ +
+ +
+ +
+
ESP-NOW APIs
+
+
+ +

ESP-NOW APIs. +More...

+ + + + + + + + +

+Typedefs

typedef void(* esp_now_recv_cb_t) (uint8 *mac_addr, uint8 *data, uint8 len)
 ESP-NOW send callback. More...
 
typedef void(* esp_now_send_cb_t) (uint8 *mac_addr, uint8 status)
 ESP-NOW send callback. More...
 
+ + + +

+Enumerations

enum  esp_now_role { ESP_NOW_ROLE_IDLE = 0, +ESP_NOW_ROLE_CONTROLLER, +ESP_NOW_ROLE_SLAVE, +ESP_NOW_ROLE_MAX + }
 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Functions

sint32 esp_now_init (void)
 ESP-NOW initialization. More...
 
sint32 esp_now_deinit (void)
 Deinitialize ESP-NOW. More...
 
sint32 esp_now_register_send_cb (esp_now_send_cb_t cb)
 Register ESP-NOW send callback. More...
 
sint32 esp_now_unregister_send_cb (void)
 Unregister ESP-NOW send callback. More...
 
sint32 esp_now_register_recv_cb (esp_now_recv_cb_t cb)
 Register ESP-NOW receive callback. More...
 
sint32 esp_now_unregister_recv_cb (void)
 Unregister ESP-NOW receive callback. More...
 
sint32 esp_now_send (uint8 *da, uint8 *data, uint8 len)
 Send ESP-NOW packet. More...
 
sint32 esp_now_add_peer (uint8 *mac_addr, uint8 role, uint8 channel, uint8 *key, uint8 key_len)
 Add an ESP-NOW peer, store MAC address of target device into ESP-NOW MAC list. More...
 
sint32 esp_now_del_peer (uint8 *mac_addr)
 Delete an ESP-NOW peer, delete MAC address of the device from ESP-NOW MAC list. More...
 
sint32 esp_now_set_self_role (uint8 role)
 Set ESP-NOW role of device itself. More...
 
sint32 esp_now_get_self_role (void)
 Get ESP-NOW role of device itself. More...
 
sint32 esp_now_set_peer_role (uint8 *mac_addr, uint8 role)
 Set ESP-NOW role for a target device. If it is set multiple times, new role will cover the old one. More...
 
sint32 esp_now_get_peer_role (uint8 *mac_addr)
 Get ESP-NOW role of a target device. More...
 
sint32 esp_now_set_peer_channel (uint8 *mac_addr, uint8 channel)
 Record channel information of a ESP-NOW device. More...
 
sint32 esp_now_get_peer_channel (uint8 *mac_addr)
 Get channel information of a ESP-NOW device. More...
 
sint32 esp_now_set_peer_key (uint8 *mac_addr, uint8 *key, uint8 key_len)
 Set ESP-NOW key for a target device. More...
 
sint32 esp_now_get_peer_key (uint8 *mac_addr, uint8 *key, uint8 *key_len)
 Get ESP-NOW key of a target device. More...
 
uint8 * esp_now_fetch_peer (bool restart)
 Get MAC address of ESP-NOW device. More...
 
sint32 esp_now_is_peer_exist (uint8 *mac_addr)
 Check if target device exists or not. More...
 
sint32 esp_now_get_cnt_info (uint8 *all_cnt, uint8 *encrypt_cnt)
 Get the total number of ESP-NOW devices which are associated, and the number count of encrypted devices. More...
 
sint32 esp_now_set_kok (uint8 *key, uint8 len)
 Set the encrypt key of communication key. More...
 
+

Detailed Description

+

ESP-NOW APIs.

+
Attention
1. ESP-NOW do not support broadcast and multicast.
+
+2. ESP-NOW is targeted to Smart-Light project, so it is suggested that slave role corresponding to soft-AP or soft-AP+station mode, controller role corresponding to station mode.
+
+3. When ESP8266 is in soft-AP+station mode, it will communicate through station interface if it is in slave role, and communicate through soft-AP interface if it is in controller role.
+
+4. ESP-NOW can not wake ESP8266 up from sleep, so if the target ESP8266 station is in sleep, ESP-NOW communication will fail.
+
+5. In station mode, ESP8266 supports 10 encrypt ESP-NOW peers at most, with the unencrypted peers, it can be 20 peers in total at most.
+
+6. In the soft-AP mode or soft-AP + station mode, the ESP8266 supports 6 encrypt ESP-NOW peers at most, with the unencrypted peers, it can be 20 peers in total at most.
+

Typedef Documentation

+ +
+
+ + + + +
typedef void(* esp_now_recv_cb_t) (uint8 *mac_addr, uint8 *data, uint8 len)
+
+ +

ESP-NOW send callback.

+
Attention
The status will be OK, if ESP-NOW send packet successfully. But users need to make sure by themselves that key of communication is correct.
+
Parameters
+ + + + +
uint8*mac_addr : MAC address of target device
uint8*data : data received
uint8len : data length
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + +
typedef void(* esp_now_send_cb_t) (uint8 *mac_addr, uint8 status)
+
+ +

ESP-NOW send callback.

+
Attention
The status will be OK, if ESP-NOW send packet successfully. But users need to make sure by themselves that key of communication is correct.
+
Parameters
+ + + +
uint8*mac_addr : MAC address of target device
uint8status : status of ESP-NOW sending packet, 0, OK; 1, fail.
+
+
+
Returns
null
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
sint32 esp_now_add_peer (uint8 * mac_addr,
uint8 role,
uint8 channel,
uint8 * key,
uint8 key_len 
)
+
+ +

Add an ESP-NOW peer, store MAC address of target device into ESP-NOW MAC list.

+
Parameters
+ + + + + + +
uint8*mac_addr : MAC address of device
uint8role : role type of device, enum esp_now_role
uint8channel : channel of device
uint8*key : 16 bytes key which is needed for ESP-NOW communication
uint8key_len : length of key, has to be 16 bytes now
+
+
+
Returns
0 : succeed
+
+Non-0 : fail
+ +
+
+ +
+
+ + + + + + + + +
sint32 esp_now_deinit (void )
+
+ +

Deinitialize ESP-NOW.

+
Parameters
+ + +
null
+
+
+
Returns
0 : succeed
+
+Non-0 : fail
+ +
+
+ +
+
+ + + + + + + + +
sint32 esp_now_del_peer (uint8 * mac_addr)
+
+ +

Delete an ESP-NOW peer, delete MAC address of the device from ESP-NOW MAC list.

+
Parameters
+ + +
u8*mac_addr : MAC address of device
+
+
+
Returns
0 : succeed
+
+Non-0 : fail
+ +
+
+ +
+
+ + + + + + + + +
uint8* esp_now_fetch_peer (bool restart)
+
+ +

Get MAC address of ESP-NOW device.

+

Get MAC address of ESP-NOW device which is pointed now, and move the pointer to next one in ESP-NOW MAC list or move the pointer to the first one in ESP-NOW MAC list.

+
Attention
1. This API can not re-entry
+
+2. Parameter has to be true when you call it the first time.
+
Parameters
+ + +
boolrestart : true, move pointer to the first one in ESP-NOW MAC list; false, move pointer to the next one in ESP-NOW MAC list
+
+
+
Returns
NULL, no ESP-NOW devices exist
+
+Otherwise, MAC address of ESP-NOW device which is pointed now
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
sint32 esp_now_get_cnt_info (uint8 * all_cnt,
uint8 * encrypt_cnt 
)
+
+ +

Get the total number of ESP-NOW devices which are associated, and the number count of encrypted devices.

+
Parameters
+ + + +
uint8*all_cnt : total number of ESP-NOW devices which are associated.
uint8*encryp_cnt : number count of encrypted devices
+
+
+
Returns
0 : succeed
+
+Non-0 : fail
+ +
+
+ +
+
+ + + + + + + + +
sint32 esp_now_get_peer_channel (uint8 * mac_addr)
+
+ +

Get channel information of a ESP-NOW device.

+
Attention
ESP-NOW communication needs to be at the same channel.
+
Parameters
+ + +
uint8*mac_addr : MAC address of target device.
+
+
+
Returns
1 ~ 13 (some area may get 14) : channel number
+
+Non-0 : fail
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
sint32 esp_now_get_peer_key (uint8 * mac_addr,
uint8 * key,
uint8 * key_len 
)
+
+ +

Get ESP-NOW key of a target device.

+

If it is set multiple times, new key will cover the old one.

+
Parameters
+ + + + +
uint8*mac_addr : MAC address of target device.
uint8*key : pointer of key, buffer size has to be 16 bytes at least
uint8key_len : key length
+
+
+
Returns
0 : succeed
+
+> 0 : find target device but can't get key
+
+< 0 : fail
+ +
+
+ +
+
+ + + + + + + + +
sint32 esp_now_get_peer_role (uint8 * mac_addr)
+
+ +

Get ESP-NOW role of a target device.

+
Parameters
+ + +
uint8*mac_addr : MAC address of device.
+
+
+
Returns
ESP_NOW_ROLE_CONTROLLER, role type : controller
+
+ESP_NOW_ROLE_SLAVE, role type : slave
+
+otherwise : fail
+ +
+
+ +
+
+ + + + + + + + +
sint32 esp_now_get_self_role (void )
+
+ +

Get ESP-NOW role of device itself.

+
Parameters
+ + +
uint8role : role type of device, enum esp_now_role.
+
+
+
Returns
0 : succeed
+
+Non-0 : fail
+ +
+
+ +
+
+ + + + + + + + +
sint32 esp_now_init (void )
+
+ +

ESP-NOW initialization.

+
Parameters
+ + +
null
+
+
+
Returns
0 : succeed
+
+Non-0 : fail
+ +
+
+ +
+
+ + + + + + + + +
sint32 esp_now_is_peer_exist (uint8 * mac_addr)
+
+ +

Check if target device exists or not.

+
Parameters
+ + +
uint8*mac_addr : MAC address of target device.
+
+
+
Returns
0 : device does not exist
+
+< 0 : error occur, check fail
+
+> 0 : device exists
+ +
+
+ +
+
+ + + + + + + + +
sint32 esp_now_register_recv_cb (esp_now_recv_cb_t cb)
+
+ +

Register ESP-NOW receive callback.

+
Parameters
+ + +
esp_now_recv_cb_tcb : receive callback
+
+
+
Returns
0 : succeed
+
+Non-0 : fail
+ +
+
+ +
+
+ + + + + + + + +
sint32 esp_now_register_send_cb (esp_now_send_cb_t cb)
+
+ +

Register ESP-NOW send callback.

+
Parameters
+ + +
esp_now_send_cb_tcb : send callback
+
+
+
Returns
0 : succeed
+
+Non-0 : fail
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
sint32 esp_now_send (uint8 * da,
uint8 * data,
uint8 len 
)
+
+ +

Send ESP-NOW packet.

+
Parameters
+ + + + +
uint8*da : destination MAC address. If it's NULL, send packet to all MAC addresses recorded by ESP-NOW; otherwise, send packet to target MAC address.
uint8*data : data need to send
uint8len : data length
+
+
+
Returns
0 : succeed
+
+Non-0 : fail
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
sint32 esp_now_set_kok (uint8 * key,
uint8 len 
)
+
+ +

Set the encrypt key of communication key.

+

All ESP-NOW devices share the same encrypt key. If users do not set the encrypt key, ESP-NOW communication key will be encrypted by a default key.

+
Parameters
+ + + +
uint8*key : pointer of encrypt key.
uint8len : key length, has to be 16 bytes now.
+
+
+
Returns
0 : succeed
+
+Non-0 : fail
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
sint32 esp_now_set_peer_channel (uint8 * mac_addr,
uint8 channel 
)
+
+ +

Record channel information of a ESP-NOW device.

+

When communicate with this device,

    +
  • call esp_now_get_peer_channel to get its channel first,
  • +
  • then call wifi_set_channel to be in the same channel and do communication.
  • +
+
Parameters
+ + + +
uint8*mac_addr : MAC address of target device.
uint8channel : channel, usually to be 1 ~ 13, some area may use channel 14.
+
+
+
Returns
0 : succeed
+
+Non-0 : fail
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
sint32 esp_now_set_peer_key (uint8 * mac_addr,
uint8 * key,
uint8 key_len 
)
+
+ +

Set ESP-NOW key for a target device.

+

If it is set multiple times, new key will cover the old one.

+
Parameters
+ + + + +
uint8*mac_addr : MAC address of target device.
uint8*key : 16 bytes key which is needed for ESP-NOW communication, if it is NULL, current key will be reset to be none.
uint8key_len : key length, has to be 16 bytes now
+
+
+
Returns
0 : succeed
+
+Non-0 : fail
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
sint32 esp_now_set_peer_role (uint8 * mac_addr,
uint8 role 
)
+
+ +

Set ESP-NOW role for a target device. If it is set multiple times, new role will cover the old one.

+
Parameters
+ + + +
uint8*mac_addr : MAC address of device.
uint8role : role type, enum esp_now_role.
+
+
+
Returns
0 : succeed
+
+Non-0 : fail
+ +
+
+ +
+
+ + + + + + + + +
sint32 esp_now_set_self_role (uint8 role)
+
+ +

Set ESP-NOW role of device itself.

+
Parameters
+ + +
uint8role : role type of device, enum esp_now_role.
+
+
+
Returns
0 : succeed
+
+Non-0 : fail
+ +
+
+ +
+
+ + + + + + + + +
sint32 esp_now_unregister_recv_cb (void )
+
+ +

Unregister ESP-NOW receive callback.

+
Parameters
+ + +
null
+
+
+
Returns
0 : succeed
+
+Non-0 : fail
+ +
+
+ +
+
+ + + + + + + + +
sint32 esp_now_unregister_send_cb (void )
+
+ +

Unregister ESP-NOW send callback.

+
Parameters
+ + +
null
+
+
+
Returns
0 : succeed
+
+Non-0 : fail
+ +
+
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Espconn__APIs.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Espconn__APIs.html new file mode 100644 index 0000000..ca82100 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Espconn__APIs.html @@ -0,0 +1,1977 @@ + + + + + + +ESP8266_RTOS_SDK: Network Espconn APIs + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + +
+ +
+
+ + +
+ +
+ +
+ +
+
Network Espconn APIs
+
+
+ +

Network espconn APIs. +More...

+ + + + + + + + + + +

+Data Structures

struct  _esp_tcp
 
struct  _esp_udp
 
struct  _remot_info
 
struct  espconn
 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Macros

#define ESPCONN_OK   0
 
#define ESPCONN_MEM   -1
 
#define ESPCONN_TIMEOUT   -3
 
#define ESPCONN_RTE   -4
 
#define ESPCONN_INPROGRESS   -5
 
#define ESPCONN_MAXNUM   -7
 
#define ESPCONN_ABRT   -8
 
#define ESPCONN_RST   -9
 
#define ESPCONN_CLSD   -10
 
#define ESPCONN_CONN   -11
 
#define ESPCONN_ARG   -12
 
#define ESPCONN_IF   -14
 
#define ESPCONN_ISCONN   -15
 
+ + + + + + + + + + + + + + + + + + + + +

+Typedefs

typedef void(* espconn_connect_callback) (void *arg)
 Connect callback. More...
 
typedef void(* espconn_reconnect_callback) (void *arg, sint8 err)
 Reconnect callback. More...
 
+typedef struct _esp_tcp esp_tcp
 
+typedef struct _esp_udp esp_udp
 
+typedef struct _remot_info remot_info
 
typedef void(* espconn_recv_callback) (void *arg, char *pdata, unsigned short len)
 
+typedef void(* espconn_sent_callback) (void *arg)
 
typedef void(* dns_found_callback) (const char *name, ip_addr_t *ipaddr, void *callback_arg)
 Callback which is invoked when a hostname is found. More...
 
+ + + + + + + + + + + +

+Enumerations

enum  espconn_type { ESPCONN_INVALID = 0, +ESPCONN_TCP = 0x10, +ESPCONN_UDP = 0x20 + }
 
enum  espconn_state {
+  ESPCONN_NONE, +ESPCONN_WAIT, +ESPCONN_LISTEN, +ESPCONN_CONNECT, +
+  ESPCONN_WRITE, +ESPCONN_READ, +ESPCONN_CLOSE +
+ }
 
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_IDLE = 0, +ESPCONN_CLIENT, +ESPCONN_SERVER, +ESPCONN_BOTH, +
+  ESPCONN_MAX +
+ }
 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Functions

void espconn_init (void)
 espconn initialization. More...
 
sint8 espconn_connect (struct espconn *espconn)
 Connect to a TCP server (ESP8266 acting as TCP client). More...
 
sint8 espconn_disconnect (struct espconn *espconn)
 Disconnect a TCP connection. More...
 
sint8 espconn_delete (struct espconn *espconn)
 Delete a transmission. More...
 
sint8 espconn_accept (struct espconn *espconn)
 Creates a TCP server (i.e. accepts connections). More...
 
sint8 espconn_create (struct espconn *espconn)
 Create UDP transmission. More...
 
uint8 espconn_tcp_get_max_con (void)
 Get maximum number of how many TCP connections are allowed. More...
 
sint8 espconn_tcp_set_max_con (uint8 num)
 Set the maximum number of how many TCP connection is allowed. More...
 
sint8 espconn_tcp_get_max_con_allow (struct espconn *espconn)
 Get the maximum number of TCP clients which are allowed to connect to ESP8266 TCP server. More...
 
sint8 espconn_tcp_set_max_con_allow (struct espconn *espconn, uint8 num)
 Set the maximum number of TCP clients allowed to connect to ESP8266 TCP server. More...
 
sint8 espconn_regist_time (struct espconn *espconn, uint32 interval, uint8 type_flag)
 Register timeout interval of ESP8266 TCP server. More...
 
sint8 espconn_get_connection_info (struct espconn *pespconn, remot_info **pcon_info, uint8 typeflags)
 Get the information about a TCP connection or UDP transmission. More...
 
sint8 espconn_regist_sentcb (struct espconn *espconn, espconn_sent_callback sent_cb)
 Register data sent callback which will be called back when data are successfully sent. More...
 
sint8 espconn_regist_write_finish (struct espconn *espconn, espconn_connect_callback write_finish_fn)
 Register a callback which will be called when all sending TCP data is completely write into write-buffer or sent. More...
 
sint8 espconn_send (struct espconn *espconn, uint8 *psent, uint16 length)
 Send data through network. More...
 
sint8 espconn_sent (struct espconn *espconn, uint8 *psent, uint16 length)
 Send data through network. More...
 
sint16 espconn_sendto (struct espconn *espconn, uint8 *psent, uint16 length)
 Send UDP data. More...
 
sint8 espconn_regist_connectcb (struct espconn *espconn, espconn_connect_callback connect_cb)
 Register connection function which will be called back under successful TCP connection. More...
 
sint8 espconn_regist_recvcb (struct espconn *espconn, espconn_recv_callback recv_cb)
 register data receive function which will be called back when data are received. More...
 
sint8 espconn_regist_reconcb (struct espconn *espconn, espconn_reconnect_callback recon_cb)
 Register reconnect callback. More...
 
sint8 espconn_regist_disconcb (struct espconn *espconn, espconn_connect_callback discon_cb)
 Register disconnection function which will be called back under successful TCP disconnection. More...
 
uint32 espconn_port (void)
 Get an available port for network. More...
 
sint8 espconn_set_opt (struct espconn *espconn, uint8 opt)
 Set option of TCP connection. More...
 
sint8 espconn_clear_opt (struct espconn *espconn, uint8 opt)
 Clear option of TCP connection. More...
 
sint8 espconn_set_keepalive (struct espconn *espconn, uint8 level, void *optarg)
 Set configuration of TCP keep alive. More...
 
sint8 espconn_get_keepalive (struct espconn *espconn, uint8 level, void *optarg)
 Get configuration of TCP keep alive. More...
 
err_t espconn_gethostbyname (struct espconn *pespconn, const char *hostname, ip_addr_t *addr, dns_found_callback found)
 DNS function. More...
 
sint8 espconn_igmp_join (ip_addr_t *host_ip, ip_addr_t *multicast_ip)
 Join a multicast group. More...
 
sint8 espconn_igmp_leave (ip_addr_t *host_ip, ip_addr_t *multicast_ip)
 Leave a multicast group. More...
 
sint8 espconn_recv_hold (struct espconn *pespconn)
 Puts in a request to block the TCP receive function. More...
 
sint8 espconn_recv_unhold (struct espconn *pespconn)
 Unblock TCP receiving data (i.e. undo espconn_recv_hold). More...
 
void espconn_dns_setserver (char numdns, ip_addr_t *dnsserver)
 Set default DNS server. Two DNS server is allowed to be set. More...
 
+

Detailed Description

+

Network espconn APIs.

+

Macro Definition Documentation

+ +
+
+ + + + +
#define ESPCONN_ABRT   -8
+
+

Connection aborted.

+ +
+
+ +
+
+ + + + +
#define ESPCONN_ARG   -12
+
+

Illegal argument.

+ +
+
+ +
+
+ + + + +
#define ESPCONN_CLSD   -10
+
+

Connection closed.

+ +
+
+ +
+
+ + + + +
#define ESPCONN_CONN   -11
+
+

Not connected.

+ +
+
+ +
+
+ + + + +
#define ESPCONN_IF   -14
+
+

UDP send error.

+ +
+
+ +
+
+ + + + +
#define ESPCONN_INPROGRESS   -5
+
+

Operation in progress.

+ +
+
+ +
+
+ + + + +
#define ESPCONN_ISCONN   -15
+
+

Already connected.

+ +
+
+ +
+
+ + + + +
#define ESPCONN_MAXNUM   -7
+
+

Total number exceeds the maximum limitation.

+ +
+
+ +
+
+ + + + +
#define ESPCONN_MEM   -1
+
+

Out of memory.

+ +
+
+ +
+
+ + + + +
#define ESPCONN_OK   0
+
+

No error, everything OK.

+ +
+
+ +
+
+ + + + +
#define ESPCONN_RST   -9
+
+

Connection reset.

+ +
+
+ +
+
+ + + + +
#define ESPCONN_RTE   -4
+
+

Routing problem.

+ +
+
+ +
+
+ + + + +
#define ESPCONN_TIMEOUT   -3
+
+

Timeout.

+ +
+
+

Typedef Documentation

+ +
+
+ + + + +
typedef void(* dns_found_callback) (const char *name, ip_addr_t *ipaddr, void *callback_arg)
+
+ +

Callback which is invoked when a hostname is found.

+
Parameters
+ + + + +
constchar *name : hostname
ip_addr_t*ipaddr : IP address of the hostname, or to be NULL if the name could not be found (or on any other error).
void*callback_arg : callback argument.
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + +
typedef void(* espconn_connect_callback) (void *arg)
+
+ +

Connect callback.

+

Callback which will be called if successful listening (ESP8266 as TCP server) or connection (ESP8266 as TCP client) callback, register by espconn_regist_connectcb.

+
Attention
The pointer "void *arg" may be different in different callbacks, please don't use this pointer directly to distinguish one from another in multiple connections, use remote_ip and remote_port in espconn instead.
+
Parameters
+ + +
void*arg : pointer corresponding structure espconn.
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + +
typedef void(* espconn_reconnect_callback) (void *arg, sint8 err)
+
+ +

Reconnect callback.

+

Enter this callback when error occurred, TCP connection broke. This callback is registered by espconn_regist_reconcb.

+
Attention
The pointer "void *arg" may be different in different callbacks, please don't use this pointer directly to distinguish one from another in multiple connections, use remote_ip and remote_port in espconn instead.
+
Parameters
+ + + +
void*arg : pointer corresponding structure espconn.
sint8err : error code
    +
  • ESCONN_TIMEOUT - Timeout
  • +
  • ESPCONN_ABRT - TCP connection aborted
  • +
  • ESPCONN_RST - TCP connection abort
  • +
  • ESPCONN_CLSD - TCP connection closed
  • +
  • ESPCONN_CONN - TCP connection
  • +
  • ESPCONN_HANDSHAKE - TCP SSL handshake fail
  • +
  • ESPCONN_PROTO_MSG - SSL application invalid
  • +
+
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + +
typedef void(* espconn_recv_callback) (void *arg, char *pdata, unsigned short len)
+
+

A callback prototype to inform about events for a espconn

+ +
+
+

Enumeration Type Documentation

+ +
+
+ + + + +
enum espconn_level
+
+ + + + +
Enumerator
ESPCONN_KEEPIDLE  +

TCP keep-alive interval, unit : second.

+
ESPCONN_KEEPINTVL  +

packet interval during TCP keep-alive, unit : second.

+
ESPCONN_KEEPCNT  +

maximum packet retry count of TCP keep-alive.

+
+ +
+
+ +
+
+ + + + +
enum espconn_option
+
+ + + + + + + +
Enumerator
ESPCONN_START  +

no option, start enum.

+
ESPCONN_REUSEADDR  +

free memory after TCP disconnection happen, need not wait 2 minutes.

+
ESPCONN_NODELAY  +

disable nagle algorithm during TCP data transmission, quicken the data transmission.

+
ESPCONN_COPY  +

enable espconn_regist_write_finish, enter write_finish_callback means that the data espconn_send sending was written into 2920 bytes write-buffer waiting for sending or already sent.

+
ESPCONN_KEEPALIVE  +

enable TCP keep alive.

+
ESPCONN_END  +

no option, end enum.

+
+ +
+
+ +
+
+ + + + +
enum espconn_state
+
+

Current state of the espconn.

+ + + + + + + + +
Enumerator
ESPCONN_NONE  +

idle state, no connection

+
ESPCONN_WAIT  +

ESP8266 is as TCP client, and waiting for connection

+
ESPCONN_LISTEN  +

ESP8266 is as TCP server, and waiting for connection

+
ESPCONN_CONNECT  +

connected

+
ESPCONN_WRITE  +

sending data

+
ESPCONN_READ  +

receiving data

+
ESPCONN_CLOSE  +

connection closed

+
+ +
+
+ +
+
+ + + + +
enum espconn_type
+
+

Protocol family and type of the espconn

+ + + + +
Enumerator
ESPCONN_INVALID  +

invalid type

+
ESPCONN_TCP  +

TCP

+
ESPCONN_UDP  +

UDP

+
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + +
sint8 espconn_accept (struct espconnespconn)
+
+ +

Creates a TCP server (i.e. accepts connections).

+
Parameters
+ + +
structespconn *espconn : the network connection structure
+
+
+
Returns
0 : succeed
+
+Non-0 : error code
    +
  • ESPCONN_MEM - Out of memory
  • +
  • ESPCONN_ISCONN - Already connected
  • +
  • ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection according to structure espconn
  • +
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
sint8 espconn_clear_opt (struct espconnespconn,
uint8 opt 
)
+
+ +

Clear option of TCP connection.

+
Parameters
+ + + +
structespconn *espconn : the TCP connection structure
uint8opt : enum espconn_option
+
+
+
Returns
0 : succeed
+
+Non-0 : error code
    +
  • ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection according to structure espconn
  • +
+
+ +
+
+ +
+
+ + + + + + + + +
sint8 espconn_connect (struct espconnespconn)
+
+ +

Connect to a TCP server (ESP8266 acting as TCP client).

+
Attention
If espconn_connect fail, returns non-0 value, there is no connection, so it won't enter any espconn callback.
+
Parameters
+ + +
structespconn *espconn : the network connection structure, the espconn to listen to the connection
+
+
+
Returns
0 : succeed
+
+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 TCP connection according to structure espconn
  • +
+
+ +
+
+ +
+
+ + + + + + + + +
sint8 espconn_create (struct espconnespconn)
+
+ +

Create UDP transmission.

+
Attention
Parameter remote_ip and remote_port need to be set, do not set to be 0.
+
Parameters
+ + +
structespconn *espconn : the UDP control block structure
+
+
+
Returns
0 : succeed
+
+Non-0 : error code
    +
  • ESPCONN_MEM - Out of memory
  • +
  • ESPCONN_ISCONN - Already connected
  • +
  • ESPCONN_ARG - illegal argument, can't find the corresponding UDP transmission according to structure espconn
  • +
+
+ +
+
+ +
+
+ + + + + + + + +
sint8 espconn_delete (struct espconnespconn)
+
+ +

Delete a transmission.

+
Attention
Corresponding creation API :
    +
  • TCP: espconn_accept,
  • +
  • UDP: espconn_create
  • +
+
+
Parameters
+ + +
structespconn *espconn : the network connection structure
+
+
+
Returns
0 : succeed
+
+Non-0 : error code
    +
  • ESPCONN_ARG - illegal argument, can't find the corresponding network according to structure espconn
  • +
  • ESPCONN_INPROGRESS - the connection is still in progress, please call espconn_disconnect to disconnect before delete it.
  • +
+
+ +
+
+ +
+
+ + + + + + + + +
sint8 espconn_disconnect (struct espconnespconn)
+
+ +

Disconnect a TCP connection.

+
Attention
Don't call this API in any espconn callback. If needed, please use system task to trigger espconn_disconnect.
+
Parameters
+ + +
structespconn *espconn : the network connection structure
+
+
+
Returns
0 : succeed
+
+Non-0 : error code
    +
  • ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection according to structure espconn
  • +
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void espconn_dns_setserver (char numdns,
ip_addr_t * dnsserver 
)
+
+ +

Set default DNS server. Two DNS server is allowed to be set.

+
Attention
Only if ESP8266 DHCP client is disabled (wifi_station_dhcpc_stop), this API can be used.
+
Parameters
+ + + +
charnumdns : DNS server ID, 0 or 1
ip_addr_t*dnsserver : DNS server IP
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
sint8 espconn_get_connection_info (struct espconnpespconn,
remot_info ** pcon_info,
uint8 typeflags 
)
+
+ +

Get the information about a TCP connection or UDP transmission.

+
Parameters
+ + + + +
structespconn *espconn : the network connection structure
remot_info**pcon_info : connect to client info
uint8typeflags : 0, regular server; 1, ssl server
+
+
+
Returns
0 : succeed
+
+Non-0 : error code
    +
  • ESPCONN_ARG - illegal argument, can't find the corresponding transmission according to structure espconn
  • +
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
sint8 espconn_get_keepalive (struct espconnespconn,
uint8 level,
void * optarg 
)
+
+ +

Get configuration of TCP keep alive.

+
Parameters
+ + + + +
structespconn *espconn : the TCP connection structure
uint8level : enum espconn_level
void*optarg : value of parameter
+
+
+
Returns
0 : succeed
+
+Non-0 : error code
    +
  • ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection according to structure espconn
  • +
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
err_t espconn_gethostbyname (struct espconnpespconn,
const char * hostname,
ip_addr_t * addr,
dns_found_callback found 
)
+
+ +

DNS function.

+

Parse a hostname (string) to an IP address.

+
Parameters
+ + + + + +
structespconn *pespconn : espconn to parse a hostname.
constchar *hostname : the hostname.
ip_addr_t*addr : IP address.
dns_found_callbackfound : callback of DNS
+
+
+
Returns
err_t :
    +
  • ESPCONN_OK - succeed
  • +
  • ESPCONN_INPROGRESS - error code : already connected
  • +
  • ESPCONN_ARG - error code : illegal argument, can't find network transmission according to structure espconn
  • +
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
sint8 espconn_igmp_join (ip_addr_t * host_ip,
ip_addr_t * multicast_ip 
)
+
+ +

Join a multicast group.

+
Attention
This API can only be called after the ESP8266 station connects to a router.
+
Parameters
+ + + +
ip_addr_t*host_ip : IP of UDP host
ip_addr_t*multicast_ip : IP of multicast group
+
+
+
Returns
0 : succeed
+
+Non-0 : error code
    +
  • ESPCONN_MEM - Out of memory
  • +
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
sint8 espconn_igmp_leave (ip_addr_t * host_ip,
ip_addr_t * multicast_ip 
)
+
+ +

Leave a multicast group.

+
Attention
This API can only be called after the ESP8266 station connects to a router.
+
Parameters
+ + + +
ip_addr_t*host_ip : IP of UDP host
ip_addr_t*multicast_ip : IP of multicast group
+
+
+
Returns
0 : succeed
+
+Non-0 : error code
    +
  • ESPCONN_MEM - Out of memory
  • +
+
+ +
+
+ +
+
+ + + + + + + + +
void espconn_init (void )
+
+ +

espconn initialization.

+
Attention
Please call this API in user_init, if you need to use espconn functions.
+
Parameters
+ + +
null
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
uint32 espconn_port (void )
+
+ +

Get an available port for network.

+
Parameters
+ + +
null
+
+
+
Returns
Port number.
+ +
+
+ +
+
+ + + + + + + + +
sint8 espconn_recv_hold (struct espconnpespconn)
+
+ +

Puts in a request to block the TCP receive function.

+
Attention
The function does not act immediately; we recommend calling it while reserving 5*1460 bytes of memory. This API can be called more than once.
+
Parameters
+ + +
structespconn *espconn : corresponding TCP connection structure
+
+
+
Returns
0 : succeed
+
+Non-0 : error code
    +
  • ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection according to structure espconn.
  • +
+
+ +
+
+ +
+
+ + + + + + + + +
sint8 espconn_recv_unhold (struct espconnpespconn)
+
+ +

Unblock TCP receiving data (i.e. undo espconn_recv_hold).

+
Attention
This API takes effect immediately.
+
Parameters
+ + +
structespconn *espconn : corresponding TCP connection structure
+
+
+
Returns
0 : succeed
+
+Non-0 : error code
    +
  • ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection according to structure espconn.
  • +
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
sint8 espconn_regist_connectcb (struct espconnespconn,
espconn_connect_callback connect_cb 
)
+
+ +

Register connection function which will be called back under successful TCP connection.

+
Parameters
+ + + +
structespconn *espconn : the TCP connection structure
espconn_connect_callbackconnect_cb : registered callback function
+
+
+
Returns
0 : succeed
+
+Non-0 : error code
    +
  • ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection according to structure espconn
  • +
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
sint8 espconn_regist_disconcb (struct espconnespconn,
espconn_connect_callback discon_cb 
)
+
+ +

Register disconnection function which will be called back under successful TCP disconnection.

+
Parameters
+ + + +
structespconn *espconn : the TCP connection structure
espconn_connect_callbackdiscon_cb : registered callback function
+
+
+
Returns
0 : succeed
+
+Non-0 : error code
    +
  • ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection according to structure espconn
  • +
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
sint8 espconn_regist_reconcb (struct espconnespconn,
espconn_reconnect_callback recon_cb 
)
+
+ +

Register reconnect callback.

+
Attention
espconn_reconnect_callback is more like a network-broken error handler; it handles errors that occurs in any phase of the connection. For instance, if espconn_send fails, espconn_reconnect_callback will be called because the network is broken.
+
Parameters
+ + + +
structespconn *espconn : the TCP connection structure
espconn_reconnect_callbackrecon_cb : registered callback function
+
+
+
Returns
0 : succeed
+
+Non-0 : error code
    +
  • ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection according to structure espconn
  • +
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
sint8 espconn_regist_recvcb (struct espconnespconn,
espconn_recv_callback recv_cb 
)
+
+ +

register data receive function which will be called back when data are received.

+
Parameters
+ + + +
structespconn *espconn : the network transmission structure
espconn_recv_callbackrecv_cb : registered callback function
+
+
+
Returns
0 : succeed
+
+Non-0 : error code
    +
  • ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection according to structure espconn
  • +
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
sint8 espconn_regist_sentcb (struct espconnespconn,
espconn_sent_callback sent_cb 
)
+
+ +

Register data sent callback which will be called back when data are successfully sent.

+
Parameters
+ + + +
structespconn *espconn : the network connection structure
espconn_sent_callbacksent_cb : registered callback function which will be called if the data is successfully sent
+
+
+
Returns
0 : succeed
+
+Non-0 : error code
    +
  • ESPCONN_ARG - illegal argument, can't find the corresponding transmission according to structure espconn
  • +
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
sint8 espconn_regist_time (struct espconnespconn,
uint32 interval,
uint8 type_flag 
)
+
+ +

Register timeout interval of ESP8266 TCP server.

+
Attention
1. If timeout is set to 0, timeout will be disable and ESP8266 TCP server will not disconnect TCP clients has stopped communication. This usage of timeout=0, is deprecated.
+
+2. This timeout interval is not very precise, only as reference.
+
Parameters
+ + + + +
structespconn *espconn : the TCP connection structure
uint32interval : timeout interval, unit: second, maximum: 7200 seconds
uint8type_flag : 0, set for all connections; 1, set for a specific connection
    +
  • If the type_flag set to be 0, please call this API after espconn_accept, before listened a TCP connection.
  • +
  • If the type_flag set to be 1, the first parameter *espconn is the specific connection.
  • +
+
+
+
+
Returns
0 : succeed
+
+Non-0 : error code
    +
  • ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection according to structure espconn
  • +
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
sint8 espconn_regist_write_finish (struct espconnespconn,
espconn_connect_callback write_finish_fn 
)
+
+ +

Register a callback which will be called when all sending TCP data is completely write into write-buffer or sent.

+

Need to call espconn_set_opt to enable write-buffer first.

+
Attention
1. write-buffer is used to keep TCP data that waiting to be sent, queue number of the write-buffer is 8 which means that it can keep 8 packets at most. The size of write-buffer is 2920 bytes.
+
+2. Users can enable it by using espconn_set_opt.
+
+3. Users can call espconn_send to send the next packet in write_finish_callback instead of using espconn_sent_callback.
+
Parameters
+ + + +
structespconn *espconn : the network connection structure
espconn_connect_callbackwrite_finish_fn : registered callback function which will be called if the data is completely write into write buffer or sent.
+
+
+
Returns
0 : succeed
+
+Non-0 : error code
    +
  • ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection according to structure espconn
  • +
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
sint8 espconn_send (struct espconnespconn,
uint8 * psent,
uint16 length 
)
+
+ +

Send data through network.

+
Attention
1. Please call espconn_send after espconn_sent_callback of the pre-packet.
+
+2. If it is a UDP transmission, it is suggested to set espconn->proto.udp->remote_ip and remote_port before every calling of espconn_send.
+
Parameters
+ + + + +
structespconn *espconn : the network connection structure
uint8*psent : pointer of data
uint16length : data length
+
+
+
Returns
0 : succeed
+
+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
  • +
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
sint16 espconn_sendto (struct espconnespconn,
uint8 * psent,
uint16 length 
)
+
+ +

Send UDP data.

+
Parameters
+ + + + +
structespconn *espconn : the UDP structure
uint8*psent : pointer of data
uint16length : data length
+
+
+
Returns
0 : succeed
+
+Non-0 : error code
    +
  • ESPCONN_MEM - Out of memory
  • +
  • ESPCONN_MAXNUM - buffer of sending data is full
  • +
  • ESPCONN_IF - send UDP data fail
  • +
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
sint8 espconn_sent (struct espconnespconn,
uint8 * psent,
uint16 length 
)
+
+ +

Send data through network.

+

This API is deprecated, please use espconn_send instead.

+
Attention
1. Please call espconn_sent after espconn_sent_callback of the pre-packet.
+
+2. If it is a UDP transmission, it is suggested to set espconn->proto.udp->remote_ip and remote_port before every calling of espconn_sent.
+
Parameters
+ + + + +
structespconn *espconn : the network connection structure
uint8*psent : pointer of data
uint16length : data length
+
+
+
Returns
0 : succeed
+
+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
  • +
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
sint8 espconn_set_keepalive (struct espconnespconn,
uint8 level,
void * optarg 
)
+
+ +

Set configuration of TCP keep alive.

+
Attention
In general, we need not call this API. If needed, please call it in espconn_connect_callback and call espconn_set_opt to enable keep alive first.
+
Parameters
+ + + + +
structespconn *espconn : the TCP connection structure
uint8level : To do TCP keep-alive detection every ESPCONN_KEEPIDLE. If there is no response, retry ESPCONN_KEEPCNT times every ESPCONN_KEEPINTVL. If still no response, considers it as TCP connection broke, goes into espconn_reconnect_callback. Notice, keep alive interval is not precise, only for reference, it depends on priority.
void*optarg : value of parameter
+
+
+
Returns
0 : succeed
+
+Non-0 : error code
    +
  • ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection according to structure espconn
  • +
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
sint8 espconn_set_opt (struct espconnespconn,
uint8 opt 
)
+
+ +

Set option of TCP connection.

+
Attention
In general, we need not call this API. If call espconn_set_opt, please call it in espconn_connect_callback.
+
Parameters
+ + + +
structespconn *espconn : the TCP connection structure
uint8opt : option of TCP connection, refer to enum espconn_option
    +
  • bit 0: 1: free memory after TCP disconnection happen need not wait 2 minutes;
  • +
  • bit 1: 1: disable nagle algorithm during TCP data transmission, quiken the data transmission.
  • +
  • bit 2: 1: enable espconn_regist_write_finish, enter write finish callback means the data espconn_send sending was written into 2920 bytes write-buffer waiting for sending or already sent.
  • +
  • bit 3: 1: enable TCP keep alive
  • +
+
+
+
+
Returns
0 : succeed
+
+Non-0 : error code
    +
  • ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection according to structure espconn
  • +
+
+ +
+
+ +
+
+ + + + + + + + +
uint8 espconn_tcp_get_max_con (void )
+
+ +

Get maximum number of how many TCP connections are allowed.

+
Parameters
+ + +
null
+
+
+
Returns
Maximum number of how many TCP connections are allowed.
+ +
+
+ +
+
+ + + + + + + + +
sint8 espconn_tcp_get_max_con_allow (struct espconnespconn)
+
+ +

Get the maximum number of TCP clients which are allowed to connect to ESP8266 TCP server.

+
Parameters
+ + +
structespconn *espconn : the TCP server structure
+
+
+
Returns
0 : succeed
+
+Non-0 : error code
    +
  • ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection according to structure espconn
  • +
+
+ +
+
+ +
+
+ + + + + + + + +
sint8 espconn_tcp_set_max_con (uint8 num)
+
+ +

Set the maximum number of how many TCP connection is allowed.

+
Parameters
+ + +
uint8num : Maximum number of how many TCP connection is allowed.
+
+
+
Returns
0 : succeed
+
+Non-0 : error code
    +
  • ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection according to structure espconn
  • +
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
sint8 espconn_tcp_set_max_con_allow (struct espconnespconn,
uint8 num 
)
+
+ +

Set the maximum number of TCP clients allowed to connect to ESP8266 TCP server.

+
Parameters
+ + + +
structespconn *espconn : the TCP server structure
uint8num : Maximum number of TCP clients which are allowed
+
+
+
Returns
0 : succeed
+
+Non-0 : error code
    +
  • ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection according to structure espconn
  • +
+
+ +
+
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__GPIO__Driver__APIs.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__GPIO__Driver__APIs.html new file mode 100644 index 0000000..a31f072 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__GPIO__Driver__APIs.html @@ -0,0 +1,638 @@ + + + + + + +ESP8266_RTOS_SDK: GPIO Driver APIs + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + +
+ +
+
+ + +
+ +
+ +
+ +
+
GPIO Driver APIs
+
+
+ +

GPIO APIs. +More...

+ + + + + + + + + + + + + + + + + + + + +

+Macros

#define GPIO_OUTPUT_SET(gpio_no, bit_value)   gpio_output_conf(bit_value<<gpio_no, ((~bit_value)&0x01)<<gpio_no, 1<<gpio_no, 0)
 Set GPIO pin output level. More...
 
#define GPIO_OUTPUT(gpio_bits, bit_value)
 Set GPIO pin output level. More...
 
#define GPIO_DIS_OUTPUT(gpio_no)    gpio_output_conf(0, 0, 0, 1<<gpio_no)
 Disable GPIO pin output. More...
 
#define GPIO_AS_INPUT(gpio_bits)    gpio_output_conf(0, 0, 0, gpio_bits)
 Enable GPIO pin intput. More...
 
#define GPIO_AS_OUTPUT(gpio_bits)    gpio_output_conf(0, 0, gpio_bits, 0)
 Enable GPIO pin output. More...
 
#define GPIO_INPUT_GET(gpio_no)    ((gpio_input_get()>>gpio_no)&BIT0)
 Sample the level of GPIO input. More...
 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Functions

void gpio16_output_conf (void)
 Enable GPIO16 output. More...
 
void gpio16_output_set (uint8 value)
 Set GPIO16 output level. More...
 
void gpio16_input_conf (void)
 Enable GPIO pin intput. More...
 
uint8 gpio16_input_get (void)
 Sample the value of GPIO16 input. More...
 
void gpio_output_conf (uint32 set_mask, uint32 clear_mask, uint32 enable_mask, uint32 disable_mask)
 Configure Gpio pins out or input. More...
 
void gpio_intr_handler_register (void *fn, void *arg)
 Register an application-specific interrupt handler for GPIO pin interrupts. More...
 
void gpio_pin_wakeup_enable (uint32 i, GPIO_INT_TYPE intr_state)
 Configure GPIO wake up to light sleep,Only level way is effective. More...
 
void gpio_pin_wakeup_disable ()
 Disable GPIO wake up to light sleep. More...
 
void gpio_pin_intr_state_set (uint32 i, GPIO_INT_TYPE intr_state)
 Config interrupt types of GPIO pin. More...
 
uint32 gpio_input_get (void)
 Sample the value of GPIO input pins and returns a bitmask. More...
 
+

Detailed Description

+

GPIO APIs.

+

Macro Definition Documentation

+ +
+
+ + + + + + + + +
#define GPIO_AS_INPUT( gpio_bits)   gpio_output_conf(0, 0, 0, gpio_bits)
+
+ +

Enable GPIO pin intput.

+
Parameters
+ + +
gpio_bits: The GPIO bit number.
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
#define GPIO_AS_OUTPUT( gpio_bits)   gpio_output_conf(0, 0, gpio_bits, 0)
+
+ +

Enable GPIO pin output.

+
Parameters
+ + +
gpio_bits: The GPIO bit number.
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
#define GPIO_DIS_OUTPUT( gpio_no)   gpio_output_conf(0, 0, 0, 1<<gpio_no)
+
+ +

Disable GPIO pin output.

+
Parameters
+ + +
gpio_no: The GPIO sequence number.
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
#define GPIO_INPUT_GET( gpio_no)   ((gpio_input_get()>>gpio_no)&BIT0)
+
+ +

Sample the level of GPIO input.

+
Parameters
+ + +
gpio_no: The GPIO sequence number.
+
+
+
Returns
the level of GPIO input
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
#define GPIO_OUTPUT( gpio_bits,
 bit_value 
)
+
+Value:
if(bit_value) gpio_output_conf(gpio_bits, 0, gpio_bits, 0);\
+
else gpio_output_conf(0, gpio_bits, gpio_bits, 0)
+
void gpio_output_conf(uint32 set_mask, uint32 clear_mask, uint32 enable_mask, uint32 disable_mask)
Configure Gpio pins out or input.
+
+

Set GPIO pin output level.

+
Parameters
+ + + +
gpio_bits: The GPIO bit number.
bit_value: GPIO pin output level.
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
#define GPIO_OUTPUT_SET( gpio_no,
 bit_value 
)   gpio_output_conf(bit_value<<gpio_no, ((~bit_value)&0x01)<<gpio_no, 1<<gpio_no, 0)
+
+ +

Set GPIO pin output level.

+
Parameters
+ + + +
gpio_no: The GPIO sequence number.
bit_value: GPIO pin output level.
+
+
+
Returns
null
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + +
void gpio16_input_conf (void )
+
+ +

Enable GPIO pin intput.

+
Parameters
+ + +
null
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
uint8 gpio16_input_get (void )
+
+ +

Sample the value of GPIO16 input.

+
Parameters
+ + +
null
+
+
+
Returns
the level of GPIO16 input.
+ +
+
+ +
+
+ + + + + + + + +
void gpio16_output_conf (void )
+
+ +

Enable GPIO16 output.

+
Parameters
+ + +
null
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
void gpio16_output_set (uint8 value)
+
+ +

Set GPIO16 output level.

+
Parameters
+ + +
uint8value : GPIO16 output level.
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
uint32 gpio_input_get (void )
+
+ +

Sample the value of GPIO input pins and returns a bitmask.

+
Parameters
+ + +
null
+
+
+
Returns
bitmask of GPIO pins input
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void gpio_intr_handler_register (void * fn,
void * arg 
)
+
+ +

Register an application-specific interrupt handler for GPIO pin interrupts.

+
Parameters
+ + + +
void*fn:interrupt handler for GPIO pin interrupts.
void*arg:interrupt handler's arg
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void gpio_output_conf (uint32 set_mask,
uint32 clear_mask,
uint32 enable_mask,
uint32 disable_mask 
)
+
+ +

Configure Gpio pins out or input.

+
Parameters
+ + + + + +
uint32set_mask : Set the output for the high bit, the corresponding bit is 1, the output of high, the corresponding bit is 0, do not change the state.
uint32set_mask : Set the output for the high bit, the corresponding bit is 1, the output of low, the corresponding bit is 0, do not change the state.
uint32enable_mask : Enable Output
uint32disable_mask : Enable Input
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void gpio_pin_intr_state_set (uint32 i,
GPIO_INT_TYPE intr_state 
)
+
+ +

Config interrupt types of GPIO pin.

+
Parameters
+ + + +
uint32i : The GPIO sequence number.
GPIO_INT_TYPEintr_state : GPIO interrupt types.
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + +
void gpio_pin_wakeup_disable ()
+
+ +

Disable GPIO wake up to light sleep.

+
Parameters
+ + +
null
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void gpio_pin_wakeup_enable (uint32 i,
GPIO_INT_TYPE intr_state 
)
+
+ +

Configure GPIO wake up to light sleep,Only level way is effective.

+
Parameters
+ + + +
uint32i : Gpio sequence number
GPIO_INT_TYPEintr_state : the level of wake up to light sleep
+
+
+
Returns
null
+ +
+
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__HW__Timer__APIs.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__HW__Timer__APIs.html new file mode 100644 index 0000000..826f717 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__HW__Timer__APIs.html @@ -0,0 +1,197 @@ + + + + + + +ESP8266_RTOS_SDK: Hardware timer APIs + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + +
+ +
+
+ + +
+ +
+ +
+ +
+
Hardware timer APIs
+
+
+ +

Hardware timer APIs. +More...

+ + + + + + + + + + + +

+Functions

void hw_timer_init (uint8 req)
 Initialize the hardware ISR timer. More...
 
void hw_timer_arm (uint32 val)
 Set a trigger timer delay to enable this timer. More...
 
void hw_timer_set_func (void(*user_hw_timer_cb_set)(void))
 Set timer callback function. More...
 
+

Detailed Description

+

Hardware timer APIs.

+
Attention
Hardware timer can not interrupt other ISRs.
+

Function Documentation

+ +
+
+ + + + + + + + +
void hw_timer_arm (uint32 val)
+
+ +

Set a trigger timer delay to enable this timer.

+
Parameters
+ + +
uint32val : Timing
    +
  • In autoload mode, range : 50 ~ 0x7fffff
  • +
  • In non-autoload mode, range : 10 ~ 0x7fffff
  • +
+
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
void hw_timer_init (uint8 req)
+
+ +

Initialize the hardware ISR timer.

+
Parameters
+ + +
uint8req : 0, not autoload; 1, autoload mode.
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
void hw_timer_set_func (void(*)(void) user_hw_timer_cb_set)
+
+ +

Set timer callback function.

+

For enabled timer, timer callback has to be set.

+
Parameters
+ + +
uint32val : Timing
    +
  • In autoload mode, range : 50 ~ 0x7fffff
  • +
  • In non-autoload mode, range : 10 ~ 0x7fffff
  • +
+
+
+
+
Returns
null
+ +
+
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Mesh__APIs.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Mesh__APIs.html new file mode 100644 index 0000000..2f2dd84 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Mesh__APIs.html @@ -0,0 +1,731 @@ + + + + + + +ESP8266_RTOS_SDK: Mesh APIs + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + +
+ +
+
+ + +
+ +
+ +
+ +
+
Mesh APIs
+
+
+ +

Mesh APIs. +More...

+ + + + + + +

+Enumerations

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 + }
 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Functions

bool espconn_mesh_local_addr (struct ip_addr *ip)
 Check whether the IP address is mesh local IP address or not. More...
 
bool espconn_mesh_get_node_info (enum mesh_node_type type, uint8_t **info, uint8_t *count)
 Get the information of mesh node. More...
 
bool espconn_mesh_encrypt_init (AUTH_MODE mode, uint8_t *passwd, uint8_t passwd_len)
 Set WiFi cryption algrithm and password for mesh node. More...
 
bool espconn_mesh_set_ssid_prefix (uint8_t *prefix, uint8_t prefix_len)
 Set prefix of SSID for mesh node. More...
 
bool espconn_mesh_set_max_hops (uint8_t max_hops)
 Set max hop for mesh network. More...
 
bool espconn_mesh_group_id_init (uint8_t *grp_id, uint16_t gid_len)
 Set group ID of mesh node. More...
 
bool espconn_mesh_set_dev_type (uint8_t dev_type)
 Set the curent device type. More...
 
sint8 espconn_mesh_connect (struct espconn *usr_esp)
 Try to establish mesh connection to server. More...
 
sint8 espconn_mesh_disconnect (struct espconn *usr_esp)
 Disconnect a mesh connection. More...
 
sint8 espconn_mesh_get_status ()
 Get current mesh status. More...
 
sint8 espconn_mesh_sent (struct espconn *usr_esp, uint8 *pdata, uint16 len)
 Send data through mesh network. More...
 
uint8 espconn_mesh_get_max_hops ()
 Get max hop of mesh network. More...
 
void espconn_mesh_enable (espconn_mesh_callback enable_cb, enum mesh_type type)
 To enable mesh network. More...
 
void espconn_mesh_disable (espconn_mesh_callback disable_cb)
 To disable mesh network. More...
 
void espconn_mesh_init ()
 To print version of mesh. More...
 
+

Detailed Description

+

Mesh APIs.

+

Enumeration Type Documentation

+ +
+
+ + + + +
enum mesh_node_type
+
+ + + + +
Enumerator
MESH_NODE_PARENT  +

get information of parent node

+
MESH_NODE_CHILD  +

get information of child node(s)

+
MESH_NODE_ALL  +

get information of all nodes

+
+ +
+
+ +
+
+ + + + +
enum mesh_status
+
+ + + + + + +
Enumerator
MESH_DISABLE  +

mesh disabled

+
MESH_WIFI_CONN  +

WiFi connected

+
MESH_NET_CONN  +

TCP connection OK

+
MESH_LOCAL_AVAIL  +

local mesh is avaliable

+
MESH_ONLINE_AVAIL  +

online mesh is avaliable

+
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + +
sint8 espconn_mesh_connect (struct espconnusr_esp)
+
+ +

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.
+
Parameters
+ + +
structespconn *usr_esp : the network connection structure, the usr_esp to listen to the connection
+
+
+
Returns
0 : succeed
+
+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
  • +
+
+ +
+
+ +
+
+ + + + + + + + +
void espconn_mesh_disable (espconn_mesh_callback disable_cb)
+
+ +

To disable mesh network.

+
Attention
When mesh network is disabed, the system will trigger disable_cb.
+
Parameters
+ + + +
espconn_mesh_callbackdisable_cb : callback function of mesh-disable
enummesh_type type : type of mesh, local or online.
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
sint8 espconn_mesh_disconnect (struct espconnusr_esp)
+
+ +

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.
+
Parameters
+ + +
structespconn *usr_esp : the network connection structure
+
+
+
Returns
0 : succeed
+
+Non-0 : error code
    +
  • ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection according to structure espconn
  • +
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void espconn_mesh_enable (espconn_mesh_callback enable_cb,
enum mesh_type type 
)
+
+ +

To enable mesh network.

+
Attention
1. the function should be called in user_init.
+
+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.
+
+3. if user try to enable online mesh, but node fails to establish mesh connection the node will work with local mesh.
+
Parameters
+ + + +
espconn_mesh_callbackenable_cb : callback function of mesh-enable
enummesh_type type : type of mesh, local or online.
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
bool espconn_mesh_encrypt_init (AUTH_MODE mode,
uint8_t * passwd,
uint8_t passwd_len 
)
+
+ +

Set WiFi cryption algrithm and password for mesh node.

+
Attention
The function must be called before espconn_mesh_enable.
+
Parameters
+ + + + +
AUTH_MODEmode : cryption algrithm (WPA/WAP2/WPA_WPA2).
uint8_t*passwd : password of WiFi.
uint8_tpasswd_len : length of password (8 <= passwd_len <= 64).
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + +
uint8 espconn_mesh_get_max_hops ()
+
+ +

Get max hop of mesh network.

+
Parameters
+ + +
null.
+
+
+
Returns
the current max hop of mesh
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
bool espconn_mesh_get_node_info (enum mesh_node_type type,
uint8_t ** info,
uint8_t * count 
)
+
+ +

Get the information of mesh node.

+
Parameters
+ + + + +
enummesh_node_type typ : mesh node type.
uint8_t**info : the information will be saved in *info.
uint8_t*count : the node count in *info.
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + +
sint8 espconn_mesh_get_status ()
+
+ +

Get current mesh status.

+
Parameters
+ + +
null
+
+
+
Returns
the current mesh status, please refer to enum mesh_status.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
bool espconn_mesh_group_id_init (uint8_t * grp_id,
uint16_t gid_len 
)
+
+ +

Set group ID of mesh node.

+
Attention
The function must be called before espconn_mesh_enable.
+
Parameters
+ + + +
uint8_t*grp_id : group ID.
uint16_tgid_len: length of group ID, now gid_len = 6.
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + +
void espconn_mesh_init ()
+
+ +

To print version of mesh.

+
Parameters
+ + +
null
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
bool espconn_mesh_local_addr (struct ip_addr * ip)
+
+ +

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.*.
+
+2. IP pointer should not be NULL. If the IP pointer is NULL, it will return false.
+
Parameters
+ + +
structip_addr *ip : IP address
+
+
+
Returns
true : the IP address is mesh local IP address
+
+false : the IP address is not mesh local IP address
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
sint8 espconn_mesh_sent (struct espconnusr_esp,
uint8 * pdata,
uint16 len 
)
+
+ +

Send data through mesh network.

+
Attention
Please call espconn_mesh_sent after espconn_sent_callback of the pre-packet.
+
Parameters
+ + + + +
structespconn *usr_esp : the network connection structure
uint8*pdata : pointer of data
uint16len : data length
+
+
+
Returns
0 : succeed
+
+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
  • +
+
+ +
+
+ +
+
+ + + + + + + + +
bool espconn_mesh_set_dev_type (uint8_t dev_type)
+
+ +

Set the curent device type.

+
Parameters
+ + +
uint8_tdev_type : device type of mesh node
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
bool espconn_mesh_set_max_hops (uint8_t max_hops)
+
+ +

Set max hop for mesh network.

+
Attention
The function must be called before espconn_mesh_enable.
+
Parameters
+ + +
uint8_tmax_hops : max hop of mesh network (1 <= max_hops < 10, 4 is recommended).
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
bool espconn_mesh_set_ssid_prefix (uint8_t * prefix,
uint8_t prefix_len 
)
+
+ +

Set prefix of SSID for mesh node.

+
Attention
The function must be called before espconn_mesh_enable.
+
Parameters
+ + + +
uint8_t*prefix : prefix of SSID.
uint8_tprefix_len : length of prefix (0 < passwd_len <= 22).
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Misc__APIs.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Misc__APIs.html new file mode 100644 index 0000000..718d1a1 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Misc__APIs.html @@ -0,0 +1,287 @@ + + + + + + +ESP8266_RTOS_SDK: Misc APIs + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + +
+ +
+
+ + +
+ +
+ +
+ +
+
Misc APIs
+
+
+ +

misc APIs +More...

+ + + + +

+Data Structures

struct  dhcps_lease
 
+ + + + + + + + + +

+Macros

+#define MAC2STR(a)   (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
 
+#define MACSTR   "%02x:%02x:%02x:%02x:%02x:%02x"
 
#define IP2STR(ipaddr)
 
+#define IPSTR   "%d.%d.%d.%d"
 
+ + + + + +

+Enumerations

enum  dhcp_status { DHCP_STOPPED, +DHCP_STARTED + }
 
enum  dhcps_offer_option { OFFER_START = 0x00, +OFFER_ROUTER = 0x01, +OFFER_END + }
 
+ + + + + + + + + + +

+Functions

void os_delay_us (uint16 us)
 Delay function, maximum value: 65535 us. More...
 
void os_install_putc1 (void(*p)(char c))
 Register the print output function. More...
 
void os_putc (char c)
 Print a character. Start from from UART0 by default. More...
 
+

Detailed Description

+

misc APIs

+

Macro Definition Documentation

+ +
+
+ + + + + + + + +
#define IP2STR( ipaddr)
+
+Value:
ip4_addr1_16(ipaddr), \
+
ip4_addr2_16(ipaddr), \
+
ip4_addr3_16(ipaddr), \
+
ip4_addr4_16(ipaddr)
+
+
+
+

Enumeration Type Documentation

+ +
+
+ + + + +
enum dhcp_status
+
+ + + +
Enumerator
DHCP_STOPPED  +

disable DHCP

+
DHCP_STARTED  +

enable DHCP

+
+ +
+
+ +
+
+ + + + +
enum dhcps_offer_option
+
+ + + + +
Enumerator
OFFER_START  +

DHCP offer option start

+
OFFER_ROUTER  +

DHCP offer router, only support this option now

+
OFFER_END  +

DHCP offer option start

+
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + +
void os_delay_us (uint16 us)
+
+ +

Delay function, maximum value: 65535 us.

+
Parameters
+ + +
uint16us : delay time, uint: us, maximum value: 65535 us
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
void os_install_putc1 (void(*)(char c) p)
+
+ +

Register the print output function.

+
Attention
os_install_putc1((void *)uart1_write_char) in uart_init will set printf to print from UART 1, otherwise, printf will start from UART 0 by default.
+
Parameters
+ + +
void(*p)(charc) - pointer of print function
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
void os_putc (char c)
+
+ +

Print a character. Start from from UART0 by default.

+
Parameters
+ + +
charc - character to be printed
+
+
+
Returns
null
+ +
+
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__PWM__Driver__APIs.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__PWM__Driver__APIs.html new file mode 100644 index 0000000..355a74a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__PWM__Driver__APIs.html @@ -0,0 +1,326 @@ + + + + + + +ESP8266_RTOS_SDK: PWM Driver APIs + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + +
+ +
+
+ + +
+ +
+ +
+ +
+
PWM Driver APIs
+
+
+ +

PWM driver APIs. +More...

+ + + + +

+Data Structures

struct  pwm_param
 
+ + + +

+Macros

+#define PWM_DEPTH   1023
 
+ + + + + + + + + + + + + + + + + + + +

+Functions

void pwm_init (uint32 period, uint32 *duty, uint32 pwm_channel_num, uint32(*pin_info_list)[3])
 PWM function initialization, including GPIO, frequency and duty cycle. More...
 
void pwm_set_duty (uint32 duty, uint8 channel)
 Set the duty cycle of a PWM channel. More...
 
uint32 pwm_get_duty (uint8 channel)
 Get the duty cycle of a PWM channel. More...
 
void pwm_set_period (uint32 period)
 Set PWM period, unit : us. More...
 
uint32 pwm_get_period (void)
 Get PWM period, unit : us. More...
 
void pwm_start (void)
 Starts PWM. More...
 
+

Detailed Description

+

PWM driver APIs.

+

Function Documentation

+ +
+
+ + + + + + + + +
uint32 pwm_get_duty (uint8 channel)
+
+ +

Get the duty cycle of a PWM channel.

+
Parameters
+ + +
uint8channel : PWM channel number
+
+
+
Returns
Duty cycle of PWM output.
+ +
+
+ +
+
+ + + + + + + + +
uint32 pwm_get_period (void )
+
+ +

Get PWM period, unit : us.

+
Parameters
+ + +
null
+
+
+
Returns
PWM period, unit : us.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void pwm_init (uint32 period,
uint32 * duty,
uint32 pwm_channel_num,
uint32(*) pin_info_list[3] 
)
+
+ +

PWM function initialization, including GPIO, frequency and duty cycle.

+
Attention
This API can be called only once.
+
Parameters
+ + + + + +
uint32period : pwm frequency
uint32*duty : duty cycle
uint32pwm_channel_num : PWM channel number
uint32(*pin_info_list)[3] : GPIO parameter of PWM channel, it is a pointer of n x 3 array which defines GPIO register, IO reuse of corresponding pin and GPIO number.
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void pwm_set_duty (uint32 duty,
uint8 channel 
)
+
+ +

Set the duty cycle of a PWM channel.

+

Set the time that high level signal will last, duty depends on period, the maximum value can be 1023.

+
Attention
After set configuration, pwm_start needs to be called to take effect.
+
Parameters
+ + + +
uint32duty : duty cycle
uint8channel : PWM channel number
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
void pwm_set_period (uint32 period)
+
+ +

Set PWM period, unit : us.

+

For example, for 1KHz PWM, period is 1000 us.

+
Attention
After set configuration, pwm_start needs to be called to take effect.
+
Parameters
+ + +
uint32period : PWM period, unit : us.
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
void pwm_start (void )
+
+ +

Starts PWM.

+
Attention
This function needs to be called after PWM configuration is changed.
+
Parameters
+ + +
null
+
+
+
Returns
null
+ +
+
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__SPI__Driver__APIs.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__SPI__Driver__APIs.html new file mode 100644 index 0000000..5d65924 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__SPI__Driver__APIs.html @@ -0,0 +1,428 @@ + + + + + + +ESP8266_RTOS_SDK: SPI Driver APIs + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + +
+ +
+
+ + +
+ +
+ +
+ +
+
SPI Driver APIs
+
+
+ +

SPI Flash APIs. +More...

+ + + + +

+Data Structures

struct  SpiFlashChip
 
+ + + +

+Macros

#define SPI_FLASH_SEC_SIZE   4096
 
+ + + + +

+Typedefs

typedef SpiFlashOpResult(* user_spi_flash_read) (SpiFlashChip *spi, uint32 src_addr, uint32 *des_addr, uint32 size)
 Registered function for spi_flash_set_read_func. More...
 
+ + + +

+Enumerations

enum  SpiFlashOpResult { SPI_FLASH_RESULT_OK, +SPI_FLASH_RESULT_ERR, +SPI_FLASH_RESULT_TIMEOUT + }
 
+ + + + + + + + + + + + + + + + + + + + + + +

+Functions

uint32 spi_flash_get_id (void)
 Get ID info of SPI Flash. More...
 
SpiFlashOpResult spi_flash_read_status (uint32 *status)
 Read state register of SPI Flash. More...
 
SpiFlashOpResult spi_flash_write_status (uint32 status_value)
 Write state register of SPI Flash. More...
 
SpiFlashOpResult spi_flash_erase_sector (uint16 sec)
 Erase the Flash sector. More...
 
SpiFlashOpResult spi_flash_write (uint32 des_addr, uint32 *src_addr, uint32 size)
 Write data to Flash. More...
 
SpiFlashOpResult spi_flash_read (uint32 src_addr, uint32 *des_addr, uint32 size)
 Read data from Flash. More...
 
void spi_flash_set_read_func (user_spi_flash_read read)
 Register user-define SPI flash read API. More...
 
+

Detailed Description

+

SPI Flash APIs.

+

Macro Definition Documentation

+ +
+
+ + + + +
#define SPI_FLASH_SEC_SIZE   4096
+
+

SPI Flash sector size

+ +
+
+

Typedef Documentation

+ +
+
+ + + + +
typedef SpiFlashOpResult(* user_spi_flash_read) (SpiFlashChip *spi, uint32 src_addr, uint32 *des_addr, uint32 size)
+
+ +

Registered function for spi_flash_set_read_func.

+
Attention
used for sdk internal, don't need to care about params
+
Parameters
+ + + + + +
SpiFlashChip*spi : spi flash struct pointer.
uint32src_addr : source address of the data.
uint32*des_addr : destination address in Flash.
uint32size : length of data
+
+
+
Returns
SpiFlashOpResult
+ +
+
+

Enumeration Type Documentation

+ +
+
+ + + + +
enum SpiFlashOpResult
+
+ + + + +
Enumerator
SPI_FLASH_RESULT_OK  +

SPI Flash operating OK

+
SPI_FLASH_RESULT_ERR  +

SPI Flash operating fail

+
SPI_FLASH_RESULT_TIMEOUT  +

SPI Flash operating time out

+
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + +
SpiFlashOpResult spi_flash_erase_sector (uint16 sec)
+
+ +

Erase the Flash sector.

+
Parameters
+ + +
uint16sec : Sector number, the count starts at sector 0, 4KB per sector.
+
+
+
Returns
SpiFlashOpResult
+ +
+
+ +
+
+ + + + + + + + +
uint32 spi_flash_get_id (void )
+
+ +

Get ID info of SPI Flash.

+
Parameters
+ + +
null
+
+
+
Returns
SPI Flash ID
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
SpiFlashOpResult spi_flash_read (uint32 src_addr,
uint32 * des_addr,
uint32 size 
)
+
+ +

Read data from Flash.

+
Parameters
+ + + + +
uint32src_addr : source address of the data.
uint32*des_addr : destination address in Flash.
uint32size : length of data
+
+
+
Returns
SpiFlashOpResult
+ +
+
+ +
+
+ + + + + + + + +
SpiFlashOpResult spi_flash_read_status (uint32 * status)
+
+ +

Read state register of SPI Flash.

+
Parameters
+ + +
uint32*status : the read value (pointer) of state register.
+
+
+
Returns
SpiFlashOpResult
+ +
+
+ +
+
+ + + + + + + + +
void spi_flash_set_read_func (user_spi_flash_read read)
+
+ +

Register user-define SPI flash read API.

+
Attention
This API can be only used in SPI overlap mode, please refer to ESP8266_RTOS_SDK .c
+
Parameters
+ + +
user_spi_flash_readread : user-define SPI flash read API .
+
+
+
Returns
none
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
SpiFlashOpResult spi_flash_write (uint32 des_addr,
uint32 * src_addr,
uint32 size 
)
+
+ +

Write data to Flash.

+
Parameters
+ + + + +
uint32des_addr : destination address in Flash.
uint32*src_addr : source address of the data.
uint32size : length of data
+
+
+
Returns
SpiFlashOpResult
+ +
+
+ +
+
+ + + + + + + + +
SpiFlashOpResult spi_flash_write_status (uint32 status_value)
+
+ +

Write state register of SPI Flash.

+
Parameters
+ + +
uint32status_value : Write state register value.
+
+
+
Returns
SpiFlashOpResult
+ +
+
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__SSC__APIs.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__SSC__APIs.html new file mode 100644 index 0000000..454ef5e --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__SSC__APIs.html @@ -0,0 +1,273 @@ + + + + + + +ESP8266_RTOS_SDK: SSC APIs + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + +
+ +
+
+ + +
+ +
+ +
+ +
+
SSC APIs
+
+
+ +

SSC APIs. +More...

+ + + + + + + + + + + + + + + + + +

+Functions

void ssc_attach (SscBaudRate bandrate)
 Initial the ssc function. More...
 
int ssc_param_len (void)
 Get the length of the simple serial command. More...
 
char * ssc_param_str (void)
 Get the simple serial command string. More...
 
int ssc_parse_param (char *pLine, char *argv[])
 Parse the simple serial command (ssc). More...
 
void ssc_register (ssc_cmd_t *cmdset, uint8 cmdnum, void(*help)(void))
 Register the user-defined simple serial command (ssc) set. More...
 
+

Detailed Description

+

SSC APIs.

+

SSC means simple serial command. SSC APIs allows users to define their own command, users can refer to spiffs_test/test_main.c.

+

Function Documentation

+ +
+
+ + + + + + + + +
void ssc_attach (SscBaudRate bandrate)
+
+ +

Initial the ssc function.

+
Parameters
+ + +
SscBaudRatebandrate : baud rate
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
int ssc_param_len (void )
+
+ +

Get the length of the simple serial command.

+
Parameters
+ + +
null
+
+
+
Returns
length of the command.
+ +
+
+ +
+
+ + + + + + + + +
char* ssc_param_str (void )
+
+ +

Get the simple serial command string.

+
Parameters
+ + +
null
+
+
+
Returns
the command.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int ssc_parse_param (char * pLine,
char * argv[] 
)
+
+ +

Parse the simple serial command (ssc).

+
Parameters
+ + + +
char*pLine : [input] the ssc string
char*argv[] : [output] parameters of the ssc
+
+
+
Returns
the number of parameters.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void ssc_register (ssc_cmd_tcmdset,
uint8 cmdnum,
void(*)(void) help 
)
+
+ +

Register the user-defined simple serial command (ssc) set.

+
Parameters
+ + + + +
ssc_cmd_t*cmdset : the ssc set
uint8cmdnum : number of commands
void(* help)(void) : callback of user-guide
+
+
+
Returns
null
+ +
+
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Smartconfig__APIs.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Smartconfig__APIs.html new file mode 100644 index 0000000..5b619c9 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Smartconfig__APIs.html @@ -0,0 +1,382 @@ + + + + + + +ESP8266_RTOS_SDK: Smartconfig APIs + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + +
+ +
+
+ + +
+ +
+ +
+ +
+
Smartconfig APIs
+
+
+ +

SmartConfig APIs. +More...

+ + + + + +

+Typedefs

typedef void(* sc_callback_t) (sc_status status, void *pdata)
 The callback of SmartConfig, executed when smart-config status changed. More...
 
+ + + + + +

+Enumerations

enum  sc_status {
+  SC_STATUS_WAIT = 0, +SC_STATUS_FIND_CHANNEL, +SC_STATUS_GETTING_SSID_PSWD, +SC_STATUS_LINK, +
+  SC_STATUS_LINK_OVER +
+ }
 
enum  sc_type { SC_TYPE_ESPTOUCH = 0, +SC_TYPE_AIRKISS, +SC_TYPE_ESPTOUCH_AIRKISS + }
 
+ + + + + + + + + + + + + + + + +

+Functions

const char * smartconfig_get_version (void)
 Get the version of SmartConfig. More...
 
bool smartconfig_start (sc_callback_t cb,...)
 Start SmartConfig mode. More...
 
bool smartconfig_stop (void)
 Stop SmartConfig, free the buffer taken by smartconfig_start. More...
 
bool esptouch_set_timeout (uint8 time_s)
 Set timeout of SmartConfig. More...
 
bool smartconfig_set_type (sc_type type)
 Set protocol type of SmartConfig. More...
 
+

Detailed Description

+

SmartConfig APIs.

+

SmartConfig can only be enabled in station only mode. Please make sure the target AP is enabled before enable SmartConfig.

+

Typedef Documentation

+ +
+
+ + + + +
typedef void(* sc_callback_t) (sc_status status, void *pdata)
+
+ +

The callback of SmartConfig, executed when smart-config status changed.

+
Parameters
+ + + +
sc_statusstatus : status of SmartConfig:
    +
  • if status == SC_STATUS_GETTING_SSID_PSWD, parameter void *pdata is a pointer of sc_type, means SmartConfig type: AirKiss or ESP-TOUCH.
  • +
  • if status == SC_STATUS_LINK, parameter void *pdata is a pointer of struct station_config;
  • +
  • if status == SC_STATUS_LINK_OVER, parameter void *pdata is a pointer of mobile phone's IP address, 4 bytes. This is only available in ESPTOUCH, otherwise, it is NULL.
  • +
  • otherwise, parameter void *pdata is NULL.
  • +
+
void*pdata : data of SmartConfig
+
+
+
Returns
null
+ +
+
+

Enumeration Type Documentation

+ +
+
+ + + + +
enum sc_status
+
+ + + + + + +
Enumerator
SC_STATUS_WAIT  +

waiting, do not start connection in this phase

+
SC_STATUS_FIND_CHANNEL  +

find target channel, start connection by APP in this phase

+
SC_STATUS_GETTING_SSID_PSWD  +

getting SSID and password of target AP

+
SC_STATUS_LINK  +

connecting to target AP

+
SC_STATUS_LINK_OVER  +

got IP, connect to AP successfully

+
+ +
+
+ +
+
+ + + + +
enum sc_type
+
+ + + + +
Enumerator
SC_TYPE_ESPTOUCH  +

protocol: ESPTouch

+
SC_TYPE_AIRKISS  +

protocol: AirKiss

+
SC_TYPE_ESPTOUCH_AIRKISS  +

protocol: ESPTouch and AirKiss

+
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + +
bool esptouch_set_timeout (uint8 time_s)
+
+ +

Set timeout of SmartConfig.

+
Attention
SmartConfig timeout start at SC_STATUS_FIND_CHANNEL, SmartConfig will restart if timeout.
+
Parameters
+ + +
uint8time_s : range 15s~255s, offset:45s.
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
const char* smartconfig_get_version (void )
+
+ +

Get the version of SmartConfig.

+
Parameters
+ + +
null
+
+
+
Returns
SmartConfig version
+ +
+
+ +
+
+ + + + + + + + +
bool smartconfig_set_type (sc_type type)
+
+ +

Set protocol type of SmartConfig.

+
Attention
If users need to set the SmartConfig type, please set it before calling smartconfig_start.
+
Parameters
+ + +
sc_typetype : AirKiss, ESP-TOUCH or both.
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
bool smartconfig_start (sc_callback_t cb,
 ... 
)
+
+ +

Start SmartConfig mode.

+

Start SmartConfig mode, to connect ESP8266 station to AP, by sniffing for special packets from the air, containing SSID and password of desired AP. You need to broadcast the SSID and password (e.g. from mobile device or computer) with the SSID and password encoded.

+
Attention
1. This api can only be called in station mode.
+
+2. During SmartConfig, ESP8266 station and soft-AP are disabled.
+
+3. Can not call smartconfig_start twice before it finish, please call smartconfig_stop first.
+
+4. Don't call any other APIs during SmartConfig, please call smartconfig_stop first.
+
Parameters
+ + + +
sc_callback_tcb : SmartConfig callback; executed when SmartConfig status changed;
uint8log : 1, UART output logs; otherwise, UART only outputs the result.
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
bool smartconfig_stop (void )
+
+ +

Stop SmartConfig, free the buffer taken by smartconfig_start.

+
Attention
Whether connect to AP succeed or not, this API should be called to free memory taken by smartconfig_start.
+
Parameters
+ + +
null
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__SoftAP__APIs.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__SoftAP__APIs.html new file mode 100644 index 0000000..4ef24fd --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__SoftAP__APIs.html @@ -0,0 +1,623 @@ + + + + + + +ESP8266_RTOS_SDK: SoftAP APIs + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + +
+ +
+
+ + +
+ +
+ + +
+ +

ESP8266 Soft-AP APIs. +More...

+ + + + + + +

+Data Structures

struct  softap_config
 
struct  station_info
 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Functions

bool wifi_softap_get_config (struct softap_config *config)
 Get the current configuration of the ESP8266 WiFi soft-AP. More...
 
bool wifi_softap_get_config_default (struct softap_config *config)
 Get the configuration of the ESP8266 WiFi soft-AP saved in the flash. More...
 
bool wifi_softap_set_config (struct softap_config *config)
 Set the configuration of the WiFi soft-AP and save it to the Flash. More...
 
bool wifi_softap_set_config_current (struct softap_config *config)
 Set the configuration of the WiFi soft-AP; the configuration will not be saved to the Flash. More...
 
uint8 wifi_softap_get_station_num (void)
 Get the number of stations connected to the ESP8266 soft-AP. More...
 
struct station_infowifi_softap_get_station_info (void)
 Get the information of stations connected to the ESP8266 soft-AP, including MAC and IP. More...
 
void wifi_softap_free_station_info (void)
 Free the space occupied by station_info when wifi_softap_get_station_info is called. More...
 
bool wifi_softap_dhcps_start (void)
 Enable the ESP8266 soft-AP DHCP server. More...
 
bool wifi_softap_dhcps_stop (void)
 Disable the ESP8266 soft-AP DHCP server. The DHCP is enabled by default. More...
 
enum dhcp_status wifi_softap_dhcps_status (void)
 Get the ESP8266 soft-AP DHCP server status. More...
 
bool wifi_softap_get_dhcps_lease (struct dhcps_lease *please)
 Query the IP range that can be got from the ESP8266 soft-AP DHCP server. More...
 
bool wifi_softap_set_dhcps_lease (struct dhcps_lease *please)
 Set the IP range of the ESP8266 soft-AP DHCP server. More...
 
uint32 wifi_softap_get_dhcps_lease_time (void)
 Get ESP8266 soft-AP DHCP server lease time. More...
 
bool wifi_softap_set_dhcps_lease_time (uint32 minute)
 Set ESP8266 soft-AP DHCP server lease time, default is 120 minutes. More...
 
bool wifi_softap_reset_dhcps_lease_time (void)
 Reset ESP8266 soft-AP DHCP server lease time which is 120 minutes by default. More...
 
bool wifi_softap_set_dhcps_offer_option (uint8 level, void *optarg)
 Set the ESP8266 soft-AP DHCP server option. More...
 
+

Detailed Description

+

ESP8266 Soft-AP APIs.

+
Attention
To call APIs related to ESP8266 soft-AP has to enable soft-AP mode first (wifi_set_opmode)
+

Function Documentation

+ +
+
+ + + + + + + + +
bool wifi_softap_dhcps_start (void )
+
+ +

Enable the ESP8266 soft-AP DHCP server.

+
Attention
1. The DHCP is enabled by default.
+
+2. The DHCP and the static IP related API (wifi_set_ip_info) influence each other, if the DHCP is enabled, the static IP will be disabled; if the static IP is enabled, the DHCP will be disabled. It depends on the latest configuration.
+
Parameters
+ + +
null
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
enum dhcp_status wifi_softap_dhcps_status (void )
+
+ +

Get the ESP8266 soft-AP DHCP server status.

+
Parameters
+ + +
null
+
+
+
Returns
enum dhcp_status
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_softap_dhcps_stop (void )
+
+ +

Disable the ESP8266 soft-AP DHCP server. The DHCP is enabled by default.

+
Parameters
+ + +
null
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
void wifi_softap_free_station_info (void )
+
+ +

Free the space occupied by station_info when wifi_softap_get_station_info is called.

+
Attention
The ESP8266 is limited to only one channel, so when in the soft-AP+station mode, the soft-AP will adjust its channel automatically to be the same as the channel of the ESP8266 station.
+
Parameters
+ + +
null
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_softap_get_config (struct softap_configconfig)
+
+ +

Get the current configuration of the ESP8266 WiFi soft-AP.

+
Parameters
+ + +
structsoftap_config *config : ESP8266 soft-AP configuration
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_softap_get_config_default (struct softap_configconfig)
+
+ +

Get the configuration of the ESP8266 WiFi soft-AP saved in the flash.

+
Parameters
+ + +
structsoftap_config *config : ESP8266 soft-AP configuration
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_softap_get_dhcps_lease (struct dhcps_leaseplease)
+
+ +

Query the IP range that can be got from the ESP8266 soft-AP DHCP server.

+
Attention
This API can only be called during ESP8266 soft-AP DHCP server enabled.
+
Parameters
+ + +
structdhcps_lease *please : IP range of the ESP8266 soft-AP DHCP server.
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
uint32 wifi_softap_get_dhcps_lease_time (void )
+
+ +

Get ESP8266 soft-AP DHCP server lease time.

+
Attention
This API can only be called during ESP8266 soft-AP DHCP server enabled.
+
Parameters
+ + +
null
+
+
+
Returns
lease time, uint: minute.
+ +
+
+ +
+
+ + + + + + + + +
struct station_info* wifi_softap_get_station_info (void )
+
+ +

Get the information of stations connected to the ESP8266 soft-AP, including MAC and IP.

+
Attention
wifi_softap_get_station_info depends on DHCP, it can only be used when DHCP is enabled, so it can not get the static IP.
+
Parameters
+ + +
null
+
+
+
Returns
struct station_info* : station information structure
+ +
+
+ +
+
+ + + + + + + + +
uint8 wifi_softap_get_station_num (void )
+
+ +

Get the number of stations connected to the ESP8266 soft-AP.

+
Attention
The ESP8266 is limited to only one channel, so when in the soft-AP+station mode, the soft-AP will adjust its channel automatically to be the same as the channel of the ESP8266 station.
+
Parameters
+ + +
null
+
+
+
Returns
the number of stations connected to the ESP8266 soft-AP
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_softap_reset_dhcps_lease_time (void )
+
+ +

Reset ESP8266 soft-AP DHCP server lease time which is 120 minutes by default.

+
Attention
This API can only be called during ESP8266 soft-AP DHCP server enabled.
+
Parameters
+ + +
null
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_softap_set_config (struct softap_configconfig)
+
+ +

Set the configuration of the WiFi soft-AP and save it to the Flash.

+
Attention
1. This configuration will be saved in flash system parameter area if changed
+
+2. The ESP8266 is limited to only one channel, so when in the soft-AP+station mode, the soft-AP will adjust its channel automatically to be the same as the channel of the ESP8266 station.
+
Parameters
+ + +
structsoftap_config *config : ESP8266 soft-AP configuration
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_softap_set_config_current (struct softap_configconfig)
+
+ +

Set the configuration of the WiFi soft-AP; the configuration will not be saved to the Flash.

+
Attention
The ESP8266 is limited to only one channel, so when in the soft-AP+station mode, the soft-AP will adjust its channel automatically to be the same as the channel of the ESP8266 station.
+
Parameters
+ + +
structsoftap_config *config : ESP8266 soft-AP configuration
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_softap_set_dhcps_lease (struct dhcps_leaseplease)
+
+ +

Set the IP range of the ESP8266 soft-AP DHCP server.

+
Attention
1. The IP range should be in the same sub-net with the ESP8266 soft-AP IP address.
+
+2. This API should only be called when the DHCP server is disabled (wifi_softap_dhcps_stop).
+
+3. This configuration will only take effect the next time when the DHCP server is enabled (wifi_softap_dhcps_start).
    +
  • If the DHCP server is disabled again, this API should be called to set the IP range.
  • +
  • Otherwise, when the DHCP server is enabled later, the default IP range will be used.
  • +
+
+
Parameters
+ + +
structdhcps_lease *please : IP range of the ESP8266 soft-AP DHCP server.
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_softap_set_dhcps_lease_time (uint32 minute)
+
+ +

Set ESP8266 soft-AP DHCP server lease time, default is 120 minutes.

+
Attention
This API can only be called during ESP8266 soft-AP DHCP server enabled.
+
Parameters
+ + +
uint32minute : lease time, uint: minute, range:[1, 2880].
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
bool wifi_softap_set_dhcps_offer_option (uint8 level,
void * optarg 
)
+
+ +

Set the ESP8266 soft-AP DHCP server option.

+

Example:

 
+        uint8 mode = 0;
+        wifi_softap_set_dhcps_offer_option(OFFER_ROUTER, &mode);
+
Parameters
+ + + +
uint8level : OFFER_ROUTER, set the router option.
void*optarg :
    +
  • bit0, 0 disable the router information;
  • +
  • bit0, 1 enable the router information.
  • +
+
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Spiffs__APIs.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Spiffs__APIs.html new file mode 100644 index 0000000..ffd3149 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Spiffs__APIs.html @@ -0,0 +1,168 @@ + + + + + + +ESP8266_RTOS_SDK: Spiffs APIs + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + +
+ +
+
+ + +
+ +
+ +
+ +
+
Spiffs APIs
+
+
+ +

Spiffs APIs. +More...

+ + + + +

+Data Structures

struct  esp_spiffs_config
 
+ + + + + + + +

+Functions

sint32 esp_spiffs_init (struct esp_spiffs_config *config)
 Initialize spiffs. More...
 
void esp_spiffs_deinit (uint8 format)
 Deinitialize spiffs. More...
 
+

Detailed Description

+

Spiffs APIs.

+

More details about spiffs on https://github.com/pellepl/spiffs

+

Function Documentation

+ +
+
+ + + + + + + + +
void esp_spiffs_deinit (uint8 format)
+
+ +

Deinitialize spiffs.

+
Parameters
+ + +
uint8format : 0, only deinit; otherwise, deinit spiffs and format.
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
sint32 esp_spiffs_init (struct esp_spiffs_configconfig)
+
+ +

Initialize spiffs.

+
Parameters
+ + +
structesp_spiffs_config *config : ESP8266 spiffs configuration
+
+
+
Returns
0 : succeed
+
+otherwise : fail
+ +
+
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Station__APIs.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Station__APIs.html new file mode 100644 index 0000000..4fb9424 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Station__APIs.html @@ -0,0 +1,888 @@ + + + + + + +ESP8266_RTOS_SDK: Station APIs + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + +
+ +
+
+ + +
+ +
+ + +
+ +

ESP8266 station APIs. +More...

+ + + + + + + + +

+Data Structures

struct  station_config
 
struct  scan_config
 
struct  bss_info
 
+ + + + +

+Typedefs

typedef void(* scan_done_cb_t) (void *arg, STATUS status)
 Callback function for wifi_station_scan. More...
 
+ + + +

+Enumerations

enum  STATION_STATUS {
+  STATION_IDLE = 0, +STATION_CONNECTING, +STATION_WRONG_PASSWORD, +STATION_NO_AP_FOUND, +
+  STATION_CONNECT_FAIL, +STATION_GOT_IP +
+ }
 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Functions

bool wifi_station_get_config (struct station_config *config)
 Get the current configuration of the ESP8266 WiFi station. More...
 
bool wifi_station_get_config_default (struct station_config *config)
 Get the configuration parameters saved in the Flash of the ESP8266 WiFi station. More...
 
bool wifi_station_set_config (struct station_config *config)
 Set the configuration of the ESP8266 station and save it to the Flash. More...
 
bool wifi_station_set_config_current (struct station_config *config)
 Set the configuration of the ESP8266 station. And the configuration will not be saved to the Flash. More...
 
bool wifi_station_connect (void)
 Connect the ESP8266 WiFi station to the AP. More...
 
bool wifi_station_disconnect (void)
 Disconnect the ESP8266 WiFi station from the AP. More...
 
bool wifi_station_scan (struct scan_config *config, scan_done_cb_t cb)
 Scan all available APs. More...
 
bool wifi_station_get_auto_connect (void)
 Check if the ESP8266 station will connect to the recorded AP automatically when the power is on. More...
 
bool wifi_station_set_auto_connect (bool set)
 Set whether the ESP8266 station will connect to the recorded AP automatically when the power is on. It will do so by default. More...
 
bool wifi_station_get_reconnect_policy (void)
 Check whether the ESP8266 station will reconnect to the AP after disconnection. More...
 
bool wifi_station_set_reconnect_policy (bool set)
 Set whether the ESP8266 station will reconnect to the AP after disconnection. It will do so by default. More...
 
STATION_STATUS wifi_station_get_connect_status (void)
 Get the connection status of the ESP8266 WiFi station. More...
 
uint8 wifi_station_get_current_ap_id (void)
 Get the information of APs (5 at most) recorded by ESP8266 station. More...
 
bool wifi_station_ap_change (uint8 current_ap_id)
 Switch the ESP8266 station connection to a recorded AP. More...
 
bool wifi_station_ap_number_set (uint8 ap_number)
 Set the number of APs that can be recorded in the ESP8266 station. When the ESP8266 station is connected to an AP, the SSID and password of the AP will be recorded. More...
 
uint8 wifi_station_get_ap_info (struct station_config config[])
 Get the information of APs (5 at most) recorded by ESP8266 station. More...
 
sint8 wifi_station_get_rssi (void)
 Get rssi of the AP which ESP8266 station connected to. More...
 
bool wifi_station_dhcpc_start (void)
 Enable the ESP8266 station DHCP client. More...
 
bool wifi_station_dhcpc_stop (void)
 Disable the ESP8266 station DHCP client. More...
 
enum dhcp_status wifi_station_dhcpc_status (void)
 Get the ESP8266 station DHCP client status. More...
 
bool wifi_station_set_hostname (char *name)
 Set ESP8266 station DHCP hostname. More...
 
char * wifi_station_get_hostname (void)
 Get ESP8266 station DHCP hostname. More...
 
+

Detailed Description

+

ESP8266 station APIs.

+
Attention
To call APIs related to ESP8266 station has to enable station mode first (wifi_set_opmode)
+

Typedef Documentation

+ +
+
+ + + + +
typedef void(* scan_done_cb_t) (void *arg, STATUS status)
+
+ +

Callback function for wifi_station_scan.

+
Parameters
+ + + +
void*arg : information of APs that are found; save them as linked list; refer to struct bss_info
STATUSstatus : status of scanning
+
+
+
Returns
null
+ +
+
+

Enumeration Type Documentation

+ +
+
+ + + + +
enum STATION_STATUS
+
+ + + + + + + +
Enumerator
STATION_IDLE  +

ESP8266 station idle

+
STATION_CONNECTING  +

ESP8266 station is connecting to AP

+
STATION_WRONG_PASSWORD  +

the password is wrong

+
STATION_NO_AP_FOUND  +

ESP8266 station can not find the target AP

+
STATION_CONNECT_FAIL  +

ESP8266 station fail to connect to AP

+
STATION_GOT_IP  +

ESP8266 station got IP address from AP

+
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + +
bool wifi_station_ap_change (uint8 current_ap_id)
+
+ +

Switch the ESP8266 station connection to a recorded AP.

+
Parameters
+ + +
uint8new_ap_id : AP's record id, start counting from 0.
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_station_ap_number_set (uint8 ap_number)
+
+ +

Set the number of APs that can be recorded in the ESP8266 station. When the ESP8266 station is connected to an AP, the SSID and password of the AP will be recorded.

+
Attention
This configuration will be saved in the Flash system parameter area if changed.
+
Parameters
+ + +
uint8ap_number : the number of APs that can be recorded (MAX: 5)
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_station_connect (void )
+
+ +

Connect the ESP8266 WiFi station to the AP.

+
Attention
1. This API should be called when the ESP8266 station is enabled, and the system initialization is completed. Do not call this API in user_init.
+
+2. If the ESP8266 is connected to an AP, call wifi_station_disconnect to disconnect.
+
Parameters
+ + +
null
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_station_dhcpc_start (void )
+
+ +

Enable the ESP8266 station DHCP client.

+
Attention
1. The DHCP is enabled by default.
+
+2. The DHCP and the static IP API ((wifi_set_ip_info)) influence each other, and if the DHCP is enabled, the static IP will be disabled; if the static IP is enabled, the DHCP will be disabled. It depends on the latest configuration.
+
Parameters
+ + +
null
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
enum dhcp_status wifi_station_dhcpc_status (void )
+
+ +

Get the ESP8266 station DHCP client status.

+
Parameters
+ + +
null
+
+
+
Returns
enum dhcp_status
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_station_dhcpc_stop (void )
+
+ +

Disable the ESP8266 station DHCP client.

+
Attention
1. The DHCP is enabled by default.
+
+2. The DHCP and the static IP API ((wifi_set_ip_info)) influence each other, and if the DHCP is enabled, the static IP will be disabled; if the static IP is enabled, the DHCP will be disabled. It depends on the latest configuration.
+
Parameters
+ + +
null
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_station_disconnect (void )
+
+ +

Disconnect the ESP8266 WiFi station from the AP.

+
Attention
This API should be called when the ESP8266 station is enabled, and the system initialization is completed. Do not call this API in user_init.
+
Parameters
+ + +
null
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
uint8 wifi_station_get_ap_info (struct station_config config[])
+
+ +

Get the information of APs (5 at most) recorded by ESP8266 station.

+

Example:

 
+        struct station_config config[5];
+        nt i = wifi_station_get_ap_info(config);
+
Parameters
+ + +
structstation_config config[] : information of the APs, the array size should be 5.
+
+
+
Returns
The number of APs recorded.
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_station_get_auto_connect (void )
+
+ +

Check if the ESP8266 station will connect to the recorded AP automatically when the power is on.

+
Parameters
+ + +
null
+
+
+
Returns
true : connect to the AP automatically
+
+false : not connect to the AP automatically
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_station_get_config (struct station_configconfig)
+
+ +

Get the current configuration of the ESP8266 WiFi station.

+
Parameters
+ + +
structstation_config *config : ESP8266 station configuration
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_station_get_config_default (struct station_configconfig)
+
+ +

Get the configuration parameters saved in the Flash of the ESP8266 WiFi station.

+
Parameters
+ + +
structstation_config *config : ESP8266 station configuration
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
STATION_STATUS wifi_station_get_connect_status (void )
+
+ +

Get the connection status of the ESP8266 WiFi station.

+
Parameters
+ + +
null
+
+
+
Returns
the status of connection
+ +
+
+ +
+
+ + + + + + + + +
uint8 wifi_station_get_current_ap_id (void )
+
+ +

Get the information of APs (5 at most) recorded by ESP8266 station.

+
Parameters
+ + +
structstation_config config[] : information of the APs, the array size should be 5.
+
+
+
Returns
The number of APs recorded.
+ +
+
+ +
+
+ + + + + + + + +
char* wifi_station_get_hostname (void )
+
+ +

Get ESP8266 station DHCP hostname.

+
Parameters
+ + +
null
+
+
+
Returns
the hostname of ESP8266 station
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_station_get_reconnect_policy (void )
+
+ +

Check whether the ESP8266 station will reconnect to the AP after disconnection.

+
Parameters
+ + +
null
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
sint8 wifi_station_get_rssi (void )
+
+ +

Get rssi of the AP which ESP8266 station connected to.

+
Parameters
+ + +
null
+
+
+
Returns
31 : fail, invalid value.
+
+others : succeed, value of rssi. In general, rssi value < 10
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
bool wifi_station_scan (struct scan_configconfig,
scan_done_cb_t cb 
)
+
+ +

Scan all available APs.

+
Attention
This API should be called when the ESP8266 station is enabled, and the system initialization is completed. Do not call this API in user_init.
+
Parameters
+ + + +
structscan_config *config : configuration of scanning
structscan_done_cb_t cb : callback of scanning
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_station_set_auto_connect (bool set)
+
+ +

Set whether the ESP8266 station will connect to the recorded AP automatically when the power is on. It will do so by default.

+
Attention
1. If this API is called in user_init, it is effective immediately after the power is on. If it is called in other places, it will be effective the next time when the power is on.
+
+2. This configuration will be saved in Flash system parameter area if changed.
+
Parameters
+ + +
boolset : If it will automatically connect to the AP when the power is on
    +
  • true : it will connect automatically
  • +
  • false: it will not connect automatically
  • +
+
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_station_set_config (struct station_configconfig)
+
+ +

Set the configuration of the ESP8266 station and save it to the Flash.

+
Attention
1. This API can be called only when the ESP8266 station is enabled.
+
+2. If wifi_station_set_config is called in user_init , there is no need to call wifi_station_connect. The ESP8266 station will automatically connect to the AP (router) after the system initialization. Otherwise, wifi_station_connect should be called.
+
+3. Generally, station_config.bssid_set needs to be 0; and it needs to be 1 only when users need to check the MAC address of the AP.
+
+4. This configuration will be saved in the Flash system parameter area if changed.
+
Parameters
+ + +
structstation_config *config : ESP8266 station configuration
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_station_set_config_current (struct station_configconfig)
+
+ +

Set the configuration of the ESP8266 station. And the configuration will not be saved to the Flash.

+
Attention
1. This API can be called only when the ESP8266 station is enabled.
+
+2. If wifi_station_set_config_current is called in user_init , there is no need to call wifi_station_connect. The ESP8266 station will automatically connect to the AP (router) after the system initialization. Otherwise, wifi_station_connect should be called.
+
+3. Generally, station_config.bssid_set needs to be 0; and it needs to be 1 only when users need to check the MAC address of the AP.
+
Parameters
+ + +
structstation_config *config : ESP8266 station configuration
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_station_set_hostname (char * name)
+
+ +

Set ESP8266 station DHCP hostname.

+
Parameters
+ + +
char*name : hostname of ESP8266 station
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_station_set_reconnect_policy (bool set)
+
+ +

Set whether the ESP8266 station will reconnect to the AP after disconnection. It will do so by default.

+
Attention
If users want to call this API, it is suggested that users call this API in user_init.
+
Parameters
+ + +
boolset : if it's true, it will enable reconnection; if it's false, it will disable reconnection.
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__System__APIs.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__System__APIs.html new file mode 100644 index 0000000..0d2c7ea --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__System__APIs.html @@ -0,0 +1,975 @@ + + + + + + +ESP8266_RTOS_SDK: System APIs + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + +
+ +
+
+ + +
+ +
+ +
+ +
+
System APIs
+
+
+ +

System APIs. +More...

+ + + + + + + + +

+Modules

 Boot APIs
 boot APIs
 
 Upgrade APIs
 Firmware upgrade (FOTA) APIs.
 
+ + + +

+Data Structures

struct  rst_info
 
+ + + +

+Enumerations

enum  rst_reason {
+  REASON_DEFAULT_RST = 0, +REASON_WDT_RST, +REASON_EXCEPTION_RST, +REASON_SOFT_WDT_RST, +
+  REASON_SOFT_RESTART, +REASON_DEEP_SLEEP_AWAKE, +REASON_EXT_SYS_RST +
+ }
 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Functions

struct rst_infosystem_get_rst_info (void)
 Get the reason of restart. More...
 
const char * system_get_sdk_version (void)
 Get information of the SDK version. More...
 
void system_restore (void)
 Reset to default settings. More...
 
void system_restart (void)
 Restart system. More...
 
void system_deep_sleep (uint32 time_in_us)
 Set the chip to deep-sleep mode. More...
 
bool system_deep_sleep_set_option (uint8 option)
 Call this API before system_deep_sleep to set the activity after the next deep-sleep wakeup. More...
 
uint32 system_get_time (void)
 Get system time, unit: microsecond. More...
 
void system_print_meminfo (void)
 Print the system memory distribution, including data/rodata/bss/heap. More...
 
uint32 system_get_free_heap_size (void)
 Get the size of available heap. More...
 
uint32 system_get_chip_id (void)
 Get the chip ID. More...
 
uint32 system_rtc_clock_cali_proc (void)
 Get the RTC clock cycle. More...
 
uint32 system_get_rtc_time (void)
 Get RTC time, unit: RTC clock cycle. More...
 
bool system_rtc_mem_read (uint8 src, void *dst, uint16 n)
 Read user data from the RTC memory. More...
 
bool system_rtc_mem_write (uint8 dst, const void *src, uint16 n)
 Write user data to the RTC memory. More...
 
void system_uart_swap (void)
 UART0 swap. More...
 
void system_uart_de_swap (void)
 Disable UART0 swap. More...
 
uint16 system_adc_read (void)
 Measure the input voltage of TOUT pin 6, unit : 1/1024 V. More...
 
uint16 system_get_vdd33 (void)
 Measure the power voltage of VDD3P3 pin 3 and 4, unit : 1/1024 V. More...
 
bool system_param_save_with_protect (uint16 start_sec, void *param, uint16 len)
 Write data into flash with protection. More...
 
bool system_param_load (uint16 start_sec, uint16 offset, void *param, uint16 len)
 Read the data saved into flash with the read/write protection. More...
 
void system_phy_set_max_tpw (uint8 max_tpw)
 Set the maximum value of RF TX Power, unit : 0.25dBm. More...
 
void system_phy_set_tpw_via_vdd33 (uint16 vdd33)
 Adjust the RF TX Power according to VDD33, unit : 1/1024 V. More...
 
void system_phy_set_rfoption (uint8 option)
 Enable RF or not when wakeup from deep-sleep. More...
 
+

Detailed Description

+

System APIs.

+

Enumeration Type Documentation

+ +
+
+ + + + +
enum rst_reason
+
+ + + + + + + + +
Enumerator
REASON_DEFAULT_RST  +

normal startup by power on

+
REASON_WDT_RST  +

hardware watch dog reset

+
REASON_EXCEPTION_RST  +

exception reset, GPIO status won't change

+
REASON_SOFT_WDT_RST  +

software watch dog reset, GPIO status won't change

+
REASON_SOFT_RESTART  +

software restart ,system_restart , GPIO status won't change

+
REASON_DEEP_SLEEP_AWAKE  +

wake up from deep-sleep

+
REASON_EXT_SYS_RST  +

external system reset

+
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + +
uint16 system_adc_read (void )
+
+ +

Measure the input voltage of TOUT pin 6, unit : 1/1024 V.

+
Attention
1. system_adc_read can only be called when the TOUT pin is connected to the external circuitry, and the TOUT pin input voltage should be limited to 0~1.0V.
+
+2. When the TOUT pin is connected to the external circuitry, the 107th byte (vdd33_const) of esp_init_data_default.bin(0~127byte) should be set as the real power voltage of VDD3P3 pin 3 and 4.
+
+3. The unit of vdd33_const is 0.1V, the effective value range is [18, 36]; if vdd33_const is in [0, 18) or (36, 255), 3.3V is used to optimize RF by default.
+
Parameters
+ + +
null
+
+
+
Returns
Input voltage of TOUT pin 6, unit : 1/1024 V
+ +
+
+ +
+
+ + + + + + + + +
void system_deep_sleep (uint32 time_in_us)
+
+ +

Set the chip to deep-sleep mode.

+

The device will automatically wake up after the deep-sleep time set by the users. Upon waking up, the device boots up from user_init.

+
Attention
1. XPD_DCDC should be connected to EXT_RSTB through 0 ohm resistor in order to support deep-sleep wakeup.
+
+2. system_deep_sleep(0): there is no wake up timer; in order to wake up, connect a GPIO to pin RST, the chip will wake up by a falling-edge on pin RST
+
Parameters
+ + +
uint32time_in_us : deep-sleep time, unit: microsecond
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
bool system_deep_sleep_set_option (uint8 option)
+
+ +

Call this API before system_deep_sleep to set the activity after the next deep-sleep wakeup.

+

If this API is not called, default to be system_deep_sleep_set_option(1).

+
Parameters
+ + + + + + +
uint8option :
0: Radio calibration after the deep-sleep wakeup is decided by byte 108 of esp_init_data_default.bin (0~127byte).
1: Radio calibration will be done after the deep-sleep wakeup. This will lead to stronger current.
2: Radio calibration will not be done after the deep-sleep wakeup. This will lead to weaker current.
4: Disable radio calibration after the deep-sleep wakeup (the same as modem-sleep). This will lead to the weakest current, but the device can't receive or transmit data after waking up.
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
uint32 system_get_chip_id (void )
+
+ +

Get the chip ID.

+
Parameters
+ + +
null
+
+
+
Returns
The chip ID.
+ +
+
+ +
+
+ + + + + + + + +
uint32 system_get_free_heap_size (void )
+
+ +

Get the size of available heap.

+
Parameters
+ + +
null
+
+
+
Returns
Available heap size.
+ +
+
+ +
+
+ + + + + + + + +
struct rst_info* system_get_rst_info (void )
+
+ +

Get the reason of restart.

+
Parameters
+ + +
null
+
+
+
Returns
struct rst_info* : information of the system restart
+ +
+
+ +
+
+ + + + + + + + +
uint32 system_get_rtc_time (void )
+
+ +

Get RTC time, unit: RTC clock cycle.

+

Example: If system_get_rtc_time returns 10 (it means 10 RTC cycles), and system_rtc_clock_cali_proc returns 5.75 (it means 5.75 microseconds per RTC clock cycle), (then the actual time is 10 x 5.75 = 57.5 microseconds.

+
Attention
System time will return to zero because of system_restart, but the RTC time still goes on. If the chip is reset by pin EXT_RST or pin CHIP_EN (including the deep-sleep wakeup), situations are shown as below:
+
+1. reset by pin EXT_RST : RTC memory won't change, RTC timer returns to zero
+
+2. watchdog reset : RTC memory won't change, RTC timer won't change
+
+3. system_restart : RTC memory won't change, RTC timer won't change
+
+4. power on : RTC memory is random value, RTC timer starts from zero
+
+5. reset by pin CHIP_EN : RTC memory is random value, RTC timer starts from zero
+
Parameters
+ + +
null
+
+
+
Returns
RTC time.
+ +
+
+ +
+
+ + + + + + + + +
const char* system_get_sdk_version (void )
+
+ +

Get information of the SDK version.

+
Parameters
+ + +
null
+
+
+
Returns
Information of the SDK version.
+ +
+
+ +
+
+ + + + + + + + +
uint32 system_get_time (void )
+
+ +

Get system time, unit: microsecond.

+
Parameters
+ + +
null
+
+
+
Returns
System time, unit: microsecond.
+ +
+
+ +
+
+ + + + + + + + +
uint16 system_get_vdd33 (void )
+
+ +

Measure the power voltage of VDD3P3 pin 3 and 4, unit : 1/1024 V.

+
Attention
1. system_get_vdd33 depends on RF, please do not use it if RF is disabled.
+
+2. system_get_vdd33 can only be called when TOUT pin is suspended.
+
+3. The 107th byte in esp_init_data_default.bin (0~127byte) is named as "vdd33_const", when TOUT pin is suspended vdd33_const must be set as 0xFF, that is 255.
+
Parameters
+ + +
null
+
+
+
Returns
Power voltage of VDD33, unit : 1/1024 V
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
bool system_param_load (uint16 start_sec,
uint16 offset,
void * param,
uint16 len 
)
+
+ +

Read the data saved into flash with the read/write protection.

+

Flash read/write has to be 4-bytes aligned.

+

Read/write protection of flash: use 3 sectors (4KB per sector) to save 4KB data with protect, sector 0 and sector 1 are data sectors, back up each other, save data alternately, sector 2 is flag sector, point out which sector is keeping the latest data, sector 0 or sector 1.

+
Parameters
+ + + + + +
uint16start_sec : start sector (sector 0) of the 3 sectors used for flash read/write protection. It cannot be sector 1 or sector 2.
    +
  • For example, in IOT_Demo, the 3 sectors (3 * 4KB) starting from flash 0x3D000 can be used for flash read/write protection. The parameter start_sec is 0x3D, and it cannot be 0x3E or 0x3F.
  • +
+
uint16offset : offset of data saved in sector
void*param : data pointer
uint16len : data length, offset + len =< 4 * 1024
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
bool system_param_save_with_protect (uint16 start_sec,
void * param,
uint16 len 
)
+
+ +

Write data into flash with protection.

+

Flash read/write has to be 4-bytes aligned.

+

Protection of flash read/write : use 3 sectors (4KBytes per sector) to save 4KB data with protect, sector 0 and sector 1 are data sectors, back up each other, save data alternately, sector 2 is flag sector, point out which sector is keeping the latest data, sector 0 or sector 1.

+
Parameters
+ + + + +
uint16start_sec : start sector (sector 0) of the 3 sectors which are used for flash read/write protection.
    +
  • For example, in IOT_Demo we can use the 3 sectors (3 * 4KB) starting from flash 0x3D000 for flash read/write protection, so the parameter start_sec should be 0x3D
  • +
+
void*param : pointer of the data to be written
uint16len : data length, should be less than a sector, which is 4 * 1024
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
void system_phy_set_max_tpw (uint8 max_tpw)
+
+ +

Set the maximum value of RF TX Power, unit : 0.25dBm.

+
Parameters
+ + +
uint8max_tpw : the maximum value of RF Tx Power, unit : 0.25dBm, range [0, 82]. It can be set refer to the 34th byte (target_power_qdb_0) of esp_init_data_default.bin(0~127byte)
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
void system_phy_set_rfoption (uint8 option)
+
+ +

Enable RF or not when wakeup from deep-sleep.

+
Attention
1. This API can only be called in user_rf_pre_init.
+
+2. Function of this API is similar to system_deep_sleep_set_option, if they are both called, it will disregard system_deep_sleep_set_option which is called before deep-sleep, and refer to system_phy_set_rfoption which is called when deep-sleep wake up.
+
+3. Before calling this API, system_deep_sleep_set_option should be called once at least.
+
Parameters
+ + +
uint8option :
    +
  • 0 : Radio calibration after deep-sleep wake up depends on esp_init_data_default.bin (0~127byte) byte 108.
  • +
  • 1 : Radio calibration is done after deep-sleep wake up; this increases the current consumption.
  • +
  • 2 : No radio calibration after deep-sleep wake up; this reduces the current consumption.
  • +
  • 4 : Disable RF after deep-sleep wake up, just like modem sleep; this has the least current consumption; the device is not able to transmit or receive data after wake up.
  • +
+
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
void system_phy_set_tpw_via_vdd33 (uint16 vdd33)
+
+ +

Adjust the RF TX Power according to VDD33, unit : 1/1024 V.

+
Attention
1. When TOUT pin is suspended, VDD33 can be measured by system_get_vdd33.
+
+2. When TOUT pin is connected to the external circuitry, system_get_vdd33 can not be used to measure VDD33.
+
Parameters
+ + +
uint16vdd33 : VDD33, unit : 1/1024V, range [1900, 3300]
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
void system_print_meminfo (void )
+
+ +

Print the system memory distribution, including data/rodata/bss/heap.

+
Parameters
+ + +
null
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
void system_restart (void )
+
+ +

Restart system.

+
Parameters
+ + +
null
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
void system_restore (void )
+
+ +

Reset to default settings.

+

Reset to default settings of the following APIs : wifi_station_set_auto_connect, wifi_set_phy_mode, wifi_softap_set_config related, wifi_station_set_config related, and wifi_set_opmode.

+
Parameters
+ + +
null
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
uint32 system_rtc_clock_cali_proc (void )
+
+ +

Get the RTC clock cycle.

+
Attention
1. The RTC clock cycle has decimal part.
+
+2. The RTC clock cycle will change according to the temperature, so RTC timer is not very precise.
+
Parameters
+ + +
null
+
+
+
Returns
RTC clock period (unit: microsecond), bit11~ bit0 are decimal.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
bool system_rtc_mem_read (uint8 src,
void * dst,
uint16 n 
)
+
+ +

Read user data from the RTC memory.

+

The user data segment (512 bytes, as shown below) is used to store user data.

+

|<-— system data(256 bytes) -—>|<--------— user data(512 bytes) ------—>|

+
Attention
Read and write unit for data stored in the RTC memory is 4 bytes.
+
+src_addr is the block number (4 bytes per block). So when reading data at the beginning of the user data segment, src_addr will be 256/4 = 64, n will be data length.
+
Parameters
+ + + + +
uint8src : source address of rtc memory, src_addr >= 64
void*dst : data pointer
uint16n : data length, unit: byte
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
bool system_rtc_mem_write (uint8 dst,
const void * src,
uint16 n 
)
+
+ +

Write user data to the RTC memory.

+

During deep-sleep, only RTC is working. So users can store their data in RTC memory if it is needed. The user data segment below (512 bytes) is used to store the user data.

+

|<-— system data(256 bytes) -—>|<--------— user data(512 bytes) ------—>|

+
Attention
Read and write unit for data stored in the RTC memory is 4 bytes.
+
+src_addr is the block number (4 bytes per block). So when storing data at the beginning of the user data segment, src_addr will be 256/4 = 64, n will be data length.
+
Parameters
+ + + + +
uint8src : source address of rtc memory, src_addr >= 64
void*dst : data pointer
uint16n : data length, unit: byte
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
void system_uart_de_swap (void )
+
+ +

Disable UART0 swap.

+

Use the original UART0, not MTCK and MTDO.

+
Parameters
+ + +
null
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
void system_uart_swap (void )
+
+ +

UART0 swap.

+

Use MTCK as UART0 RX, MTDO as UART0 TX, so ROM log will not output from this new UART0. We also need to use MTDO (U0RTS) and MTCK (U0CTS) as UART0 in hardware.

+
Parameters
+ + +
null
+
+
+
Returns
null
+ +
+
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__System__boot__APIs.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__System__boot__APIs.html new file mode 100644 index 0000000..11cf090 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__System__boot__APIs.html @@ -0,0 +1,447 @@ + + + + + + +ESP8266_RTOS_SDK: Boot APIs + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + +
+ +
+
+ + +
+ +
+ +
+ +
+
Boot APIs
+
+
+ +

boot APIs +More...

+ + + + + + + + + + + + + + +

+Macros

#define SYS_BOOT_ENHANCE_MODE   0
 
#define SYS_BOOT_NORMAL_MODE   1
 
#define SYS_BOOT_NORMAL_BIN   0
 
#define SYS_BOOT_TEST_BIN   1
 
+#define SYS_CPU_80MHZ   80
 
+#define SYS_CPU_160MHZ   160
 
+ + + +

+Enumerations

enum  flash_size_map {
+  FLASH_SIZE_4M_MAP_256_256 = 0, +FLASH_SIZE_2M, +FLASH_SIZE_8M_MAP_512_512, +FLASH_SIZE_16M_MAP_512_512, +
+  FLASH_SIZE_32M_MAP_512_512, +FLASH_SIZE_16M_MAP_1024_1024, +FLASH_SIZE_32M_MAP_1024_1024 +
+ }
 
+ + + + + + + + + + + + + + + + + + + + + + +

+Functions

uint8 system_get_boot_version (void)
 Get information of the boot version. More...
 
uint32 system_get_userbin_addr (void)
 Get the address of the current running user bin (user1.bin or user2.bin). More...
 
uint8 system_get_boot_mode (void)
 Get the boot mode. More...
 
bool system_restart_enhance (uint8 bin_type, uint32 bin_addr)
 Restarts the system, and enters the enhanced boot mode. More...
 
flash_size_map system_get_flash_size_map (void)
 Get the current Flash size and Flash map. More...
 
bool system_update_cpu_freq (uint8 freq)
 Set CPU frequency. Default is 80MHz. More...
 
uint8 system_get_cpu_freq (void)
 Get CPU frequency. More...
 
+

Detailed Description

+

boot APIs

+

Macro Definition Documentation

+ +
+
+ + + + +
#define SYS_BOOT_ENHANCE_MODE   0
+
+

It can load and run firmware at any address, for Espressif factory test bin

+ +
+
+ +
+
+ + + + +
#define SYS_BOOT_NORMAL_BIN   0
+
+

user1.bin or user2.bin

+ +
+
+ +
+
+ + + + +
#define SYS_BOOT_NORMAL_MODE   1
+
+

It can only load and run at some addresses of user1.bin (or user2.bin)

+ +
+
+ +
+
+ + + + +
#define SYS_BOOT_TEST_BIN   1
+
+

can only be Espressif test bin

+ +
+
+

Enumeration Type Documentation

+ +
+
+ + + + +
enum flash_size_map
+
+ + + + + + + + +
Enumerator
FLASH_SIZE_4M_MAP_256_256  +

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

+
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + +
uint8 system_get_boot_mode (void )
+
+ +

Get the boot mode.

+
Parameters
+ + +
null
+
+
+
Returns
#define SYS_BOOT_ENHANCE_MODE 0
+
+#define SYS_BOOT_NORMAL_MODE 1
+ +
+
+ +
+
+ + + + + + + + +
uint8 system_get_boot_version (void )
+
+ +

Get information of the boot version.

+
Attention
If boot version >= 1.3 , users can enable the enhanced boot mode (refer to system_restart_enhance).
+
Parameters
+ + +
null
+
+
+
Returns
Information of the boot version.
+ +
+
+ +
+
+ + + + + + + + +
uint8 system_get_cpu_freq (void )
+
+ +

Get CPU frequency.

+
Parameters
+ + +
null
+
+
+
Returns
CPU frequency, unit : MHz.
+ +
+
+ +
+
+ + + + + + + + +
flash_size_map system_get_flash_size_map (void )
+
+ +

Get the current Flash size and Flash map.

+

Flash map depends on the selection when compiling, more details in document "2A-ESP8266__IOT_SDK_User_Manual"

+
Parameters
+ + +
null
+
+
+
Returns
enum flash_size_map
+ +
+
+ +
+
+ + + + + + + + +
uint32 system_get_userbin_addr (void )
+
+ +

Get the address of the current running user bin (user1.bin or user2.bin).

+
Parameters
+ + +
null
+
+
+
Returns
The address of the current running user bin.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
bool system_restart_enhance (uint8 bin_type,
uint32 bin_addr 
)
+
+ +

Restarts the system, and enters the enhanced boot mode.

+
Attention
SYS_BOOT_TEST_BIN is used for factory test during production; users can apply for the test bin from Espressif Systems.
+
Parameters
+ + + +
uint8bin_type : type of bin
    +
  • #define SYS_BOOT_NORMAL_BIN 0 // user1.bin or user2.bin
  • +
  • #define SYS_BOOT_TEST_BIN 1 // can only be Espressif test bin
  • +
+
uint32bin_addr : starting address of the bin file
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
bool system_update_cpu_freq (uint8 freq)
+
+ +

Set CPU frequency. Default is 80MHz.

+

System bus frequency is 80MHz, will not be affected by CPU frequency. The frequency of UART, SPI, or other peripheral devices, are divided from system bus frequency, so they will not be affected by CPU frequency either.

+
Parameters
+ + +
uint8freq : CPU frequency, 80 or 160.
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Timer__APIs.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Timer__APIs.html new file mode 100644 index 0000000..9890855 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Timer__APIs.html @@ -0,0 +1,230 @@ + + + + + + +ESP8266_RTOS_SDK: Software timer APIs + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + +
+ +
+
+ + +
+ +
+ +
+ +
+
Software timer APIs
+
+
+ +

Software timer APIs. +More...

+ + + + + + + + + + + +

+Functions

void os_timer_setfn (os_timer_t *ptimer, os_timer_func_t *pfunction, void *parg)
 Set the timer callback function. More...
 
void os_timer_arm (os_timer_t *ptimer, uint32 msec, bool repeat_flag)
 Enable the millisecond timer. More...
 
void os_timer_disarm (os_timer_t *ptimer)
 Disarm the timer. More...
 
+

Detailed Description

+

Software timer APIs.

+

Timers of the following interfaces are software timers. Functions of the timers are executed during the tasks. Since a task can be stopped, or be delayed because there are other tasks with higher priorities, the following os_timer interfaces cannot guarantee the precise execution of the timers.

    +
  • For the same timer, os_timer_arm (or os_timer_arm_us) cannot be invoked repeatedly. os_timer_disarm should be invoked first.
  • +
  • os_timer_setfn can only be invoked when the timer is not enabled, i.e., after os_timer_disarm or before os_timer_arm (or os_timer_arm_us).
  • +
+

Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void os_timer_arm (os_timer_tptimer,
uint32 msec,
bool repeat_flag 
)
+
+ +

Enable the millisecond timer.

+
Parameters
+ + + + +
os_timer_t*ptimer : timer structure
uint32_tmilliseconds : Timing, unit: millisecond, range: 5 ~ 0x68DB8
boolrepeat_flag : Whether the timer will be invoked repeatedly or not
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
void os_timer_disarm (os_timer_tptimer)
+
+ +

Disarm the timer.

+
Parameters
+ + +
os_timer_t*ptimer : Timer structure
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void os_timer_setfn (os_timer_tptimer,
os_timer_func_t * pfunction,
void * parg 
)
+
+ +

Set the timer callback function.

+
Attention
1. The callback function must be set in order to enable the timer.
+
+2. Operating system scheduling is disabled in timer callback.
+
Parameters
+ + + + +
os_timer_t*ptimer : Timer structure
os_timer_func_t*pfunction : timer callback function
void*parg : callback function parameter
+
+
+
Returns
null
+ +
+
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__UART__Driver__APIs.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__UART__Driver__APIs.html new file mode 100644 index 0000000..d7a3719 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__UART__Driver__APIs.html @@ -0,0 +1,651 @@ + + + + + + +ESP8266_RTOS_SDK: UART Driver APIs + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + +
+ +
+
+ + +
+ +
+ +
+ +
+
UART Driver APIs
+
+
+ +

UART driver APIs. +More...

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Functions

void UART_WaitTxFifoEmpty (UART_Port uart_no)
 Wait uart tx fifo empty, do not use it if tx flow control enabled. More...
 
void UART_ResetFifo (UART_Port uart_no)
 Clear uart tx fifo and rx fifo. More...
 
void UART_ClearIntrStatus (UART_Port uart_no, uint32 clr_mask)
 Clear uart interrupt flags. More...
 
void UART_SetIntrEna (UART_Port uart_no, uint32 ena_mask)
 Enable uart interrupts . More...
 
void UART_intr_handler_register (void *fn, void *arg)
 Register an application-specific interrupt handler for Uarts interrupts. More...
 
void UART_SetPrintPort (UART_Port uart_no)
 Config from which serial output printf function. More...
 
void UART_ParamConfig (UART_Port uart_no, UART_ConfigTypeDef *pUARTConfig)
 Config Common parameters of serial ports. More...
 
void UART_IntrConfig (UART_Port uart_no, UART_IntrConfTypeDef *pUARTIntrConf)
 Config types of uarts. More...
 
void UART_SetWordLength (UART_Port uart_no, UART_WordLength len)
 Config the length of the uart communication data bits. More...
 
void UART_SetStopBits (UART_Port uart_no, UART_StopBits bit_num)
 Config the length of the uart communication stop bits. More...
 
void UART_SetParity (UART_Port uart_no, UART_ParityMode Parity_mode)
 Configure whether to open the parity. More...
 
void UART_SetBaudrate (UART_Port uart_no, uint32 baud_rate)
 Configure the Baud rate. More...
 
void UART_SetFlowCtrl (UART_Port uart_no, UART_HwFlowCtrl flow_ctrl, uint8 rx_thresh)
 Configure Hardware flow control. More...
 
void UART_SetLineInverse (UART_Port uart_no, UART_LineLevelInverse inverse_mask)
 Configure trigging signal of uarts. More...
 
void uart_init_new (void)
 An example illustrates how to configure the serial port. More...
 
+

Detailed Description

+

UART driver APIs.

+

Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + +
void UART_ClearIntrStatus (UART_Port uart_no,
uint32 clr_mask 
)
+
+ +

Clear uart interrupt flags.

+
Parameters
+ + + +
UART_Portuart_no : UART0 or UART1
uint32clr_mask : To clear the interrupt bits
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
void uart_init_new (void )
+
+ +

An example illustrates how to configure the serial port.

+
Parameters
+ + +
null
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void UART_intr_handler_register (void * fn,
void * arg 
)
+
+ +

Register an application-specific interrupt handler for Uarts interrupts.

+
Parameters
+ + + +
void*fn : interrupt handler for Uart interrupts.
void*arg : interrupt handler's arg.
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void UART_IntrConfig (UART_Port uart_no,
UART_IntrConfTypeDefpUARTIntrConf 
)
+
+ +

Config types of uarts.

+
Parameters
+ + + +
UART_Portuart_no : UART0 or UART1
UART_IntrConfTypeDef*pUARTIntrConf : parameters structure
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void UART_ParamConfig (UART_Port uart_no,
UART_ConfigTypeDefpUARTConfig 
)
+
+ +

Config Common parameters of serial ports.

+
Parameters
+ + + +
UART_Portuart_no : UART0 or UART1
UART_ConfigTypeDef*pUARTConfig : parameters structure
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
void UART_ResetFifo (UART_Port uart_no)
+
+ +

Clear uart tx fifo and rx fifo.

+
Parameters
+ + +
UART_Portuart_no : UART0 or UART1
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void UART_SetBaudrate (UART_Port uart_no,
uint32 baud_rate 
)
+
+ +

Configure the Baud rate.

+
Parameters
+ + + +
UART_Portuart_no : UART0 or UART1
uint32baud_rate : the Baud rate
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void UART_SetFlowCtrl (UART_Port uart_no,
UART_HwFlowCtrl flow_ctrl,
uint8 rx_thresh 
)
+
+ +

Configure Hardware flow control.

+
Parameters
+ + + + +
UART_Portuart_no : UART0 or UART1
UART_HwFlowCtrlflow_ctrl : Hardware flow control mode
uint8rx_thresh : threshold of Hardware flow control
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void UART_SetIntrEna (UART_Port uart_no,
uint32 ena_mask 
)
+
+ +

Enable uart interrupts .

+
Parameters
+ + + +
UART_Portuart_no : UART0 or UART1
uint32ena_mask : To enable the interrupt bits
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void UART_SetLineInverse (UART_Port uart_no,
UART_LineLevelInverse inverse_mask 
)
+
+ +

Configure trigging signal of uarts.

+
Parameters
+ + + +
UART_Portuart_no : UART0 or UART1
UART_LineLevelInverseinverse_mask : Choose need to flip the IO
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void UART_SetParity (UART_Port uart_no,
UART_ParityMode Parity_mode 
)
+
+ +

Configure whether to open the parity.

+
Parameters
+ + + +
UART_Portuart_no : UART0 or UART1
UART_ParityModeParity_mode : the enum of uart parity configuration
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
void UART_SetPrintPort (UART_Port uart_no)
+
+ +

Config from which serial output printf function.

+
Parameters
+ + +
UART_Portuart_no : UART0 or UART1
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void UART_SetStopBits (UART_Port uart_no,
UART_StopBits bit_num 
)
+
+ +

Config the length of the uart communication stop bits.

+
Parameters
+ + + +
UART_Portuart_no : UART0 or UART1
UART_StopBitsbit_num : the length uart communication stop bits
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void UART_SetWordLength (UART_Port uart_no,
UART_WordLength len 
)
+
+ +

Config the length of the uart communication data bits.

+
Parameters
+ + + +
UART_Portuart_no : UART0 or UART1
UART_WordLengthlen : the length of the uart communication data bits
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
void UART_WaitTxFifoEmpty (UART_Port uart_no)
+
+ +

Wait uart tx fifo empty, do not use it if tx flow control enabled.

+
Parameters
+ + +
UART_Portuart_no:UART0 or UART1
+
+
+
Returns
null
+ +
+
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Upgrade__APIs.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Upgrade__APIs.html new file mode 100644 index 0000000..506911f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__Upgrade__APIs.html @@ -0,0 +1,509 @@ + + + + + + +ESP8266_RTOS_SDK: Upgrade APIs + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + +
+ +
+
+ + +
+ +
+ +
+ +
+
Upgrade APIs
+
+
+ +

Firmware upgrade (FOTA) APIs. +More...

+ + + + +

+Data Structures

struct  upgrade_server_info
 
+ + + + + + + + + + + + + + + + + +

+Macros

#define SPI_FLASH_SEC_SIZE   4096
 
#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
 
+ + + + +

+Typedefs

typedef void(* upgrade_states_check_callback) (void *arg)
 Callback of upgrading firmware through WiFi. More...
 
+ + + + + + + + + + + + + + + + + + + + + + + + + +

+Functions

uint8 system_upgrade_userbin_check (void)
 Check the user bin. More...
 
void system_upgrade_reboot (void)
 Reboot system to use the new software. More...
 
uint8 system_upgrade_flag_check ()
 Check the upgrade status flag. More...
 
void system_upgrade_flag_set (uint8 flag)
 Set the upgrade status flag. More...
 
void system_upgrade_init ()
 Upgrade function initialization. More...
 
void system_upgrade_deinit ()
 Upgrade function de-initialization. More...
 
bool system_upgrade (uint8 *data, uint32 len)
 Upgrade function de-initialization. More...
 
bool system_upgrade_start (struct upgrade_server_info *server)
 Start upgrade firmware through WiFi with normal connection. More...
 
+

Detailed Description

+

Firmware upgrade (FOTA) APIs.

+

Macro Definition Documentation

+ +
+
+ + + + +
#define SPI_FLASH_SEC_SIZE   4096
+
+

SPI Flash sector size

+ +
+
+ +
+
+ + + + +
#define UPGRADE_FLAG_FINISH   0x02
+
+

flag of upgrading firmware, finish upgrading

+ +
+
+ +
+
+ + + + +
#define UPGRADE_FLAG_IDLE   0x00
+
+

flag of upgrading firmware, idle

+ +
+
+ +
+
+ + + + +
#define UPGRADE_FLAG_START   0x01
+
+

flag of upgrading firmware, start upgrade

+ +
+
+ +
+
+ + + + +
#define UPGRADE_FW_BIN1   0x00
+
+

firmware, user1.bin

+ +
+
+ +
+
+ + + + +
#define UPGRADE_FW_BIN2   0x01
+
+

firmware, user2.bin

+ +
+
+ +
+
+ + + + +
#define USER_BIN1   0x00
+
+

firmware, user1.bin

+ +
+
+ +
+
+ + + + +
#define USER_BIN2   0x01
+
+

firmware, user2.bin

+ +
+
+

Typedef Documentation

+ +
+
+ + + + +
typedef void(* upgrade_states_check_callback) (void *arg)
+
+ +

Callback of upgrading firmware through WiFi.

+
Parameters
+ + +
void* arg : information about upgrading server
+
+
+
Returns
null
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + +
bool system_upgrade (uint8 * data,
uint32 len 
)
+
+ +

Upgrade function de-initialization.

+
Parameters
+ + + +
uint8*data : segment of the firmware bin data
uint32len : length of the segment bin data
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + +
void system_upgrade_deinit ()
+
+ +

Upgrade function de-initialization.

+
Parameters
+ + +
null
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + +
uint8 system_upgrade_flag_check ()
+
+ +

Check the upgrade status flag.

+
Parameters
+ + +
null
+
+
+
Returns
#define UPGRADE_FLAG_IDLE 0x00
+
+#define UPGRADE_FLAG_START 0x01
+
+#define UPGRADE_FLAG_FINISH 0x02
+ +
+
+ +
+
+ + + + + + + + +
void system_upgrade_flag_set (uint8 flag)
+
+ +

Set the upgrade status flag.

+
Attention
After downloading new softwares, set the flag to UPGRADE_FLAG_FINISH and call system_upgrade_reboot to reboot the system in order to run the new software.
+
Parameters
+ + +
uint8flag:
    +
  • UPGRADE_FLAG_IDLE 0x00
  • +
  • UPGRADE_FLAG_START 0x01
  • +
  • UPGRADE_FLAG_FINISH 0x02
  • +
+
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + +
void system_upgrade_init ()
+
+ +

Upgrade function initialization.

+
Parameters
+ + +
null
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
void system_upgrade_reboot (void )
+
+ +

Reboot system to use the new software.

+
Parameters
+ + +
null
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
bool system_upgrade_start (struct upgrade_server_infoserver)
+
+ +

Start upgrade firmware through WiFi with normal connection.

+
Parameters
+ + +
structupgrade_server_info *server : the firmware upgrade server info
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
uint8 system_upgrade_userbin_check (void )
+
+ +

Check the user bin.

+
Parameters
+ + +
null
+
+
+
Returns
0x00 : UPGRADE_FW_BIN1, i.e. user1.bin
+
+0x01 : UPGRADE_FW_BIN2, i.e. user2.bin
+ +
+
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__WPS__APIs.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__WPS__APIs.html new file mode 100644 index 0000000..ebce1fb --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__WPS__APIs.html @@ -0,0 +1,317 @@ + + + + + + +ESP8266_RTOS_SDK: WPS APIs + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + +
+ +
+
+ + +
+ +
+ + +
+ +

ESP8266 WPS APIs. +More...

+ + + + + + + +

+Typedefs

+typedef enum wps_type WPS_TYPE_t
 
typedef void(* wps_st_cb_t) (int status)
 WPS callback. More...
 
+ + + + + +

+Enumerations

enum  wps_type {
+  WPS_TYPE_DISABLE = 0, +WPS_TYPE_PBC, +WPS_TYPE_PIN, +WPS_TYPE_DISPLAY, +
+  WPS_TYPE_MAX +
+ }
 
enum  wps_cb_status {
+  WPS_CB_ST_SUCCESS = 0, +WPS_CB_ST_FAILED, +WPS_CB_ST_TIMEOUT, +WPS_CB_ST_WEP, +
+  WPS_CB_ST_SCAN_ERR +
+ }
 
+ + + + + + + + + + + + + +

+Functions

bool wifi_wps_enable (WPS_TYPE_t wps_type)
 Enable Wi-Fi WPS function. More...
 
bool wifi_wps_disable (void)
 Disable Wi-Fi WPS function and release resource it taken. More...
 
bool wifi_wps_start (void)
 WPS starts to work. More...
 
bool wifi_set_wps_cb (wps_st_cb_t cb)
 Set WPS callback. More...
 
+

Detailed Description

+

ESP8266 WPS APIs.

+

WPS can only be used when ESP8266 station is enabled.

+

Typedef Documentation

+ +
+
+ + + + +
typedef void(* wps_st_cb_t) (int status)
+
+ +

WPS callback.

+
Parameters
+ + +
intstatus : status of WPS, enum wps_cb_status.
    +
  • If parameter status == WPS_CB_ST_SUCCESS in WPS callback, it means WPS got AP's information, user can call wifi_wps_disable to disable WPS and release resource, then call wifi_station_connect to connect to target AP.
  • +
  • Otherwise, it means that WPS fail, user can create a timer to retry WPS by wifi_wps_start after a while, or call wifi_wps_disable to disable WPS and release resource.
  • +
+
+
+
+
Returns
null
+ +
+
+

Enumeration Type Documentation

+ +
+
+ + + + +
enum wps_cb_status
+
+ + + + + + +
Enumerator
WPS_CB_ST_SUCCESS  +

WPS succeed

+
WPS_CB_ST_FAILED  +

WPS fail

+
WPS_CB_ST_TIMEOUT  +

WPS timeout, fail

+
WPS_CB_ST_WEP  +

WPS failed because that WEP is not supported

+
WPS_CB_ST_SCAN_ERR  +

can not find the target WPS AP

+
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + +
bool wifi_set_wps_cb (wps_st_cb_t cb)
+
+ +

Set WPS callback.

+
Attention
WPS can only be used when ESP8266 station is enabled.
+
Parameters
+ + +
wps_st_cb_tcb : callback.
+
+
+
Returns
true : WPS starts to work successfully, but does not mean WPS succeed.
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_wps_disable (void )
+
+ +

Disable Wi-Fi WPS function and release resource it taken.

+
Parameters
+ + +
null
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_wps_enable (WPS_TYPE_t wps_type)
+
+ +

Enable Wi-Fi WPS function.

+
Attention
WPS can only be used when ESP8266 station is enabled.
+
Parameters
+ + +
WPS_TYPE_twps_type : WPS type, so far only WPS_TYPE_PBC is supported
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_wps_start (void )
+
+ +

WPS starts to work.

+
Attention
WPS can only be used when ESP8266 station is enabled.
+
Parameters
+ + +
null
+
+
+
Returns
true : WPS starts to work successfully, but does not mean WPS succeed.
+
+false : fail
+ +
+
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__WiFi__APIs.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__WiFi__APIs.html new file mode 100644 index 0000000..5a14cae --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__WiFi__APIs.html @@ -0,0 +1,132 @@ + + + + + + +ESP8266_RTOS_SDK: WiFi Related APIs + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + +
+ +
+
+ + +
+ +
+ +
+ +
+
WiFi Related APIs
+
+
+ +

WiFi APIs. +More...

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Modules

 AirKiss APIs
 AirKiss APIs.
 
 SoftAP APIs
 ESP8266 Soft-AP APIs.
 
 Station APIs
 ESP8266 station APIs.
 
 Common APIs
 WiFi common APIs.
 
 Force Sleep APIs
 WiFi Force Sleep APIs.
 
 Rate Control APIs
 WiFi Rate Control APIs.
 
 User IE APIs
 WiFi User IE APIs.
 
 Sniffer APIs
 WiFi sniffer APIs.
 
 WPS APIs
 ESP8266 WPS APIs.
 
 Smartconfig APIs
 SmartConfig APIs.
 
+

Detailed Description

+

WiFi APIs.

+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__WiFi__Common__APIs.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__WiFi__Common__APIs.html new file mode 100644 index 0000000..aa08c1b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__WiFi__Common__APIs.html @@ -0,0 +1,1219 @@ + + + + + + +ESP8266_RTOS_SDK: Common APIs + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + +
+ +
+
+ + +
+ +
+ + +
+ +

WiFi common APIs. +More...

+ + + + + + + + + + + + + + + + + + + + + + + + +

+Data Structures

struct  ip_info
 
struct  Event_StaMode_ScanDone_t
 
struct  Event_StaMode_Connected_t
 
struct  Event_StaMode_Disconnected_t
 
struct  Event_StaMode_AuthMode_Change_t
 
struct  Event_StaMode_Got_IP_t
 
struct  Event_SoftAPMode_StaConnected_t
 
struct  Event_SoftAPMode_StaDisconnected_t
 
struct  Event_SoftAPMode_ProbeReqRecved_t
 
union  Event_Info_u
 
struct  _esp_event
 
+ + + + + + + + + + + + +

+Typedefs

+typedef struct _esp_event System_Event_t
 
typedef void(* wifi_event_handler_cb_t) (System_Event_t *event)
 The Wi-Fi event handler. More...
 
typedef void(* freedom_outside_cb_t) (uint8 status)
 Callback of sending user-define 802.11 packets. More...
 
typedef void(* rfid_locp_cb_t) (uint8 *frm, int len, sint8 rssi)
 RFID LOCP (Location Control Protocol) receive callback . More...
 
+ + + + + + + + + + + + + + + +

+Enumerations

enum  WIFI_MODE {
+  NULL_MODE = 0, +STATION_MODE, +SOFTAP_MODE, +STATIONAP_MODE, +
+  MAX_MODE +
+ }
 
enum  AUTH_MODE {
+  AUTH_OPEN = 0, +AUTH_WEP, +AUTH_WPA_PSK, +AUTH_WPA2_PSK, +
+  AUTH_WPA_WPA2_PSK, +AUTH_MAX +
+ }
 
enum  WIFI_INTERFACE { STATION_IF = 0, +SOFTAP_IF, +MAX_IF + }
 
enum  WIFI_PHY_MODE { PHY_MODE_11B = 1, +PHY_MODE_11G = 2, +PHY_MODE_11N = 3 + }
 
enum  SYSTEM_EVENT {
+  EVENT_STAMODE_SCAN_DONE = 0, +EVENT_STAMODE_CONNECTED, +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_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, +REASON_DISASSOC_SUPCHAN_BAD = 11, +REASON_IE_INVALID = 13, +
+  REASON_MIC_FAILURE = 14, +REASON_4WAY_HANDSHAKE_TIMEOUT = 15, +REASON_GROUP_KEY_UPDATE_TIMEOUT = 16, +REASON_IE_IN_4WAY_DIFFERS = 17, +
+  REASON_GROUP_CIPHER_INVALID = 18, +REASON_PAIRWISE_CIPHER_INVALID = 19, +REASON_AKMP_INVALID = 20, +REASON_UNSUPP_RSN_IE_VERSION = 21, +
+  REASON_INVALID_RSN_IE_CAP = 22, +REASON_802_1X_AUTH_FAILED = 23, +REASON_CIPHER_SUITE_REJECTED = 24, +REASON_BEACON_TIMEOUT = 200, +
+  REASON_NO_AP_FOUND = 201, +REASON_AUTH_FAIL = 202, +REASON_ASSOC_FAIL = 203, +REASON_HANDSHAKE_TIMEOUT = 204 +
+ }
 
enum  sleep_type { NONE_SLEEP_T = 0, +LIGHT_SLEEP_T, +MODEM_SLEEP_T + }
 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Functions

WIFI_MODE wifi_get_opmode (void)
 Get the current operating mode of the WiFi. More...
 
WIFI_MODE wifi_get_opmode_default (void)
 Get the operating mode of the WiFi saved in the Flash. More...
 
bool wifi_set_opmode (WIFI_MODE opmode)
 Set the WiFi operating mode, and save it to Flash. More...
 
bool wifi_set_opmode_current (WIFI_MODE opmode)
 Set the WiFi operating mode, and will not save it to Flash. More...
 
bool wifi_get_ip_info (WIFI_INTERFACE if_index, struct ip_info *info)
 Get the IP address of the ESP8266 WiFi station or the soft-AP interface. More...
 
bool wifi_set_ip_info (WIFI_INTERFACE if_index, struct ip_info *info)
 Set the IP address of the ESP8266 WiFi station or the soft-AP interface. More...
 
bool wifi_get_macaddr (WIFI_INTERFACE if_index, uint8 *macaddr)
 Get MAC address of the ESP8266 WiFi station or the soft-AP interface. More...
 
bool wifi_set_macaddr (WIFI_INTERFACE if_index, uint8 *macaddr)
 Set MAC address of the ESP8266 WiFi station or the soft-AP interface. More...
 
void wifi_status_led_install (uint8 gpio_id, uint32 gpio_name, uint8 gpio_func)
 Install the WiFi status LED. More...
 
void wifi_status_led_uninstall (void)
 Uninstall the WiFi status LED. More...
 
WIFI_PHY_MODE wifi_get_phy_mode (void)
 Get the ESP8266 physical mode (802.11b/g/n). More...
 
bool wifi_set_phy_mode (WIFI_PHY_MODE mode)
 Set the ESP8266 physical mode (802.11b/g/n). More...
 
bool wifi_set_event_handler_cb (wifi_event_handler_cb_t cb)
 Register the Wi-Fi event handler. More...
 
sint32 wifi_register_send_pkt_freedom_cb (freedom_outside_cb_t cb)
 Register a callback for sending user-define 802.11 packets. More...
 
void wifi_unregister_send_pkt_freedom_cb (void)
 Unregister the callback for sending user-define 802.11 packets. More...
 
sint32 wifi_send_pkt_freedom (uint8 *buf, uint16 len, bool sys_seq)
 Send user-define 802.11 packets. More...
 
sint32 wifi_rfid_locp_recv_open (void)
 Enable RFID LOCP (Location Control Protocol) to receive WDS packets. More...
 
void wifi_rfid_locp_recv_close (void)
 Disable RFID LOCP (Location Control Protocol) . More...
 
sint32 wifi_register_rfid_locp_recv_cb (rfid_locp_cb_t cb)
 Register a callback of receiving WDS packets. More...
 
void wifi_unregister_rfid_locp_recv_cb (void)
 Unregister the callback of receiving WDS packets. More...
 
bool wifi_set_sleep_type (sleep_type type)
 Sets sleep type. More...
 
sleep_type wifi_get_sleep_type (void)
 Gets sleep type. More...
 
+

Detailed Description

+

WiFi common APIs.

+

The Flash system parameter area is the last 16KB of the Flash.

+

Typedef Documentation

+ +
+
+ + + + +
typedef void(* freedom_outside_cb_t) (uint8 status)
+
+ +

Callback of sending user-define 802.11 packets.

+
Parameters
+ + +
uint8status : 0, packet sending succeed; otherwise, fail.
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + +
typedef void(* rfid_locp_cb_t) (uint8 *frm, int len, sint8 rssi)
+
+ +

RFID LOCP (Location Control Protocol) receive callback .

+
Parameters
+ + + + +
uint8*frm : point to the head of 802.11 packet
intlen : packet length
intrssi : signal strength
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + +
typedef void(* wifi_event_handler_cb_t) (System_Event_t *event)
+
+ +

The Wi-Fi event handler.

+
Attention
No complex operations are allowed in callback. If users want to execute any complex operations, please post message to another task instead.
+
Parameters
+ + +
System_Event_t*event : WiFi event
+
+
+
Returns
null
+ +
+
+

Enumeration Type Documentation

+ +
+
+ + + + +
enum AUTH_MODE
+
+ + + + + + +
Enumerator
AUTH_OPEN  +

authenticate mode : open

+
AUTH_WEP  +

authenticate mode : WEP

+
AUTH_WPA_PSK  +

authenticate mode : WPA_PSK

+
AUTH_WPA2_PSK  +

authenticate mode : WPA2_PSK

+
AUTH_WPA_WPA2_PSK  +

authenticate mode : WPA_WPA2_PSK

+
+ +
+
+ +
+
+ + + + +
enum SYSTEM_EVENT
+
+ + + + + + + + + + +
Enumerator
EVENT_STAMODE_SCAN_DONE  +

ESP8266 station finish scanning AP

+
EVENT_STAMODE_CONNECTED  +

ESP8266 station connected to AP

+
EVENT_STAMODE_DISCONNECTED  +

ESP8266 station disconnected to AP

+
EVENT_STAMODE_AUTHMODE_CHANGE  +

the auth mode of AP connected by ESP8266 station changed

+
EVENT_STAMODE_GOT_IP  +

ESP8266 station got IP from connected AP

+
EVENT_STAMODE_DHCP_TIMEOUT  +

ESP8266 station dhcp client got IP timeout

+
EVENT_SOFTAPMODE_STACONNECTED  +

a station connected to ESP8266 soft-AP

+
EVENT_SOFTAPMODE_STADISCONNECTED  +

a station disconnected to ESP8266 soft-AP

+
EVENT_SOFTAPMODE_PROBEREQRECVED  +

Receive probe request packet in soft-AP interface

+
+ +
+
+ +
+
+ + + + +
enum WIFI_INTERFACE
+
+ + + +
Enumerator
STATION_IF  +

ESP8266 station interface

+
SOFTAP_IF  +

ESP8266 soft-AP interface

+
+ +
+
+ +
+
+ + + + +
enum WIFI_MODE
+
+ + + + + +
Enumerator
NULL_MODE  +

null mode

+
STATION_MODE  +

WiFi station mode

+
SOFTAP_MODE  +

WiFi soft-AP mode

+
STATIONAP_MODE  +

WiFi station + soft-AP mode

+
+ +
+
+ +
+
+ + + + +
enum WIFI_PHY_MODE
+
+ + + + +
Enumerator
PHY_MODE_11B  +

802.11b

+
PHY_MODE_11G  +

802.11g

+
PHY_MODE_11N  +

802.11n

+
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + +
bool wifi_get_ip_info (WIFI_INTERFACE if_index,
struct ip_infoinfo 
)
+
+ +

Get the IP address of the ESP8266 WiFi station or the soft-AP interface.

+
Attention
Users need to enable the target interface (station or soft-AP) by wifi_set_opmode first.
+
Parameters
+ + + +
WIFI_INTERFACEif_index : get the IP address of the station or the soft-AP interface, 0x00 for STATION_IF, 0x01 for SOFTAP_IF.
structip_info *info : the IP information obtained.
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
bool wifi_get_macaddr (WIFI_INTERFACE if_index,
uint8 * macaddr 
)
+
+ +

Get MAC address of the ESP8266 WiFi station or the soft-AP interface.

+
Parameters
+ + + +
WIFI_INTERFACEif_index : get the IP address of the station or the soft-AP interface, 0x00 for STATION_IF, 0x01 for SOFTAP_IF.
uint8*macaddr : the MAC address.
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
WIFI_MODE wifi_get_opmode (void )
+
+ +

Get the current operating mode of the WiFi.

+
Parameters
+ + +
null
+
+
+
Returns
WiFi operating modes:
    +
  • 0x01: station mode;
  • +
  • 0x02: soft-AP mode
  • +
  • 0x03: station+soft-AP mode
  • +
+
+ +
+
+ +
+
+ + + + + + + + +
WIFI_MODE wifi_get_opmode_default (void )
+
+ +

Get the operating mode of the WiFi saved in the Flash.

+
Parameters
+ + +
null
+
+
+
Returns
WiFi operating modes:
    +
  • 0x01: station mode;
  • +
  • 0x02: soft-AP mode
  • +
  • 0x03: station+soft-AP mode
  • +
+
+ +
+
+ +
+
+ + + + + + + + +
WIFI_PHY_MODE wifi_get_phy_mode (void )
+
+ +

Get the ESP8266 physical mode (802.11b/g/n).

+
Parameters
+ + +
null
+
+
+
Returns
enum WIFI_PHY_MODE
+ +
+
+ +
+
+ + + + + + + + +
sleep_type wifi_get_sleep_type (void )
+
+ +

Gets sleep type.

+
Parameters
+ + +
null
+
+
+
Returns
sleep type
+ +
+
+ +
+
+ + + + + + + + +
sint32 wifi_register_rfid_locp_recv_cb (rfid_locp_cb_t cb)
+
+ +

Register a callback of receiving WDS packets.

+

Register a callback of receiving WDS packets. Only if the first MAC address of the WDS packet is a multicast address.

+
Parameters
+ + +
rfid_locp_cb_tcb : callback
+
+
+
Returns
0, succeed;
+
+otherwise, fail.
+ +
+
+ +
+
+ + + + + + + + +
sint32 wifi_register_send_pkt_freedom_cb (freedom_outside_cb_t cb)
+
+ +

Register a callback for sending user-define 802.11 packets.

+
Attention
Only after the previous packet was sent, entered the freedom_outside_cb_t, the next packet is allowed to send.
+
Parameters
+ + +
freedom_outside_cb_tcb : sent callback
+
+
+
Returns
0, succeed;
+
+-1, fail.
+ +
+
+ +
+
+ + + + + + + + +
void wifi_rfid_locp_recv_close (void )
+
+ +

Disable RFID LOCP (Location Control Protocol) .

+
Parameters
+ + +
null
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
sint32 wifi_rfid_locp_recv_open (void )
+
+ +

Enable RFID LOCP (Location Control Protocol) to receive WDS packets.

+
Parameters
+ + +
null
+
+
+
Returns
0, succeed;
+
+otherwise, fail.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
sint32 wifi_send_pkt_freedom (uint8 * buf,
uint16 len,
bool sys_seq 
)
+
+ +

Send user-define 802.11 packets.

+
Attention
1. Packet has to be the whole 802.11 packet, does not include the FCS. The length of the packet has to be longer than the minimum length of the header of 802.11 packet which is 24 bytes, and less than 1400 bytes.
+
+2. Duration area is invalid for user, it will be filled in SDK.
+
+3. The rate of sending packet is same as the management packet which is the same as the system rate of sending packets.
+
+4. Only after the previous packet was sent, entered the sent callback, the next packet is allowed to send. Otherwise, wifi_send_pkt_freedom will return fail.
+
Parameters
+ + + + +
uint8*buf : pointer of packet
uint16len : packet length
boolsys_seq : follow the system's 802.11 packets sequence number or not, if it is true, the sequence number will be increased 1 every time a packet sent.
+
+
+
Returns
0, succeed;
+
+-1, fail.
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_set_event_handler_cb (wifi_event_handler_cb_t cb)
+
+ +

Register the Wi-Fi event handler.

+
Parameters
+ + +
wifi_event_handler_cb_tcb : callback function
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
bool wifi_set_ip_info (WIFI_INTERFACE if_index,
struct ip_infoinfo 
)
+
+ +

Set the IP address of the ESP8266 WiFi station or the soft-AP interface.

+
Attention
1. Users need to enable the target interface (station or soft-AP) by wifi_set_opmode first.
+
+2. To set static IP, users need to disable DHCP first (wifi_station_dhcpc_stop or wifi_softap_dhcps_stop):
    +
  • If the DHCP is enabled, the static IP will be disabled; if the static IP is enabled, the DHCP will be disabled. It depends on the latest configuration.
  • +
+
+
Parameters
+ + + +
WIFI_INTERFACEif_index : get the IP address of the station or the soft-AP interface, 0x00 for STATION_IF, 0x01 for SOFTAP_IF.
structip_info *info : the IP information obtained.
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
bool wifi_set_macaddr (WIFI_INTERFACE if_index,
uint8 * macaddr 
)
+
+ +

Set MAC address of the ESP8266 WiFi station or the soft-AP interface.

+
Attention
1. This API can only be called in user_init.
+
+2. Users need to enable the target interface (station or soft-AP) by wifi_set_opmode first.
+
+3. ESP8266 soft-AP and station have different MAC addresses, do not set them to be the same.
    +
  • The bit0 of the first byte of ESP8266 MAC address can not be 1. For example, the MAC address can set to be "1a:XX:XX:XX:XX:XX", but can not be "15:XX:XX:XX:XX:XX".
  • +
+
+
Parameters
+ + + +
WIFI_INTERFACEif_index : get the IP address of the station or the soft-AP interface, 0x00 for STATION_IF, 0x01 for SOFTAP_IF.
uint8*macaddr : the MAC address.
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_set_opmode (WIFI_MODE opmode)
+
+ +

Set the WiFi operating mode, and save it to Flash.

+

Set the WiFi operating mode as station, soft-AP or station+soft-AP, and save it to Flash. The default mode is soft-AP mode.

+
Attention
This configuration will be saved in the Flash system parameter area if changed.
+
Parameters
+ + +
uint8opmode : WiFi operating modes:
    +
  • 0x01: station mode;
  • +
  • 0x02: soft-AP mode
  • +
  • 0x03: station+soft-AP mode
  • +
+
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_set_opmode_current (WIFI_MODE opmode)
+
+ +

Set the WiFi operating mode, and will not save it to Flash.

+

Set the WiFi operating mode as station, soft-AP or station+soft-AP, and the mode won't be saved to the Flash.

+
Parameters
+ + +
uint8opmode : WiFi operating modes:
    +
  • 0x01: station mode;
  • +
  • 0x02: soft-AP mode
  • +
  • 0x03: station+soft-AP mode
  • +
+
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_set_phy_mode (WIFI_PHY_MODE mode)
+
+ +

Set the ESP8266 physical mode (802.11b/g/n).

+
Attention
The ESP8266 soft-AP only supports bg.
+
Parameters
+ + +
WIFI_PHY_MODEmode : physical mode
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_set_sleep_type (sleep_type type)
+
+ +

Sets sleep type.

+

Set NONE_SLEEP_T to disable sleep. Default to be Modem sleep.

+
Attention
Sleep function only takes effect in station-only mode.
+
Parameters
+ + +
sleep_typetype : sleep type
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void wifi_status_led_install (uint8 gpio_id,
uint32 gpio_name,
uint8 gpio_func 
)
+
+ +

Install the WiFi status LED.

+
Parameters
+ + + + +
uint8gpio_id : GPIO ID
uint8gpio_name : GPIO mux name
uint8gpio_func : GPIO function
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
void wifi_status_led_uninstall (void )
+
+ +

Uninstall the WiFi status LED.

+
Parameters
+ + +
null
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
void wifi_unregister_rfid_locp_recv_cb (void )
+
+ +

Unregister the callback of receiving WDS packets.

+
Parameters
+ + +
null
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
void wifi_unregister_send_pkt_freedom_cb (void )
+
+ +

Unregister the callback for sending user-define 802.11 packets.

+
Parameters
+ + +
null
+
+
+
Returns
null
+ +
+
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__WiFi__Force__Sleep__APIs.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__WiFi__Force__Sleep__APIs.html new file mode 100644 index 0000000..506b26e --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__WiFi__Force__Sleep__APIs.html @@ -0,0 +1,326 @@ + + + + + + +ESP8266_RTOS_SDK: Force Sleep APIs + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + +
+ +
+
+ + +
+ +
+ +
+ +
+
Force Sleep APIs
+
+
+ +

WiFi Force Sleep APIs. +More...

+ + + + +

+Typedefs

+typedef void(* fpm_wakeup_cb) (void)
 
+ + + + + + + + + + + + + + + + + + + + + + +

+Functions

void wifi_fpm_open (void)
 Enable force sleep function. More...
 
void wifi_fpm_close (void)
 Disable force sleep function. More...
 
void wifi_fpm_do_wakeup (void)
 Wake ESP8266 up from MODEM_SLEEP_T force sleep. More...
 
void wifi_fpm_set_wakeup_cb (fpm_wakeup_cb cb)
 Set a callback of waken up from force sleep because of time out. More...
 
sint8 wifi_fpm_do_sleep (uint32 sleep_time_in_us)
 Force ESP8266 enter sleep mode, and it will wake up automatically when time out. More...
 
void wifi_fpm_set_sleep_type (sleep_type type)
 Set sleep type for force sleep function. More...
 
sleep_type wifi_fpm_get_sleep_type (void)
 Get sleep type of force sleep function. More...
 
+

Detailed Description

+

WiFi Force Sleep APIs.

+

Function Documentation

+ +
+
+ + + + + + + + +
void wifi_fpm_close (void )
+
+ +

Disable force sleep function.

+
Parameters
+ + +
null
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
sint8 wifi_fpm_do_sleep (uint32 sleep_time_in_us)
+
+ +

Force ESP8266 enter sleep mode, and it will wake up automatically when time out.

+
Attention
1. This API can only be called when force sleep function is enabled, after calling wifi_fpm_open. This API can not be called after calling wifi_fpm_close.
+
+2. If this API returned 0 means that the configuration is set successfully, but the ESP8266 will not enter sleep mode immediately, it is going to sleep in the system idle task. Please do not call other WiFi related function right after calling this API.
+
Parameters
+ + +
uint32sleep_time_in_us : sleep time, ESP8266 will wake up automatically when time out. Unit: us. Range: 10000 ~ 268435455(0xFFFFFFF).
    +
  • If sleep_time_in_us is 0xFFFFFFF, the ESP8266 will sleep till
  • +
  • if wifi_fpm_set_sleep_type is set to be LIGHT_SLEEP_T, ESP8266 can wake up by GPIO.
  • +
  • if wifi_fpm_set_sleep_type is set to be MODEM_SLEEP_T, ESP8266 can wake up by wifi_fpm_do_wakeup.
  • +
+
+
+
+
Returns
0, setting succeed;
+
+-1, fail to sleep, sleep status error;
+
+-2, fail to sleep, force sleep function is not enabled.
+ +
+
+ +
+
+ + + + + + + + +
void wifi_fpm_do_wakeup (void )
+
+ +

Wake ESP8266 up from MODEM_SLEEP_T force sleep.

+
Attention
This API can only be called when MODEM_SLEEP_T force sleep function is enabled, after calling wifi_fpm_open. This API can not be called after calling wifi_fpm_close.
+
Parameters
+ + +
null
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
sleep_type wifi_fpm_get_sleep_type (void )
+
+ +

Get sleep type of force sleep function.

+
Parameters
+ + +
null
+
+
+
Returns
sleep type
+ +
+
+ +
+
+ + + + + + + + +
void wifi_fpm_open (void )
+
+ +

Enable force sleep function.

+
Attention
Force sleep function is disabled by default.
+
Parameters
+ + +
null
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
void wifi_fpm_set_sleep_type (sleep_type type)
+
+ +

Set sleep type for force sleep function.

+
Attention
This API can only be called before wifi_fpm_open.
+
Parameters
+ + +
sleep_typetype : sleep type
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
void wifi_fpm_set_wakeup_cb (fpm_wakeup_cb cb)
+
+ +

Set a callback of waken up from force sleep because of time out.

+
Attention
1. This API can only be called when force sleep function is enabled, after calling wifi_fpm_open. This API can not be called after calling wifi_fpm_close.
+
+2. fpm_wakeup_cb_func will be called after system woke up only if the force sleep time out (wifi_fpm_do_sleep and the parameter is not 0xFFFFFFF).
+
+3. fpm_wakeup_cb_func will not be called if woke up by wifi_fpm_do_wakeup from MODEM_SLEEP_T type force sleep.
+
Parameters
+ + +
void(*fpm_wakeup_cb_func)(void) : callback of waken up
+
+
+
Returns
null
+ +
+
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__WiFi__Rate__Control__APIs.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__WiFi__Rate__Control__APIs.html new file mode 100644 index 0000000..8a170bd --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__WiFi__Rate__Control__APIs.html @@ -0,0 +1,496 @@ + + + + + + +ESP8266_RTOS_SDK: Rate Control APIs + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + +
+ +
+
+ + +
+ +
+ +
+ +
+
Rate Control APIs
+
+
+ +

WiFi Rate Control APIs. +More...

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Macros

+#define FIXED_RATE_MASK_NONE   0x00
 
+#define FIXED_RATE_MASK_STA   0x01
 
+#define FIXED_RATE_MASK_AP   0x02
 
+#define FIXED_RATE_MASK_ALL   0x03
 
+#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
 
+ + + + + + + + + + + +

+Enumerations

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 +
+ }
 
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 +
+ }
 
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 +
+ }
 
+ + + + + + + + + + + + + + + + + + + +

+Functions

sint32 wifi_set_user_fixed_rate (uint8 enable_mask, uint8 rate)
 Set the fixed rate and mask of sending data from ESP8266. More...
 
int wifi_get_user_fixed_rate (uint8 *enable_mask, uint8 *rate)
 Get the fixed rate and mask of ESP8266. More...
 
sint32 wifi_set_user_sup_rate (uint8 min, uint8 max)
 Set the support rate of ESP8266. More...
 
bool wifi_set_user_rate_limit (uint8 mode, uint8 ifidx, uint8 max, uint8 min)
 Limit the initial rate of sending data from ESP8266. More...
 
uint8 wifi_get_user_limit_rate_mask (void)
 Get the interfaces of ESP8266 whose rate of sending data is limited by wifi_set_user_rate_limit. More...
 
bool wifi_set_user_limit_rate_mask (uint8 enable_mask)
 Set the interfaces of ESP8266 whose rate of sending packets is limited by wifi_set_user_rate_limit. More...
 
+

Detailed Description

+

WiFi Rate Control APIs.

+

Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + +
int wifi_get_user_fixed_rate (uint8 * enable_mask,
uint8 * rate 
)
+
+ +

Get the fixed rate and mask of ESP8266.

+
Parameters
+ + + +
uint8*enable_mask : pointer of the enable_mask
uint8*rate : pointer of the fixed rate
+
+
+
Returns
0 : succeed
+
+otherwise : fail
+ +
+
+ +
+
+ + + + + + + + +
uint8 wifi_get_user_limit_rate_mask (void )
+
+ +

Get the interfaces of ESP8266 whose rate of sending data is limited by wifi_set_user_rate_limit.

+
Parameters
+ + +
null
+
+
+
Returns
LIMIT_RATE_MASK_NONE - disable the limitation on both ESP8266 station and soft-AP
+
+LIMIT_RATE_MASK_STA - enable the limitation on ESP8266 station
+
+LIMIT_RATE_MASK_AP - enable the limitation on ESP8266 soft-AP
+
+LIMIT_RATE_MASK_ALL - enable the limitation on both ESP8266 station and soft-AP
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
sint32 wifi_set_user_fixed_rate (uint8 enable_mask,
uint8 rate 
)
+
+ +

Set the fixed rate and mask of sending data from ESP8266.

+
Attention
1. Only if the corresponding bit in enable_mask is 1, ESP8266 station or soft-AP will send data in the fixed rate.
+
+2. If the enable_mask is 0, both ESP8266 station and soft-AP will not send data in the fixed rate.
+
+3. ESP8266 station and soft-AP share the same rate, they can not be set into the different rate.
+
Parameters
+ + + +
uint8enable_mask : 0x00 - disable the fixed rate
    +
  • 0x01 - use the fixed rate on ESP8266 station
  • +
  • 0x02 - use the fixed rate on ESP8266 soft-AP
  • +
  • 0x03 - use the fixed rate on ESP8266 station and soft-AP
  • +
+
uint8rate : value of the fixed rate
+
+
+
Returns
0 : succeed
+
+otherwise : fail
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_set_user_limit_rate_mask (uint8 enable_mask)
+
+ +

Set the interfaces of ESP8266 whose rate of sending packets is limited by wifi_set_user_rate_limit.

+
Parameters
+ + +
uint8enable_mask :
    +
  • LIMIT_RATE_MASK_NONE - disable the limitation on both ESP8266 station and soft-AP
  • +
  • LIMIT_RATE_MASK_STA - enable the limitation on ESP8266 station
  • +
  • LIMIT_RATE_MASK_AP - enable the limitation on ESP8266 soft-AP
  • +
  • LIMIT_RATE_MASK_ALL - enable the limitation on both ESP8266 station and soft-AP
  • +
+
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
bool wifi_set_user_rate_limit (uint8 mode,
uint8 ifidx,
uint8 max,
uint8 min 
)
+
+ +

Limit the initial rate of sending data from ESP8266.

+

Example: wifi_set_user_rate_limit(RC_LIMIT_11G, 0, RATE_11G_G18M, RATE_11G_G6M);

+
Attention
The rate of retransmission is not limited by this API.
+
Parameters
+ + + + + +
uint8mode : WiFi mode
    +
  • #define RC_LIMIT_11B 0
  • +
  • #define RC_LIMIT_11G 1
  • +
  • #define RC_LIMIT_11N 2
  • +
+
uint8ifidx : interface of ESP8266
    +
  • 0x00 - ESP8266 station
  • +
  • 0x01 - ESP8266 soft-AP
  • +
+
uint8max : the maximum value of the rate, according to the enum rate corresponding to the first parameter mode.
uint8min : the minimum value of the rate, according to the enum rate corresponding to the first parameter mode.
+
+
+
Returns
0 : succeed
+
+otherwise : fail
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
sint32 wifi_set_user_sup_rate (uint8 min,
uint8 max 
)
+
+ +

Set the support rate of ESP8266.

+

Set the rate range in the IE of support rate in ESP8266's beacon, probe req/resp and other packets. Tell other devices about the rate range supported by ESP8266 to limit the rate of sending packets from other devices. Example : wifi_set_user_sup_rate(RATE_11G6M, RATE_11G24M);

+
Attention
This API can only support 802.11g now, but it will support 802.11b in next version.
+
Parameters
+ + + +
uint8min : the minimum value of the support rate, according to enum support_rate.
uint8max : the maximum value of the support rate, according to enum support_rate.
+
+
+
Returns
0 : succeed
+
+otherwise : fail
+ +
+
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__WiFi__Sniffer__APIs.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__WiFi__Sniffer__APIs.html new file mode 100644 index 0000000..a28983e --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__WiFi__Sniffer__APIs.html @@ -0,0 +1,291 @@ + + + + + + +ESP8266_RTOS_SDK: Sniffer APIs + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + +
+ +
+
+ + +
+ +
+ +
+ +
+
Sniffer APIs
+
+
+ +

WiFi sniffer APIs. +More...

+ + + + + +

+Typedefs

typedef void(* wifi_promiscuous_cb_t) (uint8 *buf, uint16 len)
 The RX callback function in the promiscuous mode. More...
 
+ + + + + + + + + + + + + + + + +

+Functions

void wifi_set_promiscuous_rx_cb (wifi_promiscuous_cb_t cb)
 Register the RX callback function in the promiscuous mode. More...
 
uint8 wifi_get_channel (void)
 Get the channel number for sniffer functions. More...
 
bool wifi_set_channel (uint8 channel)
 Set the channel number for sniffer functions. More...
 
bool wifi_promiscuous_set_mac (const uint8_t *address)
 Set the MAC address filter for the sniffer mode. More...
 
void wifi_promiscuous_enable (uint8 promiscuous)
 Enable the promiscuous mode. More...
 
+

Detailed Description

+

WiFi sniffer APIs.

+

Typedef Documentation

+ +
+
+ + + + +
typedef void(* wifi_promiscuous_cb_t) (uint8 *buf, uint16 len)
+
+ +

The RX callback function in the promiscuous mode.

+

Each time a packet is received, the callback function will be called.

+
Parameters
+ + + +
uint8*buf : the data received
uint16len : data length
+
+
+
Returns
null
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + +
uint8 wifi_get_channel (void )
+
+ +

Get the channel number for sniffer functions.

+
Parameters
+ + +
null
+
+
+
Returns
channel number
+ +
+
+ +
+
+ + + + + + + + +
void wifi_promiscuous_enable (uint8 promiscuous)
+
+ +

Enable the promiscuous mode.

+
Attention
1. The promiscuous mode can only be enabled in the ESP8266 station mode. Do not call this API in user_init.
+
+2. When in the promiscuous mode, the ESP8266 station and soft-AP are disabled.
+
+3. Call wifi_station_disconnect to disconnect before enabling the promiscuous mode.
+
+4. Don't call any other APIs when in the promiscuous mode. Call wifi_promiscuous_enable(0) to quit sniffer before calling other APIs.
+
Parameters
+ + +
uint8promiscuous :
    +
  • 0: to disable the promiscuous mode
  • +
  • 1: to enable the promiscuous mode
  • +
+
+
+
+
Returns
null
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_promiscuous_set_mac (const uint8_t * address)
+
+ +

Set the MAC address filter for the sniffer mode.

+
Attention
This filter works only for the current sniffer mode. If users disable and then enable the sniffer mode, and then enable sniffer, they need to set the MAC address filter again.
+
Parameters
+ + +
constuint8_t *address : MAC address
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
bool wifi_set_channel (uint8 channel)
+
+ +

Set the channel number for sniffer functions.

+
Parameters
+ + +
uint8channel : channel number
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
void wifi_set_promiscuous_rx_cb (wifi_promiscuous_cb_t cb)
+
+ +

Register the RX callback function in the promiscuous mode.

+

Each time a packet is received, the registered callback function will be called.

+
Parameters
+ + +
wifi_promiscuous_cb_tcb : callback
+
+
+
Returns
null
+ +
+
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__WiFi__User__IE__APIs.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__WiFi__User__IE__APIs.html new file mode 100644 index 0000000..6c8cf3f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/group__WiFi__User__IE__APIs.html @@ -0,0 +1,277 @@ + + + + + + +ESP8266_RTOS_SDK: User IE APIs + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + +
+ +
+
+ + +
+ +
+ + +
+ +

WiFi User IE APIs. +More...

+ + + + + +

+Typedefs

typedef void(* user_ie_manufacturer_recv_cb_t) (user_ie_type type, const uint8 sa[6], const uint8 m_oui[3], uint8 *ie, uint8 ie_len, sint32 rssi)
 User IE received callback. More...
 
+ + + +

+Enumerations

enum  user_ie_type {
+  USER_IE_BEACON = 0, +USER_IE_PROBE_REQ, +USER_IE_PROBE_RESP, +USER_IE_ASSOC_REQ, +
+  USER_IE_ASSOC_RESP, +USER_IE_MAX +
+ }
 
+ + + + + + + + + + +

+Functions

bool wifi_set_user_ie (bool enable, uint8 *m_oui, user_ie_type type, uint8 *user_ie, uint8 len)
 Set user IE of ESP8266. More...
 
sint32 wifi_register_user_ie_manufacturer_recv_cb (user_ie_manufacturer_recv_cb_t cb)
 Register user IE received callback. More...
 
void wifi_unregister_user_ie_manufacturer_recv_cb (void)
 Unregister user IE received callback. More...
 
+

Detailed Description

+

WiFi User IE APIs.

+

Typedef Documentation

+ +
+
+ + + + +
typedef void(* user_ie_manufacturer_recv_cb_t) (user_ie_type type, const uint8 sa[6], const uint8 m_oui[3], uint8 *ie, uint8 ie_len, sint32 rssi)
+
+ +

User IE received callback.

+
Parameters
+ + + + + + + +
user_ie_typetype : type of user IE.
constuint8 sa[6] : source address of the packet.
constuint8 m_oui[3] : factory tag.
uint8*user_ie : pointer of user IE.
uint8ie_len : length of user IE.
sint32rssi : signal strength.
+
+
+
Returns
null
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + +
sint32 wifi_register_user_ie_manufacturer_recv_cb (user_ie_manufacturer_recv_cb_t cb)
+
+ +

Register user IE received callback.

+
Parameters
+ + +
user_ie_manufacturer_recv_cb_tcb : callback
+
+
+
Returns
0 : succeed
+
+-1 : fail
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
bool wifi_set_user_ie (bool enable,
uint8 * m_oui,
user_ie_type type,
uint8 * user_ie,
uint8 len 
)
+
+ +

Set user IE of ESP8266.

+

The user IE will be added to the target packets of user_ie_type.

+
Parameters
+ + + + + + +
boolenable :
    +
  • true, enable the corresponding user IE function, all parameters below have to be set.
  • +
  • false, disable the corresponding user IE function and release the resource, only the parameter "type" below has to be set.
  • +
+
uint8*m_oui : factory tag, apply for it from Espressif System.
user_ie_typetype : IE type. If it is USER_IE_BEACON, please disable the IE function and enable again to take the configuration effect immediately .
uint8*user_ie : user-defined information elements, need not input the whole 802.11 IE, need only the user-define part.
uint8len : length of user IE, 247 bytes at most.
+
+
+
Returns
true : succeed
+
+false : fail
+ +
+
+ +
+
+ + + + + + + + +
void wifi_unregister_user_ie_manufacturer_recv_cb (void )
+
+ +

Unregister user IE received callback.

+
Parameters
+ + +
null
+
+
+
Returns
null
+ +
+
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/hw__timer_8h_source.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/hw__timer_8h_source.html new file mode 100644 index 0000000..6e2b215 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/hw__timer_8h_source.html @@ -0,0 +1,145 @@ + + + + + + +ESP8266_RTOS_SDK: examples/driver_lib/include/hw_timer.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
hw_timer.h
+
+
+
1 /*
+
2  * ESPRSSIF MIT License
+
3  *
+
4  * Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+
5  *
+
6  * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+
7  * it is free of charge, to any person obtaining a copy of this software and associated
+
8  * documentation files (the "Software"), to deal in the Software without restriction, including
+
9  * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+
10  * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
+
11  * to do so, subject to the following conditions:
+
12  *
+
13  * The above copyright notice and this permission notice shall be included in all copies or
+
14  * substantial portions of the Software.
+
15  *
+
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
22  *
+
23  */
+
24 
+
25 #ifndef __HW_TIMER_H__
+
26 #define __HW_TIMER_H__
+
27 
+
28 #ifdef __cplusplus
+
29 extern "C" {
+
30 #endif
+
31 
+
59 void hw_timer_init(uint8 req);
+
60 
+
70 void hw_timer_arm(uint32 val);
+
71 
+
83 void hw_timer_set_func(void (* user_hw_timer_cb_set)(void));
+
84 
+
93 #ifdef __cplusplus
+
94 }
+
95 #endif
+
96 
+
97 #endif
+
void hw_timer_set_func(void(*user_hw_timer_cb_set)(void))
Set timer callback function.
+
void hw_timer_arm(uint32 val)
Set a trigger timer delay to enable this timer.
+
void hw_timer_init(uint8 req)
Initialize the hardware ISR timer.
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/index.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/index.html new file mode 100644 index 0000000..0d63e09 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/index.html @@ -0,0 +1,151 @@ + + + + + + +ESP8266_RTOS_SDK: ESP8266_RTOS_SDK + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + +
+ +
+
+ + +
+ +
+ +
+
+
ESP8266_RTOS_SDK
+
+
+
    +
  • Misc APIs : misc APIs
  • +
  • WiFi APIs : WiFi related APIs
      +
    • SoftAP APIs : ESP8266 Soft-AP APIs
    • +
    • Station APIs : ESP8266 station APIs
    • +
    • Common APIs : WiFi common APIs
    • +
    • Force Sleep APIs : WiFi Force Sleep APIs
    • +
    • Rate Control APIs : WiFi Rate Control APIs
    • +
    • User IE APIs : WiFi User IE APIs
    • +
    • Sniffer APIs : WiFi sniffer APIs
    • +
    • WPS APIs : WiFi WPS APIs
    • +
    • Smartconfig APIs : SmartConfig APIs
    • +
    • AirKiss APIs : AirKiss APIs
    • +
    +
  • +
  • Spiffs APIs : Spiffs APIs
  • +
  • SSC APIs : Simple Serial Command APIs
  • +
  • System APIs : System APIs
      +
    • Boot APIs : Boot mode APIs
    • +
    • Upgrade APIs : Firmware upgrade (FOTA) APIs
    • +
    +
  • +
  • Software timer APIs : Software timer APIs
  • +
  • Network Espconn APIs : Network espconn APIs
  • +
  • ESP-NOW APIs : ESP-NOW APIs
  • +
  • Mesh APIs : Mesh APIs
  • +
  • Driver APIs : Driver APIs
      +
    • PWM Driver APIs : PWM driver APIs
    • +
    • UART Driver APIs : UART driver APIs
    • +
    • GPIO Driver APIs : GPIO driver APIs
    • +
    • SPI Driver APIs : SPI Flash APIs
    • +
    • Hardware timer APIs : Hardware timer APIs
    • +
    +
  • +
+

void user_init(void) is the entrance function of the application.

Attention
1. It is recommended that users set the timer to the periodic mode for periodic checks.
+
+(1). In freeRTOS timer or os_timer, do not delay by while(1) or in the manner that will block the thread.
+
+(2). The timer callback should not occupy CPU more than 15ms.
+
+(3). os_timer_t should not define a local variable, it has to be global varialbe or memory got by malloc.
+
+2. Since esp_iot_rtos_sdk_v1.0.4, functions are stored in CACHE by default, need not be added ICACHE_FLASH_ATTR any more. The interrupt functions can also be stored in CACHE. If users want to store some frequently called functions in RAM, please add IRAM_ATTR before functions' name.
+
+3. Network programming use socket, please do not bind to the same port.
+
+(1). If users want to create 3 or more than 3 TCP connections, please add "TCP_WND = 2 x TCP_MSS;" in "user_init".
+
+4. Priority of the RTOS SDK is 15. xTaskCreate is an interface of freeRTOS. For details of the freeRTOS and APIs of the system, please visit http://www.freertos.org
+
+(1). When using xTaskCreate to create a task, the task stack range is [176, 512].
+
+(2). If an array whose length is over 60 bytes is used in a task, it is suggested that users use malloc and free rather than local variable to allocate array. Large local variables could lead to task stack overflow.
+
+(3). The RTOS SDK takes some priorities. Priority of the pp task is 13; priority of precise timer(ms) thread is 12; priority of the TCP/IP task is 10; priority of the freeRTOS timer is 2; priority of the idle task is 0.
+
+(4). Users can use tasks with priorities from 1 to 9.
+
+(5). Do not revise FreeRTOSConfig.h, configurations are decided by source code inside the RTOS SDK, users can not change it.
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/jquery.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/jquery.js new file mode 100644 index 0000000..1f4d0b4 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/jquery.js @@ -0,0 +1,68 @@ +/*! + * jQuery JavaScript Library v1.7.1 + * http://jquery.com/ + * + * Copyright 2011, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Mon Nov 21 21:11:03 2011 -0500 + */ +(function(bb,L){var av=bb.document,bu=bb.navigator,bl=bb.location;var b=(function(){var bF=function(b0,b1){return new bF.fn.init(b0,b1,bD)},bU=bb.jQuery,bH=bb.$,bD,bY=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,bM=/\S/,bI=/^\s+/,bE=/\s+$/,bA=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,bN=/^[\],:{}\s]*$/,bW=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,bP=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,bJ=/(?:^|:|,)(?:\s*\[)+/g,by=/(webkit)[ \/]([\w.]+)/,bR=/(opera)(?:.*version)?[ \/]([\w.]+)/,bQ=/(msie) ([\w.]+)/,bS=/(mozilla)(?:.*? rv:([\w.]+))?/,bB=/-([a-z]|[0-9])/ig,bZ=/^-ms-/,bT=function(b0,b1){return(b1+"").toUpperCase()},bX=bu.userAgent,bV,bC,e,bL=Object.prototype.toString,bG=Object.prototype.hasOwnProperty,bz=Array.prototype.push,bK=Array.prototype.slice,bO=String.prototype.trim,bv=Array.prototype.indexOf,bx={};bF.fn=bF.prototype={constructor:bF,init:function(b0,b4,b3){var b2,b5,b1,b6;if(!b0){return this}if(b0.nodeType){this.context=this[0]=b0;this.length=1;return this}if(b0==="body"&&!b4&&av.body){this.context=av;this[0]=av.body;this.selector=b0;this.length=1;return this}if(typeof b0==="string"){if(b0.charAt(0)==="<"&&b0.charAt(b0.length-1)===">"&&b0.length>=3){b2=[null,b0,null]}else{b2=bY.exec(b0)}if(b2&&(b2[1]||!b4)){if(b2[1]){b4=b4 instanceof bF?b4[0]:b4;b6=(b4?b4.ownerDocument||b4:av);b1=bA.exec(b0);if(b1){if(bF.isPlainObject(b4)){b0=[av.createElement(b1[1])];bF.fn.attr.call(b0,b4,true)}else{b0=[b6.createElement(b1[1])]}}else{b1=bF.buildFragment([b2[1]],[b6]);b0=(b1.cacheable?bF.clone(b1.fragment):b1.fragment).childNodes}return bF.merge(this,b0)}else{b5=av.getElementById(b2[2]);if(b5&&b5.parentNode){if(b5.id!==b2[2]){return b3.find(b0)}this.length=1;this[0]=b5}this.context=av;this.selector=b0;return this}}else{if(!b4||b4.jquery){return(b4||b3).find(b0)}else{return this.constructor(b4).find(b0)}}}else{if(bF.isFunction(b0)){return b3.ready(b0)}}if(b0.selector!==L){this.selector=b0.selector;this.context=b0.context}return bF.makeArray(b0,this)},selector:"",jquery:"1.7.1",length:0,size:function(){return this.length},toArray:function(){return bK.call(this,0)},get:function(b0){return b0==null?this.toArray():(b0<0?this[this.length+b0]:this[b0])},pushStack:function(b1,b3,b0){var b2=this.constructor();if(bF.isArray(b1)){bz.apply(b2,b1)}else{bF.merge(b2,b1)}b2.prevObject=this;b2.context=this.context;if(b3==="find"){b2.selector=this.selector+(this.selector?" ":"")+b0}else{if(b3){b2.selector=this.selector+"."+b3+"("+b0+")"}}return b2},each:function(b1,b0){return bF.each(this,b1,b0)},ready:function(b0){bF.bindReady();bC.add(b0);return this},eq:function(b0){b0=+b0;return b0===-1?this.slice(b0):this.slice(b0,b0+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(bK.apply(this,arguments),"slice",bK.call(arguments).join(","))},map:function(b0){return this.pushStack(bF.map(this,function(b2,b1){return b0.call(b2,b1,b2)}))},end:function(){return this.prevObject||this.constructor(null)},push:bz,sort:[].sort,splice:[].splice};bF.fn.init.prototype=bF.fn;bF.extend=bF.fn.extend=function(){var b9,b2,b0,b1,b6,b7,b5=arguments[0]||{},b4=1,b3=arguments.length,b8=false;if(typeof b5==="boolean"){b8=b5;b5=arguments[1]||{};b4=2}if(typeof b5!=="object"&&!bF.isFunction(b5)){b5={}}if(b3===b4){b5=this;--b4}for(;b40){return}bC.fireWith(av,[bF]);if(bF.fn.trigger){bF(av).trigger("ready").off("ready")}}},bindReady:function(){if(bC){return}bC=bF.Callbacks("once memory");if(av.readyState==="complete"){return setTimeout(bF.ready,1)}if(av.addEventListener){av.addEventListener("DOMContentLoaded",e,false);bb.addEventListener("load",bF.ready,false)}else{if(av.attachEvent){av.attachEvent("onreadystatechange",e);bb.attachEvent("onload",bF.ready);var b0=false;try{b0=bb.frameElement==null}catch(b1){}if(av.documentElement.doScroll&&b0){bw()}}}},isFunction:function(b0){return bF.type(b0)==="function"},isArray:Array.isArray||function(b0){return bF.type(b0)==="array"},isWindow:function(b0){return b0&&typeof b0==="object"&&"setInterval" in b0},isNumeric:function(b0){return !isNaN(parseFloat(b0))&&isFinite(b0)},type:function(b0){return b0==null?String(b0):bx[bL.call(b0)]||"object"},isPlainObject:function(b2){if(!b2||bF.type(b2)!=="object"||b2.nodeType||bF.isWindow(b2)){return false}try{if(b2.constructor&&!bG.call(b2,"constructor")&&!bG.call(b2.constructor.prototype,"isPrototypeOf")){return false}}catch(b1){return false}var b0;for(b0 in b2){}return b0===L||bG.call(b2,b0)},isEmptyObject:function(b1){for(var b0 in b1){return false}return true},error:function(b0){throw new Error(b0)},parseJSON:function(b0){if(typeof b0!=="string"||!b0){return null}b0=bF.trim(b0);if(bb.JSON&&bb.JSON.parse){return bb.JSON.parse(b0)}if(bN.test(b0.replace(bW,"@").replace(bP,"]").replace(bJ,""))){return(new Function("return "+b0))()}bF.error("Invalid JSON: "+b0)},parseXML:function(b2){var b0,b1;try{if(bb.DOMParser){b1=new DOMParser();b0=b1.parseFromString(b2,"text/xml")}else{b0=new ActiveXObject("Microsoft.XMLDOM");b0.async="false";b0.loadXML(b2)}}catch(b3){b0=L}if(!b0||!b0.documentElement||b0.getElementsByTagName("parsererror").length){bF.error("Invalid XML: "+b2)}return b0},noop:function(){},globalEval:function(b0){if(b0&&bM.test(b0)){(bb.execScript||function(b1){bb["eval"].call(bb,b1)})(b0)}},camelCase:function(b0){return b0.replace(bZ,"ms-").replace(bB,bT)},nodeName:function(b1,b0){return b1.nodeName&&b1.nodeName.toUpperCase()===b0.toUpperCase()},each:function(b3,b6,b2){var b1,b4=0,b5=b3.length,b0=b5===L||bF.isFunction(b3);if(b2){if(b0){for(b1 in b3){if(b6.apply(b3[b1],b2)===false){break}}}else{for(;b40&&b0[0]&&b0[b1-1])||b1===0||bF.isArray(b0));if(b3){for(;b21?aJ.call(arguments,0):bG;if(!(--bw)){bC.resolveWith(bC,bx)}}}function bz(bF){return function(bG){bB[bF]=arguments.length>1?aJ.call(arguments,0):bG;bC.notifyWith(bE,bB)}}if(e>1){for(;bv
a";bI=bv.getElementsByTagName("*");bF=bv.getElementsByTagName("a")[0];if(!bI||!bI.length||!bF){return{}}bG=av.createElement("select");bx=bG.appendChild(av.createElement("option"));bE=bv.getElementsByTagName("input")[0];bJ={leadingWhitespace:(bv.firstChild.nodeType===3),tbody:!bv.getElementsByTagName("tbody").length,htmlSerialize:!!bv.getElementsByTagName("link").length,style:/top/.test(bF.getAttribute("style")),hrefNormalized:(bF.getAttribute("href")==="/a"),opacity:/^0.55/.test(bF.style.opacity),cssFloat:!!bF.style.cssFloat,checkOn:(bE.value==="on"),optSelected:bx.selected,getSetAttribute:bv.className!=="t",enctype:!!av.createElement("form").enctype,html5Clone:av.createElement("nav").cloneNode(true).outerHTML!=="<:nav>",submitBubbles:true,changeBubbles:true,focusinBubbles:false,deleteExpando:true,noCloneEvent:true,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableMarginRight:true};bE.checked=true;bJ.noCloneChecked=bE.cloneNode(true).checked;bG.disabled=true;bJ.optDisabled=!bx.disabled;try{delete bv.test}catch(bC){bJ.deleteExpando=false}if(!bv.addEventListener&&bv.attachEvent&&bv.fireEvent){bv.attachEvent("onclick",function(){bJ.noCloneEvent=false});bv.cloneNode(true).fireEvent("onclick")}bE=av.createElement("input");bE.value="t";bE.setAttribute("type","radio");bJ.radioValue=bE.value==="t";bE.setAttribute("checked","checked");bv.appendChild(bE);bD=av.createDocumentFragment();bD.appendChild(bv.lastChild);bJ.checkClone=bD.cloneNode(true).cloneNode(true).lastChild.checked;bJ.appendChecked=bE.checked;bD.removeChild(bE);bD.appendChild(bv);bv.innerHTML="";if(bb.getComputedStyle){bA=av.createElement("div");bA.style.width="0";bA.style.marginRight="0";bv.style.width="2px";bv.appendChild(bA);bJ.reliableMarginRight=(parseInt((bb.getComputedStyle(bA,null)||{marginRight:0}).marginRight,10)||0)===0}if(bv.attachEvent){for(by in {submit:1,change:1,focusin:1}){bB="on"+by;bw=(bB in bv);if(!bw){bv.setAttribute(bB,"return;");bw=(typeof bv[bB]==="function")}bJ[by+"Bubbles"]=bw}}bD.removeChild(bv);bD=bG=bx=bA=bv=bE=null;b(function(){var bM,bU,bV,bT,bN,bO,bL,bS,bR,e,bP,bQ=av.getElementsByTagName("body")[0];if(!bQ){return}bL=1;bS="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;";bR="visibility:hidden;border:0;";e="style='"+bS+"border:5px solid #000;padding:0;'";bP="
";bM=av.createElement("div");bM.style.cssText=bR+"width:0;height:0;position:static;top:0;margin-top:"+bL+"px";bQ.insertBefore(bM,bQ.firstChild);bv=av.createElement("div");bM.appendChild(bv);bv.innerHTML="
t
";bz=bv.getElementsByTagName("td");bw=(bz[0].offsetHeight===0);bz[0].style.display="";bz[1].style.display="none";bJ.reliableHiddenOffsets=bw&&(bz[0].offsetHeight===0);bv.innerHTML="";bv.style.width=bv.style.paddingLeft="1px";b.boxModel=bJ.boxModel=bv.offsetWidth===2;if(typeof bv.style.zoom!=="undefined"){bv.style.display="inline";bv.style.zoom=1;bJ.inlineBlockNeedsLayout=(bv.offsetWidth===2);bv.style.display="";bv.innerHTML="
";bJ.shrinkWrapBlocks=(bv.offsetWidth!==2)}bv.style.cssText=bS+bR;bv.innerHTML=bP;bU=bv.firstChild;bV=bU.firstChild;bN=bU.nextSibling.firstChild.firstChild;bO={doesNotAddBorder:(bV.offsetTop!==5),doesAddBorderForTableAndCells:(bN.offsetTop===5)};bV.style.position="fixed";bV.style.top="20px";bO.fixedPosition=(bV.offsetTop===20||bV.offsetTop===15);bV.style.position=bV.style.top="";bU.style.overflow="hidden";bU.style.position="relative";bO.subtractsBorderForOverflowNotVisible=(bV.offsetTop===-5);bO.doesNotIncludeMarginInBodyOffset=(bQ.offsetTop!==bL);bQ.removeChild(bM);bv=bM=null;b.extend(bJ,bO)});return bJ})();var aS=/^(?:\{.*\}|\[.*\])$/,aA=/([A-Z])/g;b.extend({cache:{},uuid:0,expando:"jQuery"+(b.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},hasData:function(e){e=e.nodeType?b.cache[e[b.expando]]:e[b.expando];return !!e&&!S(e)},data:function(bx,bv,bz,by){if(!b.acceptData(bx)){return}var bG,bA,bD,bE=b.expando,bC=typeof bv==="string",bF=bx.nodeType,e=bF?b.cache:bx,bw=bF?bx[bE]:bx[bE]&&bE,bB=bv==="events";if((!bw||!e[bw]||(!bB&&!by&&!e[bw].data))&&bC&&bz===L){return}if(!bw){if(bF){bx[bE]=bw=++b.uuid}else{bw=bE}}if(!e[bw]){e[bw]={};if(!bF){e[bw].toJSON=b.noop}}if(typeof bv==="object"||typeof bv==="function"){if(by){e[bw]=b.extend(e[bw],bv)}else{e[bw].data=b.extend(e[bw].data,bv)}}bG=bA=e[bw];if(!by){if(!bA.data){bA.data={}}bA=bA.data}if(bz!==L){bA[b.camelCase(bv)]=bz}if(bB&&!bA[bv]){return bG.events}if(bC){bD=bA[bv];if(bD==null){bD=bA[b.camelCase(bv)]}}else{bD=bA}return bD},removeData:function(bx,bv,by){if(!b.acceptData(bx)){return}var bB,bA,bz,bC=b.expando,bD=bx.nodeType,e=bD?b.cache:bx,bw=bD?bx[bC]:bC;if(!e[bw]){return}if(bv){bB=by?e[bw]:e[bw].data;if(bB){if(!b.isArray(bv)){if(bv in bB){bv=[bv]}else{bv=b.camelCase(bv);if(bv in bB){bv=[bv]}else{bv=bv.split(" ")}}}for(bA=0,bz=bv.length;bA-1){return true}}return false},val:function(bx){var e,bv,by,bw=this[0];if(!arguments.length){if(bw){e=b.valHooks[bw.nodeName.toLowerCase()]||b.valHooks[bw.type];if(e&&"get" in e&&(bv=e.get(bw,"value"))!==L){return bv}bv=bw.value;return typeof bv==="string"?bv.replace(aU,""):bv==null?"":bv}return}by=b.isFunction(bx);return this.each(function(bA){var bz=b(this),bB;if(this.nodeType!==1){return}if(by){bB=bx.call(this,bA,bz.val())}else{bB=bx}if(bB==null){bB=""}else{if(typeof bB==="number"){bB+=""}else{if(b.isArray(bB)){bB=b.map(bB,function(bC){return bC==null?"":bC+""})}}}e=b.valHooks[this.nodeName.toLowerCase()]||b.valHooks[this.type];if(!e||!("set" in e)||e.set(this,bB,"value")===L){this.value=bB}})}});b.extend({valHooks:{option:{get:function(e){var bv=e.attributes.value;return !bv||bv.specified?e.value:e.text}},select:{get:function(e){var bA,bv,bz,bx,by=e.selectedIndex,bB=[],bC=e.options,bw=e.type==="select-one";if(by<0){return null}bv=bw?by:0;bz=bw?by+1:bC.length;for(;bv=0});if(!e.length){bv.selectedIndex=-1}return e}}},attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(bA,bx,bB,bz){var bw,e,by,bv=bA.nodeType;if(!bA||bv===3||bv===8||bv===2){return}if(bz&&bx in b.attrFn){return b(bA)[bx](bB)}if(typeof bA.getAttribute==="undefined"){return b.prop(bA,bx,bB)}by=bv!==1||!b.isXMLDoc(bA);if(by){bx=bx.toLowerCase();e=b.attrHooks[bx]||(ao.test(bx)?aY:be)}if(bB!==L){if(bB===null){b.removeAttr(bA,bx);return}else{if(e&&"set" in e&&by&&(bw=e.set(bA,bB,bx))!==L){return bw}else{bA.setAttribute(bx,""+bB);return bB}}}else{if(e&&"get" in e&&by&&(bw=e.get(bA,bx))!==null){return bw}else{bw=bA.getAttribute(bx);return bw===null?L:bw}}},removeAttr:function(bx,bz){var by,bA,bv,e,bw=0;if(bz&&bx.nodeType===1){bA=bz.toLowerCase().split(af);e=bA.length;for(;bw=0)}}})});var bd=/^(?:textarea|input|select)$/i,n=/^([^\.]*)?(?:\.(.+))?$/,J=/\bhover(\.\S+)?\b/,aO=/^key/,bf=/^(?:mouse|contextmenu)|click/,T=/^(?:focusinfocus|focusoutblur)$/,U=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,Y=function(e){var bv=U.exec(e);if(bv){bv[1]=(bv[1]||"").toLowerCase();bv[3]=bv[3]&&new RegExp("(?:^|\\s)"+bv[3]+"(?:\\s|$)")}return bv},j=function(bw,e){var bv=bw.attributes||{};return((!e[1]||bw.nodeName.toLowerCase()===e[1])&&(!e[2]||(bv.id||{}).value===e[2])&&(!e[3]||e[3].test((bv["class"]||{}).value)))},bt=function(e){return b.event.special.hover?e:e.replace(J,"mouseenter$1 mouseleave$1")};b.event={add:function(bx,bC,bJ,bA,by){var bD,bB,bK,bI,bH,bF,e,bG,bv,bz,bw,bE;if(bx.nodeType===3||bx.nodeType===8||!bC||!bJ||!(bD=b._data(bx))){return}if(bJ.handler){bv=bJ;bJ=bv.handler}if(!bJ.guid){bJ.guid=b.guid++}bK=bD.events;if(!bK){bD.events=bK={}}bB=bD.handle;if(!bB){bD.handle=bB=function(bL){return typeof b!=="undefined"&&(!bL||b.event.triggered!==bL.type)?b.event.dispatch.apply(bB.elem,arguments):L};bB.elem=bx}bC=b.trim(bt(bC)).split(" ");for(bI=0;bI=0){bG=bG.slice(0,-1);bw=true}if(bG.indexOf(".")>=0){bx=bG.split(".");bG=bx.shift();bx.sort()}if((!bA||b.event.customEvent[bG])&&!b.event.global[bG]){return}bv=typeof bv==="object"?bv[b.expando]?bv:new b.Event(bG,bv):new b.Event(bG);bv.type=bG;bv.isTrigger=true;bv.exclusive=bw;bv.namespace=bx.join(".");bv.namespace_re=bv.namespace?new RegExp("(^|\\.)"+bx.join("\\.(?:.*\\.)?")+"(\\.|$)"):null;by=bG.indexOf(":")<0?"on"+bG:"";if(!bA){e=b.cache;for(bC in e){if(e[bC].events&&e[bC].events[bG]){b.event.trigger(bv,bD,e[bC].handle.elem,true)}}return}bv.result=L;if(!bv.target){bv.target=bA}bD=bD!=null?b.makeArray(bD):[];bD.unshift(bv);bF=b.event.special[bG]||{};if(bF.trigger&&bF.trigger.apply(bA,bD)===false){return}bB=[[bA,bF.bindType||bG]];if(!bJ&&!bF.noBubble&&!b.isWindow(bA)){bI=bF.delegateType||bG;bH=T.test(bI+bG)?bA:bA.parentNode;bz=null;for(;bH;bH=bH.parentNode){bB.push([bH,bI]);bz=bH}if(bz&&bz===bA.ownerDocument){bB.push([bz.defaultView||bz.parentWindow||bb,bI])}}for(bC=0;bCbA){bH.push({elem:this,matches:bz.slice(bA)})}for(bC=0;bC0?this.on(e,null,bx,bw):this.trigger(e)};if(b.attrFn){b.attrFn[e]=true}if(aO.test(e)){b.event.fixHooks[e]=b.event.keyHooks}if(bf.test(e)){b.event.fixHooks[e]=b.event.mouseHooks}}); +/*! + * Sizzle CSS Selector Engine + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){var bH=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,bC="sizcache"+(Math.random()+"").replace(".",""),bI=0,bL=Object.prototype.toString,bB=false,bA=true,bK=/\\/g,bO=/\r\n/g,bQ=/\W/;[0,0].sort(function(){bA=false;return 0});var by=function(bV,e,bY,bZ){bY=bY||[];e=e||av;var b1=e;if(e.nodeType!==1&&e.nodeType!==9){return[]}if(!bV||typeof bV!=="string"){return bY}var bS,b3,b6,bR,b2,b5,b4,bX,bU=true,bT=by.isXML(e),bW=[],b0=bV;do{bH.exec("");bS=bH.exec(b0);if(bS){b0=bS[3];bW.push(bS[1]);if(bS[2]){bR=bS[3];break}}}while(bS);if(bW.length>1&&bD.exec(bV)){if(bW.length===2&&bE.relative[bW[0]]){b3=bM(bW[0]+bW[1],e,bZ)}else{b3=bE.relative[bW[0]]?[e]:by(bW.shift(),e);while(bW.length){bV=bW.shift();if(bE.relative[bV]){bV+=bW.shift()}b3=bM(bV,b3,bZ)}}}else{if(!bZ&&bW.length>1&&e.nodeType===9&&!bT&&bE.match.ID.test(bW[0])&&!bE.match.ID.test(bW[bW.length-1])){b2=by.find(bW.shift(),e,bT);e=b2.expr?by.filter(b2.expr,b2.set)[0]:b2.set[0]}if(e){b2=bZ?{expr:bW.pop(),set:bF(bZ)}:by.find(bW.pop(),bW.length===1&&(bW[0]==="~"||bW[0]==="+")&&e.parentNode?e.parentNode:e,bT);b3=b2.expr?by.filter(b2.expr,b2.set):b2.set;if(bW.length>0){b6=bF(b3)}else{bU=false}while(bW.length){b5=bW.pop();b4=b5;if(!bE.relative[b5]){b5=""}else{b4=bW.pop()}if(b4==null){b4=e}bE.relative[b5](b6,b4,bT)}}else{b6=bW=[]}}if(!b6){b6=b3}if(!b6){by.error(b5||bV)}if(bL.call(b6)==="[object Array]"){if(!bU){bY.push.apply(bY,b6)}else{if(e&&e.nodeType===1){for(bX=0;b6[bX]!=null;bX++){if(b6[bX]&&(b6[bX]===true||b6[bX].nodeType===1&&by.contains(e,b6[bX]))){bY.push(b3[bX])}}}else{for(bX=0;b6[bX]!=null;bX++){if(b6[bX]&&b6[bX].nodeType===1){bY.push(b3[bX])}}}}}else{bF(b6,bY)}if(bR){by(bR,b1,bY,bZ);by.uniqueSort(bY)}return bY};by.uniqueSort=function(bR){if(bJ){bB=bA;bR.sort(bJ);if(bB){for(var e=1;e0};by.find=function(bX,e,bY){var bW,bS,bU,bT,bV,bR;if(!bX){return[]}for(bS=0,bU=bE.order.length;bS":function(bW,bR){var bV,bU=typeof bR==="string",bS=0,e=bW.length;if(bU&&!bQ.test(bR)){bR=bR.toLowerCase();for(;bS=0)){if(!bS){e.push(bV)}}else{if(bS){bR[bU]=false}}}}return false},ID:function(e){return e[1].replace(bK,"")},TAG:function(bR,e){return bR[1].replace(bK,"").toLowerCase()},CHILD:function(e){if(e[1]==="nth"){if(!e[2]){by.error(e[0])}e[2]=e[2].replace(/^\+|\s*/g,"");var bR=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(e[2]==="even"&&"2n"||e[2]==="odd"&&"2n+1"||!/\D/.test(e[2])&&"0n+"+e[2]||e[2]);e[2]=(bR[1]+(bR[2]||1))-0;e[3]=bR[3]-0}else{if(e[2]){by.error(e[0])}}e[0]=bI++;return e},ATTR:function(bU,bR,bS,e,bV,bW){var bT=bU[1]=bU[1].replace(bK,"");if(!bW&&bE.attrMap[bT]){bU[1]=bE.attrMap[bT]}bU[4]=(bU[4]||bU[5]||"").replace(bK,"");if(bU[2]==="~="){bU[4]=" "+bU[4]+" "}return bU},PSEUDO:function(bU,bR,bS,e,bV){if(bU[1]==="not"){if((bH.exec(bU[3])||"").length>1||/^\w/.test(bU[3])){bU[3]=by(bU[3],null,null,bR)}else{var bT=by.filter(bU[3],bR,bS,true^bV);if(!bS){e.push.apply(e,bT)}return false}}else{if(bE.match.POS.test(bU[0])||bE.match.CHILD.test(bU[0])){return true}}return bU},POS:function(e){e.unshift(true);return e}},filters:{enabled:function(e){return e.disabled===false&&e.type!=="hidden"},disabled:function(e){return e.disabled===true},checked:function(e){return e.checked===true},selected:function(e){if(e.parentNode){e.parentNode.selectedIndex}return e.selected===true},parent:function(e){return !!e.firstChild},empty:function(e){return !e.firstChild},has:function(bS,bR,e){return !!by(e[3],bS).length},header:function(e){return(/h\d/i).test(e.nodeName)},text:function(bS){var e=bS.getAttribute("type"),bR=bS.type;return bS.nodeName.toLowerCase()==="input"&&"text"===bR&&(e===bR||e===null)},radio:function(e){return e.nodeName.toLowerCase()==="input"&&"radio"===e.type},checkbox:function(e){return e.nodeName.toLowerCase()==="input"&&"checkbox"===e.type},file:function(e){return e.nodeName.toLowerCase()==="input"&&"file"===e.type},password:function(e){return e.nodeName.toLowerCase()==="input"&&"password"===e.type},submit:function(bR){var e=bR.nodeName.toLowerCase();return(e==="input"||e==="button")&&"submit"===bR.type},image:function(e){return e.nodeName.toLowerCase()==="input"&&"image"===e.type},reset:function(bR){var e=bR.nodeName.toLowerCase();return(e==="input"||e==="button")&&"reset"===bR.type},button:function(bR){var e=bR.nodeName.toLowerCase();return e==="input"&&"button"===bR.type||e==="button"},input:function(e){return(/input|select|textarea|button/i).test(e.nodeName)},focus:function(e){return e===e.ownerDocument.activeElement}},setFilters:{first:function(bR,e){return e===0},last:function(bS,bR,e,bT){return bR===bT.length-1},even:function(bR,e){return e%2===0},odd:function(bR,e){return e%2===1},lt:function(bS,bR,e){return bRe[3]-0},nth:function(bS,bR,e){return e[3]-0===bR},eq:function(bS,bR,e){return e[3]-0===bR}},filter:{PSEUDO:function(bS,bX,bW,bY){var e=bX[1],bR=bE.filters[e];if(bR){return bR(bS,bW,bX,bY)}else{if(e==="contains"){return(bS.textContent||bS.innerText||bw([bS])||"").indexOf(bX[3])>=0}else{if(e==="not"){var bT=bX[3];for(var bV=0,bU=bT.length;bV=0)}}},ID:function(bR,e){return bR.nodeType===1&&bR.getAttribute("id")===e},TAG:function(bR,e){return(e==="*"&&bR.nodeType===1)||!!bR.nodeName&&bR.nodeName.toLowerCase()===e},CLASS:function(bR,e){return(" "+(bR.className||bR.getAttribute("class"))+" ").indexOf(e)>-1},ATTR:function(bV,bT){var bS=bT[1],e=by.attr?by.attr(bV,bS):bE.attrHandle[bS]?bE.attrHandle[bS](bV):bV[bS]!=null?bV[bS]:bV.getAttribute(bS),bW=e+"",bU=bT[2],bR=bT[4];return e==null?bU==="!=":!bU&&by.attr?e!=null:bU==="="?bW===bR:bU==="*="?bW.indexOf(bR)>=0:bU==="~="?(" "+bW+" ").indexOf(bR)>=0:!bR?bW&&e!==false:bU==="!="?bW!==bR:bU==="^="?bW.indexOf(bR)===0:bU==="$="?bW.substr(bW.length-bR.length)===bR:bU==="|="?bW===bR||bW.substr(0,bR.length+1)===bR+"-":false},POS:function(bU,bR,bS,bV){var e=bR[2],bT=bE.setFilters[e];if(bT){return bT(bU,bS,bR,bV)}}}};var bD=bE.match.POS,bx=function(bR,e){return"\\"+(e-0+1)};for(var bz in bE.match){bE.match[bz]=new RegExp(bE.match[bz].source+(/(?![^\[]*\])(?![^\(]*\))/.source));bE.leftMatch[bz]=new RegExp(/(^(?:.|\r|\n)*?)/.source+bE.match[bz].source.replace(/\\(\d+)/g,bx))}var bF=function(bR,e){bR=Array.prototype.slice.call(bR,0);if(e){e.push.apply(e,bR);return e}return bR};try{Array.prototype.slice.call(av.documentElement.childNodes,0)[0].nodeType}catch(bP){bF=function(bU,bT){var bS=0,bR=bT||[];if(bL.call(bU)==="[object Array]"){Array.prototype.push.apply(bR,bU)}else{if(typeof bU.length==="number"){for(var e=bU.length;bS";e.insertBefore(bR,e.firstChild);if(av.getElementById(bS)){bE.find.ID=function(bU,bV,bW){if(typeof bV.getElementById!=="undefined"&&!bW){var bT=bV.getElementById(bU[1]);return bT?bT.id===bU[1]||typeof bT.getAttributeNode!=="undefined"&&bT.getAttributeNode("id").nodeValue===bU[1]?[bT]:L:[]}};bE.filter.ID=function(bV,bT){var bU=typeof bV.getAttributeNode!=="undefined"&&bV.getAttributeNode("id");return bV.nodeType===1&&bU&&bU.nodeValue===bT}}e.removeChild(bR);e=bR=null})();(function(){var e=av.createElement("div");e.appendChild(av.createComment(""));if(e.getElementsByTagName("*").length>0){bE.find.TAG=function(bR,bV){var bU=bV.getElementsByTagName(bR[1]);if(bR[1]==="*"){var bT=[];for(var bS=0;bU[bS];bS++){if(bU[bS].nodeType===1){bT.push(bU[bS])}}bU=bT}return bU}}e.innerHTML="";if(e.firstChild&&typeof e.firstChild.getAttribute!=="undefined"&&e.firstChild.getAttribute("href")!=="#"){bE.attrHandle.href=function(bR){return bR.getAttribute("href",2)}}e=null})();if(av.querySelectorAll){(function(){var e=by,bT=av.createElement("div"),bS="__sizzle__";bT.innerHTML="

";if(bT.querySelectorAll&&bT.querySelectorAll(".TEST").length===0){return}by=function(b4,bV,bZ,b3){bV=bV||av;if(!b3&&!by.isXML(bV)){var b2=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b4);if(b2&&(bV.nodeType===1||bV.nodeType===9)){if(b2[1]){return bF(bV.getElementsByTagName(b4),bZ)}else{if(b2[2]&&bE.find.CLASS&&bV.getElementsByClassName){return bF(bV.getElementsByClassName(b2[2]),bZ)}}}if(bV.nodeType===9){if(b4==="body"&&bV.body){return bF([bV.body],bZ)}else{if(b2&&b2[3]){var bY=bV.getElementById(b2[3]);if(bY&&bY.parentNode){if(bY.id===b2[3]){return bF([bY],bZ)}}else{return bF([],bZ)}}}try{return bF(bV.querySelectorAll(b4),bZ)}catch(b0){}}else{if(bV.nodeType===1&&bV.nodeName.toLowerCase()!=="object"){var bW=bV,bX=bV.getAttribute("id"),bU=bX||bS,b6=bV.parentNode,b5=/^\s*[+~]/.test(b4);if(!bX){bV.setAttribute("id",bU)}else{bU=bU.replace(/'/g,"\\$&")}if(b5&&b6){bV=bV.parentNode}try{if(!b5||b6){return bF(bV.querySelectorAll("[id='"+bU+"'] "+b4),bZ)}}catch(b1){}finally{if(!bX){bW.removeAttribute("id")}}}}}return e(b4,bV,bZ,b3)};for(var bR in e){by[bR]=e[bR]}bT=null})()}(function(){var e=av.documentElement,bS=e.matchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.msMatchesSelector;if(bS){var bU=!bS.call(av.createElement("div"),"div"),bR=false;try{bS.call(av.documentElement,"[test!='']:sizzle")}catch(bT){bR=true}by.matchesSelector=function(bW,bY){bY=bY.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!by.isXML(bW)){try{if(bR||!bE.match.PSEUDO.test(bY)&&!/!=/.test(bY)){var bV=bS.call(bW,bY);if(bV||!bU||bW.document&&bW.document.nodeType!==11){return bV}}}catch(bX){}}return by(bY,null,null,[bW]).length>0}}})();(function(){var e=av.createElement("div");e.innerHTML="
";if(!e.getElementsByClassName||e.getElementsByClassName("e").length===0){return}e.lastChild.className="e";if(e.getElementsByClassName("e").length===1){return}bE.order.splice(1,0,"CLASS");bE.find.CLASS=function(bR,bS,bT){if(typeof bS.getElementsByClassName!=="undefined"&&!bT){return bS.getElementsByClassName(bR[1])}};e=null})();function bv(bR,bW,bV,bZ,bX,bY){for(var bT=0,bS=bZ.length;bT0){bU=e;break}}}e=e[bR]}bZ[bT]=bU}}}if(av.documentElement.contains){by.contains=function(bR,e){return bR!==e&&(bR.contains?bR.contains(e):true)}}else{if(av.documentElement.compareDocumentPosition){by.contains=function(bR,e){return !!(bR.compareDocumentPosition(e)&16)}}else{by.contains=function(){return false}}}by.isXML=function(e){var bR=(e?e.ownerDocument||e:0).documentElement;return bR?bR.nodeName!=="HTML":false};var bM=function(bS,e,bW){var bV,bX=[],bU="",bY=e.nodeType?[e]:e;while((bV=bE.match.PSEUDO.exec(bS))){bU+=bV[0];bS=bS.replace(bE.match.PSEUDO,"")}bS=bE.relative[bS]?bS+"*":bS;for(var bT=0,bR=bY.length;bT0){for(bB=bA;bB=0:b.filter(e,this).length>0:this.filter(e).length>0)},closest:function(by,bx){var bv=[],bw,e,bz=this[0];if(b.isArray(by)){var bB=1;while(bz&&bz.ownerDocument&&bz!==bx){for(bw=0;bw-1:b.find.matchesSelector(bz,by)){bv.push(bz);break}else{bz=bz.parentNode;if(!bz||!bz.ownerDocument||bz===bx||bz.nodeType===11){break}}}}bv=bv.length>1?b.unique(bv):bv;return this.pushStack(bv,"closest",by)},index:function(e){if(!e){return(this[0]&&this[0].parentNode)?this.prevAll().length:-1}if(typeof e==="string"){return b.inArray(this[0],b(e))}return b.inArray(e.jquery?e[0]:e,this)},add:function(e,bv){var bx=typeof e==="string"?b(e,bv):b.makeArray(e&&e.nodeType?[e]:e),bw=b.merge(this.get(),bx);return this.pushStack(C(bx[0])||C(bw[0])?bw:b.unique(bw))},andSelf:function(){return this.add(this.prevObject)}});function C(e){return !e||!e.parentNode||e.parentNode.nodeType===11}b.each({parent:function(bv){var e=bv.parentNode;return e&&e.nodeType!==11?e:null},parents:function(e){return b.dir(e,"parentNode")},parentsUntil:function(bv,e,bw){return b.dir(bv,"parentNode",bw)},next:function(e){return b.nth(e,2,"nextSibling")},prev:function(e){return b.nth(e,2,"previousSibling")},nextAll:function(e){return b.dir(e,"nextSibling")},prevAll:function(e){return b.dir(e,"previousSibling")},nextUntil:function(bv,e,bw){return b.dir(bv,"nextSibling",bw)},prevUntil:function(bv,e,bw){return b.dir(bv,"previousSibling",bw)},siblings:function(e){return b.sibling(e.parentNode.firstChild,e)},children:function(e){return b.sibling(e.firstChild)},contents:function(e){return b.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:b.makeArray(e.childNodes)}},function(e,bv){b.fn[e]=function(by,bw){var bx=b.map(this,bv,by);if(!ab.test(e)){bw=by}if(bw&&typeof bw==="string"){bx=b.filter(bw,bx)}bx=this.length>1&&!ay[e]?b.unique(bx):bx;if((this.length>1||a9.test(bw))&&aq.test(e)){bx=bx.reverse()}return this.pushStack(bx,e,P.call(arguments).join(","))}});b.extend({filter:function(bw,e,bv){if(bv){bw=":not("+bw+")"}return e.length===1?b.find.matchesSelector(e[0],bw)?[e[0]]:[]:b.find.matches(bw,e)},dir:function(bw,bv,by){var e=[],bx=bw[bv];while(bx&&bx.nodeType!==9&&(by===L||bx.nodeType!==1||!b(bx).is(by))){if(bx.nodeType===1){e.push(bx)}bx=bx[bv]}return e},nth:function(by,e,bw,bx){e=e||1;var bv=0;for(;by;by=by[bw]){if(by.nodeType===1&&++bv===e){break}}return by},sibling:function(bw,bv){var e=[];for(;bw;bw=bw.nextSibling){if(bw.nodeType===1&&bw!==bv){e.push(bw)}}return e}});function aG(bx,bw,e){bw=bw||0;if(b.isFunction(bw)){return b.grep(bx,function(bz,by){var bA=!!bw.call(bz,by,bz);return bA===e})}else{if(bw.nodeType){return b.grep(bx,function(bz,by){return(bz===bw)===e})}else{if(typeof bw==="string"){var bv=b.grep(bx,function(by){return by.nodeType===1});if(bp.test(bw)){return b.filter(bw,bv,!e)}else{bw=b.filter(bw,bv)}}}}return b.grep(bx,function(bz,by){return(b.inArray(bz,bw)>=0)===e})}function a(e){var bw=aR.split("|"),bv=e.createDocumentFragment();if(bv.createElement){while(bw.length){bv.createElement(bw.pop())}}return bv}var aR="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ag=/ jQuery\d+="(?:\d+|null)"/g,ar=/^\s+/,R=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,d=/<([\w:]+)/,w=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},ac=a(av);ax.optgroup=ax.option;ax.tbody=ax.tfoot=ax.colgroup=ax.caption=ax.thead;ax.th=ax.td;if(!b.support.htmlSerialize){ax._default=[1,"div
","
"]}b.fn.extend({text:function(e){if(b.isFunction(e)){return this.each(function(bw){var bv=b(this);bv.text(e.call(this,bw,bv.text()))})}if(typeof e!=="object"&&e!==L){return this.empty().append((this[0]&&this[0].ownerDocument||av).createTextNode(e))}return b.text(this)},wrapAll:function(e){if(b.isFunction(e)){return this.each(function(bw){b(this).wrapAll(e.call(this,bw))})}if(this[0]){var bv=b(e,this[0].ownerDocument).eq(0).clone(true);if(this[0].parentNode){bv.insertBefore(this[0])}bv.map(function(){var bw=this;while(bw.firstChild&&bw.firstChild.nodeType===1){bw=bw.firstChild}return bw}).append(this)}return this},wrapInner:function(e){if(b.isFunction(e)){return this.each(function(bv){b(this).wrapInner(e.call(this,bv))})}return this.each(function(){var bv=b(this),bw=bv.contents();if(bw.length){bw.wrapAll(e)}else{bv.append(e)}})},wrap:function(e){var bv=b.isFunction(e);return this.each(function(bw){b(this).wrapAll(bv?e.call(this,bw):e)})},unwrap:function(){return this.parent().each(function(){if(!b.nodeName(this,"body")){b(this).replaceWith(this.childNodes)}}).end()},append:function(){return this.domManip(arguments,true,function(e){if(this.nodeType===1){this.appendChild(e)}})},prepend:function(){return this.domManip(arguments,true,function(e){if(this.nodeType===1){this.insertBefore(e,this.firstChild)}})},before:function(){if(this[0]&&this[0].parentNode){return this.domManip(arguments,false,function(bv){this.parentNode.insertBefore(bv,this)})}else{if(arguments.length){var e=b.clean(arguments);e.push.apply(e,this.toArray());return this.pushStack(e,"before",arguments)}}},after:function(){if(this[0]&&this[0].parentNode){return this.domManip(arguments,false,function(bv){this.parentNode.insertBefore(bv,this.nextSibling)})}else{if(arguments.length){var e=this.pushStack(this,"after",arguments);e.push.apply(e,b.clean(arguments));return e}}},remove:function(e,bx){for(var bv=0,bw;(bw=this[bv])!=null;bv++){if(!e||b.filter(e,[bw]).length){if(!bx&&bw.nodeType===1){b.cleanData(bw.getElementsByTagName("*"));b.cleanData([bw])}if(bw.parentNode){bw.parentNode.removeChild(bw)}}}return this},empty:function(){for(var e=0,bv;(bv=this[e])!=null;e++){if(bv.nodeType===1){b.cleanData(bv.getElementsByTagName("*"))}while(bv.firstChild){bv.removeChild(bv.firstChild)}}return this},clone:function(bv,e){bv=bv==null?false:bv;e=e==null?bv:e;return this.map(function(){return b.clone(this,bv,e)})},html:function(bx){if(bx===L){return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(ag,""):null}else{if(typeof bx==="string"&&!ae.test(bx)&&(b.support.leadingWhitespace||!ar.test(bx))&&!ax[(d.exec(bx)||["",""])[1].toLowerCase()]){bx=bx.replace(R,"<$1>");try{for(var bw=0,bv=this.length;bw1&&bw0?this.clone(true):this).get();b(bC[bA])[bv](by);bz=bz.concat(by)}return this.pushStack(bz,e,bC.selector)}}});function bg(e){if(typeof e.getElementsByTagName!=="undefined"){return e.getElementsByTagName("*")}else{if(typeof e.querySelectorAll!=="undefined"){return e.querySelectorAll("*")}else{return[]}}}function az(e){if(e.type==="checkbox"||e.type==="radio"){e.defaultChecked=e.checked}}function E(e){var bv=(e.nodeName||"").toLowerCase();if(bv==="input"){az(e)}else{if(bv!=="script"&&typeof e.getElementsByTagName!=="undefined"){b.grep(e.getElementsByTagName("input"),az)}}}function al(e){var bv=av.createElement("div");ac.appendChild(bv);bv.innerHTML=e.outerHTML;return bv.firstChild}b.extend({clone:function(by,bA,bw){var e,bv,bx,bz=b.support.html5Clone||!ah.test("<"+by.nodeName)?by.cloneNode(true):al(by);if((!b.support.noCloneEvent||!b.support.noCloneChecked)&&(by.nodeType===1||by.nodeType===11)&&!b.isXMLDoc(by)){ai(by,bz);e=bg(by);bv=bg(bz);for(bx=0;e[bx];++bx){if(bv[bx]){ai(e[bx],bv[bx])}}}if(bA){t(by,bz);if(bw){e=bg(by);bv=bg(bz);for(bx=0;e[bx];++bx){t(e[bx],bv[bx])}}}e=bv=null;return bz},clean:function(bw,by,bH,bA){var bF;by=by||av;if(typeof by.createElement==="undefined"){by=by.ownerDocument||by[0]&&by[0].ownerDocument||av}var bI=[],bB;for(var bE=0,bz;(bz=bw[bE])!=null;bE++){if(typeof bz==="number"){bz+=""}if(!bz){continue}if(typeof bz==="string"){if(!W.test(bz)){bz=by.createTextNode(bz)}else{bz=bz.replace(R,"<$1>");var bK=(d.exec(bz)||["",""])[1].toLowerCase(),bx=ax[bK]||ax._default,bD=bx[0],bv=by.createElement("div");if(by===av){ac.appendChild(bv)}else{a(by).appendChild(bv)}bv.innerHTML=bx[1]+bz+bx[2];while(bD--){bv=bv.lastChild}if(!b.support.tbody){var e=w.test(bz),bC=bK==="table"&&!e?bv.firstChild&&bv.firstChild.childNodes:bx[1]===""&&!e?bv.childNodes:[];for(bB=bC.length-1;bB>=0;--bB){if(b.nodeName(bC[bB],"tbody")&&!bC[bB].childNodes.length){bC[bB].parentNode.removeChild(bC[bB])}}}if(!b.support.leadingWhitespace&&ar.test(bz)){bv.insertBefore(by.createTextNode(ar.exec(bz)[0]),bv.firstChild)}bz=bv.childNodes}}var bG;if(!b.support.appendChecked){if(bz[0]&&typeof(bG=bz.length)==="number"){for(bB=0;bB=0){return bx+"px"}}else{return bx}}}});if(!b.support.opacity){b.cssHooks.opacity={get:function(bv,e){return au.test((e&&bv.currentStyle?bv.currentStyle.filter:bv.style.filter)||"")?(parseFloat(RegExp.$1)/100)+"":e?"1":""},set:function(by,bz){var bx=by.style,bv=by.currentStyle,e=b.isNumeric(bz)?"alpha(opacity="+bz*100+")":"",bw=bv&&bv.filter||bx.filter||"";bx.zoom=1;if(bz>=1&&b.trim(bw.replace(ak,""))===""){bx.removeAttribute("filter");if(bv&&!bv.filter){return}}bx.filter=ak.test(bw)?bw.replace(ak,e):bw+" "+e}}}b(function(){if(!b.support.reliableMarginRight){b.cssHooks.marginRight={get:function(bw,bv){var e;b.swap(bw,{display:"inline-block"},function(){if(bv){e=Z(bw,"margin-right","marginRight")}else{e=bw.style.marginRight}});return e}}}});if(av.defaultView&&av.defaultView.getComputedStyle){aI=function(by,bw){var bv,bx,e;bw=bw.replace(z,"-$1").toLowerCase();if((bx=by.ownerDocument.defaultView)&&(e=bx.getComputedStyle(by,null))){bv=e.getPropertyValue(bw);if(bv===""&&!b.contains(by.ownerDocument.documentElement,by)){bv=b.style(by,bw)}}return bv}}if(av.documentElement.currentStyle){aX=function(bz,bw){var bA,e,by,bv=bz.currentStyle&&bz.currentStyle[bw],bx=bz.style;if(bv===null&&bx&&(by=bx[bw])){bv=by}if(!bc.test(bv)&&bn.test(bv)){bA=bx.left;e=bz.runtimeStyle&&bz.runtimeStyle.left;if(e){bz.runtimeStyle.left=bz.currentStyle.left}bx.left=bw==="fontSize"?"1em":(bv||0);bv=bx.pixelLeft+"px";bx.left=bA;if(e){bz.runtimeStyle.left=e}}return bv===""?"auto":bv}}Z=aI||aX;function p(by,bw,bv){var bA=bw==="width"?by.offsetWidth:by.offsetHeight,bz=bw==="width"?an:a1,bx=0,e=bz.length;if(bA>0){if(bv!=="border"){for(;bx)<[^<]*)*<\/script>/gi,q=/^(?:select|textarea)/i,h=/\s+/,br=/([?&])_=[^&]*/,K=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,A=b.fn.load,aa={},r={},aE,s,aV=["*/"]+["*"];try{aE=bl.href}catch(aw){aE=av.createElement("a");aE.href="";aE=aE.href}s=K.exec(aE.toLowerCase())||[];function f(e){return function(by,bA){if(typeof by!=="string"){bA=by;by="*"}if(b.isFunction(bA)){var bx=by.toLowerCase().split(h),bw=0,bz=bx.length,bv,bB,bC;for(;bw=0){var e=bw.slice(by,bw.length);bw=bw.slice(0,by)}var bx="GET";if(bz){if(b.isFunction(bz)){bA=bz;bz=L}else{if(typeof bz==="object"){bz=b.param(bz,b.ajaxSettings.traditional);bx="POST"}}}var bv=this;b.ajax({url:bw,type:bx,dataType:"html",data:bz,complete:function(bC,bB,bD){bD=bC.responseText;if(bC.isResolved()){bC.done(function(bE){bD=bE});bv.html(e?b("
").append(bD.replace(a6,"")).find(e):bD)}if(bA){bv.each(bA,[bD,bB,bC])}}});return this},serialize:function(){return b.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?b.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||q.test(this.nodeName)||aZ.test(this.type))}).map(function(e,bv){var bw=b(this).val();return bw==null?null:b.isArray(bw)?b.map(bw,function(by,bx){return{name:bv.name,value:by.replace(bs,"\r\n")}}):{name:bv.name,value:bw.replace(bs,"\r\n")}}).get()}});b.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,bv){b.fn[bv]=function(bw){return this.on(bv,bw)}});b.each(["get","post"],function(e,bv){b[bv]=function(bw,by,bz,bx){if(b.isFunction(by)){bx=bx||bz;bz=by;by=L}return b.ajax({type:bv,url:bw,data:by,success:bz,dataType:bx})}});b.extend({getScript:function(e,bv){return b.get(e,L,bv,"script")},getJSON:function(e,bv,bw){return b.get(e,bv,bw,"json")},ajaxSetup:function(bv,e){if(e){am(bv,b.ajaxSettings)}else{e=bv;bv=b.ajaxSettings}am(bv,e);return bv},ajaxSettings:{url:aE,isLocal:aM.test(s[1]),global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":aV},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":bb.String,"text html":true,"text json":b.parseJSON,"text xml":b.parseXML},flatOptions:{context:true,url:true}},ajaxPrefilter:f(aa),ajaxTransport:f(r),ajax:function(bz,bx){if(typeof bz==="object"){bx=bz;bz=L}bx=bx||{};var bD=b.ajaxSetup({},bx),bS=bD.context||bD,bG=bS!==bD&&(bS.nodeType||bS instanceof b)?b(bS):b.event,bR=b.Deferred(),bN=b.Callbacks("once memory"),bB=bD.statusCode||{},bC,bH={},bO={},bQ,by,bL,bE,bI,bA=0,bw,bK,bJ={readyState:0,setRequestHeader:function(bT,bU){if(!bA){var e=bT.toLowerCase();bT=bO[e]=bO[e]||bT;bH[bT]=bU}return this},getAllResponseHeaders:function(){return bA===2?bQ:null},getResponseHeader:function(bT){var e;if(bA===2){if(!by){by={};while((e=aD.exec(bQ))){by[e[1].toLowerCase()]=e[2]}}e=by[bT.toLowerCase()]}return e===L?null:e},overrideMimeType:function(e){if(!bA){bD.mimeType=e}return this},abort:function(e){e=e||"abort";if(bL){bL.abort(e)}bF(0,e);return this}};function bF(bZ,bU,b0,bW){if(bA===2){return}bA=2;if(bE){clearTimeout(bE)}bL=L;bQ=bW||"";bJ.readyState=bZ>0?4:0;var bT,b4,b3,bX=bU,bY=b0?bj(bD,bJ,b0):L,bV,b2;if(bZ>=200&&bZ<300||bZ===304){if(bD.ifModified){if((bV=bJ.getResponseHeader("Last-Modified"))){b.lastModified[bC]=bV}if((b2=bJ.getResponseHeader("Etag"))){b.etag[bC]=b2}}if(bZ===304){bX="notmodified";bT=true}else{try{b4=G(bD,bY);bX="success";bT=true}catch(b1){bX="parsererror";b3=b1}}}else{b3=bX;if(!bX||bZ){bX="error";if(bZ<0){bZ=0}}}bJ.status=bZ;bJ.statusText=""+(bU||bX);if(bT){bR.resolveWith(bS,[b4,bX,bJ])}else{bR.rejectWith(bS,[bJ,bX,b3])}bJ.statusCode(bB);bB=L;if(bw){bG.trigger("ajax"+(bT?"Success":"Error"),[bJ,bD,bT?b4:b3])}bN.fireWith(bS,[bJ,bX]);if(bw){bG.trigger("ajaxComplete",[bJ,bD]);if(!(--b.active)){b.event.trigger("ajaxStop")}}}bR.promise(bJ);bJ.success=bJ.done;bJ.error=bJ.fail;bJ.complete=bN.add;bJ.statusCode=function(bT){if(bT){var e;if(bA<2){for(e in bT){bB[e]=[bB[e],bT[e]]}}else{e=bT[bJ.status];bJ.then(e,e)}}return this};bD.url=((bz||bD.url)+"").replace(bq,"").replace(c,s[1]+"//");bD.dataTypes=b.trim(bD.dataType||"*").toLowerCase().split(h);if(bD.crossDomain==null){bI=K.exec(bD.url.toLowerCase());bD.crossDomain=!!(bI&&(bI[1]!=s[1]||bI[2]!=s[2]||(bI[3]||(bI[1]==="http:"?80:443))!=(s[3]||(s[1]==="http:"?80:443))))}if(bD.data&&bD.processData&&typeof bD.data!=="string"){bD.data=b.param(bD.data,bD.traditional)}aW(aa,bD,bx,bJ);if(bA===2){return false}bw=bD.global;bD.type=bD.type.toUpperCase();bD.hasContent=!aQ.test(bD.type);if(bw&&b.active++===0){b.event.trigger("ajaxStart")}if(!bD.hasContent){if(bD.data){bD.url+=(M.test(bD.url)?"&":"?")+bD.data;delete bD.data}bC=bD.url;if(bD.cache===false){var bv=b.now(),bP=bD.url.replace(br,"$1_="+bv);bD.url=bP+((bP===bD.url)?(M.test(bD.url)?"&":"?")+"_="+bv:"")}}if(bD.data&&bD.hasContent&&bD.contentType!==false||bx.contentType){bJ.setRequestHeader("Content-Type",bD.contentType)}if(bD.ifModified){bC=bC||bD.url;if(b.lastModified[bC]){bJ.setRequestHeader("If-Modified-Since",b.lastModified[bC])}if(b.etag[bC]){bJ.setRequestHeader("If-None-Match",b.etag[bC])}}bJ.setRequestHeader("Accept",bD.dataTypes[0]&&bD.accepts[bD.dataTypes[0]]?bD.accepts[bD.dataTypes[0]]+(bD.dataTypes[0]!=="*"?", "+aV+"; q=0.01":""):bD.accepts["*"]);for(bK in bD.headers){bJ.setRequestHeader(bK,bD.headers[bK])}if(bD.beforeSend&&(bD.beforeSend.call(bS,bJ,bD)===false||bA===2)){bJ.abort();return false}for(bK in {success:1,error:1,complete:1}){bJ[bK](bD[bK])}bL=aW(r,bD,bx,bJ);if(!bL){bF(-1,"No Transport")}else{bJ.readyState=1;if(bw){bG.trigger("ajaxSend",[bJ,bD])}if(bD.async&&bD.timeout>0){bE=setTimeout(function(){bJ.abort("timeout")},bD.timeout)}try{bA=1;bL.send(bH,bF)}catch(bM){if(bA<2){bF(-1,bM)}else{throw bM}}}return bJ},param:function(e,bw){var bv=[],by=function(bz,bA){bA=b.isFunction(bA)?bA():bA;bv[bv.length]=encodeURIComponent(bz)+"="+encodeURIComponent(bA)};if(bw===L){bw=b.ajaxSettings.traditional}if(b.isArray(e)||(e.jquery&&!b.isPlainObject(e))){b.each(e,function(){by(this.name,this.value)})}else{for(var bx in e){v(bx,e[bx],bw,by)}}return bv.join("&").replace(k,"+")}});function v(bw,by,bv,bx){if(b.isArray(by)){b.each(by,function(bA,bz){if(bv||ap.test(bw)){bx(bw,bz)}else{v(bw+"["+(typeof bz==="object"||b.isArray(bz)?bA:"")+"]",bz,bv,bx)}})}else{if(!bv&&by!=null&&typeof by==="object"){for(var e in by){v(bw+"["+e+"]",by[e],bv,bx)}}else{bx(bw,by)}}}b.extend({active:0,lastModified:{},etag:{}});function bj(bD,bC,bz){var bv=bD.contents,bB=bD.dataTypes,bw=bD.responseFields,by,bA,bx,e;for(bA in bw){if(bA in bz){bC[bw[bA]]=bz[bA]}}while(bB[0]==="*"){bB.shift();if(by===L){by=bD.mimeType||bC.getResponseHeader("content-type")}}if(by){for(bA in bv){if(bv[bA]&&bv[bA].test(by)){bB.unshift(bA);break}}}if(bB[0] in bz){bx=bB[0]}else{for(bA in bz){if(!bB[0]||bD.converters[bA+" "+bB[0]]){bx=bA;break}if(!e){e=bA}}bx=bx||e}if(bx){if(bx!==bB[0]){bB.unshift(bx)}return bz[bx]}}function G(bH,bz){if(bH.dataFilter){bz=bH.dataFilter(bz,bH.dataType)}var bD=bH.dataTypes,bG={},bA,bE,bw=bD.length,bB,bC=bD[0],bx,by,bF,bv,e;for(bA=1;bA=bw.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();bw.animatedProperties[this.prop]=true;for(bA in bw.animatedProperties){if(bw.animatedProperties[bA]!==true){e=false}}if(e){if(bw.overflow!=null&&!b.support.shrinkWrapBlocks){b.each(["","X","Y"],function(bC,bD){bz.style["overflow"+bD]=bw.overflow[bC]})}if(bw.hide){b(bz).hide()}if(bw.hide||bw.show){for(bA in bw.animatedProperties){b.style(bz,bA,bw.orig[bA]);b.removeData(bz,"fxshow"+bA,true);b.removeData(bz,"toggle"+bA,true)}}bv=bw.complete;if(bv){bw.complete=false;bv.call(bz)}}return false}else{if(bw.duration==Infinity){this.now=bx}else{bB=bx-this.startTime;this.state=bB/bw.duration;this.pos=b.easing[bw.animatedProperties[this.prop]](this.state,bB,0,1,bw.duration);this.now=this.start+((this.end-this.start)*this.pos)}this.update()}return true}};b.extend(b.fx,{tick:function(){var bw,bv=b.timers,e=0;for(;e").appendTo(e),bw=bv.css("display");bv.remove();if(bw==="none"||bw===""){if(!a8){a8=av.createElement("iframe");a8.frameBorder=a8.width=a8.height=0}e.appendChild(a8);if(!m||!a8.createElement){m=(a8.contentWindow||a8.contentDocument).document;m.write((av.compatMode==="CSS1Compat"?"":"")+"");m.close()}bv=m.createElement(bx);m.body.appendChild(bv);bw=b.css(bv,"display");e.removeChild(a8)}Q[bx]=bw}return Q[bx]}var V=/^t(?:able|d|h)$/i,ad=/^(?:body|html)$/i;if("getBoundingClientRect" in av.documentElement){b.fn.offset=function(bI){var by=this[0],bB;if(bI){return this.each(function(e){b.offset.setOffset(this,bI,e)})}if(!by||!by.ownerDocument){return null}if(by===by.ownerDocument.body){return b.offset.bodyOffset(by)}try{bB=by.getBoundingClientRect()}catch(bF){}var bH=by.ownerDocument,bw=bH.documentElement;if(!bB||!b.contains(bw,by)){return bB?{top:bB.top,left:bB.left}:{top:0,left:0}}var bC=bH.body,bD=aK(bH),bA=bw.clientTop||bC.clientTop||0,bE=bw.clientLeft||bC.clientLeft||0,bv=bD.pageYOffset||b.support.boxModel&&bw.scrollTop||bC.scrollTop,bz=bD.pageXOffset||b.support.boxModel&&bw.scrollLeft||bC.scrollLeft,bG=bB.top+bv-bA,bx=bB.left+bz-bE;return{top:bG,left:bx}}}else{b.fn.offset=function(bF){var bz=this[0];if(bF){return this.each(function(bG){b.offset.setOffset(this,bF,bG)})}if(!bz||!bz.ownerDocument){return null}if(bz===bz.ownerDocument.body){return b.offset.bodyOffset(bz)}var bC,bw=bz.offsetParent,bv=bz,bE=bz.ownerDocument,bx=bE.documentElement,bA=bE.body,bB=bE.defaultView,e=bB?bB.getComputedStyle(bz,null):bz.currentStyle,bD=bz.offsetTop,by=bz.offsetLeft;while((bz=bz.parentNode)&&bz!==bA&&bz!==bx){if(b.support.fixedPosition&&e.position==="fixed"){break}bC=bB?bB.getComputedStyle(bz,null):bz.currentStyle;bD-=bz.scrollTop;by-=bz.scrollLeft;if(bz===bw){bD+=bz.offsetTop;by+=bz.offsetLeft;if(b.support.doesNotAddBorder&&!(b.support.doesAddBorderForTableAndCells&&V.test(bz.nodeName))){bD+=parseFloat(bC.borderTopWidth)||0;by+=parseFloat(bC.borderLeftWidth)||0}bv=bw;bw=bz.offsetParent}if(b.support.subtractsBorderForOverflowNotVisible&&bC.overflow!=="visible"){bD+=parseFloat(bC.borderTopWidth)||0;by+=parseFloat(bC.borderLeftWidth)||0}e=bC}if(e.position==="relative"||e.position==="static"){bD+=bA.offsetTop;by+=bA.offsetLeft}if(b.support.fixedPosition&&e.position==="fixed"){bD+=Math.max(bx.scrollTop,bA.scrollTop);by+=Math.max(bx.scrollLeft,bA.scrollLeft)}return{top:bD,left:by}}}b.offset={bodyOffset:function(e){var bw=e.offsetTop,bv=e.offsetLeft;if(b.support.doesNotIncludeMarginInBodyOffset){bw+=parseFloat(b.css(e,"marginTop"))||0;bv+=parseFloat(b.css(e,"marginLeft"))||0}return{top:bw,left:bv}},setOffset:function(bx,bG,bA){var bB=b.css(bx,"position");if(bB==="static"){bx.style.position="relative"}var bz=b(bx),bv=bz.offset(),e=b.css(bx,"top"),bE=b.css(bx,"left"),bF=(bB==="absolute"||bB==="fixed")&&b.inArray("auto",[e,bE])>-1,bD={},bC={},bw,by;if(bF){bC=bz.position();bw=bC.top;by=bC.left}else{bw=parseFloat(e)||0;by=parseFloat(bE)||0}if(b.isFunction(bG)){bG=bG.call(bx,bA,bv)}if(bG.top!=null){bD.top=(bG.top-bv.top)+bw}if(bG.left!=null){bD.left=(bG.left-bv.left)+by}if("using" in bG){bG.using.call(bx,bD)}else{bz.css(bD)}}};b.fn.extend({position:function(){if(!this[0]){return null}var bw=this[0],bv=this.offsetParent(),bx=this.offset(),e=ad.test(bv[0].nodeName)?{top:0,left:0}:bv.offset();bx.top-=parseFloat(b.css(bw,"marginTop"))||0;bx.left-=parseFloat(b.css(bw,"marginLeft"))||0;e.top+=parseFloat(b.css(bv[0],"borderTopWidth"))||0;e.left+=parseFloat(b.css(bv[0],"borderLeftWidth"))||0;return{top:bx.top-e.top,left:bx.left-e.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||av.body;while(e&&(!ad.test(e.nodeName)&&b.css(e,"position")==="static")){e=e.offsetParent}return e})}});b.each(["Left","Top"],function(bv,e){var bw="scroll"+e;b.fn[bw]=function(bz){var bx,by;if(bz===L){bx=this[0];if(!bx){return null}by=aK(bx);return by?("pageXOffset" in by)?by[bv?"pageYOffset":"pageXOffset"]:b.support.boxModel&&by.document.documentElement[bw]||by.document.body[bw]:bx[bw]}return this.each(function(){by=aK(this);if(by){by.scrollTo(!bv?bz:b(by).scrollLeft(),bv?bz:b(by).scrollTop())}else{this[bw]=bz}})}});function aK(e){return b.isWindow(e)?e:e.nodeType===9?e.defaultView||e.parentWindow:false}b.each(["Height","Width"],function(bv,e){var bw=e.toLowerCase();b.fn["inner"+e]=function(){var bx=this[0];return bx?bx.style?parseFloat(b.css(bx,bw,"padding")):this[bw]():null};b.fn["outer"+e]=function(by){var bx=this[0];return bx?bx.style?parseFloat(b.css(bx,bw,by?"margin":"border")):this[bw]():null};b.fn[bw]=function(bz){var bA=this[0];if(!bA){return bz==null?null:this}if(b.isFunction(bz)){return this.each(function(bE){var bD=b(this);bD[bw](bz.call(this,bE,bD[bw]()))})}if(b.isWindow(bA)){var bB=bA.document.documentElement["client"+e],bx=bA.document.body;return bA.document.compatMode==="CSS1Compat"&&bB||bx&&bx["client"+e]||bB}else{if(bA.nodeType===9){return Math.max(bA.documentElement["client"+e],bA.body["scroll"+e],bA.documentElement["scroll"+e],bA.body["offset"+e],bA.documentElement["offset"+e])}else{if(bz===L){var bC=b.css(bA,bw),by=parseFloat(bC);return b.isNumeric(by)?by:bC}else{return this.css(bw,typeof bz==="string"?bz:bz+"px")}}}}});bb.jQuery=bb.$=b;if(typeof define==="function"&&define.amd&&define.amd.jQuery){define("jquery",[],function(){return b})}})(window);/*! + * jQuery UI 1.8.18 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI + */ +(function(a,d){a.ui=a.ui||{};if(a.ui.version){return}a.extend(a.ui,{version:"1.8.18",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});a.fn.extend({propAttr:a.fn.prop||a.fn.attr,_focus:a.fn.focus,focus:function(e,f){return typeof e==="number"?this.each(function(){var g=this;setTimeout(function(){a(g).focus();if(f){f.call(g)}},e)}):this._focus.apply(this,arguments)},scrollParent:function(){var e;if((a.browser.msie&&(/(static|relative)/).test(this.css("position")))||(/absolute/).test(this.css("position"))){e=this.parents().filter(function(){return(/(relative|absolute|fixed)/).test(a.curCSS(this,"position",1))&&(/(auto|scroll)/).test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0)}else{e=this.parents().filter(function(){return(/(auto|scroll)/).test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0)}return(/fixed/).test(this.css("position"))||!e.length?a(document):e},zIndex:function(h){if(h!==d){return this.css("zIndex",h)}if(this.length){var f=a(this[0]),e,g;while(f.length&&f[0]!==document){e=f.css("position");if(e==="absolute"||e==="relative"||e==="fixed"){g=parseInt(f.css("zIndex"),10);if(!isNaN(g)&&g!==0){return g}}f=f.parent()}}return 0},disableSelection:function(){return this.bind((a.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(e){e.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});a.each(["Width","Height"],function(g,e){var f=e==="Width"?["Left","Right"]:["Top","Bottom"],h=e.toLowerCase(),k={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight,outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};function j(m,l,i,n){a.each(f,function(){l-=parseFloat(a.curCSS(m,"padding"+this,true))||0;if(i){l-=parseFloat(a.curCSS(m,"border"+this+"Width",true))||0}if(n){l-=parseFloat(a.curCSS(m,"margin"+this,true))||0}});return l}a.fn["inner"+e]=function(i){if(i===d){return k["inner"+e].call(this)}return this.each(function(){a(this).css(h,j(this,i)+"px")})};a.fn["outer"+e]=function(i,l){if(typeof i!=="number"){return k["outer"+e].call(this,i)}return this.each(function(){a(this).css(h,j(this,i,true,l)+"px")})}});function c(g,e){var j=g.nodeName.toLowerCase();if("area"===j){var i=g.parentNode,h=i.name,f;if(!g.href||!h||i.nodeName.toLowerCase()!=="map"){return false}f=a("img[usemap=#"+h+"]")[0];return !!f&&b(f)}return(/input|select|textarea|button|object/.test(j)?!g.disabled:"a"==j?g.href||e:e)&&b(g)}function b(e){return !a(e).parents().andSelf().filter(function(){return a.curCSS(this,"visibility")==="hidden"||a.expr.filters.hidden(this)}).length}a.extend(a.expr[":"],{data:function(g,f,e){return !!a.data(g,e[3])},focusable:function(e){return c(e,!isNaN(a.attr(e,"tabindex")))},tabbable:function(g){var e=a.attr(g,"tabindex"),f=isNaN(e);return(f||e>=0)&&c(g,!f)}});a(function(){var e=document.body,f=e.appendChild(f=document.createElement("div"));f.offsetHeight;a.extend(f.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});a.support.minHeight=f.offsetHeight===100;a.support.selectstart="onselectstart" in f;e.removeChild(f).style.display="none"});a.extend(a.ui,{plugin:{add:function(f,g,j){var h=a.ui[f].prototype;for(var e in j){h.plugins[e]=h.plugins[e]||[];h.plugins[e].push([g,j[e]])}},call:function(e,g,f){var j=e.plugins[g];if(!j||!e.element[0].parentNode){return}for(var h=0;h0){return true}h[e]=1;g=(h[e]>0);h[e]=0;return g},isOverAxis:function(f,e,g){return(f>e)&&(f<(e+g))},isOver:function(j,f,i,h,e,g){return a.ui.isOverAxis(j,i,e)&&a.ui.isOverAxis(f,h,g)}})})(jQuery);/*! + * jQuery UI Widget 1.8.18 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Widget + */ +(function(b,d){if(b.cleanData){var c=b.cleanData;b.cleanData=function(f){for(var g=0,h;(h=f[g])!=null;g++){try{b(h).triggerHandler("remove")}catch(j){}}c(f)}}else{var a=b.fn.remove;b.fn.remove=function(e,f){return this.each(function(){if(!f){if(!e||b.filter(e,[this]).length){b("*",this).add([this]).each(function(){try{b(this).triggerHandler("remove")}catch(g){}})}}return a.call(b(this),e,f)})}}b.widget=function(f,h,e){var g=f.split(".")[0],j;f=f.split(".")[1];j=g+"-"+f;if(!e){e=h;h=b.Widget}b.expr[":"][j]=function(k){return !!b.data(k,f)};b[g]=b[g]||{};b[g][f]=function(k,l){if(arguments.length){this._createWidget(k,l)}};var i=new h();i.options=b.extend(true,{},i.options);b[g][f].prototype=b.extend(true,i,{namespace:g,widgetName:f,widgetEventPrefix:b[g][f].prototype.widgetEventPrefix||f,widgetBaseClass:j},e);b.widget.bridge(f,b[g][f])};b.widget.bridge=function(f,e){b.fn[f]=function(i){var g=typeof i==="string",h=Array.prototype.slice.call(arguments,1),j=this;i=!g&&h.length?b.extend.apply(null,[true,i].concat(h)):i;if(g&&i.charAt(0)==="_"){return j}if(g){this.each(function(){var k=b.data(this,f),l=k&&b.isFunction(k[i])?k[i].apply(k,h):k;if(l!==k&&l!==d){j=l;return false}})}else{this.each(function(){var k=b.data(this,f);if(k){k.option(i||{})._init()}else{b.data(this,f,new e(i,this))}})}return j}};b.Widget=function(e,f){if(arguments.length){this._createWidget(e,f)}};b.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:false},_createWidget:function(f,g){b.data(g,this.widgetName,this);this.element=b(g);this.options=b.extend(true,{},this.options,this._getCreateOptions(),f);var e=this;this.element.bind("remove."+this.widgetName,function(){e.destroy()});this._create();this._trigger("create");this._init()},_getCreateOptions:function(){return b.metadata&&b.metadata.get(this.element[0])[this.widgetName]},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled ui-state-disabled")},widget:function(){return this.element},option:function(f,g){var e=f;if(arguments.length===0){return b.extend({},this.options)}if(typeof f==="string"){if(g===d){return this.options[f]}e={};e[f]=g}this._setOptions(e);return this},_setOptions:function(f){var e=this;b.each(f,function(g,h){e._setOption(g,h)});return this},_setOption:function(e,f){this.options[e]=f;if(e==="disabled"){this.widget()[f?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",f)}return this},enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(e,f,g){var j,i,h=this.options[e];g=g||{};f=b.Event(f);f.type=(e===this.widgetEventPrefix?e:this.widgetEventPrefix+e).toLowerCase();f.target=this.element[0];i=f.originalEvent;if(i){for(j in i){if(!(j in f)){f[j]=i[j]}}}this.element.trigger(f,g);return !(b.isFunction(h)&&h.call(this.element[0],f,g)===false||f.isDefaultPrevented())}}})(jQuery);/*! + * jQuery UI Mouse 1.8.18 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Mouse + * + * Depends: + * jquery.ui.widget.js + */ +(function(b,c){var a=false;b(document).mouseup(function(d){a=false});b.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var d=this;this.element.bind("mousedown."+this.widgetName,function(e){return d._mouseDown(e)}).bind("click."+this.widgetName,function(e){if(true===b.data(e.target,d.widgetName+".preventClickEvent")){b.removeData(e.target,d.widgetName+".preventClickEvent");e.stopImmediatePropagation();return false}});this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName)},_mouseDown:function(f){if(a){return}(this._mouseStarted&&this._mouseUp(f));this._mouseDownEvent=f;var e=this,g=(f.which==1),d=(typeof this.options.cancel=="string"&&f.target.nodeName?b(f.target).closest(this.options.cancel).length:false);if(!g||d||!this._mouseCapture(f)){return true}this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet){this._mouseDelayTimer=setTimeout(function(){e.mouseDelayMet=true},this.options.delay)}if(this._mouseDistanceMet(f)&&this._mouseDelayMet(f)){this._mouseStarted=(this._mouseStart(f)!==false);if(!this._mouseStarted){f.preventDefault();return true}}if(true===b.data(f.target,this.widgetName+".preventClickEvent")){b.removeData(f.target,this.widgetName+".preventClickEvent")}this._mouseMoveDelegate=function(h){return e._mouseMove(h)};this._mouseUpDelegate=function(h){return e._mouseUp(h)};b(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);f.preventDefault();a=true;return true},_mouseMove:function(d){if(b.browser.msie&&!(document.documentMode>=9)&&!d.button){return this._mouseUp(d)}if(this._mouseStarted){this._mouseDrag(d);return d.preventDefault()}if(this._mouseDistanceMet(d)&&this._mouseDelayMet(d)){this._mouseStarted=(this._mouseStart(this._mouseDownEvent,d)!==false);(this._mouseStarted?this._mouseDrag(d):this._mouseUp(d))}return !this._mouseStarted},_mouseUp:function(d){b(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;if(d.target==this._mouseDownEvent.target){b.data(d.target,this.widgetName+".preventClickEvent",true)}this._mouseStop(d)}return false},_mouseDistanceMet:function(d){return(Math.max(Math.abs(this._mouseDownEvent.pageX-d.pageX),Math.abs(this._mouseDownEvent.pageY-d.pageY))>=this.options.distance)},_mouseDelayMet:function(d){return this.mouseDelayMet},_mouseStart:function(d){},_mouseDrag:function(d){},_mouseStop:function(d){},_mouseCapture:function(d){return true}})})(jQuery);(function(c,d){c.widget("ui.resizable",c.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,containment:false,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1000},_create:function(){var f=this,k=this.options;this.element.addClass("ui-resizable");c.extend(this,{_aspectRatio:!!(k.aspectRatio),aspectRatio:k.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:k.helper||k.ghost||k.animate?k.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){this.element.wrap(c('
').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=k.handles||(!c(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all"){this.handles="n,e,s,w,se,sw,ne,nw"}var l=this.handles.split(",");this.handles={};for(var g=0;g
');if(/sw|se|ne|nw/.test(j)){h.css({zIndex:++k.zIndex})}if("se"==j){h.addClass("ui-icon ui-icon-gripsmall-diagonal-se")}this.handles[j]=".ui-resizable-"+j;this.element.append(h)}}this._renderAxis=function(q){q=q||this.element;for(var n in this.handles){if(this.handles[n].constructor==String){this.handles[n]=c(this.handles[n],this.element).show()}if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var o=c(this.handles[n],this.element),p=0;p=/sw|ne|nw|se|n|s/.test(n)?o.outerHeight():o.outerWidth();var m=["padding",/ne|nw|n/.test(n)?"Top":/se|sw|s/.test(n)?"Bottom":/^e$/.test(n)?"Right":"Left"].join("");q.css(m,p);this._proportionallyResize()}if(!c(this.handles[n]).length){continue}}};this._renderAxis(this.element);this._handles=c(".ui-resizable-handle",this.element).disableSelection();this._handles.mouseover(function(){if(!f.resizing){if(this.className){var i=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)}f.axis=i&&i[1]?i[1]:"se"}});if(k.autoHide){this._handles.hide();c(this.element).addClass("ui-resizable-autohide").hover(function(){if(k.disabled){return}c(this).removeClass("ui-resizable-autohide");f._handles.show()},function(){if(k.disabled){return}if(!f.resizing){c(this).addClass("ui-resizable-autohide");f._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var e=function(g){c(g).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){e(this.element);var f=this.element;f.after(this.originalElement.css({position:f.css("position"),width:f.outerWidth(),height:f.outerHeight(),top:f.css("top"),left:f.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);e(this.originalElement);return this},_mouseCapture:function(f){var g=false;for(var e in this.handles){if(c(this.handles[e])[0]==f.target){g=true}}return !this.options.disabled&&g},_mouseStart:function(g){var j=this.options,f=this.element.position(),e=this.element;this.resizing=true;this.documentScroll={top:c(document).scrollTop(),left:c(document).scrollLeft()};if(e.is(".ui-draggable")||(/absolute/).test(e.css("position"))){e.css({position:"absolute",top:f.top,left:f.left})}this._renderProxy();var k=b(this.helper.css("left")),h=b(this.helper.css("top"));if(j.containment){k+=c(j.containment).scrollLeft()||0;h+=c(j.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:k,top:h};this.size=this._helper?{width:e.outerWidth(),height:e.outerHeight()}:{width:e.width(),height:e.height()};this.originalSize=this._helper?{width:e.outerWidth(),height:e.outerHeight()}:{width:e.width(),height:e.height()};this.originalPosition={left:k,top:h};this.sizeDiff={width:e.outerWidth()-e.width(),height:e.outerHeight()-e.height()};this.originalMousePosition={left:g.pageX,top:g.pageY};this.aspectRatio=(typeof j.aspectRatio=="number")?j.aspectRatio:((this.originalSize.width/this.originalSize.height)||1);var i=c(".ui-resizable-"+this.axis).css("cursor");c("body").css("cursor",i=="auto"?this.axis+"-resize":i);e.addClass("ui-resizable-resizing");this._propagate("start",g);return true},_mouseDrag:function(e){var h=this.helper,g=this.options,m={},q=this,j=this.originalMousePosition,n=this.axis;var r=(e.pageX-j.left)||0,p=(e.pageY-j.top)||0;var i=this._change[n];if(!i){return false}var l=i.apply(this,[e,r,p]),k=c.browser.msie&&c.browser.version<7,f=this.sizeDiff;this._updateVirtualBoundaries(e.shiftKey);if(this._aspectRatio||e.shiftKey){l=this._updateRatio(l,e)}l=this._respectSize(l,e);this._propagate("resize",e);h.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});if(!this._helper&&this._proportionallyResizeElements.length){this._proportionallyResize()}this._updateCache(l);this._trigger("resize",e,this.ui());return false},_mouseStop:function(h){this.resizing=false;var i=this.options,m=this;if(this._helper){var g=this._proportionallyResizeElements,e=g.length&&(/textarea/i).test(g[0].nodeName),f=e&&c.ui.hasScroll(g[0],"left")?0:m.sizeDiff.height,k=e?0:m.sizeDiff.width;var n={width:(m.helper.width()-k),height:(m.helper.height()-f)},j=(parseInt(m.element.css("left"),10)+(m.position.left-m.originalPosition.left))||null,l=(parseInt(m.element.css("top"),10)+(m.position.top-m.originalPosition.top))||null;if(!i.animate){this.element.css(c.extend(n,{top:l,left:j}))}m.helper.height(m.size.height);m.helper.width(m.size.width);if(this._helper&&!i.animate){this._proportionallyResize()}}c("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",h);if(this._helper){this.helper.remove()}return false},_updateVirtualBoundaries:function(g){var j=this.options,i,h,f,k,e;e={minWidth:a(j.minWidth)?j.minWidth:0,maxWidth:a(j.maxWidth)?j.maxWidth:Infinity,minHeight:a(j.minHeight)?j.minHeight:0,maxHeight:a(j.maxHeight)?j.maxHeight:Infinity};if(this._aspectRatio||g){i=e.minHeight*this.aspectRatio;f=e.minWidth/this.aspectRatio;h=e.maxHeight*this.aspectRatio;k=e.maxWidth/this.aspectRatio;if(i>e.minWidth){e.minWidth=i}if(f>e.minHeight){e.minHeight=f}if(hl.width),s=a(l.height)&&i.minHeight&&(i.minHeight>l.height);if(h){l.width=i.minWidth}if(s){l.height=i.minHeight}if(t){l.width=i.maxWidth}if(m){l.height=i.maxHeight}var f=this.originalPosition.left+this.originalSize.width,p=this.position.top+this.size.height;var k=/sw|nw|w/.test(q),e=/nw|ne|n/.test(q);if(h&&k){l.left=f-i.minWidth}if(t&&k){l.left=f-i.maxWidth}if(s&&e){l.top=p-i.minHeight}if(m&&e){l.top=p-i.maxHeight}var n=!l.width&&!l.height;if(n&&!l.left&&l.top){l.top=null}else{if(n&&!l.top&&l.left){l.left=null}}return l},_proportionallyResize:function(){var k=this.options;if(!this._proportionallyResizeElements.length){return}var g=this.helper||this.element;for(var f=0;f');var e=c.browser.msie&&c.browser.version<7,g=(e?1:0),h=(e?2:-1);this.helper.addClass(this._helper).css({width:this.element.outerWidth()+h,height:this.element.outerHeight()+h,position:"absolute",left:this.elementOffset.left-g+"px",top:this.elementOffset.top-g+"px",zIndex:++i.zIndex});this.helper.appendTo("body").disableSelection()}else{this.helper=this.element}},_change:{e:function(g,f,e){return{width:this.originalSize.width+f}},w:function(h,f,e){var j=this.options,g=this.originalSize,i=this.originalPosition;return{left:i.left+f,width:g.width-f}},n:function(h,f,e){var j=this.options,g=this.originalSize,i=this.originalPosition;return{top:i.top+e,height:g.height-e}},s:function(g,f,e){return{height:this.originalSize.height+e}},se:function(g,f,e){return c.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[g,f,e]))},sw:function(g,f,e){return c.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[g,f,e]))},ne:function(g,f,e){return c.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[g,f,e]))},nw:function(g,f,e){return c.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[g,f,e]))}},_propagate:function(f,e){c.ui.plugin.call(this,f,[e,this.ui()]);(f!="resize"&&this._trigger(f,e,this.ui()))},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});c.extend(c.ui.resizable,{version:"1.8.18"});c.ui.plugin.add("resizable","alsoResize",{start:function(f,g){var e=c(this).data("resizable"),i=e.options;var h=function(j){c(j).each(function(){var k=c(this);k.data("resizable-alsoresize",{width:parseInt(k.width(),10),height:parseInt(k.height(),10),left:parseInt(k.css("left"),10),top:parseInt(k.css("top"),10)})})};if(typeof(i.alsoResize)=="object"&&!i.alsoResize.parentNode){if(i.alsoResize.length){i.alsoResize=i.alsoResize[0];h(i.alsoResize)}else{c.each(i.alsoResize,function(j){h(j)})}}else{h(i.alsoResize)}},resize:function(g,i){var f=c(this).data("resizable"),j=f.options,h=f.originalSize,l=f.originalPosition;var k={height:(f.size.height-h.height)||0,width:(f.size.width-h.width)||0,top:(f.position.top-l.top)||0,left:(f.position.left-l.left)||0},e=function(m,n){c(m).each(function(){var q=c(this),r=c(this).data("resizable-alsoresize"),p={},o=n&&n.length?n:q.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];c.each(o,function(s,u){var t=(r[u]||0)+(k[u]||0);if(t&&t>=0){p[u]=t||null}});q.css(p)})};if(typeof(j.alsoResize)=="object"&&!j.alsoResize.nodeType){c.each(j.alsoResize,function(m,n){e(m,n)})}else{e(j.alsoResize)}},stop:function(e,f){c(this).removeData("resizable-alsoresize")}});c.ui.plugin.add("resizable","animate",{stop:function(i,n){var p=c(this).data("resizable"),j=p.options;var h=p._proportionallyResizeElements,e=h.length&&(/textarea/i).test(h[0].nodeName),f=e&&c.ui.hasScroll(h[0],"left")?0:p.sizeDiff.height,l=e?0:p.sizeDiff.width;var g={width:(p.size.width-l),height:(p.size.height-f)},k=(parseInt(p.element.css("left"),10)+(p.position.left-p.originalPosition.left))||null,m=(parseInt(p.element.css("top"),10)+(p.position.top-p.originalPosition.top))||null;p.element.animate(c.extend(g,m&&k?{top:m,left:k}:{}),{duration:j.animateDuration,easing:j.animateEasing,step:function(){var o={width:parseInt(p.element.css("width"),10),height:parseInt(p.element.css("height"),10),top:parseInt(p.element.css("top"),10),left:parseInt(p.element.css("left"),10)};if(h&&h.length){c(h[0]).css({width:o.width,height:o.height})}p._updateCache(o);p._propagate("resize",i)}})}});c.ui.plugin.add("resizable","containment",{start:function(f,r){var t=c(this).data("resizable"),j=t.options,l=t.element;var g=j.containment,k=(g instanceof c)?g.get(0):(/parent/.test(g))?l.parent().get(0):g;if(!k){return}t.containerElement=c(k);if(/document/.test(g)||g==document){t.containerOffset={left:0,top:0};t.containerPosition={left:0,top:0};t.parentData={element:c(document),left:0,top:0,width:c(document).width(),height:c(document).height()||document.body.parentNode.scrollHeight}}else{var n=c(k),i=[];c(["Top","Right","Left","Bottom"]).each(function(p,o){i[p]=b(n.css("padding"+o))});t.containerOffset=n.offset();t.containerPosition=n.position();t.containerSize={height:(n.innerHeight()-i[3]),width:(n.innerWidth()-i[1])};var q=t.containerOffset,e=t.containerSize.height,m=t.containerSize.width,h=(c.ui.hasScroll(k,"left")?k.scrollWidth:m),s=(c.ui.hasScroll(k)?k.scrollHeight:e);t.parentData={element:k,left:q.left,top:q.top,width:h,height:s}}},resize:function(g,q){var t=c(this).data("resizable"),i=t.options,f=t.containerSize,p=t.containerOffset,m=t.size,n=t.position,r=t._aspectRatio||g.shiftKey,e={top:0,left:0},h=t.containerElement;if(h[0]!=document&&(/static/).test(h.css("position"))){e=p}if(n.left<(t._helper?p.left:0)){t.size.width=t.size.width+(t._helper?(t.position.left-p.left):(t.position.left-e.left));if(r){t.size.height=t.size.width/i.aspectRatio}t.position.left=i.helper?p.left:0}if(n.top<(t._helper?p.top:0)){t.size.height=t.size.height+(t._helper?(t.position.top-p.top):t.position.top);if(r){t.size.width=t.size.height*i.aspectRatio}t.position.top=t._helper?p.top:0}t.offset.left=t.parentData.left+t.position.left;t.offset.top=t.parentData.top+t.position.top;var l=Math.abs((t._helper?t.offset.left-e.left:(t.offset.left-e.left))+t.sizeDiff.width),s=Math.abs((t._helper?t.offset.top-e.top:(t.offset.top-p.top))+t.sizeDiff.height);var k=t.containerElement.get(0)==t.element.parent().get(0),j=/relative|absolute/.test(t.containerElement.css("position"));if(k&&j){l-=t.parentData.left}if(l+t.size.width>=t.parentData.width){t.size.width=t.parentData.width-l;if(r){t.size.height=t.size.width/t.aspectRatio}}if(s+t.size.height>=t.parentData.height){t.size.height=t.parentData.height-s;if(r){t.size.width=t.size.height*t.aspectRatio}}},stop:function(f,n){var q=c(this).data("resizable"),g=q.options,l=q.position,m=q.containerOffset,e=q.containerPosition,i=q.containerElement;var j=c(q.helper),r=j.offset(),p=j.outerWidth()-q.sizeDiff.width,k=j.outerHeight()-q.sizeDiff.height;if(q._helper&&!g.animate&&(/relative/).test(i.css("position"))){c(this).css({left:r.left-e.left-m.left,width:p,height:k})}if(q._helper&&!g.animate&&(/static/).test(i.css("position"))){c(this).css({left:r.left-e.left-m.left,width:p,height:k})}}});c.ui.plugin.add("resizable","ghost",{start:function(g,h){var e=c(this).data("resizable"),i=e.options,f=e.size;e.ghost=e.originalElement.clone();e.ghost.css({opacity:0.25,display:"block",position:"relative",height:f.height,width:f.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof i.ghost=="string"?i.ghost:"");e.ghost.appendTo(e.helper)},resize:function(f,g){var e=c(this).data("resizable"),h=e.options;if(e.ghost){e.ghost.css({position:"relative",height:e.size.height,width:e.size.width})}},stop:function(f,g){var e=c(this).data("resizable"),h=e.options;if(e.ghost&&e.helper){e.helper.get(0).removeChild(e.ghost.get(0))}}});c.ui.plugin.add("resizable","grid",{resize:function(e,m){var p=c(this).data("resizable"),h=p.options,k=p.size,i=p.originalSize,j=p.originalPosition,n=p.axis,l=h._aspectRatio||e.shiftKey;h.grid=typeof h.grid=="number"?[h.grid,h.grid]:h.grid;var g=Math.round((k.width-i.width)/(h.grid[0]||1))*(h.grid[0]||1),f=Math.round((k.height-i.height)/(h.grid[1]||1))*(h.grid[1]||1);if(/^(se|s|e)$/.test(n)){p.size.width=i.width+g;p.size.height=i.height+f}else{if(/^(ne)$/.test(n)){p.size.width=i.width+g;p.size.height=i.height+f;p.position.top=j.top-f}else{if(/^(sw)$/.test(n)){p.size.width=i.width+g;p.size.height=i.height+f;p.position.left=j.left-g}else{p.size.width=i.width+g;p.size.height=i.height+f;p.position.top=j.top-f;p.position.left=j.left-g}}}}});var b=function(e){return parseInt(e,10)||0};var a=function(e){return !isNaN(parseInt(e,10))}})(jQuery);/*! + * jQuery hashchange event - v1.3 - 7/21/2010 + * http://benalman.com/projects/jquery-hashchange-plugin/ + * + * Copyright (c) 2010 "Cowboy" Ben Alman + * Dual licensed under the MIT and GPL licenses. + * http://benalman.com/about/license/ + */ +(function($,e,b){var c="hashchange",h=document,f,g=$.event.special,i=h.documentMode,d="on"+c in e&&(i===b||i>7);function a(j){j=j||location.href;return"#"+j.replace(/^[^#]*#?(.*)$/,"$1")}$.fn[c]=function(j){return j?this.bind(c,j):this.trigger(c)};$.fn[c].delay=50;g[c]=$.extend(g[c],{setup:function(){if(d){return false}$(f.start)},teardown:function(){if(d){return false}$(f.stop)}});f=(function(){var j={},p,m=a(),k=function(q){return q},l=k,o=k;j.start=function(){p||n()};j.stop=function(){p&&clearTimeout(p);p=b};function n(){var r=a(),q=o(m);if(r!==m){l(m=r,q);$(e).trigger(c)}else{if(q!==m){location.href=location.href.replace(/#.*/,"")+q}}p=setTimeout(n,$.fn[c].delay)}$.browser.msie&&!d&&(function(){var q,r;j.start=function(){if(!q){r=$.fn[c].src;r=r&&r+a();q=$(' + + + + +
+
+
mesh.h
+
+
+
1 /*
+
2  * ESPRSSIF MIT License
+
3  *
+
4  * Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+
5  *
+
6  * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+
7  * it is free of charge, to any person obtaining a copy of this software and associated
+
8  * documentation files (the "Software"), to deal in the Software without restriction, including
+
9  * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+
10  * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
+
11  * to do so, subject to the following conditions:
+
12  *
+
13  * The above copyright notice and this permission notice shall be included in all copies or
+
14  * substantial portions of the Software.
+
15  *
+
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
22  *
+
23  */
+
24 
+
25 #ifndef __LWIP_API_MESH_H__
+
26 #define __LWIP_API_MESH_H__
+
27 
+
28 #include "lwip/ip_addr.h"
+
29 #include "espconn.h"
+
30 
+
31 #ifdef __cplusplus
+
32 extern "C" {
+
33 #endif
+
34 
+
35 typedef void (* espconn_mesh_callback)();
+
36 
+
37 enum mesh_type {
+
38  MESH_CLOSE = 0,
+
39  MESH_LOCAL,
+
40  MESH_ONLINE,
+
41  MESH_NONE = 0xFF
+
42 };
+
43 
+ + + + + + +
61 };
+
62 
+ + + + +
67 };
+
68 
+
80 bool espconn_mesh_local_addr(struct ip_addr *ip);
+
81 
+ +
93  uint8_t **info, uint8_t *count);
+
94 
+
107 bool espconn_mesh_encrypt_init(AUTH_MODE mode, uint8_t *passwd, uint8_t passwd_len);
+
108 
+
120 bool espconn_mesh_set_ssid_prefix(uint8_t *prefix, uint8_t prefix_len);
+
121 
+
132 bool espconn_mesh_set_max_hops(uint8_t max_hops);
+
133 
+
145 bool espconn_mesh_group_id_init(uint8_t *grp_id, uint16_t gid_len);
+
146 
+
155 bool espconn_mesh_set_dev_type(uint8_t dev_type);
+
156 
+
174 sint8 espconn_mesh_connect(struct espconn *usr_esp);
+
175 
+
190 sint8 espconn_mesh_disconnect(struct espconn *usr_esp);
+
191 
+ +
200 
+
218 sint8 espconn_mesh_sent(struct espconn *usr_esp, uint8 *pdata, uint16 len);
+
219 
+ +
228 
+
243 void espconn_mesh_enable(espconn_mesh_callback enable_cb, enum mesh_type type);
+
244 
+
255 void espconn_mesh_disable(espconn_mesh_callback disable_cb);
+
256 
+
264 void espconn_mesh_init();
+
265 
+
270 #ifdef __cplusplus
+
271 }
+
272 #endif
+
273 
+
274 #endif
+
bool espconn_mesh_set_dev_type(uint8_t dev_type)
Set the curent device type.
+
bool espconn_mesh_set_max_hops(uint8_t max_hops)
Set max hop for mesh network.
+
Definition: mesh.h:57
+
AUTH_MODE
Definition: esp_wifi.h:59
+
void espconn_mesh_init()
To print version of mesh.
+
Definition: mesh.h:66
+
sint8 espconn_mesh_get_status()
Get current mesh status.
+
mesh_node_type
Definition: mesh.h:63
+
Definition: mesh.h:60
+
sint8 espconn_mesh_disconnect(struct espconn *usr_esp)
Disconnect a mesh connection.
+
Definition: mesh.h:58
+
sint8 espconn_mesh_connect(struct espconn *usr_esp)
Try to establish mesh connection to server.
+
bool espconn_mesh_local_addr(struct ip_addr *ip)
Check whether the IP address is mesh local IP address or not.
+
void espconn_mesh_enable(espconn_mesh_callback enable_cb, enum mesh_type type)
To enable mesh network.
+
void espconn_mesh_disable(espconn_mesh_callback disable_cb)
To disable mesh network.
+
bool espconn_mesh_get_node_info(enum mesh_node_type type, uint8_t **info, uint8_t *count)
Get the information of mesh node.
+
Definition: mesh.h:65
+
Definition: mesh.h:56
+
bool espconn_mesh_set_ssid_prefix(uint8_t *prefix, uint8_t prefix_len)
Set prefix of SSID for mesh node.
+
Definition: espconn.h:150
+
Definition: mesh.h:59
+
bool espconn_mesh_encrypt_init(AUTH_MODE mode, uint8_t *passwd, uint8_t passwd_len)
Set WiFi cryption algrithm and password for mesh node.
+
mesh_status
Definition: mesh.h:55
+
Definition: mesh.h:64
+
sint8 espconn_mesh_sent(struct espconn *usr_esp, uint8 *pdata, uint16 len)
Send data through mesh network.
+
bool espconn_mesh_group_id_init(uint8_t *grp_id, uint16_t gid_len)
Set group ID of mesh node.
+
uint8 espconn_mesh_get_max_hops()
Get max hop of mesh network.
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/modules.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/modules.html new file mode 100644 index 0000000..65c77b0 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/modules.html @@ -0,0 +1,122 @@ + + + + + + +ESP8266_RTOS_SDK: Modules + + + + + + + + + + +
+
+
+ + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+ + + + + + + +
+
+ + +
+ +
+ +
+
+
Modules
+
+
+
Here is a list of all modules:
+
[detail level 12]
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
 WiFi Related APIsWiFi APIs
 AirKiss APIsAirKiss APIs
 SoftAP APIsESP8266 Soft-AP APIs
 Station APIsESP8266 station APIs
 Common APIsWiFi common APIs
 Force Sleep APIsWiFi Force Sleep APIs
 Rate Control APIsWiFi Rate Control APIs
 User IE APIsWiFi User IE APIs
 Sniffer APIsWiFi sniffer APIs
 WPS APIsESP8266 WPS APIs
 Smartconfig APIsSmartConfig APIs
 Misc APIsMisc APIs
 Spiffs APIsSpiffs APIs
 SSC APIsSSC APIs
 System APIsSystem APIs
 Boot APIsBoot APIs
 Upgrade APIsFirmware upgrade (FOTA) APIs
 Software timer APIsSoftware timer APIs
 Network Espconn APIsNetwork espconn APIs
 ESP-NOW APIsESP-NOW APIs
 Mesh APIsMesh APIs
 Driver APIsDriver APIs
 PWM Driver APIsPWM driver APIs
 SPI Driver APIsSPI Flash APIs
 GPIO Driver APIsGPIO APIs
 Hardware timer APIsHardware timer APIs
 UART Driver APIsUART driver APIs
+
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/nav_f.png b/Distrib/ESPressif/RTOS/1.5.0/documents/html/nav_f.png new file mode 100644 index 0000000000000000000000000000000000000000..72a58a529ed3a9ed6aa0c51a79cf207e026deee2 GIT binary patch literal 153 zcmeAS@N?(olHy`uVBq!ia0vp^j6iI`!2~2XGqLUlQVE_ejv*C{Z|{2ZH7M}7UYxc) zn!W8uqtnIQ>_z8U literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/nav_g.png b/Distrib/ESPressif/RTOS/1.5.0/documents/html/nav_g.png new file mode 100644 index 0000000000000000000000000000000000000000..2093a237a94f6c83e19ec6e5fd42f7ddabdafa81 GIT binary patch literal 95 zcmeAS@N?(olHy`uVBq!ia0vp^j6lrB!3HFm1ilyoDK$?Q$B+ufw|5PB85lU25BhtE tr?otc=hd~V+ws&_A@j8Fiv!KF$B+ufw|5=67#uj90@pIL wZ=Q8~_Ju`#59=RjDrmm`tMD@M=!-l18IR?&vFVdQ&MBb@0HFXL1|%O$WD@{VPM$7~Ar*{o?;hlAFyLXmaDC0y znK1_#cQqJWPES%4Uujug^TE?jMft$}Eq^WaR~)%f)vSNs&gek&x%A9X9sM + + + + + +ESP8266_RTOS_SDK: include/espressif/pwm.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
pwm.h
+
+
+
1 /*
+
2  * ESPRSSIF MIT License
+
3  *
+
4  * Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+
5  *
+
6  * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+
7  * it is free of charge, to any person obtaining a copy of this software and associated
+
8  * documentation files (the "Software"), to deal in the Software without restriction, including
+
9  * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+
10  * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
+
11  * to do so, subject to the following conditions:
+
12  *
+
13  * The above copyright notice and this permission notice shall be included in all copies or
+
14  * substantial portions of the Software.
+
15  *
+
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
22  *
+
23  */
+
24 
+
25 #ifndef __PWM_H__
+
26 #define __PWM_H__
+
27 
+
28 #ifdef __cplusplus
+
29 extern "C" {
+
30 #endif
+
31 
+
48 struct pwm_param {
+
49  uint32 period;
+
50  uint32 freq;
+
51  uint32 duty[8];
+
52 };
+
53 
+
54 #define PWM_DEPTH 1023
+
55 
+
70 void pwm_init(uint32 period, uint32 *duty, uint32 pwm_channel_num, uint32(*pin_info_list)[3]);
+
71 
+
86 void pwm_set_duty(uint32 duty, uint8 channel);
+
87 
+
95 uint32 pwm_get_duty(uint8 channel);
+
96 
+
108 void pwm_set_period(uint32 period);
+
109 
+
117 uint32 pwm_get_period(void);
+
118 
+
128 void pwm_start(void);
+
129 
+
138 #ifdef __cplusplus
+
139 }
+
140 #endif
+
141 
+
142 #endif
+
uint32 freq
Definition: pwm.h:50
+
uint32 period
Definition: pwm.h:49
+
uint32 duty[8]
Definition: pwm.h:51
+
uint32 pwm_get_period(void)
Get PWM period, unit : us.
+
void pwm_set_period(uint32 period)
Set PWM period, unit : us.
+
void pwm_set_duty(uint32 duty, uint8 channel)
Set the duty cycle of a PWM channel.
+
void pwm_init(uint32 period, uint32 *duty, uint32 pwm_channel_num, uint32(*pin_info_list)[3])
PWM function initialization, including GPIO, frequency and duty cycle.
+
uint32 pwm_get_duty(uint8 channel)
Get the duty cycle of a PWM channel.
+
Definition: pwm.h:48
+
void pwm_start(void)
Starts PWM.
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/queue_8h_source.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/queue_8h_source.html new file mode 100644 index 0000000..7a29f96 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/queue_8h_source.html @@ -0,0 +1,336 @@ + + + + + + +ESP8266_RTOS_SDK: include/espressif/queue.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
queue.h
+
+
+
1 /*
+
2  * ESPRSSIF MIT License
+
3  *
+
4  * Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+
5  *
+
6  * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+
7  * it is free of charge, to any person obtaining a copy of this software and associated
+
8  * documentation files (the "Software"), to deal in the Software without restriction, including
+
9  * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+
10  * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
+
11  * to do so, subject to the following conditions:
+
12  *
+
13  * The above copyright notice and this permission notice shall be included in all copies or
+
14  * substantial portions of the Software.
+
15  *
+
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
22  *
+
23  */
+
24 
+
25 #ifndef _SYS_QUEUE_H_
+
26 #define _SYS_QUEUE_H_
+
27 
+
28 #ifdef __cplusplus
+
29 extern "C" {
+
30 #endif
+
31 
+
32 #define QMD_SAVELINK(name, link)
+
33 #define TRASHIT(x)
+
34 
+
35 /*
+
36  * Singly-linked List declarations.
+
37  */
+
38 #define SLIST_HEAD(name, type) \
+
39  struct name { \
+
40  struct type *slh_first; /* first element */ \
+
41  }
+
42 
+
43 #define SLIST_HEAD_INITIALIZER(head) \
+
44  { NULL }
+
45 
+
46 #define SLIST_ENTRY(type) \
+
47  struct { \
+
48  struct type *sle_next; /* next element */ \
+
49  }
+
50 
+
51 /*
+
52  * Singly-linked List functions.
+
53  */
+
54 #define SLIST_EMPTY(head) ((head)->slh_first == NULL)
+
55 
+
56 #define SLIST_FIRST(head) ((head)->slh_first)
+
57 
+
58 #define SLIST_FOREACH(var, head, field) \
+
59  for ((var) = SLIST_FIRST((head)); \
+
60  (var); \
+
61  (var) = SLIST_NEXT((var), field))
+
62 
+
63 #define SLIST_FOREACH_SAFE(var, head, field, tvar) \
+
64  for ((var) = SLIST_FIRST((head)); \
+
65  (var) && ((tvar) = SLIST_NEXT((var), field), 1); \
+
66  (var) = (tvar))
+
67 
+
68 #define SLIST_FOREACH_PREVPTR(var, varp, head, field) \
+
69  for ((varp) = &SLIST_FIRST((head)); \
+
70  ((var) = *(varp)) != NULL; \
+
71  (varp) = &SLIST_NEXT((var), field))
+
72 
+
73 #define SLIST_INIT(head) do { \
+
74  SLIST_FIRST((head)) = NULL; \
+
75  } while (0)
+
76 
+
77 #define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
+
78  SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
+
79  SLIST_NEXT((slistelm), field) = (elm); \
+
80  } while (0)
+
81 
+
82 #define SLIST_INSERT_HEAD(head, elm, field) do { \
+
83  SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \
+
84  SLIST_FIRST((head)) = (elm); \
+
85  } while (0)
+
86 
+
87 #define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
+
88 
+
89 #define SLIST_REMOVE(head, elm, type, field) do { \
+
90  QMD_SAVELINK(oldnext, (elm)->field.sle_next); \
+
91  if (SLIST_FIRST((head)) == (elm)) { \
+
92  SLIST_REMOVE_HEAD((head), field); \
+
93  } \
+
94  else { \
+
95  struct type *curelm = SLIST_FIRST((head)); \
+
96  while (SLIST_NEXT(curelm, field) != (elm)) \
+
97  curelm = SLIST_NEXT(curelm, field); \
+
98  SLIST_REMOVE_AFTER(curelm, field); \
+
99  } \
+
100  TRASHIT(*oldnext); \
+
101  } while (0)
+
102 
+
103 #define SLIST_REMOVE_AFTER(elm, field) do { \
+
104  SLIST_NEXT(elm, field) = \
+
105  SLIST_NEXT(SLIST_NEXT(elm, field), field); \
+
106  } while (0)
+
107 
+
108 #define SLIST_REMOVE_HEAD(head, field) do { \
+
109  SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \
+
110  } while (0)
+
111 
+
112 /*
+
113  * Singly-linked Tail queue declarations.
+
114  */
+
115 #define STAILQ_HEAD(name, type) \
+
116  struct name { \
+
117  struct type *stqh_first; /* first element */ \
+
118  struct type **stqh_last; /* addr of last next element */ \
+
119  }
+
120 
+
121 #define STAILQ_HEAD_INITIALIZER(head) \
+
122  { NULL, &(head).stqh_first }
+
123 
+
124 #define STAILQ_ENTRY(type) \
+
125  struct { \
+
126  struct type *stqe_next; /* next element */ \
+
127  }
+
128 
+
129 /*
+
130  * Singly-linked Tail queue functions.
+
131  */
+
132 #define STAILQ_CONCAT(head1, head2) do { \
+
133  if (!STAILQ_EMPTY((head2))) { \
+
134  *(head1)->stqh_last = (head2)->stqh_first; \
+
135  (head1)->stqh_last = (head2)->stqh_last; \
+
136  STAILQ_INIT((head2)); \
+
137  } \
+
138  } while (0)
+
139 
+
140 #define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
+
141 
+
142 #define STAILQ_FIRST(head) ((head)->stqh_first)
+
143 
+
144 #define STAILQ_FOREACH(var, head, field) \
+
145  for((var) = STAILQ_FIRST((head)); \
+
146  (var); \
+
147  (var) = STAILQ_NEXT((var), field))
+
148 
+
149 
+
150 #define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
+
151  for ((var) = STAILQ_FIRST((head)); \
+
152  (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
+
153  (var) = (tvar))
+
154 
+
155 #define STAILQ_INIT(head) do { \
+
156  STAILQ_FIRST((head)) = NULL; \
+
157  (head)->stqh_last = &STAILQ_FIRST((head)); \
+
158  } while (0)
+
159 
+
160 #define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \
+
161  if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\
+
162  (head)->stqh_last = &STAILQ_NEXT((elm), field); \
+
163  STAILQ_NEXT((tqelm), field) = (elm); \
+
164  } while (0)
+
165 
+
166 #define STAILQ_INSERT_HEAD(head, elm, field) do { \
+
167  if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \
+
168  (head)->stqh_last = &STAILQ_NEXT((elm), field); \
+
169  STAILQ_FIRST((head)) = (elm); \
+
170  } while (0)
+
171 
+
172 #define STAILQ_INSERT_TAIL(head, elm, field) do { \
+
173  STAILQ_NEXT((elm), field) = NULL; \
+
174  *(head)->stqh_last = (elm); \
+
175  (head)->stqh_last = &STAILQ_NEXT((elm), field); \
+
176  } while (0)
+
177 
+
178 #define STAILQ_LAST(head, type, field) \
+
179  (STAILQ_EMPTY((head))? \
+
180  NULL : \
+
181  ((struct type *)(void *)\
+
182  ((char *)((head)->stqh_last) - __offsetof(struct type, field))))
+
183 
+
184 #define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
+
185 
+
186 #define STAILQ_REMOVE(head, elm, type, field) do { \
+
187  QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \
+
188  if (STAILQ_FIRST((head)) == (elm)) { \
+
189  STAILQ_REMOVE_HEAD((head), field); \
+
190  } \
+
191  else { \
+
192  struct type *curelm = STAILQ_FIRST((head)); \
+
193  while (STAILQ_NEXT(curelm, field) != (elm)) \
+
194  curelm = STAILQ_NEXT(curelm, field); \
+
195  STAILQ_REMOVE_AFTER(head, curelm, field); \
+
196  } \
+
197  TRASHIT(*oldnext); \
+
198  } while (0)
+
199 
+
200 #define STAILQ_REMOVE_HEAD(head, field) do { \
+
201  if ((STAILQ_FIRST((head)) = \
+
202  STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \
+
203  (head)->stqh_last = &STAILQ_FIRST((head)); \
+
204  } while (0)
+
205 
+
206 #define STAILQ_REMOVE_AFTER(head, elm, field) do { \
+
207  if ((STAILQ_NEXT(elm, field) = \
+
208  STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \
+
209  (head)->stqh_last = &STAILQ_NEXT((elm), field); \
+
210  } while (0)
+
211 
+
212 #define STAILQ_SWAP(head1, head2, type) do { \
+
213  struct type *swap_first = STAILQ_FIRST(head1); \
+
214  struct type **swap_last = (head1)->stqh_last; \
+
215  STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \
+
216  (head1)->stqh_last = (head2)->stqh_last; \
+
217  STAILQ_FIRST(head2) = swap_first; \
+
218  (head2)->stqh_last = swap_last; \
+
219  if (STAILQ_EMPTY(head1)) \
+
220  (head1)->stqh_last = &STAILQ_FIRST(head1); \
+
221  if (STAILQ_EMPTY(head2)) \
+
222  (head2)->stqh_last = &STAILQ_FIRST(head2); \
+
223  } while (0)
+
224 
+
225 #define STAILQ_INSERT_CHAIN_HEAD(head, elm_chead, elm_ctail, field) do { \
+
226  if ((STAILQ_NEXT(elm_ctail, field) = STAILQ_FIRST(head)) == NULL ) { \
+
227  (head)->stqh_last = &STAILQ_NEXT(elm_ctail, field); \
+
228  } \
+
229  STAILQ_FIRST(head) = (elm_chead); \
+
230  } while (0)
+
231 
+
232 #ifdef __cplusplus
+
233 }
+
234 #endif
+
235 
+
236 #endif /* !_SYS_QUEUE_H_ */
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_0.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_0.html new file mode 100644 index 0000000..1d46950 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_0.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_0.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_0.js new file mode 100644 index 0000000..9a187c6 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_0.js @@ -0,0 +1,8 @@ +var searchData= +[ + ['_5fesp_5fevent',['_esp_event',['../struct__esp__event.html',1,'']]], + ['_5fesp_5ftcp',['_esp_tcp',['../struct__esp__tcp.html',1,'']]], + ['_5fesp_5fudp',['_esp_udp',['../struct__esp__udp.html',1,'']]], + ['_5fos_5ftimer_5ft',['_os_timer_t',['../struct__os__timer__t.html',1,'']]], + ['_5fremot_5finfo',['_remot_info',['../struct__remot__info.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_1.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_1.html new file mode 100644 index 0000000..1fbc509 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_1.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_1.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_1.js new file mode 100644 index 0000000..bde509b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_1.js @@ -0,0 +1,27 @@ +var searchData= +[ + ['aid',['aid',['../structEvent__SoftAPMode__StaConnected__t.html#aea3f00ab9b78748e0e6aa5b46064d866',1,'Event_SoftAPMode_StaConnected_t::aid()'],['../structEvent__SoftAPMode__StaDisconnected__t.html#aea3f00ab9b78748e0e6aa5b46064d866',1,'Event_SoftAPMode_StaDisconnected_t::aid()']]], + ['airkiss_20apis',['AirKiss APIs',['../group__AirKiss__APIs.html',1,'']]], + ['airkiss_5fconfig_5ft',['airkiss_config_t',['../structairkiss__config__t.html',1,'']]], + ['airkiss_5flan_5fcontinue',['AIRKISS_LAN_CONTINUE',['../group__AirKiss__APIs.html#ggaa0ebed8b87dd27c1c1d80c316fe2e691a6c669d0e28f90ea37e6aea8f9084c0d1',1,'airkiss.h']]], + ['airkiss_5flan_5ferr_5fcmd',['AIRKISS_LAN_ERR_CMD',['../group__AirKiss__APIs.html#ggaa0ebed8b87dd27c1c1d80c316fe2e691a30641c2d4b8fee854a90861f957c5923',1,'airkiss.h']]], + ['airkiss_5flan_5ferr_5foverflow',['AIRKISS_LAN_ERR_OVERFLOW',['../group__AirKiss__APIs.html#ggaa0ebed8b87dd27c1c1d80c316fe2e691a3eec80987fe47f20344931bf4afeb4e4',1,'airkiss.h']]], + ['airkiss_5flan_5ferr_5fpake',['AIRKISS_LAN_ERR_PAKE',['../group__AirKiss__APIs.html#ggaa0ebed8b87dd27c1c1d80c316fe2e691aa48241b150e73210e45c81aa9b76137f',1,'airkiss.h']]], + ['airkiss_5flan_5ferr_5fpara',['AIRKISS_LAN_ERR_PARA',['../group__AirKiss__APIs.html#ggaa0ebed8b87dd27c1c1d80c316fe2e691ae4043da2985abd40a90fd198fd607622',1,'airkiss.h']]], + ['airkiss_5flan_5ferr_5fpkg',['AIRKISS_LAN_ERR_PKG',['../group__AirKiss__APIs.html#ggaa0ebed8b87dd27c1c1d80c316fe2e691a14bf764748a58af181c316c2e2ee5322',1,'airkiss.h']]], + ['airkiss_5flan_5fpack',['airkiss_lan_pack',['../group__AirKiss__APIs.html#gab6bab3b00620928bca5e2adc0d2abd31',1,'airkiss.h']]], + ['airkiss_5flan_5fpake_5fready',['AIRKISS_LAN_PAKE_READY',['../group__AirKiss__APIs.html#ggaa0ebed8b87dd27c1c1d80c316fe2e691a5743b4699a34a902a43540149ef380fb',1,'airkiss.h']]], + ['airkiss_5flan_5frecv',['airkiss_lan_recv',['../group__AirKiss__APIs.html#ga7545a7e75de00da0b22c232de602e092',1,'airkiss.h']]], + ['airkiss_5flan_5fret_5ft',['airkiss_lan_ret_t',['../group__AirKiss__APIs.html#gaa0ebed8b87dd27c1c1d80c316fe2e691',1,'airkiss.h']]], + ['airkiss_5flan_5fssdp_5freq',['AIRKISS_LAN_SSDP_REQ',['../group__AirKiss__APIs.html#ggaa0ebed8b87dd27c1c1d80c316fe2e691aad38be677ab42b9f59e773c456695b02',1,'airkiss.h']]], + ['airkiss_5fversion',['airkiss_version',['../group__AirKiss__APIs.html#gad2485fae7edd33913a96ae91fd277acd',1,'airkiss.h']]], + ['ap_5fprobereqrecved',['ap_probereqrecved',['../unionEvent__Info__u.html#ad1cd671ae667ea3fcc720c3f225e0605',1,'Event_Info_u']]], + ['auth_5fchange',['auth_change',['../unionEvent__Info__u.html#a0825220ae21b63db9ddc3125d484187d',1,'Event_Info_u']]], + ['auth_5fmode',['AUTH_MODE',['../group__WiFi__Common__APIs.html#ga49c8969263c0503dbe9811f16c500296',1,'esp_wifi.h']]], + ['auth_5fopen',['AUTH_OPEN',['../group__WiFi__Common__APIs.html#gga49c8969263c0503dbe9811f16c500296a5611249f5c4eb3fde3ad3d20334176c0',1,'esp_wifi.h']]], + ['auth_5fwep',['AUTH_WEP',['../group__WiFi__Common__APIs.html#gga49c8969263c0503dbe9811f16c500296a9026e85ef4d28d1dfa1073b2b5cfb759',1,'esp_wifi.h']]], + ['auth_5fwpa2_5fpsk',['AUTH_WPA2_PSK',['../group__WiFi__Common__APIs.html#gga49c8969263c0503dbe9811f16c500296ac24ee2c2098f0a76fe72aec33847b36c',1,'esp_wifi.h']]], + ['auth_5fwpa_5fpsk',['AUTH_WPA_PSK',['../group__WiFi__Common__APIs.html#gga49c8969263c0503dbe9811f16c500296a90870da11cf3408b057beb4abf9fe1bb',1,'esp_wifi.h']]], + ['auth_5fwpa_5fwpa2_5fpsk',['AUTH_WPA_WPA2_PSK',['../group__WiFi__Common__APIs.html#gga49c8969263c0503dbe9811f16c500296aa01ed8cd33a42c2837a09cdcb5cb5931',1,'esp_wifi.h']]], + ['authmode',['authmode',['../structsoftap__config.html#ad787bf1eaf486b53c52496364469fec0',1,'softap_config::authmode()'],['../structbss__info.html#ad787bf1eaf486b53c52496364469fec0',1,'bss_info::authmode()']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_10.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_10.html new file mode 100644 index 0000000..80581d5 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_10.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_10.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_10.js new file mode 100644 index 0000000..2d14f0c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_10.js @@ -0,0 +1,118 @@ +var searchData= +[ + ['sc_5fcallback_5ft',['sc_callback_t',['../group__Smartconfig__APIs.html#ga98fdb334fead4d1bd026b9ceee8c3db0',1,'smartconfig.h']]], + ['sc_5fstatus',['sc_status',['../group__Smartconfig__APIs.html#gafec33e52eaa14ed795ab28ce69c685e3',1,'smartconfig.h']]], + ['sc_5fstatus_5ffind_5fchannel',['SC_STATUS_FIND_CHANNEL',['../group__Smartconfig__APIs.html#ggafec33e52eaa14ed795ab28ce69c685e3a30fee0de55f059ac14821f8e2b22ac03',1,'smartconfig.h']]], + ['sc_5fstatus_5fgetting_5fssid_5fpswd',['SC_STATUS_GETTING_SSID_PSWD',['../group__Smartconfig__APIs.html#ggafec33e52eaa14ed795ab28ce69c685e3aefc9b644b16531defe122b7316cea0c0',1,'smartconfig.h']]], + ['sc_5fstatus_5flink',['SC_STATUS_LINK',['../group__Smartconfig__APIs.html#ggafec33e52eaa14ed795ab28ce69c685e3aae1dcaae9b8358bd43499bbca2e0bf95',1,'smartconfig.h']]], + ['sc_5fstatus_5flink_5fover',['SC_STATUS_LINK_OVER',['../group__Smartconfig__APIs.html#ggafec33e52eaa14ed795ab28ce69c685e3a1ae1253a12888c150c36cd30f56394dc',1,'smartconfig.h']]], + ['sc_5fstatus_5fwait',['SC_STATUS_WAIT',['../group__Smartconfig__APIs.html#ggafec33e52eaa14ed795ab28ce69c685e3a3de75e54ab5d15e0aa697d2d35adc363',1,'smartconfig.h']]], + ['sc_5ftype',['sc_type',['../group__Smartconfig__APIs.html#ga533261c0af94cdbb04fe90f452af9b9d',1,'smartconfig.h']]], + ['sc_5ftype_5fairkiss',['SC_TYPE_AIRKISS',['../group__Smartconfig__APIs.html#gga533261c0af94cdbb04fe90f452af9b9da6254d899f4bf164fdb0f3dd778c206e9',1,'smartconfig.h']]], + ['sc_5ftype_5fesptouch',['SC_TYPE_ESPTOUCH',['../group__Smartconfig__APIs.html#gga533261c0af94cdbb04fe90f452af9b9dabae45491cc05b00bd1b069bb61e37b01',1,'smartconfig.h']]], + ['sc_5ftype_5fesptouch_5fairkiss',['SC_TYPE_ESPTOUCH_AIRKISS',['../group__Smartconfig__APIs.html#gga533261c0af94cdbb04fe90f452af9b9da50e8065c00b088cdb87b8b0ded4a853c',1,'smartconfig.h']]], + ['scan_5fconfig',['scan_config',['../structscan__config.html',1,'']]], + ['scan_5fdone',['scan_done',['../unionEvent__Info__u.html#a1aec02af40844b393be6f3909f961c58',1,'Event_Info_u']]], + ['scan_5fdone_5fcb_5ft',['scan_done_cb_t',['../group__Station__APIs.html#ga953373c37a80c04a576ac03986a1ebfb',1,'esp_sta.h']]], + ['sent_5fcallback',['sent_callback',['../structespconn.html#aee31e3e88191acb2de9dbbc43a40cd47',1,'espconn']]], + ['show_5fhidden',['show_hidden',['../structscan__config.html#a34fae8706d36b49d6462103708a8f306',1,'scan_config']]], + ['smartconfig_20apis',['Smartconfig APIs',['../group__Smartconfig__APIs.html',1,'']]], + ['smartconfig_5fget_5fversion',['smartconfig_get_version',['../group__Smartconfig__APIs.html#ga9537246ce540bc1e1a294de687d488bf',1,'smartconfig.h']]], + ['smartconfig_5fset_5ftype',['smartconfig_set_type',['../group__Smartconfig__APIs.html#ga14d5f55176a12436d58014272f6df156',1,'smartconfig.h']]], + ['smartconfig_5fstart',['smartconfig_start',['../group__Smartconfig__APIs.html#ga390ec2c5af28b29044899c8ffd016b04',1,'smartconfig.h']]], + ['smartconfig_5fstop',['smartconfig_stop',['../group__Smartconfig__APIs.html#ga85819fc5109441eae24e4262ca34bd48',1,'smartconfig.h']]], + ['sockaddrin',['sockaddrin',['../structupgrade__server__info.html#aff5a0f0a52dbedb0aa98a1cc408ba7df',1,'upgrade_server_info']]], + ['softap_20apis',['SoftAP APIs',['../group__SoftAP__APIs.html',1,'']]], + ['softap_5fconfig',['softap_config',['../structsoftap__config.html',1,'']]], + ['softap_5fif',['SOFTAP_IF',['../group__WiFi__Common__APIs.html#ggaea3f7e6b27f1008eb9fa2d0fac3de857af55135c54ee2a64ba9c52a74cf2fd189',1,'esp_wifi.h']]], + ['softap_5fmode',['SOFTAP_MODE',['../group__WiFi__Common__APIs.html#gga2cdd09724a071506f717d721f6aa633ca92e54e4df3bbe26a86fee10322867a8f',1,'esp_wifi.h']]], + ['spi_20driver_20apis',['SPI Driver APIs',['../group__SPI__Driver__APIs.html',1,'']]], + ['spi_5fflash_5ferase_5fsector',['spi_flash_erase_sector',['../group__SPI__Driver__APIs.html#ga3210ddd52247977cff3d018bf34f9048',1,'spi_flash.h']]], + ['spi_5fflash_5fget_5fid',['spi_flash_get_id',['../group__SPI__Driver__APIs.html#ga9ffc628fbfc74b51a78ed0a03c3f8dd0',1,'spi_flash.h']]], + ['spi_5fflash_5fread',['spi_flash_read',['../group__SPI__Driver__APIs.html#gacfd871ce143884d5c3dfb456024b0096',1,'spi_flash.h']]], + ['spi_5fflash_5fread_5fstatus',['spi_flash_read_status',['../group__SPI__Driver__APIs.html#ga8bd9176a0db21f8a04c0ab8792b74fec',1,'spi_flash.h']]], + ['spi_5fflash_5fresult_5ferr',['SPI_FLASH_RESULT_ERR',['../group__SPI__Driver__APIs.html#gga7546515bb162fd2bb252ebe20fd92dbea6a7e104b6106ddf6a7fa6e2fbe93edca',1,'spi_flash.h']]], + ['spi_5fflash_5fresult_5fok',['SPI_FLASH_RESULT_OK',['../group__SPI__Driver__APIs.html#gga7546515bb162fd2bb252ebe20fd92dbea8c0e5ba08fbb8fbe8f5f1a6eac6e01cc',1,'spi_flash.h']]], + ['spi_5fflash_5fresult_5ftimeout',['SPI_FLASH_RESULT_TIMEOUT',['../group__SPI__Driver__APIs.html#gga7546515bb162fd2bb252ebe20fd92dbea266272773eeee7e649575a8ad4f5d119',1,'spi_flash.h']]], + ['spi_5fflash_5fsec_5fsize',['SPI_FLASH_SEC_SIZE',['../group__SPI__Driver__APIs.html#ga518257817c69fec25290c1bebad544b0',1,'SPI_FLASH_SEC_SIZE(): spi_flash.h'],['../group__Upgrade__APIs.html#ga518257817c69fec25290c1bebad544b0',1,'SPI_FLASH_SEC_SIZE(): upgrade.h']]], + ['spi_5fflash_5fset_5fread_5ffunc',['spi_flash_set_read_func',['../group__SPI__Driver__APIs.html#ga826a3caeec9fd019d6a30c3113d1547e',1,'spi_flash.h']]], + ['spi_5fflash_5fwrite',['spi_flash_write',['../group__SPI__Driver__APIs.html#ga97906813255238cdb0da4d21040abf90',1,'spi_flash.h']]], + ['spi_5fflash_5fwrite_5fstatus',['spi_flash_write_status',['../group__SPI__Driver__APIs.html#ga0e1358b06ac94b1e94c6aec83d034c56',1,'spi_flash.h']]], + ['spiffs_20apis',['Spiffs APIs',['../group__Spiffs__APIs.html',1,'']]], + ['spiflashchip',['SpiFlashChip',['../structSpiFlashChip.html',1,'']]], + ['spiflashopresult',['SpiFlashOpResult',['../group__SPI__Driver__APIs.html#ga7546515bb162fd2bb252ebe20fd92dbe',1,'spi_flash.h']]], + ['ssc_20apis',['SSC APIs',['../group__SSC__APIs.html',1,'']]], + ['ssc_5fattach',['ssc_attach',['../group__SSC__APIs.html#ga43430a78447488ff0f9b854a55c52c15',1,'esp_ssc.h']]], + ['ssc_5fparam_5flen',['ssc_param_len',['../group__SSC__APIs.html#gad4623d4bbefc7aa8609027c5acaa21f1',1,'esp_ssc.h']]], + ['ssc_5fparam_5fstr',['ssc_param_str',['../group__SSC__APIs.html#ga3d6124b4b604fa47f591fbfd44667d10',1,'esp_ssc.h']]], + ['ssc_5fparse_5fparam',['ssc_parse_param',['../group__SSC__APIs.html#gaab6bf99fc9487915cec7b2fe690ef08c',1,'esp_ssc.h']]], + ['ssc_5fregister',['ssc_register',['../group__SSC__APIs.html#ga9a8525423b629764cd90e132bf3d8c0b',1,'esp_ssc.h']]], + ['ssid',['ssid',['../structsoftap__config.html#ad09c9f62c8c9f7a27707b46a0cd6af0e',1,'softap_config::ssid()'],['../structstation__config.html#ad09c9f62c8c9f7a27707b46a0cd6af0e',1,'station_config::ssid()'],['../structscan__config.html#a19b5d447df6e5c3feed382b08e9ad556',1,'scan_config::ssid()'],['../structbss__info.html#ad09c9f62c8c9f7a27707b46a0cd6af0e',1,'bss_info::ssid()'],['../structEvent__StaMode__Connected__t.html#ad09c9f62c8c9f7a27707b46a0cd6af0e',1,'Event_StaMode_Connected_t::ssid()'],['../structEvent__StaMode__Disconnected__t.html#ad09c9f62c8c9f7a27707b46a0cd6af0e',1,'Event_StaMode_Disconnected_t::ssid()']]], + ['ssid_5fhidden',['ssid_hidden',['../structsoftap__config.html#afea88ca4deb29f0ff7b0b41bb8ec2fec',1,'softap_config']]], + ['ssid_5flen',['ssid_len',['../structsoftap__config.html#a4f59d44ab2571442c2da0e50047380da',1,'softap_config::ssid_len()'],['../structbss__info.html#a4f59d44ab2571442c2da0e50047380da',1,'bss_info::ssid_len()'],['../structEvent__StaMode__Connected__t.html#a4f59d44ab2571442c2da0e50047380da',1,'Event_StaMode_Connected_t::ssid_len()'],['../structEvent__StaMode__Disconnected__t.html#a4f59d44ab2571442c2da0e50047380da',1,'Event_StaMode_Disconnected_t::ssid_len()']]], + ['sta_5fconnected',['sta_connected',['../unionEvent__Info__u.html#a1edd94c6f778ad482755a58d1019c9fc',1,'Event_Info_u']]], + ['sta_5fdisconnected',['sta_disconnected',['../unionEvent__Info__u.html#a9c7023c6473d664561a09253f6eedf98',1,'Event_Info_u']]], + ['stailq_5fentry',['STAILQ_ENTRY',['../structstation__info.html#aad64fb4a210e02bd3b25891e29d39a95',1,'station_info::STAILQ_ENTRY()'],['../structbss__info.html#a792bb0f673392f8281c38ea1e3568073',1,'bss_info::STAILQ_ENTRY()']]], + ['start_5fip',['start_ip',['../structdhcps__lease.html#ad1290ecd3f8204d196999369712a586e',1,'dhcps_lease']]], + ['state',['state',['../struct__remot__info.html#ac3a8d9cd6eef4ec46bcabfd07120e40c',1,'_remot_info::state()'],['../structespconn.html#ac3a8d9cd6eef4ec46bcabfd07120e40c',1,'espconn::state()']]], + ['station_20apis',['Station APIs',['../group__Station__APIs.html',1,'']]], + ['station_5fconfig',['station_config',['../structstation__config.html',1,'']]], + ['station_5fconnect_5ffail',['STATION_CONNECT_FAIL',['../group__Station__APIs.html#gga4c23fd73def991ebbce2a16bf7d474bca25d788a7722116d2bf2b26bb6402d118',1,'esp_sta.h']]], + ['station_5fconnecting',['STATION_CONNECTING',['../group__Station__APIs.html#gga4c23fd73def991ebbce2a16bf7d474bcaff0fbe033edf483a60063bdfcf1e39b9',1,'esp_sta.h']]], + ['station_5fgot_5fip',['STATION_GOT_IP',['../group__Station__APIs.html#gga4c23fd73def991ebbce2a16bf7d474bca6df279173c26c3e7b1c65fdd41b50889',1,'esp_sta.h']]], + ['station_5fidle',['STATION_IDLE',['../group__Station__APIs.html#gga4c23fd73def991ebbce2a16bf7d474bca27894ff65729ce4cf0a322e2e3a71c04',1,'esp_sta.h']]], + ['station_5fif',['STATION_IF',['../group__WiFi__Common__APIs.html#ggaea3f7e6b27f1008eb9fa2d0fac3de857a71d2c1b8dd45be5f720c155153cd6803',1,'esp_wifi.h']]], + ['station_5finfo',['station_info',['../structstation__info.html',1,'']]], + ['station_5fmode',['STATION_MODE',['../group__WiFi__Common__APIs.html#gga2cdd09724a071506f717d721f6aa633cabd03eae7aff57049c70079dc7877de47',1,'esp_wifi.h']]], + ['station_5fno_5fap_5ffound',['STATION_NO_AP_FOUND',['../group__Station__APIs.html#gga4c23fd73def991ebbce2a16bf7d474bca95a3d4b77c93e76281ff5355f24acfd0',1,'esp_sta.h']]], + ['station_5fstatus',['STATION_STATUS',['../group__Station__APIs.html#ga4c23fd73def991ebbce2a16bf7d474bc',1,'esp_sta.h']]], + ['station_5fwrong_5fpassword',['STATION_WRONG_PASSWORD',['../group__Station__APIs.html#gga4c23fd73def991ebbce2a16bf7d474bcaa9d77c934ee5b916f3ff0743204f3d7a',1,'esp_sta.h']]], + ['stationap_5fmode',['STATIONAP_MODE',['../group__WiFi__Common__APIs.html#gga2cdd09724a071506f717d721f6aa633caa5510a47f526ca8c4de330fd05fb5032',1,'esp_wifi.h']]], + ['status',['status',['../structEvent__StaMode__ScanDone__t.html#af91a4c0bd977c78af5dd4c112bb0bc47',1,'Event_StaMode_ScanDone_t']]], + ['sys_5fboot_5fenhance_5fmode',['SYS_BOOT_ENHANCE_MODE',['../group__System__boot__APIs.html#ga04009897446ea5a0c5aa3d3c6ef01357',1,'esp_system.h']]], + ['sys_5fboot_5fnormal_5fbin',['SYS_BOOT_NORMAL_BIN',['../group__System__boot__APIs.html#ga52853f4dcc9a1208fbb366e59efb3054',1,'esp_system.h']]], + ['sys_5fboot_5fnormal_5fmode',['SYS_BOOT_NORMAL_MODE',['../group__System__boot__APIs.html#ga993bbfc899c5495e5600dea34e5400bd',1,'esp_system.h']]], + ['sys_5fboot_5ftest_5fbin',['SYS_BOOT_TEST_BIN',['../group__System__boot__APIs.html#gabcadf084776b83e26f0f3db8f0bdfbe1',1,'esp_system.h']]], + ['system_5fadc_5fread',['system_adc_read',['../group__System__APIs.html#ga3b49ed94048da366d384364482c5ae43',1,'esp_system.h']]], + ['system_20apis',['System APIs',['../group__System__APIs.html',1,'']]], + ['system_5fdeep_5fsleep',['system_deep_sleep',['../group__System__APIs.html#ga2b2d62411a8baa3b7fec777d281397e1',1,'esp_system.h']]], + ['system_5fdeep_5fsleep_5fset_5foption',['system_deep_sleep_set_option',['../group__System__APIs.html#gaaaf7c29067d92bf6c03747b4ad2c2bf6',1,'esp_system.h']]], + ['system_5fevent',['SYSTEM_EVENT',['../group__WiFi__Common__APIs.html#gaeecbdf938220e31d3d52cd49c57400bd',1,'esp_wifi.h']]], + ['system_5fget_5fboot_5fmode',['system_get_boot_mode',['../group__System__boot__APIs.html#ga0663faaa88f4c899daf21e54400dfed0',1,'esp_system.h']]], + ['system_5fget_5fboot_5fversion',['system_get_boot_version',['../group__System__boot__APIs.html#gadecd4fbc78bf128281c5e48055155864',1,'esp_system.h']]], + ['system_5fget_5fchip_5fid',['system_get_chip_id',['../group__System__APIs.html#ga86228f8d572c91ec871684121dad0647',1,'esp_system.h']]], + ['system_5fget_5fcpu_5ffreq',['system_get_cpu_freq',['../group__System__boot__APIs.html#ga9ed4a3a5a4d57e26ed5250a423a5c3a0',1,'esp_system.h']]], + ['system_5fget_5fflash_5fsize_5fmap',['system_get_flash_size_map',['../group__System__boot__APIs.html#gae173ade9144230f0b8f950a804d4afd5',1,'esp_system.h']]], + ['system_5fget_5ffree_5fheap_5fsize',['system_get_free_heap_size',['../group__System__APIs.html#ga258edd68184bb78f062a3b375dca997c',1,'esp_system.h']]], + ['system_5fget_5frst_5finfo',['system_get_rst_info',['../group__System__APIs.html#ga9f0263b1c227015248c7020e41d787b9',1,'esp_system.h']]], + ['system_5fget_5frtc_5ftime',['system_get_rtc_time',['../group__System__APIs.html#gaff1e2f744888e01d75bbb1cb2fdee0cb',1,'esp_system.h']]], + ['system_5fget_5fsdk_5fversion',['system_get_sdk_version',['../group__System__APIs.html#ga82dfc665528462dbaa945e45512b8c93',1,'esp_system.h']]], + ['system_5fget_5ftime',['system_get_time',['../group__System__APIs.html#gaff40fbcef002e346e8f36c378cf75d86',1,'esp_system.h']]], + ['system_5fget_5fuserbin_5faddr',['system_get_userbin_addr',['../group__System__boot__APIs.html#gaa2fd426b0a2cb0bf77cbc0868ad63e77',1,'esp_system.h']]], + ['system_5fget_5fvdd33',['system_get_vdd33',['../group__System__APIs.html#gacf1baad08cac941b54b44126045e38cc',1,'esp_system.h']]], + ['system_5fparam_5fload',['system_param_load',['../group__System__APIs.html#ga753aade115708d360f25bff422ef1f55',1,'esp_system.h']]], + ['system_5fparam_5fsave_5fwith_5fprotect',['system_param_save_with_protect',['../group__System__APIs.html#gae68a7b6345630e42fde3e827108571e0',1,'esp_system.h']]], + ['system_5fphy_5fset_5fmax_5ftpw',['system_phy_set_max_tpw',['../group__System__APIs.html#gafc39ba5754615bd82e13302e289651ee',1,'esp_system.h']]], + ['system_5fphy_5fset_5frfoption',['system_phy_set_rfoption',['../group__System__APIs.html#ga96d92897e242b7f1bcd484e58f3b4a66',1,'esp_system.h']]], + ['system_5fphy_5fset_5ftpw_5fvia_5fvdd33',['system_phy_set_tpw_via_vdd33',['../group__System__APIs.html#ga7d3301798674f7ed1163f0b2ed333c44',1,'esp_system.h']]], + ['system_5fprint_5fmeminfo',['system_print_meminfo',['../group__System__APIs.html#ga3103885b6ff682cac77fea78c2b73425',1,'esp_system.h']]], + ['system_5frestart',['system_restart',['../group__System__APIs.html#ga80e0119dbfcaaa43025fe2135d3d1efc',1,'esp_system.h']]], + ['system_5frestart_5fenhance',['system_restart_enhance',['../group__System__boot__APIs.html#gaf7b2162f7ed788f3e8d8d90b27f60e7f',1,'esp_system.h']]], + ['system_5frestore',['system_restore',['../group__System__APIs.html#gae04bb6e4dba5ca53c4f5af629c235bec',1,'esp_system.h']]], + ['system_5frtc_5fclock_5fcali_5fproc',['system_rtc_clock_cali_proc',['../group__System__APIs.html#ga53909af3917e5dafc57c5a4d75e6ca2a',1,'esp_system.h']]], + ['system_5frtc_5fmem_5fread',['system_rtc_mem_read',['../group__System__APIs.html#gac89e6906018b3f4ccd1ba4059f344d5e',1,'esp_system.h']]], + ['system_5frtc_5fmem_5fwrite',['system_rtc_mem_write',['../group__System__APIs.html#ga669af802153a408dbf9b8b34697e34e2',1,'esp_system.h']]], + ['system_5fuart_5fde_5fswap',['system_uart_de_swap',['../group__System__APIs.html#ga2fe928c2d760669eaa7928b6e00c615c',1,'esp_system.h']]], + ['system_5fuart_5fswap',['system_uart_swap',['../group__System__APIs.html#ga6fc697cba1894da7a66d8816ec590682',1,'esp_system.h']]], + ['system_5fupdate_5fcpu_5ffreq',['system_update_cpu_freq',['../group__System__boot__APIs.html#ga0590aa925e7f87eb6cfc81d5577fc98a',1,'esp_system.h']]], + ['system_5fupgrade',['system_upgrade',['../group__Upgrade__APIs.html#ga738472f97b8dc72342cb3eb6b984d0bd',1,'upgrade.h']]], + ['system_5fupgrade_5fdeinit',['system_upgrade_deinit',['../group__Upgrade__APIs.html#ga643d7df496074bba1c6d165a3b5c7296',1,'upgrade.h']]], + ['system_5fupgrade_5fflag_5fcheck',['system_upgrade_flag_check',['../group__Upgrade__APIs.html#ga18b07d5b7a8b951a41da50506e03c837',1,'esp_system.h']]], + ['system_5fupgrade_5fflag_5fset',['system_upgrade_flag_set',['../group__Upgrade__APIs.html#ga6760e9df629662611372bcdfca7a4f77',1,'esp_system.h']]], + ['system_5fupgrade_5finit',['system_upgrade_init',['../group__Upgrade__APIs.html#ga9b7abd9fa4790f5807c20a24e5e9a51a',1,'upgrade.h']]], + ['system_5fupgrade_5freboot',['system_upgrade_reboot',['../group__Upgrade__APIs.html#gafbc93a806155a9cf65d25119df0c6b1d',1,'esp_system.h']]], + ['system_5fupgrade_5fstart',['system_upgrade_start',['../group__Upgrade__APIs.html#ga9575df7b73865f9a373637c1d7a3763f',1,'upgrade.h']]], + ['system_5fupgrade_5fuserbin_5fcheck',['system_upgrade_userbin_check',['../group__Upgrade__APIs.html#gad04181af74584d470c30d6c21dd2db85',1,'esp_system.h']]], + ['software_20timer_20apis',['Software timer APIs',['../group__Timer__APIs.html',1,'']]], + ['sniffer_20apis',['Sniffer APIs',['../group__WiFi__Sniffer__APIs.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_11.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_11.html new file mode 100644 index 0000000..bb6241b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_11.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_11.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_11.js new file mode 100644 index 0000000..9bc6488 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_11.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['type',['type',['../structespconn.html#a2431ce92ac5c0bda2b6e5812ba8e3323',1,'espconn']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_12.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_12.html new file mode 100644 index 0000000..fe93a5b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_12.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_12.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_12.js new file mode 100644 index 0000000..7144d06 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_12.js @@ -0,0 +1,37 @@ +var searchData= +[ + ['uart_5fclearintrstatus',['UART_ClearIntrStatus',['../group__UART__Driver__APIs.html#ga805fa76dba1011c2c84c986fa6b55bad',1,'uart.h']]], + ['uart_5fconfigtypedef',['UART_ConfigTypeDef',['../structUART__ConfigTypeDef.html',1,'']]], + ['uart_20driver_20apis',['UART Driver APIs',['../group__UART__Driver__APIs.html',1,'']]], + ['uart_5finit_5fnew',['uart_init_new',['../group__UART__Driver__APIs.html#gaf76603d6634a53a0f678ef6451fe2b4e',1,'uart.h']]], + ['uart_5fintr_5fhandler_5fregister',['UART_intr_handler_register',['../group__UART__Driver__APIs.html#ga09240ead2da85d23b9af33585c972eb7',1,'uart.h']]], + ['uart_5fintrconfig',['UART_IntrConfig',['../group__UART__Driver__APIs.html#ga11d7ecf6eb666e29f19ed1c01d70221f',1,'uart.h']]], + ['uart_5fintrconftypedef',['UART_IntrConfTypeDef',['../structUART__IntrConfTypeDef.html',1,'']]], + ['uart_5fparamconfig',['UART_ParamConfig',['../group__UART__Driver__APIs.html#ga7acf0ca55c5f3449933864112e054bfc',1,'uart.h']]], + ['uart_5fresetfifo',['UART_ResetFifo',['../group__UART__Driver__APIs.html#ga408ab554bfe539dbba0561ec6c2794c7',1,'uart.h']]], + ['uart_5fsetbaudrate',['UART_SetBaudrate',['../group__UART__Driver__APIs.html#ga09596c76ab170e0440ea64ca9b677680',1,'uart.h']]], + ['uart_5fsetflowctrl',['UART_SetFlowCtrl',['../group__UART__Driver__APIs.html#ga5989d1e1de100edc2f7a2f5254053b6a',1,'uart.h']]], + ['uart_5fsetintrena',['UART_SetIntrEna',['../group__UART__Driver__APIs.html#ga0d23d8ca7457e4785f514ae5fbb761f0',1,'uart.h']]], + ['uart_5fsetlineinverse',['UART_SetLineInverse',['../group__UART__Driver__APIs.html#ga66f2b126442f8b9e0ea8472a0c7ffee6',1,'uart.h']]], + ['uart_5fsetparity',['UART_SetParity',['../group__UART__Driver__APIs.html#ga0b10d5990a126b715cfc4f1bf018148a',1,'uart.h']]], + ['uart_5fsetprintport',['UART_SetPrintPort',['../group__UART__Driver__APIs.html#gad7d853939e394a209f41b98e99778cc2',1,'uart.h']]], + ['uart_5fsetstopbits',['UART_SetStopBits',['../group__UART__Driver__APIs.html#ga52fbc6f996d0b4b8ef7354932d0bac54',1,'uart.h']]], + ['uart_5fsetwordlength',['UART_SetWordLength',['../group__UART__Driver__APIs.html#gad0f29e4f5d178e756bbc42711044dae2',1,'uart.h']]], + ['uart_5fwaittxfifoempty',['UART_WaitTxFifoEmpty',['../group__UART__Driver__APIs.html#gafd23b8eef2c570b8c785b83aa2a5caee',1,'uart.h']]], + ['upgrade_20apis',['Upgrade APIs',['../group__Upgrade__APIs.html',1,'']]], + ['upgrade_5fflag',['upgrade_flag',['../structupgrade__server__info.html#a983ad0843b8753df3491570b65a20348',1,'upgrade_server_info']]], + ['upgrade_5fflag_5ffinish',['UPGRADE_FLAG_FINISH',['../group__Upgrade__APIs.html#ga568d84b95c752e811a27a337830c3a54',1,'upgrade.h']]], + ['upgrade_5fflag_5fidle',['UPGRADE_FLAG_IDLE',['../group__Upgrade__APIs.html#gae9af3da1e7d88b1e0f353d45059f6f1b',1,'upgrade.h']]], + ['upgrade_5fflag_5fstart',['UPGRADE_FLAG_START',['../group__Upgrade__APIs.html#gaa45c4c3f3b5ed0d3070af7cf0fe151a9',1,'upgrade.h']]], + ['upgrade_5ffw_5fbin1',['UPGRADE_FW_BIN1',['../group__Upgrade__APIs.html#ga3b1051980757f4b853a8e436397e0fa6',1,'upgrade.h']]], + ['upgrade_5ffw_5fbin2',['UPGRADE_FW_BIN2',['../group__Upgrade__APIs.html#ga9c5730b00a161df609340303bd6b4647',1,'upgrade.h']]], + ['upgrade_5fserver_5finfo',['upgrade_server_info',['../structupgrade__server__info.html',1,'']]], + ['upgrade_5fstates_5fcheck_5fcallback',['upgrade_states_check_callback',['../group__Upgrade__APIs.html#ga2897893fe6b22f7cd3159e57370dee7d',1,'upgrade.h']]], + ['upgrade_5fversion',['upgrade_version',['../structupgrade__server__info.html#a54bc0d4687b1f9b5f8671bd157abd94d',1,'upgrade_server_info']]], + ['url',['url',['../structupgrade__server__info.html#aa68fc9d50895a4a8df09b200ae030867',1,'upgrade_server_info']]], + ['user_5fbin1',['USER_BIN1',['../group__Upgrade__APIs.html#ga72e5aaa69793c72dc40998cb4b76168c',1,'upgrade.h']]], + ['user_5fbin2',['USER_BIN2',['../group__Upgrade__APIs.html#ga7c4188e60c7cc5293d25dfb3b34dd224',1,'upgrade.h']]], + ['user_5fie_5fmanufacturer_5frecv_5fcb_5ft',['user_ie_manufacturer_recv_cb_t',['../group__WiFi__User__IE__APIs.html#ga48a93836b1b5d84a69592b90613cf01f',1,'esp_wifi.h']]], + ['user_5fspi_5fflash_5fread',['user_spi_flash_read',['../group__SPI__Driver__APIs.html#gacda8d0eb9ddb859ea21726108d825f17',1,'spi_flash.h']]], + ['user_20ie_20apis',['User IE APIs',['../group__WiFi__User__IE__APIs.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_13.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_13.html new file mode 100644 index 0000000..cb938b9 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_13.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_13.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_13.js new file mode 100644 index 0000000..9c647fe --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_13.js @@ -0,0 +1,103 @@ +var searchData= +[ + ['wifi_20related_20apis',['WiFi Related APIs',['../group__WiFi__APIs.html',1,'']]], + ['wifi_5fevent_5fhandler_5fcb_5ft',['wifi_event_handler_cb_t',['../group__WiFi__Common__APIs.html#gaa7cc45ed46e00f9035baeb90e77f3996',1,'esp_wifi.h']]], + ['wifi_5ffpm_5fclose',['wifi_fpm_close',['../group__WiFi__Force__Sleep__APIs.html#gaa20f76f974962fe47ae31c0f65b657c1',1,'esp_wifi.h']]], + ['wifi_5ffpm_5fdo_5fsleep',['wifi_fpm_do_sleep',['../group__WiFi__Force__Sleep__APIs.html#ga51dffd1b54e5a225378632d08162b048',1,'esp_wifi.h']]], + ['wifi_5ffpm_5fdo_5fwakeup',['wifi_fpm_do_wakeup',['../group__WiFi__Force__Sleep__APIs.html#gaa0c860b5a8fac128712596db935b174c',1,'esp_wifi.h']]], + ['wifi_5ffpm_5fget_5fsleep_5ftype',['wifi_fpm_get_sleep_type',['../group__WiFi__Force__Sleep__APIs.html#ga46b8069d18c7d8657dae947bc3c47faa',1,'esp_wifi.h']]], + ['wifi_5ffpm_5fopen',['wifi_fpm_open',['../group__WiFi__Force__Sleep__APIs.html#ga18a528b1a07c371a92fec9668a8526bf',1,'esp_wifi.h']]], + ['wifi_5ffpm_5fset_5fsleep_5ftype',['wifi_fpm_set_sleep_type',['../group__WiFi__Force__Sleep__APIs.html#ga8fbbe4c4d1399e6e39bb8ae1f0c10737',1,'esp_wifi.h']]], + ['wifi_5ffpm_5fset_5fwakeup_5fcb',['wifi_fpm_set_wakeup_cb',['../group__WiFi__Force__Sleep__APIs.html#ga60a15e23e9026636a71251e0fe46b16d',1,'esp_wifi.h']]], + ['wifi_5fget_5fchannel',['wifi_get_channel',['../group__WiFi__Sniffer__APIs.html#ga152796dafaf3baffe84e1a45ff05b5e0',1,'esp_wifi.h']]], + ['wifi_5fget_5fip_5finfo',['wifi_get_ip_info',['../group__WiFi__Common__APIs.html#ga536807ea21e2273344dbc4711a25f4a6',1,'esp_wifi.h']]], + ['wifi_5fget_5fmacaddr',['wifi_get_macaddr',['../group__WiFi__Common__APIs.html#gafe236024d7e749725b8c089fe0cedfba',1,'esp_wifi.h']]], + ['wifi_5fget_5fopmode',['wifi_get_opmode',['../group__WiFi__Common__APIs.html#ga8cb277f2cbfd5778c72c2d66375e0caf',1,'esp_wifi.h']]], + ['wifi_5fget_5fopmode_5fdefault',['wifi_get_opmode_default',['../group__WiFi__Common__APIs.html#ga68a1594d0a0a830d5c57c7fdbe03faf9',1,'esp_wifi.h']]], + ['wifi_5fget_5fphy_5fmode',['wifi_get_phy_mode',['../group__WiFi__Common__APIs.html#gacf50acde50fcc315ee58099a9c158d2a',1,'esp_wifi.h']]], + ['wifi_5fget_5fsleep_5ftype',['wifi_get_sleep_type',['../group__WiFi__Common__APIs.html#ga26409ea2492ddd98181cb17b789be30f',1,'esp_wifi.h']]], + ['wifi_5fget_5fuser_5ffixed_5frate',['wifi_get_user_fixed_rate',['../group__WiFi__Rate__Control__APIs.html#ga0f8d0671a13fbfa34d30d56857018228',1,'esp_wifi.h']]], + ['wifi_5fget_5fuser_5flimit_5frate_5fmask',['wifi_get_user_limit_rate_mask',['../group__WiFi__Rate__Control__APIs.html#ga4c4b499ff0ebba2e74c3168f3e354052',1,'esp_wifi.h']]], + ['wifi_5finterface',['WIFI_INTERFACE',['../group__WiFi__Common__APIs.html#gaea3f7e6b27f1008eb9fa2d0fac3de857',1,'esp_wifi.h']]], + ['wifi_5fmode',['WIFI_MODE',['../group__WiFi__Common__APIs.html#ga2cdd09724a071506f717d721f6aa633c',1,'esp_wifi.h']]], + ['wifi_5fphy_5fmode',['WIFI_PHY_MODE',['../group__WiFi__Common__APIs.html#ga75ce0bfb28d23bd9b671608d38da34ea',1,'esp_wifi.h']]], + ['wifi_5fpromiscuous_5fcb_5ft',['wifi_promiscuous_cb_t',['../group__WiFi__Sniffer__APIs.html#gaec780f59bcc8f01c0a4098da86bea999',1,'esp_wifi.h']]], + ['wifi_5fpromiscuous_5fenable',['wifi_promiscuous_enable',['../group__WiFi__Sniffer__APIs.html#ga39964266988f76d3c08d65820d289410',1,'esp_wifi.h']]], + ['wifi_5fpromiscuous_5fset_5fmac',['wifi_promiscuous_set_mac',['../group__WiFi__Sniffer__APIs.html#ga2cc97dea2fc14040123a9b8fb623d284',1,'esp_wifi.h']]], + ['wifi_5fregister_5frfid_5flocp_5frecv_5fcb',['wifi_register_rfid_locp_recv_cb',['../group__WiFi__Common__APIs.html#gaba41e6e0d6e37bd683a4c45d3459a59f',1,'esp_wifi.h']]], + ['wifi_5fregister_5fsend_5fpkt_5ffreedom_5fcb',['wifi_register_send_pkt_freedom_cb',['../group__WiFi__Common__APIs.html#gaad8a8f2cbb0bf2b93d63e63b84d57fb8',1,'esp_wifi.h']]], + ['wifi_5fregister_5fuser_5fie_5fmanufacturer_5frecv_5fcb',['wifi_register_user_ie_manufacturer_recv_cb',['../group__WiFi__User__IE__APIs.html#gaef66bcf79ecaaf03da9c9f1a484b192f',1,'esp_wifi.h']]], + ['wifi_5frfid_5flocp_5frecv_5fclose',['wifi_rfid_locp_recv_close',['../group__WiFi__Common__APIs.html#ga3fc0a0d198bb5f688d91f0c8f34649b6',1,'esp_wifi.h']]], + ['wifi_5frfid_5flocp_5frecv_5fopen',['wifi_rfid_locp_recv_open',['../group__WiFi__Common__APIs.html#ga7c1311ecd8ae0b5a58fcfea0f254600a',1,'esp_wifi.h']]], + ['wifi_5fsend_5fpkt_5ffreedom',['wifi_send_pkt_freedom',['../group__WiFi__Common__APIs.html#gad53e38f5591dc2ab6d9d78ecf79d51fc',1,'esp_wifi.h']]], + ['wifi_5fset_5fchannel',['wifi_set_channel',['../group__WiFi__Sniffer__APIs.html#ga6e75b0345bab8347d02e421f28801b6c',1,'esp_wifi.h']]], + ['wifi_5fset_5fevent_5fhandler_5fcb',['wifi_set_event_handler_cb',['../group__WiFi__Common__APIs.html#ga4fafbb94468303730e39b60e4bd36367',1,'esp_wifi.h']]], + ['wifi_5fset_5fip_5finfo',['wifi_set_ip_info',['../group__WiFi__Common__APIs.html#gac2bfa0967810f1b52a279903fccb3820',1,'esp_wifi.h']]], + ['wifi_5fset_5fmacaddr',['wifi_set_macaddr',['../group__WiFi__Common__APIs.html#gad6c60d5fca798d25a2a3251beab18d5d',1,'esp_wifi.h']]], + ['wifi_5fset_5fopmode',['wifi_set_opmode',['../group__WiFi__Common__APIs.html#ga460f95d854680e435e4b1cb00a61d0c9',1,'esp_wifi.h']]], + ['wifi_5fset_5fopmode_5fcurrent',['wifi_set_opmode_current',['../group__WiFi__Common__APIs.html#gaae9c82a5eeebba94d7a6b65dcc704508',1,'esp_wifi.h']]], + ['wifi_5fset_5fphy_5fmode',['wifi_set_phy_mode',['../group__WiFi__Common__APIs.html#gac882480595e50f407e6ccd3072555bab',1,'esp_wifi.h']]], + ['wifi_5fset_5fpromiscuous_5frx_5fcb',['wifi_set_promiscuous_rx_cb',['../group__WiFi__Sniffer__APIs.html#ga2baed988e772a0ba9107984b4ef5e7a2',1,'esp_wifi.h']]], + ['wifi_5fset_5fsleep_5ftype',['wifi_set_sleep_type',['../group__WiFi__Common__APIs.html#ga8c6a105486e14aff96d31d324ca15baf',1,'esp_wifi.h']]], + ['wifi_5fset_5fuser_5ffixed_5frate',['wifi_set_user_fixed_rate',['../group__WiFi__Rate__Control__APIs.html#ga23f9bd250fe2c037889cc061dbc8a15b',1,'esp_wifi.h']]], + ['wifi_5fset_5fuser_5fie',['wifi_set_user_ie',['../group__WiFi__User__IE__APIs.html#gaae332b9c26be88e95787a825f828c827',1,'esp_wifi.h']]], + ['wifi_5fset_5fuser_5flimit_5frate_5fmask',['wifi_set_user_limit_rate_mask',['../group__WiFi__Rate__Control__APIs.html#gaed1b4660c13be6154fd73c84a3ba96c2',1,'esp_wifi.h']]], + ['wifi_5fset_5fuser_5frate_5flimit',['wifi_set_user_rate_limit',['../group__WiFi__Rate__Control__APIs.html#ga0cb4293aeced3e3636b40f831dee54cc',1,'esp_wifi.h']]], + ['wifi_5fset_5fuser_5fsup_5frate',['wifi_set_user_sup_rate',['../group__WiFi__Rate__Control__APIs.html#gafb6fea0b53f61743170baec0bd207b4f',1,'esp_wifi.h']]], + ['wifi_5fset_5fwps_5fcb',['wifi_set_wps_cb',['../group__WPS__APIs.html#ga43d54c785288a8ca0689b621f852a443',1,'esp_wps.h']]], + ['wifi_5fsoftap_5fdhcps_5fstart',['wifi_softap_dhcps_start',['../group__SoftAP__APIs.html#ga3955db3d72e1669492143e64f7b32775',1,'esp_softap.h']]], + ['wifi_5fsoftap_5fdhcps_5fstatus',['wifi_softap_dhcps_status',['../group__SoftAP__APIs.html#ga0fd4c4454b23c6532a8dcbfbcbaa4e13',1,'esp_softap.h']]], + ['wifi_5fsoftap_5fdhcps_5fstop',['wifi_softap_dhcps_stop',['../group__SoftAP__APIs.html#gadc4b55015e0a64892d33a7d79a7627d6',1,'esp_softap.h']]], + ['wifi_5fsoftap_5ffree_5fstation_5finfo',['wifi_softap_free_station_info',['../group__SoftAP__APIs.html#ga964c8cead391b94375d374b028286c49',1,'esp_softap.h']]], + ['wifi_5fsoftap_5fget_5fconfig',['wifi_softap_get_config',['../group__SoftAP__APIs.html#ga77b8e55ff0c8ff6d01aa0da307a7ea37',1,'esp_softap.h']]], + ['wifi_5fsoftap_5fget_5fconfig_5fdefault',['wifi_softap_get_config_default',['../group__SoftAP__APIs.html#gaf8f06f31b9c07479b775b30ec1ce4515',1,'esp_softap.h']]], + ['wifi_5fsoftap_5fget_5fdhcps_5flease',['wifi_softap_get_dhcps_lease',['../group__SoftAP__APIs.html#gab2a17bcf37d23826044a0fb221188265',1,'esp_softap.h']]], + ['wifi_5fsoftap_5fget_5fdhcps_5flease_5ftime',['wifi_softap_get_dhcps_lease_time',['../group__SoftAP__APIs.html#gaa69724e463906776f0ad148d53880059',1,'esp_softap.h']]], + ['wifi_5fsoftap_5fget_5fstation_5finfo',['wifi_softap_get_station_info',['../group__SoftAP__APIs.html#ga491f411c5bf740d1ee254d4d05f1318d',1,'esp_softap.h']]], + ['wifi_5fsoftap_5fget_5fstation_5fnum',['wifi_softap_get_station_num',['../group__SoftAP__APIs.html#ga1565b7a74387e9bdce78771086f0083c',1,'esp_softap.h']]], + ['wifi_5fsoftap_5freset_5fdhcps_5flease_5ftime',['wifi_softap_reset_dhcps_lease_time',['../group__SoftAP__APIs.html#ga78ef453f3e627eefd1c5a2ef077cc0b9',1,'esp_softap.h']]], + ['wifi_5fsoftap_5fset_5fconfig',['wifi_softap_set_config',['../group__SoftAP__APIs.html#ga22c2108fdcadc9bf0cbfe9b642e759b7',1,'esp_softap.h']]], + ['wifi_5fsoftap_5fset_5fconfig_5fcurrent',['wifi_softap_set_config_current',['../group__SoftAP__APIs.html#ga865d02d3e00b6105c9446bce9d6b8e12',1,'esp_softap.h']]], + ['wifi_5fsoftap_5fset_5fdhcps_5flease',['wifi_softap_set_dhcps_lease',['../group__SoftAP__APIs.html#ga88284afccfb825d3b47ed45d1a6f26e2',1,'esp_softap.h']]], + ['wifi_5fsoftap_5fset_5fdhcps_5flease_5ftime',['wifi_softap_set_dhcps_lease_time',['../group__SoftAP__APIs.html#ga4d2c217a01e271ce74a00a32a6e5187f',1,'esp_softap.h']]], + ['wifi_5fsoftap_5fset_5fdhcps_5foffer_5foption',['wifi_softap_set_dhcps_offer_option',['../group__SoftAP__APIs.html#gaab0a8265f075049245fa284051e9ee24',1,'esp_softap.h']]], + ['wifi_5fstation_5fap_5fchange',['wifi_station_ap_change',['../group__Station__APIs.html#ga9711fca72415e7894c33ae4cef1d371d',1,'esp_sta.h']]], + ['wifi_5fstation_5fap_5fnumber_5fset',['wifi_station_ap_number_set',['../group__Station__APIs.html#ga63e11de2570080b8379da8625e9cb949',1,'esp_sta.h']]], + ['wifi_5fstation_5fconnect',['wifi_station_connect',['../group__Station__APIs.html#gab03cd1e7e4ad93cd241c94bd57430384',1,'esp_sta.h']]], + ['wifi_5fstation_5fdhcpc_5fstart',['wifi_station_dhcpc_start',['../group__Station__APIs.html#ga8319ad450244b7742b85150adc3cd424',1,'esp_sta.h']]], + ['wifi_5fstation_5fdhcpc_5fstatus',['wifi_station_dhcpc_status',['../group__Station__APIs.html#ga4f0dbe9ff0d79cd8d947f9ff23bc747a',1,'esp_sta.h']]], + ['wifi_5fstation_5fdhcpc_5fstop',['wifi_station_dhcpc_stop',['../group__Station__APIs.html#ga955438bce6a3cdfc702d032f4d086704',1,'esp_sta.h']]], + ['wifi_5fstation_5fdisconnect',['wifi_station_disconnect',['../group__Station__APIs.html#gaba69e9646b1f29d8a72972787400f4f1',1,'esp_sta.h']]], + ['wifi_5fstation_5fget_5fap_5finfo',['wifi_station_get_ap_info',['../group__Station__APIs.html#ga8e02856a8da8a5c2d5cc2b58ac2abe8d',1,'esp_sta.h']]], + ['wifi_5fstation_5fget_5fauto_5fconnect',['wifi_station_get_auto_connect',['../group__Station__APIs.html#ga00570be3792df2117fabaf78f1715377',1,'esp_sta.h']]], + ['wifi_5fstation_5fget_5fconfig',['wifi_station_get_config',['../group__Station__APIs.html#ga1f0be53caaf81058292a1e6559bdaa36',1,'esp_sta.h']]], + ['wifi_5fstation_5fget_5fconfig_5fdefault',['wifi_station_get_config_default',['../group__Station__APIs.html#ga6731bedbb516f8709c236084fa721dd4',1,'esp_sta.h']]], + ['wifi_5fstation_5fget_5fconnect_5fstatus',['wifi_station_get_connect_status',['../group__Station__APIs.html#ga759708bdf7cbb858a9b5c87100ccd4f8',1,'esp_sta.h']]], + ['wifi_5fstation_5fget_5fcurrent_5fap_5fid',['wifi_station_get_current_ap_id',['../group__Station__APIs.html#ga0b52a9b584de66a3806ec340e3e5c909',1,'esp_sta.h']]], + ['wifi_5fstation_5fget_5fhostname',['wifi_station_get_hostname',['../group__Station__APIs.html#gadfca0ed0d87c94c27168a826bcc88b54',1,'esp_sta.h']]], + ['wifi_5fstation_5fget_5freconnect_5fpolicy',['wifi_station_get_reconnect_policy',['../group__Station__APIs.html#ga31710ba9a7d42a9503a33149fa0b06e8',1,'esp_sta.h']]], + ['wifi_5fstation_5fget_5frssi',['wifi_station_get_rssi',['../group__Station__APIs.html#gaf8572ea9f6e1b7785e9df6941932bb3d',1,'esp_sta.h']]], + ['wifi_5fstation_5fscan',['wifi_station_scan',['../group__Station__APIs.html#gac80b0607b1cb20c161c681581c998626',1,'esp_sta.h']]], + ['wifi_5fstation_5fset_5fauto_5fconnect',['wifi_station_set_auto_connect',['../group__Station__APIs.html#ga814fa9c0218cd4c1df29b4d22aeef442',1,'esp_sta.h']]], + ['wifi_5fstation_5fset_5fconfig',['wifi_station_set_config',['../group__Station__APIs.html#gab3699b2e258bf21ad6e85e4b1ec1c271',1,'esp_sta.h']]], + ['wifi_5fstation_5fset_5fconfig_5fcurrent',['wifi_station_set_config_current',['../group__Station__APIs.html#gafd1188add491eee183d4ee2daa37dca6',1,'esp_sta.h']]], + ['wifi_5fstation_5fset_5fhostname',['wifi_station_set_hostname',['../group__Station__APIs.html#gaed5b5cb8eb9d881a77ca4a832b9ae50d',1,'esp_sta.h']]], + ['wifi_5fstation_5fset_5freconnect_5fpolicy',['wifi_station_set_reconnect_policy',['../group__Station__APIs.html#ga8df829fe1b522f576cc8d97835c0a64a',1,'esp_sta.h']]], + ['wifi_5fstatus_5fled_5finstall',['wifi_status_led_install',['../group__WiFi__Common__APIs.html#gafa9800e7f02ac0036e03c101aff67b56',1,'esp_wifi.h']]], + ['wifi_5fstatus_5fled_5funinstall',['wifi_status_led_uninstall',['../group__WiFi__Common__APIs.html#gaf5f3d866bb77ebd5f48543a2e0e9da8c',1,'esp_wifi.h']]], + ['wifi_5funregister_5frfid_5flocp_5frecv_5fcb',['wifi_unregister_rfid_locp_recv_cb',['../group__WiFi__Common__APIs.html#gab108ee67954d01805b4721c416805123',1,'esp_wifi.h']]], + ['wifi_5funregister_5fsend_5fpkt_5ffreedom_5fcb',['wifi_unregister_send_pkt_freedom_cb',['../group__WiFi__Common__APIs.html#ga8fba24461d736ce9d94c4acdb5295df2',1,'esp_wifi.h']]], + ['wifi_5funregister_5fuser_5fie_5fmanufacturer_5frecv_5fcb',['wifi_unregister_user_ie_manufacturer_recv_cb',['../group__WiFi__User__IE__APIs.html#ga8f1e33403097564f724cc7d5115d2ab4',1,'esp_wifi.h']]], + ['wifi_5fwps_5fdisable',['wifi_wps_disable',['../group__WPS__APIs.html#gaefc2fa1f3e4ba57ff82d41438c20badc',1,'esp_wps.h']]], + ['wifi_5fwps_5fenable',['wifi_wps_enable',['../group__WPS__APIs.html#ga6c3bf6dc44cf11fa735b2d190d9a2861',1,'esp_wps.h']]], + ['wifi_5fwps_5fstart',['wifi_wps_start',['../group__WPS__APIs.html#gad23a740bd3fb80e6f871c78728b4e58b',1,'esp_wps.h']]], + ['wps_20apis',['WPS APIs',['../group__WPS__APIs.html',1,'']]], + ['wps_5fcb_5fst_5ffailed',['WPS_CB_ST_FAILED',['../group__WPS__APIs.html#ggad7729ea41405ddb427166e3c6ed9407aa82d6a587f16918a5e08fc7bd72e82256',1,'esp_wps.h']]], + ['wps_5fcb_5fst_5fscan_5ferr',['WPS_CB_ST_SCAN_ERR',['../group__WPS__APIs.html#ggad7729ea41405ddb427166e3c6ed9407aabebbd63e324d7efaaaa19643b6db3c5b',1,'esp_wps.h']]], + ['wps_5fcb_5fst_5fsuccess',['WPS_CB_ST_SUCCESS',['../group__WPS__APIs.html#ggad7729ea41405ddb427166e3c6ed9407aac8a6efa900487f4e54f8f09acd2fc4f8',1,'esp_wps.h']]], + ['wps_5fcb_5fst_5ftimeout',['WPS_CB_ST_TIMEOUT',['../group__WPS__APIs.html#ggad7729ea41405ddb427166e3c6ed9407aa06494c31ab495602b84bbf165ecdeffd',1,'esp_wps.h']]], + ['wps_5fcb_5fst_5fwep',['WPS_CB_ST_WEP',['../group__WPS__APIs.html#ggad7729ea41405ddb427166e3c6ed9407aabb3484dae0443776c8afe92d23d82621',1,'esp_wps.h']]], + ['wps_5fcb_5fstatus',['wps_cb_status',['../group__WPS__APIs.html#gad7729ea41405ddb427166e3c6ed9407a',1,'esp_wps.h']]], + ['wps_5fst_5fcb_5ft',['wps_st_cb_t',['../group__WPS__APIs.html#ga0da3c16841a4b3b2404577dd8f56251a',1,'esp_wps.h']]], + ['write_5ffinish_5ffn',['write_finish_fn',['../struct__esp__tcp.html#ae885dafd86eabefcff4ead713c21eb82',1,'_esp_tcp']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_2.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_2.html new file mode 100644 index 0000000..93962b7 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_2.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_2.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_2.js new file mode 100644 index 0000000..7cfd2d6 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_2.js @@ -0,0 +1,9 @@ +var searchData= +[ + ['beacon_5finterval',['beacon_interval',['../structsoftap__config.html#a2b535ca353a179a70ea977c7e522ddf5',1,'softap_config']]], + ['bss',['bss',['../structEvent__StaMode__ScanDone__t.html#abcc828d7caabe78ac4a5a54215c42e6a',1,'Event_StaMode_ScanDone_t']]], + ['bss_5finfo',['bss_info',['../structbss__info.html',1,'']]], + ['bssid',['bssid',['../structstation__info.html#a27f40250591ad1ec3d905b4b61e7ddde',1,'station_info::bssid()'],['../structstation__config.html#a27f40250591ad1ec3d905b4b61e7ddde',1,'station_config::bssid()'],['../structscan__config.html#a4fb944a230a11d0c4b7582b3d4d79fa4',1,'scan_config::bssid()'],['../structbss__info.html#a27f40250591ad1ec3d905b4b61e7ddde',1,'bss_info::bssid()'],['../structEvent__StaMode__Connected__t.html#a27f40250591ad1ec3d905b4b61e7ddde',1,'Event_StaMode_Connected_t::bssid()'],['../structEvent__StaMode__Disconnected__t.html#a27f40250591ad1ec3d905b4b61e7ddde',1,'Event_StaMode_Disconnected_t::bssid()']]], + ['bssid_5fset',['bssid_set',['../structstation__config.html#ab8bd65a9dba6168d9a62bb54a67d1f50',1,'station_config']]], + ['boot_20apis',['Boot APIs',['../group__System__boot__APIs.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_3.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_3.html new file mode 100644 index 0000000..679f93c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_3.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_3.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_3.js new file mode 100644 index 0000000..a6cb999 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_3.js @@ -0,0 +1,11 @@ +var searchData= +[ + ['cache_5fbuf_5fsize',['cache_buf_size',['../structesp__spiffs__config.html#ad509b97f939dee79cf1cbdbddd780798',1,'esp_spiffs_config']]], + ['channel',['channel',['../structsoftap__config.html#a94e9cfdc116e8607615a5e8529048b1e',1,'softap_config::channel()'],['../structscan__config.html#a94e9cfdc116e8607615a5e8529048b1e',1,'scan_config::channel()'],['../structbss__info.html#a94e9cfdc116e8607615a5e8529048b1e',1,'bss_info::channel()'],['../structEvent__StaMode__Connected__t.html#a94e9cfdc116e8607615a5e8529048b1e',1,'Event_StaMode_Connected_t::channel()']]], + ['check_5fcb',['check_cb',['../structupgrade__server__info.html#a60f52082196cd22a78142fd14eef594e',1,'upgrade_server_info']]], + ['check_5ftimes',['check_times',['../structupgrade__server__info.html#a9ca9a8d4a9ec737b8694bf3625c48e88',1,'upgrade_server_info']]], + ['cmd_5fs',['cmd_s',['../structcmd__s.html',1,'']]], + ['connect_5fcallback',['connect_callback',['../struct__esp__tcp.html#a5b1fd73f4d26ae0efbaa786ae2ef5ff1',1,'_esp_tcp']]], + ['connected',['connected',['../unionEvent__Info__u.html#a3276cf21406a5988ea359ba2cf9c5e84',1,'Event_Info_u']]], + ['common_20apis',['Common APIs',['../group__WiFi__Common__APIs.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_4.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_4.html new file mode 100644 index 0000000..adc99fb --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_4.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_4.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_4.js new file mode 100644 index 0000000..1ceaa69 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_4.js @@ -0,0 +1,13 @@ +var searchData= +[ + ['dhcp_5fstarted',['DHCP_STARTED',['../group__Misc__APIs.html#gga9e40444d24f71f875b15136edec8fc47af861d0338581584e3be0abd10af2d0ff',1,'esp_misc.h']]], + ['dhcp_5fstatus',['dhcp_status',['../group__Misc__APIs.html#ga9e40444d24f71f875b15136edec8fc47',1,'esp_misc.h']]], + ['dhcp_5fstopped',['DHCP_STOPPED',['../group__Misc__APIs.html#gga9e40444d24f71f875b15136edec8fc47a7c9cbdc204a9ed4b2a46cec8daeacfb8',1,'esp_misc.h']]], + ['dhcps_5flease',['dhcps_lease',['../structdhcps__lease.html',1,'']]], + ['dhcps_5foffer_5foption',['dhcps_offer_option',['../group__Misc__APIs.html#ga47797d528afd74db93dd37a2c9207333',1,'esp_misc.h']]], + ['disconnect_5fcallback',['disconnect_callback',['../struct__esp__tcp.html#a90d49d2fa682397e7d439b1e616057a7',1,'_esp_tcp']]], + ['disconnected',['disconnected',['../unionEvent__Info__u.html#a004df3b560cf7f00b0fc1d205c5c6f98',1,'Event_Info_u']]], + ['dns_5ffound_5fcallback',['dns_found_callback',['../group__Espconn__APIs.html#gac6c8cf602f9c20d36003dc6d1b518d78',1,'espconn.h']]], + ['driver_20apis',['Driver APIs',['../group__Driver__APIs.html',1,'']]], + ['duty',['duty',['../structpwm__param.html#a06e6b4fb1983f85d1908d44cb32686a8',1,'pwm_param']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_5.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_5.html new file mode 100644 index 0000000..a9fcd17 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_5.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_5.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_5.js new file mode 100644 index 0000000..9637cf0 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_5.js @@ -0,0 +1,140 @@ +var searchData= +[ + ['enable',['enable',['../structdhcps__lease.html#ac842b6c1dcb3b1f11b611620199dc55c',1,'dhcps_lease']]], + ['end_5fip',['end_ip',['../structdhcps__lease.html#a2ecbf3162350cb32b51fcf7e0562dc84',1,'dhcps_lease']]], + ['esp_5fnow_5fadd_5fpeer',['esp_now_add_peer',['../group__ESPNow__APIs.html#ga780113b4069cbf971a58353987d25240',1,'espnow.h']]], + ['esp_5fnow_5fdeinit',['esp_now_deinit',['../group__ESPNow__APIs.html#ga5a85f4807948eaa75b76ebef7cad1a22',1,'espnow.h']]], + ['esp_5fnow_5fdel_5fpeer',['esp_now_del_peer',['../group__ESPNow__APIs.html#gab5b0ca5ece92af7fb04c27a8c1bfce4d',1,'espnow.h']]], + ['esp_5fnow_5ffetch_5fpeer',['esp_now_fetch_peer',['../group__ESPNow__APIs.html#gaffa4f035416078c3d0dbf34f2d67795a',1,'espnow.h']]], + ['esp_5fnow_5fget_5fcnt_5finfo',['esp_now_get_cnt_info',['../group__ESPNow__APIs.html#ga59320ae71ba3f4d4b2904e69ce7b72f2',1,'espnow.h']]], + ['esp_5fnow_5fget_5fpeer_5fchannel',['esp_now_get_peer_channel',['../group__ESPNow__APIs.html#ga42cd1efe5ef32d2f35682bccddb5d83e',1,'espnow.h']]], + ['esp_5fnow_5fget_5fpeer_5fkey',['esp_now_get_peer_key',['../group__ESPNow__APIs.html#ga6b2c449a35daf4c91e51496f7622f2a0',1,'espnow.h']]], + ['esp_5fnow_5fget_5fpeer_5frole',['esp_now_get_peer_role',['../group__ESPNow__APIs.html#ga0629a89cf89b13439f8306fe0ba95023',1,'espnow.h']]], + ['esp_5fnow_5fget_5fself_5frole',['esp_now_get_self_role',['../group__ESPNow__APIs.html#ga5838cbb89faf492c4904fab6d83b87bb',1,'espnow.h']]], + ['esp_5fnow_5finit',['esp_now_init',['../group__ESPNow__APIs.html#ga407ae697a77bd49ade96fc2a72f49636',1,'espnow.h']]], + ['esp_5fnow_5fis_5fpeer_5fexist',['esp_now_is_peer_exist',['../group__ESPNow__APIs.html#ga735fbbcc99172abd887d1e248a7e9fb3',1,'espnow.h']]], + ['esp_5fnow_5frecv_5fcb_5ft',['esp_now_recv_cb_t',['../group__ESPNow__APIs.html#gadd5a6237e11ed8513c4956f6109730a7',1,'espnow.h']]], + ['esp_5fnow_5fregister_5frecv_5fcb',['esp_now_register_recv_cb',['../group__ESPNow__APIs.html#gaf3488572d55b5b2f3748a7a87e902a0f',1,'espnow.h']]], + ['esp_5fnow_5fregister_5fsend_5fcb',['esp_now_register_send_cb',['../group__ESPNow__APIs.html#ga6dbbbb859a5d37c2b74a79baaa8011f0',1,'espnow.h']]], + ['esp_5fnow_5fsend',['esp_now_send',['../group__ESPNow__APIs.html#ga2ef5f592b161d885b6f0d8dde18ff802',1,'espnow.h']]], + ['esp_5fnow_5fsend_5fcb_5ft',['esp_now_send_cb_t',['../group__ESPNow__APIs.html#ga5d05ff4fff6db81409e30f7e7e5d48c7',1,'espnow.h']]], + ['esp_5fnow_5fset_5fkok',['esp_now_set_kok',['../group__ESPNow__APIs.html#gaab9b169f115cffd354637c79d2a16789',1,'espnow.h']]], + ['esp_5fnow_5fset_5fpeer_5fchannel',['esp_now_set_peer_channel',['../group__ESPNow__APIs.html#ga49e3aa3ba63d7883124e1dfcf2a0533b',1,'espnow.h']]], + ['esp_5fnow_5fset_5fpeer_5fkey',['esp_now_set_peer_key',['../group__ESPNow__APIs.html#ga936b9caa1127d362aa63225f865afd99',1,'espnow.h']]], + ['esp_5fnow_5fset_5fpeer_5frole',['esp_now_set_peer_role',['../group__ESPNow__APIs.html#ga7a5f50b81300b3b8ae403854d76901a3',1,'espnow.h']]], + ['esp_5fnow_5fset_5fself_5frole',['esp_now_set_self_role',['../group__ESPNow__APIs.html#ga08297bacf8c88648d09c11ba3b69d594',1,'espnow.h']]], + ['esp_5fnow_5funregister_5frecv_5fcb',['esp_now_unregister_recv_cb',['../group__ESPNow__APIs.html#gaac4facb9a7ec9bf4c7c0e18054664b03',1,'espnow.h']]], + ['esp_5fnow_5funregister_5fsend_5fcb',['esp_now_unregister_send_cb',['../group__ESPNow__APIs.html#gacf2a9263a2f55d55440dbf7ca2b43709',1,'espnow.h']]], + ['esp_5fspiffs_5fconfig',['esp_spiffs_config',['../structesp__spiffs__config.html',1,'']]], + ['esp_5fspiffs_5fdeinit',['esp_spiffs_deinit',['../group__Spiffs__APIs.html#ga03894c9cf5d03c55d9f406ea5b58651d',1,'esp_spiffs.h']]], + ['esp_5fspiffs_5finit',['esp_spiffs_init',['../group__Spiffs__APIs.html#ga72e4d349ef03c2671462a12976e4552f',1,'esp_spiffs.h']]], + ['espconn',['espconn',['../structespconn.html',1,'']]], + ['espconn_5fabrt',['ESPCONN_ABRT',['../group__Espconn__APIs.html#ga0bf23d2d937c693c7d9a66ac609194bc',1,'espconn.h']]], + ['espconn_5faccept',['espconn_accept',['../group__Espconn__APIs.html#gabd44446e3fc4a61fdef77d473deb678b',1,'espconn.h']]], + ['espconn_5farg',['ESPCONN_ARG',['../group__Espconn__APIs.html#ga0ab82f63b7e43bf6ea1c36653707b67d',1,'espconn.h']]], + ['espconn_5fclear_5fopt',['espconn_clear_opt',['../group__Espconn__APIs.html#ga9a8be5ecdee08ca20a2516c4aa289c5e',1,'espconn.h']]], + ['espconn_5fclose',['ESPCONN_CLOSE',['../group__Espconn__APIs.html#gga27ebed6341108494ecf41ec8a7d37c4ba755ebf5af367126c8c2c33f8e919bac4',1,'espconn.h']]], + ['espconn_5fclsd',['ESPCONN_CLSD',['../group__Espconn__APIs.html#ga867f470db66f9ba20f7ea9a494fe6320',1,'espconn.h']]], + ['espconn_5fconn',['ESPCONN_CONN',['../group__Espconn__APIs.html#ga39113d279962242d9ed0aaba5fc57c46',1,'espconn.h']]], + ['espconn_5fconnect',['espconn_connect',['../group__Espconn__APIs.html#ga949cd618667cea85b1b99d14b90dce7d',1,'espconn_connect(struct espconn *espconn): espconn.h'],['../group__Espconn__APIs.html#gga27ebed6341108494ecf41ec8a7d37c4ba2581f4215688fddcb1852ea4cbbcdaef',1,'ESPCONN_CONNECT(): espconn.h']]], + ['espconn_5fconnect_5fcallback',['espconn_connect_callback',['../group__Espconn__APIs.html#gac2f5cc499f1d963723ed37d87a029a00',1,'espconn.h']]], + ['espconn_5fcopy',['ESPCONN_COPY',['../group__Espconn__APIs.html#gga9db40198a52a9becd150a851f9855a92a5a42c1ab1c6a9e2cce272046bce29687',1,'espconn.h']]], + ['espconn_5fcreate',['espconn_create',['../group__Espconn__APIs.html#gad55b9729c7629f40c8e7ae2d73f7f174',1,'espconn.h']]], + ['espconn_5fdelete',['espconn_delete',['../group__Espconn__APIs.html#ga63d15dda14dfcd8da278c31f048910c3',1,'espconn.h']]], + ['espconn_5fdisconnect',['espconn_disconnect',['../group__Espconn__APIs.html#ga9969873c3b8ee86a34496a5166cf8bfc',1,'espconn.h']]], + ['espconn_5fdns_5fsetserver',['espconn_dns_setserver',['../group__Espconn__APIs.html#gabc578b3f5f5701f2a140683a4524ff0a',1,'espconn.h']]], + ['espconn_5fend',['ESPCONN_END',['../group__Espconn__APIs.html#gga9db40198a52a9becd150a851f9855a92ae2ad46665b977365b8cc24f2b325155f',1,'espconn.h']]], + ['espconn_5fget_5fconnection_5finfo',['espconn_get_connection_info',['../group__Espconn__APIs.html#ga95deabffd3b8a4bec81f91596901f84d',1,'espconn.h']]], + ['espconn_5fget_5fkeepalive',['espconn_get_keepalive',['../group__Espconn__APIs.html#gae7b470d0af4052d0945ed87ffbf8e684',1,'espconn.h']]], + ['espconn_5fgethostbyname',['espconn_gethostbyname',['../group__Espconn__APIs.html#ga34a3074b536dfc09c842b75210cfcdf1',1,'espconn.h']]], + ['espconn_5fif',['ESPCONN_IF',['../group__Espconn__APIs.html#ga4abb7c01f3e8465771f76aba5071c1fd',1,'espconn.h']]], + ['espconn_5figmp_5fjoin',['espconn_igmp_join',['../group__Espconn__APIs.html#ga7858298be65d5fb385e0614775799292',1,'espconn.h']]], + ['espconn_5figmp_5fleave',['espconn_igmp_leave',['../group__Espconn__APIs.html#ga49a50b6b7007818a45e5aa7eb19eace9',1,'espconn.h']]], + ['espconn_5finit',['espconn_init',['../group__Espconn__APIs.html#gab1bd524be2b4c1b727e3519e3cae69bf',1,'espconn.h']]], + ['espconn_5finprogress',['ESPCONN_INPROGRESS',['../group__Espconn__APIs.html#gab2d9a86577de714e72eb79e757b6e6d2',1,'espconn.h']]], + ['espconn_5finvalid',['ESPCONN_INVALID',['../group__Espconn__APIs.html#gga822c96862e04f46aff8d65cb8170b60faf10957d87831780be73e55426e8da737',1,'espconn.h']]], + ['espconn_5fisconn',['ESPCONN_ISCONN',['../group__Espconn__APIs.html#gadbb6b13a82c7a627b13faf308fe38981',1,'espconn.h']]], + ['espconn_5fkeepalive',['ESPCONN_KEEPALIVE',['../group__Espconn__APIs.html#gga9db40198a52a9becd150a851f9855a92a131641817461609c89b8086dd90f64a9',1,'espconn.h']]], + ['espconn_5fkeepcnt',['ESPCONN_KEEPCNT',['../group__Espconn__APIs.html#ggaaae7451fb36d445e625d52b3f0eec36ea1e723b94b0ac601545a717261203eb1b',1,'espconn.h']]], + ['espconn_5fkeepidle',['ESPCONN_KEEPIDLE',['../group__Espconn__APIs.html#ggaaae7451fb36d445e625d52b3f0eec36ea858f5c8ad925f16f59eb728619235e8b',1,'espconn.h']]], + ['espconn_5fkeepintvl',['ESPCONN_KEEPINTVL',['../group__Espconn__APIs.html#ggaaae7451fb36d445e625d52b3f0eec36ea9266ad9351007ce73e8877405970a6d8',1,'espconn.h']]], + ['espconn_5flevel',['espconn_level',['../group__Espconn__APIs.html#gaaae7451fb36d445e625d52b3f0eec36e',1,'espconn.h']]], + ['espconn_5flisten',['ESPCONN_LISTEN',['../group__Espconn__APIs.html#gga27ebed6341108494ecf41ec8a7d37c4ba97c2f022ffce819bc2658f4e5796543a',1,'espconn.h']]], + ['espconn_5fmaxnum',['ESPCONN_MAXNUM',['../group__Espconn__APIs.html#ga35b472e2b51197621984908dfe3a0984',1,'espconn.h']]], + ['espconn_5fmem',['ESPCONN_MEM',['../group__Espconn__APIs.html#ga45549b79bd5d005eaeabd547f9c9b8d6',1,'espconn.h']]], + ['espconn_5fmesh_5fconnect',['espconn_mesh_connect',['../group__Mesh__APIs.html#gaa00a7caa98b654fe5435f5990d99c06d',1,'mesh.h']]], + ['espconn_5fmesh_5fdisable',['espconn_mesh_disable',['../group__Mesh__APIs.html#ga130feda4a6e3a5e7ed1d750b6c4bc6ee',1,'mesh.h']]], + ['espconn_5fmesh_5fdisconnect',['espconn_mesh_disconnect',['../group__Mesh__APIs.html#ga819e5e382bc1aaa254a347b2eb880250',1,'mesh.h']]], + ['espconn_5fmesh_5fenable',['espconn_mesh_enable',['../group__Mesh__APIs.html#gab9f4efbcf201ac6b1425cf447485f7d8',1,'mesh.h']]], + ['espconn_5fmesh_5fencrypt_5finit',['espconn_mesh_encrypt_init',['../group__Mesh__APIs.html#gad6bb1d256497efb94543235414a1f7e5',1,'mesh.h']]], + ['espconn_5fmesh_5fget_5fmax_5fhops',['espconn_mesh_get_max_hops',['../group__Mesh__APIs.html#ga3dea1ef65bbb8c168082de273588c040',1,'mesh.h']]], + ['espconn_5fmesh_5fget_5fnode_5finfo',['espconn_mesh_get_node_info',['../group__Mesh__APIs.html#gacfa17fe9fe638da7cea59ff5f63e887e',1,'mesh.h']]], + ['espconn_5fmesh_5fget_5fstatus',['espconn_mesh_get_status',['../group__Mesh__APIs.html#gafec6034951b2c5cf70a7ea1c7707a03f',1,'mesh.h']]], + ['espconn_5fmesh_5fgroup_5fid_5finit',['espconn_mesh_group_id_init',['../group__Mesh__APIs.html#gad9db6b93cb1e3f37efdbb7a3e5180556',1,'mesh.h']]], + ['espconn_5fmesh_5finit',['espconn_mesh_init',['../group__Mesh__APIs.html#gacb87f54723aeacf3f4336eb1eb78633a',1,'mesh.h']]], + ['espconn_5fmesh_5flocal_5faddr',['espconn_mesh_local_addr',['../group__Mesh__APIs.html#ga3b2ebffff1527d4fb3fec86ab73c804b',1,'mesh.h']]], + ['espconn_5fmesh_5fsent',['espconn_mesh_sent',['../group__Mesh__APIs.html#ga8c60c7f53352f4e12bda09d0f2484075',1,'mesh.h']]], + ['espconn_5fmesh_5fset_5fdev_5ftype',['espconn_mesh_set_dev_type',['../group__Mesh__APIs.html#ga7cb73ffe93d15bfe0bcc6c5d17bef4ac',1,'mesh.h']]], + ['espconn_5fmesh_5fset_5fmax_5fhops',['espconn_mesh_set_max_hops',['../group__Mesh__APIs.html#ga4e2fd63e3eeaeba305b5ded90fcc753f',1,'mesh.h']]], + ['espconn_5fmesh_5fset_5fssid_5fprefix',['espconn_mesh_set_ssid_prefix',['../group__Mesh__APIs.html#ga55a5712902986a0cfc4e57fbb7d34821',1,'mesh.h']]], + ['espconn_5fnodelay',['ESPCONN_NODELAY',['../group__Espconn__APIs.html#gga9db40198a52a9becd150a851f9855a92a22a60c5e343e19f83f9facedc8cd6f89',1,'espconn.h']]], + ['espconn_5fnone',['ESPCONN_NONE',['../group__Espconn__APIs.html#gga27ebed6341108494ecf41ec8a7d37c4ba7dd74b008ab5d04f15ff84de4b70bf90',1,'espconn.h']]], + ['espconn_5fok',['ESPCONN_OK',['../group__Espconn__APIs.html#ga0149e7f6afdf2a5aef57e1fbe19c0b65',1,'espconn.h']]], + ['espconn_5foption',['espconn_option',['../group__Espconn__APIs.html#ga9db40198a52a9becd150a851f9855a92',1,'espconn.h']]], + ['espconn_5fport',['espconn_port',['../group__Espconn__APIs.html#ga8666579cda9afb8e01dff613326062c0',1,'espconn.h']]], + ['espconn_5fread',['ESPCONN_READ',['../group__Espconn__APIs.html#gga27ebed6341108494ecf41ec8a7d37c4ba01caf55e6b01ffa1089348102d42734c',1,'espconn.h']]], + ['espconn_5freconnect_5fcallback',['espconn_reconnect_callback',['../group__Espconn__APIs.html#ga06024aeff44004ddbdb7044b97676bba',1,'espconn.h']]], + ['espconn_5frecv_5fcallback',['espconn_recv_callback',['../group__Espconn__APIs.html#ga5c93b1b8d3455a8f4fdeb35b064c4b0f',1,'espconn.h']]], + ['espconn_5frecv_5fhold',['espconn_recv_hold',['../group__Espconn__APIs.html#ga2193ea6779889bef71dc6d368c6b8f80',1,'espconn.h']]], + ['espconn_5frecv_5funhold',['espconn_recv_unhold',['../group__Espconn__APIs.html#gac409e8c250ee409985475f5c7fa02950',1,'espconn.h']]], + ['espconn_5fregist_5fconnectcb',['espconn_regist_connectcb',['../group__Espconn__APIs.html#ga233874487e43ccdacf772e47bcd9b976',1,'espconn.h']]], + ['espconn_5fregist_5fdisconcb',['espconn_regist_disconcb',['../group__Espconn__APIs.html#gaf43c93f2f0cc14a1c1e95c38e9469b9f',1,'espconn.h']]], + ['espconn_5fregist_5freconcb',['espconn_regist_reconcb',['../group__Espconn__APIs.html#ga771463177734012911e42931a10ee7a2',1,'espconn.h']]], + ['espconn_5fregist_5frecvcb',['espconn_regist_recvcb',['../group__Espconn__APIs.html#ga56d063a430d96d20b4ea5e28ba41011c',1,'espconn.h']]], + ['espconn_5fregist_5fsentcb',['espconn_regist_sentcb',['../group__Espconn__APIs.html#ga438ded04b3f8a70948fcf8c551bce179',1,'espconn.h']]], + ['espconn_5fregist_5ftime',['espconn_regist_time',['../group__Espconn__APIs.html#gacd79a347f8e665d7b93f31569865b494',1,'espconn.h']]], + ['espconn_5fregist_5fwrite_5ffinish',['espconn_regist_write_finish',['../group__Espconn__APIs.html#ga28cae7c705c8d3da7bb614b6c41c8d1a',1,'espconn.h']]], + ['espconn_5freuseaddr',['ESPCONN_REUSEADDR',['../group__Espconn__APIs.html#gga9db40198a52a9becd150a851f9855a92a8c4b05b4bdbd12c64f1809c48d99e395',1,'espconn.h']]], + ['espconn_5frst',['ESPCONN_RST',['../group__Espconn__APIs.html#ga2bae98a46863135cfb79a5296b41d058',1,'espconn.h']]], + ['espconn_5frte',['ESPCONN_RTE',['../group__Espconn__APIs.html#ga22ce1e3a32571dd2ec6d755a77ac976c',1,'espconn.h']]], + ['espconn_5fsend',['espconn_send',['../group__Espconn__APIs.html#ga6677ecbe38ce063102e4b7a733829a7f',1,'espconn.h']]], + ['espconn_5fsendto',['espconn_sendto',['../group__Espconn__APIs.html#ga62219be0ac7e8dd6085915d5c0777476',1,'espconn.h']]], + ['espconn_5fsent',['espconn_sent',['../group__Espconn__APIs.html#ga579e4f1c62f7c33be01398931617e988',1,'espconn.h']]], + ['espconn_5fset_5fkeepalive',['espconn_set_keepalive',['../group__Espconn__APIs.html#ga0a78bf74f326d99a2cb498a338da8240',1,'espconn.h']]], + ['espconn_5fset_5fopt',['espconn_set_opt',['../group__Espconn__APIs.html#gac76f13b1bd09b3e43beedd50907e0c72',1,'espconn.h']]], + ['espconn_5fstart',['ESPCONN_START',['../group__Espconn__APIs.html#gga9db40198a52a9becd150a851f9855a92a9cb44b08d9f53701b054b08d04f7d71f',1,'espconn.h']]], + ['espconn_5fstate',['espconn_state',['../group__Espconn__APIs.html#ga27ebed6341108494ecf41ec8a7d37c4b',1,'espconn.h']]], + ['espconn_5ftcp',['ESPCONN_TCP',['../group__Espconn__APIs.html#gga822c96862e04f46aff8d65cb8170b60faf9113ca7b14a1637d2a0099367622879',1,'espconn.h']]], + ['espconn_5ftcp_5fget_5fmax_5fcon',['espconn_tcp_get_max_con',['../group__Espconn__APIs.html#gaa7665768ea19f95957284938cc0af950',1,'espconn.h']]], + ['espconn_5ftcp_5fget_5fmax_5fcon_5fallow',['espconn_tcp_get_max_con_allow',['../group__Espconn__APIs.html#ga8418023ae67bd83742d7d2642c3d4da0',1,'espconn.h']]], + ['espconn_5ftcp_5fset_5fmax_5fcon',['espconn_tcp_set_max_con',['../group__Espconn__APIs.html#ga6281d28b05672dc10f702f0e5386fb98',1,'espconn.h']]], + ['espconn_5ftcp_5fset_5fmax_5fcon_5fallow',['espconn_tcp_set_max_con_allow',['../group__Espconn__APIs.html#gaef6e59fa5bb5d813449d190e2fe66b2e',1,'espconn.h']]], + ['espconn_5ftimeout',['ESPCONN_TIMEOUT',['../group__Espconn__APIs.html#ga444a33b46763426495ef6445427301f2',1,'espconn.h']]], + ['espconn_5ftype',['espconn_type',['../group__Espconn__APIs.html#ga822c96862e04f46aff8d65cb8170b60f',1,'espconn.h']]], + ['espconn_5fudp',['ESPCONN_UDP',['../group__Espconn__APIs.html#gga822c96862e04f46aff8d65cb8170b60fa85d8592fc339ccda13561161ddfd63f7',1,'espconn.h']]], + ['espconn_5fwait',['ESPCONN_WAIT',['../group__Espconn__APIs.html#gga27ebed6341108494ecf41ec8a7d37c4baa13c91321f9aef1bf5023f1ea18e093a',1,'espconn.h']]], + ['espconn_5fwrite',['ESPCONN_WRITE',['../group__Espconn__APIs.html#gga27ebed6341108494ecf41ec8a7d37c4bab7b47f073e3e6db0ce792ab8fff1df02',1,'espconn.h']]], + ['esp_2dnow_20apis',['ESP-NOW APIs',['../group__ESPNow__APIs.html',1,'']]], + ['esptouch_5fset_5ftimeout',['esptouch_set_timeout',['../group__Smartconfig__APIs.html#ga068b054aecdba51c0ea5219089d5b3c0',1,'smartconfig.h']]], + ['event_5fid',['event_id',['../struct__esp__event.html#a03d39c10d31a495b8f30f745cd64cc7e',1,'_esp_event']]], + ['event_5finfo',['event_info',['../struct__esp__event.html#a34291c3b14eb4f42f70922ac2c4e17e7',1,'_esp_event']]], + ['event_5finfo_5fu',['Event_Info_u',['../unionEvent__Info__u.html',1,'']]], + ['event_5fsoftapmode_5fprobereqrecved',['EVENT_SOFTAPMODE_PROBEREQRECVED',['../group__WiFi__Common__APIs.html#ggaeecbdf938220e31d3d52cd49c57400bdafe4cacbfe933b32292c05dcc69faad50',1,'esp_wifi.h']]], + ['event_5fsoftapmode_5fprobereqrecved_5ft',['Event_SoftAPMode_ProbeReqRecved_t',['../structEvent__SoftAPMode__ProbeReqRecved__t.html',1,'']]], + ['event_5fsoftapmode_5fstaconnected',['EVENT_SOFTAPMODE_STACONNECTED',['../group__WiFi__Common__APIs.html#ggaeecbdf938220e31d3d52cd49c57400bdadcf5be1211c8c8348981847ff00b9381',1,'esp_wifi.h']]], + ['event_5fsoftapmode_5fstaconnected_5ft',['Event_SoftAPMode_StaConnected_t',['../structEvent__SoftAPMode__StaConnected__t.html',1,'']]], + ['event_5fsoftapmode_5fstadisconnected',['EVENT_SOFTAPMODE_STADISCONNECTED',['../group__WiFi__Common__APIs.html#ggaeecbdf938220e31d3d52cd49c57400bda5ba176bb1121e6a273c6400fd0bb2da8',1,'esp_wifi.h']]], + ['event_5fsoftapmode_5fstadisconnected_5ft',['Event_SoftAPMode_StaDisconnected_t',['../structEvent__SoftAPMode__StaDisconnected__t.html',1,'']]], + ['event_5fstamode_5fauthmode_5fchange',['EVENT_STAMODE_AUTHMODE_CHANGE',['../group__WiFi__Common__APIs.html#ggaeecbdf938220e31d3d52cd49c57400bdae6c201c8b490470cb65b166f0081c181',1,'esp_wifi.h']]], + ['event_5fstamode_5fauthmode_5fchange_5ft',['Event_StaMode_AuthMode_Change_t',['../structEvent__StaMode__AuthMode__Change__t.html',1,'']]], + ['event_5fstamode_5fconnected',['EVENT_STAMODE_CONNECTED',['../group__WiFi__Common__APIs.html#ggaeecbdf938220e31d3d52cd49c57400bdaa9d9acf861ff464e516aa92c8179a9f5',1,'esp_wifi.h']]], + ['event_5fstamode_5fconnected_5ft',['Event_StaMode_Connected_t',['../structEvent__StaMode__Connected__t.html',1,'']]], + ['event_5fstamode_5fdhcp_5ftimeout',['EVENT_STAMODE_DHCP_TIMEOUT',['../group__WiFi__Common__APIs.html#ggaeecbdf938220e31d3d52cd49c57400bdaa3b272b55e1cb2ceef2080d4d05add01',1,'esp_wifi.h']]], + ['event_5fstamode_5fdisconnected',['EVENT_STAMODE_DISCONNECTED',['../group__WiFi__Common__APIs.html#ggaeecbdf938220e31d3d52cd49c57400bda3e65821c77d0a3fe3e48d70f51412775',1,'esp_wifi.h']]], + ['event_5fstamode_5fdisconnected_5ft',['Event_StaMode_Disconnected_t',['../structEvent__StaMode__Disconnected__t.html',1,'']]], + ['event_5fstamode_5fgot_5fip',['EVENT_STAMODE_GOT_IP',['../group__WiFi__Common__APIs.html#ggaeecbdf938220e31d3d52cd49c57400bda7b92b134071315f5d10222e00b756620',1,'esp_wifi.h']]], + ['event_5fstamode_5fgot_5fip_5ft',['Event_StaMode_Got_IP_t',['../structEvent__StaMode__Got__IP__t.html',1,'']]], + ['event_5fstamode_5fscan_5fdone',['EVENT_STAMODE_SCAN_DONE',['../group__WiFi__Common__APIs.html#ggaeecbdf938220e31d3d52cd49c57400bda1db1eab9330111152c3d468e672d8885',1,'esp_wifi.h']]], + ['event_5fstamode_5fscandone_5ft',['Event_StaMode_ScanDone_t',['../structEvent__StaMode__ScanDone__t.html',1,'']]], + ['esp8266_5frtos_5fsdk',['ESP8266_RTOS_SDK',['../index.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_6.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_6.html new file mode 100644 index 0000000..821c374 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_6.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_6.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_6.js new file mode 100644 index 0000000..deef713 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_6.js @@ -0,0 +1,16 @@ +var searchData= +[ + ['fd_5fbuf_5fsize',['fd_buf_size',['../structesp__spiffs__config.html#a0a344b6b0ea486bc2c857249dfd2e364',1,'esp_spiffs_config']]], + ['flash_5fsize_5f16m_5fmap_5f1024_5f1024',['FLASH_SIZE_16M_MAP_1024_1024',['../group__System__boot__APIs.html#gga09fedddfc198c6f5b12e795d7a560de2a1c1807f4d5cccfdf38f15a603e7557ce',1,'esp_system.h']]], + ['flash_5fsize_5f16m_5fmap_5f512_5f512',['FLASH_SIZE_16M_MAP_512_512',['../group__System__boot__APIs.html#gga09fedddfc198c6f5b12e795d7a560de2a58eeb18a28a2904a2424ce808ed0e2a6',1,'esp_system.h']]], + ['flash_5fsize_5f2m',['FLASH_SIZE_2M',['../group__System__boot__APIs.html#gga09fedddfc198c6f5b12e795d7a560de2a68191ccca310b30e6a0f6cfac494321c',1,'esp_system.h']]], + ['flash_5fsize_5f32m_5fmap_5f1024_5f1024',['FLASH_SIZE_32M_MAP_1024_1024',['../group__System__boot__APIs.html#gga09fedddfc198c6f5b12e795d7a560de2aa88e113314ba8a3de7fe693c1c14b9a0',1,'esp_system.h']]], + ['flash_5fsize_5f32m_5fmap_5f512_5f512',['FLASH_SIZE_32M_MAP_512_512',['../group__System__boot__APIs.html#gga09fedddfc198c6f5b12e795d7a560de2af31f99de17734586c910bddfe8c427bf',1,'esp_system.h']]], + ['flash_5fsize_5f4m_5fmap_5f256_5f256',['FLASH_SIZE_4M_MAP_256_256',['../group__System__boot__APIs.html#gga09fedddfc198c6f5b12e795d7a560de2a4c0ac10cfa5e7ecc6cc95b60e0faeb70',1,'esp_system.h']]], + ['flash_5fsize_5f8m_5fmap_5f512_5f512',['FLASH_SIZE_8M_MAP_512_512',['../group__System__boot__APIs.html#gga09fedddfc198c6f5b12e795d7a560de2a6de4efc98763d016d92d87fb73ca8849',1,'esp_system.h']]], + ['flash_5fsize_5fmap',['flash_size_map',['../group__System__boot__APIs.html#ga09fedddfc198c6f5b12e795d7a560de2',1,'esp_system.h']]], + ['freedom_5foutside_5fcb_5ft',['freedom_outside_cb_t',['../group__WiFi__Common__APIs.html#gae90568b8d2cdc0aeeb78ec34843e5c04',1,'esp_wifi.h']]], + ['freq',['freq',['../structpwm__param.html#a8524d98a86c8c4679521ae91d35f6e51',1,'pwm_param']]], + ['freq_5foffset',['freq_offset',['../structbss__info.html#abc41a63643b5fa7974868e1972d2675c',1,'bss_info']]], + ['force_20sleep_20apis',['Force Sleep APIs',['../group__WiFi__Force__Sleep__APIs.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_7.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_7.html new file mode 100644 index 0000000..38c6c00 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_7.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_7.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_7.js new file mode 100644 index 0000000..e5a3382 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_7.js @@ -0,0 +1,26 @@ +var searchData= +[ + ['got_5fip',['got_ip',['../unionEvent__Info__u.html#a75708143088f7424bcb4a47f6395b91a',1,'Event_Info_u']]], + ['gpio16_5finput_5fconf',['gpio16_input_conf',['../group__GPIO__Driver__APIs.html#gacc7e5be6c1aed84fe3c3260deea64a3e',1,'gpio.h']]], + ['gpio16_5finput_5fget',['gpio16_input_get',['../group__GPIO__Driver__APIs.html#ga4484530a542760c430ebb2e754b6e621',1,'gpio.h']]], + ['gpio16_5foutput_5fconf',['gpio16_output_conf',['../group__GPIO__Driver__APIs.html#gaf94c9f201c7ee9ad7a71b5eb8b720b00',1,'gpio.h']]], + ['gpio16_5foutput_5fset',['gpio16_output_set',['../group__GPIO__Driver__APIs.html#ga4f83a12f673ab6e664c6ea129a1ca9c2',1,'gpio.h']]], + ['gpio_5fas_5finput',['GPIO_AS_INPUT',['../group__GPIO__Driver__APIs.html#gae1dba8cd1835b53c3e8f19ed03704678',1,'gpio.h']]], + ['gpio_5fas_5foutput',['GPIO_AS_OUTPUT',['../group__GPIO__Driver__APIs.html#ga42af7fcc6e27fda6e62210c756d859f5',1,'gpio.h']]], + ['gpio_5fconfigtypedef',['GPIO_ConfigTypeDef',['../structGPIO__ConfigTypeDef.html',1,'']]], + ['gpio_5fdis_5foutput',['GPIO_DIS_OUTPUT',['../group__GPIO__Driver__APIs.html#gadc761184e3d3dbcac5088b099bb809cc',1,'gpio.h']]], + ['gpio_20driver_20apis',['GPIO Driver APIs',['../group__GPIO__Driver__APIs.html',1,'']]], + ['gpio_5finput_5fget',['GPIO_INPUT_GET',['../group__GPIO__Driver__APIs.html#gaa633831c2027196743ccd277cbf75572',1,'GPIO_INPUT_GET(): gpio.h'],['../group__GPIO__Driver__APIs.html#ga678824698fa5936b7928c24c6cfd0a17',1,'gpio_input_get(void): gpio.h']]], + ['gpio_5fintr_5fhandler_5fregister',['gpio_intr_handler_register',['../group__GPIO__Driver__APIs.html#ga7b94b7d43c84a8177f4301b6a001fae3',1,'gpio.h']]], + ['gpio_5fintrtype',['GPIO_IntrType',['../structGPIO__ConfigTypeDef.html#a9888e40b7e27b35c3408f5056e12c5e0',1,'GPIO_ConfigTypeDef']]], + ['gpio_5fmode',['GPIO_Mode',['../structGPIO__ConfigTypeDef.html#a0c7e8901d8b511bbb8c3b153f705dbba',1,'GPIO_ConfigTypeDef']]], + ['gpio_5foutput',['GPIO_OUTPUT',['../group__GPIO__Driver__APIs.html#gae42853d0b143e451a9ad05465b353538',1,'gpio.h']]], + ['gpio_5foutput_5fconf',['gpio_output_conf',['../group__GPIO__Driver__APIs.html#gad57551861ccb3b7f4d16c0de00717e29',1,'gpio.h']]], + ['gpio_5foutput_5fset',['GPIO_OUTPUT_SET',['../group__GPIO__Driver__APIs.html#ga2cc3f29ed0d46de6cbd2f013281881a6',1,'gpio.h']]], + ['gpio_5fpin',['GPIO_Pin',['../structGPIO__ConfigTypeDef.html#ab88f866e27ec419ab320a38bd8ce4db9',1,'GPIO_ConfigTypeDef']]], + ['gpio_5fpin_5fintr_5fstate_5fset',['gpio_pin_intr_state_set',['../group__GPIO__Driver__APIs.html#ga0adef8a3e9d5c302d96d1ddc360f7c79',1,'gpio.h']]], + ['gpio_5fpin_5fwakeup_5fdisable',['gpio_pin_wakeup_disable',['../group__GPIO__Driver__APIs.html#gaffbe088057472f44ddf99c7912f54300',1,'gpio.h']]], + ['gpio_5fpin_5fwakeup_5fenable',['gpio_pin_wakeup_enable',['../group__GPIO__Driver__APIs.html#gae37bc72b183440f9733f14df516cee7b',1,'gpio.h']]], + ['gpio_5fpullup',['GPIO_Pullup',['../structGPIO__ConfigTypeDef.html#a4397d9dc86f357d68e92846f74ea6a1f',1,'GPIO_ConfigTypeDef']]], + ['gw',['gw',['../structip__info.html#ae2fb969d40c572827b52c6006b83357d',1,'ip_info::gw()'],['../structEvent__StaMode__Got__IP__t.html#ae2fb969d40c572827b52c6006b83357d',1,'Event_StaMode_Got_IP_t::gw()']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_8.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_8.html new file mode 100644 index 0000000..2a22cd5 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_8.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_8.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_8.js new file mode 100644 index 0000000..bf0798e --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_8.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['hardware_20timer_20apis',['Hardware timer APIs',['../group__HW__Timer__APIs.html',1,'']]], + ['hw_5ftimer_5farm',['hw_timer_arm',['../group__HW__Timer__APIs.html#gace64c59d338a9d785bd5730029086553',1,'hw_timer.h']]], + ['hw_5ftimer_5finit',['hw_timer_init',['../group__HW__Timer__APIs.html#ga09f8d1ed286cb02bfe47bc5f6c67b570',1,'hw_timer.h']]], + ['hw_5ftimer_5fset_5ffunc',['hw_timer_set_func',['../group__HW__Timer__APIs.html#ga78c91a9ec46aa9fb5b9fae9d357e9957',1,'hw_timer.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_9.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_9.html new file mode 100644 index 0000000..bd9b05c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_9.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_9.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_9.js new file mode 100644 index 0000000..54b3f09 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_9.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['ip',['ip',['../structstation__info.html#a0f308afbb6ff9d8999fd963597ffaafd',1,'station_info::ip()'],['../structip__info.html#a0f308afbb6ff9d8999fd963597ffaafd',1,'ip_info::ip()'],['../structEvent__StaMode__Got__IP__t.html#a0f308afbb6ff9d8999fd963597ffaafd',1,'Event_StaMode_Got_IP_t::ip()']]], + ['ip_5finfo',['ip_info',['../structip__info.html',1,'']]], + ['is_5fhidden',['is_hidden',['../structbss__info.html#a752c7117050279bff70c6bce738be833',1,'bss_info']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_a.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_a.html new file mode 100644 index 0000000..4a25af1 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_a.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_a.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_a.js new file mode 100644 index 0000000..960a6b0 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_a.js @@ -0,0 +1,8 @@ +var searchData= +[ + ['link_5fcnt',['link_cnt',['../structespconn.html#a44c66baf2083925ae34e6ff46e7ec281',1,'espconn']]], + ['local_5fip',['local_ip',['../struct__esp__tcp.html#a2b79759620ce85a36254e2b07c86b62b',1,'_esp_tcp::local_ip()'],['../struct__esp__udp.html#a2b79759620ce85a36254e2b07c86b62b',1,'_esp_udp::local_ip()']]], + ['local_5fport',['local_port',['../struct__esp__tcp.html#a009e2d58737d2223ce009dc0631e65dc',1,'_esp_tcp::local_port()'],['../struct__esp__udp.html#a009e2d58737d2223ce009dc0631e65dc',1,'_esp_udp::local_port()']]], + ['log_5fblock_5fsize',['log_block_size',['../structesp__spiffs__config.html#ac7518f38292532ca42fd8ed8a290259b',1,'esp_spiffs_config']]], + ['log_5fpage_5fsize',['log_page_size',['../structesp__spiffs__config.html#a0cfa1078dbb0a9591e9955d6dd0ad13a',1,'esp_spiffs_config']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_b.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_b.html new file mode 100644 index 0000000..a92de48 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_b.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_b.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_b.js new file mode 100644 index 0000000..e93b284 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_b.js @@ -0,0 +1,18 @@ +var searchData= +[ + ['mac',['mac',['../structEvent__SoftAPMode__StaConnected__t.html#adef72662fd97f14968405c927136b700',1,'Event_SoftAPMode_StaConnected_t::mac()'],['../structEvent__SoftAPMode__StaDisconnected__t.html#adef72662fd97f14968405c927136b700',1,'Event_SoftAPMode_StaDisconnected_t::mac()'],['../structEvent__SoftAPMode__ProbeReqRecved__t.html#adef72662fd97f14968405c927136b700',1,'Event_SoftAPMode_ProbeReqRecved_t::mac()']]], + ['mask',['mask',['../structEvent__StaMode__Got__IP__t.html#a494da30773601639d4aa8e289ca33ccc',1,'Event_StaMode_Got_IP_t']]], + ['max_5fconnection',['max_connection',['../structsoftap__config.html#ad6cbad99ccec22e10893f883a2a4d092',1,'softap_config']]], + ['mesh_20apis',['Mesh APIs',['../group__Mesh__APIs.html',1,'']]], + ['mesh_5fdisable',['MESH_DISABLE',['../group__Mesh__APIs.html#gga73a6546355fa7461bbe09af0643c719ea34024c70dfdfac6cd104addcb7efdf4b',1,'mesh.h']]], + ['mesh_5flocal_5favail',['MESH_LOCAL_AVAIL',['../group__Mesh__APIs.html#gga73a6546355fa7461bbe09af0643c719ea2db29fbbb0d36ee854ddbf7325b4dbc0',1,'mesh.h']]], + ['mesh_5fnet_5fconn',['MESH_NET_CONN',['../group__Mesh__APIs.html#gga73a6546355fa7461bbe09af0643c719eaf8707ddf897e616743134a1e28ed03f4',1,'mesh.h']]], + ['mesh_5fnode_5fall',['MESH_NODE_ALL',['../group__Mesh__APIs.html#gga4947b8b90891b481b81383e08d45c346a95346a7d9886d3e5781fec75aff99ad7',1,'mesh.h']]], + ['mesh_5fnode_5fchild',['MESH_NODE_CHILD',['../group__Mesh__APIs.html#gga4947b8b90891b481b81383e08d45c346ad1d85742ae6b9b121f3f5dc6f93827f4',1,'mesh.h']]], + ['mesh_5fnode_5fparent',['MESH_NODE_PARENT',['../group__Mesh__APIs.html#gga4947b8b90891b481b81383e08d45c346a8dc1197b5edf569a7e041845c7aae34e',1,'mesh.h']]], + ['mesh_5fnode_5ftype',['mesh_node_type',['../group__Mesh__APIs.html#ga4947b8b90891b481b81383e08d45c346',1,'mesh.h']]], + ['mesh_5fonline_5favail',['MESH_ONLINE_AVAIL',['../group__Mesh__APIs.html#gga73a6546355fa7461bbe09af0643c719ea3ed309a6fce09a48d29a668345170026',1,'mesh.h']]], + ['mesh_5fstatus',['mesh_status',['../group__Mesh__APIs.html#ga73a6546355fa7461bbe09af0643c719e',1,'mesh.h']]], + ['mesh_5fwifi_5fconn',['MESH_WIFI_CONN',['../group__Mesh__APIs.html#gga73a6546355fa7461bbe09af0643c719eafc8893dffe37c367602bd732dd57277f',1,'mesh.h']]], + ['misc_20apis',['Misc APIs',['../group__Misc__APIs.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_c.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_c.html new file mode 100644 index 0000000..20cdfbc --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_c.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_c.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_c.js new file mode 100644 index 0000000..cd8f79a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_c.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['network_20espconn_20apis',['Network Espconn APIs',['../group__Espconn__APIs.html',1,'']]], + ['netmask',['netmask',['../structip__info.html#a9b6d1d396ad76ad9c32ab40332c8e5ae',1,'ip_info']]], + ['new_5fmode',['new_mode',['../structEvent__StaMode__AuthMode__Change__t.html#a87330332c13687acbf3fa85aa30b32ea',1,'Event_StaMode_AuthMode_Change_t']]], + ['null_5fmode',['NULL_MODE',['../group__WiFi__Common__APIs.html#gga2cdd09724a071506f717d721f6aa633ca055d8a581738cc0181ce387afe3ab99a',1,'esp_wifi.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_d.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_d.html new file mode 100644 index 0000000..00b28ed --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_d.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_d.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_d.js new file mode 100644 index 0000000..b2454d9 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_d.js @@ -0,0 +1,13 @@ +var searchData= +[ + ['offer_5fend',['OFFER_END',['../group__Misc__APIs.html#gga47797d528afd74db93dd37a2c9207333ab67ba95f9dcf33d1cd600d798c76ab88',1,'esp_misc.h']]], + ['offer_5frouter',['OFFER_ROUTER',['../group__Misc__APIs.html#gga47797d528afd74db93dd37a2c9207333ad88e6ec93eb09e1cccb8d4d039681f42',1,'esp_misc.h']]], + ['offer_5fstart',['OFFER_START',['../group__Misc__APIs.html#gga47797d528afd74db93dd37a2c9207333a8d64153b2be4f126695bb7f6d36cff2c',1,'esp_misc.h']]], + ['old_5fmode',['old_mode',['../structEvent__StaMode__AuthMode__Change__t.html#aec107fd7e68f2881586ebd4c9d1df031',1,'Event_StaMode_AuthMode_Change_t']]], + ['os_5fdelay_5fus',['os_delay_us',['../group__Misc__APIs.html#ga34cbc249ab7d5737df5cbff540535f9f',1,'esp_misc.h']]], + ['os_5finstall_5fputc1',['os_install_putc1',['../group__Misc__APIs.html#ga1e58a0af820fa16197c614872b2d4eaa',1,'esp_misc.h']]], + ['os_5fputc',['os_putc',['../group__Misc__APIs.html#ga279c08566a8fb3910dff740c106cd26a',1,'esp_misc.h']]], + ['os_5ftimer_5farm',['os_timer_arm',['../group__Timer__APIs.html#ga26366c1af6634ad1bac5579c3cbe301d',1,'esp_timer.h']]], + ['os_5ftimer_5fdisarm',['os_timer_disarm',['../group__Timer__APIs.html#gae5d5bc766def32d5dbba2bb44e02fd00',1,'esp_timer.h']]], + ['os_5ftimer_5fsetfn',['os_timer_setfn',['../group__Timer__APIs.html#ga77b22f92e381327c7d717ab408df9967',1,'esp_timer.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_e.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_e.html new file mode 100644 index 0000000..07d5259 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_e.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_e.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_e.js new file mode 100644 index 0000000..8c29c94 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_e.js @@ -0,0 +1,20 @@ +var searchData= +[ + ['password',['password',['../structsoftap__config.html#a7f8efb8f0ad39a8b94c3407c841750bb',1,'softap_config::password()'],['../structstation__config.html#a7f8efb8f0ad39a8b94c3407c841750bb',1,'station_config::password()']]], + ['period',['period',['../structpwm__param.html#a3c1ef865ae62e58233701a3bfc68f262',1,'pwm_param']]], + ['phy_5fmode_5f11b',['PHY_MODE_11B',['../group__WiFi__Common__APIs.html#gga75ce0bfb28d23bd9b671608d38da34eaa1a1163f960df76560e7a230dfe5016ba',1,'esp_wifi.h']]], + ['phy_5fmode_5f11g',['PHY_MODE_11G',['../group__WiFi__Common__APIs.html#gga75ce0bfb28d23bd9b671608d38da34eaabf4e268c14075414d5a966ba274b6645',1,'esp_wifi.h']]], + ['phy_5fmode_5f11n',['PHY_MODE_11N',['../group__WiFi__Common__APIs.html#gga75ce0bfb28d23bd9b671608d38da34eaa4da3ad686cf4aec7cc445b0e76aa5a8e',1,'esp_wifi.h']]], + ['phys_5faddr',['phys_addr',['../structesp__spiffs__config.html#a7ba95ed315e15b8c4573ff01477b1ecf',1,'esp_spiffs_config']]], + ['phys_5ferase_5fblock',['phys_erase_block',['../structesp__spiffs__config.html#af4070ae5fe9914a88e6b5afa775c112a',1,'esp_spiffs_config']]], + ['phys_5fsize',['phys_size',['../structesp__spiffs__config.html#a3730a1b272a6d5d2f567a2876f4cdc46',1,'esp_spiffs_config']]], + ['pre_5fversion',['pre_version',['../structupgrade__server__info.html#ab7408cf1414fc2d3ebd4ced54962e2b8',1,'upgrade_server_info']]], + ['pwm_20driver_20apis',['PWM Driver APIs',['../group__PWM__Driver__APIs.html',1,'']]], + ['pwm_5fget_5fduty',['pwm_get_duty',['../group__PWM__Driver__APIs.html#gaa2c27474ef8774f6a85971f813785068',1,'pwm.h']]], + ['pwm_5fget_5fperiod',['pwm_get_period',['../group__PWM__Driver__APIs.html#ga347173af17daf294b4312d975f3bed8b',1,'pwm.h']]], + ['pwm_5finit',['pwm_init',['../group__PWM__Driver__APIs.html#ga96286902d138bbba183495583db6f369',1,'pwm.h']]], + ['pwm_5fparam',['pwm_param',['../structpwm__param.html',1,'']]], + ['pwm_5fset_5fduty',['pwm_set_duty',['../group__PWM__Driver__APIs.html#ga3c85e3b8654b48f23033f132b91c07b3',1,'pwm.h']]], + ['pwm_5fset_5fperiod',['pwm_set_period',['../group__PWM__Driver__APIs.html#ga57dad644319cd4324edd382d5ce772f5',1,'pwm.h']]], + ['pwm_5fstart',['pwm_start',['../group__PWM__Driver__APIs.html#gad405ef7080a8cea5c9ac23ba25da1fbb',1,'pwm.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_f.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_f.html new file mode 100644 index 0000000..2213eb2 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_f.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_f.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_f.js new file mode 100644 index 0000000..c9d9e74 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/all_f.js @@ -0,0 +1,21 @@ +var searchData= +[ + ['reason',['reason',['../structrst__info.html#af5b53fbb4b238f9aa0261eed1236b9ba',1,'rst_info::reason()'],['../structEvent__StaMode__Disconnected__t.html#abf07e8ad67430e516654d1b8d42b9731',1,'Event_StaMode_Disconnected_t::reason()']]], + ['reason_5fdeep_5fsleep_5fawake',['REASON_DEEP_SLEEP_AWAKE',['../group__System__APIs.html#ggaf560461b4a37405f75fd789165f6c576acee6519d545f6be1bac3e00be8637ee7',1,'esp_system.h']]], + ['reason_5fdefault_5frst',['REASON_DEFAULT_RST',['../group__System__APIs.html#ggaf560461b4a37405f75fd789165f6c576af39e71277c3bfc84b75a4a5683531565',1,'esp_system.h']]], + ['reason_5fexception_5frst',['REASON_EXCEPTION_RST',['../group__System__APIs.html#ggaf560461b4a37405f75fd789165f6c576a37032d096425911146ce105004cc8adb',1,'esp_system.h']]], + ['reason_5fext_5fsys_5frst',['REASON_EXT_SYS_RST',['../group__System__APIs.html#ggaf560461b4a37405f75fd789165f6c576a9ab5cbcccb384a176990019a8e1b2cc8',1,'esp_system.h']]], + ['reason_5fsoft_5frestart',['REASON_SOFT_RESTART',['../group__System__APIs.html#ggaf560461b4a37405f75fd789165f6c576a6d052f0a22d1b1d060a7e017f6152559',1,'esp_system.h']]], + ['reason_5fsoft_5fwdt_5frst',['REASON_SOFT_WDT_RST',['../group__System__APIs.html#ggaf560461b4a37405f75fd789165f6c576a57184a4fb4d760f85fd0834566bf6e9c',1,'esp_system.h']]], + ['reason_5fwdt_5frst',['REASON_WDT_RST',['../group__System__APIs.html#ggaf560461b4a37405f75fd789165f6c576a90f8f58c2fec687ee00f4735bf24006d',1,'esp_system.h']]], + ['reconnect_5fcallback',['reconnect_callback',['../struct__esp__tcp.html#a7dfb00c9f12a97566da16c71bebd253b',1,'_esp_tcp']]], + ['recv_5fcallback',['recv_callback',['../structespconn.html#a66d8db64dbb623bab3e442dd923371b5',1,'espconn']]], + ['remote_5fip',['remote_ip',['../struct__esp__tcp.html#a1e97206aeb1c8767a07fba34b0e10630',1,'_esp_tcp::remote_ip()'],['../struct__esp__udp.html#a1e97206aeb1c8767a07fba34b0e10630',1,'_esp_udp::remote_ip()'],['../struct__remot__info.html#a1e97206aeb1c8767a07fba34b0e10630',1,'_remot_info::remote_ip()']]], + ['remote_5fport',['remote_port',['../struct__esp__tcp.html#a50c260a2144cb980f505670e1ea22ccd',1,'_esp_tcp::remote_port()'],['../struct__esp__udp.html#a50c260a2144cb980f505670e1ea22ccd',1,'_esp_udp::remote_port()'],['../struct__remot__info.html#a50c260a2144cb980f505670e1ea22ccd',1,'_remot_info::remote_port()']]], + ['reserve',['reserve',['../structespconn.html#aaaa8d264a32f8754cf0ffa69f70d8f8d',1,'espconn']]], + ['rfid_5flocp_5fcb_5ft',['rfid_locp_cb_t',['../group__WiFi__Common__APIs.html#gae1c8898c72bc7b1dde854068662527bc',1,'esp_wifi.h']]], + ['rssi',['rssi',['../structbss__info.html#a919873edc1a7b2795e7efc5b9108ef53',1,'bss_info::rssi()'],['../structEvent__SoftAPMode__ProbeReqRecved__t.html#ab6f4522a5a5c4577c16d0e23339a1414',1,'Event_SoftAPMode_ProbeReqRecved_t::rssi()']]], + ['rst_5finfo',['rst_info',['../structrst__info.html',1,'']]], + ['rst_5freason',['rst_reason',['../group__System__APIs.html#gaf560461b4a37405f75fd789165f6c576',1,'esp_system.h']]], + ['rate_20control_20apis',['Rate Control APIs',['../group__WiFi__Rate__Control__APIs.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_0.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_0.html new file mode 100644 index 0000000..523591f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_0.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_0.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_0.js new file mode 100644 index 0000000..9a187c6 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_0.js @@ -0,0 +1,8 @@ +var searchData= +[ + ['_5fesp_5fevent',['_esp_event',['../struct__esp__event.html',1,'']]], + ['_5fesp_5ftcp',['_esp_tcp',['../struct__esp__tcp.html',1,'']]], + ['_5fesp_5fudp',['_esp_udp',['../struct__esp__udp.html',1,'']]], + ['_5fos_5ftimer_5ft',['_os_timer_t',['../struct__os__timer__t.html',1,'']]], + ['_5fremot_5finfo',['_remot_info',['../struct__remot__info.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_1.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_1.html new file mode 100644 index 0000000..f5a65ad --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_1.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_1.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_1.js new file mode 100644 index 0000000..8c2cb7d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_1.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['airkiss_5fconfig_5ft',['airkiss_config_t',['../structairkiss__config__t.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_2.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_2.html new file mode 100644 index 0000000..5b89b27 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_2.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_2.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_2.js new file mode 100644 index 0000000..6f2e394 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_2.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['bss_5finfo',['bss_info',['../structbss__info.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_3.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_3.html new file mode 100644 index 0000000..63ffc5d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_3.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_3.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_3.js new file mode 100644 index 0000000..ad9fccd --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_3.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['cmd_5fs',['cmd_s',['../structcmd__s.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_4.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_4.html new file mode 100644 index 0000000..4acce5b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_4.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_4.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_4.js new file mode 100644 index 0000000..d19fe64 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_4.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['dhcps_5flease',['dhcps_lease',['../structdhcps__lease.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_5.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_5.html new file mode 100644 index 0000000..67b3b9f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_5.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_5.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_5.js new file mode 100644 index 0000000..d0aabcf --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_5.js @@ -0,0 +1,14 @@ +var searchData= +[ + ['esp_5fspiffs_5fconfig',['esp_spiffs_config',['../structesp__spiffs__config.html',1,'']]], + ['espconn',['espconn',['../structespconn.html',1,'']]], + ['event_5finfo_5fu',['Event_Info_u',['../unionEvent__Info__u.html',1,'']]], + ['event_5fsoftapmode_5fprobereqrecved_5ft',['Event_SoftAPMode_ProbeReqRecved_t',['../structEvent__SoftAPMode__ProbeReqRecved__t.html',1,'']]], + ['event_5fsoftapmode_5fstaconnected_5ft',['Event_SoftAPMode_StaConnected_t',['../structEvent__SoftAPMode__StaConnected__t.html',1,'']]], + ['event_5fsoftapmode_5fstadisconnected_5ft',['Event_SoftAPMode_StaDisconnected_t',['../structEvent__SoftAPMode__StaDisconnected__t.html',1,'']]], + ['event_5fstamode_5fauthmode_5fchange_5ft',['Event_StaMode_AuthMode_Change_t',['../structEvent__StaMode__AuthMode__Change__t.html',1,'']]], + ['event_5fstamode_5fconnected_5ft',['Event_StaMode_Connected_t',['../structEvent__StaMode__Connected__t.html',1,'']]], + ['event_5fstamode_5fdisconnected_5ft',['Event_StaMode_Disconnected_t',['../structEvent__StaMode__Disconnected__t.html',1,'']]], + ['event_5fstamode_5fgot_5fip_5ft',['Event_StaMode_Got_IP_t',['../structEvent__StaMode__Got__IP__t.html',1,'']]], + ['event_5fstamode_5fscandone_5ft',['Event_StaMode_ScanDone_t',['../structEvent__StaMode__ScanDone__t.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_6.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_6.html new file mode 100644 index 0000000..ab174b5 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_6.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_6.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_6.js new file mode 100644 index 0000000..afd7f3a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_6.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['gpio_5fconfigtypedef',['GPIO_ConfigTypeDef',['../structGPIO__ConfigTypeDef.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_7.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_7.html new file mode 100644 index 0000000..737ed8b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_7.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_7.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_7.js new file mode 100644 index 0000000..cf3ee85 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_7.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['ip_5finfo',['ip_info',['../structip__info.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_8.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_8.html new file mode 100644 index 0000000..b58c4b4 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_8.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_8.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_8.js new file mode 100644 index 0000000..2360fa7 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_8.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['pwm_5fparam',['pwm_param',['../structpwm__param.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_9.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_9.html new file mode 100644 index 0000000..83984ab --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_9.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_9.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_9.js new file mode 100644 index 0000000..4cb3602 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_9.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['rst_5finfo',['rst_info',['../structrst__info.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_a.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_a.html new file mode 100644 index 0000000..8a0a656 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_a.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_a.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_a.js new file mode 100644 index 0000000..d54af8c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_a.js @@ -0,0 +1,8 @@ +var searchData= +[ + ['scan_5fconfig',['scan_config',['../structscan__config.html',1,'']]], + ['softap_5fconfig',['softap_config',['../structsoftap__config.html',1,'']]], + ['spiflashchip',['SpiFlashChip',['../structSpiFlashChip.html',1,'']]], + ['station_5fconfig',['station_config',['../structstation__config.html',1,'']]], + ['station_5finfo',['station_info',['../structstation__info.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_b.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_b.html new file mode 100644 index 0000000..3173cc0 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_b.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_b.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_b.js new file mode 100644 index 0000000..9aada1d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/classes_b.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['uart_5fconfigtypedef',['UART_ConfigTypeDef',['../structUART__ConfigTypeDef.html',1,'']]], + ['uart_5fintrconftypedef',['UART_IntrConfTypeDef',['../structUART__IntrConfTypeDef.html',1,'']]], + ['upgrade_5fserver_5finfo',['upgrade_server_info',['../structupgrade__server__info.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/close.png b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/close.png new file mode 100644 index 0000000000000000000000000000000000000000..9342d3dfeea7b7c4ee610987e717804b5a42ceb9 GIT binary patch literal 273 zcmV+s0q*{ZP)4(RlMby96)VwnbG{ zbe&}^BDn7x>$<{ck4zAK-=nT;=hHG)kmplIF${xqm8db3oX6wT3bvp`TE@m0cg;b) zBuSL}5?N7O(iZLdAlz@)b)Rd~DnSsSX&P5qC`XwuFwcAYLC+d2>+1(8on;wpt8QIC X2MT$R4iQDd00000NkvXXu0mjfia~GN literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_0.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_0.html new file mode 100644 index 0000000..d8d79a3 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_0.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_0.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_0.js new file mode 100644 index 0000000..93c22f3 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_0.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['airkiss_5flan_5fret_5ft',['airkiss_lan_ret_t',['../group__AirKiss__APIs.html#gaa0ebed8b87dd27c1c1d80c316fe2e691',1,'airkiss.h']]], + ['auth_5fmode',['AUTH_MODE',['../group__WiFi__Common__APIs.html#ga49c8969263c0503dbe9811f16c500296',1,'esp_wifi.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_1.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_1.html new file mode 100644 index 0000000..9c2ae9a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_1.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_1.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_1.js new file mode 100644 index 0000000..be8964d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_1.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['dhcp_5fstatus',['dhcp_status',['../group__Misc__APIs.html#ga9e40444d24f71f875b15136edec8fc47',1,'esp_misc.h']]], + ['dhcps_5foffer_5foption',['dhcps_offer_option',['../group__Misc__APIs.html#ga47797d528afd74db93dd37a2c9207333',1,'esp_misc.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_2.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_2.html new file mode 100644 index 0000000..e547781 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_2.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_2.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_2.js new file mode 100644 index 0000000..c1f2d21 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_2.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['espconn_5flevel',['espconn_level',['../group__Espconn__APIs.html#gaaae7451fb36d445e625d52b3f0eec36e',1,'espconn.h']]], + ['espconn_5foption',['espconn_option',['../group__Espconn__APIs.html#ga9db40198a52a9becd150a851f9855a92',1,'espconn.h']]], + ['espconn_5fstate',['espconn_state',['../group__Espconn__APIs.html#ga27ebed6341108494ecf41ec8a7d37c4b',1,'espconn.h']]], + ['espconn_5ftype',['espconn_type',['../group__Espconn__APIs.html#ga822c96862e04f46aff8d65cb8170b60f',1,'espconn.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_3.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_3.html new file mode 100644 index 0000000..16795d5 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_3.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_3.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_3.js new file mode 100644 index 0000000..e2621f7 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_3.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['flash_5fsize_5fmap',['flash_size_map',['../group__System__boot__APIs.html#ga09fedddfc198c6f5b12e795d7a560de2',1,'esp_system.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_4.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_4.html new file mode 100644 index 0000000..55ec3ef --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_4.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_4.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_4.js new file mode 100644 index 0000000..3f71a62 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_4.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['mesh_5fnode_5ftype',['mesh_node_type',['../group__Mesh__APIs.html#ga4947b8b90891b481b81383e08d45c346',1,'mesh.h']]], + ['mesh_5fstatus',['mesh_status',['../group__Mesh__APIs.html#ga73a6546355fa7461bbe09af0643c719e',1,'mesh.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_5.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_5.html new file mode 100644 index 0000000..5e1b3fa --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_5.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_5.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_5.js new file mode 100644 index 0000000..62a7ddc --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_5.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['rst_5freason',['rst_reason',['../group__System__APIs.html#gaf560461b4a37405f75fd789165f6c576',1,'esp_system.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_6.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_6.html new file mode 100644 index 0000000..66cc643 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_6.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_6.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_6.js new file mode 100644 index 0000000..0384663 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_6.js @@ -0,0 +1,8 @@ +var searchData= +[ + ['sc_5fstatus',['sc_status',['../group__Smartconfig__APIs.html#gafec33e52eaa14ed795ab28ce69c685e3',1,'smartconfig.h']]], + ['sc_5ftype',['sc_type',['../group__Smartconfig__APIs.html#ga533261c0af94cdbb04fe90f452af9b9d',1,'smartconfig.h']]], + ['spiflashopresult',['SpiFlashOpResult',['../group__SPI__Driver__APIs.html#ga7546515bb162fd2bb252ebe20fd92dbe',1,'spi_flash.h']]], + ['station_5fstatus',['STATION_STATUS',['../group__Station__APIs.html#ga4c23fd73def991ebbce2a16bf7d474bc',1,'esp_sta.h']]], + ['system_5fevent',['SYSTEM_EVENT',['../group__WiFi__Common__APIs.html#gaeecbdf938220e31d3d52cd49c57400bd',1,'esp_wifi.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_7.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_7.html new file mode 100644 index 0000000..18a38c3 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_7.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_7.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_7.js new file mode 100644 index 0000000..2fc46a4 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enums_7.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['wifi_5finterface',['WIFI_INTERFACE',['../group__WiFi__Common__APIs.html#gaea3f7e6b27f1008eb9fa2d0fac3de857',1,'esp_wifi.h']]], + ['wifi_5fmode',['WIFI_MODE',['../group__WiFi__Common__APIs.html#ga2cdd09724a071506f717d721f6aa633c',1,'esp_wifi.h']]], + ['wifi_5fphy_5fmode',['WIFI_PHY_MODE',['../group__WiFi__Common__APIs.html#ga75ce0bfb28d23bd9b671608d38da34ea',1,'esp_wifi.h']]], + ['wps_5fcb_5fstatus',['wps_cb_status',['../group__WPS__APIs.html#gad7729ea41405ddb427166e3c6ed9407a',1,'esp_wps.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_0.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_0.html new file mode 100644 index 0000000..450f1ac --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_0.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_0.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_0.js new file mode 100644 index 0000000..07d0aaf --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_0.js @@ -0,0 +1,16 @@ +var searchData= +[ + ['airkiss_5flan_5fcontinue',['AIRKISS_LAN_CONTINUE',['../group__AirKiss__APIs.html#ggaa0ebed8b87dd27c1c1d80c316fe2e691a6c669d0e28f90ea37e6aea8f9084c0d1',1,'airkiss.h']]], + ['airkiss_5flan_5ferr_5fcmd',['AIRKISS_LAN_ERR_CMD',['../group__AirKiss__APIs.html#ggaa0ebed8b87dd27c1c1d80c316fe2e691a30641c2d4b8fee854a90861f957c5923',1,'airkiss.h']]], + ['airkiss_5flan_5ferr_5foverflow',['AIRKISS_LAN_ERR_OVERFLOW',['../group__AirKiss__APIs.html#ggaa0ebed8b87dd27c1c1d80c316fe2e691a3eec80987fe47f20344931bf4afeb4e4',1,'airkiss.h']]], + ['airkiss_5flan_5ferr_5fpake',['AIRKISS_LAN_ERR_PAKE',['../group__AirKiss__APIs.html#ggaa0ebed8b87dd27c1c1d80c316fe2e691aa48241b150e73210e45c81aa9b76137f',1,'airkiss.h']]], + ['airkiss_5flan_5ferr_5fpara',['AIRKISS_LAN_ERR_PARA',['../group__AirKiss__APIs.html#ggaa0ebed8b87dd27c1c1d80c316fe2e691ae4043da2985abd40a90fd198fd607622',1,'airkiss.h']]], + ['airkiss_5flan_5ferr_5fpkg',['AIRKISS_LAN_ERR_PKG',['../group__AirKiss__APIs.html#ggaa0ebed8b87dd27c1c1d80c316fe2e691a14bf764748a58af181c316c2e2ee5322',1,'airkiss.h']]], + ['airkiss_5flan_5fpake_5fready',['AIRKISS_LAN_PAKE_READY',['../group__AirKiss__APIs.html#ggaa0ebed8b87dd27c1c1d80c316fe2e691a5743b4699a34a902a43540149ef380fb',1,'airkiss.h']]], + ['airkiss_5flan_5fssdp_5freq',['AIRKISS_LAN_SSDP_REQ',['../group__AirKiss__APIs.html#ggaa0ebed8b87dd27c1c1d80c316fe2e691aad38be677ab42b9f59e773c456695b02',1,'airkiss.h']]], + ['auth_5fopen',['AUTH_OPEN',['../group__WiFi__Common__APIs.html#gga49c8969263c0503dbe9811f16c500296a5611249f5c4eb3fde3ad3d20334176c0',1,'esp_wifi.h']]], + ['auth_5fwep',['AUTH_WEP',['../group__WiFi__Common__APIs.html#gga49c8969263c0503dbe9811f16c500296a9026e85ef4d28d1dfa1073b2b5cfb759',1,'esp_wifi.h']]], + ['auth_5fwpa2_5fpsk',['AUTH_WPA2_PSK',['../group__WiFi__Common__APIs.html#gga49c8969263c0503dbe9811f16c500296ac24ee2c2098f0a76fe72aec33847b36c',1,'esp_wifi.h']]], + ['auth_5fwpa_5fpsk',['AUTH_WPA_PSK',['../group__WiFi__Common__APIs.html#gga49c8969263c0503dbe9811f16c500296a90870da11cf3408b057beb4abf9fe1bb',1,'esp_wifi.h']]], + ['auth_5fwpa_5fwpa2_5fpsk',['AUTH_WPA_WPA2_PSK',['../group__WiFi__Common__APIs.html#gga49c8969263c0503dbe9811f16c500296aa01ed8cd33a42c2837a09cdcb5cb5931',1,'esp_wifi.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_1.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_1.html new file mode 100644 index 0000000..ac8ff57 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_1.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_1.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_1.js new file mode 100644 index 0000000..adf54c7 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_1.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['dhcp_5fstarted',['DHCP_STARTED',['../group__Misc__APIs.html#gga9e40444d24f71f875b15136edec8fc47af861d0338581584e3be0abd10af2d0ff',1,'esp_misc.h']]], + ['dhcp_5fstopped',['DHCP_STOPPED',['../group__Misc__APIs.html#gga9e40444d24f71f875b15136edec8fc47a7c9cbdc204a9ed4b2a46cec8daeacfb8',1,'esp_misc.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_2.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_2.html new file mode 100644 index 0000000..71e42ad --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_2.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_2.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_2.js new file mode 100644 index 0000000..5115c6a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_2.js @@ -0,0 +1,31 @@ +var searchData= +[ + ['espconn_5fclose',['ESPCONN_CLOSE',['../group__Espconn__APIs.html#gga27ebed6341108494ecf41ec8a7d37c4ba755ebf5af367126c8c2c33f8e919bac4',1,'espconn.h']]], + ['espconn_5fconnect',['ESPCONN_CONNECT',['../group__Espconn__APIs.html#gga27ebed6341108494ecf41ec8a7d37c4ba2581f4215688fddcb1852ea4cbbcdaef',1,'espconn.h']]], + ['espconn_5fcopy',['ESPCONN_COPY',['../group__Espconn__APIs.html#gga9db40198a52a9becd150a851f9855a92a5a42c1ab1c6a9e2cce272046bce29687',1,'espconn.h']]], + ['espconn_5fend',['ESPCONN_END',['../group__Espconn__APIs.html#gga9db40198a52a9becd150a851f9855a92ae2ad46665b977365b8cc24f2b325155f',1,'espconn.h']]], + ['espconn_5finvalid',['ESPCONN_INVALID',['../group__Espconn__APIs.html#gga822c96862e04f46aff8d65cb8170b60faf10957d87831780be73e55426e8da737',1,'espconn.h']]], + ['espconn_5fkeepalive',['ESPCONN_KEEPALIVE',['../group__Espconn__APIs.html#gga9db40198a52a9becd150a851f9855a92a131641817461609c89b8086dd90f64a9',1,'espconn.h']]], + ['espconn_5fkeepcnt',['ESPCONN_KEEPCNT',['../group__Espconn__APIs.html#ggaaae7451fb36d445e625d52b3f0eec36ea1e723b94b0ac601545a717261203eb1b',1,'espconn.h']]], + ['espconn_5fkeepidle',['ESPCONN_KEEPIDLE',['../group__Espconn__APIs.html#ggaaae7451fb36d445e625d52b3f0eec36ea858f5c8ad925f16f59eb728619235e8b',1,'espconn.h']]], + ['espconn_5fkeepintvl',['ESPCONN_KEEPINTVL',['../group__Espconn__APIs.html#ggaaae7451fb36d445e625d52b3f0eec36ea9266ad9351007ce73e8877405970a6d8',1,'espconn.h']]], + ['espconn_5flisten',['ESPCONN_LISTEN',['../group__Espconn__APIs.html#gga27ebed6341108494ecf41ec8a7d37c4ba97c2f022ffce819bc2658f4e5796543a',1,'espconn.h']]], + ['espconn_5fnodelay',['ESPCONN_NODELAY',['../group__Espconn__APIs.html#gga9db40198a52a9becd150a851f9855a92a22a60c5e343e19f83f9facedc8cd6f89',1,'espconn.h']]], + ['espconn_5fnone',['ESPCONN_NONE',['../group__Espconn__APIs.html#gga27ebed6341108494ecf41ec8a7d37c4ba7dd74b008ab5d04f15ff84de4b70bf90',1,'espconn.h']]], + ['espconn_5fread',['ESPCONN_READ',['../group__Espconn__APIs.html#gga27ebed6341108494ecf41ec8a7d37c4ba01caf55e6b01ffa1089348102d42734c',1,'espconn.h']]], + ['espconn_5freuseaddr',['ESPCONN_REUSEADDR',['../group__Espconn__APIs.html#gga9db40198a52a9becd150a851f9855a92a8c4b05b4bdbd12c64f1809c48d99e395',1,'espconn.h']]], + ['espconn_5fstart',['ESPCONN_START',['../group__Espconn__APIs.html#gga9db40198a52a9becd150a851f9855a92a9cb44b08d9f53701b054b08d04f7d71f',1,'espconn.h']]], + ['espconn_5ftcp',['ESPCONN_TCP',['../group__Espconn__APIs.html#gga822c96862e04f46aff8d65cb8170b60faf9113ca7b14a1637d2a0099367622879',1,'espconn.h']]], + ['espconn_5fudp',['ESPCONN_UDP',['../group__Espconn__APIs.html#gga822c96862e04f46aff8d65cb8170b60fa85d8592fc339ccda13561161ddfd63f7',1,'espconn.h']]], + ['espconn_5fwait',['ESPCONN_WAIT',['../group__Espconn__APIs.html#gga27ebed6341108494ecf41ec8a7d37c4baa13c91321f9aef1bf5023f1ea18e093a',1,'espconn.h']]], + ['espconn_5fwrite',['ESPCONN_WRITE',['../group__Espconn__APIs.html#gga27ebed6341108494ecf41ec8a7d37c4bab7b47f073e3e6db0ce792ab8fff1df02',1,'espconn.h']]], + ['event_5fsoftapmode_5fprobereqrecved',['EVENT_SOFTAPMODE_PROBEREQRECVED',['../group__WiFi__Common__APIs.html#ggaeecbdf938220e31d3d52cd49c57400bdafe4cacbfe933b32292c05dcc69faad50',1,'esp_wifi.h']]], + ['event_5fsoftapmode_5fstaconnected',['EVENT_SOFTAPMODE_STACONNECTED',['../group__WiFi__Common__APIs.html#ggaeecbdf938220e31d3d52cd49c57400bdadcf5be1211c8c8348981847ff00b9381',1,'esp_wifi.h']]], + ['event_5fsoftapmode_5fstadisconnected',['EVENT_SOFTAPMODE_STADISCONNECTED',['../group__WiFi__Common__APIs.html#ggaeecbdf938220e31d3d52cd49c57400bda5ba176bb1121e6a273c6400fd0bb2da8',1,'esp_wifi.h']]], + ['event_5fstamode_5fauthmode_5fchange',['EVENT_STAMODE_AUTHMODE_CHANGE',['../group__WiFi__Common__APIs.html#ggaeecbdf938220e31d3d52cd49c57400bdae6c201c8b490470cb65b166f0081c181',1,'esp_wifi.h']]], + ['event_5fstamode_5fconnected',['EVENT_STAMODE_CONNECTED',['../group__WiFi__Common__APIs.html#ggaeecbdf938220e31d3d52cd49c57400bdaa9d9acf861ff464e516aa92c8179a9f5',1,'esp_wifi.h']]], + ['event_5fstamode_5fdhcp_5ftimeout',['EVENT_STAMODE_DHCP_TIMEOUT',['../group__WiFi__Common__APIs.html#ggaeecbdf938220e31d3d52cd49c57400bdaa3b272b55e1cb2ceef2080d4d05add01',1,'esp_wifi.h']]], + ['event_5fstamode_5fdisconnected',['EVENT_STAMODE_DISCONNECTED',['../group__WiFi__Common__APIs.html#ggaeecbdf938220e31d3d52cd49c57400bda3e65821c77d0a3fe3e48d70f51412775',1,'esp_wifi.h']]], + ['event_5fstamode_5fgot_5fip',['EVENT_STAMODE_GOT_IP',['../group__WiFi__Common__APIs.html#ggaeecbdf938220e31d3d52cd49c57400bda7b92b134071315f5d10222e00b756620',1,'esp_wifi.h']]], + ['event_5fstamode_5fscan_5fdone',['EVENT_STAMODE_SCAN_DONE',['../group__WiFi__Common__APIs.html#ggaeecbdf938220e31d3d52cd49c57400bda1db1eab9330111152c3d468e672d8885',1,'esp_wifi.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_3.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_3.html new file mode 100644 index 0000000..a7d9109 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_3.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_3.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_3.js new file mode 100644 index 0000000..173cb34 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_3.js @@ -0,0 +1,10 @@ +var searchData= +[ + ['flash_5fsize_5f16m_5fmap_5f1024_5f1024',['FLASH_SIZE_16M_MAP_1024_1024',['../group__System__boot__APIs.html#gga09fedddfc198c6f5b12e795d7a560de2a1c1807f4d5cccfdf38f15a603e7557ce',1,'esp_system.h']]], + ['flash_5fsize_5f16m_5fmap_5f512_5f512',['FLASH_SIZE_16M_MAP_512_512',['../group__System__boot__APIs.html#gga09fedddfc198c6f5b12e795d7a560de2a58eeb18a28a2904a2424ce808ed0e2a6',1,'esp_system.h']]], + ['flash_5fsize_5f2m',['FLASH_SIZE_2M',['../group__System__boot__APIs.html#gga09fedddfc198c6f5b12e795d7a560de2a68191ccca310b30e6a0f6cfac494321c',1,'esp_system.h']]], + ['flash_5fsize_5f32m_5fmap_5f1024_5f1024',['FLASH_SIZE_32M_MAP_1024_1024',['../group__System__boot__APIs.html#gga09fedddfc198c6f5b12e795d7a560de2aa88e113314ba8a3de7fe693c1c14b9a0',1,'esp_system.h']]], + ['flash_5fsize_5f32m_5fmap_5f512_5f512',['FLASH_SIZE_32M_MAP_512_512',['../group__System__boot__APIs.html#gga09fedddfc198c6f5b12e795d7a560de2af31f99de17734586c910bddfe8c427bf',1,'esp_system.h']]], + ['flash_5fsize_5f4m_5fmap_5f256_5f256',['FLASH_SIZE_4M_MAP_256_256',['../group__System__boot__APIs.html#gga09fedddfc198c6f5b12e795d7a560de2a4c0ac10cfa5e7ecc6cc95b60e0faeb70',1,'esp_system.h']]], + ['flash_5fsize_5f8m_5fmap_5f512_5f512',['FLASH_SIZE_8M_MAP_512_512',['../group__System__boot__APIs.html#gga09fedddfc198c6f5b12e795d7a560de2a6de4efc98763d016d92d87fb73ca8849',1,'esp_system.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_4.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_4.html new file mode 100644 index 0000000..5b4a765 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_4.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_4.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_4.js new file mode 100644 index 0000000..7811a8a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_4.js @@ -0,0 +1,11 @@ +var searchData= +[ + ['mesh_5fdisable',['MESH_DISABLE',['../group__Mesh__APIs.html#gga73a6546355fa7461bbe09af0643c719ea34024c70dfdfac6cd104addcb7efdf4b',1,'mesh.h']]], + ['mesh_5flocal_5favail',['MESH_LOCAL_AVAIL',['../group__Mesh__APIs.html#gga73a6546355fa7461bbe09af0643c719ea2db29fbbb0d36ee854ddbf7325b4dbc0',1,'mesh.h']]], + ['mesh_5fnet_5fconn',['MESH_NET_CONN',['../group__Mesh__APIs.html#gga73a6546355fa7461bbe09af0643c719eaf8707ddf897e616743134a1e28ed03f4',1,'mesh.h']]], + ['mesh_5fnode_5fall',['MESH_NODE_ALL',['../group__Mesh__APIs.html#gga4947b8b90891b481b81383e08d45c346a95346a7d9886d3e5781fec75aff99ad7',1,'mesh.h']]], + ['mesh_5fnode_5fchild',['MESH_NODE_CHILD',['../group__Mesh__APIs.html#gga4947b8b90891b481b81383e08d45c346ad1d85742ae6b9b121f3f5dc6f93827f4',1,'mesh.h']]], + ['mesh_5fnode_5fparent',['MESH_NODE_PARENT',['../group__Mesh__APIs.html#gga4947b8b90891b481b81383e08d45c346a8dc1197b5edf569a7e041845c7aae34e',1,'mesh.h']]], + ['mesh_5fonline_5favail',['MESH_ONLINE_AVAIL',['../group__Mesh__APIs.html#gga73a6546355fa7461bbe09af0643c719ea3ed309a6fce09a48d29a668345170026',1,'mesh.h']]], + ['mesh_5fwifi_5fconn',['MESH_WIFI_CONN',['../group__Mesh__APIs.html#gga73a6546355fa7461bbe09af0643c719eafc8893dffe37c367602bd732dd57277f',1,'mesh.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_5.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_5.html new file mode 100644 index 0000000..dc7d99f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_5.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_5.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_5.js new file mode 100644 index 0000000..fceec68 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_5.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['null_5fmode',['NULL_MODE',['../group__WiFi__Common__APIs.html#gga2cdd09724a071506f717d721f6aa633ca055d8a581738cc0181ce387afe3ab99a',1,'esp_wifi.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_6.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_6.html new file mode 100644 index 0000000..af14f29 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_6.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_6.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_6.js new file mode 100644 index 0000000..888c62b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_6.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['offer_5fend',['OFFER_END',['../group__Misc__APIs.html#gga47797d528afd74db93dd37a2c9207333ab67ba95f9dcf33d1cd600d798c76ab88',1,'esp_misc.h']]], + ['offer_5frouter',['OFFER_ROUTER',['../group__Misc__APIs.html#gga47797d528afd74db93dd37a2c9207333ad88e6ec93eb09e1cccb8d4d039681f42',1,'esp_misc.h']]], + ['offer_5fstart',['OFFER_START',['../group__Misc__APIs.html#gga47797d528afd74db93dd37a2c9207333a8d64153b2be4f126695bb7f6d36cff2c',1,'esp_misc.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_7.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_7.html new file mode 100644 index 0000000..ecc13a0 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_7.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_7.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_7.js new file mode 100644 index 0000000..01e8650 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_7.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['phy_5fmode_5f11b',['PHY_MODE_11B',['../group__WiFi__Common__APIs.html#gga75ce0bfb28d23bd9b671608d38da34eaa1a1163f960df76560e7a230dfe5016ba',1,'esp_wifi.h']]], + ['phy_5fmode_5f11g',['PHY_MODE_11G',['../group__WiFi__Common__APIs.html#gga75ce0bfb28d23bd9b671608d38da34eaabf4e268c14075414d5a966ba274b6645',1,'esp_wifi.h']]], + ['phy_5fmode_5f11n',['PHY_MODE_11N',['../group__WiFi__Common__APIs.html#gga75ce0bfb28d23bd9b671608d38da34eaa4da3ad686cf4aec7cc445b0e76aa5a8e',1,'esp_wifi.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_8.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_8.html new file mode 100644 index 0000000..2202dd5 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_8.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_8.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_8.js new file mode 100644 index 0000000..cdba028 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_8.js @@ -0,0 +1,10 @@ +var searchData= +[ + ['reason_5fdeep_5fsleep_5fawake',['REASON_DEEP_SLEEP_AWAKE',['../group__System__APIs.html#ggaf560461b4a37405f75fd789165f6c576acee6519d545f6be1bac3e00be8637ee7',1,'esp_system.h']]], + ['reason_5fdefault_5frst',['REASON_DEFAULT_RST',['../group__System__APIs.html#ggaf560461b4a37405f75fd789165f6c576af39e71277c3bfc84b75a4a5683531565',1,'esp_system.h']]], + ['reason_5fexception_5frst',['REASON_EXCEPTION_RST',['../group__System__APIs.html#ggaf560461b4a37405f75fd789165f6c576a37032d096425911146ce105004cc8adb',1,'esp_system.h']]], + ['reason_5fext_5fsys_5frst',['REASON_EXT_SYS_RST',['../group__System__APIs.html#ggaf560461b4a37405f75fd789165f6c576a9ab5cbcccb384a176990019a8e1b2cc8',1,'esp_system.h']]], + ['reason_5fsoft_5frestart',['REASON_SOFT_RESTART',['../group__System__APIs.html#ggaf560461b4a37405f75fd789165f6c576a6d052f0a22d1b1d060a7e017f6152559',1,'esp_system.h']]], + ['reason_5fsoft_5fwdt_5frst',['REASON_SOFT_WDT_RST',['../group__System__APIs.html#ggaf560461b4a37405f75fd789165f6c576a57184a4fb4d760f85fd0834566bf6e9c',1,'esp_system.h']]], + ['reason_5fwdt_5frst',['REASON_WDT_RST',['../group__System__APIs.html#ggaf560461b4a37405f75fd789165f6c576a90f8f58c2fec687ee00f4735bf24006d',1,'esp_system.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_9.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_9.html new file mode 100644 index 0000000..597e954 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_9.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_9.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_9.js new file mode 100644 index 0000000..c760cbe --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_9.js @@ -0,0 +1,25 @@ +var searchData= +[ + ['sc_5fstatus_5ffind_5fchannel',['SC_STATUS_FIND_CHANNEL',['../group__Smartconfig__APIs.html#ggafec33e52eaa14ed795ab28ce69c685e3a30fee0de55f059ac14821f8e2b22ac03',1,'smartconfig.h']]], + ['sc_5fstatus_5fgetting_5fssid_5fpswd',['SC_STATUS_GETTING_SSID_PSWD',['../group__Smartconfig__APIs.html#ggafec33e52eaa14ed795ab28ce69c685e3aefc9b644b16531defe122b7316cea0c0',1,'smartconfig.h']]], + ['sc_5fstatus_5flink',['SC_STATUS_LINK',['../group__Smartconfig__APIs.html#ggafec33e52eaa14ed795ab28ce69c685e3aae1dcaae9b8358bd43499bbca2e0bf95',1,'smartconfig.h']]], + ['sc_5fstatus_5flink_5fover',['SC_STATUS_LINK_OVER',['../group__Smartconfig__APIs.html#ggafec33e52eaa14ed795ab28ce69c685e3a1ae1253a12888c150c36cd30f56394dc',1,'smartconfig.h']]], + ['sc_5fstatus_5fwait',['SC_STATUS_WAIT',['../group__Smartconfig__APIs.html#ggafec33e52eaa14ed795ab28ce69c685e3a3de75e54ab5d15e0aa697d2d35adc363',1,'smartconfig.h']]], + ['sc_5ftype_5fairkiss',['SC_TYPE_AIRKISS',['../group__Smartconfig__APIs.html#gga533261c0af94cdbb04fe90f452af9b9da6254d899f4bf164fdb0f3dd778c206e9',1,'smartconfig.h']]], + ['sc_5ftype_5fesptouch',['SC_TYPE_ESPTOUCH',['../group__Smartconfig__APIs.html#gga533261c0af94cdbb04fe90f452af9b9dabae45491cc05b00bd1b069bb61e37b01',1,'smartconfig.h']]], + ['sc_5ftype_5fesptouch_5fairkiss',['SC_TYPE_ESPTOUCH_AIRKISS',['../group__Smartconfig__APIs.html#gga533261c0af94cdbb04fe90f452af9b9da50e8065c00b088cdb87b8b0ded4a853c',1,'smartconfig.h']]], + ['softap_5fif',['SOFTAP_IF',['../group__WiFi__Common__APIs.html#ggaea3f7e6b27f1008eb9fa2d0fac3de857af55135c54ee2a64ba9c52a74cf2fd189',1,'esp_wifi.h']]], + ['softap_5fmode',['SOFTAP_MODE',['../group__WiFi__Common__APIs.html#gga2cdd09724a071506f717d721f6aa633ca92e54e4df3bbe26a86fee10322867a8f',1,'esp_wifi.h']]], + ['spi_5fflash_5fresult_5ferr',['SPI_FLASH_RESULT_ERR',['../group__SPI__Driver__APIs.html#gga7546515bb162fd2bb252ebe20fd92dbea6a7e104b6106ddf6a7fa6e2fbe93edca',1,'spi_flash.h']]], + ['spi_5fflash_5fresult_5fok',['SPI_FLASH_RESULT_OK',['../group__SPI__Driver__APIs.html#gga7546515bb162fd2bb252ebe20fd92dbea8c0e5ba08fbb8fbe8f5f1a6eac6e01cc',1,'spi_flash.h']]], + ['spi_5fflash_5fresult_5ftimeout',['SPI_FLASH_RESULT_TIMEOUT',['../group__SPI__Driver__APIs.html#gga7546515bb162fd2bb252ebe20fd92dbea266272773eeee7e649575a8ad4f5d119',1,'spi_flash.h']]], + ['station_5fconnect_5ffail',['STATION_CONNECT_FAIL',['../group__Station__APIs.html#gga4c23fd73def991ebbce2a16bf7d474bca25d788a7722116d2bf2b26bb6402d118',1,'esp_sta.h']]], + ['station_5fconnecting',['STATION_CONNECTING',['../group__Station__APIs.html#gga4c23fd73def991ebbce2a16bf7d474bcaff0fbe033edf483a60063bdfcf1e39b9',1,'esp_sta.h']]], + ['station_5fgot_5fip',['STATION_GOT_IP',['../group__Station__APIs.html#gga4c23fd73def991ebbce2a16bf7d474bca6df279173c26c3e7b1c65fdd41b50889',1,'esp_sta.h']]], + ['station_5fidle',['STATION_IDLE',['../group__Station__APIs.html#gga4c23fd73def991ebbce2a16bf7d474bca27894ff65729ce4cf0a322e2e3a71c04',1,'esp_sta.h']]], + ['station_5fif',['STATION_IF',['../group__WiFi__Common__APIs.html#ggaea3f7e6b27f1008eb9fa2d0fac3de857a71d2c1b8dd45be5f720c155153cd6803',1,'esp_wifi.h']]], + ['station_5fmode',['STATION_MODE',['../group__WiFi__Common__APIs.html#gga2cdd09724a071506f717d721f6aa633cabd03eae7aff57049c70079dc7877de47',1,'esp_wifi.h']]], + ['station_5fno_5fap_5ffound',['STATION_NO_AP_FOUND',['../group__Station__APIs.html#gga4c23fd73def991ebbce2a16bf7d474bca95a3d4b77c93e76281ff5355f24acfd0',1,'esp_sta.h']]], + ['station_5fwrong_5fpassword',['STATION_WRONG_PASSWORD',['../group__Station__APIs.html#gga4c23fd73def991ebbce2a16bf7d474bcaa9d77c934ee5b916f3ff0743204f3d7a',1,'esp_sta.h']]], + ['stationap_5fmode',['STATIONAP_MODE',['../group__WiFi__Common__APIs.html#gga2cdd09724a071506f717d721f6aa633caa5510a47f526ca8c4de330fd05fb5032',1,'esp_wifi.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_a.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_a.html new file mode 100644 index 0000000..8545d24 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_a.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_a.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_a.js new file mode 100644 index 0000000..fb31802 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/enumvalues_a.js @@ -0,0 +1,8 @@ +var searchData= +[ + ['wps_5fcb_5fst_5ffailed',['WPS_CB_ST_FAILED',['../group__WPS__APIs.html#ggad7729ea41405ddb427166e3c6ed9407aa82d6a587f16918a5e08fc7bd72e82256',1,'esp_wps.h']]], + ['wps_5fcb_5fst_5fscan_5ferr',['WPS_CB_ST_SCAN_ERR',['../group__WPS__APIs.html#ggad7729ea41405ddb427166e3c6ed9407aabebbd63e324d7efaaaa19643b6db3c5b',1,'esp_wps.h']]], + ['wps_5fcb_5fst_5fsuccess',['WPS_CB_ST_SUCCESS',['../group__WPS__APIs.html#ggad7729ea41405ddb427166e3c6ed9407aac8a6efa900487f4e54f8f09acd2fc4f8',1,'esp_wps.h']]], + ['wps_5fcb_5fst_5ftimeout',['WPS_CB_ST_TIMEOUT',['../group__WPS__APIs.html#ggad7729ea41405ddb427166e3c6ed9407aa06494c31ab495602b84bbf165ecdeffd',1,'esp_wps.h']]], + ['wps_5fcb_5fst_5fwep',['WPS_CB_ST_WEP',['../group__WPS__APIs.html#ggad7729ea41405ddb427166e3c6ed9407aabb3484dae0443776c8afe92d23d82621',1,'esp_wps.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_0.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_0.html new file mode 100644 index 0000000..246d167 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_0.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_0.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_0.js new file mode 100644 index 0000000..36e2f11 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_0.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['airkiss_5flan_5fpack',['airkiss_lan_pack',['../group__AirKiss__APIs.html#gab6bab3b00620928bca5e2adc0d2abd31',1,'airkiss.h']]], + ['airkiss_5flan_5frecv',['airkiss_lan_recv',['../group__AirKiss__APIs.html#ga7545a7e75de00da0b22c232de602e092',1,'airkiss.h']]], + ['airkiss_5fversion',['airkiss_version',['../group__AirKiss__APIs.html#gad2485fae7edd33913a96ae91fd277acd',1,'airkiss.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_1.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_1.html new file mode 100644 index 0000000..5f14d67 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_1.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_1.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_1.js new file mode 100644 index 0000000..44a1050 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_1.js @@ -0,0 +1,74 @@ +var searchData= +[ + ['esp_5fnow_5fadd_5fpeer',['esp_now_add_peer',['../group__ESPNow__APIs.html#ga780113b4069cbf971a58353987d25240',1,'espnow.h']]], + ['esp_5fnow_5fdeinit',['esp_now_deinit',['../group__ESPNow__APIs.html#ga5a85f4807948eaa75b76ebef7cad1a22',1,'espnow.h']]], + ['esp_5fnow_5fdel_5fpeer',['esp_now_del_peer',['../group__ESPNow__APIs.html#gab5b0ca5ece92af7fb04c27a8c1bfce4d',1,'espnow.h']]], + ['esp_5fnow_5ffetch_5fpeer',['esp_now_fetch_peer',['../group__ESPNow__APIs.html#gaffa4f035416078c3d0dbf34f2d67795a',1,'espnow.h']]], + ['esp_5fnow_5fget_5fcnt_5finfo',['esp_now_get_cnt_info',['../group__ESPNow__APIs.html#ga59320ae71ba3f4d4b2904e69ce7b72f2',1,'espnow.h']]], + ['esp_5fnow_5fget_5fpeer_5fchannel',['esp_now_get_peer_channel',['../group__ESPNow__APIs.html#ga42cd1efe5ef32d2f35682bccddb5d83e',1,'espnow.h']]], + ['esp_5fnow_5fget_5fpeer_5fkey',['esp_now_get_peer_key',['../group__ESPNow__APIs.html#ga6b2c449a35daf4c91e51496f7622f2a0',1,'espnow.h']]], + ['esp_5fnow_5fget_5fpeer_5frole',['esp_now_get_peer_role',['../group__ESPNow__APIs.html#ga0629a89cf89b13439f8306fe0ba95023',1,'espnow.h']]], + ['esp_5fnow_5fget_5fself_5frole',['esp_now_get_self_role',['../group__ESPNow__APIs.html#ga5838cbb89faf492c4904fab6d83b87bb',1,'espnow.h']]], + ['esp_5fnow_5finit',['esp_now_init',['../group__ESPNow__APIs.html#ga407ae697a77bd49ade96fc2a72f49636',1,'espnow.h']]], + ['esp_5fnow_5fis_5fpeer_5fexist',['esp_now_is_peer_exist',['../group__ESPNow__APIs.html#ga735fbbcc99172abd887d1e248a7e9fb3',1,'espnow.h']]], + ['esp_5fnow_5fregister_5frecv_5fcb',['esp_now_register_recv_cb',['../group__ESPNow__APIs.html#gaf3488572d55b5b2f3748a7a87e902a0f',1,'espnow.h']]], + ['esp_5fnow_5fregister_5fsend_5fcb',['esp_now_register_send_cb',['../group__ESPNow__APIs.html#ga6dbbbb859a5d37c2b74a79baaa8011f0',1,'espnow.h']]], + ['esp_5fnow_5fsend',['esp_now_send',['../group__ESPNow__APIs.html#ga2ef5f592b161d885b6f0d8dde18ff802',1,'espnow.h']]], + ['esp_5fnow_5fset_5fkok',['esp_now_set_kok',['../group__ESPNow__APIs.html#gaab9b169f115cffd354637c79d2a16789',1,'espnow.h']]], + ['esp_5fnow_5fset_5fpeer_5fchannel',['esp_now_set_peer_channel',['../group__ESPNow__APIs.html#ga49e3aa3ba63d7883124e1dfcf2a0533b',1,'espnow.h']]], + ['esp_5fnow_5fset_5fpeer_5fkey',['esp_now_set_peer_key',['../group__ESPNow__APIs.html#ga936b9caa1127d362aa63225f865afd99',1,'espnow.h']]], + ['esp_5fnow_5fset_5fpeer_5frole',['esp_now_set_peer_role',['../group__ESPNow__APIs.html#ga7a5f50b81300b3b8ae403854d76901a3',1,'espnow.h']]], + ['esp_5fnow_5fset_5fself_5frole',['esp_now_set_self_role',['../group__ESPNow__APIs.html#ga08297bacf8c88648d09c11ba3b69d594',1,'espnow.h']]], + ['esp_5fnow_5funregister_5frecv_5fcb',['esp_now_unregister_recv_cb',['../group__ESPNow__APIs.html#gaac4facb9a7ec9bf4c7c0e18054664b03',1,'espnow.h']]], + ['esp_5fnow_5funregister_5fsend_5fcb',['esp_now_unregister_send_cb',['../group__ESPNow__APIs.html#gacf2a9263a2f55d55440dbf7ca2b43709',1,'espnow.h']]], + ['esp_5fspiffs_5fdeinit',['esp_spiffs_deinit',['../group__Spiffs__APIs.html#ga03894c9cf5d03c55d9f406ea5b58651d',1,'esp_spiffs.h']]], + ['esp_5fspiffs_5finit',['esp_spiffs_init',['../group__Spiffs__APIs.html#ga72e4d349ef03c2671462a12976e4552f',1,'esp_spiffs.h']]], + ['espconn_5faccept',['espconn_accept',['../group__Espconn__APIs.html#gabd44446e3fc4a61fdef77d473deb678b',1,'espconn.h']]], + ['espconn_5fclear_5fopt',['espconn_clear_opt',['../group__Espconn__APIs.html#ga9a8be5ecdee08ca20a2516c4aa289c5e',1,'espconn.h']]], + ['espconn_5fconnect',['espconn_connect',['../group__Espconn__APIs.html#ga949cd618667cea85b1b99d14b90dce7d',1,'espconn.h']]], + ['espconn_5fcreate',['espconn_create',['../group__Espconn__APIs.html#gad55b9729c7629f40c8e7ae2d73f7f174',1,'espconn.h']]], + ['espconn_5fdelete',['espconn_delete',['../group__Espconn__APIs.html#ga63d15dda14dfcd8da278c31f048910c3',1,'espconn.h']]], + ['espconn_5fdisconnect',['espconn_disconnect',['../group__Espconn__APIs.html#ga9969873c3b8ee86a34496a5166cf8bfc',1,'espconn.h']]], + ['espconn_5fdns_5fsetserver',['espconn_dns_setserver',['../group__Espconn__APIs.html#gabc578b3f5f5701f2a140683a4524ff0a',1,'espconn.h']]], + ['espconn_5fget_5fconnection_5finfo',['espconn_get_connection_info',['../group__Espconn__APIs.html#ga95deabffd3b8a4bec81f91596901f84d',1,'espconn.h']]], + ['espconn_5fget_5fkeepalive',['espconn_get_keepalive',['../group__Espconn__APIs.html#gae7b470d0af4052d0945ed87ffbf8e684',1,'espconn.h']]], + ['espconn_5fgethostbyname',['espconn_gethostbyname',['../group__Espconn__APIs.html#ga34a3074b536dfc09c842b75210cfcdf1',1,'espconn.h']]], + ['espconn_5figmp_5fjoin',['espconn_igmp_join',['../group__Espconn__APIs.html#ga7858298be65d5fb385e0614775799292',1,'espconn.h']]], + ['espconn_5figmp_5fleave',['espconn_igmp_leave',['../group__Espconn__APIs.html#ga49a50b6b7007818a45e5aa7eb19eace9',1,'espconn.h']]], + ['espconn_5finit',['espconn_init',['../group__Espconn__APIs.html#gab1bd524be2b4c1b727e3519e3cae69bf',1,'espconn.h']]], + ['espconn_5fmesh_5fconnect',['espconn_mesh_connect',['../group__Mesh__APIs.html#gaa00a7caa98b654fe5435f5990d99c06d',1,'mesh.h']]], + ['espconn_5fmesh_5fdisable',['espconn_mesh_disable',['../group__Mesh__APIs.html#ga130feda4a6e3a5e7ed1d750b6c4bc6ee',1,'mesh.h']]], + ['espconn_5fmesh_5fdisconnect',['espconn_mesh_disconnect',['../group__Mesh__APIs.html#ga819e5e382bc1aaa254a347b2eb880250',1,'mesh.h']]], + ['espconn_5fmesh_5fenable',['espconn_mesh_enable',['../group__Mesh__APIs.html#gab9f4efbcf201ac6b1425cf447485f7d8',1,'mesh.h']]], + ['espconn_5fmesh_5fencrypt_5finit',['espconn_mesh_encrypt_init',['../group__Mesh__APIs.html#gad6bb1d256497efb94543235414a1f7e5',1,'mesh.h']]], + ['espconn_5fmesh_5fget_5fmax_5fhops',['espconn_mesh_get_max_hops',['../group__Mesh__APIs.html#ga3dea1ef65bbb8c168082de273588c040',1,'mesh.h']]], + ['espconn_5fmesh_5fget_5fnode_5finfo',['espconn_mesh_get_node_info',['../group__Mesh__APIs.html#gacfa17fe9fe638da7cea59ff5f63e887e',1,'mesh.h']]], + ['espconn_5fmesh_5fget_5fstatus',['espconn_mesh_get_status',['../group__Mesh__APIs.html#gafec6034951b2c5cf70a7ea1c7707a03f',1,'mesh.h']]], + ['espconn_5fmesh_5fgroup_5fid_5finit',['espconn_mesh_group_id_init',['../group__Mesh__APIs.html#gad9db6b93cb1e3f37efdbb7a3e5180556',1,'mesh.h']]], + ['espconn_5fmesh_5finit',['espconn_mesh_init',['../group__Mesh__APIs.html#gacb87f54723aeacf3f4336eb1eb78633a',1,'mesh.h']]], + ['espconn_5fmesh_5flocal_5faddr',['espconn_mesh_local_addr',['../group__Mesh__APIs.html#ga3b2ebffff1527d4fb3fec86ab73c804b',1,'mesh.h']]], + ['espconn_5fmesh_5fsent',['espconn_mesh_sent',['../group__Mesh__APIs.html#ga8c60c7f53352f4e12bda09d0f2484075',1,'mesh.h']]], + ['espconn_5fmesh_5fset_5fdev_5ftype',['espconn_mesh_set_dev_type',['../group__Mesh__APIs.html#ga7cb73ffe93d15bfe0bcc6c5d17bef4ac',1,'mesh.h']]], + ['espconn_5fmesh_5fset_5fmax_5fhops',['espconn_mesh_set_max_hops',['../group__Mesh__APIs.html#ga4e2fd63e3eeaeba305b5ded90fcc753f',1,'mesh.h']]], + ['espconn_5fmesh_5fset_5fssid_5fprefix',['espconn_mesh_set_ssid_prefix',['../group__Mesh__APIs.html#ga55a5712902986a0cfc4e57fbb7d34821',1,'mesh.h']]], + ['espconn_5fport',['espconn_port',['../group__Espconn__APIs.html#ga8666579cda9afb8e01dff613326062c0',1,'espconn.h']]], + ['espconn_5frecv_5fhold',['espconn_recv_hold',['../group__Espconn__APIs.html#ga2193ea6779889bef71dc6d368c6b8f80',1,'espconn.h']]], + ['espconn_5frecv_5funhold',['espconn_recv_unhold',['../group__Espconn__APIs.html#gac409e8c250ee409985475f5c7fa02950',1,'espconn.h']]], + ['espconn_5fregist_5fconnectcb',['espconn_regist_connectcb',['../group__Espconn__APIs.html#ga233874487e43ccdacf772e47bcd9b976',1,'espconn.h']]], + ['espconn_5fregist_5fdisconcb',['espconn_regist_disconcb',['../group__Espconn__APIs.html#gaf43c93f2f0cc14a1c1e95c38e9469b9f',1,'espconn.h']]], + ['espconn_5fregist_5freconcb',['espconn_regist_reconcb',['../group__Espconn__APIs.html#ga771463177734012911e42931a10ee7a2',1,'espconn.h']]], + ['espconn_5fregist_5frecvcb',['espconn_regist_recvcb',['../group__Espconn__APIs.html#ga56d063a430d96d20b4ea5e28ba41011c',1,'espconn.h']]], + ['espconn_5fregist_5fsentcb',['espconn_regist_sentcb',['../group__Espconn__APIs.html#ga438ded04b3f8a70948fcf8c551bce179',1,'espconn.h']]], + ['espconn_5fregist_5ftime',['espconn_regist_time',['../group__Espconn__APIs.html#gacd79a347f8e665d7b93f31569865b494',1,'espconn.h']]], + ['espconn_5fregist_5fwrite_5ffinish',['espconn_regist_write_finish',['../group__Espconn__APIs.html#ga28cae7c705c8d3da7bb614b6c41c8d1a',1,'espconn.h']]], + ['espconn_5fsend',['espconn_send',['../group__Espconn__APIs.html#ga6677ecbe38ce063102e4b7a733829a7f',1,'espconn.h']]], + ['espconn_5fsendto',['espconn_sendto',['../group__Espconn__APIs.html#ga62219be0ac7e8dd6085915d5c0777476',1,'espconn.h']]], + ['espconn_5fsent',['espconn_sent',['../group__Espconn__APIs.html#ga579e4f1c62f7c33be01398931617e988',1,'espconn.h']]], + ['espconn_5fset_5fkeepalive',['espconn_set_keepalive',['../group__Espconn__APIs.html#ga0a78bf74f326d99a2cb498a338da8240',1,'espconn.h']]], + ['espconn_5fset_5fopt',['espconn_set_opt',['../group__Espconn__APIs.html#gac76f13b1bd09b3e43beedd50907e0c72',1,'espconn.h']]], + ['espconn_5ftcp_5fget_5fmax_5fcon',['espconn_tcp_get_max_con',['../group__Espconn__APIs.html#gaa7665768ea19f95957284938cc0af950',1,'espconn.h']]], + ['espconn_5ftcp_5fget_5fmax_5fcon_5fallow',['espconn_tcp_get_max_con_allow',['../group__Espconn__APIs.html#ga8418023ae67bd83742d7d2642c3d4da0',1,'espconn.h']]], + ['espconn_5ftcp_5fset_5fmax_5fcon',['espconn_tcp_set_max_con',['../group__Espconn__APIs.html#ga6281d28b05672dc10f702f0e5386fb98',1,'espconn.h']]], + ['espconn_5ftcp_5fset_5fmax_5fcon_5fallow',['espconn_tcp_set_max_con_allow',['../group__Espconn__APIs.html#gaef6e59fa5bb5d813449d190e2fe66b2e',1,'espconn.h']]], + ['esptouch_5fset_5ftimeout',['esptouch_set_timeout',['../group__Smartconfig__APIs.html#ga068b054aecdba51c0ea5219089d5b3c0',1,'smartconfig.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_2.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_2.html new file mode 100644 index 0000000..3995cf8 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_2.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_2.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_2.js new file mode 100644 index 0000000..bc139c0 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_2.js @@ -0,0 +1,13 @@ +var searchData= +[ + ['gpio16_5finput_5fconf',['gpio16_input_conf',['../group__GPIO__Driver__APIs.html#gacc7e5be6c1aed84fe3c3260deea64a3e',1,'gpio.h']]], + ['gpio16_5finput_5fget',['gpio16_input_get',['../group__GPIO__Driver__APIs.html#ga4484530a542760c430ebb2e754b6e621',1,'gpio.h']]], + ['gpio16_5foutput_5fconf',['gpio16_output_conf',['../group__GPIO__Driver__APIs.html#gaf94c9f201c7ee9ad7a71b5eb8b720b00',1,'gpio.h']]], + ['gpio16_5foutput_5fset',['gpio16_output_set',['../group__GPIO__Driver__APIs.html#ga4f83a12f673ab6e664c6ea129a1ca9c2',1,'gpio.h']]], + ['gpio_5finput_5fget',['gpio_input_get',['../group__GPIO__Driver__APIs.html#ga678824698fa5936b7928c24c6cfd0a17',1,'gpio.h']]], + ['gpio_5fintr_5fhandler_5fregister',['gpio_intr_handler_register',['../group__GPIO__Driver__APIs.html#ga7b94b7d43c84a8177f4301b6a001fae3',1,'gpio.h']]], + ['gpio_5foutput_5fconf',['gpio_output_conf',['../group__GPIO__Driver__APIs.html#gad57551861ccb3b7f4d16c0de00717e29',1,'gpio.h']]], + ['gpio_5fpin_5fintr_5fstate_5fset',['gpio_pin_intr_state_set',['../group__GPIO__Driver__APIs.html#ga0adef8a3e9d5c302d96d1ddc360f7c79',1,'gpio.h']]], + ['gpio_5fpin_5fwakeup_5fdisable',['gpio_pin_wakeup_disable',['../group__GPIO__Driver__APIs.html#gaffbe088057472f44ddf99c7912f54300',1,'gpio.h']]], + ['gpio_5fpin_5fwakeup_5fenable',['gpio_pin_wakeup_enable',['../group__GPIO__Driver__APIs.html#gae37bc72b183440f9733f14df516cee7b',1,'gpio.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_3.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_3.html new file mode 100644 index 0000000..4e302d6 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_3.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_3.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_3.js new file mode 100644 index 0000000..7215b8c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_3.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['hw_5ftimer_5farm',['hw_timer_arm',['../group__HW__Timer__APIs.html#gace64c59d338a9d785bd5730029086553',1,'hw_timer.h']]], + ['hw_5ftimer_5finit',['hw_timer_init',['../group__HW__Timer__APIs.html#ga09f8d1ed286cb02bfe47bc5f6c67b570',1,'hw_timer.h']]], + ['hw_5ftimer_5fset_5ffunc',['hw_timer_set_func',['../group__HW__Timer__APIs.html#ga78c91a9ec46aa9fb5b9fae9d357e9957',1,'hw_timer.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_4.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_4.html new file mode 100644 index 0000000..58ca83a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_4.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_4.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_4.js new file mode 100644 index 0000000..c894ee4 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_4.js @@ -0,0 +1,9 @@ +var searchData= +[ + ['os_5fdelay_5fus',['os_delay_us',['../group__Misc__APIs.html#ga34cbc249ab7d5737df5cbff540535f9f',1,'esp_misc.h']]], + ['os_5finstall_5fputc1',['os_install_putc1',['../group__Misc__APIs.html#ga1e58a0af820fa16197c614872b2d4eaa',1,'esp_misc.h']]], + ['os_5fputc',['os_putc',['../group__Misc__APIs.html#ga279c08566a8fb3910dff740c106cd26a',1,'esp_misc.h']]], + ['os_5ftimer_5farm',['os_timer_arm',['../group__Timer__APIs.html#ga26366c1af6634ad1bac5579c3cbe301d',1,'esp_timer.h']]], + ['os_5ftimer_5fdisarm',['os_timer_disarm',['../group__Timer__APIs.html#gae5d5bc766def32d5dbba2bb44e02fd00',1,'esp_timer.h']]], + ['os_5ftimer_5fsetfn',['os_timer_setfn',['../group__Timer__APIs.html#ga77b22f92e381327c7d717ab408df9967',1,'esp_timer.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_5.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_5.html new file mode 100644 index 0000000..5f9f05a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_5.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_5.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_5.js new file mode 100644 index 0000000..ba3b8b9 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_5.js @@ -0,0 +1,9 @@ +var searchData= +[ + ['pwm_5fget_5fduty',['pwm_get_duty',['../group__PWM__Driver__APIs.html#gaa2c27474ef8774f6a85971f813785068',1,'pwm.h']]], + ['pwm_5fget_5fperiod',['pwm_get_period',['../group__PWM__Driver__APIs.html#ga347173af17daf294b4312d975f3bed8b',1,'pwm.h']]], + ['pwm_5finit',['pwm_init',['../group__PWM__Driver__APIs.html#ga96286902d138bbba183495583db6f369',1,'pwm.h']]], + ['pwm_5fset_5fduty',['pwm_set_duty',['../group__PWM__Driver__APIs.html#ga3c85e3b8654b48f23033f132b91c07b3',1,'pwm.h']]], + ['pwm_5fset_5fperiod',['pwm_set_period',['../group__PWM__Driver__APIs.html#ga57dad644319cd4324edd382d5ce772f5',1,'pwm.h']]], + ['pwm_5fstart',['pwm_start',['../group__PWM__Driver__APIs.html#gad405ef7080a8cea5c9ac23ba25da1fbb',1,'pwm.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_6.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_6.html new file mode 100644 index 0000000..c980da2 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_6.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_6.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_6.js new file mode 100644 index 0000000..978ed69 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_6.js @@ -0,0 +1,58 @@ +var searchData= +[ + ['smartconfig_5fget_5fversion',['smartconfig_get_version',['../group__Smartconfig__APIs.html#ga9537246ce540bc1e1a294de687d488bf',1,'smartconfig.h']]], + ['smartconfig_5fset_5ftype',['smartconfig_set_type',['../group__Smartconfig__APIs.html#ga14d5f55176a12436d58014272f6df156',1,'smartconfig.h']]], + ['smartconfig_5fstart',['smartconfig_start',['../group__Smartconfig__APIs.html#ga390ec2c5af28b29044899c8ffd016b04',1,'smartconfig.h']]], + ['smartconfig_5fstop',['smartconfig_stop',['../group__Smartconfig__APIs.html#ga85819fc5109441eae24e4262ca34bd48',1,'smartconfig.h']]], + ['spi_5fflash_5ferase_5fsector',['spi_flash_erase_sector',['../group__SPI__Driver__APIs.html#ga3210ddd52247977cff3d018bf34f9048',1,'spi_flash.h']]], + ['spi_5fflash_5fget_5fid',['spi_flash_get_id',['../group__SPI__Driver__APIs.html#ga9ffc628fbfc74b51a78ed0a03c3f8dd0',1,'spi_flash.h']]], + ['spi_5fflash_5fread',['spi_flash_read',['../group__SPI__Driver__APIs.html#gacfd871ce143884d5c3dfb456024b0096',1,'spi_flash.h']]], + ['spi_5fflash_5fread_5fstatus',['spi_flash_read_status',['../group__SPI__Driver__APIs.html#ga8bd9176a0db21f8a04c0ab8792b74fec',1,'spi_flash.h']]], + ['spi_5fflash_5fset_5fread_5ffunc',['spi_flash_set_read_func',['../group__SPI__Driver__APIs.html#ga826a3caeec9fd019d6a30c3113d1547e',1,'spi_flash.h']]], + ['spi_5fflash_5fwrite',['spi_flash_write',['../group__SPI__Driver__APIs.html#ga97906813255238cdb0da4d21040abf90',1,'spi_flash.h']]], + ['spi_5fflash_5fwrite_5fstatus',['spi_flash_write_status',['../group__SPI__Driver__APIs.html#ga0e1358b06ac94b1e94c6aec83d034c56',1,'spi_flash.h']]], + ['ssc_5fattach',['ssc_attach',['../group__SSC__APIs.html#ga43430a78447488ff0f9b854a55c52c15',1,'esp_ssc.h']]], + ['ssc_5fparam_5flen',['ssc_param_len',['../group__SSC__APIs.html#gad4623d4bbefc7aa8609027c5acaa21f1',1,'esp_ssc.h']]], + ['ssc_5fparam_5fstr',['ssc_param_str',['../group__SSC__APIs.html#ga3d6124b4b604fa47f591fbfd44667d10',1,'esp_ssc.h']]], + ['ssc_5fparse_5fparam',['ssc_parse_param',['../group__SSC__APIs.html#gaab6bf99fc9487915cec7b2fe690ef08c',1,'esp_ssc.h']]], + ['ssc_5fregister',['ssc_register',['../group__SSC__APIs.html#ga9a8525423b629764cd90e132bf3d8c0b',1,'esp_ssc.h']]], + ['stailq_5fentry',['STAILQ_ENTRY',['../structstation__info.html#aad64fb4a210e02bd3b25891e29d39a95',1,'station_info::STAILQ_ENTRY()'],['../structbss__info.html#a792bb0f673392f8281c38ea1e3568073',1,'bss_info::STAILQ_ENTRY()']]], + ['system_5fadc_5fread',['system_adc_read',['../group__System__APIs.html#ga3b49ed94048da366d384364482c5ae43',1,'esp_system.h']]], + ['system_5fdeep_5fsleep',['system_deep_sleep',['../group__System__APIs.html#ga2b2d62411a8baa3b7fec777d281397e1',1,'esp_system.h']]], + ['system_5fdeep_5fsleep_5fset_5foption',['system_deep_sleep_set_option',['../group__System__APIs.html#gaaaf7c29067d92bf6c03747b4ad2c2bf6',1,'esp_system.h']]], + ['system_5fget_5fboot_5fmode',['system_get_boot_mode',['../group__System__boot__APIs.html#ga0663faaa88f4c899daf21e54400dfed0',1,'esp_system.h']]], + ['system_5fget_5fboot_5fversion',['system_get_boot_version',['../group__System__boot__APIs.html#gadecd4fbc78bf128281c5e48055155864',1,'esp_system.h']]], + ['system_5fget_5fchip_5fid',['system_get_chip_id',['../group__System__APIs.html#ga86228f8d572c91ec871684121dad0647',1,'esp_system.h']]], + ['system_5fget_5fcpu_5ffreq',['system_get_cpu_freq',['../group__System__boot__APIs.html#ga9ed4a3a5a4d57e26ed5250a423a5c3a0',1,'esp_system.h']]], + ['system_5fget_5fflash_5fsize_5fmap',['system_get_flash_size_map',['../group__System__boot__APIs.html#gae173ade9144230f0b8f950a804d4afd5',1,'esp_system.h']]], + ['system_5fget_5ffree_5fheap_5fsize',['system_get_free_heap_size',['../group__System__APIs.html#ga258edd68184bb78f062a3b375dca997c',1,'esp_system.h']]], + ['system_5fget_5frst_5finfo',['system_get_rst_info',['../group__System__APIs.html#ga9f0263b1c227015248c7020e41d787b9',1,'esp_system.h']]], + ['system_5fget_5frtc_5ftime',['system_get_rtc_time',['../group__System__APIs.html#gaff1e2f744888e01d75bbb1cb2fdee0cb',1,'esp_system.h']]], + ['system_5fget_5fsdk_5fversion',['system_get_sdk_version',['../group__System__APIs.html#ga82dfc665528462dbaa945e45512b8c93',1,'esp_system.h']]], + ['system_5fget_5ftime',['system_get_time',['../group__System__APIs.html#gaff40fbcef002e346e8f36c378cf75d86',1,'esp_system.h']]], + ['system_5fget_5fuserbin_5faddr',['system_get_userbin_addr',['../group__System__boot__APIs.html#gaa2fd426b0a2cb0bf77cbc0868ad63e77',1,'esp_system.h']]], + ['system_5fget_5fvdd33',['system_get_vdd33',['../group__System__APIs.html#gacf1baad08cac941b54b44126045e38cc',1,'esp_system.h']]], + ['system_5fparam_5fload',['system_param_load',['../group__System__APIs.html#ga753aade115708d360f25bff422ef1f55',1,'esp_system.h']]], + ['system_5fparam_5fsave_5fwith_5fprotect',['system_param_save_with_protect',['../group__System__APIs.html#gae68a7b6345630e42fde3e827108571e0',1,'esp_system.h']]], + ['system_5fphy_5fset_5fmax_5ftpw',['system_phy_set_max_tpw',['../group__System__APIs.html#gafc39ba5754615bd82e13302e289651ee',1,'esp_system.h']]], + ['system_5fphy_5fset_5frfoption',['system_phy_set_rfoption',['../group__System__APIs.html#ga96d92897e242b7f1bcd484e58f3b4a66',1,'esp_system.h']]], + ['system_5fphy_5fset_5ftpw_5fvia_5fvdd33',['system_phy_set_tpw_via_vdd33',['../group__System__APIs.html#ga7d3301798674f7ed1163f0b2ed333c44',1,'esp_system.h']]], + ['system_5fprint_5fmeminfo',['system_print_meminfo',['../group__System__APIs.html#ga3103885b6ff682cac77fea78c2b73425',1,'esp_system.h']]], + ['system_5frestart',['system_restart',['../group__System__APIs.html#ga80e0119dbfcaaa43025fe2135d3d1efc',1,'esp_system.h']]], + ['system_5frestart_5fenhance',['system_restart_enhance',['../group__System__boot__APIs.html#gaf7b2162f7ed788f3e8d8d90b27f60e7f',1,'esp_system.h']]], + ['system_5frestore',['system_restore',['../group__System__APIs.html#gae04bb6e4dba5ca53c4f5af629c235bec',1,'esp_system.h']]], + ['system_5frtc_5fclock_5fcali_5fproc',['system_rtc_clock_cali_proc',['../group__System__APIs.html#ga53909af3917e5dafc57c5a4d75e6ca2a',1,'esp_system.h']]], + ['system_5frtc_5fmem_5fread',['system_rtc_mem_read',['../group__System__APIs.html#gac89e6906018b3f4ccd1ba4059f344d5e',1,'esp_system.h']]], + ['system_5frtc_5fmem_5fwrite',['system_rtc_mem_write',['../group__System__APIs.html#ga669af802153a408dbf9b8b34697e34e2',1,'esp_system.h']]], + ['system_5fuart_5fde_5fswap',['system_uart_de_swap',['../group__System__APIs.html#ga2fe928c2d760669eaa7928b6e00c615c',1,'esp_system.h']]], + ['system_5fuart_5fswap',['system_uart_swap',['../group__System__APIs.html#ga6fc697cba1894da7a66d8816ec590682',1,'esp_system.h']]], + ['system_5fupdate_5fcpu_5ffreq',['system_update_cpu_freq',['../group__System__boot__APIs.html#ga0590aa925e7f87eb6cfc81d5577fc98a',1,'esp_system.h']]], + ['system_5fupgrade',['system_upgrade',['../group__Upgrade__APIs.html#ga738472f97b8dc72342cb3eb6b984d0bd',1,'upgrade.h']]], + ['system_5fupgrade_5fdeinit',['system_upgrade_deinit',['../group__Upgrade__APIs.html#ga643d7df496074bba1c6d165a3b5c7296',1,'upgrade.h']]], + ['system_5fupgrade_5fflag_5fcheck',['system_upgrade_flag_check',['../group__Upgrade__APIs.html#ga18b07d5b7a8b951a41da50506e03c837',1,'esp_system.h']]], + ['system_5fupgrade_5fflag_5fset',['system_upgrade_flag_set',['../group__Upgrade__APIs.html#ga6760e9df629662611372bcdfca7a4f77',1,'esp_system.h']]], + ['system_5fupgrade_5finit',['system_upgrade_init',['../group__Upgrade__APIs.html#ga9b7abd9fa4790f5807c20a24e5e9a51a',1,'upgrade.h']]], + ['system_5fupgrade_5freboot',['system_upgrade_reboot',['../group__Upgrade__APIs.html#gafbc93a806155a9cf65d25119df0c6b1d',1,'esp_system.h']]], + ['system_5fupgrade_5fstart',['system_upgrade_start',['../group__Upgrade__APIs.html#ga9575df7b73865f9a373637c1d7a3763f',1,'upgrade.h']]], + ['system_5fupgrade_5fuserbin_5fcheck',['system_upgrade_userbin_check',['../group__Upgrade__APIs.html#gad04181af74584d470c30d6c21dd2db85',1,'esp_system.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_7.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_7.html new file mode 100644 index 0000000..3857329 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_7.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_7.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_7.js new file mode 100644 index 0000000..7198699 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_7.js @@ -0,0 +1,18 @@ +var searchData= +[ + ['uart_5fclearintrstatus',['UART_ClearIntrStatus',['../group__UART__Driver__APIs.html#ga805fa76dba1011c2c84c986fa6b55bad',1,'uart.h']]], + ['uart_5finit_5fnew',['uart_init_new',['../group__UART__Driver__APIs.html#gaf76603d6634a53a0f678ef6451fe2b4e',1,'uart.h']]], + ['uart_5fintr_5fhandler_5fregister',['UART_intr_handler_register',['../group__UART__Driver__APIs.html#ga09240ead2da85d23b9af33585c972eb7',1,'uart.h']]], + ['uart_5fintrconfig',['UART_IntrConfig',['../group__UART__Driver__APIs.html#ga11d7ecf6eb666e29f19ed1c01d70221f',1,'uart.h']]], + ['uart_5fparamconfig',['UART_ParamConfig',['../group__UART__Driver__APIs.html#ga7acf0ca55c5f3449933864112e054bfc',1,'uart.h']]], + ['uart_5fresetfifo',['UART_ResetFifo',['../group__UART__Driver__APIs.html#ga408ab554bfe539dbba0561ec6c2794c7',1,'uart.h']]], + ['uart_5fsetbaudrate',['UART_SetBaudrate',['../group__UART__Driver__APIs.html#ga09596c76ab170e0440ea64ca9b677680',1,'uart.h']]], + ['uart_5fsetflowctrl',['UART_SetFlowCtrl',['../group__UART__Driver__APIs.html#ga5989d1e1de100edc2f7a2f5254053b6a',1,'uart.h']]], + ['uart_5fsetintrena',['UART_SetIntrEna',['../group__UART__Driver__APIs.html#ga0d23d8ca7457e4785f514ae5fbb761f0',1,'uart.h']]], + ['uart_5fsetlineinverse',['UART_SetLineInverse',['../group__UART__Driver__APIs.html#ga66f2b126442f8b9e0ea8472a0c7ffee6',1,'uart.h']]], + ['uart_5fsetparity',['UART_SetParity',['../group__UART__Driver__APIs.html#ga0b10d5990a126b715cfc4f1bf018148a',1,'uart.h']]], + ['uart_5fsetprintport',['UART_SetPrintPort',['../group__UART__Driver__APIs.html#gad7d853939e394a209f41b98e99778cc2',1,'uart.h']]], + ['uart_5fsetstopbits',['UART_SetStopBits',['../group__UART__Driver__APIs.html#ga52fbc6f996d0b4b8ef7354932d0bac54',1,'uart.h']]], + ['uart_5fsetwordlength',['UART_SetWordLength',['../group__UART__Driver__APIs.html#gad0f29e4f5d178e756bbc42711044dae2',1,'uart.h']]], + ['uart_5fwaittxfifoempty',['UART_WaitTxFifoEmpty',['../group__UART__Driver__APIs.html#gafd23b8eef2c570b8c785b83aa2a5caee',1,'uart.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_8.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_8.html new file mode 100644 index 0000000..088e437 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_8.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_8.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_8.js new file mode 100644 index 0000000..06bed6c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/functions_8.js @@ -0,0 +1,88 @@ +var searchData= +[ + ['wifi_5ffpm_5fclose',['wifi_fpm_close',['../group__WiFi__Force__Sleep__APIs.html#gaa20f76f974962fe47ae31c0f65b657c1',1,'esp_wifi.h']]], + ['wifi_5ffpm_5fdo_5fsleep',['wifi_fpm_do_sleep',['../group__WiFi__Force__Sleep__APIs.html#ga51dffd1b54e5a225378632d08162b048',1,'esp_wifi.h']]], + ['wifi_5ffpm_5fdo_5fwakeup',['wifi_fpm_do_wakeup',['../group__WiFi__Force__Sleep__APIs.html#gaa0c860b5a8fac128712596db935b174c',1,'esp_wifi.h']]], + ['wifi_5ffpm_5fget_5fsleep_5ftype',['wifi_fpm_get_sleep_type',['../group__WiFi__Force__Sleep__APIs.html#ga46b8069d18c7d8657dae947bc3c47faa',1,'esp_wifi.h']]], + ['wifi_5ffpm_5fopen',['wifi_fpm_open',['../group__WiFi__Force__Sleep__APIs.html#ga18a528b1a07c371a92fec9668a8526bf',1,'esp_wifi.h']]], + ['wifi_5ffpm_5fset_5fsleep_5ftype',['wifi_fpm_set_sleep_type',['../group__WiFi__Force__Sleep__APIs.html#ga8fbbe4c4d1399e6e39bb8ae1f0c10737',1,'esp_wifi.h']]], + ['wifi_5ffpm_5fset_5fwakeup_5fcb',['wifi_fpm_set_wakeup_cb',['../group__WiFi__Force__Sleep__APIs.html#ga60a15e23e9026636a71251e0fe46b16d',1,'esp_wifi.h']]], + ['wifi_5fget_5fchannel',['wifi_get_channel',['../group__WiFi__Sniffer__APIs.html#ga152796dafaf3baffe84e1a45ff05b5e0',1,'esp_wifi.h']]], + ['wifi_5fget_5fip_5finfo',['wifi_get_ip_info',['../group__WiFi__Common__APIs.html#ga536807ea21e2273344dbc4711a25f4a6',1,'esp_wifi.h']]], + ['wifi_5fget_5fmacaddr',['wifi_get_macaddr',['../group__WiFi__Common__APIs.html#gafe236024d7e749725b8c089fe0cedfba',1,'esp_wifi.h']]], + ['wifi_5fget_5fopmode',['wifi_get_opmode',['../group__WiFi__Common__APIs.html#ga8cb277f2cbfd5778c72c2d66375e0caf',1,'esp_wifi.h']]], + ['wifi_5fget_5fopmode_5fdefault',['wifi_get_opmode_default',['../group__WiFi__Common__APIs.html#ga68a1594d0a0a830d5c57c7fdbe03faf9',1,'esp_wifi.h']]], + ['wifi_5fget_5fphy_5fmode',['wifi_get_phy_mode',['../group__WiFi__Common__APIs.html#gacf50acde50fcc315ee58099a9c158d2a',1,'esp_wifi.h']]], + ['wifi_5fget_5fsleep_5ftype',['wifi_get_sleep_type',['../group__WiFi__Common__APIs.html#ga26409ea2492ddd98181cb17b789be30f',1,'esp_wifi.h']]], + ['wifi_5fget_5fuser_5ffixed_5frate',['wifi_get_user_fixed_rate',['../group__WiFi__Rate__Control__APIs.html#ga0f8d0671a13fbfa34d30d56857018228',1,'esp_wifi.h']]], + ['wifi_5fget_5fuser_5flimit_5frate_5fmask',['wifi_get_user_limit_rate_mask',['../group__WiFi__Rate__Control__APIs.html#ga4c4b499ff0ebba2e74c3168f3e354052',1,'esp_wifi.h']]], + ['wifi_5fpromiscuous_5fenable',['wifi_promiscuous_enable',['../group__WiFi__Sniffer__APIs.html#ga39964266988f76d3c08d65820d289410',1,'esp_wifi.h']]], + ['wifi_5fpromiscuous_5fset_5fmac',['wifi_promiscuous_set_mac',['../group__WiFi__Sniffer__APIs.html#ga2cc97dea2fc14040123a9b8fb623d284',1,'esp_wifi.h']]], + ['wifi_5fregister_5frfid_5flocp_5frecv_5fcb',['wifi_register_rfid_locp_recv_cb',['../group__WiFi__Common__APIs.html#gaba41e6e0d6e37bd683a4c45d3459a59f',1,'esp_wifi.h']]], + ['wifi_5fregister_5fsend_5fpkt_5ffreedom_5fcb',['wifi_register_send_pkt_freedom_cb',['../group__WiFi__Common__APIs.html#gaad8a8f2cbb0bf2b93d63e63b84d57fb8',1,'esp_wifi.h']]], + ['wifi_5fregister_5fuser_5fie_5fmanufacturer_5frecv_5fcb',['wifi_register_user_ie_manufacturer_recv_cb',['../group__WiFi__User__IE__APIs.html#gaef66bcf79ecaaf03da9c9f1a484b192f',1,'esp_wifi.h']]], + ['wifi_5frfid_5flocp_5frecv_5fclose',['wifi_rfid_locp_recv_close',['../group__WiFi__Common__APIs.html#ga3fc0a0d198bb5f688d91f0c8f34649b6',1,'esp_wifi.h']]], + ['wifi_5frfid_5flocp_5frecv_5fopen',['wifi_rfid_locp_recv_open',['../group__WiFi__Common__APIs.html#ga7c1311ecd8ae0b5a58fcfea0f254600a',1,'esp_wifi.h']]], + ['wifi_5fsend_5fpkt_5ffreedom',['wifi_send_pkt_freedom',['../group__WiFi__Common__APIs.html#gad53e38f5591dc2ab6d9d78ecf79d51fc',1,'esp_wifi.h']]], + ['wifi_5fset_5fchannel',['wifi_set_channel',['../group__WiFi__Sniffer__APIs.html#ga6e75b0345bab8347d02e421f28801b6c',1,'esp_wifi.h']]], + ['wifi_5fset_5fevent_5fhandler_5fcb',['wifi_set_event_handler_cb',['../group__WiFi__Common__APIs.html#ga4fafbb94468303730e39b60e4bd36367',1,'esp_wifi.h']]], + ['wifi_5fset_5fip_5finfo',['wifi_set_ip_info',['../group__WiFi__Common__APIs.html#gac2bfa0967810f1b52a279903fccb3820',1,'esp_wifi.h']]], + ['wifi_5fset_5fmacaddr',['wifi_set_macaddr',['../group__WiFi__Common__APIs.html#gad6c60d5fca798d25a2a3251beab18d5d',1,'esp_wifi.h']]], + ['wifi_5fset_5fopmode',['wifi_set_opmode',['../group__WiFi__Common__APIs.html#ga460f95d854680e435e4b1cb00a61d0c9',1,'esp_wifi.h']]], + ['wifi_5fset_5fopmode_5fcurrent',['wifi_set_opmode_current',['../group__WiFi__Common__APIs.html#gaae9c82a5eeebba94d7a6b65dcc704508',1,'esp_wifi.h']]], + ['wifi_5fset_5fphy_5fmode',['wifi_set_phy_mode',['../group__WiFi__Common__APIs.html#gac882480595e50f407e6ccd3072555bab',1,'esp_wifi.h']]], + ['wifi_5fset_5fpromiscuous_5frx_5fcb',['wifi_set_promiscuous_rx_cb',['../group__WiFi__Sniffer__APIs.html#ga2baed988e772a0ba9107984b4ef5e7a2',1,'esp_wifi.h']]], + ['wifi_5fset_5fsleep_5ftype',['wifi_set_sleep_type',['../group__WiFi__Common__APIs.html#ga8c6a105486e14aff96d31d324ca15baf',1,'esp_wifi.h']]], + ['wifi_5fset_5fuser_5ffixed_5frate',['wifi_set_user_fixed_rate',['../group__WiFi__Rate__Control__APIs.html#ga23f9bd250fe2c037889cc061dbc8a15b',1,'esp_wifi.h']]], + ['wifi_5fset_5fuser_5fie',['wifi_set_user_ie',['../group__WiFi__User__IE__APIs.html#gaae332b9c26be88e95787a825f828c827',1,'esp_wifi.h']]], + ['wifi_5fset_5fuser_5flimit_5frate_5fmask',['wifi_set_user_limit_rate_mask',['../group__WiFi__Rate__Control__APIs.html#gaed1b4660c13be6154fd73c84a3ba96c2',1,'esp_wifi.h']]], + ['wifi_5fset_5fuser_5frate_5flimit',['wifi_set_user_rate_limit',['../group__WiFi__Rate__Control__APIs.html#ga0cb4293aeced3e3636b40f831dee54cc',1,'esp_wifi.h']]], + ['wifi_5fset_5fuser_5fsup_5frate',['wifi_set_user_sup_rate',['../group__WiFi__Rate__Control__APIs.html#gafb6fea0b53f61743170baec0bd207b4f',1,'esp_wifi.h']]], + ['wifi_5fset_5fwps_5fcb',['wifi_set_wps_cb',['../group__WPS__APIs.html#ga43d54c785288a8ca0689b621f852a443',1,'esp_wps.h']]], + ['wifi_5fsoftap_5fdhcps_5fstart',['wifi_softap_dhcps_start',['../group__SoftAP__APIs.html#ga3955db3d72e1669492143e64f7b32775',1,'esp_softap.h']]], + ['wifi_5fsoftap_5fdhcps_5fstatus',['wifi_softap_dhcps_status',['../group__SoftAP__APIs.html#ga0fd4c4454b23c6532a8dcbfbcbaa4e13',1,'esp_softap.h']]], + ['wifi_5fsoftap_5fdhcps_5fstop',['wifi_softap_dhcps_stop',['../group__SoftAP__APIs.html#gadc4b55015e0a64892d33a7d79a7627d6',1,'esp_softap.h']]], + ['wifi_5fsoftap_5ffree_5fstation_5finfo',['wifi_softap_free_station_info',['../group__SoftAP__APIs.html#ga964c8cead391b94375d374b028286c49',1,'esp_softap.h']]], + ['wifi_5fsoftap_5fget_5fconfig',['wifi_softap_get_config',['../group__SoftAP__APIs.html#ga77b8e55ff0c8ff6d01aa0da307a7ea37',1,'esp_softap.h']]], + ['wifi_5fsoftap_5fget_5fconfig_5fdefault',['wifi_softap_get_config_default',['../group__SoftAP__APIs.html#gaf8f06f31b9c07479b775b30ec1ce4515',1,'esp_softap.h']]], + ['wifi_5fsoftap_5fget_5fdhcps_5flease',['wifi_softap_get_dhcps_lease',['../group__SoftAP__APIs.html#gab2a17bcf37d23826044a0fb221188265',1,'esp_softap.h']]], + ['wifi_5fsoftap_5fget_5fdhcps_5flease_5ftime',['wifi_softap_get_dhcps_lease_time',['../group__SoftAP__APIs.html#gaa69724e463906776f0ad148d53880059',1,'esp_softap.h']]], + ['wifi_5fsoftap_5fget_5fstation_5finfo',['wifi_softap_get_station_info',['../group__SoftAP__APIs.html#ga491f411c5bf740d1ee254d4d05f1318d',1,'esp_softap.h']]], + ['wifi_5fsoftap_5fget_5fstation_5fnum',['wifi_softap_get_station_num',['../group__SoftAP__APIs.html#ga1565b7a74387e9bdce78771086f0083c',1,'esp_softap.h']]], + ['wifi_5fsoftap_5freset_5fdhcps_5flease_5ftime',['wifi_softap_reset_dhcps_lease_time',['../group__SoftAP__APIs.html#ga78ef453f3e627eefd1c5a2ef077cc0b9',1,'esp_softap.h']]], + ['wifi_5fsoftap_5fset_5fconfig',['wifi_softap_set_config',['../group__SoftAP__APIs.html#ga22c2108fdcadc9bf0cbfe9b642e759b7',1,'esp_softap.h']]], + ['wifi_5fsoftap_5fset_5fconfig_5fcurrent',['wifi_softap_set_config_current',['../group__SoftAP__APIs.html#ga865d02d3e00b6105c9446bce9d6b8e12',1,'esp_softap.h']]], + ['wifi_5fsoftap_5fset_5fdhcps_5flease',['wifi_softap_set_dhcps_lease',['../group__SoftAP__APIs.html#ga88284afccfb825d3b47ed45d1a6f26e2',1,'esp_softap.h']]], + ['wifi_5fsoftap_5fset_5fdhcps_5flease_5ftime',['wifi_softap_set_dhcps_lease_time',['../group__SoftAP__APIs.html#ga4d2c217a01e271ce74a00a32a6e5187f',1,'esp_softap.h']]], + ['wifi_5fsoftap_5fset_5fdhcps_5foffer_5foption',['wifi_softap_set_dhcps_offer_option',['../group__SoftAP__APIs.html#gaab0a8265f075049245fa284051e9ee24',1,'esp_softap.h']]], + ['wifi_5fstation_5fap_5fchange',['wifi_station_ap_change',['../group__Station__APIs.html#ga9711fca72415e7894c33ae4cef1d371d',1,'esp_sta.h']]], + ['wifi_5fstation_5fap_5fnumber_5fset',['wifi_station_ap_number_set',['../group__Station__APIs.html#ga63e11de2570080b8379da8625e9cb949',1,'esp_sta.h']]], + ['wifi_5fstation_5fconnect',['wifi_station_connect',['../group__Station__APIs.html#gab03cd1e7e4ad93cd241c94bd57430384',1,'esp_sta.h']]], + ['wifi_5fstation_5fdhcpc_5fstart',['wifi_station_dhcpc_start',['../group__Station__APIs.html#ga8319ad450244b7742b85150adc3cd424',1,'esp_sta.h']]], + ['wifi_5fstation_5fdhcpc_5fstatus',['wifi_station_dhcpc_status',['../group__Station__APIs.html#ga4f0dbe9ff0d79cd8d947f9ff23bc747a',1,'esp_sta.h']]], + ['wifi_5fstation_5fdhcpc_5fstop',['wifi_station_dhcpc_stop',['../group__Station__APIs.html#ga955438bce6a3cdfc702d032f4d086704',1,'esp_sta.h']]], + ['wifi_5fstation_5fdisconnect',['wifi_station_disconnect',['../group__Station__APIs.html#gaba69e9646b1f29d8a72972787400f4f1',1,'esp_sta.h']]], + ['wifi_5fstation_5fget_5fap_5finfo',['wifi_station_get_ap_info',['../group__Station__APIs.html#ga8e02856a8da8a5c2d5cc2b58ac2abe8d',1,'esp_sta.h']]], + ['wifi_5fstation_5fget_5fauto_5fconnect',['wifi_station_get_auto_connect',['../group__Station__APIs.html#ga00570be3792df2117fabaf78f1715377',1,'esp_sta.h']]], + ['wifi_5fstation_5fget_5fconfig',['wifi_station_get_config',['../group__Station__APIs.html#ga1f0be53caaf81058292a1e6559bdaa36',1,'esp_sta.h']]], + ['wifi_5fstation_5fget_5fconfig_5fdefault',['wifi_station_get_config_default',['../group__Station__APIs.html#ga6731bedbb516f8709c236084fa721dd4',1,'esp_sta.h']]], + ['wifi_5fstation_5fget_5fconnect_5fstatus',['wifi_station_get_connect_status',['../group__Station__APIs.html#ga759708bdf7cbb858a9b5c87100ccd4f8',1,'esp_sta.h']]], + ['wifi_5fstation_5fget_5fcurrent_5fap_5fid',['wifi_station_get_current_ap_id',['../group__Station__APIs.html#ga0b52a9b584de66a3806ec340e3e5c909',1,'esp_sta.h']]], + ['wifi_5fstation_5fget_5fhostname',['wifi_station_get_hostname',['../group__Station__APIs.html#gadfca0ed0d87c94c27168a826bcc88b54',1,'esp_sta.h']]], + ['wifi_5fstation_5fget_5freconnect_5fpolicy',['wifi_station_get_reconnect_policy',['../group__Station__APIs.html#ga31710ba9a7d42a9503a33149fa0b06e8',1,'esp_sta.h']]], + ['wifi_5fstation_5fget_5frssi',['wifi_station_get_rssi',['../group__Station__APIs.html#gaf8572ea9f6e1b7785e9df6941932bb3d',1,'esp_sta.h']]], + ['wifi_5fstation_5fscan',['wifi_station_scan',['../group__Station__APIs.html#gac80b0607b1cb20c161c681581c998626',1,'esp_sta.h']]], + ['wifi_5fstation_5fset_5fauto_5fconnect',['wifi_station_set_auto_connect',['../group__Station__APIs.html#ga814fa9c0218cd4c1df29b4d22aeef442',1,'esp_sta.h']]], + ['wifi_5fstation_5fset_5fconfig',['wifi_station_set_config',['../group__Station__APIs.html#gab3699b2e258bf21ad6e85e4b1ec1c271',1,'esp_sta.h']]], + ['wifi_5fstation_5fset_5fconfig_5fcurrent',['wifi_station_set_config_current',['../group__Station__APIs.html#gafd1188add491eee183d4ee2daa37dca6',1,'esp_sta.h']]], + ['wifi_5fstation_5fset_5fhostname',['wifi_station_set_hostname',['../group__Station__APIs.html#gaed5b5cb8eb9d881a77ca4a832b9ae50d',1,'esp_sta.h']]], + ['wifi_5fstation_5fset_5freconnect_5fpolicy',['wifi_station_set_reconnect_policy',['../group__Station__APIs.html#ga8df829fe1b522f576cc8d97835c0a64a',1,'esp_sta.h']]], + ['wifi_5fstatus_5fled_5finstall',['wifi_status_led_install',['../group__WiFi__Common__APIs.html#gafa9800e7f02ac0036e03c101aff67b56',1,'esp_wifi.h']]], + ['wifi_5fstatus_5fled_5funinstall',['wifi_status_led_uninstall',['../group__WiFi__Common__APIs.html#gaf5f3d866bb77ebd5f48543a2e0e9da8c',1,'esp_wifi.h']]], + ['wifi_5funregister_5frfid_5flocp_5frecv_5fcb',['wifi_unregister_rfid_locp_recv_cb',['../group__WiFi__Common__APIs.html#gab108ee67954d01805b4721c416805123',1,'esp_wifi.h']]], + ['wifi_5funregister_5fsend_5fpkt_5ffreedom_5fcb',['wifi_unregister_send_pkt_freedom_cb',['../group__WiFi__Common__APIs.html#ga8fba24461d736ce9d94c4acdb5295df2',1,'esp_wifi.h']]], + ['wifi_5funregister_5fuser_5fie_5fmanufacturer_5frecv_5fcb',['wifi_unregister_user_ie_manufacturer_recv_cb',['../group__WiFi__User__IE__APIs.html#ga8f1e33403097564f724cc7d5115d2ab4',1,'esp_wifi.h']]], + ['wifi_5fwps_5fdisable',['wifi_wps_disable',['../group__WPS__APIs.html#gaefc2fa1f3e4ba57ff82d41438c20badc',1,'esp_wps.h']]], + ['wifi_5fwps_5fenable',['wifi_wps_enable',['../group__WPS__APIs.html#ga6c3bf6dc44cf11fa735b2d190d9a2861',1,'esp_wps.h']]], + ['wifi_5fwps_5fstart',['wifi_wps_start',['../group__WPS__APIs.html#gad23a740bd3fb80e6f871c78728b4e58b',1,'esp_wps.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_0.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_0.html new file mode 100644 index 0000000..aaba07e --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_0.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_0.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_0.js new file mode 100644 index 0000000..dd188c8 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_0.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['airkiss_20apis',['AirKiss APIs',['../group__AirKiss__APIs.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_1.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_1.html new file mode 100644 index 0000000..d287bfa --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_1.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_1.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_1.js new file mode 100644 index 0000000..cf37e3e --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_1.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['boot_20apis',['Boot APIs',['../group__System__boot__APIs.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_2.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_2.html new file mode 100644 index 0000000..29681b2 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_2.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_2.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_2.js new file mode 100644 index 0000000..e6b0667 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_2.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['common_20apis',['Common APIs',['../group__WiFi__Common__APIs.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_3.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_3.html new file mode 100644 index 0000000..b51e57f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_3.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_3.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_3.js new file mode 100644 index 0000000..aa0347a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_3.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['driver_20apis',['Driver APIs',['../group__Driver__APIs.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_4.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_4.html new file mode 100644 index 0000000..987621b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_4.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_4.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_4.js new file mode 100644 index 0000000..657dd88 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_4.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['esp_2dnow_20apis',['ESP-NOW APIs',['../group__ESPNow__APIs.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_5.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_5.html new file mode 100644 index 0000000..2ccec27 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_5.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_5.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_5.js new file mode 100644 index 0000000..e77839d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_5.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['force_20sleep_20apis',['Force Sleep APIs',['../group__WiFi__Force__Sleep__APIs.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_6.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_6.html new file mode 100644 index 0000000..ed69c07 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_6.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_6.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_6.js new file mode 100644 index 0000000..2689e46 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_6.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['gpio_20driver_20apis',['GPIO Driver APIs',['../group__GPIO__Driver__APIs.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_7.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_7.html new file mode 100644 index 0000000..027daaa --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_7.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_7.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_7.js new file mode 100644 index 0000000..4250ccd --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_7.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['hardware_20timer_20apis',['Hardware timer APIs',['../group__HW__Timer__APIs.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_8.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_8.html new file mode 100644 index 0000000..936f141 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_8.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_8.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_8.js new file mode 100644 index 0000000..e1489e6 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_8.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['mesh_20apis',['Mesh APIs',['../group__Mesh__APIs.html',1,'']]], + ['misc_20apis',['Misc APIs',['../group__Misc__APIs.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_9.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_9.html new file mode 100644 index 0000000..c66e6a6 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_9.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_9.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_9.js new file mode 100644 index 0000000..d7da12f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_9.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['network_20espconn_20apis',['Network Espconn APIs',['../group__Espconn__APIs.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_a.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_a.html new file mode 100644 index 0000000..93ac2a1 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_a.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_a.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_a.js new file mode 100644 index 0000000..5a46315 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_a.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['pwm_20driver_20apis',['PWM Driver APIs',['../group__PWM__Driver__APIs.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_b.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_b.html new file mode 100644 index 0000000..46da692 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_b.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_b.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_b.js new file mode 100644 index 0000000..247135b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_b.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['rate_20control_20apis',['Rate Control APIs',['../group__WiFi__Rate__Control__APIs.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_c.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_c.html new file mode 100644 index 0000000..960b8d7 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_c.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_c.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_c.js new file mode 100644 index 0000000..e0c4986 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_c.js @@ -0,0 +1,12 @@ +var searchData= +[ + ['smartconfig_20apis',['Smartconfig APIs',['../group__Smartconfig__APIs.html',1,'']]], + ['softap_20apis',['SoftAP APIs',['../group__SoftAP__APIs.html',1,'']]], + ['spi_20driver_20apis',['SPI Driver APIs',['../group__SPI__Driver__APIs.html',1,'']]], + ['spiffs_20apis',['Spiffs APIs',['../group__Spiffs__APIs.html',1,'']]], + ['ssc_20apis',['SSC APIs',['../group__SSC__APIs.html',1,'']]], + ['station_20apis',['Station APIs',['../group__Station__APIs.html',1,'']]], + ['system_20apis',['System APIs',['../group__System__APIs.html',1,'']]], + ['software_20timer_20apis',['Software timer APIs',['../group__Timer__APIs.html',1,'']]], + ['sniffer_20apis',['Sniffer APIs',['../group__WiFi__Sniffer__APIs.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_d.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_d.html new file mode 100644 index 0000000..f4878cd --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_d.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_d.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_d.js new file mode 100644 index 0000000..ba6b5aa --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_d.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['uart_20driver_20apis',['UART Driver APIs',['../group__UART__Driver__APIs.html',1,'']]], + ['upgrade_20apis',['Upgrade APIs',['../group__Upgrade__APIs.html',1,'']]], + ['user_20ie_20apis',['User IE APIs',['../group__WiFi__User__IE__APIs.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_e.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_e.html new file mode 100644 index 0000000..68e8547 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_e.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_e.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_e.js new file mode 100644 index 0000000..c7d8f60 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/groups_e.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['wifi_20related_20apis',['WiFi Related APIs',['../group__WiFi__APIs.html',1,'']]], + ['wps_20apis',['WPS APIs',['../group__WPS__APIs.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/mag_sel.png b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/mag_sel.png new file mode 100644 index 0000000000000000000000000000000000000000..81f6040a2092402b4d98f9ffa8855d12a0d4ca17 GIT binary patch literal 563 zcmV-30?hr1P)zxx&tqG15pu7)IiiXFflOc2k;dXd>%13GZAy? zRz!q0=|E6a6vV)&ZBS~G9oe0kbqyw1*gvY`{Pop2oKq#FlzgXt@Xh-7fxh>}`Fxg> z$%N%{$!4=5nM{(;=c!aG1Ofr^Do{u%Ih{^&Fc@H2)+a-?TBXrw5DW&z%Nb6mQ!L9O zl}b@6mB?f=tX3;#vl)}ggh(Vpyh(IK z(Mb0D{l{U$FsRjP;!{($+bsaaVi8T#1c0V#qEIOCYa9@UVLV`f__E81L;?WEaRA;Y zUH;rZ;vb;mk7JX|$=i3O~&If0O@oZfLg8gfIjW=dcBsz;gI=!{-r4# z4%6v$&~;q^j7Fo67yJ(NJWuX+I~I!tj^nW3?}^9bq|<3^+vapS5sgM^x7!cs(+mMT z&y%j};&~po+YO)3hoUH4E*E;e9>?R6SS&`X)p`njycAVcg{rEb41T{~Hk(bl-7eSb zmFxA2uIqo#@R?lKm50ND`~6Nfn|-b1|L6O98vt3Tx@gKz#isxO002ovPDHLkV1kyW B_l^Jn literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/nomatches.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/nomatches.html new file mode 100644 index 0000000..b1ded27 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/nomatches.html @@ -0,0 +1,12 @@ + + + + + + + +
+
No Matches
+
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/pages_0.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/pages_0.html new file mode 100644 index 0000000..75d203d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/pages_0.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/pages_0.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/pages_0.js new file mode 100644 index 0000000..b6c649c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/pages_0.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['esp8266_5frtos_5fsdk',['ESP8266_RTOS_SDK',['../index.html',1,'']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/search.css b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/search.css new file mode 100644 index 0000000..4d7612f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/search.css @@ -0,0 +1,271 @@ +/*---------------- Search Box */ + +#FSearchBox { + float: left; +} + +#MSearchBox { + white-space : nowrap; + position: absolute; + float: none; + display: inline; + margin-top: 8px; + right: 0px; + width: 170px; + z-index: 102; + background-color: white; +} + +#MSearchBox .left +{ + display:block; + position:absolute; + left:10px; + width:20px; + height:19px; + background:url('search_l.png') no-repeat; + background-position:right; +} + +#MSearchSelect { + display:block; + position:absolute; + width:20px; + height:19px; +} + +.left #MSearchSelect { + left:4px; +} + +.right #MSearchSelect { + right:5px; +} + +#MSearchField { + display:block; + position:absolute; + height:19px; + background:url('search_m.png') repeat-x; + border:none; + width:111px; + margin-left:20px; + padding-left:4px; + color: #909090; + outline: none; + font: 9pt Arial, Verdana, sans-serif; +} + +#FSearchBox #MSearchField { + margin-left:15px; +} + +#MSearchBox .right { + display:block; + position:absolute; + right:10px; + top:0px; + width:20px; + height:19px; + background:url('search_r.png') no-repeat; + background-position:left; +} + +#MSearchClose { + display: none; + position: absolute; + top: 4px; + background : none; + border: none; + margin: 0px 4px 0px 0px; + padding: 0px 0px; + outline: none; +} + +.left #MSearchClose { + left: 6px; +} + +.right #MSearchClose { + right: 2px; +} + +.MSearchBoxActive #MSearchField { + color: #000000; +} + +/*---------------- Search filter selection */ + +#MSearchSelectWindow { + display: none; + position: absolute; + left: 0; top: 0; + border: 1px solid #90A5CE; + background-color: #F9FAFC; + z-index: 1; + padding-top: 4px; + padding-bottom: 4px; + -moz-border-radius: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); +} + +.SelectItem { + font: 8pt Arial, Verdana, sans-serif; + padding-left: 2px; + padding-right: 12px; + border: 0px; +} + +span.SelectionMark { + margin-right: 4px; + font-family: monospace; + outline-style: none; + text-decoration: none; +} + +a.SelectItem { + display: block; + outline-style: none; + color: #000000; + text-decoration: none; + padding-left: 6px; + padding-right: 12px; +} + +a.SelectItem:focus, +a.SelectItem:active { + color: #000000; + outline-style: none; + text-decoration: none; +} + +a.SelectItem:hover { + color: #FFFFFF; + background-color: #3D578C; + outline-style: none; + text-decoration: none; + cursor: pointer; + display: block; +} + +/*---------------- Search results window */ + +iframe#MSearchResults { + width: 60ex; + height: 15em; +} + +#MSearchResultsWindow { + display: none; + position: absolute; + left: 0; top: 0; + border: 1px solid #000; + background-color: #EEF1F7; +} + +/* ----------------------------------- */ + + +#SRIndex { + clear:both; + padding-bottom: 15px; +} + +.SREntry { + font-size: 10pt; + padding-left: 1ex; +} + +.SRPage .SREntry { + font-size: 8pt; + padding: 1px 5px; +} + +body.SRPage { + margin: 5px 2px; +} + +.SRChildren { + padding-left: 3ex; padding-bottom: .5em +} + +.SRPage .SRChildren { + display: none; +} + +.SRSymbol { + font-weight: bold; + color: #425E97; + font-family: Arial, Verdana, sans-serif; + text-decoration: none; + outline: none; +} + +a.SRScope { + display: block; + color: #425E97; + font-family: Arial, Verdana, sans-serif; + text-decoration: none; + outline: none; +} + +a.SRSymbol:focus, a.SRSymbol:active, +a.SRScope:focus, a.SRScope:active { + text-decoration: underline; +} + +span.SRScope { + padding-left: 4px; +} + +.SRPage .SRStatus { + padding: 2px 5px; + font-size: 8pt; + font-style: italic; +} + +.SRResult { + display: none; +} + +DIV.searchresults { + margin-left: 10px; + margin-right: 10px; +} + +/*---------------- External search page results */ + +.searchresult { + background-color: #F0F3F8; +} + +.pages b { + color: white; + padding: 5px 5px 3px 5px; + background-image: url("../tab_a.png"); + background-repeat: repeat-x; + text-shadow: 0 1px 1px #000000; +} + +.pages { + line-height: 17px; + margin-left: 4px; + text-decoration: none; +} + +.hl { + font-weight: bold; +} + +#searchresults { + margin-bottom: 20px; +} + +.searchpages { + margin-top: 10px; +} + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/search.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/search.js new file mode 100644 index 0000000..dedce3b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/search.js @@ -0,0 +1,791 @@ +function convertToId(search) +{ + var result = ''; + for (i=0;i do a search + { + this.Search(); + } + } + + this.OnSearchSelectKey = function(evt) + { + var e = (evt) ? evt : window.event; // for IE + if (e.keyCode==40 && this.searchIndex0) // Up + { + this.searchIndex--; + this.OnSelectItem(this.searchIndex); + } + else if (e.keyCode==13 || e.keyCode==27) + { + this.OnSelectItem(this.searchIndex); + this.CloseSelectionWindow(); + this.DOMSearchField().focus(); + } + return false; + } + + // --------- Actions + + // Closes the results window. + this.CloseResultsWindow = function() + { + this.DOMPopupSearchResultsWindow().style.display = 'none'; + this.DOMSearchClose().style.display = 'none'; + this.Activate(false); + } + + this.CloseSelectionWindow = function() + { + this.DOMSearchSelectWindow().style.display = 'none'; + } + + // Performs a search. + this.Search = function() + { + this.keyTimeout = 0; + + // strip leading whitespace + var searchValue = this.DOMSearchField().value.replace(/^ +/, ""); + + var code = searchValue.toLowerCase().charCodeAt(0); + var idxChar = searchValue.substr(0, 1).toLowerCase(); + if ( 0xD800 <= code && code <= 0xDBFF && searchValue > 1) // surrogate pair + { + idxChar = searchValue.substr(0, 2); + } + + var resultsPage; + var resultsPageWithSearch; + var hasResultsPage; + + var idx = indexSectionsWithContent[this.searchIndex].indexOf(idxChar); + if (idx!=-1) + { + var hexCode=idx.toString(16); + resultsPage = this.resultsPath + '/' + indexSectionNames[this.searchIndex] + '_' + hexCode + '.html'; + resultsPageWithSearch = resultsPage+'?'+escape(searchValue); + hasResultsPage = true; + } + else // nothing available for this search term + { + resultsPage = this.resultsPath + '/nomatches.html'; + resultsPageWithSearch = resultsPage; + hasResultsPage = false; + } + + window.frames.MSearchResults.location = resultsPageWithSearch; + var domPopupSearchResultsWindow = this.DOMPopupSearchResultsWindow(); + + if (domPopupSearchResultsWindow.style.display!='block') + { + var domSearchBox = this.DOMSearchBox(); + this.DOMSearchClose().style.display = 'inline'; + if (this.insideFrame) + { + var domPopupSearchResults = this.DOMPopupSearchResults(); + domPopupSearchResultsWindow.style.position = 'relative'; + domPopupSearchResultsWindow.style.display = 'block'; + var width = document.body.clientWidth - 8; // the -8 is for IE :-( + domPopupSearchResultsWindow.style.width = width + 'px'; + domPopupSearchResults.style.width = width + 'px'; + } + else + { + var domPopupSearchResults = this.DOMPopupSearchResults(); + var left = getXPos(domSearchBox) + 150; // domSearchBox.offsetWidth; + var top = getYPos(domSearchBox) + 20; // domSearchBox.offsetHeight + 1; + domPopupSearchResultsWindow.style.display = 'block'; + left -= domPopupSearchResults.offsetWidth; + domPopupSearchResultsWindow.style.top = top + 'px'; + domPopupSearchResultsWindow.style.left = left + 'px'; + } + } + + this.lastSearchValue = searchValue; + this.lastResultsPage = resultsPage; + } + + // -------- Activation Functions + + // Activates or deactivates the search panel, resetting things to + // their default values if necessary. + this.Activate = function(isActive) + { + if (isActive || // open it + this.DOMPopupSearchResultsWindow().style.display == 'block' + ) + { + this.DOMSearchBox().className = 'MSearchBoxActive'; + + var searchField = this.DOMSearchField(); + + if (searchField.value == this.searchLabel) // clear "Search" term upon entry + { + searchField.value = ''; + this.searchActive = true; + } + } + else if (!isActive) // directly remove the panel + { + this.DOMSearchBox().className = 'MSearchBoxInactive'; + this.DOMSearchField().value = this.searchLabel; + this.searchActive = false; + this.lastSearchValue = '' + this.lastResultsPage = ''; + } + } +} + +// ----------------------------------------------------------------------- + +// The class that handles everything on the search results page. +function SearchResults(name) +{ + // The number of matches from the last run of . + this.lastMatchCount = 0; + this.lastKey = 0; + this.repeatOn = false; + + // Toggles the visibility of the passed element ID. + this.FindChildElement = function(id) + { + var parentElement = document.getElementById(id); + var element = parentElement.firstChild; + + while (element && element!=parentElement) + { + if (element.nodeName == 'DIV' && element.className == 'SRChildren') + { + return element; + } + + if (element.nodeName == 'DIV' && element.hasChildNodes()) + { + element = element.firstChild; + } + else if (element.nextSibling) + { + element = element.nextSibling; + } + else + { + do + { + element = element.parentNode; + } + while (element && element!=parentElement && !element.nextSibling); + + if (element && element!=parentElement) + { + element = element.nextSibling; + } + } + } + } + + this.Toggle = function(id) + { + var element = this.FindChildElement(id); + if (element) + { + if (element.style.display == 'block') + { + element.style.display = 'none'; + } + else + { + element.style.display = 'block'; + } + } + } + + // Searches for the passed string. If there is no parameter, + // it takes it from the URL query. + // + // Always returns true, since other documents may try to call it + // and that may or may not be possible. + this.Search = function(search) + { + if (!search) // get search word from URL + { + search = window.location.search; + search = search.substring(1); // Remove the leading '?' + search = unescape(search); + } + + search = search.replace(/^ +/, ""); // strip leading spaces + search = search.replace(/ +$/, ""); // strip trailing spaces + search = search.toLowerCase(); + search = convertToId(search); + + var resultRows = document.getElementsByTagName("div"); + var matches = 0; + + var i = 0; + while (i < resultRows.length) + { + var row = resultRows.item(i); + if (row.className == "SRResult") + { + var rowMatchName = row.id.toLowerCase(); + rowMatchName = rowMatchName.replace(/^sr\d*_/, ''); // strip 'sr123_' + + if (search.length<=rowMatchName.length && + rowMatchName.substr(0, search.length)==search) + { + row.style.display = 'block'; + matches++; + } + else + { + row.style.display = 'none'; + } + } + i++; + } + document.getElementById("Searching").style.display='none'; + if (matches == 0) // no results + { + document.getElementById("NoMatches").style.display='block'; + } + else // at least one result + { + document.getElementById("NoMatches").style.display='none'; + } + this.lastMatchCount = matches; + return true; + } + + // return the first item with index index or higher that is visible + this.NavNext = function(index) + { + var focusItem; + while (1) + { + var focusName = 'Item'+index; + focusItem = document.getElementById(focusName); + if (focusItem && focusItem.parentNode.parentNode.style.display=='block') + { + break; + } + else if (!focusItem) // last element + { + break; + } + focusItem=null; + index++; + } + return focusItem; + } + + this.NavPrev = function(index) + { + var focusItem; + while (1) + { + var focusName = 'Item'+index; + focusItem = document.getElementById(focusName); + if (focusItem && focusItem.parentNode.parentNode.style.display=='block') + { + break; + } + else if (!focusItem) // last element + { + break; + } + focusItem=null; + index--; + } + return focusItem; + } + + this.ProcessKeys = function(e) + { + if (e.type == "keydown") + { + this.repeatOn = false; + this.lastKey = e.keyCode; + } + else if (e.type == "keypress") + { + if (!this.repeatOn) + { + if (this.lastKey) this.repeatOn = true; + return false; // ignore first keypress after keydown + } + } + else if (e.type == "keyup") + { + this.lastKey = 0; + this.repeatOn = false; + } + return this.lastKey!=0; + } + + this.Nav = function(evt,itemIndex) + { + var e = (evt) ? evt : window.event; // for IE + if (e.keyCode==13) return true; + if (!this.ProcessKeys(e)) return false; + + if (this.lastKey==38) // Up + { + var newIndex = itemIndex-1; + var focusItem = this.NavPrev(newIndex); + if (focusItem) + { + var child = this.FindChildElement(focusItem.parentNode.parentNode.id); + if (child && child.style.display == 'block') // children visible + { + var n=0; + var tmpElem; + while (1) // search for last child + { + tmpElem = document.getElementById('Item'+newIndex+'_c'+n); + if (tmpElem) + { + focusItem = tmpElem; + } + else // found it! + { + break; + } + n++; + } + } + } + if (focusItem) + { + focusItem.focus(); + } + else // return focus to search field + { + parent.document.getElementById("MSearchField").focus(); + } + } + else if (this.lastKey==40) // Down + { + var newIndex = itemIndex+1; + var focusItem; + var item = document.getElementById('Item'+itemIndex); + var elem = this.FindChildElement(item.parentNode.parentNode.id); + if (elem && elem.style.display == 'block') // children visible + { + focusItem = document.getElementById('Item'+itemIndex+'_c0'); + } + if (!focusItem) focusItem = this.NavNext(newIndex); + if (focusItem) focusItem.focus(); + } + else if (this.lastKey==39) // Right + { + var item = document.getElementById('Item'+itemIndex); + var elem = this.FindChildElement(item.parentNode.parentNode.id); + if (elem) elem.style.display = 'block'; + } + else if (this.lastKey==37) // Left + { + var item = document.getElementById('Item'+itemIndex); + var elem = this.FindChildElement(item.parentNode.parentNode.id); + if (elem) elem.style.display = 'none'; + } + else if (this.lastKey==27) // Escape + { + parent.searchBox.CloseResultsWindow(); + parent.document.getElementById("MSearchField").focus(); + } + else if (this.lastKey==13) // Enter + { + return true; + } + return false; + } + + this.NavChild = function(evt,itemIndex,childIndex) + { + var e = (evt) ? evt : window.event; // for IE + if (e.keyCode==13) return true; + if (!this.ProcessKeys(e)) return false; + + if (this.lastKey==38) // Up + { + if (childIndex>0) + { + var newIndex = childIndex-1; + document.getElementById('Item'+itemIndex+'_c'+newIndex).focus(); + } + else // already at first child, jump to parent + { + document.getElementById('Item'+itemIndex).focus(); + } + } + else if (this.lastKey==40) // Down + { + var newIndex = childIndex+1; + var elem = document.getElementById('Item'+itemIndex+'_c'+newIndex); + if (!elem) // last child, jump to parent next parent + { + elem = this.NavNext(itemIndex+1); + } + if (elem) + { + elem.focus(); + } + } + else if (this.lastKey==27) // Escape + { + parent.searchBox.CloseResultsWindow(); + parent.document.getElementById("MSearchField").focus(); + } + else if (this.lastKey==13) // Enter + { + return true; + } + return false; + } +} + +function setKeyActions(elem,action) +{ + elem.setAttribute('onkeydown',action); + elem.setAttribute('onkeypress',action); + elem.setAttribute('onkeyup',action); +} + +function setClassAttr(elem,attr) +{ + elem.setAttribute('class',attr); + elem.setAttribute('className',attr); +} + +function createResults() +{ + var results = document.getElementById("SRResults"); + for (var e=0; ek7RCwB~R6VQOP#AvB$vH7i{6H{96zot$7cZT<7246EF5Np6N}+$IbiG6W zg#87A+NFaX+=_^xM1#gCtshC=E{%9^uQX_%?YwXvo{#q&MnpJ8uh(O?ZRc&~_1%^SsPxG@rfElJg-?U zm!Cz-IOn(qJP3kDp-^~qt+FGbl=5jNli^Wj_xIBG{Rc0en{!oFvyoNC7{V~T8}b>| z=jL2WIReZzX(YN(_9fV;BBD$VXQIxNasAL8ATvEu822WQ%mvv4FO#qs` BFGc_W literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/search_r.png b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/search_r.png new file mode 100644 index 0000000000000000000000000000000000000000..97ee8b439687084201b79c6f776a41f495c6392a GIT binary patch literal 612 zcmV-q0-ODbP)PbXFRCwB?)W514K@j&X?z2*SxFI6-@HT2E2K=9X9%Pb zEK*!TBw&g(DMC;|A)uGlRkOS9vd-?zNs%bR4d$w+ox_iFnE8fvIvv7^5<(>Te12Li z7C)9srCzmK{ZcNM{YIl9j{DePFgOWiS%xG@5CnnnJa4nvY<^glbz7^|-ZY!dUkAwd z{gaTC@_>b5h~;ug#R0wRL0>o5!hxm*s0VW?8dr}O#zXTRTnrQm_Z7z1Mrnx>&p zD4qifUjzLvbVVWi?l?rUzwt^sdb~d!f_LEhsRVIXZtQ=qSxuxqm zEX#tf>$?M_Y1-LSDT)HqG?`%-%ZpY!#{N!rcNIiL;G7F0`l?)mNGTD9;f9F5Up3Kg zw}a<-JylhG&;=!>B+fZaCX+?C+kHYrP%c?X2!Zu_olK|GcS4A70HEy;vn)I0>0kLH z`jc(WIaaHc7!HS@f*^R^Znx8W=_jIl2oWJoQ*h1^$FX!>*PqR1J8k|fw}w_y}TpE>7m8DqDO<3z`OzXt$ccSejbEZCg@0000 + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_0.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_0.js new file mode 100644 index 0000000..7141186 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_0.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['dns_5ffound_5fcallback',['dns_found_callback',['../group__Espconn__APIs.html#gac6c8cf602f9c20d36003dc6d1b518d78',1,'espconn.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_1.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_1.html new file mode 100644 index 0000000..c44c36f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_1.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_1.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_1.js new file mode 100644 index 0000000..8267a46 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_1.js @@ -0,0 +1,8 @@ +var searchData= +[ + ['esp_5fnow_5frecv_5fcb_5ft',['esp_now_recv_cb_t',['../group__ESPNow__APIs.html#gadd5a6237e11ed8513c4956f6109730a7',1,'espnow.h']]], + ['esp_5fnow_5fsend_5fcb_5ft',['esp_now_send_cb_t',['../group__ESPNow__APIs.html#ga5d05ff4fff6db81409e30f7e7e5d48c7',1,'espnow.h']]], + ['espconn_5fconnect_5fcallback',['espconn_connect_callback',['../group__Espconn__APIs.html#gac2f5cc499f1d963723ed37d87a029a00',1,'espconn.h']]], + ['espconn_5freconnect_5fcallback',['espconn_reconnect_callback',['../group__Espconn__APIs.html#ga06024aeff44004ddbdb7044b97676bba',1,'espconn.h']]], + ['espconn_5frecv_5fcallback',['espconn_recv_callback',['../group__Espconn__APIs.html#ga5c93b1b8d3455a8f4fdeb35b064c4b0f',1,'espconn.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_2.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_2.html new file mode 100644 index 0000000..d64bac3 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_2.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_2.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_2.js new file mode 100644 index 0000000..71bc754 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_2.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['freedom_5foutside_5fcb_5ft',['freedom_outside_cb_t',['../group__WiFi__Common__APIs.html#gae90568b8d2cdc0aeeb78ec34843e5c04',1,'esp_wifi.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_3.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_3.html new file mode 100644 index 0000000..10b9917 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_3.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_3.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_3.js new file mode 100644 index 0000000..c764b1a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_3.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['rfid_5flocp_5fcb_5ft',['rfid_locp_cb_t',['../group__WiFi__Common__APIs.html#gae1c8898c72bc7b1dde854068662527bc',1,'esp_wifi.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_4.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_4.html new file mode 100644 index 0000000..c1ff64d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_4.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_4.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_4.js new file mode 100644 index 0000000..09bf374 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_4.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['sc_5fcallback_5ft',['sc_callback_t',['../group__Smartconfig__APIs.html#ga98fdb334fead4d1bd026b9ceee8c3db0',1,'smartconfig.h']]], + ['scan_5fdone_5fcb_5ft',['scan_done_cb_t',['../group__Station__APIs.html#ga953373c37a80c04a576ac03986a1ebfb',1,'esp_sta.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_5.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_5.html new file mode 100644 index 0000000..14adc8e --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_5.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_5.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_5.js new file mode 100644 index 0000000..b863419 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_5.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['upgrade_5fstates_5fcheck_5fcallback',['upgrade_states_check_callback',['../group__Upgrade__APIs.html#ga2897893fe6b22f7cd3159e57370dee7d',1,'upgrade.h']]], + ['user_5fie_5fmanufacturer_5frecv_5fcb_5ft',['user_ie_manufacturer_recv_cb_t',['../group__WiFi__User__IE__APIs.html#ga48a93836b1b5d84a69592b90613cf01f',1,'esp_wifi.h']]], + ['user_5fspi_5fflash_5fread',['user_spi_flash_read',['../group__SPI__Driver__APIs.html#gacda8d0eb9ddb859ea21726108d825f17',1,'spi_flash.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_6.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_6.html new file mode 100644 index 0000000..742e92b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_6.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_6.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_6.js new file mode 100644 index 0000000..ef4c871 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/typedefs_6.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['wifi_5fevent_5fhandler_5fcb_5ft',['wifi_event_handler_cb_t',['../group__WiFi__Common__APIs.html#gaa7cc45ed46e00f9035baeb90e77f3996',1,'esp_wifi.h']]], + ['wifi_5fpromiscuous_5fcb_5ft',['wifi_promiscuous_cb_t',['../group__WiFi__Sniffer__APIs.html#gaec780f59bcc8f01c0a4098da86bea999',1,'esp_wifi.h']]], + ['wps_5fst_5fcb_5ft',['wps_st_cb_t',['../group__WPS__APIs.html#ga0da3c16841a4b3b2404577dd8f56251a',1,'esp_wps.h']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_0.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_0.html new file mode 100644 index 0000000..c98c046 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_0.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_0.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_0.js new file mode 100644 index 0000000..1e9a028 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_0.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['aid',['aid',['../structEvent__SoftAPMode__StaConnected__t.html#aea3f00ab9b78748e0e6aa5b46064d866',1,'Event_SoftAPMode_StaConnected_t::aid()'],['../structEvent__SoftAPMode__StaDisconnected__t.html#aea3f00ab9b78748e0e6aa5b46064d866',1,'Event_SoftAPMode_StaDisconnected_t::aid()']]], + ['ap_5fprobereqrecved',['ap_probereqrecved',['../unionEvent__Info__u.html#ad1cd671ae667ea3fcc720c3f225e0605',1,'Event_Info_u']]], + ['auth_5fchange',['auth_change',['../unionEvent__Info__u.html#a0825220ae21b63db9ddc3125d484187d',1,'Event_Info_u']]], + ['authmode',['authmode',['../structsoftap__config.html#ad787bf1eaf486b53c52496364469fec0',1,'softap_config::authmode()'],['../structbss__info.html#ad787bf1eaf486b53c52496364469fec0',1,'bss_info::authmode()']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_1.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_1.html new file mode 100644 index 0000000..3eab7ea --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_1.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_1.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_1.js new file mode 100644 index 0000000..380a22a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_1.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['beacon_5finterval',['beacon_interval',['../structsoftap__config.html#a2b535ca353a179a70ea977c7e522ddf5',1,'softap_config']]], + ['bss',['bss',['../structEvent__StaMode__ScanDone__t.html#abcc828d7caabe78ac4a5a54215c42e6a',1,'Event_StaMode_ScanDone_t']]], + ['bssid',['bssid',['../structstation__info.html#a27f40250591ad1ec3d905b4b61e7ddde',1,'station_info::bssid()'],['../structstation__config.html#a27f40250591ad1ec3d905b4b61e7ddde',1,'station_config::bssid()'],['../structscan__config.html#a4fb944a230a11d0c4b7582b3d4d79fa4',1,'scan_config::bssid()'],['../structbss__info.html#a27f40250591ad1ec3d905b4b61e7ddde',1,'bss_info::bssid()'],['../structEvent__StaMode__Connected__t.html#a27f40250591ad1ec3d905b4b61e7ddde',1,'Event_StaMode_Connected_t::bssid()'],['../structEvent__StaMode__Disconnected__t.html#a27f40250591ad1ec3d905b4b61e7ddde',1,'Event_StaMode_Disconnected_t::bssid()']]], + ['bssid_5fset',['bssid_set',['../structstation__config.html#ab8bd65a9dba6168d9a62bb54a67d1f50',1,'station_config']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_10.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_10.html new file mode 100644 index 0000000..7e4c8b2 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_10.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_10.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_10.js new file mode 100644 index 0000000..708c0fc --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_10.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['upgrade_5fflag',['upgrade_flag',['../structupgrade__server__info.html#a983ad0843b8753df3491570b65a20348',1,'upgrade_server_info']]], + ['upgrade_5fversion',['upgrade_version',['../structupgrade__server__info.html#a54bc0d4687b1f9b5f8671bd157abd94d',1,'upgrade_server_info']]], + ['url',['url',['../structupgrade__server__info.html#aa68fc9d50895a4a8df09b200ae030867',1,'upgrade_server_info']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_11.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_11.html new file mode 100644 index 0000000..8dd1dba --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_11.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_11.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_11.js new file mode 100644 index 0000000..b427ae1 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_11.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['write_5ffinish_5ffn',['write_finish_fn',['../struct__esp__tcp.html#ae885dafd86eabefcff4ead713c21eb82',1,'_esp_tcp']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_2.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_2.html new file mode 100644 index 0000000..282f35b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_2.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_2.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_2.js new file mode 100644 index 0000000..49cab8a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_2.js @@ -0,0 +1,9 @@ +var searchData= +[ + ['cache_5fbuf_5fsize',['cache_buf_size',['../structesp__spiffs__config.html#ad509b97f939dee79cf1cbdbddd780798',1,'esp_spiffs_config']]], + ['channel',['channel',['../structsoftap__config.html#a94e9cfdc116e8607615a5e8529048b1e',1,'softap_config::channel()'],['../structscan__config.html#a94e9cfdc116e8607615a5e8529048b1e',1,'scan_config::channel()'],['../structbss__info.html#a94e9cfdc116e8607615a5e8529048b1e',1,'bss_info::channel()'],['../structEvent__StaMode__Connected__t.html#a94e9cfdc116e8607615a5e8529048b1e',1,'Event_StaMode_Connected_t::channel()']]], + ['check_5fcb',['check_cb',['../structupgrade__server__info.html#a60f52082196cd22a78142fd14eef594e',1,'upgrade_server_info']]], + ['check_5ftimes',['check_times',['../structupgrade__server__info.html#a9ca9a8d4a9ec737b8694bf3625c48e88',1,'upgrade_server_info']]], + ['connect_5fcallback',['connect_callback',['../struct__esp__tcp.html#a5b1fd73f4d26ae0efbaa786ae2ef5ff1',1,'_esp_tcp']]], + ['connected',['connected',['../unionEvent__Info__u.html#a3276cf21406a5988ea359ba2cf9c5e84',1,'Event_Info_u']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_3.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_3.html new file mode 100644 index 0000000..36e31b1 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_3.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_3.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_3.js new file mode 100644 index 0000000..9787e30 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_3.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['disconnect_5fcallback',['disconnect_callback',['../struct__esp__tcp.html#a90d49d2fa682397e7d439b1e616057a7',1,'_esp_tcp']]], + ['disconnected',['disconnected',['../unionEvent__Info__u.html#a004df3b560cf7f00b0fc1d205c5c6f98',1,'Event_Info_u']]], + ['duty',['duty',['../structpwm__param.html#a06e6b4fb1983f85d1908d44cb32686a8',1,'pwm_param']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_4.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_4.html new file mode 100644 index 0000000..c736635 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_4.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_4.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_4.js new file mode 100644 index 0000000..34157cd --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_4.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['enable',['enable',['../structdhcps__lease.html#ac842b6c1dcb3b1f11b611620199dc55c',1,'dhcps_lease']]], + ['end_5fip',['end_ip',['../structdhcps__lease.html#a2ecbf3162350cb32b51fcf7e0562dc84',1,'dhcps_lease']]], + ['event_5fid',['event_id',['../struct__esp__event.html#a03d39c10d31a495b8f30f745cd64cc7e',1,'_esp_event']]], + ['event_5finfo',['event_info',['../struct__esp__event.html#a34291c3b14eb4f42f70922ac2c4e17e7',1,'_esp_event']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_5.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_5.html new file mode 100644 index 0000000..4e9e673 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_5.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_5.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_5.js new file mode 100644 index 0000000..c4f92a7 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_5.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['fd_5fbuf_5fsize',['fd_buf_size',['../structesp__spiffs__config.html#a0a344b6b0ea486bc2c857249dfd2e364',1,'esp_spiffs_config']]], + ['freq',['freq',['../structpwm__param.html#a8524d98a86c8c4679521ae91d35f6e51',1,'pwm_param']]], + ['freq_5foffset',['freq_offset',['../structbss__info.html#abc41a63643b5fa7974868e1972d2675c',1,'bss_info']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_6.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_6.html new file mode 100644 index 0000000..3460c61 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_6.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_6.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_6.js new file mode 100644 index 0000000..6857439 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_6.js @@ -0,0 +1,9 @@ +var searchData= +[ + ['got_5fip',['got_ip',['../unionEvent__Info__u.html#a75708143088f7424bcb4a47f6395b91a',1,'Event_Info_u']]], + ['gpio_5fintrtype',['GPIO_IntrType',['../structGPIO__ConfigTypeDef.html#a9888e40b7e27b35c3408f5056e12c5e0',1,'GPIO_ConfigTypeDef']]], + ['gpio_5fmode',['GPIO_Mode',['../structGPIO__ConfigTypeDef.html#a0c7e8901d8b511bbb8c3b153f705dbba',1,'GPIO_ConfigTypeDef']]], + ['gpio_5fpin',['GPIO_Pin',['../structGPIO__ConfigTypeDef.html#ab88f866e27ec419ab320a38bd8ce4db9',1,'GPIO_ConfigTypeDef']]], + ['gpio_5fpullup',['GPIO_Pullup',['../structGPIO__ConfigTypeDef.html#a4397d9dc86f357d68e92846f74ea6a1f',1,'GPIO_ConfigTypeDef']]], + ['gw',['gw',['../structip__info.html#ae2fb969d40c572827b52c6006b83357d',1,'ip_info::gw()'],['../structEvent__StaMode__Got__IP__t.html#ae2fb969d40c572827b52c6006b83357d',1,'Event_StaMode_Got_IP_t::gw()']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_7.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_7.html new file mode 100644 index 0000000..34e7f98 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_7.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_7.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_7.js new file mode 100644 index 0000000..1124710 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_7.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['ip',['ip',['../structstation__info.html#a0f308afbb6ff9d8999fd963597ffaafd',1,'station_info::ip()'],['../structip__info.html#a0f308afbb6ff9d8999fd963597ffaafd',1,'ip_info::ip()'],['../structEvent__StaMode__Got__IP__t.html#a0f308afbb6ff9d8999fd963597ffaafd',1,'Event_StaMode_Got_IP_t::ip()']]], + ['is_5fhidden',['is_hidden',['../structbss__info.html#a752c7117050279bff70c6bce738be833',1,'bss_info']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_8.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_8.html new file mode 100644 index 0000000..1c5802c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_8.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_8.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_8.js new file mode 100644 index 0000000..960a6b0 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_8.js @@ -0,0 +1,8 @@ +var searchData= +[ + ['link_5fcnt',['link_cnt',['../structespconn.html#a44c66baf2083925ae34e6ff46e7ec281',1,'espconn']]], + ['local_5fip',['local_ip',['../struct__esp__tcp.html#a2b79759620ce85a36254e2b07c86b62b',1,'_esp_tcp::local_ip()'],['../struct__esp__udp.html#a2b79759620ce85a36254e2b07c86b62b',1,'_esp_udp::local_ip()']]], + ['local_5fport',['local_port',['../struct__esp__tcp.html#a009e2d58737d2223ce009dc0631e65dc',1,'_esp_tcp::local_port()'],['../struct__esp__udp.html#a009e2d58737d2223ce009dc0631e65dc',1,'_esp_udp::local_port()']]], + ['log_5fblock_5fsize',['log_block_size',['../structesp__spiffs__config.html#ac7518f38292532ca42fd8ed8a290259b',1,'esp_spiffs_config']]], + ['log_5fpage_5fsize',['log_page_size',['../structesp__spiffs__config.html#a0cfa1078dbb0a9591e9955d6dd0ad13a',1,'esp_spiffs_config']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_9.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_9.html new file mode 100644 index 0000000..ea8a856 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_9.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_9.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_9.js new file mode 100644 index 0000000..a37eb84 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_9.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['mac',['mac',['../structEvent__SoftAPMode__StaConnected__t.html#adef72662fd97f14968405c927136b700',1,'Event_SoftAPMode_StaConnected_t::mac()'],['../structEvent__SoftAPMode__StaDisconnected__t.html#adef72662fd97f14968405c927136b700',1,'Event_SoftAPMode_StaDisconnected_t::mac()'],['../structEvent__SoftAPMode__ProbeReqRecved__t.html#adef72662fd97f14968405c927136b700',1,'Event_SoftAPMode_ProbeReqRecved_t::mac()']]], + ['mask',['mask',['../structEvent__StaMode__Got__IP__t.html#a494da30773601639d4aa8e289ca33ccc',1,'Event_StaMode_Got_IP_t']]], + ['max_5fconnection',['max_connection',['../structsoftap__config.html#ad6cbad99ccec22e10893f883a2a4d092',1,'softap_config']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_a.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_a.html new file mode 100644 index 0000000..f2e7496 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_a.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_a.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_a.js new file mode 100644 index 0000000..73e00a9 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_a.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['netmask',['netmask',['../structip__info.html#a9b6d1d396ad76ad9c32ab40332c8e5ae',1,'ip_info']]], + ['new_5fmode',['new_mode',['../structEvent__StaMode__AuthMode__Change__t.html#a87330332c13687acbf3fa85aa30b32ea',1,'Event_StaMode_AuthMode_Change_t']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_b.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_b.html new file mode 100644 index 0000000..cd7dfb6 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_b.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_b.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_b.js new file mode 100644 index 0000000..5ea3fea --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_b.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['old_5fmode',['old_mode',['../structEvent__StaMode__AuthMode__Change__t.html#aec107fd7e68f2881586ebd4c9d1df031',1,'Event_StaMode_AuthMode_Change_t']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_c.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_c.html new file mode 100644 index 0000000..4f03f98 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_c.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_c.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_c.js new file mode 100644 index 0000000..9f0d9b4 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_c.js @@ -0,0 +1,9 @@ +var searchData= +[ + ['password',['password',['../structsoftap__config.html#a7f8efb8f0ad39a8b94c3407c841750bb',1,'softap_config::password()'],['../structstation__config.html#a7f8efb8f0ad39a8b94c3407c841750bb',1,'station_config::password()']]], + ['period',['period',['../structpwm__param.html#a3c1ef865ae62e58233701a3bfc68f262',1,'pwm_param']]], + ['phys_5faddr',['phys_addr',['../structesp__spiffs__config.html#a7ba95ed315e15b8c4573ff01477b1ecf',1,'esp_spiffs_config']]], + ['phys_5ferase_5fblock',['phys_erase_block',['../structesp__spiffs__config.html#af4070ae5fe9914a88e6b5afa775c112a',1,'esp_spiffs_config']]], + ['phys_5fsize',['phys_size',['../structesp__spiffs__config.html#a3730a1b272a6d5d2f567a2876f4cdc46',1,'esp_spiffs_config']]], + ['pre_5fversion',['pre_version',['../structupgrade__server__info.html#ab7408cf1414fc2d3ebd4ced54962e2b8',1,'upgrade_server_info']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_d.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_d.html new file mode 100644 index 0000000..ec2ae78 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_d.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_d.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_d.js new file mode 100644 index 0000000..3f2815e --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_d.js @@ -0,0 +1,10 @@ +var searchData= +[ + ['reason',['reason',['../structrst__info.html#af5b53fbb4b238f9aa0261eed1236b9ba',1,'rst_info::reason()'],['../structEvent__StaMode__Disconnected__t.html#abf07e8ad67430e516654d1b8d42b9731',1,'Event_StaMode_Disconnected_t::reason()']]], + ['reconnect_5fcallback',['reconnect_callback',['../struct__esp__tcp.html#a7dfb00c9f12a97566da16c71bebd253b',1,'_esp_tcp']]], + ['recv_5fcallback',['recv_callback',['../structespconn.html#a66d8db64dbb623bab3e442dd923371b5',1,'espconn']]], + ['remote_5fip',['remote_ip',['../struct__esp__tcp.html#a1e97206aeb1c8767a07fba34b0e10630',1,'_esp_tcp::remote_ip()'],['../struct__esp__udp.html#a1e97206aeb1c8767a07fba34b0e10630',1,'_esp_udp::remote_ip()'],['../struct__remot__info.html#a1e97206aeb1c8767a07fba34b0e10630',1,'_remot_info::remote_ip()']]], + ['remote_5fport',['remote_port',['../struct__esp__tcp.html#a50c260a2144cb980f505670e1ea22ccd',1,'_esp_tcp::remote_port()'],['../struct__esp__udp.html#a50c260a2144cb980f505670e1ea22ccd',1,'_esp_udp::remote_port()'],['../struct__remot__info.html#a50c260a2144cb980f505670e1ea22ccd',1,'_remot_info::remote_port()']]], + ['reserve',['reserve',['../structespconn.html#aaaa8d264a32f8754cf0ffa69f70d8f8d',1,'espconn']]], + ['rssi',['rssi',['../structbss__info.html#a919873edc1a7b2795e7efc5b9108ef53',1,'bss_info::rssi()'],['../structEvent__SoftAPMode__ProbeReqRecved__t.html#ab6f4522a5a5c4577c16d0e23339a1414',1,'Event_SoftAPMode_ProbeReqRecved_t::rssi()']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_e.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_e.html new file mode 100644 index 0000000..704caba --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_e.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_e.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_e.js new file mode 100644 index 0000000..7253134 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_e.js @@ -0,0 +1,15 @@ +var searchData= +[ + ['scan_5fdone',['scan_done',['../unionEvent__Info__u.html#a1aec02af40844b393be6f3909f961c58',1,'Event_Info_u']]], + ['sent_5fcallback',['sent_callback',['../structespconn.html#aee31e3e88191acb2de9dbbc43a40cd47',1,'espconn']]], + ['show_5fhidden',['show_hidden',['../structscan__config.html#a34fae8706d36b49d6462103708a8f306',1,'scan_config']]], + ['sockaddrin',['sockaddrin',['../structupgrade__server__info.html#aff5a0f0a52dbedb0aa98a1cc408ba7df',1,'upgrade_server_info']]], + ['ssid',['ssid',['../structsoftap__config.html#ad09c9f62c8c9f7a27707b46a0cd6af0e',1,'softap_config::ssid()'],['../structstation__config.html#ad09c9f62c8c9f7a27707b46a0cd6af0e',1,'station_config::ssid()'],['../structscan__config.html#a19b5d447df6e5c3feed382b08e9ad556',1,'scan_config::ssid()'],['../structbss__info.html#ad09c9f62c8c9f7a27707b46a0cd6af0e',1,'bss_info::ssid()'],['../structEvent__StaMode__Connected__t.html#ad09c9f62c8c9f7a27707b46a0cd6af0e',1,'Event_StaMode_Connected_t::ssid()'],['../structEvent__StaMode__Disconnected__t.html#ad09c9f62c8c9f7a27707b46a0cd6af0e',1,'Event_StaMode_Disconnected_t::ssid()']]], + ['ssid_5fhidden',['ssid_hidden',['../structsoftap__config.html#afea88ca4deb29f0ff7b0b41bb8ec2fec',1,'softap_config']]], + ['ssid_5flen',['ssid_len',['../structsoftap__config.html#a4f59d44ab2571442c2da0e50047380da',1,'softap_config::ssid_len()'],['../structbss__info.html#a4f59d44ab2571442c2da0e50047380da',1,'bss_info::ssid_len()'],['../structEvent__StaMode__Connected__t.html#a4f59d44ab2571442c2da0e50047380da',1,'Event_StaMode_Connected_t::ssid_len()'],['../structEvent__StaMode__Disconnected__t.html#a4f59d44ab2571442c2da0e50047380da',1,'Event_StaMode_Disconnected_t::ssid_len()']]], + ['sta_5fconnected',['sta_connected',['../unionEvent__Info__u.html#a1edd94c6f778ad482755a58d1019c9fc',1,'Event_Info_u']]], + ['sta_5fdisconnected',['sta_disconnected',['../unionEvent__Info__u.html#a9c7023c6473d664561a09253f6eedf98',1,'Event_Info_u']]], + ['start_5fip',['start_ip',['../structdhcps__lease.html#ad1290ecd3f8204d196999369712a586e',1,'dhcps_lease']]], + ['state',['state',['../struct__remot__info.html#ac3a8d9cd6eef4ec46bcabfd07120e40c',1,'_remot_info::state()'],['../structespconn.html#ac3a8d9cd6eef4ec46bcabfd07120e40c',1,'espconn::state()']]], + ['status',['status',['../structEvent__StaMode__ScanDone__t.html#af91a4c0bd977c78af5dd4c112bb0bc47',1,'Event_StaMode_ScanDone_t']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_f.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_f.html new file mode 100644 index 0000000..3f6c92f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_f.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_f.js b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_f.js new file mode 100644 index 0000000..9bc6488 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/search/variables_f.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['type',['type',['../structespconn.html#a2431ce92ac5c0bda2b6e5812ba8e3323',1,'espconn']]] +]; diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/smartconfig_8h_source.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/smartconfig_8h_source.html new file mode 100644 index 0000000..f3568b5 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/smartconfig_8h_source.html @@ -0,0 +1,178 @@ + + + + + + +ESP8266_RTOS_SDK: include/espressif/smartconfig.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
smartconfig.h
+
+
+
1 /*
+
2  * ESPRSSIF MIT License
+
3  *
+
4  * Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+
5  *
+
6  * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+
7  * it is free of charge, to any person obtaining a copy of this software and associated
+
8  * documentation files (the "Software"), to deal in the Software without restriction, including
+
9  * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+
10  * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
+
11  * to do so, subject to the following conditions:
+
12  *
+
13  * The above copyright notice and this permission notice shall be included in all copies or
+
14  * substantial portions of the Software.
+
15  *
+
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
22  *
+
23  */
+
24 
+
25 #ifndef __SMARTCONFIG_H__
+
26 #define __SMARTCONFIG_H__
+
27 
+
28 #ifdef __cplusplus
+
29 extern "C" {
+
30 #endif
+
31 
+
52 typedef enum {
+ + + + + +
58 } sc_status;
+
59 
+
60 typedef enum {
+ + + +
64 } sc_type;
+
65 
+
81 typedef void (*sc_callback_t)(sc_status status, void *pdata);
+
82 
+
90 const char *smartconfig_get_version(void);
+
91 
+
112 bool smartconfig_start(sc_callback_t cb, ...);
+
113 
+
125 bool smartconfig_stop(void);
+
126 
+
138 bool esptouch_set_timeout(uint8 time_s);
+
139 
+
151 bool smartconfig_set_type(sc_type type);
+
152 
+
161 #ifdef __cplusplus
+
162 }
+
163 #endif
+
164 
+
165 #endif
+
Definition: smartconfig.h:53
+
Definition: smartconfig.h:54
+
void(* sc_callback_t)(sc_status status, void *pdata)
The callback of SmartConfig, executed when smart-config status changed.
Definition: smartconfig.h:81
+
Definition: smartconfig.h:62
+
sc_type
Definition: smartconfig.h:60
+
bool smartconfig_set_type(sc_type type)
Set protocol type of SmartConfig.
+
Definition: smartconfig.h:55
+
const char * smartconfig_get_version(void)
Get the version of SmartConfig.
+
Definition: smartconfig.h:57
+
sc_status
Definition: smartconfig.h:52
+
Definition: smartconfig.h:63
+
Definition: smartconfig.h:56
+
bool smartconfig_start(sc_callback_t cb,...)
Start SmartConfig mode.
+
bool esptouch_set_timeout(uint8 time_s)
Set timeout of SmartConfig.
+
Definition: smartconfig.h:61
+
bool smartconfig_stop(void)
Stop SmartConfig, free the buffer taken by smartconfig_start.
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/spi__flash_8h_source.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/spi__flash_8h_source.html new file mode 100644 index 0000000..f49f3fd --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/spi__flash_8h_source.html @@ -0,0 +1,184 @@ + + + + + + +ESP8266_RTOS_SDK: include/espressif/spi_flash.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
spi_flash.h
+
+
+
1 /*
+
2  * ESPRSSIF MIT License
+
3  *
+
4  * Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+
5  *
+
6  * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+
7  * it is free of charge, to any person obtaining a copy of this software and associated
+
8  * documentation files (the "Software"), to deal in the Software without restriction, including
+
9  * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+
10  * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
+
11  * to do so, subject to the following conditions:
+
12  *
+
13  * The above copyright notice and this permission notice shall be included in all copies or
+
14  * substantial portions of the Software.
+
15  *
+
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
22  *
+
23  */
+
24 
+
25 #ifndef __SPI_FLASH_H__
+
26 #define __SPI_FLASH_H__
+
27 
+
28 #ifdef __cplusplus
+
29 extern "C" {
+
30 #endif
+
31 
+
48 typedef enum {
+ + + + +
53 
+
54 typedef struct{
+
55  uint32 deviceId;
+
56  uint32 chip_size; // chip size in byte
+
57  uint32 block_size;
+
58  uint32 sector_size;
+
59  uint32 page_size;
+
60  uint32 status_mask;
+
61 } SpiFlashChip;
+
62 
+
63 #define SPI_FLASH_SEC_SIZE 4096
+
72 uint32 spi_flash_get_id(void);
+
73 
+ +
82 
+
90 SpiFlashOpResult spi_flash_write_status(uint32 status_value);
+
91 
+ +
100 
+
110 SpiFlashOpResult spi_flash_write(uint32 des_addr, uint32 *src_addr, uint32 size);
+
111 
+
121 SpiFlashOpResult spi_flash_read(uint32 src_addr, uint32 *des_addr, uint32 size);
+
122 
+ +
136  SpiFlashChip *spi,
+
137  uint32 src_addr,
+
138  uint32 *des_addr,
+
139  uint32 size);
+
140 
+ +
152 
+
161 #ifdef __cplusplus
+
162 }
+
163 #endif
+
164 
+
165 #endif
+
Definition: spi_flash.h:54
+
SpiFlashOpResult spi_flash_write_status(uint32 status_value)
Write state register of SPI Flash.
+
SpiFlashOpResult spi_flash_read(uint32 src_addr, uint32 *des_addr, uint32 size)
Read data from Flash.
+
Definition: spi_flash.h:50
+
SpiFlashOpResult spi_flash_erase_sector(uint16 sec)
Erase the Flash sector.
+
Definition: spi_flash.h:51
+
SpiFlashOpResult spi_flash_write(uint32 des_addr, uint32 *src_addr, uint32 size)
Write data to Flash.
+
SpiFlashOpResult
Definition: spi_flash.h:48
+
SpiFlashOpResult(* user_spi_flash_read)(SpiFlashChip *spi, uint32 src_addr, uint32 *des_addr, uint32 size)
Registered function for spi_flash_set_read_func.
Definition: spi_flash.h:135
+
SpiFlashOpResult spi_flash_read_status(uint32 *status)
Read state register of SPI Flash.
+
Definition: spi_flash.h:49
+
void spi_flash_set_read_func(user_spi_flash_read read)
Register user-define SPI flash read API.
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/splitbar.png b/Distrib/ESPressif/RTOS/1.5.0/documents/html/splitbar.png new file mode 100644 index 0000000000000000000000000000000000000000..fe895f2c58179b471a22d8320b39a4bd7312ec8e GIT binary patch literal 314 zcmeAS@N?(olHy`uVBq!ia0vp^Yzz!63>-{AmhX=Jf(#6djGiuzAr*{o?=JLmPLyc> z_*`QK&+BH@jWrYJ7>r6%keRM@)Qyv8R=enp0jiI>aWlGyB58O zFVR20d+y`K7vDw(hJF3;>dD*3-?v=<8M)@x|EEGLnJsniYK!2U1 Y!`|5biEc?d1`HDhPgg&ebxsLQ02F6;9RL6T literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__SoftAPMode__ProbeReqRecved__t.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__SoftAPMode__ProbeReqRecved__t.html new file mode 100644 index 0000000..52fcd47 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__SoftAPMode__ProbeReqRecved__t.html @@ -0,0 +1,138 @@ + + + + + + +ESP8266_RTOS_SDK: Event_SoftAPMode_ProbeReqRecved_t Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
Event_SoftAPMode_ProbeReqRecved_t Struct Reference
+
+
+ + + + + + +

+Data Fields

int rssi
 
uint8 mac [6]
 
+

Field Documentation

+ +
+
+ + + + +
uint8 mac[6]
+
+

MAC address of the station which send probe request

+ +
+
+ +
+
+ + + + +
int rssi
+
+

Received probe request signal strength

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__SoftAPMode__StaConnected__t.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__SoftAPMode__StaConnected__t.html new file mode 100644 index 0000000..b951308 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__SoftAPMode__StaConnected__t.html @@ -0,0 +1,138 @@ + + + + + + +ESP8266_RTOS_SDK: Event_SoftAPMode_StaConnected_t Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
Event_SoftAPMode_StaConnected_t Struct Reference
+
+
+ + + + + + +

+Data Fields

uint8 mac [6]
 
uint8 aid
 
+

Field Documentation

+ +
+
+ + + + +
uint8 aid
+
+

the aid that ESP8266 soft-AP gives to the station connected to

+ +
+
+ +
+
+ + + + +
uint8 mac[6]
+
+

MAC address of the station connected to ESP8266 soft-AP

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__SoftAPMode__StaDisconnected__t.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__SoftAPMode__StaDisconnected__t.html new file mode 100644 index 0000000..527a171 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__SoftAPMode__StaDisconnected__t.html @@ -0,0 +1,138 @@ + + + + + + +ESP8266_RTOS_SDK: Event_SoftAPMode_StaDisconnected_t Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
Event_SoftAPMode_StaDisconnected_t Struct Reference
+
+
+ + + + + + +

+Data Fields

uint8 mac [6]
 
uint8 aid
 
+

Field Documentation

+ +
+
+ + + + +
uint8 aid
+
+

the aid that ESP8266 soft-AP gave to the station disconnects to

+ +
+
+ +
+
+ + + + +
uint8 mac[6]
+
+

MAC address of the station disconnects to ESP8266 soft-AP

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__StaMode__AuthMode__Change__t.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__StaMode__AuthMode__Change__t.html new file mode 100644 index 0000000..ad7675d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__StaMode__AuthMode__Change__t.html @@ -0,0 +1,138 @@ + + + + + + +ESP8266_RTOS_SDK: Event_StaMode_AuthMode_Change_t Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
Event_StaMode_AuthMode_Change_t Struct Reference
+
+
+ + + + + + +

+Data Fields

uint8 old_mode
 
uint8 new_mode
 
+

Field Documentation

+ +
+
+ + + + +
uint8 new_mode
+
+

the new auth mode of AP

+ +
+
+ +
+
+ + + + +
uint8 old_mode
+
+

the old auth mode of AP

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__StaMode__Connected__t.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__StaMode__Connected__t.html new file mode 100644 index 0000000..2d22708 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__StaMode__Connected__t.html @@ -0,0 +1,168 @@ + + + + + + +ESP8266_RTOS_SDK: Event_StaMode_Connected_t Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
Event_StaMode_Connected_t Struct Reference
+
+
+ + + + + + + + + + +

+Data Fields

uint8 ssid [32]
 
uint8 ssid_len
 
uint8 bssid [6]
 
uint8 channel
 
+

Field Documentation

+ +
+
+ + + + +
uint8 bssid[6]
+
+

BSSID of connected AP

+ +
+
+ +
+
+ + + + +
uint8 channel
+
+

channel of connected AP

+ +
+
+ +
+
+ + + + +
uint8 ssid[32]
+
+

SSID of connected AP

+ +
+
+ +
+
+ + + + +
uint8 ssid_len
+
+

SSID length of connected AP

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__StaMode__Disconnected__t.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__StaMode__Disconnected__t.html new file mode 100644 index 0000000..4e4ceff --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__StaMode__Disconnected__t.html @@ -0,0 +1,168 @@ + + + + + + +ESP8266_RTOS_SDK: Event_StaMode_Disconnected_t Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
Event_StaMode_Disconnected_t Struct Reference
+
+
+ + + + + + + + + + +

+Data Fields

uint8 ssid [32]
 
uint8 ssid_len
 
uint8 bssid [6]
 
uint8 reason
 
+

Field Documentation

+ +
+
+ + + + +
uint8 bssid[6]
+
+

BSSID of disconnected AP

+ +
+
+ +
+
+ + + + +
uint8 reason
+
+

reason of disconnection

+ +
+
+ +
+
+ + + + +
uint8 ssid[32]
+
+

SSID of disconnected AP

+ +
+
+ +
+
+ + + + +
uint8 ssid_len
+
+

SSID length of disconnected AP

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__StaMode__Got__IP__t.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__StaMode__Got__IP__t.html new file mode 100644 index 0000000..6301390 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__StaMode__Got__IP__t.html @@ -0,0 +1,153 @@ + + + + + + +ESP8266_RTOS_SDK: Event_StaMode_Got_IP_t Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
Event_StaMode_Got_IP_t Struct Reference
+
+
+ + + + + + + + +

+Data Fields

struct ip_addr ip
 
struct ip_addr mask
 
struct ip_addr gw
 
+

Field Documentation

+ +
+
+ + + + +
struct ip_addr gw
+
+

gateway that ESP8266 station got from connected AP

+ +
+
+ +
+
+ + + + +
struct ip_addr ip
+
+

IP address that ESP8266 station got from connected AP

+ +
+
+ +
+
+ + + + +
struct ip_addr mask
+
+

netmask that ESP8266 station got from connected AP

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__StaMode__ScanDone__t.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__StaMode__ScanDone__t.html new file mode 100644 index 0000000..ef92b5d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structEvent__StaMode__ScanDone__t.html @@ -0,0 +1,138 @@ + + + + + + +ESP8266_RTOS_SDK: Event_StaMode_ScanDone_t Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
Event_StaMode_ScanDone_t Struct Reference
+
+
+ + + + + + +

+Data Fields

uint32 status
 
struct bss_infobss
 
+

Field Documentation

+ +
+
+ + + + +
struct bss_info* bss
+
+

list of APs found

+ +
+
+ +
+
+ + + + +
uint32 status
+
+

status of scanning APs

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/structGPIO__ConfigTypeDef.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structGPIO__ConfigTypeDef.html new file mode 100644 index 0000000..353b0b3 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structGPIO__ConfigTypeDef.html @@ -0,0 +1,168 @@ + + + + + + +ESP8266_RTOS_SDK: GPIO_ConfigTypeDef Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
GPIO_ConfigTypeDef Struct Reference
+
+
+ + + + + + + + + + +

+Data Fields

uint16 GPIO_Pin
 
GPIOMode_TypeDef GPIO_Mode
 
GPIO_Pullup_IF GPIO_Pullup
 
GPIO_INT_TYPE GPIO_IntrType
 
+

Field Documentation

+ +
+
+ + + + +
GPIO_INT_TYPE GPIO_IntrType
+
+

GPIO interrupt type

+ +
+
+ +
+
+ + + + +
GPIOMode_TypeDef GPIO_Mode
+
+

GPIO mode

+ +
+
+ +
+
+ + + + +
uint16 GPIO_Pin
+
+

GPIO pin

+ +
+
+ +
+
+ + + + +
GPIO_Pullup_IF GPIO_Pullup
+
+

GPIO pullup

+ +
+
+
The documentation for this struct was generated from the following file:
    +
  • examples/driver_lib/include/gpio.h
  • +
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/structSpiFlashChip.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structSpiFlashChip.html new file mode 100644 index 0000000..ee9b992 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structSpiFlashChip.html @@ -0,0 +1,125 @@ + + + + + + +ESP8266_RTOS_SDK: SpiFlashChip Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
SpiFlashChip Struct Reference
+
+
+ + + + + + + + + + + + + + +

+Data Fields

+uint32 deviceId
 
+uint32 chip_size
 
+uint32 block_size
 
+uint32 sector_size
 
+uint32 page_size
 
+uint32 status_mask
 
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/structUART__ConfigTypeDef.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structUART__ConfigTypeDef.html new file mode 100644 index 0000000..5669f9f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structUART__ConfigTypeDef.html @@ -0,0 +1,128 @@ + + + + + + +ESP8266_RTOS_SDK: UART_ConfigTypeDef Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
UART_ConfigTypeDef Struct Reference
+
+
+ + + + + + + + + + + + + + + + +

+Data Fields

+UART_BautRate baud_rate
 
+UART_WordLength data_bits
 
+UART_ParityMode parity
 
+UART_StopBits stop_bits
 
+UART_HwFlowCtrl flow_ctrl
 
+uint8 UART_RxFlowThresh
 
+uint32 UART_InverseMask
 
+
The documentation for this struct was generated from the following file:
    +
  • examples/driver_lib/include/uart.h
  • +
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/structUART__IntrConfTypeDef.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structUART__IntrConfTypeDef.html new file mode 100644 index 0000000..1ebbe78 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structUART__IntrConfTypeDef.html @@ -0,0 +1,119 @@ + + + + + + +ESP8266_RTOS_SDK: UART_IntrConfTypeDef Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
UART_IntrConfTypeDef Struct Reference
+
+
+ + + + + + + + + + +

+Data Fields

+uint32 UART_IntrEnMask
 
+uint8 UART_RX_TimeOutIntrThresh
 
+uint8 UART_TX_FifoEmptyIntrThresh
 
+uint8 UART_RX_FifoFullIntrThresh
 
+
The documentation for this struct was generated from the following file:
    +
  • examples/driver_lib/include/uart.h
  • +
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/struct__esp__event.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/struct__esp__event.html new file mode 100644 index 0000000..3a7bbbf --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/struct__esp__event.html @@ -0,0 +1,138 @@ + + + + + + +ESP8266_RTOS_SDK: _esp_event Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
_esp_event Struct Reference
+
+
+ + + + + + +

+Data Fields

SYSTEM_EVENT event_id
 
Event_Info_u event_info
 
+

Field Documentation

+ +
+
+ + + + +
SYSTEM_EVENT event_id
+
+

even ID

+ +
+
+ +
+
+ + + + +
Event_Info_u event_info
+
+

event information

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/struct__esp__tcp.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/struct__esp__tcp.html new file mode 100644 index 0000000..1fe0a1c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/struct__esp__tcp.html @@ -0,0 +1,228 @@ + + + + + + +ESP8266_RTOS_SDK: _esp_tcp Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
_esp_tcp Struct Reference
+
+
+ + + + + + + + + + + + + + + + + + +

+Data Fields

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
 
+

Field Documentation

+ +
+
+ + + + +
espconn_connect_callback connect_callback
+
+

connected callback

+ +
+
+ +
+
+ + + + +
espconn_connect_callback disconnect_callback
+
+

disconnected callback

+ +
+
+ +
+
+ + + + +
uint8 local_ip[4]
+
+

local IP of ESP8266

+ +
+
+ +
+
+ + + + +
int local_port
+
+

ESP8266's local port of TCP connection

+ +
+
+ +
+
+ + + + +
espconn_reconnect_callback reconnect_callback
+
+

as error handler, the TCP connection broke unexpectedly

+ +
+
+ +
+
+ + + + +
uint8 remote_ip[4]
+
+

remote IP of TCP connection

+ +
+
+ +
+
+ + + + +
int remote_port
+
+

remote port of TCP connection

+ +
+
+ +
+
+ + + + +
espconn_connect_callback write_finish_fn
+
+

data send by espconn_send has wrote into buffer waiting for sending, or has sent successfully

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/struct__esp__udp.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/struct__esp__udp.html new file mode 100644 index 0000000..6181eb6 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/struct__esp__udp.html @@ -0,0 +1,168 @@ + + + + + + +ESP8266_RTOS_SDK: _esp_udp Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
_esp_udp Struct Reference
+
+
+ + + + + + + + + + +

+Data Fields

int remote_port
 
int local_port
 
uint8 local_ip [4]
 
uint8 remote_ip [4]
 
+

Field Documentation

+ +
+
+ + + + +
uint8 local_ip[4]
+
+

local IP of ESP8266

+ +
+
+ +
+
+ + + + +
int local_port
+
+

ESP8266's local port for UDP transmission

+ +
+
+ +
+
+ + + + +
uint8 remote_ip[4]
+
+

remote IP of UDP transmission

+ +
+
+ +
+
+ + + + +
int remote_port
+
+

remote port of UDP transmission

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/struct__os__timer__t.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/struct__os__timer__t.html new file mode 100644 index 0000000..5cfa666 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/struct__os__timer__t.html @@ -0,0 +1,128 @@ + + + + + + +ESP8266_RTOS_SDK: _os_timer_t Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
_os_timer_t Struct Reference
+
+
+ + + + + + + + + + + + + + + + +

+Data Fields

+struct _os_timer_ttimer_next
 
+void * timer_handle
 
+uint32 timer_expire
 
+uint32 timer_period
 
+os_timer_func_t * timer_func
 
+bool timer_repeat_flag
 
+void * timer_arg
 
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/struct__remot__info.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/struct__remot__info.html new file mode 100644 index 0000000..d601165 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/struct__remot__info.html @@ -0,0 +1,153 @@ + + + + + + +ESP8266_RTOS_SDK: _remot_info Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
_remot_info Struct Reference
+
+
+ + + + + + + + +

+Data Fields

enum espconn_state state
 
int remote_port
 
uint8 remote_ip [4]
 
+

Field Documentation

+ +
+
+ + + + +
uint8 remote_ip[4]
+
+

remote IP address

+ +
+
+ +
+
+ + + + +
int remote_port
+
+

remote port

+ +
+
+ +
+
+ + + + +
enum espconn_state state
+
+

state of espconn

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/structairkiss__config__t.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structairkiss__config__t.html new file mode 100644 index 0000000..7b8b5ea --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structairkiss__config__t.html @@ -0,0 +1,119 @@ + + + + + + +ESP8266_RTOS_SDK: airkiss_config_t Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
airkiss_config_t Struct Reference
+
+
+ + + + + + + + + + +

+Data Fields

+airkiss_memset_fn memset
 
+airkiss_memcpy_fn memcpy
 
+airkiss_memcmp_fn memcmp
 
+airkiss_printf_fn printf
 
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/structbss__info.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structbss__info.html new file mode 100644 index 0000000..463fb36 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structbss__info.html @@ -0,0 +1,258 @@ + + + + + + +ESP8266_RTOS_SDK: bss_info Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
bss_info Struct Reference
+
+
+ + + + +

+Public Member Functions

 STAILQ_ENTRY (bss_info) next
 
+ + + + + + + + + + + + + + + + + + + + + +

+Data Fields

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
 
+

Member Function Documentation

+ +
+
+ + + + + + + + +
STAILQ_ENTRY (bss_info )
+
+

information of next AP

+ +
+
+

Field Documentation

+ +
+
+ + + + +
AUTH_MODE authmode
+
+

authmode of AP

+ +
+
+ +
+
+ + + + +
uint8 bssid[6]
+
+

MAC address of AP

+ +
+
+ +
+
+ + + + +
uint8 channel
+
+

channel of AP

+ +
+
+ +
+
+ + + + +
sint16 freq_offset
+
+

frequency offset

+ +
+
+ +
+
+ + + + +
uint8 is_hidden
+
+

SSID of current AP is hidden or not.

+ +
+
+ +
+
+ + + + +
sint8 rssi
+
+

single strength of AP

+ +
+
+ +
+
+ + + + +
uint8 ssid[32]
+
+

SSID of AP

+ +
+
+ +
+
+ + + + +
uint8 ssid_len
+
+

SSID length

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/structcmd__s.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structcmd__s.html new file mode 100644 index 0000000..b10f7b6 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structcmd__s.html @@ -0,0 +1,122 @@ + + + + + + +ESP8266_RTOS_SDK: cmd_s Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
cmd_s Struct Reference
+
+
+ + + + + + + + + + + + +

+Data Fields

+char * cmd_str
 
+uint8 flag
 
+uint8 id
 
+void(* cmd_func )(void)
 
+void(* cmd_callback )(void *arg)
 
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/structdhcps__lease.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structdhcps__lease.html new file mode 100644 index 0000000..6038d10 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structdhcps__lease.html @@ -0,0 +1,153 @@ + + + + + + +ESP8266_RTOS_SDK: dhcps_lease Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
dhcps_lease Struct Reference
+
+
+ + + + + + + + +

+Data Fields

bool enable
 
struct ip_addr start_ip
 
struct ip_addr end_ip
 
+

Field Documentation

+ +
+
+ + + + +
bool enable
+
+

enable DHCP lease or not

+ +
+
+ +
+
+ + + + +
struct ip_addr end_ip
+
+

end IP of IP range

+ +
+
+ +
+
+ + + + +
struct ip_addr start_ip
+
+

start IP of IP range

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/structesp__spiffs__config.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structesp__spiffs__config.html new file mode 100644 index 0000000..118e473 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structesp__spiffs__config.html @@ -0,0 +1,213 @@ + + + + + + +ESP8266_RTOS_SDK: esp_spiffs_config Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
esp_spiffs_config Struct Reference
+
+
+ + + + + + + + + + + + + + + + +

+Data Fields

uint32 phys_size
 
uint32 phys_addr
 
uint32 phys_erase_block
 
uint32 log_block_size
 
uint32 log_page_size
 
uint32 fd_buf_size
 
uint32 cache_buf_size
 
+

Field Documentation

+ +
+
+ + + + +
uint32 cache_buf_size
+
+

cache buffer size

+ +
+
+ +
+
+ + + + +
uint32 fd_buf_size
+
+

file descriptor memory area size

+ +
+
+ +
+
+ + + + +
uint32 log_block_size
+
+

logical size of a block, must be on physical block size boundary and must never be less than a physical block

+ +
+
+ +
+
+ + + + +
uint32 log_page_size
+
+

logical size of a page, at least log_block_size/8

+ +
+
+ +
+
+ + + + +
uint32 phys_addr
+
+

physical offset in spi flash used for spiffs, must be on block boundary

+ +
+
+ +
+
+ + + + +
uint32 phys_erase_block
+
+

physical size when erasing a block

+ +
+
+ +
+
+ + + + +
uint32 phys_size
+
+

physical size of the SPI Flash

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/structespconn.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structespconn.html new file mode 100644 index 0000000..da39a3e --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structespconn.html @@ -0,0 +1,212 @@ + + + + + + +ESP8266_RTOS_SDK: espconn Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
espconn Struct Reference
+
+
+ +

#include <espconn.h>

+ + + + + + + + + + + + + + + + + + + + + +

+Data Fields

enum espconn_type type
 
enum espconn_state state
 
+union {
+   esp_tcp *   tcp
 
+   esp_udp *   udp
 
proto
 
espconn_recv_callback recv_callback
 
espconn_sent_callback sent_callback
 
uint8 link_cnt
 
void * reserve
 
+

Detailed Description

+

A espconn descriptor

+

Field Documentation

+ +
+
+ + + + +
uint8 link_cnt
+
+

link count

+ +
+
+ +
+
+ + + + +
espconn_recv_callback recv_callback
+
+

data received callback

+ +
+
+ +
+
+ + + + +
void* reserve
+
+

reserved for user data

+ +
+
+ +
+
+ + + + +
espconn_sent_callback sent_callback
+
+

data sent callback

+ +
+
+ +
+
+ + + + +
enum espconn_state state
+
+

current state of the espconn

+ +
+
+ +
+
+ + + + +
enum espconn_type type
+
+

type of the espconn (TCP or UDP)

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/structip__info.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structip__info.html new file mode 100644 index 0000000..68217c0 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structip__info.html @@ -0,0 +1,153 @@ + + + + + + +ESP8266_RTOS_SDK: ip_info Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
ip_info Struct Reference
+
+
+ + + + + + + + +

+Data Fields

struct ip_addr ip
 
struct ip_addr netmask
 
struct ip_addr gw
 
+

Field Documentation

+ +
+
+ + + + +
struct ip_addr gw
+
+

gateway

+ +
+
+ +
+
+ + + + +
struct ip_addr ip
+
+

IP address

+ +
+
+ +
+
+ + + + +
struct ip_addr netmask
+
+

netmask

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/structpwm__param.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structpwm__param.html new file mode 100644 index 0000000..a0e0eb1 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structpwm__param.html @@ -0,0 +1,153 @@ + + + + + + +ESP8266_RTOS_SDK: pwm_param Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
pwm_param Struct Reference
+
+
+ + + + + + + + +

+Data Fields

uint32 period
 
uint32 freq
 
uint32 duty [8]
 
+

Field Documentation

+ +
+
+ + + + +
uint32 duty[8]
+
+

PWM duty

+ +
+
+ +
+
+ + + + +
uint32 freq
+
+

PWM frequency

+ +
+
+ +
+
+ + + + +
uint32 period
+
+

PWM period

+ +
+
+
The documentation for this struct was generated from the following file:
    +
  • include/espressif/pwm.h
  • +
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/structrst__info.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structrst__info.html new file mode 100644 index 0000000..a4a9d37 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structrst__info.html @@ -0,0 +1,144 @@ + + + + + + +ESP8266_RTOS_SDK: rst_info Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
rst_info Struct Reference
+
+
+ + + + + + + + + + + + + + + + + + +

+Data Fields

rst_reason reason
 
+uint32 exccause
 
+uint32 epc1
 
+uint32 epc2
 
+uint32 epc3
 
+uint32 excvaddr
 
+uint32 depc
 
+uint32 rtn_addr
 
+

Field Documentation

+ +
+
+ + + + +
rst_reason reason
+
+

enum rst_reason

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/structscan__config.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structscan__config.html new file mode 100644 index 0000000..0bbad21 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structscan__config.html @@ -0,0 +1,168 @@ + + + + + + +ESP8266_RTOS_SDK: scan_config Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
scan_config Struct Reference
+
+
+ + + + + + + + + + +

+Data Fields

uint8 * ssid
 
uint8 * bssid
 
uint8 channel
 
uint8 show_hidden
 
+

Field Documentation

+ +
+
+ + + + +
uint8* bssid
+
+

MAC address of AP

+ +
+
+ +
+
+ + + + +
uint8 channel
+
+

channel, scan the specific channel

+ +
+
+ +
+
+ + + + +
uint8 show_hidden
+
+

enable to scan AP whose SSID is hidden

+ +
+
+ +
+
+ + + + +
uint8* ssid
+
+

SSID of AP

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/structsoftap__config.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structsoftap__config.html new file mode 100644 index 0000000..7ed3d0f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structsoftap__config.html @@ -0,0 +1,228 @@ + + + + + + +ESP8266_RTOS_SDK: softap_config Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
softap_config Struct Reference
+
+
+ + + + + + + + + + + + + + + + + + +

+Data Fields

uint8 ssid [32]
 
uint8 password [64]
 
uint8 ssid_len
 
uint8 channel
 
AUTH_MODE authmode
 
uint8 ssid_hidden
 
uint8 max_connection
 
uint16 beacon_interval
 
+

Field Documentation

+ +
+
+ + + + +
AUTH_MODE authmode
+
+

Auth mode of ESP8266 soft-AP. Do not support AUTH_WEP in soft-AP mode

+ +
+
+ +
+
+ + + + +
uint16 beacon_interval
+
+

Beacon interval, 100 ~ 60000 ms, default 100

+ +
+
+ +
+
+ + + + +
uint8 channel
+
+

Channel of ESP8266 soft-AP

+ +
+
+ +
+
+ + + + +
uint8 max_connection
+
+

Max number of stations allowed to connect in, default 4, max 4

+ +
+
+ +
+
+ + + + +
uint8 password[64]
+
+

Password of ESP8266 soft-AP

+ +
+
+ +
+
+ + + + +
uint8 ssid[32]
+
+

SSID of ESP8266 soft-AP

+ +
+
+ +
+
+ + + + +
uint8 ssid_hidden
+
+

Broadcast SSID or not, default 0, broadcast the SSID

+ +
+
+ +
+
+ + + + +
uint8 ssid_len
+
+

Length of SSID. If softap_config.ssid_len==0, check the SSID until there is a termination character; otherwise, set the SSID length according to softap_config.ssid_len.

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/structstation__config.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structstation__config.html new file mode 100644 index 0000000..90e42b3 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structstation__config.html @@ -0,0 +1,168 @@ + + + + + + +ESP8266_RTOS_SDK: station_config Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
station_config Struct Reference
+
+
+ + + + + + + + + + +

+Data Fields

uint8 ssid [32]
 
uint8 password [64]
 
uint8 bssid_set
 
uint8 bssid [6]
 
+

Field Documentation

+ +
+
+ + + + +
uint8 bssid[6]
+
+

MAC address of target AP

+ +
+
+ +
+
+ + + + +
uint8 bssid_set
+
+

whether set MAC address of target AP or not. Generally, station_config.bssid_set needs to be 0; and it needs to be 1 only when users need to check the MAC address of the AP.

+ +
+
+ +
+
+ + + + +
uint8 password[64]
+
+

password of target AP

+ +
+
+ +
+
+ + + + +
uint8 ssid[32]
+
+

SSID of target AP

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/structstation__info.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structstation__info.html new file mode 100644 index 0000000..4a82509 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structstation__info.html @@ -0,0 +1,162 @@ + + + + + + +ESP8266_RTOS_SDK: station_info Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
station_info Struct Reference
+
+
+ + + + +

+Public Member Functions

 STAILQ_ENTRY (station_info) next
 
+ + + + + +

+Data Fields

uint8 bssid [6]
 
struct ip_addr ip
 
+

Member Function Documentation

+ +
+
+ + + + + + + + +
STAILQ_ENTRY (station_info )
+
+

Information of next AP

+ +
+
+

Field Documentation

+ +
+
+ + + + +
uint8 bssid[6]
+
+

BSSID of AP

+ +
+
+ +
+
+ + + + +
struct ip_addr ip
+
+

IP address of AP

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/structupgrade__server__info.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structupgrade__server__info.html new file mode 100644 index 0000000..405a6ff --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/structupgrade__server__info.html @@ -0,0 +1,216 @@ + + + + + + +ESP8266_RTOS_SDK: upgrade_server_info Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
upgrade_server_info Struct Reference
+
+
+ + + + + + + + + + + + + + + + + + +

+Data Fields

struct sockaddr_in sockaddrin
 
upgrade_states_check_callback check_cb
 
uint32 check_times
 
uint8 pre_version [16]
 
uint8 upgrade_version [16]
 
uint8 * url
 
+void * pclient_param
 
uint8 upgrade_flag
 
+

Field Documentation

+ +
+
+ + + + +
upgrade_states_check_callback check_cb
+
+

callback of upgrading

+ +
+
+ +
+
+ + + + +
uint32 check_times
+
+

time out of upgrading, unit : ms

+ +
+
+ +
+
+ + + + +
uint8 pre_version[16]
+
+

previous version of firmware

+ +
+
+ +
+
+ + + + +
struct sockaddr_in sockaddrin
+
+

socket of upgrading

+ +
+
+ +
+
+ + + + +
uint8 upgrade_flag
+
+

true, upgrade succeed; false, upgrade fail

+ +
+
+ +
+
+ + + + +
uint8 upgrade_version[16]
+
+

the new version of firmware

+ +
+
+ +
+
+ + + + +
uint8* url
+
+

the url of upgrading server

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/sync_off.png b/Distrib/ESPressif/RTOS/1.5.0/documents/html/sync_off.png new file mode 100644 index 0000000000000000000000000000000000000000..3b443fc62892114406e3d399421b2a881b897acc GIT binary patch literal 853 zcmV-b1FHOqP)oT|#XixUYy%lpuf3i8{fX!o zUyDD0jOrAiT^tq>fLSOOABs-#u{dV^F$b{L9&!2=9&RmV;;8s^x&UqB$PCj4FdKbh zoB1WTskPUPu05XzFbA}=KZ-GP1fPpAfSs>6AHb12UlR%-i&uOlTpFNS7{jm@mkU1V zh`nrXr~+^lsV-s1dkZOaI|kYyVj3WBpPCY{n~yd%u%e+d=f%`N0FItMPtdgBb@py; zq@v6NVArhyTC7)ULw-Jy8y42S1~4n(3LkrW8mW(F-4oXUP3E`e#g**YyqI7h-J2zK zK{m9##m4ri!7N>CqQqCcnI3hqo1I;Yh&QLNY4T`*ptiQGozK>FF$!$+84Z`xwmeMh zJ0WT+OH$WYFALEaGj2_l+#DC3t7_S`vHpSivNeFbP6+r50cO8iu)`7i%Z4BTPh@_m3Tk!nAm^)5Bqnr%Ov|Baunj#&RPtRuK& z4RGz|D5HNrW83-#ydk}tVKJrNmyYt-sTxLGlJY5nc&Re zU4SgHNPx8~Yxwr$bsju?4q&%T1874xxzq+_%?h8_ofw~(bld=o3iC)LUNR*BY%c0y zWd_jX{Y8`l%z+ol1$@Qa?Cy!(0CVIEeYpKZ`(9{z>3$CIe;pJDQk$m3p}$>xBm4lb zKo{4S)`wdU9Ba9jJbVJ0C=SOefZe%d$8=2r={nu<_^a3~>c#t_U6dye5)JrR(_a^E f@}b6j1K9lwFJq@>o)+Ry00000NkvXXu0mjfWa5j* literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/sync_on.png b/Distrib/ESPressif/RTOS/1.5.0/documents/html/sync_on.png new file mode 100644 index 0000000000000000000000000000000000000000..e08320fb64e6fa33b573005ed6d8fe294e19db76 GIT binary patch literal 845 zcmV-T1G4;yP)Y;xxyHF2B5Wzm| zOOGupOTn@c(JmBOl)e;XMNnZuiTJP>rM8<|Q`7I_))aP?*T)ow&n59{}X4$3Goat zgjs?*aasfbrokzG5cT4K=uG`E14xZl@z)F={P0Y^?$4t z>v!teRnNZym<6h{7sLyF1V0HsfEl+l6TrZpsfr1}luH~F7L}ktXu|*uVX^RG$L0`K zWs3j|0tIvVe(N%_?2{(iCPFGf#B6Hjy6o&}D$A%W%jfO8_W%ZO#-mh}EM$LMn7joJ z05dHr!5Y92g+31l<%i1(=L1a1pXX+OYnalY>31V4K}BjyRe3)9n#;-cCVRD_IG1fT zOKGeNY8q;TL@K{dj@D^scf&VCs*-Jb>8b>|`b*osv52-!A?BpbYtTQBns5EAU**$m zSnVSm(teh>tQi*S*A>#ySc=n;`BHz`DuG4&g4Kf8lLhca+zvZ7t7RflD6-i-mcK=M z!=^P$*u2)bkY5asG4gsss!Hn%u~>}kIW`vMs%lJLH+u*9<4PaV_c6U`KqWXQH%+Nu zTv41O(^ZVi@qhjQdG!fbZw&y+2o!iYymO^?ud3{P*HdoX83YV*Uu_HB=?U&W9%AU# z80}k1SS-CXTU7dcQlsm<^oYLxVSseqY6NO}dc`Nj?8vrhNuCdm@^{a3AQ_>6myOj+ z`1RsLUXF|dm|3k7s2jD(B{rzE>WI2scH8i1;=O5Cc9xB3^aJk%fQjqsu+kH#0=_5a z0nCE8@dbQa-|YIuUVvG0L_IwHMEhOj$Mj4Uq05 X8=0q~qBNan00000NkvXXu0mjfptF>5 literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/tab_a.png b/Distrib/ESPressif/RTOS/1.5.0/documents/html/tab_a.png new file mode 100644 index 0000000000000000000000000000000000000000..3b725c41c5a527a3a3e40097077d0e206a681247 GIT binary patch literal 142 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfy!2~3aiye;!QlXwMjv*C{Z|8b*H5dputLHD# z=<0|*y7z(Vor?d;H&?EG&cXR}?!j-Lm&u1OOI7AIF5&c)RFE;&p0MYK>*Kl@eiymD r@|NpwKX@^z+;{u_Z~trSBfrMKa%3`zocFjEXaR$#tDnm{r-UW|TZ1%4 literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/tab_b.png b/Distrib/ESPressif/RTOS/1.5.0/documents/html/tab_b.png new file mode 100644 index 0000000000000000000000000000000000000000..e2b4a8638cb3496a016eaed9e16ffc12846dea18 GIT binary patch literal 169 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfy!2~3aiye;!QU#tajv*C{Z}0l@H7kg?K0Lnr z!j&C6_(~HV9oQ0Pa6x{-v0AGV_E?vLn=ZI-;YrdjIl`U`uzuDWSP?o#Dmo{%SgM#oan kX~E1%D-|#H#QbHoIja2U-MgvsK&LQxy85}Sb4q9e0Efg%P5=M^ literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/tabs.css b/Distrib/ESPressif/RTOS/1.5.0/documents/html/tabs.css new file mode 100644 index 0000000..9cf578f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/tabs.css @@ -0,0 +1,60 @@ +.tabs, .tabs2, .tabs3 { + background-image: url('tab_b.png'); + width: 100%; + z-index: 101; + font-size: 13px; + font-family: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif; +} + +.tabs2 { + font-size: 10px; +} +.tabs3 { + font-size: 9px; +} + +.tablist { + margin: 0; + padding: 0; + display: table; +} + +.tablist li { + float: left; + display: table-cell; + background-image: url('tab_b.png'); + line-height: 36px; + list-style: none; +} + +.tablist a { + display: block; + padding: 0 20px; + font-weight: bold; + background-image:url('tab_s.png'); + background-repeat:no-repeat; + background-position:right; + color: #283A5D; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + text-decoration: none; + outline: none; +} + +.tabs3 .tablist a { + padding: 0 10px; +} + +.tablist a:hover { + background-image: url('tab_h.png'); + background-repeat:repeat-x; + color: #fff; + text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0); + text-decoration: none; +} + +.tablist li.current a { + background-image: url('tab_a.png'); + background-repeat:repeat-x; + color: #fff; + text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0); +} diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/uart_8h_source.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/uart_8h_source.html new file mode 100644 index 0000000..c75e7ac --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/uart_8h_source.html @@ -0,0 +1,270 @@ + + + + + + +ESP8266_RTOS_SDK: examples/driver_lib/include/uart.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
uart.h
+
+
+
1 /*
+
2  * ESPRSSIF MIT License
+
3  *
+
4  * Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+
5  *
+
6  * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+
7  * it is free of charge, to any person obtaining a copy of this software and associated
+
8  * documentation files (the "Software"), to deal in the Software without restriction, including
+
9  * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+
10  * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
+
11  * to do so, subject to the following conditions:
+
12  *
+
13  * The above copyright notice and this permission notice shall be included in all copies or
+
14  * substantial portions of the Software.
+
15  *
+
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
22  *
+
23  */
+
24 
+
25 #ifndef __UART_H__
+
26 #define __UART_H__
+
27 
+
28 #ifdef __cplusplus
+
29 extern "C" {
+
30 #endif
+
31 
+
32 #define ETS_UART_INTR_ENABLE() _xt_isr_unmask(1 << ETS_UART_INUM)
+
33 #define ETS_UART_INTR_DISABLE() _xt_isr_mask(1 << ETS_UART_INUM)
+
34 #define UART_INTR_MASK 0x1ff
+
35 #define UART_LINE_INV_MASK (0x3f<<19)
+
36 
+
37 typedef enum {
+
38  UART_WordLength_5b = 0x0,
+
39  UART_WordLength_6b = 0x1,
+
40  UART_WordLength_7b = 0x2,
+
41  UART_WordLength_8b = 0x3
+
42 } UART_WordLength;
+
43 
+
44 typedef enum {
+
45  USART_StopBits_1 = 0x1,
+
46  USART_StopBits_1_5 = 0x2,
+
47  USART_StopBits_2 = 0x3,
+
48 } UART_StopBits;
+
49 
+
50 typedef enum {
+
51  UART0 = 0x0,
+
52  UART1 = 0x1,
+
53 } UART_Port;
+
54 
+
55 typedef enum {
+
56  USART_Parity_None = 0x2,
+
57  USART_Parity_Even = 0x0,
+
58  USART_Parity_Odd = 0x1
+
59 } UART_ParityMode;
+
60 
+
61 typedef enum {
+
62  PARITY_DIS = 0x0,
+
63  PARITY_EN = 0x2
+
64 } UartExistParity;
+
65 
+
66 typedef enum {
+
67  BIT_RATE_300 = 300,
+
68  BIT_RATE_600 = 600,
+
69  BIT_RATE_1200 = 1200,
+
70  BIT_RATE_2400 = 2400,
+
71  BIT_RATE_4800 = 4800,
+
72  BIT_RATE_9600 = 9600,
+
73  BIT_RATE_19200 = 19200,
+
74  BIT_RATE_38400 = 38400,
+
75  BIT_RATE_57600 = 57600,
+
76  BIT_RATE_74880 = 74880,
+
77  BIT_RATE_115200 = 115200,
+
78  BIT_RATE_230400 = 230400,
+
79  BIT_RATE_460800 = 460800,
+
80  BIT_RATE_921600 = 921600,
+
81  BIT_RATE_1843200 = 1843200,
+
82  BIT_RATE_3686400 = 3686400,
+
83 } UART_BautRate; //you can add any rate you need in this range
+
84 
+
85 typedef enum {
+
86  USART_HardwareFlowControl_None = 0x0,
+
87  USART_HardwareFlowControl_RTS = 0x1,
+
88  USART_HardwareFlowControl_CTS = 0x2,
+
89  USART_HardwareFlowControl_CTS_RTS = 0x3
+
90 } UART_HwFlowCtrl;
+
91 
+
92 typedef enum {
+
93  UART_None_Inverse = 0x0,
+
94  UART_Rxd_Inverse = UART_RXD_INV,
+
95  UART_CTS_Inverse = UART_CTS_INV,
+
96  UART_Txd_Inverse = UART_TXD_INV,
+
97  UART_RTS_Inverse = UART_RTS_INV,
+
98 } UART_LineLevelInverse;
+
99 
+
100 typedef struct {
+
101  UART_BautRate baud_rate;
+
102  UART_WordLength data_bits;
+
103  UART_ParityMode parity; // chip size in byte
+
104  UART_StopBits stop_bits;
+
105  UART_HwFlowCtrl flow_ctrl;
+
106  uint8 UART_RxFlowThresh ;
+
107  uint32 UART_InverseMask;
+ +
109 
+
110 typedef struct {
+
111  uint32 UART_IntrEnMask;
+
112  uint8 UART_RX_TimeOutIntrThresh;
+
113  uint8 UART_TX_FifoEmptyIntrThresh;
+
114  uint8 UART_RX_FifoFullIntrThresh;
+ +
116 
+
117 //=======================================
+
118 
+
142 void UART_WaitTxFifoEmpty(UART_Port uart_no); //do not use if tx flow control enabled
+
143 
+
151 void UART_ResetFifo(UART_Port uart_no);
+
152 
+
161 void UART_ClearIntrStatus(UART_Port uart_no, uint32 clr_mask);
+
162 
+
171 void UART_SetIntrEna(UART_Port uart_no, uint32 ena_mask);
+
172 
+
181 void UART_intr_handler_register(void *fn, void *arg);
+
182 
+
190 void UART_SetPrintPort(UART_Port uart_no);
+
191 
+
200 void UART_ParamConfig(UART_Port uart_no, UART_ConfigTypeDef *pUARTConfig);
+
201 
+
210 void UART_IntrConfig(UART_Port uart_no, UART_IntrConfTypeDef *pUARTIntrConf);
+
211 
+
220 void UART_SetWordLength(UART_Port uart_no, UART_WordLength len);
+
221 
+
230 void UART_SetStopBits(UART_Port uart_no, UART_StopBits bit_num);
+
231 
+
240 void UART_SetParity(UART_Port uart_no, UART_ParityMode Parity_mode) ;
+
241 
+
250 void UART_SetBaudrate(UART_Port uart_no, uint32 baud_rate);
+
251 
+
261 void UART_SetFlowCtrl(UART_Port uart_no, UART_HwFlowCtrl flow_ctrl, uint8 rx_thresh);
+
262 
+
271 void UART_SetLineInverse(UART_Port uart_no, UART_LineLevelInverse inverse_mask) ;
+
272 
+
280 void uart_init_new(void);
+
281 
+
290 #ifdef __cplusplus
+
291 }
+
292 #endif
+
293 
+
294 #endif
+
void UART_ParamConfig(UART_Port uart_no, UART_ConfigTypeDef *pUARTConfig)
Config Common parameters of serial ports.
+
void UART_SetFlowCtrl(UART_Port uart_no, UART_HwFlowCtrl flow_ctrl, uint8 rx_thresh)
Configure Hardware flow control.
+
void UART_SetBaudrate(UART_Port uart_no, uint32 baud_rate)
Configure the Baud rate.
+
void uart_init_new(void)
An example illustrates how to configure the serial port.
+
void UART_SetIntrEna(UART_Port uart_no, uint32 ena_mask)
Enable uart interrupts .
+
Definition: uart.h:100
+
void UART_IntrConfig(UART_Port uart_no, UART_IntrConfTypeDef *pUARTIntrConf)
Config types of uarts.
+
Definition: uart.h:110
+
void UART_SetParity(UART_Port uart_no, UART_ParityMode Parity_mode)
Configure whether to open the parity.
+
void UART_ClearIntrStatus(UART_Port uart_no, uint32 clr_mask)
Clear uart interrupt flags.
+
void UART_SetLineInverse(UART_Port uart_no, UART_LineLevelInverse inverse_mask)
Configure trigging signal of uarts.
+
void UART_SetWordLength(UART_Port uart_no, UART_WordLength len)
Config the length of the uart communication data bits.
+
void UART_intr_handler_register(void *fn, void *arg)
Register an application-specific interrupt handler for Uarts interrupts.
+
void UART_WaitTxFifoEmpty(UART_Port uart_no)
Wait uart tx fifo empty, do not use it if tx flow control enabled.
+
void UART_SetStopBits(UART_Port uart_no, UART_StopBits bit_num)
Config the length of the uart communication stop bits.
+
void UART_SetPrintPort(UART_Port uart_no)
Config from which serial output printf function.
+
void UART_ResetFifo(UART_Port uart_no)
Clear uart tx fifo and rx fifo.
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/unionEvent__Info__u.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/unionEvent__Info__u.html new file mode 100644 index 0000000..8b0476c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/unionEvent__Info__u.html @@ -0,0 +1,228 @@ + + + + + + +ESP8266_RTOS_SDK: Event_Info_u Union Reference + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
Event_Info_u Union Reference
+
+
+ + + + + + + + + + + + + + + + + + +

+Data Fields

Event_StaMode_ScanDone_t scan_done
 
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
 
+

Field Documentation

+ +
+
+ + + + +
Event_SoftAPMode_ProbeReqRecved_t ap_probereqrecved
+
+

ESP8266 softAP receive probe request packet

+ +
+
+ +
+
+ + + + +
Event_StaMode_AuthMode_Change_t auth_change
+
+

the auth mode of AP ESP8266 station connected to changed

+ +
+
+ +
+
+ + + + +
Event_StaMode_Connected_t connected
+
+

ESP8266 station connected to AP

+ +
+
+ +
+
+ + + + +
Event_StaMode_Disconnected_t disconnected
+
+

ESP8266 station disconnected to AP

+ +
+
+ +
+
+ + + + +
Event_StaMode_Got_IP_t got_ip
+
+

ESP8266 station got IP

+ +
+
+ +
+
+ + + + +
Event_StaMode_ScanDone_t scan_done
+
+

ESP8266 station scan (APs) done

+ +
+
+ +
+
+ + + + +
Event_SoftAPMode_StaConnected_t sta_connected
+
+

a station connected to ESP8266 soft-AP

+ +
+
+ +
+
+ + + + +
Event_SoftAPMode_StaDisconnected_t sta_disconnected
+
+

a station disconnected to ESP8266 soft-AP

+ +
+
+
The documentation for this union was generated from the following file: +
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/documents/html/upgrade_8h_source.html b/Distrib/ESPressif/RTOS/1.5.0/documents/html/upgrade_8h_source.html new file mode 100644 index 0000000..507d2d1 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/documents/html/upgrade_8h_source.html @@ -0,0 +1,188 @@ + + + + + + +ESP8266_RTOS_SDK: include/espressif/upgrade.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
ESP8266_RTOS_SDK +  v1.4.0 +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
upgrade.h
+
+
+
1 /*
+
2  * ESPRSSIF MIT License
+
3  *
+
4  * Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+
5  *
+
6  * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+
7  * it is free of charge, to any person obtaining a copy of this software and associated
+
8  * documentation files (the "Software"), to deal in the Software without restriction, including
+
9  * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+
10  * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
+
11  * to do so, subject to the following conditions:
+
12  *
+
13  * The above copyright notice and this permission notice shall be included in all copies or
+
14  * substantial portions of the Software.
+
15  *
+
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
22  *
+
23  */
+
24 
+
25 #ifndef __UPGRADE_H__
+
26 #define __UPGRADE_H__
+
27 
+
28 #include "lwip/sockets.h"
+
29 
+
30 #ifdef __cplusplus
+
31 extern "C" {
+
32 #endif
+
33 
+
50 #define SPI_FLASH_SEC_SIZE 4096
+
52 #define USER_BIN1 0x00
+
53 #define USER_BIN2 0x01
+
55 #define UPGRADE_FLAG_IDLE 0x00
+
56 #define UPGRADE_FLAG_START 0x01
+
57 #define UPGRADE_FLAG_FINISH 0x02
+
59 #define UPGRADE_FW_BIN1 0x00
+
60 #define UPGRADE_FW_BIN2 0x01
+
69 typedef void (*upgrade_states_check_callback)(void *arg);
+
70 
+
71 //#define UPGRADE_SSL_ENABLE
+
72 
+ +
74  struct sockaddr_in sockaddrin;
+ +
76  uint32 check_times;
+
77  uint8 pre_version[16];
+
78  uint8 upgrade_version[16];
+
79  uint8 *url;
+
80  void *pclient_param;
+
81  uint8 upgrade_flag;
+
82 };
+
83 
+
91 void system_upgrade_init();
+
92 
+
100 void system_upgrade_deinit();
+
101 
+
110 bool system_upgrade(uint8 *data, uint32 len);
+
111 
+
112 #ifdef UPGRADE_SSL_ENABLE
+
113 
+
122 bool system_upgrade_start_ssl(struct upgrade_server_info *server);
+
123 #else
+
124 
+
134 bool system_upgrade_start(struct upgrade_server_info *server);
+
135 #endif
+
136 
+
145 #ifdef __cplusplus
+
146 }
+
147 #endif
+
148 
+
149 #endif
+
uint8 upgrade_flag
Definition: upgrade.h:81
+
uint32 check_times
Definition: upgrade.h:76
+
upgrade_states_check_callback check_cb
Definition: upgrade.h:75
+
uint8 pre_version[16]
Definition: upgrade.h:77
+
void system_upgrade_init()
Upgrade function initialization.
+
Definition: upgrade.h:73
+
uint8 upgrade_version[16]
Definition: upgrade.h:78
+
bool system_upgrade_start(struct upgrade_server_info *server)
Start upgrade firmware through WiFi with normal connection.
+
struct sockaddr_in sockaddrin
Definition: upgrade.h:74
+
uint8 * url
Definition: upgrade.h:79
+
bool system_upgrade(uint8 *data, uint32 len)
Upgrade function de-initialization.
+
void system_upgrade_deinit()
Upgrade function de-initialization.
+
void(* upgrade_states_check_callback)(void *arg)
Callback of upgrading firmware through WiFi.
Definition: upgrade.h:69
+
+ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/driver_lib/Makefile b/Distrib/ESPressif/RTOS/1.5.0/driver_lib/Makefile new file mode 100644 index 0000000..2b9c6a8 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/driver_lib/Makefile @@ -0,0 +1,124 @@ +############################################################# +# 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 = -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/Distrib/ESPressif/RTOS/1.5.0/driver_lib/README.md b/Distrib/ESPressif/RTOS/1.5.0/driver_lib/README.md new file mode 100644 index 0000000..c54b736 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/driver_lib/README.md @@ -0,0 +1,22 @@ +# driver_lib +## method 1 +Generate libdriver.a in SDK/lib, in driver_lib folder, run: + + ./make_lib.sh driver + +## method 2 +* STEP 1: + + Copy driver folder to your project sub-folder, such as app folder. Unused drivers can be removed in your project. + +* STEP 2: + + Modify Makefile in app folder. + + 1). Search SUBDIRS, add driver as subdir, such as: + + SUBDIRS = user driver + + 2). Search COMPONENTS_eagle.app.v6, add libdriver.a, such as: + + COMPONENTS_eagle.app.v6 = user/libuser.a driver/libdriver.a \ No newline at end of file diff --git a/Distrib/ESPressif/RTOS/1.5.0/driver_lib/driver/Makefile b/Distrib/ESPressif/RTOS/1.5.0/driver_lib/driver/Makefile new file mode 100644 index 0000000..5b8f77a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/driver_lib/driver/Makefile @@ -0,0 +1,43 @@ + +############################################################# +# 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 +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/Distrib/ESPressif/RTOS/1.5.0/driver_lib/driver/gpio.c b/Distrib/ESPressif/RTOS/1.5.0/driver_lib/driver/gpio.c new file mode 100644 index 0000000..e55f2a0 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/driver_lib/driver/gpio.c @@ -0,0 +1,213 @@ +/* + * ESPRSSIF 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 "espressif/esp_common.h" +#include "freertos/portmacro.h" + +#include "gpio.h" + +void gpio_config(GPIO_ConfigTypeDef *pGPIOConfig) +{ + uint16 gpio_pin_mask = pGPIOConfig->GPIO_Pin; + uint32 io_reg; + uint8 io_num = 0; + uint32 pin_reg; + + if (pGPIOConfig->GPIO_Mode == GPIO_Mode_Input) { + GPIO_AS_INPUT(gpio_pin_mask); + } else if (pGPIOConfig->GPIO_Mode == GPIO_Mode_Output) { + GPIO_AS_OUTPUT(gpio_pin_mask); + } + + do { + if ((gpio_pin_mask >> io_num) & 0x1) { + io_reg = GPIO_PIN_REG(io_num); + + if ((0x1 << io_num) & (GPIO_Pin_0 | GPIO_Pin_2 | GPIO_Pin_4 | GPIO_Pin_5)) { + PIN_FUNC_SELECT(io_reg, 0); + } else { + PIN_FUNC_SELECT(io_reg, 3); + } + + if (pGPIOConfig->GPIO_Pullup) { + PIN_PULLUP_EN(io_reg); + } else { + PIN_PULLUP_DIS(io_reg); + } + + if (pGPIOConfig->GPIO_Mode == GPIO_Mode_Out_OD) { + portENTER_CRITICAL(); + + pin_reg = GPIO_REG_READ(GPIO_PIN_ADDR(io_num)); + pin_reg &= (~GPIO_PIN_DRIVER_MASK); + pin_reg |= (GPIO_PAD_DRIVER_ENABLE << GPIO_PIN_DRIVER_LSB); + GPIO_REG_WRITE(GPIO_PIN_ADDR(io_num), pin_reg); + + portEXIT_CRITICAL(); + } else if (pGPIOConfig->GPIO_Mode == GPIO_Mode_Sigma_Delta) { + portENTER_CRITICAL(); + + pin_reg = GPIO_REG_READ(GPIO_PIN_ADDR(io_num)); + pin_reg &= (~GPIO_PIN_SOURCE_MASK); + pin_reg |= (0x1 << GPIO_PIN_SOURCE_LSB); + GPIO_REG_WRITE(GPIO_PIN_ADDR(io_num), pin_reg); + GPIO_REG_WRITE(GPIO_SIGMA_DELTA_ADDRESS, SIGMA_DELTA_ENABLE); + + portEXIT_CRITICAL(); + } + + gpio_pin_intr_state_set(io_num, pGPIOConfig->GPIO_IntrType); + } + + io_num++; + } while (io_num < 16); +} + +/* + * 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_conf(uint32 set_mask, uint32 clear_mask, uint32 enable_mask, uint32 disable_mask) +{ + GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, set_mask); + GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, clear_mask); + GPIO_REG_WRITE(GPIO_ENABLE_W1TS_ADDRESS, enable_mask); + GPIO_REG_WRITE(GPIO_ENABLE_W1TC_ADDRESS, disable_mask); +} + +/* + * Sample the value of GPIO input pins and returns a bitmask. + */ +uint32 gpio_input_get(void) +{ + return GPIO_REG_READ(GPIO_IN_ADDRESS); +} + +/* + * 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(void *fn, void *arg) +{ + _xt_isr_attach(ETS_GPIO_INUM, fn, arg); +} + +/* + only highlevel and lowlevel intr can use for wakeup +*/ +void gpio_pin_wakeup_enable(uint32 i, GPIO_INT_TYPE intr_state) +{ + uint32 pin_reg; + + if ((intr_state == GPIO_PIN_INTR_LOLEVEL) || (intr_state == GPIO_PIN_INTR_HILEVEL)) { + portENTER_CRITICAL(); + + pin_reg = GPIO_REG_READ(GPIO_PIN_ADDR(i)); + pin_reg &= (~GPIO_PIN_INT_TYPE_MASK); + pin_reg |= (intr_state << GPIO_PIN_INT_TYPE_LSB); + pin_reg |= GPIO_PIN_WAKEUP_ENABLE_SET(GPIO_WAKEUP_ENABLE); + GPIO_REG_WRITE(GPIO_PIN_ADDR(i), pin_reg); + + portEXIT_CRITICAL(); + } +} + +void gpio_pin_wakeup_disable(void) +{ + uint8 i; + uint32 pin_reg; + + for (i = 0; i < GPIO_PIN_COUNT; i++) { + pin_reg = GPIO_REG_READ(GPIO_PIN_ADDR(i)); + + if (pin_reg & GPIO_PIN_WAKEUP_ENABLE_MASK) { + pin_reg &= (~GPIO_PIN_INT_TYPE_MASK); + pin_reg |= (GPIO_PIN_INTR_DISABLE << GPIO_PIN_INT_TYPE_LSB); + pin_reg &= ~(GPIO_PIN_WAKEUP_ENABLE_SET(GPIO_WAKEUP_ENABLE)); + GPIO_REG_WRITE(GPIO_PIN_ADDR(i), pin_reg); + } + } +} + +void gpio_pin_intr_state_set(uint32 i, GPIO_INT_TYPE intr_state) +{ + uint32 pin_reg; + + portENTER_CRITICAL(); + + pin_reg = GPIO_REG_READ(GPIO_PIN_ADDR(i)); + pin_reg &= (~GPIO_PIN_INT_TYPE_MASK); + pin_reg |= (intr_state << GPIO_PIN_INT_TYPE_LSB); + GPIO_REG_WRITE(GPIO_PIN_ADDR(i), pin_reg); + + portEXIT_CRITICAL(); +} + +void 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 gpio16_output_set(uint8 value) +{ + WRITE_PERI_REG(RTC_GPIO_OUT, + (READ_PERI_REG(RTC_GPIO_OUT) & (uint32)0xfffffffe) | (uint32)(value & 1)); +} + +void 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 gpio16_input_get(void) +{ + return (uint8)(READ_PERI_REG(RTC_GPIO_IN_DATA) & 1); +} diff --git a/Distrib/ESPressif/RTOS/1.5.0/driver_lib/driver/hw_timer.c b/Distrib/ESPressif/RTOS/1.5.0/driver_lib/driver/hw_timer.c new file mode 100644 index 0000000..9193539 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/driver_lib/driver/hw_timer.c @@ -0,0 +1,116 @@ +/* + * ESPRSSIF 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 "esp_common.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 + +typedef enum { // timer provided mode + 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; + +#define RTC_REG_WRITE(addr, val) WRITE_PERI_REG(addr, val) + +static void (* user_hw_timer_cb)(void) = NULL; + +static void hw_timer_isr_cb(void *arg) +{ + if (user_hw_timer_cb != NULL) { + (*(user_hw_timer_cb))(); + } +} + +void hw_timer_arm(uint32 val) +{ + RTC_REG_WRITE(FRC1_LOAD_ADDRESS, US_TO_RTC_TIMER_TICKS(val)); +} + +void hw_timer_set_func(void (* user_hw_timer_cb_set)(void)) +{ + user_hw_timer_cb = user_hw_timer_cb_set; +} + +void hw_timer_init(uint8 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); + } + + _xt_isr_attach(ETS_FRC_TIMER1_INUM, hw_timer_isr_cb, NULL); + + TM1_EDGE_INT_ENABLE(); + _xt_isr_unmask(1 << ETS_FRC_TIMER1_INUM); +} + +//-------------------------------Test Code Below-------------------------------------- +#if 0 +#include "hw_timer.h" + +#define REG_WRITE(_r,_v) (*(volatile uint32 *)(_r)) = (_v) +#define REG_READ(_r) (*(volatile uint32 *)(_r)) +#define WDEV_NOW() REG_READ(0x3ff20c00) + +uint32 tick_now2 = 0; +void hw_test_timer_cb(void) +{ + static uint16 j = 0; + j++; + + if ((WDEV_NOW() - tick_now2) >= 1000000) { + static uint32 idx = 1; + tick_now2 = WDEV_NOW(); + os_printf("b%u:%d\n", idx++, j); + j = 0; + } + + //hw_timer_arm(50); +} + +void user_init(void) +{ + hw_timer_init(1); + hw_timer_set_func(hw_test_timer_cb); + hw_timer_arm(100); +} +#endif + diff --git a/Distrib/ESPressif/RTOS/1.5.0/driver_lib/driver/i2c_master.c b/Distrib/ESPressif/RTOS/1.5.0/driver_lib/driver/i2c_master.c new file mode 100644 index 0000000..b38aed5 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/driver_lib/driver/i2c_master.c @@ -0,0 +1,319 @@ +/****************************************************************************** + * Copyright 2013-2014 Espressif Systems (Wuxi) + * + * FileName: i2c_master.c + * + * Description: i2c master API + * + * Modification history: + * 2014/3/12, v1.0 create this file. +*******************************************************************************/ +#include "c_types.h" +#include "esp8266/ets_sys.h" +#include "gpio.h" + +#include "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; + ETS_INTR_LOCK(); + 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(); + } + ETS_INTR_UNLOCK(); +} + +/****************************************************************************** + * 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; + ETS_INTR_LOCK(); + sda_out = GPIO_INPUT_GET(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO)); + ETS_INTR_UNLOCK(); + 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/Distrib/ESPressif/RTOS/1.5.0/driver_lib/driver/spi_interface.c b/Distrib/ESPressif/RTOS/1.5.0/driver_lib/driver/spi_interface.c new file mode 100644 index 0000000..dabbabb --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/driver_lib/driver/spi_interface.c @@ -0,0 +1,509 @@ +/** + * spi_interface.c + * + * Defines and Macros for the SPI. + * + * Copyright @ 2015 Espressif System Co., Ltd. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are NOT permitted except as agreed by + * Espressif System Co., Ltd. + * + * 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. + */ +/** + * @file spi_interface.c + * @brief Defines and Macros for the SPI. + */ + +#include "spi_interface.h" +#include "esp8266/eagle_soc.h" +#include "esp8266/ets_sys.h" +#include "esp_libc.h" +//***************************************************************************** +// +// Make sure all of the definitions in this header have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" +{ +#endif + +// Show the spi registers. +#define SHOWDEBUG + +void __ShowRegValue(const char * func, uint32_t line) +{ +#ifndef SHOWDEBUG + int i; + uint32_t regAddr = 0x60000140; // SPI--0x60000240, HSPI--0x60000140; + printf("\r\n FUNC[%s],line[%d]\r\n", func, line); + printf(" SPI_ADDR [0x%08x]\r\n", READ_PERI_REG(SPI_ADDR(SpiNum_HSPI))); + printf(" SPI_CMD [0x%08x]\r\n", READ_PERI_REG(SPI_CMD(SpiNum_HSPI))); + printf(" SPI_CTRL [0x%08x]\r\n", READ_PERI_REG(SPI_CTRL(SpiNum_HSPI))); + printf(" SPI_CTRL2 [0x%08x]\r\n", READ_PERI_REG(SPI_CTRL2(SpiNum_HSPI))); + printf(" SPI_CLOCK [0x%08x]\r\n", READ_PERI_REG(SPI_CLOCK(SpiNum_HSPI))); + printf(" SPI_RD_STATUS [0x%08x]\r\n", READ_PERI_REG(SPI_RD_STATUS(SpiNum_HSPI))); + printf(" SPI_WR_STATUS [0x%08x]\r\n", READ_PERI_REG(SPI_WR_STATUS(SpiNum_HSPI))); + printf(" SPI_USER [0x%08x]\r\n", READ_PERI_REG(SPI_USER(SpiNum_HSPI))); + printf(" SPI_USER1 [0x%08x]\r\n", READ_PERI_REG(SPI_USER1(SpiNum_HSPI))); + printf(" SPI_USER2 [0x%08x]\r\n", READ_PERI_REG(SPI_USER2(SpiNum_HSPI))); + printf(" SPI_PIN [0x%08x]\r\n", READ_PERI_REG(SPI_PIN(SpiNum_HSPI))); + printf(" SPI_SLAVE [0x%08x]\r\n", READ_PERI_REG(SPI_SLAVE(SpiNum_HSPI))); + printf(" SPI_SLAVE1 [0x%08x]\r\n", READ_PERI_REG(SPI_SLAVE1(SpiNum_HSPI))); + printf(" SPI_SLAVE2 [0x%08x]\r\n", READ_PERI_REG(SPI_SLAVE2(SpiNum_HSPI))); + + for (i = 0; i < 16; ++i) { + printf(" ADDR[0x%08x],Value[0x%08x]\r\n", regAddr, READ_PERI_REG(regAddr)); + regAddr += 4; + } +#endif +} + +// Define SPI interrupt enable macro +#define ETS_SPI_INTR_ENABLE() _xt_isr_unmask(1 << ETS_SPI_INUM) + +/** + * @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)) { + CLEAR_PERI_REG_MASK(SPI_CLOCK(spiNum), SPI_CLK_EQU_SYSCLK); + WRITE_PERI_REG(SPI_CLOCK(spiNum), + ((pAttr->speed & SPI_CLKCNT_N) << SPI_CLKCNT_N_S) | + ((((pAttr->speed + 1) / 2 - 1) & SPI_CLKCNT_H) << SPI_CLKCNT_H_S) | + ((pAttr->speed & 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); +} + +/** + * @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)); + // 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); + + SHOWREG(); + 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 { + *pOutData->data++ = READ_PERI_REG(SPI_W0(spiNum) + (idx << 2)); + } while (++idx < (pOutData->dataLen / 4)); + + SHOWREG(); + return 0; +} + +/** + * @brief Load data to send buffer by slave mode. + * + */ +int ICACHE_FLASH_ATTR SPISlaveSendData(SpiNum spiNum, uint32_t *pInData, uint8_t outLen) +{ + if (NULL == pInData) { + return -1; + } + char i; + for (i = 0; i < outLen; ++i) { + WRITE_PERI_REG((SPI_W8(spiNum) + (i << 2)), *pInData++); + } + return 0; +} + +/** + * @brief Configurate slave prepare for receive data. + * + */ +int ICACHE_FLASH_ATTR SPISlaveRecvData(SpiNum spiNum, void(*isrFunc)(void*)) +{ + if ((spiNum > SpiNum_HSPI)) { + return -1; + } + + SPIIntEnable(SpiNum_HSPI, SpiIntSrc_WrStaDoneEn + | SpiIntSrc_RdStaDoneEn | SpiIntSrc_WrBufDoneEn | SpiIntSrc_RdBufDoneEn); + SPIIntDisable(SpiNum_HSPI, SpiIntSrc_TransDoneEn); + + // Maybe enable slave transmission liston + SET_PERI_REG_MASK(SPI_CMD(spiNum), SPI_USR); + // + _xt_isr_attach(ETS_SPI_INUM, isrFunc, NULL); + // ETS_SPI_INTR_ATTACH(isrFunc, NULL); + // Enable isr + ETS_SPI_INTR_ENABLE(); + + + SHOWREG(); + + 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); + + SHOWREG(); +} + +/** + * @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); + SHOWREG(); + + 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); +} + +/** + * @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); +} + +/** + * @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_TransDoneEn + | SpiIntSrc_WrStaDoneEn + | SpiIntSrc_RdStaDoneEn + | SpiIntSrc_WrBufDoneEn + | SpiIntSrc_RdBufDoneEn); +} + + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/Distrib/ESPressif/RTOS/1.5.0/driver_lib/driver/uart.c b/Distrib/ESPressif/RTOS/1.5.0/driver_lib/driver/uart.c new file mode 100644 index 0000000..80314fa --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/driver_lib/driver/uart.c @@ -0,0 +1,435 @@ +/* + * ESPRSSIF 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 "esp_common.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" + +#include "uart.h" + +enum { + UART_EVENT_RX_CHAR, + UART_EVENT_MAX +}; + +typedef struct _os_event_ { + uint32 event; + uint32 param; +} os_event_t; + +xTaskHandle xUartTaskHandle; +xQueueHandle xQueueUart; + +LOCAL STATUS +uart_tx_one_char(uint8 uart, uint8 TxChar) +{ + while (true) { + uint32 fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT << UART_TXFIFO_CNT_S); + + if ((fifo_cnt >> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) < 126) { + break; + } + } + + WRITE_PERI_REG(UART_FIFO(uart) , TxChar); + return OK; +} + +LOCAL void +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); + } +} + +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); + } +} + +LOCAL void +uart_rx_intr_handler_ssc(void *arg) +{ + /* uart0 and uart1 intr combine togther, when interrupt occur, see reg 0x3ff20020, bit2, bit0 represents + * uart1 and uart0 respectively + */ + os_event_t e; + portBASE_TYPE xHigherPriorityTaskWoken; + + uint8 RcvChar; + uint8 uart_no = 0; + + if (UART_RXFIFO_FULL_INT_ST != (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST)) { + return; + } + + RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xFF; + + WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_RXFIFO_FULL_INT_CLR); + + e.event = UART_EVENT_RX_CHAR; + e.param = RcvChar; + + xQueueSendFromISR(xQueueUart, (void *)&e, &xHigherPriorityTaskWoken); + portEND_SWITCHING_ISR(xHigherPriorityTaskWoken); +} + +#if 0 +LOCAL void +uart_config(uint8 uart_no, UartDevice *uart) +{ + if (uart_no == UART1) { + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK); + } else { + /* rcv_buff size if 0x100 */ + _xt_isr_attach(ETS_UART_INUM, uart_rx_intr_handler_ssc, NULL); + PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD); + } + + uart_div_modify(uart_no, UART_CLK_FREQ / (uart->baut_rate)); + + WRITE_PERI_REG(UART_CONF0(uart_no), uart->exist_parity + | uart->parity + | (uart->stop_bits << UART_STOP_BIT_NUM_S) + | (uart->data_bits << UART_BIT_NUM_S)); + + //clear rx and tx fifo,not ready + 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); + + if (uart_no == UART0) { + //set rx fifo trigger + WRITE_PERI_REG(UART_CONF1(uart_no), + ((0x01 & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S)); + } else { + WRITE_PERI_REG(UART_CONF1(uart_no), + ((0x01 & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S)); + } + + //clear all interrupt + WRITE_PERI_REG(UART_INT_CLR(uart_no), 0xffff); + //enable rx_interrupt + SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA); +} +#endif + +LOCAL void +uart_task(void *pvParameters) +{ + os_event_t e; + + for (;;) { + if (xQueueReceive(xQueueUart, (void *)&e, (portTickType)portMAX_DELAY)) { + switch (e.event) { + case UART_EVENT_RX_CHAR: + printf("%c", e.param); + break; + + default: + break; + } + } + } + + vTaskDelete(NULL); +} + +#if 0 +void +uart_init(void) +{ + while (READ_PERI_REG(UART_STATUS(0)) & (UART_TXFIFO_CNT << UART_TXFIFO_CNT_S)); + + while (READ_PERI_REG(UART_STATUS(1)) & (UART_TXFIFO_CNT << UART_TXFIFO_CNT_S)); + + UART_ConfigTypeDef uart; + + uart.baut_rate = BIT_RATE_74880; + uart.data_bits = UART_WordLength_8b; + uart.flow_ctrl = USART_HardwareFlowControl_None; + // uart.exist_parity = PARITY_DIS; + uart.parity = USART_Parity_None; + uart.stop_bits = USART_StopBits_1; + + uart_config(UART0, &uart); + uart_config(UART1, &uart); + + os_install_putc1(uart1_write_char); + + _xt_isr_unmask(1 << ETS_UART_INUM); + + xQueueUart = xQueueCreate(32, sizeof(os_event_t)); + + xTaskCreate(uart_task, (uint8 const *)"uTask", 512, NULL, tskIDLE_PRIORITY + 2, &xUartTaskHandle); +} +#endif + +//================================================================= + +void +UART_SetWordLength(UART_Port uart_no, UART_WordLength len) +{ + SET_PERI_REG_BITS(UART_CONF0(uart_no), UART_BIT_NUM, len, UART_BIT_NUM_S); +} + +void +UART_SetStopBits(UART_Port uart_no, UART_StopBits bit_num) +{ + SET_PERI_REG_BITS(UART_CONF0(uart_no), UART_STOP_BIT_NUM, bit_num, UART_STOP_BIT_NUM_S); +} + +void +UART_SetLineInverse(UART_Port 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 +UART_SetParity(UART_Port uart_no, UART_ParityMode Parity_mode) +{ + CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_PARITY | UART_PARITY_EN); + + if (Parity_mode == USART_Parity_None) { + } else { + SET_PERI_REG_MASK(UART_CONF0(uart_no), Parity_mode | UART_PARITY_EN); + } +} + +void +UART_SetBaudrate(UART_Port uart_no, uint32 baud_rate) +{ + uart_div_modify(uart_no, UART_CLK_FREQ / baud_rate); +} + +//only when USART_HardwareFlowControl_RTS is set , will the rx_thresh value be set. +void +UART_SetFlowCtrl(UART_Port 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 +UART_WaitTxFifoEmpty(UART_Port uart_no) //do not use if tx flow control enabled +{ + while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_TXFIFO_CNT << UART_TXFIFO_CNT_S)); +} + +void +UART_ResetFifo(UART_Port 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 +UART_ClearIntrStatus(UART_Port uart_no, uint32 clr_mask) +{ + WRITE_PERI_REG(UART_INT_CLR(uart_no), clr_mask); +} + +void +UART_SetIntrEna(UART_Port uart_no, uint32 ena_mask) +{ + SET_PERI_REG_MASK(UART_INT_ENA(uart_no), ena_mask); +} + +void +UART_intr_handler_register(void *fn, void *arg) +{ + _xt_isr_attach(ETS_UART_INUM, fn, arg); +} + +void +UART_SetPrintPort(UART_Port uart_no) +{ + if (uart_no == 1) { + os_install_putc1(uart1_write_char); + } else { + os_install_putc1(uart0_write_char); + } +} + +void +UART_ParamConfig(UART_Port uart_no, UART_ConfigTypeDef *pUARTConfig) +{ + if (uart_no == UART1) { + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK); + } else { + PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD); + } + + UART_SetFlowCtrl(uart_no, pUARTConfig->flow_ctrl, pUARTConfig->UART_RxFlowThresh); + UART_SetBaudrate(uart_no, pUARTConfig->baud_rate); + + WRITE_PERI_REG(UART_CONF0(uart_no), + ((pUARTConfig->parity == USART_Parity_None) ? 0x0 : (UART_PARITY_EN | pUARTConfig->parity)) + | (pUARTConfig->stop_bits << UART_STOP_BIT_NUM_S) + | (pUARTConfig->data_bits << UART_BIT_NUM_S) + | ((pUARTConfig->flow_ctrl & USART_HardwareFlowControl_CTS) ? UART_TX_FLOW_EN : 0x0) + | pUARTConfig->UART_InverseMask); + + UART_ResetFifo(uart_no); +} + +void +UART_IntrConfig(UART_Port uart_no, UART_IntrConfTypeDef *pUARTIntrConf) +{ + + uint32 reg_val = 0; + UART_ClearIntrStatus(uart_no, UART_INTR_MASK); + reg_val = READ_PERI_REG(UART_CONF1(uart_no)) & ~((UART_RX_FLOW_THRHD << UART_RX_FLOW_THRHD_S) | UART_RX_FLOW_EN) ; + + reg_val |= ((pUARTIntrConf->UART_IntrEnMask & UART_RXFIFO_TOUT_INT_ENA) ? + ((((pUARTIntrConf->UART_RX_TimeOutIntrThresh)&UART_RX_TOUT_THRHD) << UART_RX_TOUT_THRHD_S) | UART_RX_TOUT_EN) : 0); + + reg_val |= ((pUARTIntrConf->UART_IntrEnMask & UART_RXFIFO_FULL_INT_ENA) ? + (((pUARTIntrConf->UART_RX_FifoFullIntrThresh)&UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) : 0); + + reg_val |= ((pUARTIntrConf->UART_IntrEnMask & UART_TXFIFO_EMPTY_INT_ENA) ? + (((pUARTIntrConf->UART_TX_FifoEmptyIntrThresh)&UART_TXFIFO_EMPTY_THRHD) << UART_TXFIFO_EMPTY_THRHD_S) : 0); + + WRITE_PERI_REG(UART_CONF1(uart_no), reg_val); + CLEAR_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_INTR_MASK); + SET_PERI_REG_MASK(UART_INT_ENA(uart_no), pUARTIntrConf->UART_IntrEnMask); +} + +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 fifo_tmp[128] = {0}; + + uint32 uart_intr_status = READ_PERI_REG(UART_INT_ST(uart_no)) ; + + while (uart_intr_status != 0x0) { + if (UART_FRM_ERR_INT_ST == (uart_intr_status & UART_FRM_ERR_INT_ST)) { + //printf("FRM_ERR\r\n"); + WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_FRM_ERR_INT_CLR); + } else if (UART_RXFIFO_FULL_INT_ST == (uart_intr_status & UART_RXFIFO_FULL_INT_ST)) { + printf("full\r\n"); + fifo_len = (READ_PERI_REG(UART_STATUS(UART0)) >> UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT; + buf_idx = 0; + + while (buf_idx < fifo_len) { + uart_tx_one_char(UART0, READ_PERI_REG(UART_FIFO(UART0)) & 0xFF); + buf_idx++; + } + + WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_FULL_INT_CLR); + } else if (UART_RXFIFO_TOUT_INT_ST == (uart_intr_status & UART_RXFIFO_TOUT_INT_ST)) { + printf("tout\r\n"); + fifo_len = (READ_PERI_REG(UART_STATUS(UART0)) >> UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT; + buf_idx = 0; + + while (buf_idx < fifo_len) { + uart_tx_one_char(UART0, READ_PERI_REG(UART_FIFO(UART0)) & 0xFF); + buf_idx++; + } + + WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_TOUT_INT_CLR); + } else if (UART_TXFIFO_EMPTY_INT_ST == (uart_intr_status & UART_TXFIFO_EMPTY_INT_ST)) { + printf("empty\n\r"); + WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_TXFIFO_EMPTY_INT_CLR); + CLEAR_PERI_REG_MASK(UART_INT_ENA(UART0), UART_TXFIFO_EMPTY_INT_ENA); + } else { + //skip + } + + uart_intr_status = READ_PERI_REG(UART_INT_ST(uart_no)) ; + } +} + +void +uart_init_new(void) +{ + UART_WaitTxFifoEmpty(UART0); + UART_WaitTxFifoEmpty(UART1); + + UART_ConfigTypeDef uart_config; + uart_config.baud_rate = BIT_RATE_74880; + uart_config.data_bits = UART_WordLength_8b; + uart_config.parity = USART_Parity_None; + uart_config.stop_bits = USART_StopBits_1; + uart_config.flow_ctrl = USART_HardwareFlowControl_None; + uart_config.UART_RxFlowThresh = 120; + uart_config.UART_InverseMask = UART_None_Inverse; + UART_ParamConfig(UART0, &uart_config); + + UART_IntrConfTypeDef uart_intr; + uart_intr.UART_IntrEnMask = UART_RXFIFO_TOUT_INT_ENA | UART_FRM_ERR_INT_ENA | UART_RXFIFO_FULL_INT_ENA | UART_TXFIFO_EMPTY_INT_ENA; + uart_intr.UART_RX_FifoFullIntrThresh = 10; + uart_intr.UART_RX_TimeOutIntrThresh = 2; + uart_intr.UART_TX_FifoEmptyIntrThresh = 20; + UART_IntrConfig(UART0, &uart_intr); + + UART_SetPrintPort(UART0); + UART_intr_handler_register(uart0_rx_intr_handler, NULL); + ETS_UART_INTR_ENABLE(); + + /* + UART_SetWordLength(UART0,UART_WordLength_8b); + UART_SetStopBits(UART0,USART_StopBits_1); + UART_SetParity(UART0,USART_Parity_None); + UART_SetBaudrate(UART0,74880); + UART_SetFlowCtrl(UART0,USART_HardwareFlowControl_None,0); + */ + +} diff --git a/Distrib/ESPressif/RTOS/1.5.0/driver_lib/include/gpio.h b/Distrib/ESPressif/RTOS/1.5.0/driver_lib/include/gpio.h new file mode 100644 index 0000000..1be6c53 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/driver_lib/include/gpio.h @@ -0,0 +1,307 @@ +/* + * ESPRSSIF 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 __GPIO_H__ +#define __GPIO_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define GPIO_Pin_0 (BIT(0)) /* Pin 0 selected */ +#define GPIO_Pin_1 (BIT(1)) /* Pin 1 selected */ +#define GPIO_Pin_2 (BIT(2)) /* Pin 2 selected */ +#define GPIO_Pin_3 (BIT(3)) /* Pin 3 selected */ +#define GPIO_Pin_4 (BIT(4)) /* Pin 4 selected */ +#define GPIO_Pin_5 (BIT(5)) /* Pin 5 selected */ +#define GPIO_Pin_6 (BIT(6)) /* Pin 6 selected */ +#define GPIO_Pin_7 (BIT(7)) /* Pin 7 selected */ +#define GPIO_Pin_8 (BIT(8)) /* Pin 8 selected */ +#define GPIO_Pin_9 (BIT(9)) /* Pin 9 selected */ +#define GPIO_Pin_10 (BIT(10)) /* Pin 10 selected */ +#define GPIO_Pin_11 (BIT(11)) /* Pin 11 selected */ +#define GPIO_Pin_12 (BIT(12)) /* Pin 12 selected */ +#define GPIO_Pin_13 (BIT(13)) /* Pin 13 selected */ +#define GPIO_Pin_14 (BIT(14)) /* Pin 14 selected */ +#define GPIO_Pin_15 (BIT(15)) /* Pin 15 selected */ +#define GPIO_Pin_All (0xFFFF) /* All pins selected */ + +#define GPIO_PIN_REG_0 PERIPHS_IO_MUX_GPIO0_U +#define GPIO_PIN_REG_1 PERIPHS_IO_MUX_U0TXD_U +#define GPIO_PIN_REG_2 PERIPHS_IO_MUX_GPIO2_U +#define GPIO_PIN_REG_3 PERIPHS_IO_MUX_U0RXD_U +#define GPIO_PIN_REG_4 PERIPHS_IO_MUX_GPIO4_U +#define GPIO_PIN_REG_5 PERIPHS_IO_MUX_GPIO5_U +#define GPIO_PIN_REG_6 PERIPHS_IO_MUX_SD_CLK_U +#define GPIO_PIN_REG_7 PERIPHS_IO_MUX_SD_DATA0_U +#define GPIO_PIN_REG_8 PERIPHS_IO_MUX_SD_DATA1_U +#define GPIO_PIN_REG_9 PERIPHS_IO_MUX_SD_DATA2_U +#define GPIO_PIN_REG_10 PERIPHS_IO_MUX_SD_DATA3_U +#define GPIO_PIN_REG_11 PERIPHS_IO_MUX_SD_CMD_U +#define GPIO_PIN_REG_12 PERIPHS_IO_MUX_MTDI_U +#define GPIO_PIN_REG_13 PERIPHS_IO_MUX_MTCK_U +#define GPIO_PIN_REG_14 PERIPHS_IO_MUX_MTMS_U +#define GPIO_PIN_REG_15 PERIPHS_IO_MUX_MTDO_U + +#define GPIO_PIN_REG(i) \ + (i==0) ? GPIO_PIN_REG_0: \ + (i==1) ? GPIO_PIN_REG_1: \ + (i==2) ? GPIO_PIN_REG_2: \ + (i==3) ? GPIO_PIN_REG_3: \ + (i==4) ? GPIO_PIN_REG_4: \ + (i==5) ? GPIO_PIN_REG_5: \ + (i==6) ? GPIO_PIN_REG_6: \ + (i==7) ? GPIO_PIN_REG_7: \ + (i==8) ? GPIO_PIN_REG_8: \ + (i==9) ? GPIO_PIN_REG_9: \ + (i==10)? GPIO_PIN_REG_10: \ + (i==11)? GPIO_PIN_REG_11: \ + (i==12)? GPIO_PIN_REG_12: \ + (i==13)? GPIO_PIN_REG_13: \ + (i==14)? GPIO_PIN_REG_14: \ + GPIO_PIN_REG_15 + +#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, /**< disable GPIO interrupt */ + GPIO_PIN_INTR_POSEDGE = 1, /**< GPIO interrupt type : rising edge */ + GPIO_PIN_INTR_NEGEDGE = 2, /**< GPIO interrupt type : falling edge */ + GPIO_PIN_INTR_ANYEDGE = 3, /**< GPIO interrupt type : bothe rising and falling edge */ + GPIO_PIN_INTR_LOLEVEL = 4, /**< GPIO interrupt type : low level */ + GPIO_PIN_INTR_HILEVEL = 5 /**< GPIO interrupt type : high level */ +} GPIO_INT_TYPE; + +typedef enum { + GPIO_Mode_Input = 0x0, /**< GPIO mode : Input */ + GPIO_Mode_Out_OD, /**< GPIO mode : Output_OD */ + GPIO_Mode_Output , /**< GPIO mode : Output */ + GPIO_Mode_Sigma_Delta , /**< GPIO mode : Sigma_Delta */ +} GPIOMode_TypeDef; + +typedef enum { + GPIO_PullUp_DIS = 0x0, /**< disable GPIO pullup */ + GPIO_PullUp_EN = 0x1, /**< enable GPIO pullup */ +} GPIO_Pullup_IF; + +typedef struct { + uint16 GPIO_Pin; /**< GPIO pin */ + GPIOMode_TypeDef GPIO_Mode; /**< GPIO mode */ + GPIO_Pullup_IF GPIO_Pullup; /**< GPIO pullup */ + GPIO_INT_TYPE GPIO_IntrType; /**< GPIO interrupt type */ +} GPIO_ConfigTypeDef; + +/** \defgroup Driver_APIs Driver APIs + * @brief Driver APIs + */ + +/** @addtogroup Driver_APIs + * @{ + */ + +/** \defgroup GPIO_Driver_APIs GPIO Driver APIs + * @brief GPIO APIs + */ + +/** @addtogroup GPIO_Driver_APIs + * @{ + */ + +/** + * @brief Set GPIO pin output level. + * + * @param gpio_no : The GPIO sequence number. + * @param bit_value : GPIO pin output level. + * + * @return null + */ +#define GPIO_OUTPUT_SET(gpio_no, bit_value) \ + gpio_output_conf(bit_value<>gpio_no)&BIT0) + +/** + * @brief Enable GPIO16 output. + * + * @param null + * + * @return null + */ +void gpio16_output_conf(void); + +/** + * @brief Set GPIO16 output level. + * + * @param uint8 value : GPIO16 output level. + * + * @return null + */ +void gpio16_output_set(uint8 value); + +/** + * @brief Enable GPIO pin intput. + * + * @param null + * + * @return null + */ +void gpio16_input_conf(void); + +/** + * @brief Sample the value of GPIO16 input. + * + * @param null + * + * @return the level of GPIO16 input. + */ +uint8 gpio16_input_get(void); + +/** + * @brief Configure Gpio pins out or input. + * + * @param uint32 set_mask : Set the output for the high bit, the + * corresponding bit is 1, the output of high, + * the corresponding bit is 0, do not change the state. + * @param uint32 set_mask : Set the output for the high bit, the + * corresponding bit is 1, the output of low, + * the corresponding bit is 0, do not change the state. + * @param uint32 enable_mask : Enable Output + * @param uint32 disable_mask : Enable Input + * + * @return null + */ +void gpio_output_conf(uint32 set_mask, uint32 clear_mask, uint32 enable_mask, uint32 disable_mask); + +/** + * @brief Register an application-specific interrupt handler for GPIO pin interrupts. + * + * @param void *fn:interrupt handler for GPIO pin interrupts. + * @param void *arg:interrupt handler's arg + * + * @return null + */ +void gpio_intr_handler_register(void *fn, void *arg); + +/** + * @brief Configure GPIO wake up to light sleep,Only level way is effective. + * + * @param uint32 i : Gpio sequence number + * @param GPIO_INT_TYPE intr_state : the level of wake up to light sleep + * + * @return null + */ +void gpio_pin_wakeup_enable(uint32 i, GPIO_INT_TYPE intr_state); + +/** + * @brief Disable GPIO wake up to light sleep. + * + * @param null + * + * @return null + */ +void gpio_pin_wakeup_disable(); + +/** + * @brief Config interrupt types of GPIO pin. + * + * @param uint32 i : The GPIO sequence number. + * @param GPIO_INT_TYPE intr_state : GPIO interrupt types. + * + * @return null + */ +void gpio_pin_intr_state_set(uint32 i, GPIO_INT_TYPE intr_state); + +/** + * @brief Sample the value of GPIO input pins and returns a bitmask. + * + * @param null + * + * @return bitmask of GPIO pins input + */ +uint32 gpio_input_get(void); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/driver_lib/include/hw_timer.h b/Distrib/ESPressif/RTOS/1.5.0/driver_lib/include/hw_timer.h new file mode 100644 index 0000000..e5f0564 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/driver_lib/include/hw_timer.h @@ -0,0 +1,85 @@ +/* + * ESPRSSIF 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 __HW_TIMER_H__ +#define __HW_TIMER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup HW_Timer_APIs Hardware timer APIs + * @brief Hardware timer APIs + * + * @attention Hardware timer can not interrupt other ISRs. + * + */ + +/** @addtogroup HW_Timer_APIs + * @{ + */ + + +/** + * @brief Initialize the hardware ISR timer. + * + * @param uint8 req : 0, not autoload; 1, autoload mode. + * + * @return null + */ +void hw_timer_init(uint8 req); + +/** + * @brief Set a trigger timer delay to enable this timer. + * + * @param uint32 val : Timing + * - In autoload mode, range : 50 ~ 0x7fffff + * - In non-autoload mode, range : 10 ~ 0x7fffff + * + * @return null + */ +void hw_timer_arm(uint32 val); + +/** + * @brief Set timer callback function. + * + * For enabled timer, timer callback has to be set. + * + * @param uint32 val : Timing + * - In autoload mode, range : 50 ~ 0x7fffff + * - In non-autoload mode, range : 10 ~ 0x7fffff + * + * @return null + */ +void hw_timer_set_func(void (* user_hw_timer_cb_set)(void)); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/driver_lib/include/i2c_master.h b/Distrib/ESPressif/RTOS/1.5.0/driver_lib/include/i2c_master.h new file mode 100644 index 0000000..e83b4f1 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/driver_lib/include/i2c_master.h @@ -0,0 +1,169 @@ +#ifndef __I2C_MASTER_H__ +#define __I2C_MASTER_H__ + +#include "esp8266/pin_mux_register.h" +#define I2C_MASTER_SDA_MUX PERIPHS_IO_MUX_GPIO2_U +#define I2C_MASTER_SCL_MUX PERIPHS_IO_MUX_GPIO4_U +#define I2C_MASTER_SDA_GPIO 2 +#define I2C_MASTER_SCL_GPIO 4 +#define I2C_MASTER_SDA_FUNC FUNC_GPIO2 +#define I2C_MASTER_SCL_FUNC FUNC_GPIO4 + +//#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 __UART_H__ +#define __UART_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define ETS_UART_INTR_ENABLE() _xt_isr_unmask(1 << ETS_UART_INUM) +#define ETS_UART_INTR_DISABLE() _xt_isr_mask(1 << ETS_UART_INUM) +#define UART_INTR_MASK 0x1ff +#define UART_LINE_INV_MASK (0x3f<<19) + +typedef enum { + UART_WordLength_5b = 0x0, + UART_WordLength_6b = 0x1, + UART_WordLength_7b = 0x2, + UART_WordLength_8b = 0x3 +} UART_WordLength; + +typedef enum { + USART_StopBits_1 = 0x1, + USART_StopBits_1_5 = 0x2, + USART_StopBits_2 = 0x3, +} UART_StopBits; + +typedef enum { + UART0 = 0x0, + UART1 = 0x1, +} UART_Port; + +typedef enum { + USART_Parity_None = 0x2, + USART_Parity_Even = 0x0, + USART_Parity_Odd = 0x1 +} UART_ParityMode; + +typedef enum { + PARITY_DIS = 0x0, + PARITY_EN = 0x2 +} UartExistParity; + +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, +} UART_BautRate; //you can add any rate you need in this range + +typedef enum { + USART_HardwareFlowControl_None = 0x0, + USART_HardwareFlowControl_RTS = 0x1, + USART_HardwareFlowControl_CTS = 0x2, + USART_HardwareFlowControl_CTS_RTS = 0x3 +} UART_HwFlowCtrl; + +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 struct { + UART_BautRate baud_rate; + UART_WordLength data_bits; + UART_ParityMode parity; // chip size in byte + UART_StopBits stop_bits; + UART_HwFlowCtrl flow_ctrl; + uint8 UART_RxFlowThresh ; + uint32 UART_InverseMask; +} UART_ConfigTypeDef; + +typedef struct { + uint32 UART_IntrEnMask; + uint8 UART_RX_TimeOutIntrThresh; + uint8 UART_TX_FifoEmptyIntrThresh; + uint8 UART_RX_FifoFullIntrThresh; +} UART_IntrConfTypeDef; + +//======================================= + +/** \defgroup Driver_APIs Driver APIs + * @brief Driver APIs + */ + +/** @addtogroup Driver_APIs + * @{ + */ + +/** \defgroup UART_Driver_APIs UART Driver APIs + * @brief UART driver APIs + */ + +/** @addtogroup UART_Driver_APIs + * @{ + */ + +/** + * @brief Wait uart tx fifo empty, do not use it if tx flow control enabled. + * + * @param UART_Port uart_no:UART0 or UART1 + * + * @return null + */ +void UART_WaitTxFifoEmpty(UART_Port uart_no); //do not use if tx flow control enabled + +/** + * @brief Clear uart tx fifo and rx fifo. + * + * @param UART_Port uart_no : UART0 or UART1 + * + * @return null + */ +void UART_ResetFifo(UART_Port uart_no); + +/** + * @brief Clear uart interrupt flags. + * + * @param UART_Port uart_no : UART0 or UART1 + * @param uint32 clr_mask : To clear the interrupt bits + * + * @return null + */ +void UART_ClearIntrStatus(UART_Port uart_no, uint32 clr_mask); + +/** + * @brief Enable uart interrupts . + * + * @param UART_Port uart_no : UART0 or UART1 + * @param uint32 ena_mask : To enable the interrupt bits + * + * @return null + */ +void UART_SetIntrEna(UART_Port uart_no, uint32 ena_mask); + +/** + * @brief Register an application-specific interrupt handler for Uarts interrupts. + * + * @param void *fn : interrupt handler for Uart interrupts. + * @param void *arg : interrupt handler's arg. + * + * @return null + */ +void UART_intr_handler_register(void *fn, void *arg); + +/** + * @brief Config from which serial output printf function. + * + * @param UART_Port uart_no : UART0 or UART1 + * + * @return null + */ +void UART_SetPrintPort(UART_Port uart_no); + +/** + * @brief Config Common parameters of serial ports. + * + * @param UART_Port uart_no : UART0 or UART1 + * @param UART_ConfigTypeDef *pUARTConfig : parameters structure + * + * @return null + */ +void UART_ParamConfig(UART_Port uart_no, UART_ConfigTypeDef *pUARTConfig); + +/** + * @brief Config types of uarts. + * + * @param UART_Port uart_no : UART0 or UART1 + * @param UART_IntrConfTypeDef *pUARTIntrConf : parameters structure + * + * @return null + */ +void UART_IntrConfig(UART_Port uart_no, UART_IntrConfTypeDef *pUARTIntrConf); + +/** + * @brief Config the length of the uart communication data bits. + * + * @param UART_Port uart_no : UART0 or UART1 + * @param UART_WordLength len : the length of the uart communication data bits + * + * @return null + */ +void UART_SetWordLength(UART_Port uart_no, UART_WordLength len); + +/** + * @brief Config the length of the uart communication stop bits. + * + * @param UART_Port uart_no : UART0 or UART1 + * @param UART_StopBits bit_num : the length uart communication stop bits + * + * @return null + */ +void UART_SetStopBits(UART_Port uart_no, UART_StopBits bit_num); + +/** + * @brief Configure whether to open the parity. + * + * @param UART_Port uart_no : UART0 or UART1 + * @param UART_ParityMode Parity_mode : the enum of uart parity configuration + * + * @return null + */ +void UART_SetParity(UART_Port uart_no, UART_ParityMode Parity_mode) ; + +/** + * @brief Configure the Baud rate. + * + * @param UART_Port uart_no : UART0 or UART1 + * @param uint32 baud_rate : the Baud rate + * + * @return null + */ +void UART_SetBaudrate(UART_Port uart_no, uint32 baud_rate); + +/** + * @brief Configure Hardware flow control. + * + * @param UART_Port uart_no : UART0 or UART1 + * @param UART_HwFlowCtrl flow_ctrl : Hardware flow control mode + * @param uint8 rx_thresh : threshold of Hardware flow control + * + * @return null + */ +void UART_SetFlowCtrl(UART_Port uart_no, UART_HwFlowCtrl flow_ctrl, uint8 rx_thresh); + +/** + * @brief Configure trigging signal of uarts. + * + * @param UART_Port uart_no : UART0 or UART1 + * @param UART_LineLevelInverse inverse_mask : Choose need to flip the IO + * + * @return null + */ +void UART_SetLineInverse(UART_Port uart_no, UART_LineLevelInverse inverse_mask) ; + +/** + * @brief An example illustrates how to configure the serial port. + * + * @param null + * + * @return null + */ +void uart_init_new(void); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/driver_lib/make_lib.sh b/Distrib/ESPressif/RTOS/1.5.0/driver_lib/make_lib.sh new file mode 100644 index 0000000..ec83c61 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/driver_lib/make_lib.sh @@ -0,0 +1,11 @@ +#!/bin/bash -x + +echo "make_lib.sh version 20160307" +echo "" + +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 .. diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/Makefile b/Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/Makefile new file mode 100644 index 0000000..8f76385 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/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 \ + programs + +endif # } PDIR + +LDDIR = $(SDK_PATH)/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 \ + programs/openssl_demo.a + +LINKFLAGS_eagle.app.v6 = \ + -L$(SDK_PATH)/lib \ + -Wl,--gc-sections \ + -nostdlib \ + -T$(LD_FILE) \ + -Wl,--no-check-sections \ + -u call_user_start \ + -Wl,-static \ + -Wl,--start-group \ + -lcirom \ + -lgcc \ + -lhal \ + -lcrypto \ + -lfreertos \ + -llwip \ + -lmain \ + -lnet80211 \ + -lphy \ + -lpp \ + -lmbedtls \ + -lopenssl \ + -lwpa \ + $(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 -I include -I $(SDK_PATH)/include/openssl +sinclude $(SDK_PATH)/Makefile + +.PHONY: FORCE +FORCE: + diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/gen_misc.sh b/Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/gen_misc.sh new file mode 100644 index 0000000..08d4fbb --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/gen_misc.sh @@ -0,0 +1,165 @@ +#!/bin/bash + +echo "gen_misc.sh version 20150911" +echo "" + +if [ $SDK_PATH ]; then + echo "SDK_PATH:" + echo "$SDK_PATH" + echo "" +else + echo "ERROR: Please export SDK_PATH in gen_misc.sh firstly, exit!!!" + exit +fi + +if [ $BIN_PATH ]; then + echo "BIN_PATH:" + echo "$BIN_PATH" + echo "" +else + echo "ERROR: Please export BIN_PATH in gen_misc.sh firstly, exit!!!" + exit +fi + +echo "Please check SDK_PATH & BIN_PATH, enter (Y/y) to continue:" +read input + +if [[ $input != Y ]] && [[ $input != y ]]; then + exit +fi + +echo "" + +echo "Please follow below steps(1-5) to generate specific bin(s):" +echo "STEP 1: use boot_v1.2+ by default" +boot=new + +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 "enter (0/2/3/4/5/6, 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" +else + spi_size_map=0 + echo "spi size: 512KB" + echo "spi ota map: 256KB + 256KB" +fi + +echo "" + +echo "start..." +echo "" + +make clean + +make BOOT=$boot APP=$app SPI_SPEED=$spi_speed SPI_MODE=$spi_mode SPI_SIZE_MAP=$spi_size_map diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/include/openssl_demo.h b/Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/include/openssl_demo.h new file mode 100644 index 0000000..2a8b3f7 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/include/openssl_demo.h @@ -0,0 +1,6 @@ +#ifndef _OPENSSL_DEMO_H_ +#define _OPENSSL_DEMO_H_ + +void user_conn_init(void); + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/include/user_config.h b/Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/include/user_config.h new file mode 100644 index 0000000..dc4e128 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/include/user_config.h @@ -0,0 +1,34 @@ +/* + * ESPRSSIF 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 __USER_CONFIG_H__ +#define __USER_CONFIG_H__ + +#include "openssl_demo.h" + +#define SSID "UTT-750" +#define PASSWORD "espressif" + +#endif + diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/programs/Makefile b/Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/programs/Makefile new file mode 100644 index 0000000..5c74dba --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/programs/Makefile @@ -0,0 +1,47 @@ + +############################################################# +# 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 = openssl_demo.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/Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/programs/openssl_demo.c b/Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/programs/openssl_demo.c new file mode 100644 index 0000000..cc98c4b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/programs/openssl_demo.c @@ -0,0 +1,174 @@ +#include +#include "openssl_demo.h" +#include "openssl/ssl.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "espressif/c_types.h" +#include "lwip/sockets.h" + +#define OPENSSL_DEMO_THREAD_NAME "ssl_demo" +#define OPENSSL_DEMO_THREAD_STACK_WORDS 2048 +#define OPENSSL_DEMO_THREAD_PRORIOTY 6 + +#define OPENSSL_DEMO_FRAGMENT_SIZE 8192 + +#define OPENSSL_DEMO_LOCAL_TCP_PORT 1000 + +#define OPENSSL_DEMO_TARGET_NAME "www.baidu.com" +#define OPENSSL_DEMO_TARGET_TCP_PORT 443 + +#define OPENSSL_DEMO_REQUEST "{\"path\": \"/v1/ping/\", \"method\": \"GET\"}\r\n" + +#define OPENSSL_DEMO_RECV_BUF_LEN 1024 + +LOCAL xTaskHandle openssl_handle; + +LOCAL char send_data[] = OPENSSL_DEMO_REQUEST; +LOCAL int send_bytes = sizeof(send_data); + +LOCAL char recv_buf[OPENSSL_DEMO_RECV_BUF_LEN]; + +LOCAL void openssl_demo_thread(void *p) +{ + int ret; + + SSL_CTX *ctx; + SSL *ssl; + + int socket; + struct sockaddr_in sock_addr; + + ip_addr_t target_ip; + + int recv_bytes = 0; + + os_printf("OpenSSL demo thread start...\n"); + + do { + ret = netconn_gethostbyname(OPENSSL_DEMO_TARGET_NAME, &target_ip); + } while(ret); + os_printf("get target IP is %d.%d.%d.%d\n", (unsigned char)((target_ip.addr & 0x000000ff) >> 0), + (unsigned char)((target_ip.addr & 0x0000ff00) >> 8), + (unsigned char)((target_ip.addr & 0x00ff0000) >> 16), + (unsigned char)((target_ip.addr & 0xff000000) >> 24)); + + os_printf("create SSL context ......"); + ctx = SSL_CTX_new(TLSv1_1_client_method()); + if (!ctx) { + os_printf("failed\n"); + goto failed1; + } + os_printf("OK\n"); + + os_printf("set SSL context read buffer size ......"); + SSL_CTX_set_default_read_buffer_len(ctx, OPENSSL_DEMO_FRAGMENT_SIZE); + ret = 0; + if (ret) { + os_printf("failed, return %d\n", ret); + goto failed2; + } + os_printf("OK\n"); + + os_printf("create socket ......"); + socket = socket(AF_INET, SOCK_STREAM, 0); + if (socket < 0) { + os_printf("failed\n"); + goto failed3; + } + os_printf("OK\n"); + + os_printf("bind socket ......"); + memset(&sock_addr, 0, sizeof(sock_addr)); + sock_addr.sin_family = AF_INET; + sock_addr.sin_addr.s_addr = 0; + sock_addr.sin_port = htons(OPENSSL_DEMO_LOCAL_TCP_PORT); + ret = bind(socket, (struct sockaddr*)&sock_addr, sizeof(sock_addr)); + if (ret) { + os_printf("failed\n"); + goto failed4; + } + os_printf("OK\n"); + + os_printf("socket connect to remote ......"); + memset(&sock_addr, 0, sizeof(sock_addr)); + sock_addr.sin_family = AF_INET; + sock_addr.sin_addr.s_addr = target_ip.addr; + sock_addr.sin_port = htons(OPENSSL_DEMO_TARGET_TCP_PORT); + ret = connect(socket, (struct sockaddr*)&sock_addr, sizeof(sock_addr)); + if (ret) { + os_printf("failed\n", OPENSSL_DEMO_TARGET_NAME); + goto failed5; + } + os_printf("OK\n"); + + os_printf("create SSL ......"); + ssl = SSL_new(ctx); + if (!ssl) { + os_printf("failed\n"); + goto failed6; + } + os_printf("OK\n"); + + SSL_set_fd(ssl, socket); + + os_printf("SSL connected to %s port %d ......", OPENSSL_DEMO_TARGET_NAME, OPENSSL_DEMO_TARGET_TCP_PORT); + ret = SSL_connect(ssl); + if (!ret) { + os_printf("failed, return [-0x%x]\n", -ret); + goto failed7; + } + os_printf("OK\n"); + + os_printf("send request to %s port %d ......", OPENSSL_DEMO_TARGET_NAME, OPENSSL_DEMO_TARGET_TCP_PORT); + ret = SSL_write(ssl, send_data, send_bytes); + if (ret <= 0) { + os_printf("failed, return [-0x%x]\n", -ret); + goto failed8; + } + os_printf("OK\n\n"); + + do { + ret = SSL_read(ssl, recv_buf, OPENSSL_DEMO_RECV_BUF_LEN - 1); + if (ret <= 0) { + break; + } + recv_bytes += ret; + os_printf("%s", recv_buf); + } while (1); + os_printf("read %d bytes data from %s ......\n", recv_bytes, OPENSSL_DEMO_TARGET_NAME); + +failed8: + SSL_shutdown(ssl); +failed7: + SSL_free(ssl); +failed6: +failed5: +failed4: + close(socket); +failed3: +failed2: + SSL_CTX_free(ctx); +failed1: + vTaskDelete(NULL); + + os_printf("task exit\n"); + + return ; +} + +void user_conn_init(void) +{ + int ret; + + ret = xTaskCreate(openssl_demo_thread, + OPENSSL_DEMO_THREAD_NAME, + OPENSSL_DEMO_THREAD_STACK_WORDS, + NULL, + OPENSSL_DEMO_THREAD_PRORIOTY, + &openssl_handle); + if (ret != pdPASS) { + os_printf("create thread %s failed\n", OPENSSL_DEMO_THREAD_NAME); + return ; + } +} + diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/user/Makefile b/Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/user/Makefile new file mode 100644 index 0000000..d57d85d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/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/Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/user/user_main.c b/Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/user/user_main.c new file mode 100644 index 0000000..02727d2 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/openssl_demo/user/user_main.c @@ -0,0 +1,108 @@ +/* + * ESPRSSIF 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 "esp_common.h" +#include "user_config.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 user_rf_cal_sector_set(void) +{ + 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; + + default: + rf_cal_sec = 0; + break; + } + + return rf_cal_sec; +} + +void wifi_event_handler_cb(System_Event_t *event) +{ + if (event == NULL) { + return; + } + + switch (event->event_id) { + case EVENT_STAMODE_GOT_IP: + os_printf("sta got ip , creat task %d\n", system_get_free_heap_size()); + user_conn_init(); + break; + + default: + break; + } +} + +/****************************************************************************** + * FunctionName : user_init + * Description : entry of user application, init user function here + * Parameters : none + * Returns : none +*******************************************************************************/ +void user_init(void) +{ + os_printf("SDK version:%s %d\n", system_get_sdk_version(), system_get_free_heap_size()); + wifi_set_opmode(STATION_MODE); + + // set AP parameter + struct station_config config; + bzero(&config, sizeof(struct station_config)); + sprintf(config.ssid, SSID); + sprintf(config.password, PASSWORD); + wifi_station_set_config(&config); + + wifi_set_event_handler_cb(wifi_event_handler_cb); +} diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/Makefile b/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/Makefile new file mode 100644 index 0000000..b8dd20f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/Makefile @@ -0,0 +1,132 @@ +############################################################# +# 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 \ + sample_lib + +endif # } PDIR + +LDDIR = $(SDK_PATH)/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 \ + sample_lib/libsample.a + +LINKFLAGS_eagle.app.v6 = \ + -L$(SDK_PATH)/lib \ + -Wl,--gc-sections \ + -nostdlib \ + -T$(LD_FILE) \ + -Wl,--no-check-sections \ + -u call_user_start \ + -Wl,-static \ + -Wl,--start-group \ + -lcirom \ + -lcrypto \ + -lespconn \ + -lespnow \ + -lfreertos \ + -lgcc \ + -lhal \ + -ljson \ + -llwip \ + -lmain \ + -lmesh \ + -lmirom \ + -lnet80211 \ + -lnopoll \ + -lphy \ + -lpp \ + -lpwm \ + -lsmartconfig \ + -lspiffs \ + -lssl \ + -lwpa \ + -lwps \ + $(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 +sinclude $(SDK_PATH)/Makefile + +.PHONY: FORCE +FORCE: + diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/gen_misc.bat b/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/gen_misc.bat new file mode 100644 index 0000000..fd0b44f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/gen_misc.bat @@ -0,0 +1,172 @@ +@echo off + +Rem ******NOTICE****** +Rem MUST set SDK_PATH & BIN_PATH firstly!!! +Rem example: +Rem set SDK_PATH=/c/esp_iot_sdk_freertos +Rem set BIN_PATH=/c/esp8266_bin + +set SDK_PATH="" +set BIN_PATH="" + +echo gen_misc.bat version 20150911 +echo . + +if not %SDK_PATH% == "" ( + echo SDK_PATH: %SDK_PATH% +) else ( + echo ERROR: Please set SDK_PATH in gen_misc.bat firstly, exit!!! + goto end +) + +if not %BIN_PATH% == "" ( + echo BIN_PATH: %BIN_PATH% +) else ( + echo ERROR: Please set BIN_PATH in gen_misc.bat firstly, exit!!! + goto end +) + +echo . +echo Please check SDK_PATH/BIN_PATH, enter (Y/y) to continue: +set input=default +set /p input= + +if not %input% == Y ( + if not %input% == y ( + goto end + ) +) + +echo . +echo Please follow below steps(1-5) to generate specific bin(s): +echo STEP 1: use boot_v1.2+ by default +set boot=new + +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 + ) + ) + ) + ) +) + +echo. +echo start... +echo. + +make clean + +make COMPILE=xcc BOOT=%boot% APP=%app% SPI_SPEED=%spi_speed% SPI_MODE=%spi_mode% SPI_SIZE_MAP=%spi_size_map% + +:end \ No newline at end of file diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/gen_misc.sh b/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/gen_misc.sh new file mode 100644 index 0000000..c8ffb4e --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/gen_misc.sh @@ -0,0 +1,176 @@ +#!/bin/bash + +:< + * + * 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/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/readme.txt b/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/readme.txt new file mode 100644 index 0000000..3c7e7e7 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/readme.txt @@ -0,0 +1,56 @@ +This is a simple project template. + +sample_lib is an example for multi-level folder Makefile, notice the folder structure and each Makefile, you can get the clue. + + +HOWTO: +1. Copy this folder to anywhere. +Example: + Copy to ~/workspace/project_template + You can rename this folder as you like. + +2. Export SDK_PATH and BIN_PATH. +Example: + Your SDK path is ~/esp_iot_rtos_sdk, and want generate bin at ~/esp8266_bin. + Do follow steps: + 1>. export SDK_PATH=~/esp_iot_rtos_sdk + 2>. export BIN_PATH=~/esp8266_bin + SDK and project are seperate, you can update SDK without change your project. + +3. Enter project_template folder, run ./gen_misc.sh, and follow the tips and steps. + + +Compile Options: +(1) COMPILE + Possible value: xcc + Default value: + If not set, use gcc 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: new + +(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 diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/sample_lib/Makefile b/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/sample_lib/Makefile new file mode 100644 index 0000000..69ce1ed --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/sample_lib/Makefile @@ -0,0 +1,47 @@ + +############################################################# +# 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 = libsample.a +COMPONENTS_libsample = folder1/libfolder1.a \ + folder2/libfolder2.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/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/sample_lib/folder1/Makefile b/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/sample_lib/folder1/Makefile new file mode 100644 index 0000000..e128f5f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/sample_lib/folder1/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 = libfolder1.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/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/sample_lib/folder1/file1.c b/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/sample_lib/folder1/file1.c new file mode 100644 index 0000000..e69de29 diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/sample_lib/folder2/Makefile b/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/sample_lib/folder2/Makefile new file mode 100644 index 0000000..82cbc6c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/sample_lib/folder2/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 = libfolder2.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/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/sample_lib/folder2/file2.c b/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/sample_lib/folder2/file2.c new file mode 100644 index 0000000..e69de29 diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/user/Makefile b/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/user/Makefile new file mode 100644 index 0000000..d57d85d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/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/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/user/user_main.c b/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/user/user_main.c new file mode 100644 index 0000000..d9e6132 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/project_template/user/user_main.c @@ -0,0 +1,81 @@ +/* + * ESPRSSIF 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 "esp_common.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 user_rf_cal_sector_set(void) +{ + 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; + + default: + rf_cal_sec = 0; + break; + } + + return rf_cal_sec; +} + +/****************************************************************************** + * FunctionName : user_init + * Description : entry of user application, init user function here + * Parameters : none + * Returns : none +*******************************************************************************/ +void user_init(void) +{ + printf("SDK version:%s\n", system_get_sdk_version()); +} + diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/Makefile b/Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/Makefile new file mode 100644 index 0000000..79b6d46 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/Makefile @@ -0,0 +1,122 @@ +############################################################# +# 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 + +LDDIR = $(SDK_PATH)/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$(SDK_PATH)/lib \ + -Wl,--gc-sections \ + -nostdlib \ + -T$(LD_FILE) \ + -Wl,--no-check-sections \ + -u call_user_start \ + -Wl,-static \ + -Wl,--start-group \ + -lminic \ + -lgcc \ + -lhal \ + -lphy \ + -lpp \ + -lnet80211 \ + -lwpa \ + -lcrypto \ + -lmain \ + -lfreertos \ + -llwip \ + -lespconn\ + -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 +sinclude $(SDK_PATH)/Makefile + +.PHONY: FORCE +FORCE: + diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/airkiss.txt b/Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/airkiss.txt new file mode 100644 index 0000000..fed54ec --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/airkiss.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/Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/gen_misc.bat b/Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/gen_misc.bat new file mode 100644 index 0000000..fd0b44f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/gen_misc.bat @@ -0,0 +1,172 @@ +@echo off + +Rem ******NOTICE****** +Rem MUST set SDK_PATH & BIN_PATH firstly!!! +Rem example: +Rem set SDK_PATH=/c/esp_iot_sdk_freertos +Rem set BIN_PATH=/c/esp8266_bin + +set SDK_PATH="" +set BIN_PATH="" + +echo gen_misc.bat version 20150911 +echo . + +if not %SDK_PATH% == "" ( + echo SDK_PATH: %SDK_PATH% +) else ( + echo ERROR: Please set SDK_PATH in gen_misc.bat firstly, exit!!! + goto end +) + +if not %BIN_PATH% == "" ( + echo BIN_PATH: %BIN_PATH% +) else ( + echo ERROR: Please set BIN_PATH in gen_misc.bat firstly, exit!!! + goto end +) + +echo . +echo Please check SDK_PATH/BIN_PATH, enter (Y/y) to continue: +set input=default +set /p input= + +if not %input% == Y ( + if not %input% == y ( + goto end + ) +) + +echo . +echo Please follow below steps(1-5) to generate specific bin(s): +echo STEP 1: use boot_v1.2+ by default +set boot=new + +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 + ) + ) + ) + ) +) + +echo. +echo start... +echo. + +make clean + +make COMPILE=xcc BOOT=%boot% APP=%app% SPI_SPEED=%spi_speed% SPI_MODE=%spi_mode% SPI_SIZE_MAP=%spi_size_map% + +:end \ No newline at end of file diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/gen_misc.sh b/Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/gen_misc.sh new file mode 100644 index 0000000..b24f63c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/gen_misc.sh @@ -0,0 +1,176 @@ +#!/bin/bash + +:< + * + * 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/Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/model two-dimension code.rar b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/readme.txt b/Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/readme.txt new file mode 100644 index 0000000..6063086 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/readme.txt @@ -0,0 +1,40 @@ +1¡¢compile options + +(1) COMPILE + Possible value: xcc + Default value: + If not set, use gcc 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: new + +(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. diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/user/Makefile b/Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/user/Makefile new file mode 100644 index 0000000..d57d85d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/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/Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/user/user_main.c b/Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/user/user_main.c new file mode 100644 index 0000000..00ad62c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/smart_config/user/user_main.c @@ -0,0 +1,267 @@ +/* + * ESPRSSIF 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 "esp_common.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "lwip/sockets.h" +#include "lwip/dns.h" +#include "lwip/netdb.h" +#include "espressif/espconn.h" +#include "espressif/airkiss.h" + +#define server_ip "192.168.101.142" +#define server_port 9669 + + +#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 lan_buf[200]; +uint16 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; + 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 +#include +#include +//#include +#include + +SUITE(bug_tests) +void setup() { + _setup_test_only(); +} +void teardown() { + _teardown(); +} + +TEST(nodemcu_full_fs_1) { + fs_reset_specific(0, 1280*1024, 4096*20, 4096, 4096, 128); + + int res; + spiffs_file fd; + + printf(" fill up system by writing one byte a lot\n"); + fd = SPIFFS_open(FS, "test1.txt", SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0); + TEST_CHECK(fd > 0); + int i; + spiffs_stat s; + res = SPIFFS_OK; + for (i = 0; i < 100*1000; i++) { + u8_t buf = 'x'; + res = SPIFFS_write(FS, fd, &buf, 1); + } + + int errno = SPIFFS_errno(FS); + int res2 = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res2 == SPIFFS_OK); + printf(" >>> file %s size: %i\n", s.name, s.size); + + TEST_CHECK(errno == SPIFFS_ERR_FULL); + SPIFFS_close(FS, fd); + + printf(" remove big file\n"); + res = SPIFFS_remove(FS, "test1.txt"); + + printf("res:%i errno:%i\n",res, SPIFFS_errno(FS)); + + TEST_CHECK(res == SPIFFS_OK); + res2 = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res2 == -1); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + res2 = SPIFFS_stat(FS, "test1.txt", &s); + TEST_CHECK(res2 == -1); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_NOT_FOUND); + + printf(" create small file\n"); + fd = SPIFFS_open(FS, "test2.txt", SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0); + TEST_CHECK(fd > 0); + res = SPIFFS_OK; + for (i = 0; res >= 0 && i < 1000; i++) { + u8_t buf = 'x'; + res = SPIFFS_write(FS, fd, &buf, 1); + } + TEST_CHECK(res >= SPIFFS_OK); + + res2 = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res2 == SPIFFS_OK); + printf(" >>> file %s size: %i\n", s.name, s.size); + + TEST_CHECK(s.size == 1000); + SPIFFS_close(FS, fd); + + return TEST_RES_OK; + +} TEST_END(nodemcu_full_fs_1) + +TEST(nodemcu_full_fs_2) { + fs_reset_specific(0, 1280*1024, 4096*22, 4096, 4096, 128); + + int res; + spiffs_file fd; + + printf(" fill up system by writing one byte a lot\n"); + fd = SPIFFS_open(FS, "test1.txt", SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0); + TEST_CHECK(fd > 0); + int i; + spiffs_stat s; + res = SPIFFS_OK; + for (i = 0; i < 100*1000; i++) { + u8_t buf = 'x'; + res = SPIFFS_write(FS, fd, &buf, 1); + } + + int errno = SPIFFS_errno(FS); + int res2 = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res2 == SPIFFS_OK); + printf(" >>> file %s size: %i\n", s.name, s.size); + + TEST_CHECK(errno == SPIFFS_ERR_FULL); + SPIFFS_close(FS, fd); + + res2 = SPIFFS_stat(FS, "test1.txt", &s); + TEST_CHECK(res2 == SPIFFS_OK); + + SPIFFS_clearerr(FS); + printf(" create small file\n"); + fd = SPIFFS_open(FS, "test2.txt", SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0); +#if 0 + // before gc in v3.1 + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_OK); + TEST_CHECK(fd > 0); + + for (i = 0; i < 1000; i++) { + u8_t buf = 'x'; + res = SPIFFS_write(FS, fd, &buf, 1); + } + + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FULL); + res2 = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res2 == SPIFFS_OK); + printf(" >>> file %s size: %i\n", s.name, s.size); + TEST_CHECK(s.size == 0); + SPIFFS_clearerr(FS); +#else + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FULL); + SPIFFS_clearerr(FS); +#endif + printf(" remove files\n"); + res = SPIFFS_remove(FS, "test1.txt"); + TEST_CHECK(res == SPIFFS_OK); +#if 0 + res = SPIFFS_remove(FS, "test2.txt"); + TEST_CHECK(res == SPIFFS_OK); +#endif + + printf(" create medium file\n"); + fd = SPIFFS_open(FS, "test3.txt", SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_OK); + TEST_CHECK(fd > 0); + + for (i = 0; i < 20*1000; i++) { + u8_t buf = 'x'; + res = SPIFFS_write(FS, fd, &buf, 1); + } + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_OK); + + res2 = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res2 == SPIFFS_OK); + printf(" >>> file %s size: %i\n", s.name, s.size); + TEST_CHECK(s.size == 20*1000); + + return TEST_RES_OK; + +} TEST_END(nodemcu_full_fs_2) + +TEST(magic_test) { + // one obj lu page, not full + fs_reset_specific(0, 1280*1024, 4096*16, 4096, 4096*1, 128); + TEST_CHECK(SPIFFS_CHECK_MAGIC_POSSIBLE(FS)); + // one obj lu page, full + fs_reset_specific(0, 1280*1024, 4096*16, 4096, 4096*2, 128); + TEST_CHECK(!SPIFFS_CHECK_MAGIC_POSSIBLE(FS)); + // two obj lu pages, not full + fs_reset_specific(0, 1280*1024, 4096*16, 4096, 4096*4, 128); + TEST_CHECK(SPIFFS_CHECK_MAGIC_POSSIBLE(FS)); + + return TEST_RES_OK; + +} TEST_END(magic_test) + +TEST(nodemcu_309) { + fs_reset_specific(0, 1280*1024, 4096*20, 4096, 4096, 128); + + int res; + spiffs_file fd; + int j; + + for (j = 1; j <= 3; j++) { + char fname[32]; + sprintf(fname, "20K%i.txt", j); + fd = SPIFFS_open(FS, fname, SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_DIRECT, 0); + TEST_CHECK(fd > 0); + int i; + spiffs_stat s; + res = SPIFFS_OK; + u8_t err = 0; + for (i = 1; i <= 1280; i++) { + char *buf = "0123456789ABCDE\n"; + res = SPIFFS_write(FS, fd, buf, strlen(buf)); + if (!err && res < 0) { + printf("err @ %i,%i\n", i, j); + err = 1; + } + } + } + + int errno = SPIFFS_errno(FS); + TEST_CHECK(errno == SPIFFS_ERR_FULL); + + u32_t total; + u32_t used; + + SPIFFS_info(FS, &total, &used); + printf("total:%i\nused:%i\nremain:%i\nerrno:%i\n", total, used, total-used, errno); + TEST_CHECK(total-used < 11000); + + spiffs_DIR d; + struct spiffs_dirent e; + struct spiffs_dirent *pe = &e; + + SPIFFS_opendir(FS, "/", &d); + int spoon_guard = 0; + while ((pe = SPIFFS_readdir(&d, pe))) { + printf("%s [%04x] size:%i\n", pe->name, pe->obj_id, pe->size); + TEST_CHECK(spoon_guard++ < 3); + } + TEST_CHECK(spoon_guard == 3); + SPIFFS_closedir(&d); + + return TEST_RES_OK; + +} TEST_END(nodemcu_309) + + +TEST(robert) { + // create a clean file system starting at address 0, 2 megabytes big, + // sector size 65536, block size 65536, page size 256 + fs_reset_specific(0, 1280*1024, 128*1024, 4096, 4096, 128); + + int res; + spiffs_file fd; + char fname[32]; + + sprintf(fname, "test.txt"); + fd = SPIFFS_open(FS, fname, SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0); + TEST_CHECK(fd > 0); + int i; + res = SPIFFS_OK; + char buf[500]; + memset(buf, 0xaa, 500); + res = SPIFFS_write(FS, fd, buf, 500); + TEST_CHECK(res >= SPIFFS_OK); + SPIFFS_close(FS, fd); + + int errno = SPIFFS_errno(FS); + TEST_CHECK(errno == SPIFFS_OK); + + //SPIFFS_vis(FS); + // unmount + SPIFFS_unmount(FS); + + // remount + res = fs_mount_specific(1280*1024, 256*1024, 4096, 4096, 128); + TEST_CHECK(res== SPIFFS_OK); + + //SPIFFS_vis(FS); + + spiffs_stat s; + TEST_CHECK(SPIFFS_stat(FS, fname, &s) == SPIFFS_OK); + printf("file %s stat size %i\n", s.name, s.size); + TEST_CHECK(s.size == 500); + + return TEST_RES_OK; + +} TEST_END(robert) + + +TEST(spiffs_12) { + fs_reset_specific(0, 1280*1024, 128*1024, 4096, 4096, 128); + + int res; + spiffs_file fd; + int j = 1; + + while (1) { + char fname[32]; + sprintf(fname, "file%i.txt", j); + fd = SPIFFS_open(FS, fname, SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_DIRECT, 0); + if (fd <=0) break; + + int i; + res = SPIFFS_OK; + for (i = 1; i <= 100; i++) { + char *buf = "0123456789ABCDE\n"; + res = SPIFFS_write(FS, fd, buf, strlen(buf)); + if (res < 0) break; + } + SPIFFS_close(FS, fd); + j++; + } + + int errno = SPIFFS_errno(FS); + TEST_CHECK(errno == SPIFFS_ERR_FULL); + + u32_t total; + u32_t used; + + SPIFFS_info(FS, &total, &used); + printf("total:%i (%iK)\nused:%i (%iK)\nremain:%i (%iK)\nerrno:%i\n", total, total/1024, used, used/1024, total-used, (total-used)/1024, errno); + + spiffs_DIR d; + struct spiffs_dirent e; + struct spiffs_dirent *pe = &e; + + SPIFFS_opendir(FS, "/", &d); + while ((pe = SPIFFS_readdir(&d, pe))) { + printf("%s [%04x] size:%i\n", pe->name, pe->obj_id, pe->size); + } + SPIFFS_closedir(&d); + + //SPIFFS_vis(FS); + + //dump_page(FS, 0); + //dump_page(FS, 1); + + return TEST_RES_OK; + +} TEST_END(spiffs_12) + + +SUITE_END(bug_tests) diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/test_check.c b/Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/test_check.c new file mode 100644 index 0000000..b743946 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/test_check.c @@ -0,0 +1,419 @@ +/* + * test_dev.c + * + * Created on: Jul 14, 2013 + * Author: petera + */ + + +#include "testrunner.h" +#include "test_spiffs.h" +#include "spiffs_nucleus.h" +#include "spiffs.h" +#include +#include +#include +//#include +#include + + +SUITE(check_tests) +void setup() { + _setup(); +} +void teardown() { + _teardown(); +} + +TEST(evil_write) { + fs_set_validate_flashing(0); + printf("writing corruption to block 1 data range (leaving lu intact)\n"); + u32_t data_range = SPIFFS_CFG_LOG_BLOCK_SZ(FS) - + SPIFFS_CFG_LOG_PAGE_SZ(FS) * (SPIFFS_OBJ_LOOKUP_PAGES(FS)); + u8_t *corruption = malloc(data_range); + MALLOC_CHECK(corruption != NULL, data_range); + memrand(corruption, data_range); + u32_t addr = 0 * SPIFFS_CFG_LOG_PAGE_SZ(FS) * SPIFFS_OBJ_LOOKUP_PAGES(FS) + SPIFFS_CFG_PHYS_ADDR(FS); + area_write(addr, corruption, data_range); + free(corruption); + + int size = SPIFFS_DATA_PAGE_SIZE(FS)*3; + int res = test_create_and_write_file("file", size, size); + + printf("CHECK1-----------------\n"); + SPIFFS_check(FS); + printf("CHECK2-----------------\n"); + SPIFFS_check(FS); + printf("CHECK3-----------------\n"); + SPIFFS_check(FS); + + res = test_create_and_write_file("file2", size, size); + TEST_CHECK(res >= 0); + + return TEST_RES_OK; +} TEST_END(evil_write) + + +TEST(lu_check1) { + int size = SPIFFS_DATA_PAGE_SIZE(FS)*3; + int res = test_create_and_write_file("file", size, size); + TEST_CHECK(res >= 0); + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0); + TEST_CHECK(fd > 0); + spiffs_stat s; + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + + // modify lu entry data page index 1 + spiffs_page_ix pix; + res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 1, 0, &pix); + TEST_CHECK(res >= 0); + + // reset lu entry to being erased, but keep page data + spiffs_obj_id obj_id = SPIFFS_OBJ_ID_DELETED; + spiffs_block_ix bix = SPIFFS_BLOCK_FOR_PAGE(FS, pix); + int entry = SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(FS, pix); + u32_t addr = SPIFFS_BLOCK_TO_PADDR(FS, bix) + entry*sizeof(spiffs_obj_id); + + area_write(addr, (u8_t*)&obj_id, sizeof(spiffs_obj_id)); + +#if SPIFFS_CACHE + spiffs_cache *cache = spiffs_get_cache(FS); + cache->cpage_use_map = 0; +#endif + SPIFFS_check(FS); + + return TEST_RES_OK; +} TEST_END(lu_check1) + + +TEST(page_cons1) { + int size = SPIFFS_DATA_PAGE_SIZE(FS)*3; + int res = test_create_and_write_file("file", size, size); + TEST_CHECK(res >= 0); + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0); + TEST_CHECK(fd > 0); + spiffs_stat s; + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + + // modify object index, find object index header + spiffs_page_ix pix; + res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix); + TEST_CHECK(res >= 0); + + // set object index entry 2 to a bad page + u32_t addr = SPIFFS_PAGE_TO_PADDR(FS, pix) + sizeof(spiffs_page_object_ix_header) + 0 * sizeof(spiffs_page_ix); + spiffs_page_ix bad_pix_ref = 0x55; + area_write(addr, (u8_t*)&bad_pix_ref, sizeof(spiffs_page_ix)); + area_write(addr+2, (u8_t*)&bad_pix_ref, sizeof(spiffs_page_ix)); + + // delete all cache +#if SPIFFS_CACHE + spiffs_cache *cache = spiffs_get_cache(FS); + cache->cpage_use_map = 0; +#endif + + SPIFFS_check(FS); + + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + return TEST_RES_OK; +} TEST_END(page_cons1) + + +TEST(page_cons2) { + int size = SPIFFS_DATA_PAGE_SIZE(FS)*3; + int res = test_create_and_write_file("file", size, size); + TEST_CHECK(res >= 0); + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0); + TEST_CHECK(fd > 0); + spiffs_stat s; + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + + // modify object index, find object index header + spiffs_page_ix pix; + res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix); + TEST_CHECK(res >= 0); + + // find data page span index 0 + spiffs_page_ix dpix; + res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &dpix); + TEST_CHECK(res >= 0); + + // set object index entry 1+2 to a data page 0 + u32_t addr = SPIFFS_PAGE_TO_PADDR(FS, pix) + sizeof(spiffs_page_object_ix_header) + 1 * sizeof(spiffs_page_ix); + spiffs_page_ix bad_pix_ref = dpix; + area_write(addr, (u8_t*)&bad_pix_ref, sizeof(spiffs_page_ix)); + area_write(addr+sizeof(spiffs_page_ix), (u8_t*)&bad_pix_ref, sizeof(spiffs_page_ix)); + + // delete all cache +#if SPIFFS_CACHE + spiffs_cache *cache = spiffs_get_cache(FS); + cache->cpage_use_map = 0; +#endif + + SPIFFS_check(FS); + + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + return TEST_RES_OK; +} TEST_END(page_cons2) + + + +TEST(page_cons3) { + int size = SPIFFS_DATA_PAGE_SIZE(FS)*3; + int res = test_create_and_write_file("file", size, size); + TEST_CHECK(res >= 0); + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0); + TEST_CHECK(fd > 0); + spiffs_stat s; + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + + // modify object index, find object index header + spiffs_page_ix pix; + res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix); + TEST_CHECK(res >= 0); + + // set object index entry 1+2 lookup page + u32_t addr = SPIFFS_PAGE_TO_PADDR(FS, pix) + sizeof(spiffs_page_object_ix_header) + 1 * sizeof(spiffs_page_ix); + spiffs_page_ix bad_pix_ref = SPIFFS_PAGES_PER_BLOCK(FS) * (*FS.block_count - 2); + area_write(addr, (u8_t*)&bad_pix_ref, sizeof(spiffs_page_ix)); + area_write(addr+sizeof(spiffs_page_ix), (u8_t*)&bad_pix_ref, sizeof(spiffs_page_ix)); + + // delete all cache +#if SPIFFS_CACHE + spiffs_cache *cache = spiffs_get_cache(FS); + cache->cpage_use_map = 0; +#endif + + SPIFFS_check(FS); + + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + return TEST_RES_OK; +} TEST_END(page_cons3) + + +TEST(page_cons_final) { + int size = SPIFFS_DATA_PAGE_SIZE(FS)*3; + int res = test_create_and_write_file("file", size, size); + TEST_CHECK(res >= 0); + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0); + TEST_CHECK(fd > 0); + spiffs_stat s; + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + + // modify page header, make unfinalized + spiffs_page_ix pix; + res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 1, 0, &pix); + TEST_CHECK(res >= 0); + + // set page span ix 1 as unfinalized + u32_t addr = SPIFFS_PAGE_TO_PADDR(FS, pix) + offsetof(spiffs_page_header, flags); + u8_t flags; + area_read(addr, (u8_t*)&flags, 1); + flags |= SPIFFS_PH_FLAG_FINAL; + area_write(addr, (u8_t*)&flags, 1); + + // delete all cache +#if SPIFFS_CACHE + spiffs_cache *cache = spiffs_get_cache(FS); + cache->cpage_use_map = 0; +#endif + + SPIFFS_check(FS); + + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + return TEST_RES_OK; +} TEST_END(page_cons_final) + + +TEST(index_cons1) { + int size = SPIFFS_DATA_PAGE_SIZE(FS)*SPIFFS_PAGES_PER_BLOCK(FS); + int res = test_create_and_write_file("file", size, size); + TEST_CHECK(res >= 0); + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0); + TEST_CHECK(fd > 0); + spiffs_stat s; + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + + // modify lu entry data page index header + spiffs_page_ix pix; + res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix); + TEST_CHECK(res >= 0); + + printf(" deleting lu entry pix %04x\n", pix); + // reset lu entry to being erased, but keep page data + spiffs_obj_id obj_id = SPIFFS_OBJ_ID_DELETED; + spiffs_block_ix bix = SPIFFS_BLOCK_FOR_PAGE(FS, pix); + int entry = SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(FS, pix); + u32_t addr = SPIFFS_BLOCK_TO_PADDR(FS, bix) + entry * sizeof(spiffs_obj_id); + + area_write(addr, (u8_t*)&obj_id, sizeof(spiffs_obj_id)); + +#if SPIFFS_CACHE + spiffs_cache *cache = spiffs_get_cache(FS); + cache->cpage_use_map = 0; +#endif + SPIFFS_check(FS); + + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + return TEST_RES_OK; +} TEST_END(index_cons1) + + +TEST(index_cons2) { + int size = SPIFFS_DATA_PAGE_SIZE(FS)*SPIFFS_PAGES_PER_BLOCK(FS); + int res = test_create_and_write_file("file", size, size); + TEST_CHECK(res >= 0); + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0); + TEST_CHECK(fd > 0); + spiffs_stat s; + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + + // modify lu entry data page index header + spiffs_page_ix pix; + res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix); + TEST_CHECK(res >= 0); + + printf(" writing lu entry for index page, ix %04x, as data page\n", pix); + spiffs_obj_id obj_id = 0x1234; + spiffs_block_ix bix = SPIFFS_BLOCK_FOR_PAGE(FS, pix); + int entry = SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(FS, pix); + u32_t addr = SPIFFS_BLOCK_TO_PADDR(FS, bix) + entry * sizeof(spiffs_obj_id); + + area_write(addr, (u8_t*)&obj_id, sizeof(spiffs_obj_id)); + +#if SPIFFS_CACHE + spiffs_cache *cache = spiffs_get_cache(FS); + cache->cpage_use_map = 0; +#endif + SPIFFS_check(FS); + + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + return TEST_RES_OK; +} TEST_END(index_cons2) + + +TEST(index_cons3) { + int size = SPIFFS_DATA_PAGE_SIZE(FS)*SPIFFS_PAGES_PER_BLOCK(FS); + int res = test_create_and_write_file("file", size, size); + TEST_CHECK(res >= 0); + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0); + TEST_CHECK(fd > 0); + spiffs_stat s; + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + + // modify lu entry data page index header + spiffs_page_ix pix; + res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix); + TEST_CHECK(res >= 0); + + printf(" setting lu entry pix %04x to another index page\n", pix); + // reset lu entry to being erased, but keep page data + spiffs_obj_id obj_id = 1234 | SPIFFS_OBJ_ID_IX_FLAG; + spiffs_block_ix bix = SPIFFS_BLOCK_FOR_PAGE(FS, pix); + int entry = SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(FS, pix); + u32_t addr = SPIFFS_BLOCK_TO_PADDR(FS, bix) + entry * sizeof(spiffs_obj_id); + + area_write(addr, (u8_t*)&obj_id, sizeof(spiffs_obj_id)); + +#if SPIFFS_CACHE + spiffs_cache *cache = spiffs_get_cache(FS); + cache->cpage_use_map = 0; +#endif + SPIFFS_check(FS); + + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + return TEST_RES_OK; +} TEST_END(index_cons3) + +TEST(index_cons4) { + int size = SPIFFS_DATA_PAGE_SIZE(FS)*SPIFFS_PAGES_PER_BLOCK(FS); + int res = test_create_and_write_file("file", size, size); + TEST_CHECK(res >= 0); + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0); + TEST_CHECK(fd > 0); + spiffs_stat s; + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + + // modify lu entry data page index header, flags + spiffs_page_ix pix; + res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix); + TEST_CHECK(res >= 0); + + printf(" cue objix hdr deletion in page %04x\n", pix); + // set flags as deleting ix header + u32_t addr = SPIFFS_PAGE_TO_PADDR(FS, pix) + offsetof(spiffs_page_header, flags); + u8_t flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_IXDELE); + + area_write(addr, (u8_t*)&flags, 1); + +#if SPIFFS_CACHE + spiffs_cache *cache = spiffs_get_cache(FS); + cache->cpage_use_map = 0; +#endif + SPIFFS_check(FS); + + return TEST_RES_OK; +} TEST_END(index_cons4) + + + +SUITE_END(check_tests) diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/test_dev.c b/Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/test_dev.c new file mode 100644 index 0000000..957a6d8 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/test_dev.c @@ -0,0 +1,122 @@ +/* + * test_dev.c + * + * Created on: Jul 14, 2013 + * Author: petera + */ + + +#include "testrunner.h" +#include "test_spiffs.h" +#include "spiffs_nucleus.h" +#include "spiffs.h" +#include +#include +#include +//#include +#include + + +SUITE(dev_tests) +void setup() { + _setup(); +} +void teardown() { + _teardown(); +} + +TEST(interrupted_write) { + char *name = "interrupt"; + char *name2 = "interrupt2"; + int res; + spiffs_file fd; + + const u32_t sz = SPIFFS_CFG_LOG_PAGE_SZ(FS)*8; + u8_t *buf = malloc(sz); + MALLOC_CHECK(buf != NULL, sz); + memrand(buf, sz); + + printf(" create reference file\n"); + fd = SPIFFS_open(FS, name, SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0); + TEST_CHECK(fd > 0); + clear_flash_ops_log(); + res = SPIFFS_write(FS, fd, buf, sz); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + + u32_t written = get_flash_ops_log_write_bytes(); + printf(" written bytes: %i\n", written); + + + printf(" create error file\n"); + fd = SPIFFS_open(FS, name2, SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0); + TEST_CHECK(fd > 0); + clear_flash_ops_log(); + invoke_error_after_write_bytes(written/2, 0); + res = SPIFFS_write(FS, fd, buf, sz); + SPIFFS_close(FS, fd); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_TEST); + + clear_flash_ops_log(); + +#if SPIFFS_CACHE + // delete all cache + spiffs_cache *cache = spiffs_get_cache(FS); + cache->cpage_use_map = 0; +#endif + + + printf(" read error file\n"); + fd = SPIFFS_open(FS, name2, SPIFFS_RDONLY, 0); + TEST_CHECK(fd > 0); + + spiffs_stat s; + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + printf(" file size: %i\n", s.size); + + if (s.size > 0) { + u8_t *buf2 = malloc(s.size); + MALLOC_CHECK(buf2 != NULL, s.size); + res = SPIFFS_read(FS, fd, buf2, s.size); + TEST_CHECK(res >= 0); + + u32_t ix = 0; + for (ix = 0; ix < s.size; ix += 16) { + int i; + printf(" "); + for (i = 0; i < 16; i++) { + printf("%02x", buf[ix+i]); + } + printf(" "); + for (i = 0; i < 16; i++) { + printf("%02x", buf2[ix+i]); + } + printf("\n"); + } + free(buf2); + } + SPIFFS_close(FS, fd); + + + printf(" FS check\n"); + SPIFFS_check(FS); + + printf(" read error file again\n"); + fd = SPIFFS_open(FS, name2, SPIFFS_APPEND | SPIFFS_RDWR, 0); + TEST_CHECK(fd > 0); + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + printf(" file size: %i\n", s.size); + printf(" write file\n"); + res = SPIFFS_write(FS, fd, buf, sz); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + + free(buf); + + return TEST_RES_OK; + +} TEST_END(interrupted_write) + +SUITE_END(dev_tests) diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/test_hydrogen.c b/Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/test_hydrogen.c new file mode 100644 index 0000000..5902a38 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/test_hydrogen.c @@ -0,0 +1,1471 @@ +/* + * test_suites.c + * + * Created on: Jun 19, 2013 + * Author: petera + */ + + +#include "testrunner.h" +#include "test_spiffs.h" +#include "spiffs_nucleus.h" +#include "spiffs.h" +#include +#include +#include +//#include +#include + +SUITE(hydrogen_tests) +void setup() { + _setup(); +} +void teardown() { + _teardown(); +} + +TEST(info) +{ + u32_t used, total; + int res = SPIFFS_info(FS, &total, &used); + TEST_CHECK(res == SPIFFS_OK); + TEST_CHECK(used == 0); + TEST_CHECK(total < __fs.cfg.phys_size); + return TEST_RES_OK; +} +TEST_END(info) + + +TEST(missing_file) +{ + spiffs_file fd = SPIFFS_open(FS, "this_wont_exist", SPIFFS_RDONLY, 0); + TEST_CHECK(fd < 0); + return TEST_RES_OK; +} +TEST_END(missing_file) + + +TEST(bad_fd) +{ + int res; + spiffs_stat s; + spiffs_file fd = SPIFFS_open(FS, "this_wont_exist", SPIFFS_RDONLY, 0); + TEST_CHECK(fd < 0); + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_BAD_DESCRIPTOR); + res = SPIFFS_fremove(FS, fd); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_BAD_DESCRIPTOR); + res = SPIFFS_lseek(FS, fd, 0, SPIFFS_SEEK_CUR); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_BAD_DESCRIPTOR); + res = SPIFFS_read(FS, fd, 0, 0); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_BAD_DESCRIPTOR); + res = SPIFFS_write(FS, fd, 0, 0); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_BAD_DESCRIPTOR); + return TEST_RES_OK; +} +TEST_END(bad_fd) + + +TEST(closed_fd) +{ + int res; + spiffs_stat s; + res = test_create_file("file"); + spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0); + TEST_CHECK(fd >= 0); + SPIFFS_close(FS, fd); + + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + res = SPIFFS_fremove(FS, fd); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + res = SPIFFS_lseek(FS, fd, 0, SPIFFS_SEEK_CUR); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + res = SPIFFS_read(FS, fd, 0, 0); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + res = SPIFFS_write(FS, fd, 0, 0); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + return TEST_RES_OK; +} +TEST_END(closed_fd) + + +TEST(deleted_same_fd) +{ + int res; + spiffs_stat s; + spiffs_file fd; + res = test_create_file("remove"); + fd = SPIFFS_open(FS, "remove", SPIFFS_RDWR, 0); + TEST_CHECK(fd >= 0); + fd = SPIFFS_open(FS, "remove", SPIFFS_RDWR, 0); + TEST_CHECK(fd >= 0); + res = SPIFFS_fremove(FS, fd); + TEST_CHECK(res >= 0); + + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + res = SPIFFS_fremove(FS, fd); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + res = SPIFFS_lseek(FS, fd, 0, SPIFFS_SEEK_CUR); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + res = SPIFFS_read(FS, fd, 0, 0); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + res = SPIFFS_write(FS, fd, 0, 0); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + + return TEST_RES_OK; +} +TEST_END(deleted_same_fd) + + +TEST(deleted_other_fd) +{ + int res; + spiffs_stat s; + spiffs_file fd, fd_orig; + res = test_create_file("remove"); + fd_orig = SPIFFS_open(FS, "remove", SPIFFS_RDWR, 0); + TEST_CHECK(fd_orig >= 0); + fd = SPIFFS_open(FS, "remove", SPIFFS_RDWR, 0); + TEST_CHECK(fd >= 0); + res = SPIFFS_fremove(FS, fd_orig); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd_orig); + + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + res = SPIFFS_fremove(FS, fd); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + res = SPIFFS_lseek(FS, fd, 0, SPIFFS_SEEK_CUR); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + res = SPIFFS_read(FS, fd, 0, 0); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + res = SPIFFS_write(FS, fd, 0, 0); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + + return TEST_RES_OK; +} +TEST_END(deleted_other_fd) + + +TEST(file_by_open) +{ + int res; + spiffs_stat s; + spiffs_file fd = SPIFFS_open(FS, "filebopen", SPIFFS_CREAT, 0); + TEST_CHECK(fd >= 0); + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + TEST_CHECK(strcmp((char*)s.name, "filebopen") == 0); + TEST_CHECK(s.size == 0); + SPIFFS_close(FS, fd); + + fd = SPIFFS_open(FS, "filebopen", SPIFFS_RDONLY, 0); + TEST_CHECK(fd >= 0); + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + TEST_CHECK(strcmp((char*)s.name, "filebopen") == 0); + TEST_CHECK(s.size == 0); + SPIFFS_close(FS, fd); + return TEST_RES_OK; +} +TEST_END(file_by_open) + + +TEST(file_by_creat) +{ + int res; + res = test_create_file("filebcreat"); + TEST_CHECK(res >= 0); + res = SPIFFS_creat(FS, "filebcreat", 0); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS)==SPIFFS_ERR_CONFLICTING_NAME); + return TEST_RES_OK; +} +TEST_END(file_by_creat) + +TEST(list_dir) +{ + int res; + + char *files[4] = { + "file1", + "file2", + "file3", + "file4" + }; + int file_cnt = sizeof(files)/sizeof(char *); + + int i; + + for (i = 0; i < file_cnt; i++) { + res = test_create_file(files[i]); + TEST_CHECK(res >= 0); + } + + spiffs_DIR d; + struct spiffs_dirent e; + struct spiffs_dirent *pe = &e; + + SPIFFS_opendir(FS, "/", &d); + int found = 0; + while ((pe = SPIFFS_readdir(&d, pe))) { + printf(" %s [%04x] size:%i\n", pe->name, pe->obj_id, pe->size); + for (i = 0; i < file_cnt; i++) { + if (strcmp(files[i], pe->name) == 0) { + found++; + break; + } + } + } + SPIFFS_closedir(&d); + + TEST_CHECK(found == file_cnt); + + return TEST_RES_OK; +} +TEST_END(list_dir) + + +TEST(open_by_dirent) { + int res; + + char *files[4] = { + "file1", + "file2", + "file3", + "file4" + }; + int file_cnt = sizeof(files)/sizeof(char *); + + int i; + int size = SPIFFS_DATA_PAGE_SIZE(FS); + + for (i = 0; i < file_cnt; i++) { + res = test_create_and_write_file(files[i], size, size); + TEST_CHECK(res >= 0); + } + + spiffs_DIR d; + struct spiffs_dirent e; + struct spiffs_dirent *pe = &e; + + int found = 0; + SPIFFS_opendir(FS, "/", &d); + while ((pe = SPIFFS_readdir(&d, pe))) { + spiffs_file fd = SPIFFS_open_by_dirent(FS, pe, SPIFFS_RDWR, 0); + TEST_CHECK(fd >= 0); + res = read_and_verify_fd(fd, pe->name); + TEST_CHECK(res == SPIFFS_OK); + fd = SPIFFS_open_by_dirent(FS, pe, SPIFFS_RDWR, 0); + TEST_CHECK(fd >= 0); + res = SPIFFS_fremove(FS, fd); + TEST_CHECK(res == SPIFFS_OK); + SPIFFS_close(FS, fd); + found++; + } + SPIFFS_closedir(&d); + + TEST_CHECK(found == file_cnt); + + found = 0; + SPIFFS_opendir(FS, "/", &d); + while ((pe = SPIFFS_readdir(&d, pe))) { + found++; + } + SPIFFS_closedir(&d); + + TEST_CHECK(found == 0); + + return TEST_RES_OK; + +} TEST_END(open_by_dirent) + + +TEST(rename) { + int res; + + char *src_name = "baah"; + char *dst_name = "booh"; + char *dst_name2 = "beeh"; + int size = SPIFFS_DATA_PAGE_SIZE(FS); + + res = test_create_and_write_file(src_name, size, size); + TEST_CHECK(res >= 0); + + res = SPIFFS_rename(FS, src_name, dst_name); + TEST_CHECK(res >= 0); + + res = SPIFFS_rename(FS, dst_name, dst_name); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_CONFLICTING_NAME); + + res = SPIFFS_rename(FS, src_name, dst_name2); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_NOT_FOUND); + + return TEST_RES_OK; +} TEST_END(rename) + + +TEST(remove_single_by_path) +{ + int res; + spiffs_file fd; + res = test_create_file("remove"); + TEST_CHECK(res >= 0); + res = SPIFFS_remove(FS, "remove"); + TEST_CHECK(res >= 0); + fd = SPIFFS_open(FS, "remove", SPIFFS_RDONLY, 0); + TEST_CHECK(fd < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_NOT_FOUND); + + return TEST_RES_OK; +} +TEST_END(remove_single_by_path) + + +TEST(remove_single_by_fd) +{ + int res; + spiffs_file fd; + res = test_create_file("remove"); + TEST_CHECK(res >= 0); + fd = SPIFFS_open(FS, "remove", SPIFFS_RDWR, 0); + TEST_CHECK(fd >= 0); + res = SPIFFS_fremove(FS, fd); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + fd = SPIFFS_open(FS, "remove", SPIFFS_RDONLY, 0); + TEST_CHECK(fd < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_NOT_FOUND); + + return TEST_RES_OK; +} +TEST_END(remove_single_by_fd) + + +TEST(write_big_file_chunks_page) +{ + int size = ((50*(FS)->cfg.phys_size)/100); + printf(" filesize %i\n", size); + int res = test_create_and_write_file("bigfile", size, SPIFFS_DATA_PAGE_SIZE(FS)); + TEST_CHECK(res >= 0); + res = read_and_verify("bigfile"); + TEST_CHECK(res >= 0); + + return TEST_RES_OK; +} +TEST_END(write_big_file_chunks_page) + + +TEST(write_big_files_chunks_page) +{ + char name[32]; + int f; + int files = 10; + int res; + int size = ((50*(FS)->cfg.phys_size)/100)/files; + printf(" filesize %i\n", size); + for (f = 0; f < files; f++) { + sprintf(name, "bigfile%i", f); + res = test_create_and_write_file(name, size, SPIFFS_DATA_PAGE_SIZE(FS)); + TEST_CHECK(res >= 0); + } + for (f = 0; f < files; f++) { + sprintf(name, "bigfile%i", f); + res = read_and_verify(name); + TEST_CHECK(res >= 0); + } + + return TEST_RES_OK; +} +TEST_END(write_big_files_chunks_page) + + +TEST(write_big_file_chunks_index) +{ + int size = ((50*(FS)->cfg.phys_size)/100); + printf(" filesize %i\n", size); + int res = test_create_and_write_file("bigfile", size, SPIFFS_DATA_PAGE_SIZE(FS) * SPIFFS_OBJ_HDR_IX_LEN(FS)); + TEST_CHECK(res >= 0); + res = read_and_verify("bigfile"); + TEST_CHECK(res >= 0); + + return TEST_RES_OK; +} +TEST_END(write_big_file_chunks_index) + + +TEST(write_big_files_chunks_index) +{ + char name[32]; + int f; + int files = 10; + int res; + int size = ((50*(FS)->cfg.phys_size)/100)/files; + printf(" filesize %i\n", size); + for (f = 0; f < files; f++) { + sprintf(name, "bigfile%i", f); + res = test_create_and_write_file(name, size, SPIFFS_DATA_PAGE_SIZE(FS) * SPIFFS_OBJ_HDR_IX_LEN(FS)); + TEST_CHECK(res >= 0); + } + for (f = 0; f < files; f++) { + sprintf(name, "bigfile%i", f); + res = read_and_verify(name); + TEST_CHECK(res >= 0); + } + + return TEST_RES_OK; +} +TEST_END(write_big_files_chunks_index) + + +TEST(write_big_file_chunks_huge) +{ + int size = (FS_PURE_DATA_PAGES(FS) / 2) * SPIFFS_DATA_PAGE_SIZE(FS) / 2; + printf(" filesize %i\n", size); + int res = test_create_and_write_file("bigfile", size, size); + TEST_CHECK(res >= 0); + res = read_and_verify("bigfile"); + TEST_CHECK(res >= 0); + + return TEST_RES_OK; +} +TEST_END(write_big_file_chunks_huge) + + +TEST(write_big_files_chunks_huge) +{ + char name[32]; + int f; + int files = 10; + int res; + int size = ((50*(FS)->cfg.phys_size)/100)/files; + printf(" filesize %i\n", size); + for (f = 0; f < files; f++) { + sprintf(name, "bigfile%i", f); + res = test_create_and_write_file(name, size, size); + TEST_CHECK(res >= 0); + } + for (f = 0; f < files; f++) { + sprintf(name, "bigfile%i", f); + res = read_and_verify(name); + TEST_CHECK(res >= 0); + } + + return TEST_RES_OK; +} +TEST_END(write_big_files_chunks_huge) + + +TEST(truncate_big_file) +{ + int size = (FS_PURE_DATA_PAGES(FS) / 2) * SPIFFS_DATA_PAGE_SIZE(FS) / 2; + printf(" filesize %i\n", size); + int res = test_create_and_write_file("bigfile", size, size); + TEST_CHECK(res >= 0); + res = read_and_verify("bigfile"); + TEST_CHECK(res >= 0); + spiffs_file fd = SPIFFS_open(FS, "bigfile", SPIFFS_RDWR, 0); + TEST_CHECK(fd > 0); + res = SPIFFS_fremove(FS, fd); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + + fd = SPIFFS_open(FS, "bigfile", SPIFFS_RDWR, 0); + TEST_CHECK(fd < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_NOT_FOUND); + + return TEST_RES_OK; +} +TEST_END(truncate_big_file) + + +TEST(simultaneous_write) { + int res = SPIFFS_creat(FS, "simul1", 0); + TEST_CHECK(res >= 0); + + spiffs_file fd1 = SPIFFS_open(FS, "simul1", SPIFFS_RDWR, 0); + TEST_CHECK(fd1 > 0); + spiffs_file fd2 = SPIFFS_open(FS, "simul1", SPIFFS_RDWR, 0); + TEST_CHECK(fd2 > 0); + spiffs_file fd3 = SPIFFS_open(FS, "simul1", SPIFFS_RDWR, 0); + TEST_CHECK(fd3 > 0); + + u8_t data1 = 1; + u8_t data2 = 2; + u8_t data3 = 3; + + res = SPIFFS_write(FS, fd1, &data1, 1); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd1); + res = SPIFFS_write(FS, fd2, &data2, 1); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd2); + res = SPIFFS_write(FS, fd3, &data3, 1); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd3); + + spiffs_stat s; + res = SPIFFS_stat(FS, "simul1", &s); + TEST_CHECK(res >= 0); + + TEST_CHECK(s.size == 1); + + u8_t rdata; + spiffs_file fd = SPIFFS_open(FS, "simul1", SPIFFS_RDONLY, 0); + TEST_CHECK(fd > 0); + res = SPIFFS_read(FS, fd, &rdata, 1); + TEST_CHECK(res >= 0); + + TEST_CHECK(rdata == data3); + + return TEST_RES_OK; +} +TEST_END(simultaneous_write) + + +TEST(simultaneous_write_append) { + int res = SPIFFS_creat(FS, "simul2", 0); + TEST_CHECK(res >= 0); + + spiffs_file fd1 = SPIFFS_open(FS, "simul2", SPIFFS_RDWR | SPIFFS_APPEND, 0); + TEST_CHECK(fd1 > 0); + spiffs_file fd2 = SPIFFS_open(FS, "simul2", SPIFFS_RDWR | SPIFFS_APPEND, 0); + TEST_CHECK(fd2 > 0); + spiffs_file fd3 = SPIFFS_open(FS, "simul2", SPIFFS_RDWR | SPIFFS_APPEND, 0); + TEST_CHECK(fd3 > 0); + + u8_t data1 = 1; + u8_t data2 = 2; + u8_t data3 = 3; + + res = SPIFFS_write(FS, fd1, &data1, 1); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd1); + res = SPIFFS_write(FS, fd2, &data2, 1); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd2); + res = SPIFFS_write(FS, fd3, &data3, 1); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd3); + + spiffs_stat s; + res = SPIFFS_stat(FS, "simul2", &s); + TEST_CHECK(res >= 0); + + TEST_CHECK(s.size == 3); + + u8_t rdata[3]; + spiffs_file fd = SPIFFS_open(FS, "simul2", SPIFFS_RDONLY, 0); + TEST_CHECK(fd > 0); + res = SPIFFS_read(FS, fd, &rdata, 3); + TEST_CHECK(res >= 0); + + TEST_CHECK(rdata[0] == data1); + TEST_CHECK(rdata[1] == data2); + TEST_CHECK(rdata[2] == data3); + + return TEST_RES_OK; +} +TEST_END(simultaneous_write_append) + +TEST(file_uniqueness) +{ + int res; + spiffs_file fd; + char fname[32]; + int files = ((SPIFFS_CFG_PHYS_SZ(FS) * 75) / 100) / 2 / SPIFFS_CFG_LOG_PAGE_SZ(FS); + //(FS_PURE_DATA_PAGES(FS) / 2) - SPIFFS_PAGES_PER_BLOCK(FS)*8; + int i; + printf(" creating %i files\n", files); + for (i = 0; i < files; i++) { + char content[20]; + sprintf(fname, "file%i", i); + sprintf(content, "%i", i); + res = test_create_file(fname); + TEST_CHECK(res >= 0); + fd = SPIFFS_open(FS, fname, SPIFFS_APPEND | SPIFFS_RDWR, 0); + TEST_CHECK(fd >= 0); + res = SPIFFS_write(FS, fd, content, strlen(content)+1); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + } + printf(" checking %i files\n", files); + for (i = 0; i < files; i++) { + char content[20]; + char ref_content[20]; + sprintf(fname, "file%i", i); + sprintf(content, "%i", i); + fd = SPIFFS_open(FS, fname, SPIFFS_RDONLY, 0); + TEST_CHECK(fd >= 0); + res = SPIFFS_read(FS, fd, ref_content, strlen(content)+1); + TEST_CHECK(res >= 0); + TEST_CHECK(strcmp(ref_content, content) == 0); + SPIFFS_close(FS, fd); + } + printf(" removing %i files\n", files/2); + for (i = 0; i < files; i += 2) { + sprintf(fname, "file%i", i); + res = SPIFFS_remove(FS, fname); + TEST_CHECK(res >= 0); + } + printf(" creating %i files\n", files/2); + for (i = 0; i < files; i += 2) { + char content[20]; + sprintf(fname, "file%i", i); + sprintf(content, "new%i", i); + res = test_create_file(fname); + TEST_CHECK(res >= 0); + fd = SPIFFS_open(FS, fname, SPIFFS_APPEND | SPIFFS_RDWR, 0); + TEST_CHECK(fd >= 0); + res = SPIFFS_write(FS, fd, content, strlen(content)+1); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + } + printf(" checking %i files\n", files); + for (i = 0; i < files; i++) { + char content[20]; + char ref_content[20]; + sprintf(fname, "file%i", i); + if ((i & 1) == 0) { + sprintf(content, "new%i", i); + } else { + sprintf(content, "%i", i); + } + fd = SPIFFS_open(FS, fname, SPIFFS_RDONLY, 0); + TEST_CHECK(fd >= 0); + res = SPIFFS_read(FS, fd, ref_content, strlen(content)+1); + TEST_CHECK(res >= 0); + TEST_CHECK(strcmp(ref_content, content) == 0); + SPIFFS_close(FS, fd); + } + + return TEST_RES_OK; +} +TEST_END(file_uniqueness) + +int create_and_read_back(int size, int chunk) { + char *name = "file"; + spiffs_file fd; + s32_t res; + + u8_t *buf = malloc(size); + MALLOC_CHECK_RETURN_1(buf != NULL, size); + memrand(buf, size); + + res = test_create_file(name); + CHECK(res >= 0); + fd = SPIFFS_open(FS, name, SPIFFS_APPEND | SPIFFS_RDWR, 0); + CHECK(fd >= 0); + res = SPIFFS_write(FS, fd, buf, size); + CHECK(res >= 0); + + spiffs_stat stat; + res = SPIFFS_fstat(FS, fd, &stat); + CHECK(res >= 0); + CHECK(stat.size == size); + + SPIFFS_close(FS, fd); + + fd = SPIFFS_open(FS, name, SPIFFS_RDONLY, 0); + CHECK(fd >= 0); + + u8_t *rbuf = malloc(size); + MALLOC_CHECK_RETURN_1(rbuf != NULL, size); + int offs = 0; + while (offs < size) { + int len = MIN(size - offs, chunk); + res = SPIFFS_read(FS, fd, &rbuf[offs], len); + CHECK(res >= 0); + CHECK(memcmp(&rbuf[offs], &buf[offs], len) == 0); + + offs += chunk; + } + + CHECK(memcmp(&rbuf[0], &buf[0], size) == 0); + + SPIFFS_close(FS, fd); + + free(rbuf); + free(buf); + + return 0; +} + +TEST(read_chunk_1) +{ + TEST_CHECK(create_and_read_back(SPIFFS_DATA_PAGE_SIZE(FS)*8, 1) == 0); + return TEST_RES_OK; +} +TEST_END(read_chunk_1) + + +TEST(read_chunk_page) +{ + TEST_CHECK(create_and_read_back(SPIFFS_DATA_PAGE_SIZE(FS)*(SPIFFS_PAGES_PER_BLOCK(FS) - SPIFFS_OBJ_LOOKUP_PAGES(FS))*2, + SPIFFS_DATA_PAGE_SIZE(FS)) == 0); + return TEST_RES_OK; +} +TEST_END(read_chunk_page) + + +TEST(read_chunk_index) +{ + TEST_CHECK(create_and_read_back(SPIFFS_DATA_PAGE_SIZE(FS)*(SPIFFS_PAGES_PER_BLOCK(FS) - SPIFFS_OBJ_LOOKUP_PAGES(FS))*4, + SPIFFS_DATA_PAGE_SIZE(FS)*(SPIFFS_PAGES_PER_BLOCK(FS) - SPIFFS_OBJ_LOOKUP_PAGES(FS))) == 0); + return TEST_RES_OK; +} +TEST_END(read_chunk_index) + + +TEST(read_chunk_huge) +{ + int sz = (2*(FS)->cfg.phys_size)/15; + TEST_CHECK(create_and_read_back(sz, sz) == 0); + return TEST_RES_OK; +} +TEST_END(read_chunk_huge) + + +TEST(read_beyond) +{ + char *name = "file"; + spiffs_file fd; + s32_t res; + u32_t size = SPIFFS_DATA_PAGE_SIZE(FS)*2; + + u8_t *buf = malloc(size); + MALLOC_CHECK(buf != NULL, size); + memrand(buf, size); + + res = test_create_file(name); + CHECK(res >= 0); + fd = SPIFFS_open(FS, name, SPIFFS_APPEND | SPIFFS_RDWR, 0); + CHECK(fd >= 0); + res = SPIFFS_write(FS, fd, buf, size); + CHECK(res >= 0); + + spiffs_stat stat; + res = SPIFFS_fstat(FS, fd, &stat); + CHECK(res >= 0); + CHECK(stat.size == size); + + SPIFFS_close(FS, fd); + + fd = SPIFFS_open(FS, name, SPIFFS_RDONLY, 0); + CHECK(fd >= 0); + + u8_t *rbuf = malloc(size+10); + MALLOC_CHECK(rbuf != NULL, size+10); + res = SPIFFS_read(FS, fd, rbuf, size+10); + + SPIFFS_close(FS, fd); + + free(rbuf); + free(buf); + + TEST_CHECK(res == size); + + return TEST_RES_OK; +} +TEST_END(read_beyond) + + +TEST(bad_index_1) { + int size = SPIFFS_DATA_PAGE_SIZE(FS)*3; + int res = test_create_and_write_file("file", size, size); + TEST_CHECK(res >= 0); + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0); + TEST_CHECK(fd > 0); + spiffs_stat s; + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + + // modify object index, find object index header + spiffs_page_ix pix; + res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix); + TEST_CHECK(res >= 0); + + // set object index entry 2 to a bad page, free + u32_t addr = SPIFFS_PAGE_TO_PADDR(FS, pix) + sizeof(spiffs_page_object_ix_header) + 2 * sizeof(spiffs_page_ix); + spiffs_page_ix bad_pix_ref = (spiffs_page_ix)-1; + area_write(addr, (u8_t*)&bad_pix_ref, sizeof(spiffs_page_ix)); + +#if SPIFFS_CACHE + // delete all cache + spiffs_cache *cache = spiffs_get_cache(FS); + cache->cpage_use_map = 0; +#endif + + res = read_and_verify("file"); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_INDEX_REF_FREE); + + return TEST_RES_OK; +} TEST_END(bad_index_1) + + +TEST(bad_index_2) { + int size = SPIFFS_DATA_PAGE_SIZE(FS)*3; + int res = test_create_and_write_file("file", size, size); + TEST_CHECK(res >= 0); + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0); + TEST_CHECK(fd > 0); + spiffs_stat s; + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + + // modify object index, find object index header + spiffs_page_ix pix; + res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix); + TEST_CHECK(res >= 0); + + // set object index entry 2 to a bad page, lu + u32_t addr = SPIFFS_PAGE_TO_PADDR(FS, pix) + sizeof(spiffs_page_object_ix_header) + 2 * sizeof(spiffs_page_ix); + spiffs_page_ix bad_pix_ref = SPIFFS_OBJ_LOOKUP_PAGES(FS)-1; + area_write(addr, (u8_t*)&bad_pix_ref, sizeof(spiffs_page_ix)); + +#if SPIFFS_CACHE + // delete all cache + spiffs_cache *cache = spiffs_get_cache(FS); + cache->cpage_use_map = 0; +#endif + + res = read_and_verify("file"); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_INDEX_REF_LU); + + return TEST_RES_OK; +} TEST_END(bad_index_2) + + +TEST(lseek_simple_modification) { + int res; + spiffs_file fd; + char *fname = "seekfile"; + int i; + int len = 4096; + fd = SPIFFS_open(FS, fname, SPIFFS_TRUNC | SPIFFS_CREAT | SPIFFS_RDWR, 0); + TEST_CHECK(fd > 0); + int pfd = open(make_test_fname(fname), O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + u8_t *buf = malloc(len); + MALLOC_CHECK(buf != NULL, len); + memrand(buf, len); + res = SPIFFS_write(FS, fd, buf, len); + TEST_CHECK(res >= 0); + write(pfd, buf, len); + free(buf); + res = read_and_verify(fname); + TEST_CHECK(res >= 0); + + res = SPIFFS_lseek(FS, fd, len/2, SPIFFS_SEEK_SET); + TEST_CHECK(res >= 0); + lseek(pfd, len/2, SEEK_SET); + len = len/4; + buf = malloc(len); + MALLOC_CHECK(buf != NULL, len); + memrand(buf, len); + res = SPIFFS_write(FS, fd, buf, len); + TEST_CHECK(res >= 0); + write(pfd, buf, len); + free(buf); + + res = read_and_verify(fname); + TEST_CHECK(res >= 0); + + SPIFFS_close(FS, fd); + close(pfd); + + return TEST_RES_OK; +} +TEST_END(lseek_simple_modification) + + +TEST(lseek_modification_append) { + int res; + spiffs_file fd; + char *fname = "seekfile"; + int i; + int len = 4096; + fd = SPIFFS_open(FS, fname, SPIFFS_TRUNC | SPIFFS_CREAT | SPIFFS_RDWR, 0); + TEST_CHECK(fd > 0); + int pfd = open(make_test_fname(fname), O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + u8_t *buf = malloc(len); + MALLOC_CHECK(buf != NULL, len); + memrand(buf, len); + res = SPIFFS_write(FS, fd, buf, len); + TEST_CHECK(res >= 0); + write(pfd, buf, len); + free(buf); + res = read_and_verify(fname); + TEST_CHECK(res >= 0); + + res = SPIFFS_lseek(FS, fd, len/2, SPIFFS_SEEK_SET); + TEST_CHECK(res >= 0); + lseek(pfd, len/2, SEEK_SET); + + buf = malloc(len); + MALLOC_CHECK(buf != NULL, len); + memrand(buf, len); + res = SPIFFS_write(FS, fd, buf, len); + TEST_CHECK(res >= 0); + write(pfd, buf, len); + free(buf); + + res = read_and_verify(fname); + TEST_CHECK(res >= 0); + + SPIFFS_close(FS, fd); + close(pfd); + + return TEST_RES_OK; +} +TEST_END(lseek_modification_append) + + +TEST(lseek_modification_append_multi) { + int res; + spiffs_file fd; + char *fname = "seekfile"; + int len = 1024; + int runs = (FS_PURE_DATA_PAGES(FS) / 2) * SPIFFS_DATA_PAGE_SIZE(FS) / (len/2); + + fd = SPIFFS_open(FS, fname, SPIFFS_TRUNC | SPIFFS_CREAT | SPIFFS_RDWR, 0); + TEST_CHECK(fd > 0); + int pfd = open(make_test_fname(fname), O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + u8_t *buf = malloc(len); + MALLOC_CHECK(buf != NULL, len); + memrand(buf, len); + res = SPIFFS_write(FS, fd, buf, len); + TEST_CHECK(res >= 0); + write(pfd, buf, len); + free(buf); + res = read_and_verify(fname); + TEST_CHECK(res >= 0); + + while (runs--) { + res = SPIFFS_lseek(FS, fd, -len/2, SPIFFS_SEEK_END); + TEST_CHECK(res >= 0); + lseek(pfd, -len/2, SEEK_END); + + buf = malloc(len); + MALLOC_CHECK(buf != NULL, len); + memrand(buf, len); + res = SPIFFS_write(FS, fd, buf, len); + TEST_CHECK(res >= 0); + write(pfd, buf, len); + free(buf); + + res = read_and_verify(fname); + TEST_CHECK(res >= 0); + } + + SPIFFS_close(FS, fd); + close(pfd); + + return TEST_RES_OK; +} +TEST_END(lseek_modification_append_multi) + + +TEST(lseek_read) { + int res; + spiffs_file fd; + char *fname = "seekfile"; + int len = (FS_PURE_DATA_PAGES(FS) / 2) * SPIFFS_DATA_PAGE_SIZE(FS) / 2; + int runs = 100000; + + fd = SPIFFS_open(FS, fname, SPIFFS_TRUNC | SPIFFS_CREAT | SPIFFS_RDWR, 0); + TEST_CHECK(fd > 0); + u8_t *refbuf = malloc(len); + MALLOC_CHECK(refbuf != NULL, len); + memrand(refbuf, len); + res = SPIFFS_write(FS, fd, refbuf, len); + TEST_CHECK(res >= 0); + + int offs = 0; + res = SPIFFS_lseek(FS, fd, 0, SPIFFS_SEEK_SET); + TEST_CHECK(res >= 0); + + while (runs--) { + int i; + u8_t buf[64]; + if (offs + 41 + sizeof(buf) >= len) { + offs = (offs + 41 + sizeof(buf)) % len; + res = SPIFFS_lseek(FS, fd, offs, SPIFFS_SEEK_SET); + TEST_CHECK(res >= 0); + } + res = SPIFFS_lseek(FS, fd, 41, SPIFFS_SEEK_CUR); + TEST_CHECK(res >= 0); + offs += 41; + res = SPIFFS_read(FS, fd, buf, sizeof(buf)); + TEST_CHECK(res >= 0); + for (i = 0; i < sizeof(buf); i++) { + if (buf[i] != refbuf[offs+i]) { + printf(" mismatch at offs %i\n", offs); + } + TEST_CHECK(buf[i] == refbuf[offs+i]); + } + offs += sizeof(buf); + + res = SPIFFS_lseek(FS, fd, -((u32_t)sizeof(buf)+11), SPIFFS_SEEK_CUR); + TEST_CHECK(res >= 0); + offs -= (sizeof(buf)+11); + res = SPIFFS_read(FS, fd, buf, sizeof(buf)); + TEST_CHECK(res >= 0); + for (i = 0; i < sizeof(buf); i++) { + if (buf[i] != refbuf[offs+i]) { + printf(" mismatch at offs %i\n", offs); + } + TEST_CHECK(buf[i] == refbuf[offs+i]); + } + offs += sizeof(buf); + } + + free(refbuf); + SPIFFS_close(FS, fd); + + return TEST_RES_OK; +} +TEST_END(lseek_read) + + +TEST(gc_quick) +{ + char name[32]; + int f; + int size = SPIFFS_DATA_PAGE_SIZE(FS); + int files = (SPIFFS_PAGES_PER_BLOCK(FS) - SPIFFS_OBJ_LOOKUP_PAGES(FS))/2; + int res; + + // negative, try quick gc on clean sys + res = SPIFFS_gc_quick(FS, 0); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_NO_DELETED_BLOCKS); + + // fill block with files + for (f = 0; f < files; f++) { + sprintf(name, "file%i", f); + res = test_create_and_write_file(name, size, 1); + TEST_CHECK(res >= 0); + } + for (f = 0; f < files; f++) { + sprintf(name, "file%i", f); + res = read_and_verify(name); + TEST_CHECK(res >= 0); + } + // remove all files in block + for (f = 0; f < files; f++) { + sprintf(name, "file%i", f); + res = SPIFFS_remove(FS, name); + TEST_CHECK(res >= 0); + } + + // do a quick gc + res = SPIFFS_gc_quick(FS, 0); + TEST_CHECK(res >= 0); + + // fill another block with files but two pages + for (f = 0; f < files - 1; f++) { + sprintf(name, "file%i", f); + res = test_create_and_write_file(name, size, 1); + TEST_CHECK(res >= 0); + } + for (f = 0; f < files - 1; f++) { + sprintf(name, "file%i", f); + res = read_and_verify(name); + TEST_CHECK(res >= 0); + } + // remove all files in block leaving two free pages in block + for (f = 0; f < files - 1; f++) { + sprintf(name, "file%i", f); + res = SPIFFS_remove(FS, name); + TEST_CHECK(res >= 0); + } + + // negative, try quick gc where no fully deleted blocks exist + res = SPIFFS_gc_quick(FS, 0); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_NO_DELETED_BLOCKS); + + // positive, try quick gc where allowing two free pages + res = SPIFFS_gc_quick(FS, 2); + TEST_CHECK(res >= 0); + + return TEST_RES_OK; +} +TEST_END(gc_quick) + + +TEST(write_small_file_chunks_1) +{ + int res = test_create_and_write_file("smallfile", 256, 1); + TEST_CHECK(res >= 0); + res = read_and_verify("smallfile"); + TEST_CHECK(res >= 0); + + return TEST_RES_OK; +} +TEST_END(write_small_file_chunks_1) + + +TEST(write_small_files_chunks_1) +{ + char name[32]; + int f; + int size = 512; + int files = ((20*(FS)->cfg.phys_size)/100)/size; + int res; + for (f = 0; f < files; f++) { + sprintf(name, "smallfile%i", f); + res = test_create_and_write_file(name, size, 1); + TEST_CHECK(res >= 0); + } + for (f = 0; f < files; f++) { + sprintf(name, "smallfile%i", f); + res = read_and_verify(name); + TEST_CHECK(res >= 0); + } + + return TEST_RES_OK; +} +TEST_END(write_small_files_chunks_1) + +TEST(write_big_file_chunks_1) +{ + int size = ((50*(FS)->cfg.phys_size)/100); + printf(" filesize %i\n", size); + int res = test_create_and_write_file("bigfile", size, 1); + TEST_CHECK(res >= 0); + res = read_and_verify("bigfile"); + TEST_CHECK(res >= 0); + + return TEST_RES_OK; +} +TEST_END(write_big_file_chunks_1) + +TEST(write_big_files_chunks_1) +{ + char name[32]; + int f; + int files = 10; + int res; + int size = ((50*(FS)->cfg.phys_size)/100)/files; + printf(" filesize %i\n", size); + for (f = 0; f < files; f++) { + sprintf(name, "bigfile%i", f); + res = test_create_and_write_file(name, size, 1); + TEST_CHECK(res >= 0); + } + for (f = 0; f < files; f++) { + sprintf(name, "bigfile%i", f); + res = read_and_verify(name); + TEST_CHECK(res >= 0); + } + + return TEST_RES_OK; +} +TEST_END(write_big_files_chunks_1) + + +TEST(long_run_config_many_small_one_long) +{ + tfile_conf cfgs[] = { + { .tsize = LARGE, .ttype = MODIFIED, .tlife = LONG + }, + { .tsize = SMALL, .ttype = UNTAMPERED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = UNTAMPERED, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = MODIFIED, .tlife = MEDIUM + }, + { .tsize = SMALL, .ttype = REWRITTEN, .tlife = LONG + }, + { .tsize = SMALL, .ttype = MODIFIED, .tlife = MEDIUM + }, + { .tsize = SMALL, .ttype = MODIFIED, .tlife = MEDIUM + }, + { .tsize = SMALL, .ttype = REWRITTEN, .tlife = LONG + }, + { .tsize = SMALL, .ttype = REWRITTEN, .tlife = MEDIUM + }, + { .tsize = SMALL, .ttype = MODIFIED, .tlife = LONG + }, + { .tsize = SMALL, .ttype = MODIFIED, .tlife = MEDIUM + }, + { .tsize = SMALL, .ttype = REWRITTEN, .tlife = LONG + }, + { .tsize = SMALL, .ttype = REWRITTEN, .tlife = MEDIUM + }, + { .tsize = SMALL, .ttype = MODIFIED, .tlife = LONG + }, + }; + + int res = run_file_config(sizeof(cfgs)/sizeof(cfgs[0]), &cfgs[0], 206, 5, 1); + TEST_CHECK(res >= 0); + return TEST_RES_OK; +} +TEST_END(long_run_config_many_small_one_long) + +TEST(long_run_config_many_medium) +{ + tfile_conf cfgs[] = { + { .tsize = MEDIUM, .ttype = MODIFIED, .tlife = LONG + }, + { .tsize = MEDIUM, .ttype = APPENDED, .tlife = LONG + }, + { .tsize = LARGE, .ttype = MODIFIED, .tlife = LONG + }, + { .tsize = MEDIUM, .ttype = APPENDED, .tlife = LONG + }, + { .tsize = MEDIUM, .ttype = MODIFIED, .tlife = LONG + }, + { .tsize = MEDIUM, .ttype = MODIFIED, .tlife = LONG + }, + { .tsize = MEDIUM, .ttype = APPENDED, .tlife = LONG + }, + { .tsize = LARGE, .ttype = MODIFIED, .tlife = LONG + }, + { .tsize = MEDIUM, .ttype = APPENDED, .tlife = LONG + }, + { .tsize = MEDIUM, .ttype = MODIFIED, .tlife = LONG + }, + { .tsize = MEDIUM, .ttype = MODIFIED, .tlife = LONG + }, + { .tsize = MEDIUM, .ttype = APPENDED, .tlife = LONG + }, + { .tsize = LARGE, .ttype = MODIFIED, .tlife = LONG + }, + { .tsize = MEDIUM, .ttype = APPENDED, .tlife = LONG + }, + { .tsize = MEDIUM, .ttype = MODIFIED, .tlife = LONG + }, + }; + + int res = run_file_config(sizeof(cfgs)/sizeof(cfgs[0]), &cfgs[0], 305, 5, 1); + TEST_CHECK(res >= 0); + return TEST_RES_OK; +} +TEST_END(long_run_config_many_medium) + + +TEST(long_run_config_many_small) +{ + tfile_conf cfgs[] = { + { .tsize = SMALL, .ttype = APPENDED, .tlife = LONG + }, + { .tsize = SMALL, .ttype = MODIFIED, .tlife = MEDIUM + }, + { .tsize = SMALL, .ttype = MODIFIED, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = APPENDED, .tlife = MEDIUM + }, + { .tsize = SMALL, .ttype = APPENDED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = MEDIUM + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = MEDIUM + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = REWRITTEN, .tlife = MEDIUM + }, + { .tsize = SMALL, .ttype = REWRITTEN, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = UNTAMPERED, .tlife = MEDIUM + }, + { .tsize = SMALL, .ttype = UNTAMPERED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = MEDIUM + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = MEDIUM + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = MODIFIED, .tlife = MEDIUM + }, + { .tsize = SMALL, .ttype = MODIFIED, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = APPENDED, .tlife = MEDIUM + }, + { .tsize = SMALL, .ttype = APPENDED, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = APPENDED, .tlife = LONG + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = MEDIUM + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = MEDIUM + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = REWRITTEN, .tlife = MEDIUM + }, + { .tsize = SMALL, .ttype = REWRITTEN, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = UNTAMPERED, .tlife = MEDIUM + }, + { .tsize = SMALL, .ttype = UNTAMPERED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = MEDIUM + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = MEDIUM + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = MODIFIED, .tlife = MEDIUM + }, + { .tsize = SMALL, .ttype = MODIFIED, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = APPENDED, .tlife = MEDIUM + }, + { .tsize = SMALL, .ttype = APPENDED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = MEDIUM + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = MEDIUM + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = REWRITTEN, .tlife = MEDIUM + }, + { .tsize = SMALL, .ttype = REWRITTEN, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = UNTAMPERED, .tlife = MEDIUM + }, + { .tsize = SMALL, .ttype = UNTAMPERED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = MEDIUM + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = MEDIUM + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = MODIFIED, .tlife = MEDIUM + }, + { .tsize = SMALL, .ttype = MODIFIED, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = APPENDED, .tlife = MEDIUM + }, + { .tsize = SMALL, .ttype = APPENDED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = MEDIUM + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = MEDIUM + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = REWRITTEN, .tlife = MEDIUM + }, + { .tsize = SMALL, .ttype = REWRITTEN, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = UNTAMPERED, .tlife = MEDIUM + }, + { .tsize = SMALL, .ttype = UNTAMPERED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = MEDIUM + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = MEDIUM + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = SHORT + }, + }; + + int res = run_file_config(sizeof(cfgs)/sizeof(cfgs[0]), &cfgs[0], 115, 6, 0); + TEST_CHECK(res >= 0); + return TEST_RES_OK; +} +TEST_END(long_run_config_many_small) + + +TEST(long_run) +{ + tfile_conf cfgs[] = { + { .tsize = EMPTY, .ttype = APPENDED, .tlife = MEDIUM + }, + { .tsize = SMALL, .ttype = REWRITTEN, .tlife = SHORT + }, + { .tsize = MEDIUM, .ttype = MODIFIED, .tlife = SHORT + }, + { .tsize = MEDIUM, .ttype = APPENDED, .tlife = SHORT + }, + }; + + int macro_runs = 500; + printf(" "); + u32_t clob_size = SPIFFS_CFG_PHYS_SZ(FS)/4; + int res = test_create_and_write_file("long_clobber", clob_size, clob_size); + TEST_CHECK(res >= 0); + + res = read_and_verify("long_clobber"); + TEST_CHECK(res >= 0); + + while (macro_runs--) { + //printf(" ---- run %i ----\n", macro_runs); + if ((macro_runs % 20) == 0) { + printf("."); + fflush(stdout); + } + res = run_file_config(sizeof(cfgs)/sizeof(cfgs[0]), &cfgs[0], 11, 2, 0); + TEST_CHECK(res >= 0); + } + printf("\n"); + + res = read_and_verify("long_clobber"); + TEST_CHECK(res >= 0); + + res = SPIFFS_check(FS); + TEST_CHECK(res >= 0); + + return TEST_RES_OK; +} +TEST_END(long_run) + +SUITE_END(hydrogen_tests) + diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/test_main.c b/Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/test_main.c new file mode 100644 index 0000000..29b9a92 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/test_main.c @@ -0,0 +1,103 @@ +#include "esp_common.h" +#include "testrunner.h" +#include +#include "spiffs_test_params.h" + +enum { + CMD_SPIFFS, + CMD_END, +}; + +#define SSC_CMD_N (CMD_END + 1) + +LOCAL void spiffs_test_init(void); + +LOCAL ssc_cmd_t sscCmdSet[SSC_CMD_N] = { + {"fs", CMD_T_SYNC, CMD_SPIFFS, spiffs_test_init, NULL}, + {"", CMD_T_ASYNC, CMD_END, NULL, NULL} +}; + +void spiffs_test_init(void) +{ + char *argv[10], pLine[128]; + int argc; + + strcpy(pLine, ssc_param_str()); + argc = ssc_parse_param(pLine, argv); + + run_tests(argc, argv); +} + +void spiffs_test_help(void) +{ + printf("\nhelp:\n"); + printf("$ fs \n"); +} + +void spiffs_fs1_init(void) +{ + struct esp_spiffs_config config; + + config.phys_size = FS1_FLASH_SIZE; + config.phys_addr = FS1_FLASH_ADDR; + config.phys_erase_block = SECTOR_SIZE; + config.log_block_size = LOG_BLOCK; + config.log_page_size = LOG_PAGE; + config.fd_buf_size = FD_BUF_SIZE * 2; + config.cache_buf_size = CACHE_BUF_SIZE; + + esp_spiffs_init(&config); +} + +/****************************************************************************** + * 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 user_rf_cal_sector_set(void) +{ + 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; + + default: + rf_cal_sec = 0; + break; + } + + return rf_cal_sec; +} + +void user_init(void) +{ + spiffs_fs1_init(); + + ssc_attach(SSC_BR_74880); + ssc_register(sscCmdSet, SSC_CMD_N, spiffs_test_help); +} + diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/test_spiffs.c b/Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/test_spiffs.c new file mode 100644 index 0000000..f851987 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/test_spiffs.c @@ -0,0 +1,907 @@ +/* + * test_spiffs.c + * + * Created on: Jun 19, 2013 + * Author: petera + */ + + +#include +#include +#include + +#include "spiffs.h" +#include "spiffs_nucleus.h" + +#include "testrunner.h" + +#include "test_spiffs.h" + +#include +#include +#include +//#include +#include +#include "spiffs_test_params.h" + +//#define AREA(x) area[(x) - addr_offset] + +//static unsigned char area[PHYS_FLASH_SIZE]; +static u32_t addr_offset = 0; + +static int erases[FS2_FLASH_SIZE/SECTOR_SIZE]; +static char _path[256]; +static u32_t bytes_rd = 0; +static u32_t bytes_wr = 0; +static u32_t reads = 0; +static u32_t writes = 0; +static u32_t error_after_bytes_written = 0; +static u32_t error_after_bytes_read = 0; +static char error_after_bytes_written_once_only = 0; +static char error_after_bytes_read_once_only = 0; +static char log_flash_ops = 1; +static u32_t fs_check_fixes = 0; + +spiffs __fs; +static u8_t _work[LOG_PAGE * 2]; +static u8_t _fds[FD_BUF_SIZE * 2]; +static u8_t _cache[CACHE_BUF_SIZE]; + +static int check_valid_flash = 1; + +#define TEST_PATH "test_data/" + +char *make_test_fname(const char *name) { + sprintf(_path, "%s%s", TEST_PATH, name); + return _path; +} + +void clear_test_path() { +//TODO: need to add later +#if 0 + DIR *dp; + struct dirent *ep; + dp = opendir(TEST_PATH); + + if (dp != NULL) { + while ((ep = readdir(dp))) { + if (ep->d_name[0] != '.') { + sprintf(_path, "%s%s", TEST_PATH, ep->d_name); + remove(_path); + } + } + closedir(dp); + } +#endif +} + +#define FLASH_UNIT_SIZE 4 + +static s32_t esp_spiffs_readwrite(u32_t addr, u32_t size, u8_t *p, int write) +{ + /* + * With proper configurarion spiffs never reads or writes more than + * LOG_PAGE_SIZE + */ + + if (size > __fs.cfg.log_page_size) { + printf("Invalid size provided to read/write (%d)\n\r", (int) size); + return SPIFFS_ERR_NOT_CONFIGURED; + } + + char tmp_buf[__fs.cfg.log_page_size + FLASH_UNIT_SIZE * 2]; + u32_t aligned_addr = addr & (-FLASH_UNIT_SIZE); + u32_t aligned_size = + ((size + (FLASH_UNIT_SIZE - 1)) & -FLASH_UNIT_SIZE) + FLASH_UNIT_SIZE; + + int res = spi_flash_read(aligned_addr, (u32_t *) tmp_buf, aligned_size); + + if (res != 0) { + printf("spi_flash_read failed: %d (%d, %d)\n\r", res, (int) aligned_addr, + (int) aligned_size); + return res; + } + + if (!write) { + memcpy(p, tmp_buf + (addr - aligned_addr), size); + return SPIFFS_OK; + } + + memcpy(tmp_buf + (addr - aligned_addr), p, size); + + res = spi_flash_write(aligned_addr, (u32_t *) tmp_buf, aligned_size); + + if (res != 0) { +// printf("spi_flash_write failed: %d (%d, %d)\n\r", res, +// (int) aligned_addr, (int) aligned_size); + return res; + } + + return SPIFFS_OK; +} + +static s32_t esp_spiffs_read(u32_t addr, u32_t size, u8_t *dst) +{ + return esp_spiffs_readwrite(addr, size, dst, 0); +} + +static s32_t esp_spiffs_write(u32_t addr, u32_t size, u8_t *src) +{ + return esp_spiffs_readwrite(addr, size, src, 1); +} + +static s32_t esp_spiffs_erase(u32_t addr, u32_t size) +{ + /* + * With proper configurarion spiffs always + * provides here sector address & sector size + */ + if (size != __fs.cfg.phys_erase_block || addr % __fs.cfg.phys_erase_block != 0) { + printf("Invalid size provided to esp_spiffs_erase (%d, %d)\n\r", + (int) addr, (int) size); + return SPIFFS_ERR_NOT_CONFIGURED; + } + + return spi_flash_erase_sector(addr / __fs.cfg.phys_erase_block); +} + + +static s32_t _read(u32_t addr, u32_t size, u8_t *dst) { + if (log_flash_ops) { + bytes_rd += size; + reads++; + if (error_after_bytes_read > 0 && bytes_rd >= error_after_bytes_read) { + if (error_after_bytes_read_once_only) { + error_after_bytes_read = 0; + } + return SPIFFS_ERR_TEST; + } + } + if (addr < __fs.cfg.phys_addr) { + printf("FATAL read addr too low %08x < %08x\n", addr, FS2_FLASH_ADDR); + exit(0); + } + if (addr + size > __fs.cfg.phys_addr + __fs.cfg.phys_size) { + printf("FATAL read addr too high %08x + %08x > %08x\n", addr, size, FS2_FLASH_ADDR + FS2_FLASH_SIZE); + exit(0); + } + + return esp_spiffs_read(addr, size, dst); +} + +static s32_t _write(u32_t addr, u32_t size, u8_t *src) { + int i; + //printf("wr %08x %i\n", addr, size); + if (log_flash_ops) { + bytes_wr += size; + writes++; + if (error_after_bytes_written > 0 && bytes_wr >= error_after_bytes_written) { + if (error_after_bytes_written_once_only) { + error_after_bytes_written = 0; + } + return SPIFFS_ERR_TEST; + } + } + + if (addr < __fs.cfg.phys_addr) { + printf("FATAL write addr too low %08x < %08x\n", addr, FS2_FLASH_ADDR); + exit(0); + } + if (addr + size > __fs.cfg.phys_addr + __fs.cfg.phys_size) { + printf("FATAL write addr too high %08x + %08x > %08x\n", addr, size, FS2_FLASH_ADDR + FS2_FLASH_SIZE); + exit(0); + } + +#if 0 + for (i = 0; i < size; i++) { + if (((addr + i) & (__fs.cfg.log_page_size-1)) != offsetof(spiffs_page_header, flags)) { + if (check_valid_flash && ((AREA(addr + i) ^ src[i]) & src[i])) { + printf("trying to write %02x to %02x at addr %08x\n", src[i], AREA(addr + i), addr+i); + spiffs_page_ix pix = (addr + i) / LOG_PAGE; + dump_page(&__fs, pix); + return -1; + } + } + AREA(addr + i) &= src[i]; + } +#endif + + return esp_spiffs_write(addr, size, src); +} + +static s32_t _erase(u32_t addr, u32_t size) { + if (addr & (__fs.cfg.phys_erase_block-1)) { + printf("trying to erase at addr %08x, out of boundary\n", addr); + return -1; + } + if (size & (__fs.cfg.phys_erase_block-1)) { + printf("trying to erase at with size %08x, out of boundary\n", size); + return -1; + } + erases[(addr-__fs.cfg.phys_addr)/__fs.cfg.phys_erase_block]++; + return esp_spiffs_erase(addr, size); +} + +void hexdump_mem(u8_t *b, u32_t len) { + while (len--) { + if ((((int)b)&0x1f) == 0) { + printf("\n"); + } + printf("%02x", *b++); + } + printf("\n"); +} + +void hexdump(u32_t addr, u32_t len) { +//TODO: need to add later +#if 0 + int remainder = (addr % 32) == 0 ? 0 : 32 - (addr % 32); + u32_t a; + for (a = addr - remainder; a < addr+len; a++) { + if ((a & 0x1f) == 0) { + if (a != addr) { + printf(" "); + int j; + for (j = 0; j < 32; j++) { + if (a-32+j < addr) + printf(" "); + else { + printf("%c", (AREA(a-32+j) < 32 || AREA(a-32+j) >= 0x7f) ? '.' : AREA(a-32+j)); + } + } + } + printf("%s %08x: ", a<=addr ? "":"\n", a); + } + if (a < addr) { + printf(" "); + } else { + printf("%02x", AREA(a)); + } + } + int j; + printf(" "); + for (j = 0; j < 32; j++) { + if (a-32+j < addr) + printf(" "); + else { + printf("%c", (AREA(a-32+j) < 32 || AREA(a-32+j) >= 0x7f) ? '.' : AREA(a-32+j)); + } + } + printf("\n"); +#endif +} + +void dump_page(spiffs *fs, spiffs_page_ix p) { +//TODO: need to add later +#if 0 + printf("page %04x ", p); + u32_t addr = SPIFFS_PAGE_TO_PADDR(fs, p); + if (p % SPIFFS_PAGES_PER_BLOCK(fs) < SPIFFS_OBJ_LOOKUP_PAGES(fs)) { + // obj lu page + printf("OBJ_LU"); + } else { + u32_t obj_id_addr = SPIFFS_BLOCK_TO_PADDR(fs, SPIFFS_BLOCK_FOR_PAGE(fs , p)) + + SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, p) * sizeof(spiffs_obj_id); + spiffs_obj_id obj_id = *((spiffs_obj_id *)&AREA(obj_id_addr)); + // data page + spiffs_page_header *ph = (spiffs_page_header *)&AREA(addr); + printf("DATA %04x:%04x ", obj_id, ph->span_ix); + printf("%s", ((ph->flags & SPIFFS_PH_FLAG_FINAL) == 0) ? "FIN " : "fin "); + printf("%s", ((ph->flags & SPIFFS_PH_FLAG_DELET) == 0) ? "DEL " : "del "); + printf("%s", ((ph->flags & SPIFFS_PH_FLAG_INDEX) == 0) ? "IDX " : "idx "); + printf("%s", ((ph->flags & SPIFFS_PH_FLAG_USED) == 0) ? "USD " : "usd "); + printf("%s ", ((ph->flags & SPIFFS_PH_FLAG_IXDELE) == 0) ? "IDL " : "idl "); + if (obj_id & SPIFFS_OBJ_ID_IX_FLAG) { + // object index + printf("OBJ_IX"); + if (ph->span_ix == 0) { + printf("_HDR "); + spiffs_page_object_ix_header *oix_hdr = (spiffs_page_object_ix_header *)&AREA(addr); + printf("'%s' %i bytes type:%02x", oix_hdr->name, oix_hdr->size, oix_hdr->type); + } + } else { + // data page + printf("CONTENT"); + } + } + printf("\n"); + u32_t len = fs->cfg.log_page_size; + hexdump(addr, len); +#endif +} + +void area_write(u32_t addr, u8_t *buf, u32_t size) { + u32_t phys_erase_block = __fs.cfg.phys_erase_block; + u32_t addr_align = addr & ~(phys_erase_block - 1); + u8_t sec_num = (addr + size - addr_align - 1) / phys_erase_block + 1; + u32_t buf_index = 0; + u8_t *bbuf = malloc(phys_erase_block); + + MALLOC_CHECK_RETURN(bbuf != NULL, phys_erase_block); + + int i, j; + for (i = 0; i < sec_num; i++) { + spi_flash_read(addr_align + i * phys_erase_block, (u32_t *)bbuf, phys_erase_block); + spi_flash_erase_sector((addr_align + i * phys_erase_block) / phys_erase_block); + + for (j = buf_index; + ((addr - i * phys_erase_block) % phys_erase_block + j) < phys_erase_block && j < size; + j++) { + bbuf[addr % phys_erase_block + j] = buf[j]; + } + + buf_index = j; + spi_flash_write(addr_align + i * phys_erase_block, (u32_t *)bbuf, phys_erase_block); + } + + free(bbuf); +} + +void area_read(u32_t addr, u8_t *buf, u32_t size) { + u32_t addr_align = addr & ~(3); + u8_t read_num = (addr + size - addr_align - 1) / 4 + 1; + u8_t *bbuf = malloc(read_num * 4); + + MALLOC_CHECK_RETURN(bbuf != NULL, read_num * 4); + + spi_flash_read(addr, (u32_t *)bbuf, read_num * 4); + memcpy(buf, &bbuf[addr & 3], size); + free(bbuf); +} + +void dump_erase_counts(spiffs *fs) { + spiffs_block_ix bix; + printf(" BLOCK |\n"); + printf(" AGE COUNT|\n"); + for (bix = 0; bix < fs->block_count; bix++) { + printf("----%3i ----|", bix); + } + printf("\n"); + for (bix = 0; bix < fs->block_count; bix++) { + spiffs_obj_id erase_mark; + _spiffs_rd(fs, 0, 0, SPIFFS_ERASE_COUNT_PADDR(fs, bix), sizeof(spiffs_obj_id), (u8_t *)&erase_mark); + if (erases[bix] == 0) { + printf(" |"); + } else { + printf("%7i %4i|", (fs->max_erase_count - erase_mark), erases[bix]); + } + } + printf("\n"); +} + +void dump_flash_access_stats() { + printf(" RD: %10i reads %10i bytes %10i avg bytes/read\n", reads, bytes_rd, reads == 0 ? 0 : (bytes_rd / reads)); + printf(" WR: %10i writes %10i bytes %10i avg bytes/write\n", writes, bytes_wr, writes == 0 ? 0 : (bytes_wr / writes)); +} + + +static u32_t old_perc = 999; +static void spiffs_check_cb_f(spiffs_check_type type, spiffs_check_report report, + u32_t arg1, u32_t arg2) { +/* if (report == SPIFFS_CHECK_PROGRESS && old_perc != arg1) { + old_perc = arg1; + printf("CHECK REPORT: "); + switch(type) { + case SPIFFS_CHECK_LOOKUP: + printf("LU "); break; + case SPIFFS_CHECK_INDEX: + printf("IX "); break; + case SPIFFS_CHECK_PAGE: + printf("PA "); break; + } + printf("%i%%\n", arg1 * 100 / 256); + }*/ + if (report != SPIFFS_CHECK_PROGRESS) { + if (report != SPIFFS_CHECK_ERROR) fs_check_fixes++; + printf(" check: "); + switch (type) { + case SPIFFS_CHECK_INDEX: + printf("INDEX "); break; + case SPIFFS_CHECK_LOOKUP: + printf("LOOKUP "); break; + case SPIFFS_CHECK_PAGE: + printf("PAGE "); break; + default: + printf("???? "); break; + } + if (report == SPIFFS_CHECK_ERROR) { + printf("ERROR %i", arg1); + } else if (report == SPIFFS_CHECK_DELETE_BAD_FILE) { + printf("DELETE BAD FILE %04x", arg1); + } else if (report == SPIFFS_CHECK_DELETE_ORPHANED_INDEX) { + printf("DELETE ORPHANED INDEX %04x", arg1); + } else if (report == SPIFFS_CHECK_DELETE_PAGE) { + printf("DELETE PAGE %04x", arg1); + } else if (report == SPIFFS_CHECK_FIX_INDEX) { + printf("FIX INDEX %04x:%04x", arg1, arg2); + } else if (report == SPIFFS_CHECK_FIX_LOOKUP) { + printf("FIX INDEX %04x:%04x", arg1, arg2); + } else { + printf("??"); + } + printf("\n"); + } +} + +void fs_set_addr_offset(u32_t offset) { + addr_offset = offset; +} + +s32_t fs_mount_specific(u32_t phys_addr, u32_t phys_size, + u32_t phys_sector_size, + u32_t log_block_size, u32_t log_page_size) { + spiffs_config c; + c.hal_erase_f = _erase; + c.hal_read_f = _read; + c.hal_write_f = _write; + c.log_block_size = log_block_size; + c.log_page_size = log_page_size; + c.phys_addr = phys_addr; + c.phys_erase_block = phys_sector_size; + c.phys_size = phys_size; + + return SPIFFS_mount(&__fs, &c, _work, _fds, sizeof(_fds), _cache, sizeof(_cache), spiffs_check_cb_f); +} + +void fs_reset_specific(u32_t addr_offset, u32_t phys_addr, u32_t phys_size, + u32_t phys_sector_size, + u32_t log_block_size, u32_t log_page_size) { + fs_set_addr_offset(addr_offset); + + u8_t i; + for (i = 0; i < phys_size / phys_sector_size; i++) { + spi_flash_erase_sector(phys_addr / phys_sector_size + i); + } + + memset(&__fs, 0, sizeof(__fs)); + + memset(erases,0,sizeof(erases)); + memset(_cache,0,sizeof(_cache)); + + s32_t res = fs_mount_specific(phys_addr, phys_size, phys_sector_size, log_block_size, log_page_size); + +#if SPIFFS_USE_MAGIC + if (res == SPIFFS_OK) { + SPIFFS_unmount(&__fs); + } + res = SPIFFS_format(&__fs); + if (res != SPIFFS_OK) { + printf("format failed, %i\n", SPIFFS_errno(&__fs)); + } + res = fs_mount_specific(phys_addr, phys_size, phys_sector_size, log_block_size, log_page_size); + if (res != SPIFFS_OK) { + printf("mount failed, %i\n", SPIFFS_errno(&__fs)); + } +#endif + + clear_flash_ops_log(); + log_flash_ops = 1; + fs_check_fixes = 0; +} + +void fs_reset() { + esp_spiffs_deinit(1); + spiffs_fs1_init(); + fs_reset_specific(0, FS2_FLASH_ADDR, FS2_FLASH_SIZE, SECTOR_SIZE, SECTOR_SIZE, LOG_PAGE); +} + +void fs_load_dump(char *fname) { + int pfd = open(fname, O_RDONLY, S_IRUSR | S_IWUSR); + +//too large +#if 0 + read(pfd, area, sizeof(area)); +#endif + + close(pfd); +} + +void set_flash_ops_log(int enable) { + log_flash_ops = enable; +} + +void clear_flash_ops_log() { + bytes_rd = 0; + bytes_wr = 0; + reads = 0; + writes = 0; + error_after_bytes_read = 0; + error_after_bytes_written = 0; +} + +u32_t get_flash_ops_log_read_bytes() { + return bytes_rd; +} + +u32_t get_flash_ops_log_write_bytes() { + return bytes_wr; +} + +void invoke_error_after_read_bytes(u32_t b, char once_only) { + error_after_bytes_read = b; + error_after_bytes_read_once_only = once_only; +} +void invoke_error_after_write_bytes(u32_t b, char once_only) { + error_after_bytes_written = b; + error_after_bytes_written_once_only = once_only; +} + +void fs_set_validate_flashing(int i) { + check_valid_flash = i; +} + +void real_assert(int c, const char *n, const char *file, int l) { + if (c == 0) { + printf("ASSERT: %s %s @ %i\n", (n ? n : ""), file, l); + printf("fs errno:%i\n", __fs.err_code); + exit(0); + } +} + +int read_and_verify(char *name) { + s32_t res; + int fd = SPIFFS_open(&__fs, name, SPIFFS_RDONLY, 0); + if (fd < 0) { + printf(" read_and_verify: could not open file %s\n", name); + return fd; + } + return read_and_verify_fd(fd, name); +} + +int read_and_verify_fd(spiffs_file fd, char *name) { + s32_t res; + int pfd = open(make_test_fname(name), O_RDONLY); + spiffs_stat s; + res = SPIFFS_fstat(&__fs, fd, &s); + if (res < 0) { + printf(" read_and_verify: could not stat file %s\n", name); + return res; + } + if (s.size == 0) { + SPIFFS_close(&__fs, fd); + close(pfd); + return 0; + } + + //printf("verifying %s, len %i\n", name, s.size); + int offs = 0; + u8_t buf_d[256]; + u8_t buf_v[256]; + while (offs < s.size) { + int read_len = MIN(s.size - offs, sizeof(buf_d)); + res = SPIFFS_read(&__fs, fd, buf_d, read_len); + if (res < 0) { + printf(" read_and_verify: could not read file %s offs:%i len:%i filelen:%i\n", name, offs, read_len, s.size); + return res; + } + int pres = read(pfd, buf_v, read_len); + (void)pres; + //printf("reading offs:%i len:%i spiffs_res:%i posix_res:%i\n", offs, read_len, res, pres); + int i; + int veri_ok = 1; + for (i = 0; veri_ok && i < read_len; i++) { + if (buf_d[i] != buf_v[i]) { + printf("file verification mismatch @ %i, %02x %c != %02x %c\n", offs+i, buf_d[i], buf_d[i], buf_v[i], buf_v[i]); + int j = MAX(0, i-16); + int k = MIN(sizeof(buf_d), i+16); + k = MIN(s.size-offs, k); + int l; + for (l = j; l < k; l++) { + printf("%c", buf_d[l] > 31 ? buf_d[l] : '.'); + } + printf("\n"); + for (l = j; l < k; l++) { + printf("%c", buf_v[l] > 31 ? buf_v[l] : '.'); + } + printf("\n"); + veri_ok = 0; + } + } + if (!veri_ok) { + SPIFFS_close(&__fs, fd); + close(pfd); + printf("data mismatch\n"); + return -1; + } + + offs += read_len; + } + + SPIFFS_close(&__fs, fd); + close(pfd); + + return 0; +} + +static void test_on_stop(test *t) { + printf(" spiffs errno:%i\n", SPIFFS_errno(&__fs)); +#if SPIFFS_TEST_VISUALISATION + SPIFFS_vis(FS); +#endif + +} + +void memrand(u8_t *b, int len) { + int i; + for (i = 0; i < len; i++) { + b[i] = rand(); + } +} + +int test_create_file(char *name) { + spiffs_stat s; + spiffs_file fd; + int res = SPIFFS_creat(FS, name, 0); + CHECK_RES(res); + fd = SPIFFS_open(FS, name, SPIFFS_RDONLY, 0); + CHECK(fd >= 0); + res = SPIFFS_fstat(FS, fd, &s); + CHECK_RES(res); + CHECK(strcmp((char*)s.name, name) == 0); + CHECK(s.size == 0); + SPIFFS_close(FS, fd); + return 0; +} + +int test_create_and_write_file(char *name, int size, int chunk_size) { + int res; + spiffs_file fd; + printf(" create and write %s", name); + res = test_create_file(name); + if (res < 0) { + printf(" failed creation, %i\n",res); + } + CHECK(res >= 0); + fd = SPIFFS_open(FS, name, SPIFFS_APPEND | SPIFFS_RDWR, 0); + if (res < 0) { + printf(" failed open, %i\n",res); + } + CHECK(fd >= 0); + int pfd = open(make_test_fname(name), O_APPEND | O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + int offset = 0; + int mark = 0; + while (offset < size) { + int len = MIN(size-offset, chunk_size); + if (offset > mark) { + mark += size/16; + printf("."); + fflush(stdout); + } + u8_t *buf = malloc(len); + MALLOC_CHECK_RETURN_1(buf != NULL, len); + memrand(buf, len); + res = SPIFFS_write(FS, fd, buf, len); + write(pfd, buf, len); + free(buf); + if (res < 0) { + printf("\n error @ offset %i, res %i\n", offset, res); + } + offset += len; + CHECK(res >= 0); + } + printf("\n"); + close(pfd); + + spiffs_stat stat; + res = SPIFFS_fstat(FS, fd, &stat); + if (res < 0) { + printf(" failed fstat, %i\n",res); + } + CHECK(res >= 0); + if (stat.size != size) { + printf(" failed size, %i != %i\n", stat.size, size); + } + CHECK(stat.size == size); + + SPIFFS_close(FS, fd); + return 0; +} + +#if SPIFFS_CACHE +#if SPIFFS_CACHE_STATS +static u32_t chits_tot = 0; +static u32_t cmiss_tot = 0; +#endif +#endif + +void _setup_test_only() { + fs_set_validate_flashing(1); + test_init(test_on_stop); +} + +void _setup() { + fs_reset(); + _setup_test_only(); +} + +void _teardown() { + printf(" free blocks : %i of %i\n", (FS)->free_blocks, (FS)->block_count); + printf(" pages allocated : %i\n", (FS)->stats_p_allocated); + printf(" pages deleted : %i\n", (FS)->stats_p_deleted); +#if SPIFFS_GC_STATS + printf(" gc runs : %i\n", (FS)->stats_gc_runs); +#endif +#if SPIFFS_CACHE +#if SPIFFS_CACHE_STATS + chits_tot += (FS)->cache_hits; + cmiss_tot += (FS)->cache_misses; + printf(" cache hits : %i (sum %i)\n", (FS)->cache_hits, chits_tot); + printf(" cache misses : %i (sum %i)\n", (FS)->cache_misses, cmiss_tot); + printf(" cache utiliz : %f\n", ((float)chits_tot/(float)(chits_tot + cmiss_tot))); + chits_tot = 0; + cmiss_tot = 0; +#endif +#endif + dump_flash_access_stats(); + clear_flash_ops_log(); +#if SPIFFS_GC_STATS + if ((FS)->stats_gc_runs > 0) +#endif + dump_erase_counts(FS); + printf(" fs consistency check:\n"); + SPIFFS_check(FS); + clear_test_path(); + + //hexdump_mem(&AREA(SPIFFS_PHYS_ADDR - 16), 32); + //hexdump_mem(&AREA(SPIFFS_PHYS_ADDR + SPIFFS_FLASH_SIZE - 16), 32); +} + +u32_t tfile_get_size(tfile_size s) { + switch (s) { + case EMPTY: + return 0; + case SMALL: + return SPIFFS_DATA_PAGE_SIZE(FS)/2; + case MEDIUM: + return (SPIFFS_DATA_PAGE_SIZE(FS) * (SPIFFS_PAGES_PER_BLOCK(FS) - SPIFFS_OBJ_LOOKUP_PAGES(FS)))/2; + case LARGE: + return (FS)->cfg.phys_size/40; + } + return 0; +} + +int run_file_config(int cfg_count, tfile_conf* cfgs, int max_runs, int max_concurrent_files, int dbg) { + int res; + tfile *tfiles = malloc(sizeof(tfile) * max_concurrent_files); + MALLOC_CHECK_RETURN_1(tfiles != NULL, sizeof(tfile) * max_concurrent_files); + memset(tfiles, 0, sizeof(tfile) * max_concurrent_files); + int run = 0; + int cur_config_ix = 0; + char name[32]; + while (run < max_runs) { + if (dbg) printf(" run %i/%i\n", run, max_runs); + int i; + for (i = 0; i < max_concurrent_files; i++) { + sprintf(name, "file%i_%i", (1+run), i); + tfile *tf = &tfiles[i]; + if (tf->state == 0 && cur_config_ix < cfg_count) { +// create a new file + strcpy(tf->name, name); + tf->state = 1; + tf->cfg = cfgs[cur_config_ix]; + int size = tfile_get_size(tf->cfg.tsize); + if (dbg) printf(" create new %s with cfg %i/%i, size %i\n", name, (1+cur_config_ix), cfg_count, size); + + if (tf->cfg.tsize == EMPTY) { + res = SPIFFS_creat(FS, name, 0); + CHECK_RES(res); + int pfd = open(make_test_fname(name), O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + close(pfd); + int extra_flags = tf->cfg.ttype == APPENDED ? SPIFFS_APPEND : 0; + spiffs_file fd = SPIFFS_open(FS, name, extra_flags | SPIFFS_RDWR, 0); + CHECK(fd > 0); + tf->fd = fd; + } else { + int extra_flags = tf->cfg.ttype == APPENDED ? SPIFFS_APPEND : 0; + spiffs_file fd = SPIFFS_open(FS, name, extra_flags | SPIFFS_TRUNC | SPIFFS_CREAT | SPIFFS_RDWR, 0); + CHECK(fd > 0); + extra_flags = tf->cfg.ttype == APPENDED ? O_APPEND : 0; + int pfd = open(make_test_fname(name), extra_flags | O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + tf->fd = fd; + u8_t *buf = malloc(size); + MALLOC_CHECK_RETURN_1(buf != NULL, size); + memrand(buf, size); + res = SPIFFS_write(FS, fd, buf, size); + CHECK_RES(res); + write(pfd, buf, size); + close(pfd); + free(buf); + res = read_and_verify(name); + CHECK_RES(res); + } + + cur_config_ix++; + } else if (tf->state > 0) { +// hande file lifecycle + switch (tf->cfg.ttype) { + case UNTAMPERED: { + break; + } + case APPENDED: { + if (dbg) printf(" appending %s\n", tf->name); + int size = SPIFFS_DATA_PAGE_SIZE(FS)*3; + u8_t *buf = malloc(size); + MALLOC_CHECK_RETURN_1(buf != NULL, size); + memrand(buf, size); + res = SPIFFS_write(FS, tf->fd, buf, size); + CHECK_RES(res); + int pfd = open(make_test_fname(tf->name), O_APPEND | O_RDWR); + write(pfd, buf, size); + close(pfd); + free(buf); + res = read_and_verify(tf->name); + CHECK_RES(res); + break; + } + case MODIFIED: { + if (dbg) printf(" modify %s\n", tf->name); + spiffs_stat stat; + res = SPIFFS_fstat(FS, tf->fd, &stat); + CHECK_RES(res); + int size = stat.size / tf->cfg.tlife + SPIFFS_DATA_PAGE_SIZE(FS)/3; + int offs = (stat.size / tf->cfg.tlife) * tf->state; + res = SPIFFS_lseek(FS, tf->fd, offs, SPIFFS_SEEK_SET); + CHECK_RES(res); + u8_t *buf = malloc(size); + MALLOC_CHECK_RETURN_1(buf != NULL, size); + memrand(buf, size); + res = SPIFFS_write(FS, tf->fd, buf, size); + CHECK_RES(res); + int pfd = open(make_test_fname(tf->name), O_RDWR); + lseek(pfd, offs, SEEK_SET); + write(pfd, buf, size); + close(pfd); + free(buf); + res = read_and_verify(tf->name); + CHECK_RES(res); + break; + } + case REWRITTEN: { + if (tf->fd > 0) { + SPIFFS_close(FS, tf->fd); + } + if (dbg) printf(" rewriting %s\n", tf->name); + spiffs_file fd = SPIFFS_open(FS, tf->name, SPIFFS_TRUNC | SPIFFS_CREAT | SPIFFS_RDWR, 0); + CHECK(fd > 0); + int pfd = open(make_test_fname(tf->name), O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + tf->fd = fd; + int size = tfile_get_size(tf->cfg.tsize); + u8_t *buf = malloc(size); + MALLOC_CHECK_RETURN_1(buf != NULL, size); + memrand(buf, size); + res = SPIFFS_write(FS, fd, buf, size); + CHECK_RES(res); + write(pfd, buf, size); + close(pfd); + free(buf); + res = read_and_verify(tf->name); + CHECK_RES(res); + break; + } + } + tf->state++; + if (tf->state > tf->cfg.tlife) { +// file outlived its time, kill it + if (tf->fd > 0) { + SPIFFS_close(FS, tf->fd); + } + if (dbg) printf(" removing %s\n", tf->name); + res = read_and_verify(tf->name); + CHECK_RES(res); + res = SPIFFS_remove(FS, tf->name); + CHECK_RES(res); + remove(make_test_fname(tf->name)); + memset(tf, 0, sizeof(tf)); + } + + } + } + + run++; + } + free(tfiles); + return 0; +} + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/test_spiffs.h b/Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/test_spiffs.h new file mode 100644 index 0000000..3fd1991 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/test_spiffs.h @@ -0,0 +1,94 @@ +/* + * test_spiffs.h + * + * Created on: Jun 19, 2013 + * Author: petera + */ + +#ifndef TEST_SPIFFS_H_ +#define TEST_SPIFFS_H_ + +#include "spiffs.h" + +#define FS &__fs + +extern spiffs __fs; + + +#define CHECK(r) if (!(r)) return -1; +#define CHECK_RES(r) if (r < 0) return -1; +#define FS_PURE_DATA_PAGES(fs) \ + ((fs)->cfg.phys_size / (fs)->cfg.log_page_size - (fs)->block_count * SPIFFS_OBJ_LOOKUP_PAGES(fs)) +#define FS_PURE_DATA_SIZE(fs) \ + FS_PURE_DATA_PAGES(fs) * SPIFFS_DATA_PAGE_SIZE(fs) + +typedef enum { + EMPTY, + SMALL, + MEDIUM, + LARGE, +} tfile_size; + +typedef enum { + UNTAMPERED, + APPENDED, + MODIFIED, + REWRITTEN, +} tfile_type; + +typedef enum { + SHORT = 4, + NORMAL = 20, + LONG = 100, +} tfile_life; + +typedef struct { + tfile_size tsize; + tfile_type ttype; + tfile_life tlife; +} tfile_conf; + +typedef struct { + int state; + spiffs_file fd; + tfile_conf cfg; + char name[32]; +} tfile; + + +void fs_reset(); +void fs_reset_specific(u32_t addr_offset, u32_t phys_addr, u32_t phys_size, + u32_t phys_sector_size, + u32_t log_block_size, u32_t log_page_size); +s32_t fs_mount_specific(u32_t phys_addr, u32_t phys_size, + u32_t phys_sector_size, + u32_t log_block_size, u32_t log_page_size); +void fs_set_addr_offset(u32_t offset); +int read_and_verify(char *name); +int read_and_verify_fd(spiffs_file fd, char *name); +void dump_page(spiffs *fs, spiffs_page_ix p); +void hexdump(u32_t addr, u32_t len); +char *make_test_fname(const char *name); +void clear_test_path(); +void area_write(u32_t addr, u8_t *buf, u32_t size); +void area_read(u32_t addr, u8_t *buf, u32_t size); +void dump_erase_counts(spiffs *fs); +void dump_flash_access_stats(); +void set_flash_ops_log(int enable); +void clear_flash_ops_log(); +u32_t get_flash_ops_log_read_bytes(); +u32_t get_flash_ops_log_write_bytes(); +void invoke_error_after_read_bytes(u32_t b, char once_only); +void invoke_error_after_write_bytes(u32_t b, char once_only); + +void memrand(u8_t *b, int len); +int test_create_file(char *name); +int test_create_and_write_file(char *name, int size, int chunk_size); +void _setup(); +void _setup_test_only(); +void _teardown(); +u32_t tfile_get_size(tfile_size s); +int run_file_config(int cfg_count, tfile_conf* cfgs, int max_runs, int max_concurrent_files, int dbg); + + +#endif /* TEST_SPIFFS_H_ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/testrunner.c b/Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/testrunner.c new file mode 100644 index 0000000..3b7915a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/testrunner.c @@ -0,0 +1,215 @@ +/* + * testrunner.c + * + * Created on: Jun 18, 2013 + * Author: petera + */ + + +#include +#include +#include + +#include +#include +#include +//#include +#include + +#include "esp_common.h" +#include "testrunner.h" + +static struct { + test *tests; + test *_last_test; + int test_count; + void (*on_stop)(test *t); + test_res *failed; + test_res *failed_last; + test_res *stopped; + test_res *stopped_last; + FILE *spec; + char incl_filter[256]; + char excl_filter[256]; +} test_main; + +void test_init(void (*on_stop)(test *t)) { + test_main.on_stop = on_stop; +} + +static char check_spec(char *name) { + if (test_main.spec) { + fseek(test_main.spec, 0, SEEK_SET); + char *line = NULL; + size_t sz; + ssize_t read; + while ((read = __getline(&line, &sz, test_main.spec)) != -1) { + if (strncmp(line, name, strlen(line)-1) == 0) { + free(line); + return 1; + } + } + free(line); + return 0; + } else { + return 1; + } +} + +static char check_incl_filter(char *name) { + if (strlen(test_main.incl_filter)== 0) return 1; + return strstr(name, test_main.incl_filter) == 0 ? 0 : 1; +} + +static char check_excl_filter(char *name) { + if (strlen(test_main.excl_filter)== 0) return 1; + return strstr(name, test_main.excl_filter) == 0 ? 1 : 0; +} + +void add_test(test_f f, char *name, void (*setup)(test *t), void (*teardown)(test *t)) { + if (f == 0) return; + if (!check_spec(name)) return; + if (!check_incl_filter(name)) return; + if (!check_excl_filter(name)) return; + DBGT("adding test %s\n", name); + test *t = malloc(sizeof(test)); + MALLOC_CHECK_RETURN(t != NULL, sizeof(test)); + memset(t, 0, sizeof(test)); + t->f = f; + strcpy(t->name, name); + t->setup = setup; + t->teardown = teardown; + if (test_main.tests == 0) { + test_main.tests = t; + } else { + test_main._last_test->_next = t; + } + test_main._last_test = t; + test_main.test_count++; +} + +static void add_res(test *t, test_res **head, test_res **last) { + test_res *tr = malloc(sizeof(test_res)); + MALLOC_CHECK_RETURN(t != NULL, sizeof(test)); + memset(tr,0,sizeof(test_res)); + strcpy(tr->name, t->name); + if (*head == 0) { + *head = tr; + } else { + (*last)->_next = tr; + } + *last = tr; +} + +static void dump_res(test_res **head) { + test_res *tr = (*head); + while (tr) { + test_res *next_tr = tr->_next; + printf(" %s\n", tr->name); + free(tr); + tr = next_tr; + } +} + +int run_tests(int argc, char **args) { + memset(&test_main, 0, sizeof(test_main)); + int arg; + int incl_filter = 0; + int excl_filter = 0; + for (arg = 0; arg < argc; arg++) { + if (strlen(args[arg]) == 0) continue; + if (0 == strcmp("-f", args[arg])) { + incl_filter = 1; + continue; + } + if (0 == strcmp("-e", args[arg])) { + excl_filter = 1; + continue; + } + if (incl_filter) { + strcpy(test_main.incl_filter, args[arg]); + incl_filter = 0; + } else if (excl_filter) { + strcpy(test_main.excl_filter, args[arg]); + excl_filter = 0; + } else { + printf("running tests from %s\n", args[arg]); + FILE *fd = fopen(args[1], "r"); + if (fd == NULL) { + printf("%s not found\n", args[arg]); + return -2; + } + test_main.spec = fd; + } + } + + DBGT("adding suites...\n"); + add_suites(); + DBGT("%i tests added\n", test_main.test_count); + if (test_main.spec) { + fclose(test_main.spec); + } + + if (test_main.test_count == 0) { + printf("No tests to run\n"); + return 0; + } + + int fd_success = open("_tests_ok", O_APPEND | O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + int fd_bad = open("_tests_fail", O_APPEND | O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + + DBGT("running tests...\n"); + int ok = 0; + int failed = 0; + int stopped = 0; + test *cur_t = test_main.tests; + int i = 1; + while (cur_t) { + cur_t->setup(cur_t); + test *next_test = cur_t->_next; + DBGT("TEST %i/%i : running test %s\n", i, test_main.test_count, cur_t->name); + i++; + int res = cur_t->f(cur_t); + cur_t->test_result = res; + cur_t->teardown(cur_t); + int fd = res == TEST_RES_OK ? fd_success : fd_bad; + write(fd, cur_t->name, strlen(cur_t->name)); + write(fd, "\n", 1); + switch (res) { + case TEST_RES_OK: + ok++; + printf(" .. ok\n"); + break; + case TEST_RES_FAIL: + failed++; + printf(" .. FAILED\n"); + if (test_main.on_stop) test_main.on_stop(cur_t); + add_res(cur_t, &test_main.failed, &test_main.failed_last); + break; + case TEST_RES_ASSERT: + stopped++; + printf(" .. ABORTED\n"); + if (test_main.on_stop) test_main.on_stop(cur_t); + add_res(cur_t, &test_main.stopped, &test_main.stopped_last); + break; + } + free(cur_t); + cur_t = next_test; + } + close(fd_success); + close(fd_bad); + DBGT("ran %i tests\n", test_main.test_count); + printf("Test report, %i tests\n", test_main.test_count); + printf("%i succeeded\n", ok); + printf("%i failed\n", failed); + dump_res(&test_main.failed); + printf("%i stopped\n", stopped); + dump_res(&test_main.stopped); + if (ok < test_main.test_count) { + printf("\nFAILED\n"); + return -1; + } else { + printf("\nALL TESTS OK\n"); + return 0; + } +} diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/testrunner.h b/Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/testrunner.h new file mode 100644 index 0000000..25819ea --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/testrunner.h @@ -0,0 +1,151 @@ +/* + * testrunner.h + * + * Created on: Jun 19, 2013 + * Author: petera + */ + +/* + +SUITE(mysuite) + +void setup(test *t) {} + +void teardown(test *t) {} + +TEST(mytest) { + printf("mytest runs now..\n"); + return 0; +} TEST_END(mytest) + +SUITE_END(mysuite) + + + +SUITE(mysuite2) + +void setup(test *t) {} + +void teardown(test *t) {} + +TEST(mytest2a) { + printf("mytest2a runs now..\n"); + return 0; +} TEST_END(mytest2a) + +TEST(mytest2b) { + printf("mytest2b runs now..\n"); + return 0; +} TEST_END(mytest2b) + +SUITE_END(mysuite2) + + + +void add_suites() { + ADD_SUITE(mysuite); + ADD_SUITE(mysuite2); +} + */ + +#ifndef TESTRUNNER_H_ +#define TESTRUNNER_H_ + +#define TEST_RES_OK 0 +#define TEST_RES_FAIL -1 +#define TEST_RES_ASSERT -2 + +struct test_s; + +typedef int (*test_f)(struct test_s *t); + +typedef struct test_s { + test_f f; + char name[64]; + void *data; + void (*setup)(struct test_s *t); + void (*teardown)(struct test_s *t); + struct test_s *_next; + unsigned char test_result; +} test; + +typedef struct test_res_s { + char name[256]; + struct test_res_s *_next; +} test_res; + +#define MALLOC_CHECK(x, y) if (!(x)) { \ + printf(" MALLOC %i FAIL %s:%i, FREE %i\n", y, __FILE__, __LINE__, system_get_free_heap_size()); \ + goto __fail_stop; \ +} + +#define MALLOC_CHECK_RETURN(x, y) if (!(x)) { \ + printf(" MALLOC %i FAIL %s:%i, FREE %i\n", y, __FILE__, __LINE__, system_get_free_heap_size()); \ + return; \ +} + +#define MALLOC_CHECK_RETURN_1(x, y) if (!(x)) { \ + printf(" MALLOC %i FAIL %s:%i, FREE %i\n", y, __FILE__, __LINE__, system_get_free_heap_size()); \ + return -1; \ +} + +#define TEST_CHECK(x) if (!(x)) { \ + printf(" TEST FAIL %s:%i\n", __FILE__, __LINE__); \ + goto __fail_stop; \ +} +#define TEST_CHECK_EQ(x, y) if ((x) != (y)) { \ + printf(" TEST FAIL %s:%i, %i != %i\n", __FILE__, __LINE__, (x), (y)); \ + goto __fail_stop; \ +} +#define TEST_CHECK_NEQ(x, y) if ((x) == (y)) { \ + printf(" TEST FAIL %s:%i, %i == %i\n", __FILE__, __LINE__, (x), (y)); \ + goto __fail_stop; \ +} +#define TEST_CHECK_GT(x, y) if ((x) <= (y)) { \ + printf(" TEST FAIL %s:%i, %i <= %i\n", __FILE__, __LINE__, (x), (y)); \ + goto __fail_stop; \ +} +#define TEST_CHECK_LT(x, y) if ((x) >= (y)) { \ + printf(" TEST FAIL %s:%i, %i >= %i\n", __FILE__, __LINE__, (x), (y)); \ + goto __fail_stop; \ +} +#define TEST_CHECK_GE(x, y) if ((x) < (y)) { \ + printf(" TEST FAIL %s:%i, %i < %i\n", __FILE__, __LINE__, (x), (y)); \ + goto __fail_stop; \ +} +#define TEST_CHECK_LE(x, y) if ((x) > (y)) { \ + printf(" TEST FAIL %s:%i, %i > %i\n", __FILE__, __LINE__, (x), (y)); \ + goto __fail_stop; \ +} +#define TEST_ASSERT(x) if (!(x)) { \ + printf(" TEST ASSERT %s:%i\n", __FILE__, __LINE__); \ + goto __fail_assert; \ +} + +#define DBGT(...) os_printf(__VA_ARGS__) + +#define str(s) #s + +#define SUITE(sui) \ + extern void __suite_##sui() { +#define SUITE_END(sui) \ + } +#define ADD_SUITE(sui) \ + __suite_##sui(); +#define TEST(tf) \ + int tf(struct test_s *t) { do +#define TEST_END(tf) \ + while(0); \ + __fail_stop: return TEST_RES_FAIL; \ + __fail_assert: return TEST_RES_ASSERT; \ + } \ + add_test(tf, str(tf), setup, teardown); + + +void add_suites(); +void test_init(void (*on_stop)(test *t)); +void add_test(test_f f, char *name, void (*setup)(test *t), void (*teardown)(test *t)); +// returns 0 if all tests ok, -1 if any test failed, -2 on badness +int run_tests(int argc, char **args); + +#endif /* TESTRUNNER_H_ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/testsuites.c b/Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/testsuites.c new file mode 100644 index 0000000..7627db0 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/spiffs_test/user/testsuites.c @@ -0,0 +1,15 @@ +/* + * testsuites.c + * + * Created on: Jun 19, 2013 + * Author: petera + */ + +#include "testrunner.h" + +void add_suites() { + //ADD_SUITE(dev_tests); + ADD_SUITE(check_tests); + ADD_SUITE(hydrogen_tests) + ADD_SUITE(bug_tests) +} diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/websocket_demo/Makefile b/Distrib/ESPressif/RTOS/1.5.0/examples/websocket_demo/Makefile new file mode 100644 index 0000000..5dfe57f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/websocket_demo/Makefile @@ -0,0 +1,124 @@ +############################################################# +# 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 \ + websocket + +endif # } PDIR + +LDDIR = $(SDK_PATH)/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 \ + websocket/libwebsocket.a + +LINKFLAGS_eagle.app.v6 = \ + -L$(SDK_PATH)/lib \ + -Wl,--gc-sections \ + -nostdlib \ + -T$(LD_FILE) \ + -Wl,--no-check-sections \ + -u call_user_start \ + -Wl,-static \ + -Wl,--start-group \ + -lcirom \ + -lgcc \ + -lhal \ + -lcrypto \ + -lfreertos \ + -llwip \ + -lmain \ + -lnet80211 \ + -lnopoll \ + -lphy \ + -lpp \ + -lsmartconfig \ + -lssl \ + -lwpa \ + $(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 +sinclude $(SDK_PATH)/Makefile + +.PHONY: FORCE +FORCE: + diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/websocket_demo/gen_misc.bat b/Distrib/ESPressif/RTOS/1.5.0/examples/websocket_demo/gen_misc.bat new file mode 100644 index 0000000..fd0b44f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/websocket_demo/gen_misc.bat @@ -0,0 +1,172 @@ +@echo off + +Rem ******NOTICE****** +Rem MUST set SDK_PATH & BIN_PATH firstly!!! +Rem example: +Rem set SDK_PATH=/c/esp_iot_sdk_freertos +Rem set BIN_PATH=/c/esp8266_bin + +set SDK_PATH="" +set BIN_PATH="" + +echo gen_misc.bat version 20150911 +echo . + +if not %SDK_PATH% == "" ( + echo SDK_PATH: %SDK_PATH% +) else ( + echo ERROR: Please set SDK_PATH in gen_misc.bat firstly, exit!!! + goto end +) + +if not %BIN_PATH% == "" ( + echo BIN_PATH: %BIN_PATH% +) else ( + echo ERROR: Please set BIN_PATH in gen_misc.bat firstly, exit!!! + goto end +) + +echo . +echo Please check SDK_PATH/BIN_PATH, enter (Y/y) to continue: +set input=default +set /p input= + +if not %input% == Y ( + if not %input% == y ( + goto end + ) +) + +echo . +echo Please follow below steps(1-5) to generate specific bin(s): +echo STEP 1: use boot_v1.2+ by default +set boot=new + +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 + ) + ) + ) + ) +) + +echo. +echo start... +echo. + +make clean + +make COMPILE=xcc BOOT=%boot% APP=%app% SPI_SPEED=%spi_speed% SPI_MODE=%spi_mode% SPI_SIZE_MAP=%spi_size_map% + +:end \ No newline at end of file diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/websocket_demo/gen_misc.sh b/Distrib/ESPressif/RTOS/1.5.0/examples/websocket_demo/gen_misc.sh new file mode 100644 index 0000000..b24f63c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/websocket_demo/gen_misc.sh @@ -0,0 +1,176 @@ +#!/bin/bash + +:< + * + * 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 "esp_common.h" + +char test_mode = 4; + +/****************************************************************************** + * 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 user_rf_cal_sector_set(void) +{ + 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; + + default: + rf_cal_sec = 0; + break; + } + + return rf_cal_sec; +} + +/****************************************************************************** + * FunctionName : user_init + * Description : entry of user application, init user function here + * Parameters : none + * Returns : none +*******************************************************************************/ +void user_init(void) +{ + os_printf("SDK version:%s\n", system_get_sdk_version()); + wifi_set_opmode(STATION_MODE); + websocket_start(&test_mode); +} diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/websocket_demo/websocket/Makefile b/Distrib/ESPressif/RTOS/1.5.0/examples/websocket_demo/websocket/Makefile new file mode 100644 index 0000000..64c648d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/websocket_demo/websocket/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 = libwebsocket.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/Distrib/ESPressif/RTOS/1.5.0/examples/websocket_demo/websocket/websocket.c b/Distrib/ESPressif/RTOS/1.5.0/examples/websocket_demo/websocket/websocket.c new file mode 100644 index 0000000..6629b00 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/websocket_demo/websocket/websocket.c @@ -0,0 +1,716 @@ +/* + * LibNoPoll: A websocket library + * Copyright (C) 2013 Advanced Software Production Line, S.L. + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * You may find a copy of the license under this software is released + * at COPYING file. This is LGPL software: you are welcome to develop + * proprietary applications using this library without any royalty or + * fee but returning back any change, improvement or addition in the + * form of source code, project image, documentation patches, etc. + * + * For commercial support on build Websocket enabled solutions + * contact us: + * + * Postal address: + * Advanced Software Production Line, S.L. + * Edificio Alius A, Oficina 102, + * C/ Antonio Suarez Nº 10, + * Alcalá de Henares 28802 Madrid + * Spain + * + * Email address: + * info@aspl.es - http://www.aspl.es/nopoll + */ +#include +#include "ssl_compat-1.0.h" +#include "esp_common.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" + +nopoll_bool debug = nopoll_false; +nopoll_bool show_critical_only = nopoll_false; +LOCAL xQueueHandle Web_QueueStop = NULL; + +#define local_host_name "iot.espressif.cn" +#define local_host_url "v1/datastreams/tem_hum/datapoint" +#define local_host_port "9000" +#define local_host_ports "9443" + +nopoll_bool test_sending_and_check_echo (noPollConn * conn, const char * label, const char * msg) +{ + char buffer[1024]; + int length = strlen (msg); + int bytes_read; + + /* wait for the reply */ + while (nopoll_true) { + if (nopoll_conn_is_ready (conn)) + break; + nopoll_sleep (10000); + } /* end if */ + + /* send content text(utf-8) */ + printf ("%s: sending content..\n", label); + if (nopoll_conn_send_text (conn, msg, length) != length) { + printf ("ERROR: Expected to find proper send operation..\n"); + return nopoll_false; + } + + /* wait for the reply (try to read 1024, blocking and with a 3 seconds timeout) */ + bytes_read = nopoll_conn_read (conn, buffer, length, nopoll_true, 3000); + if (bytes_read > 0) + buffer[bytes_read] = 0; + + if (bytes_read != length) { + printf ("ERROR: expected to find 14 bytes but found %d..\n", bytes_read); + return nopoll_false; + } /* end if */ + + /* check content received */ + if (! nopoll_cmp (buffer, msg)) { + printf ("ERROR: expected to find message 'This is a test' but something different was received: '%s'..\n", + buffer); + return nopoll_false; + } /* end if */ + + printf ("%s: received reply and echo matches..\n", label); + + /* return that we sent and received the echo reply */ + return nopoll_true; +} + +void __report_critical (noPollCtx * ctx, noPollDebugLevel level, const char * log_msg, noPollPtr user_data) +{ + if (level == NOPOLL_LEVEL_CRITICAL) { + printf ("CRITICAL: %s\n", log_msg); + } + return; +} + +noPollCtx * create_ctx (void) { + + /* create a context */ + noPollCtx * ctx = nopoll_ctx_new (); + nopoll_log_enable (ctx, debug); + nopoll_log_color_enable (ctx, debug); + + /* configure handler */ + if (show_critical_only) + nopoll_log_set_handler (ctx, __report_critical, NULL); + return ctx; +} + +nopoll_bool test_02 (void) { + noPollCtx * ctx; + noPollConn * conn; + noPollMsg * msg; + int iter; + + /* create context */ + ctx = create_ctx (); + + /* check connections registered */ + if (nopoll_ctx_conns (ctx) != 0) { + printf ("ERROR: expected to find 0 registered connections but found: %d\n", nopoll_ctx_conns (ctx)); + return nopoll_false; + } /* end if */ + + nopoll_ctx_unref (ctx); + + /* reinit again */ + ctx = create_ctx (); + + /* call to create a connection */ + conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error.. (conn=%p, conn->session=%d, NOPOLL_INVALID_SOCKET=%d, errno=%d, strerr=%s)..\n", + conn, (int) nopoll_conn_socket (conn), (int) NOPOLL_INVALID_SOCKET, errno, strerror (errno)); + return nopoll_false; + } + + printf ("Test 02: sending basic content..\n"); + + /* send content text(utf-8) */ + if (nopoll_conn_send_text (conn, "This is a test", 14) != 14) { + printf ("ERROR: Expected to find proper send operation..\n"); + return nopoll_false; + } + + /* wait for the reply */ + iter = 0; + while ((msg = nopoll_conn_get_msg (conn)) == NULL) { + + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: received websocket connection close during wait reply..\n"); + return nopoll_false; + } + + nopoll_sleep (10000); + + if (iter > 10) + break; + } /* end if */ + + /* check content received */ + if (! nopoll_cmp ((char*) nopoll_msg_get_payload (msg), "This is a test")) { + printf ("ERROR: expected to find message 'This is a test' but something different was received: '%s'..\n", + (const char *) nopoll_msg_get_payload (msg)); + return nopoll_false; + } /* end if */ + + /* unref message */ + nopoll_msg_unref (msg); + + /* finish connection */ + nopoll_conn_close (conn); + + /* finish */ + nopoll_ctx_unref (ctx); + + return nopoll_true; +} + +nopoll_bool test_03 (void) { + noPollCtx * ctx; + noPollConn * conn; + char buffer[1024]; + int bytes_read; + + memset (buffer, 0, 1024); + + /* create context */ + ctx = create_ctx (); + + /* check connections registered */ + if (nopoll_ctx_conns (ctx) != 0) { + printf ("ERROR: expected to find 0 registered connections but found: %d\n", nopoll_ctx_conns (ctx)); + return nopoll_false; + } /* end if */ + + nopoll_ctx_unref (ctx); + + /* reinit again */ + ctx = create_ctx (); + + /* call to create a connection */ + conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } + + printf ("Test 03: sending basic content..\n"); + + /* send content text(utf-8) */ + if (nopoll_conn_send_text (conn, "This is a test", 14) != 14) { + printf ("ERROR: Expected to find proper send operation..\n"); + return nopoll_false; + } + + /* wait for the reply (try to read 1024, blocking and with a 3 seconds timeout) */ + printf ("Test 03: now reading reply..\n"); + bytes_read = nopoll_conn_read (conn, buffer, 14, nopoll_true, 3000); + + if (bytes_read != 14) { + printf ("ERROR: expected to find 14 bytes but found %d..\n", bytes_read); + return nopoll_false; + } /* end if */ + + /* check content received */ + if (! nopoll_ncmp (buffer, "This is a test", 14)) { + printf ("ERROR: expected to find message 'This is a test' but something different was received: '%s'..\n", + buffer); + return nopoll_false; + } /* end if */ + + /* finish connection */ + nopoll_conn_close (conn); + + /* finish */ + nopoll_ctx_unref (ctx); + + return nopoll_true; +} + +nopoll_bool test_04a (void) { + noPollCtx * ctx; + noPollConn * conn; + char buffer[1024]; + int result; + + /* reinit again */ + ctx = create_ctx (); + + /* call to create a connection */ + conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } + + /* attempt to read without blocking */ + printf ("Test 04-a: checking non-blocking API..\n"); + result = nopoll_conn_read (conn, buffer, 1024, nopoll_false, 0); + if (result != -1) { + printf ("ERROR: expected return result -1(%d)\n", result); + return nopoll_false; + } + + printf ("Test 04-a: ok, operation not blocked, result %d\n", result); + if (result != -1) { + printf ("ERROR: expected return result -1(%d)\n", result); + return nopoll_false; + } + + result = nopoll_conn_read (conn, buffer, 1024, nopoll_false, 300); + if (result != -1) { + printf ("ERROR: expected return result -1(%d)\n", result); + return nopoll_false; + } + + printf ("Test 04-a: ok, operation not blocked, result %d\n", result); + + result = nopoll_conn_read (conn, buffer, 1024, nopoll_false, 1000); + if (result != -1) { + printf ("ERROR: expected return result -1(%d)\n", result); + return nopoll_false; + } + + printf ("Test 04-a: ok, operation not blocked, result %d\n", result); + + /* finish connection */ + nopoll_conn_close (conn); + + /* finish */ + nopoll_ctx_unref (ctx); + + + return nopoll_true; +} + +nopoll_bool test_04b (void) { + noPollCtx * ctx; + noPollConn * conn; + int iterator; + int length; + int bytes_written; + const char * msg = NULL; + /* reinit again */ + ctx = create_ctx (); + + /* call to create a connection */ + conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } + + printf ("Test 04-b: waiting until connection is ok\n"); + nopoll_conn_wait_until_connection_ready (conn, 5); + + printf ("Test 04-b: sending was quick as possible to flood local buffers..\n"); + + /* get message length */ + length = strlen (msg); + iterator = 0; + while (iterator < 100) { + /* send a message */ + if (nopoll_conn_send_text (conn, msg, length) != length) { + if (errno == 0) { + printf ("ERROR: expected to find errno value but found 0..\n"); + } + printf ("Test 04-b: found expected error, checking errno=%d..\n", errno); + break; + } /* end if */ + + /* next iterator */ + iterator ++; + } /* end while */ + + if (errno != NOPOLL_EWOULDBLOCK && errno != EINPROGRESS) { + printf ("ERROR: expected to find errno=%d, but found errno=%d : %s\n", + (int)NOPOLL_EWOULDBLOCK, (int)errno, strerror (errno)); + return nopoll_false; + } /* end if */ + + /* write pending content */ + if (nopoll_conn_pending_write_bytes (conn) == 0) { + printf ("ERROR: expected to have pending bytes to be written.. but found 0..\n"); + return nopoll_false; + } /* end if */ + + iterator = 0; + while (iterator < 10) { + printf ("Test 04-b: found pending write bytes=%d\n", nopoll_conn_pending_write_bytes (conn)); + + /* call to flush bytes */ + nopoll_conn_complete_pending_write (conn); + + if (nopoll_conn_pending_write_bytes (conn) == 0) { + printf ("Test 04-b: all bytes written..\n"); + break; + } /* end if */ + + /* sleep a bit */ + nopoll_sleep (1000000); + + /* next iterator */ + iterator++; + } + + if (nopoll_conn_pending_write_bytes (conn) != 0) { + printf ("Test 04-b: expected to find no pending bytes waiting to be written but found: %d\n", nopoll_conn_pending_write_bytes (conn)); + return nopoll_false; + } /* end if */ + + nopoll_conn_close (conn); + + /* call to create a connection */ + conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } + + printf ("Test 04-b: waiting until connection is ok\n"); + nopoll_conn_wait_until_connection_ready (conn, 5); + + /* send a cleanup message */ + bytes_written = nopoll_conn_send_text (conn, "release-message", 15); + if (bytes_written != 15) { + printf ("Test 04-b: unable to send release message, bytes_written=%d, but expected=%d..\n", + bytes_written, 15); + return nopoll_false; + } /* end if */ + + printf ("Test 04-b: waiting a second before finishing test..\n"); + nopoll_sleep (1000000); + + /* finish connection */ + nopoll_conn_close (conn); + + /* finish */ + nopoll_ctx_unref (ctx); + + return nopoll_true; +} + +nopoll_bool test_05 (void) { + + noPollCtx * ctx; + noPollConn * conn; + char buffer[1024]; + int bytes_read; + const char * msg = " klasdfkla akldfj klafklajetqkljt kjlwergklwejry90246tkgwr kñljwrglkjdfg lksdjglskg slkg camión adsfasdf pruébasdfad España asdfaklsjdflk jasfkjaslfjetql tjñqgkjadgklj aglkjalk jafkjaslfkjaskj asjaslfkjasfklajg klajefñlqkjetrlkqj lqkj ñlskdfjañlk asldfjñlafj añlfj ñdfjkjt4ñqlkjt lkj34tlkjañlgjañlkgjañlkgjw"; + + memset (buffer, 0, 1024); + + /* reinit again */ + ctx = create_ctx (); + + /* call to create a connection */ + conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } + + printf ("Test 05: sending UTF-8 content..\n"); + + /* send content text(utf-8) */ + if (nopoll_conn_send_text (conn, msg, -1) <= 0) { + printf ("ERROR: Expected to find proper send operation (nopoll_conn_send_test) returned less or 0..\n"); + return nopoll_false; + } + + /* wait for the reply (try to read 322, blocking and with a 3 seconds timeout) */ + bytes_read = nopoll_conn_read (conn, buffer, 322, nopoll_true, 3000); + if (bytes_read != 322) { + printf ("ERROR: expected to receive 322 bytes, but received %d\n", bytes_read); + return nopoll_false; + } + + if (! nopoll_ncmp (buffer, msg, 322)) { + printf ("ERROR: expected to receive another content....\n"); + printf ("Expected: %s\n", msg); + printf ("Received: %s\n", buffer); + + return nopoll_false; + } + + /* finish connection */ + nopoll_conn_close (conn); + + /* finish */ + nopoll_ctx_unref (ctx); + + return nopoll_true; +} + +nopoll_bool test_06 (void) { + + noPollCtx * ctx; + noPollConn * conn; + noPollConnOpts * opts; + + /* reinit again */ + ctx = create_ctx (); + + /* disable verification */ + opts = nopoll_conn_opts_new (); + nopoll_conn_opts_ssl_peer_verify (opts, nopoll_false); + + /* call to create a connection */ + conn = nopoll_conn_tls_new (ctx, opts, local_host_name, local_host_ports, NULL, local_host_url, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } + + /* check if the connection already finished its connection + handshake */ + while (! nopoll_conn_is_ready (conn)) { + + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR (4.1 jg72): expected to find proper connection handshake finished, but found connection is broken: session=%d, errno=%d : %s..\n", + (int) nopoll_conn_socket (conn), errno, strerror (errno)); + return nopoll_false; + } /* end if */ + + /* wait a bit 10ms */ + nopoll_sleep (100); + } /* end if */ + + if (! nopoll_conn_is_tls_on (conn)) { + printf ("ERROR (5): expected to find TLS enabled on the connection but found it isn't..\n"); + return nopoll_false; + } /* end if */ + + /* finish connection */ + nopoll_conn_close (conn); + + /* finish */ + nopoll_ctx_unref (ctx); + + return nopoll_true; +} + +nopoll_bool test_07 (void) { + + noPollCtx * ctx; + noPollConn * conn; + noPollConnOpts * opts; + + /* reinit again */ + ctx = create_ctx (); + + /* disable verification */ + opts = nopoll_conn_opts_new (); + nopoll_conn_opts_ssl_peer_verify (opts, nopoll_false); + + /* call to create a connection */ + conn = nopoll_conn_tls_new (ctx, opts, local_host_name, local_host_ports, NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } /* end if */ + + /* check if the connection already finished its connection + handshake */ + while (! nopoll_conn_is_ready (conn)) { + + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR (4.1 dk45): expected to find proper connection handshake finished, but found connection is broken: session=%d, errno=%d : %s..\n", + (int) nopoll_conn_socket (conn), errno, strerror (errno)); + return nopoll_false; + } /* end if */ + + /* wait a bit 10ms */ + nopoll_sleep (10000); + } /* end if */ + + printf ("Test 07: testing sending TLS content over the wire..\n"); + if (! test_sending_and_check_echo (conn, "Test 07", "This is a test")) + return nopoll_false; + + /* finish connection */ + nopoll_conn_close (conn); + + /* finish */ + nopoll_ctx_unref (ctx); + + return nopoll_true; +} + +nopoll_bool test_08 (void) { + + noPollCtx * ctx; + noPollConn * conn; + + /* reinit again */ + ctx = create_ctx (); + + /* call to connect to TLS port expecting non-TLS protocol */ + conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, NULL, NULL, NULL); + + /* wait a bit 100ms */ + nopoll_sleep (100000); + + if (nopoll_conn_is_ready (conn)) { + printf ("ERROR: Expected a FAILING connection status, but found error..\n"); + return nopoll_false; + } /* end if */ + + /* finish connection */ + nopoll_conn_close (conn); + + /* finish */ + nopoll_ctx_unref (ctx); + + return nopoll_true; +} + +LOCAL int websocket_main (char *argv) +{ + int iterator = *argv; + + switch (iterator) { + + case 2: + if (test_02()) { + printf("Test 02: Simple request/reply [ OK ]\n"); + } else { + printf("Test 02: Simple request/reply [ FAILED ]\n"); + } + + break; + + case 4: + if (test_04a()) { + printf( + "Test 04-a: check non-blocking streaming and message based API [ OK ]\n"); + } else { + printf( + "Test 04-a: check non-blocking streaming and message based API [ FAILED ]\n"); + } + break; + case 5: + if (test_05()) { + printf("Test 05: sending utf-8 content [ OK ]\n"); + } else { + printf("Test 05: sending utf-8 content [ FAILED ]\n"); + } + + break; + case 6: + if (test_06()) { + printf("Test 06: testing basic TLS connect [ OK ]\n"); + } else { + printf("Test 06: testing basic TLS connect [ FAILED ]\n"); + } + + break; + case 7: + if (test_07()) { + printf("Test 07: testing TLS request/reply [ OK ]\n"); + } else { + printf("Test 07: testing TLS request/reply [ FAILED ]\n"); + } + + break; + case 8: + if (test_08()) { + printf("Test 08: test normal connect to TLS port [ OK ]\n"); + } else { + printf("Test 08: test normal connect to TLS port [ FAILED ]\n"); + } + + break; + + default: + break; + } + + /* call to cleanup */ + nopoll_cleanup_library (); + printf ("All tests ok!!\n"); + + return 0; +} + +LOCAL void websocket_task(void *pvParameters) +{ + bool ValueFromReceive = false; + portBASE_TYPE xStatus; + struct ip_info ip_config; + struct station_config sta_config; + bzero(&sta_config, sizeof(struct station_config)); + + sprintf(sta_config.ssid, "B-LINK_845R"); + sprintf(sta_config.password, "000"); + wifi_station_set_config(&sta_config); + os_printf("%s\n", __func__); + wifi_get_ip_info(STATION_IF, &ip_config); + while(ip_config.ip.addr == 0){ + vTaskDelay(1000 / portTICK_RATE_MS); + wifi_get_ip_info(STATION_IF, &ip_config); + } + websocket_main((char*)pvParameters); + + while (1) { + xStatus = xQueueReceive(Web_QueueStop,&ValueFromReceive,0); + if (xStatus == pdPASS && ValueFromReceive == true){ + printf("websocket_task exit signal\n"); + break; + } + vTaskDelay(200 / portTICK_RATE_MS); + printf("websocket_task\n"); + } + vQueueDelete(Web_QueueStop); + Web_QueueStop = NULL; + vTaskDelete(NULL); + printf("delete the websocket_task\n"); +} + +/*start the websocket task*/ +void websocket_start(void *optarg) +{ + if (Web_QueueStop == NULL) + Web_QueueStop = xQueueCreate(1,1); + + if (Web_QueueStop != NULL) + xTaskCreate(websocket_task, "websocket_task", 512, optarg, 4, NULL); +} + +/*stop the websocket task*/ +sint8 websocket_stop(void) +{ + bool ValueToSend = true; + portBASE_TYPE xStatus; + + if (Web_QueueStop == NULL) + return -1; + + xStatus = xQueueSend(Web_QueueStop,&ValueToSend,0); + if (xStatus != pdPASS) + return -1; + else + return pdPASS; +} +/* end-of-file-found */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/Makefile b/Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/Makefile new file mode 100644 index 0000000..a36b22b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/Makefile @@ -0,0 +1,132 @@ +############################################################# +# 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 + +LDDIR = $(SDK_PATH)/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$(SDK_PATH)/lib \ + -Wl,--gc-sections \ + -nostdlib \ + -T$(LD_FILE) \ + -Wl,--no-check-sections \ + -u call_user_start \ + -Wl,-static \ + -Wl,--start-group \ + -lcirom \ + -lcrypto \ + -lespconn \ + -lespnow \ + -lfreertos \ + -lgcc \ + -lhal \ + -ljson \ + -llwip \ + -lmain \ + -lmesh \ + -lmirom \ + -lnet80211 \ + -lnopoll \ + -lphy \ + -lpp \ + -lpwm \ + -lmbedtls \ + -lopenssl \ + -lsmartconfig \ + -lspiffs \ + -lwpa \ + -lwps \ + $(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 -D__STDC_NO_ATOMICS__=1 -DESP8266_RTOS -D__STDC_VERSION__=201112L -DFREERTOS_ARCH_ESP8266 +#-DNO_LOGGING=1 + +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 +sinclude $(SDK_PATH)/Makefile + +.PHONY: FORCE +FORCE: + diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/gen_misc.bat b/Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/gen_misc.bat new file mode 100644 index 0000000..fbb53be --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/gen_misc.bat @@ -0,0 +1,172 @@ +@echo off + +Rem ******NOTICE****** +Rem MUST set SDK_PATH & BIN_PATH firstly!!! +Rem example: +Rem set SDK_PATH=/c/esp_iot_sdk_freertos +Rem set BIN_PATH=/c/esp8266_bin + +set SDK_PATH="" +set BIN_PATH="" + +echo gen_misc.bat version 20150911 +echo . + +if not %SDK_PATH% == "" ( + echo SDK_PATH: %SDK_PATH% +) else ( + echo ERROR: Please set SDK_PATH in gen_misc.bat firstly, exit!!! + goto end +) + +if not %BIN_PATH% == "" ( + echo BIN_PATH: %BIN_PATH% +) else ( + echo ERROR: Please set BIN_PATH in gen_misc.bat firstly, exit!!! + goto end +) + +echo . +echo Please check SDK_PATH/BIN_PATH, enter (Y/y) to continue: +set input=default +set /p input= + +if not %input% == Y ( + if not %input% == y ( + goto end + ) +) + +echo . +echo Please follow below steps(1-5) to generate specific bin(s): +echo STEP 1: use boot_v1.2+ by default +set boot=new + +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 + ) + ) + ) + ) +) + +echo. +echo start... +echo. + +make clean + +make COMPILE=xcc BOOT=%boot% APP=%app% SPI_SPEED=%spi_speed% SPI_MODE=%spi_mode% SPI_SIZE_MAP=%spi_size_map% + +:end \ No newline at end of file diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/gen_misc.sh b/Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/gen_misc.sh new file mode 100644 index 0000000..c8ffb4e --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/gen_misc.sh @@ -0,0 +1,176 @@ +#!/bin/bash + +:< + * + * 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 SSID "N600" +#define PASSWORD "espressif" + +#endif + diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/include/wifi_state_machine.h b/Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/include/wifi_state_machine.h new file mode 100644 index 0000000..ddc31b3 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/include/wifi_state_machine.h @@ -0,0 +1,50 @@ +/* + * ESPRSSIF MIT License + * + * Copyright (c) 2017 + * + * 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 _WIFI_STATE_MACHINE_H_ +#define _WIFI_STATE_MACHINE_H_ + +#include +#include "espressif/c_types.h" +#include "espressif/esp_wifi.h" + +typedef void (* wifi_state_cb_t)(); +typedef void (* wifi_disco_cb_t)(uint8_t reason); + +void set_on_station_first_connect(wifi_state_cb_t cb); +void set_on_station_connect(wifi_state_cb_t cb); +void set_on_station_disconnect(wifi_disco_cb_t cb); +void set_on_client_connect(wifi_state_cb_t cb); +void set_on_client_disconnect(wifi_state_cb_t cb); + +WIFI_MODE init_esp_wifi(); +bool start_wifi_station(const char * ssid, const char * pass); +bool stop_wifi_station(); +bool start_wifi_ap(const char * ssid, const char * pass); +bool stop_wifi_ap(); + +bool wifi_station_connected(); +bool wifi_ap_enabled(); + +#endif /* _WIFI_STATE_MACHINE_H_ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/readme.txt b/Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/readme.txt new file mode 100644 index 0000000..e0588e3 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/readme.txt @@ -0,0 +1,56 @@ +This is a simple project template. + +sample_lib is an example for multi-level folder Makefile, notice the folder structure and each Makefile, you can get the clue. + + +HOWTO: +1. Copy this folder to anywhere. +Example: + Copy to ~/workspace/project_template + You can rename this folder as you like. + +2. Export SDK_PATH and BIN_PATH. +Example: + Your SDK path is ~/esp_iot_rtos_sdk, and want generate bin at ~/esp8266_bin. + Do follow steps: + 1>. export SDK_PATH=~/esp_iot_rtos_sdk + 2>. export BIN_PATH=~/esp8266_bin + SDK and project are seperate, you can update SDK without change your project. + +3. Enter project_template folder, run ./gen_misc.sh, and follow the tips and steps. + + +Compile Options: +(1) COMPILE + Possible value: xcc + Default value: + If not set, use gcc 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: new + +(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 diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/user/Makefile b/Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/user/Makefile new file mode 100644 index 0000000..373aa7a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/user/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 +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 ../sample_lib/azureiot/azure-c-shared-utility/inc +INCLUDES += -I ../sample_lib/azureiot/azure-umqtt-c/inc +INCLUDES += -I ../sample_lib/azureiot/parson +INCLUDES += -I ../sample_lib/azureiot/iothub_client/inc +INCLUDES += -I ../../../include/espressif/esp8266 +INCLUDES += -I ../../../include +INCLUDES += -I ../../../include/openssl +PDIR := ../$(PDIR) + +sinclude $(PDIR)Makefile + diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/user/user_main.c b/Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/user/user_main.c new file mode 100644 index 0000000..9f291be --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/user/user_main.c @@ -0,0 +1,111 @@ +/* + * ESPRSSIF MIT License + * + * Copyright (c) 2017 + * + * 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 "esp_common.h" +#include "user_config.h" + +static os_timer_t timer; + +/****************************************************************************** + * 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 user_rf_cal_sector_set(void) +{ + 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; + + default: + rf_cal_sec = 0; + break; + } + + return rf_cal_sec; +} + +LOCAL void ICACHE_FLASH_ATTR wait_for_connection_ready(uint8 flag) +{ + os_timer_disarm(&timer); + if(wifi_station_connected()){ + os_printf("connected\n"); + } else { + os_printf("reconnect after 2s\n"); + os_timer_setfn(&timer, (os_timer_func_t *)wait_for_connection_ready, NULL); + os_timer_arm(&timer, 2000, 0); + } +} + +LOCAL void ICACHE_FLASH_ATTR on_wifi_connect(){ + os_timer_disarm(&timer); + os_timer_setfn(&timer, (os_timer_func_t *)wait_for_connection_ready, NULL); + os_timer_arm(&timer, 100, 0); +} + +LOCAL void ICACHE_FLASH_ATTR on_wifi_disconnect(uint8_t reason){ + os_printf("disconnect %d\n", reason); +} + +/****************************************************************************** + * FunctionName : user_init + * Description : entry of user application, init user function here + * Parameters : none + * Returns : none +*******************************************************************************/ +void user_init(void) +{ + printf("SDK version:%s\n", system_get_sdk_version()); + + set_on_station_connect(on_wifi_connect); + set_on_station_disconnect(on_wifi_disconnect); + init_esp_wifi(); + stop_wifi_ap(); + start_wifi_station(SSID, PASSWORD); +} diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/user/wifi_state_machine.c b/Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/user/wifi_state_machine.c new file mode 100644 index 0000000..4af4fc0 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/wifi_station_machine_demo/user/wifi_state_machine.c @@ -0,0 +1,247 @@ +/* + * ESPRSSIF MIT License + * + * Copyright (c) 2017 + * + * 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 +#include "espressif/c_types.h" +#include "lwipopts.h" +#include "lwip/ip_addr.h" +#include "espressif/esp_libc.h" +#include "espressif/esp_misc.h" +#include "espressif/esp_common.h" +#include "espressif/esp_wifi.h" +#include "espressif/esp_sta.h" +#include "espressif/esp_softap.h" +#include "wifi_state_machine.h" + +typedef void (* wifi_state_cb_t)(); + +wifi_state_cb_t on_station_first_connect = NULL; +wifi_state_cb_t on_station_connect = NULL; +wifi_disco_cb_t on_station_disconnect = NULL; + +wifi_state_cb_t on_client_connect = NULL; +wifi_state_cb_t on_client_disconnect = NULL; + +volatile bool wifi_station_static_ip = false; +volatile bool wifi_station_is_connected = false; + +void ICACHE_FLASH_ATTR wifi_event_handler_cb(System_Event_t *event) +{ + static bool station_was_connected = false; + if (event == NULL) { + return; + } + + //os_printf("[WiFi] event %u\n", event->event_id); + + switch (event->event_id) { + case EVENT_STAMODE_DISCONNECTED: + wifi_station_is_connected = false; + Event_StaMode_Disconnected_t *ev = (Event_StaMode_Disconnected_t *)&event->event_info; + if(on_station_disconnect){ + on_station_disconnect(ev->reason); + } + break; + case EVENT_STAMODE_CONNECTED: + if(wifi_station_static_ip){ + wifi_station_is_connected = true; + if(!station_was_connected){ + station_was_connected = true; + if(on_station_first_connect){ + on_station_first_connect(); + } + } + if(on_station_connect){ + on_station_connect(); + } + } + break; + case EVENT_STAMODE_DHCP_TIMEOUT: + if(wifi_station_is_connected){ + wifi_station_is_connected = false; + if(on_station_disconnect){ + on_station_disconnect(REASON_UNSPECIFIED); + } + } + break; + case EVENT_STAMODE_GOT_IP: + wifi_station_is_connected = true; + if(!station_was_connected){ + station_was_connected = true; + if(on_station_first_connect){ + on_station_first_connect(); + } + } + if(on_station_connect){ + on_station_connect(); + } + break; + + case EVENT_SOFTAPMODE_STACONNECTED: + if(on_client_connect){ + on_client_connect(); + } + break; + case EVENT_SOFTAPMODE_STADISCONNECTED: + if(on_client_disconnect){ + on_client_disconnect(); + } + break; + default: + break; + } +} + +void ICACHE_FLASH_ATTR set_on_station_first_connect(wifi_state_cb_t cb){ + on_station_first_connect = cb; +} + +void ICACHE_FLASH_ATTR set_on_station_connect(wifi_state_cb_t cb){ + on_station_connect = cb; +} + +void ICACHE_FLASH_ATTR set_on_station_disconnect(wifi_disco_cb_t cb){ + on_station_disconnect = cb; +} + +void ICACHE_FLASH_ATTR set_on_client_connect(wifi_state_cb_t cb){ + on_client_connect = cb; +} + +void ICACHE_FLASH_ATTR set_on_client_disconnect(wifi_state_cb_t cb){ + on_client_disconnect = cb; +} + +bool ICACHE_FLASH_ATTR wifi_set_mode(WIFI_MODE mode){ + if(!mode){ + bool s = wifi_set_opmode(mode); + wifi_fpm_open(); + wifi_fpm_set_sleep_type(MODEM_SLEEP_T); + wifi_fpm_do_sleep(0xFFFFFFFF); + return s; + } + wifi_fpm_close(); + return wifi_set_opmode(mode); +} + +WIFI_MODE ICACHE_FLASH_ATTR init_esp_wifi(){ + wifi_set_event_handler_cb(wifi_event_handler_cb); + WIFI_MODE mode = wifi_get_opmode_default(); + wifi_set_mode(mode); + return mode; +} + +bool ICACHE_FLASH_ATTR start_wifi_station(const char * ssid, const char * pass){ + WIFI_MODE mode = wifi_get_opmode(); + if((mode & STATION_MODE) == 0){ + mode |= STATION_MODE; + if(!wifi_set_mode(mode)){ + os_printf("Failed to enable Station mode!\n"); + return false; + } + } + if(!ssid){ + os_printf("No SSID Given. Will connect to the station saved in flash\n"); + return true; + } + struct station_config config; + memset(&config, 0, sizeof(struct station_config)); + strcpy(config.ssid, ssid); + if(pass){ + strcpy(config.password, pass); + } + if(!wifi_station_set_config(&config)){ + os_printf("Failed to set Station config!\n"); + return false; + } + + if(!wifi_station_dhcpc_status()){ + os_printf("DHCP is not started. Starting it...\n"); + if(!wifi_station_dhcpc_start()){ + os_printf("DHCP start failed!\n"); + return false; + } + } + return wifi_station_connect(); +} + +bool ICACHE_FLASH_ATTR stop_wifi_station(){ + WIFI_MODE mode = wifi_get_opmode(); + mode &= ~STATION_MODE; + if(!wifi_set_mode(mode)){ + os_printf("Failed to disable Station mode!\n"); + return false; + } + return true; +} + +bool ICACHE_FLASH_ATTR start_wifi_ap(const char * ssid, const char * pass){ + WIFI_MODE mode = wifi_get_opmode(); + if((mode & SOFTAP_MODE) == 0){ + mode |= SOFTAP_MODE; + if(!wifi_set_mode(mode)){ + os_printf("Failed to enable AP mode!\n"); + return false; + } + } + if(!ssid){ + os_printf("No SSID Given. Will start the AP saved in flash\n"); + return true; + } + struct softap_config config; + bzero(&config, sizeof(struct softap_config)); + sprintf(config.ssid, ssid); + if(pass){ + sprintf(config.password, pass); + } + return wifi_softap_set_config(&config); +} + +bool ICACHE_FLASH_ATTR stop_wifi_ap(){ + WIFI_MODE mode = wifi_get_opmode(); + mode &= ~SOFTAP_MODE; + if(!wifi_set_mode(mode)){ + os_printf("Failed to disable AP mode!\n"); + return false; + } + return true; +} + +bool ICACHE_FLASH_ATTR wifi_station_connected(){ + if(!wifi_station_is_connected){ + return false; + } + WIFI_MODE mode = wifi_get_opmode(); + if((mode & STATION_MODE) == 0){ + return false; + } + STATION_STATUS wifistate = wifi_station_get_connect_status(); + wifi_station_is_connected = (wifistate == STATION_GOT_IP || (wifi_station_static_ip && wifistate == STATION_CONNECTING)); + return wifi_station_is_connected; +} + +bool ICACHE_FLASH_ATTR wifi_ap_enabled(){ + return !!(wifi_get_opmode() & SOFTAP_MODE); +} + diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/wps_demo/Makefile b/Distrib/ESPressif/RTOS/1.5.0/examples/wps_demo/Makefile new file mode 100644 index 0000000..a36b22b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/wps_demo/Makefile @@ -0,0 +1,132 @@ +############################################################# +# 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 + +LDDIR = $(SDK_PATH)/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$(SDK_PATH)/lib \ + -Wl,--gc-sections \ + -nostdlib \ + -T$(LD_FILE) \ + -Wl,--no-check-sections \ + -u call_user_start \ + -Wl,-static \ + -Wl,--start-group \ + -lcirom \ + -lcrypto \ + -lespconn \ + -lespnow \ + -lfreertos \ + -lgcc \ + -lhal \ + -ljson \ + -llwip \ + -lmain \ + -lmesh \ + -lmirom \ + -lnet80211 \ + -lnopoll \ + -lphy \ + -lpp \ + -lpwm \ + -lmbedtls \ + -lopenssl \ + -lsmartconfig \ + -lspiffs \ + -lwpa \ + -lwps \ + $(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 -D__STDC_NO_ATOMICS__=1 -DESP8266_RTOS -D__STDC_VERSION__=201112L -DFREERTOS_ARCH_ESP8266 +#-DNO_LOGGING=1 + +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 +sinclude $(SDK_PATH)/Makefile + +.PHONY: FORCE +FORCE: + diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/wps_demo/gen_misc.bat b/Distrib/ESPressif/RTOS/1.5.0/examples/wps_demo/gen_misc.bat new file mode 100644 index 0000000..fbb53be --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/wps_demo/gen_misc.bat @@ -0,0 +1,172 @@ +@echo off + +Rem ******NOTICE****** +Rem MUST set SDK_PATH & BIN_PATH firstly!!! +Rem example: +Rem set SDK_PATH=/c/esp_iot_sdk_freertos +Rem set BIN_PATH=/c/esp8266_bin + +set SDK_PATH="" +set BIN_PATH="" + +echo gen_misc.bat version 20150911 +echo . + +if not %SDK_PATH% == "" ( + echo SDK_PATH: %SDK_PATH% +) else ( + echo ERROR: Please set SDK_PATH in gen_misc.bat firstly, exit!!! + goto end +) + +if not %BIN_PATH% == "" ( + echo BIN_PATH: %BIN_PATH% +) else ( + echo ERROR: Please set BIN_PATH in gen_misc.bat firstly, exit!!! + goto end +) + +echo . +echo Please check SDK_PATH/BIN_PATH, enter (Y/y) to continue: +set input=default +set /p input= + +if not %input% == Y ( + if not %input% == y ( + goto end + ) +) + +echo . +echo Please follow below steps(1-5) to generate specific bin(s): +echo STEP 1: use boot_v1.2+ by default +set boot=new + +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 + ) + ) + ) + ) +) + +echo. +echo start... +echo. + +make clean + +make COMPILE=xcc BOOT=%boot% APP=%app% SPI_SPEED=%spi_speed% SPI_MODE=%spi_mode% SPI_SIZE_MAP=%spi_size_map% + +:end \ No newline at end of file diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/wps_demo/gen_misc.sh b/Distrib/ESPressif/RTOS/1.5.0/examples/wps_demo/gen_misc.sh new file mode 100644 index 0000000..c8ffb4e --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/wps_demo/gen_misc.sh @@ -0,0 +1,176 @@ +#!/bin/bash + +:< + * + * 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/Distrib/ESPressif/RTOS/1.5.0/examples/wps_demo/readme.txt b/Distrib/ESPressif/RTOS/1.5.0/examples/wps_demo/readme.txt new file mode 100644 index 0000000..e0588e3 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/wps_demo/readme.txt @@ -0,0 +1,56 @@ +This is a simple project template. + +sample_lib is an example for multi-level folder Makefile, notice the folder structure and each Makefile, you can get the clue. + + +HOWTO: +1. Copy this folder to anywhere. +Example: + Copy to ~/workspace/project_template + You can rename this folder as you like. + +2. Export SDK_PATH and BIN_PATH. +Example: + Your SDK path is ~/esp_iot_rtos_sdk, and want generate bin at ~/esp8266_bin. + Do follow steps: + 1>. export SDK_PATH=~/esp_iot_rtos_sdk + 2>. export BIN_PATH=~/esp8266_bin + SDK and project are seperate, you can update SDK without change your project. + +3. Enter project_template folder, run ./gen_misc.sh, and follow the tips and steps. + + +Compile Options: +(1) COMPILE + Possible value: xcc + Default value: + If not set, use gcc 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: new + +(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 diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/wps_demo/user/Makefile b/Distrib/ESPressif/RTOS/1.5.0/examples/wps_demo/user/Makefile new file mode 100644 index 0000000..373aa7a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/wps_demo/user/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 +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 ../sample_lib/azureiot/azure-c-shared-utility/inc +INCLUDES += -I ../sample_lib/azureiot/azure-umqtt-c/inc +INCLUDES += -I ../sample_lib/azureiot/parson +INCLUDES += -I ../sample_lib/azureiot/iothub_client/inc +INCLUDES += -I ../../../include/espressif/esp8266 +INCLUDES += -I ../../../include +INCLUDES += -I ../../../include/openssl +PDIR := ../$(PDIR) + +sinclude $(PDIR)Makefile + diff --git a/Distrib/ESPressif/RTOS/1.5.0/examples/wps_demo/user/user_main.c b/Distrib/ESPressif/RTOS/1.5.0/examples/wps_demo/user/user_main.c new file mode 100644 index 0000000..c10a7e2 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/examples/wps_demo/user/user_main.c @@ -0,0 +1,99 @@ +/****************************************************************************** + * Copyright 2013-2014 Espressif Systems (Wuxi) + * + * FileName: user_main.c + * + * Description: entry file of user application + * + * Modification history: + * 2015/7/3, v1.0 create this file. +*******************************************************************************/ + +#include "esp_common.h" +#include +#include +#include +#include "esp_wps.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" + +LOCAL void user_wps_status_cb(int status) +{ + printf("scan status %d\n", 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 user_wps_start(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 user_rf_cal_sector_set(void) +{ + 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; + + default: + rf_cal_sec = 0; + break; + } + + return rf_cal_sec; +} +LOCAL void wps_task(void *pvParameters) +{ + wifi_set_opmode(STATION_MODE); + user_wps_start(); + vTaskDelete(NULL); +} +void user_init(void) +{ + + xTaskCreate(wps_task, "wps_task", 1024, NULL, 4, NULL); + + +} \ No newline at end of file diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/cacheasm.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/cacheasm.h new file mode 100644 index 0000000..7111fec --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/cacheasm.h @@ -0,0 +1,807 @@ +/* + * xtensa/cacheasm.h -- assembler-specific cache related definitions + * that depend on CORE configuration + * + * This file is logically part of xtensa/coreasm.h , + * but is kept separate for modularity / compilation-performance. + */ + +/* + * Copyright (c) 2001-2002, 2006 Tensilica Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef XTENSA_CACHEASM_H +#define XTENSA_CACHEASM_H + +#include +#include + +/* + * This header file defines assembler macros of the form: + * cache_ + * where is 'i' or 'd' for instruction and data caches, + * and indicates the function of the macro. + * + * The following functions are defined, + * and apply only to the specified cache (I or D): + * + * reset + * Resets the cache. + * + * sync + * Makes sure any previous cache instructions have been completed; + * ie. makes sure any previous cache control operations + * have had full effect and been synchronized to memory. + * Eg. any invalidate completed [so as not to generate a hit], + * any writebacks or other pipelined writes written to memory, etc. + * + * invalidate_line (single cache line) + * invalidate_region (specified memory range) + * invalidate_all (entire cache) + * Invalidates all cache entries that cache + * data from the specified memory range. + * NOTE: locked entries are not invalidated. + * + * writeback_line (single cache line) + * writeback_region (specified memory range) + * writeback_all (entire cache) + * Writes back to memory all dirty cache entries + * that cache data from the specified memory range, + * and marks these entries as clean. + * NOTE: on some future implementations, this might + * also invalidate. + * NOTE: locked entries are written back, but never invalidated. + * NOTE: instruction caches never implement writeback. + * + * writeback_inv_line (single cache line) + * writeback_inv_region (specified memory range) + * writeback_inv_all (entire cache) + * Writes back to memory all dirty cache entries + * that cache data from the specified memory range, + * and invalidates these entries (including all clean + * cache entries that cache data from that range). + * NOTE: locked entries are written back but not invalidated. + * NOTE: instruction caches never implement writeback. + * + * lock_line (single cache line) + * lock_region (specified memory range) + * Prefetch and lock the specified memory range into cache. + * NOTE: if any part of the specified memory range cannot + * be locked, a Load/Store Error (for dcache) or Instruction + * Fetch Error (for icache) exception occurs. These macros don't + * do anything special (yet anyway) to handle this situation. + * + * unlock_line (single cache line) + * unlock_region (specified memory range) + * unlock_all (entire cache) + * Unlock cache entries that cache the specified memory range. + * Entries not already locked are unaffected. + * + * coherence_on + * coherence_off + * Turn off and on cache coherence + * + */ + + + +/*************************** GENERIC -- ALL CACHES ***************************/ + + +/* + * The following macros assume the following cache size/parameter limits + * in the current Xtensa core implementation: + * cache size: 1024 bytes minimum + * line size: 16 - 64 bytes + * way count: 1 - 4 + * + * Minimum entries per way (ie. per associativity) = 1024 / 64 / 4 = 4 + * Hence the assumption that each loop can execute four cache instructions. + * + * Correspondingly, the offset range of instructions is assumed able to cover + * four lines, ie. offsets {0,1,2,3} * line_size are assumed valid for + * both hit and indexed cache instructions. Ie. these offsets are all + * valid: 0, 16, 32, 48, 64, 96, 128, 192 (for line sizes 16, 32, 64). + * This is true of all original cache instructions + * (dhi, ihi, dhwb, dhwbi, dii, iii) which have offsets + * of 0 to 1020 in multiples of 4 (ie. 8 bits shifted by 2). + * This is also true of subsequent cache instructions + * (dhu, ihu, diu, iiu, diwb, diwbi, dpfl, ipfl) which have offsets + * of 0 to 240 in multiples of 16 (ie. 4 bits shifted by 4). + * + * (Maximum cache size, currently 32k, doesn't affect the following macros. + * Cache ways > MMU min page size cause aliasing but that's another matter.) + */ + + + +/* + * Macro to apply an 'indexed' cache instruction to the entire cache. + * + * Parameters: + * cainst instruction/ that takes an address register parameter + * and an offset parameter (in range 0 .. 3*linesize). + * size size of cache in bytes + * linesize size of cache line in bytes (always power-of-2) + * assoc_or1 number of associativities (ways/sets) in cache + * if all sets affected by cainst, + * or 1 if only one set (or not all sets) of the cache + * is affected by cainst (eg. DIWB or DIWBI [not yet ISA defined]). + * aa, ab unique address registers (temporaries) + * loopokay 1 (default) allows use of zero-overhead loops, 0 does not + * immrange range (max value) of cainst's immediate offset parameter, in bytes + * (NOTE: macro assumes immrange allows power-of-2 number of lines) + */ + + .macro cache_index_all cainst, size, linesize, assoc_or1, aa, ab, loopokay=1, maxofs=240 + + // Number of indices in cache (lines per way): + .set .Lindices, (\size / (\linesize * \assoc_or1)) + // Number of indices processed per loop iteration (max 4): + .set .Lperloop, .Lindices + .ifgt .Lperloop - 4 + .set .Lperloop, 4 + .endif + // Also limit instructions per loop if cache line size exceeds immediate range: + .set .Lmaxperloop, (\maxofs / \linesize) + 1 + .ifgt .Lperloop - .Lmaxperloop + .set .Lperloop, .Lmaxperloop + .endif + // Avoid addi of 128 which takes two instructions (addmi,addi): + .ifeq .Lperloop*\linesize - 128 + .ifgt .Lperloop - 1 + .set .Lperloop, .Lperloop / 2 + .endif + .endif + + // \size byte cache, \linesize byte lines, \assoc_or1 way(s) affected by each \cainst. + .ifne (\loopokay & XCHAL_HAVE_LOOPS) + + movi \aa, .Lindices / .Lperloop // number of loop iterations + // Possible improvement: need only loop if \aa > 1 ; + // however \aa == 1 is highly unlikely. + movi \ab, 0 // to iterate over cache + loop \aa, .Lend_cachex\@ + .set .Li, 0 ; .rept .Lperloop + \cainst \ab, .Li*\linesize + .set .Li, .Li+1 ; .endr + addi \ab, \ab, .Lperloop*\linesize // move to next line +.Lend_cachex\@: + + .else + + movi \aa, (\size / \assoc_or1) + // Possible improvement: need only loop if \aa > 1 ; + // however \aa == 1 is highly unlikely. + movi \ab, 0 // to iterate over cache +.Lstart_cachex\@: + .set .Li, 0 ; .rept .Lperloop + \cainst \ab, .Li*\linesize + .set .Li, .Li+1 ; .endr + addi \ab, \ab, .Lperloop*\linesize // move to next line + bltu \ab, \aa, .Lstart_cachex\@ + + .endif + + .endm + + +/* + * Macro to apply a 'hit' cache instruction to a memory region, + * ie. to any cache entries that cache a specified portion (region) of memory. + * Takes care of the unaligned cases, ie. may apply to one + * more cache line than $asize / lineSize if $aaddr is not aligned. + * + * + * Parameters are: + * cainst instruction/macro that takes an address register parameter + * and an offset parameter (currently always zero) + * and generates a cache instruction (eg. "dhi", "dhwb", "ihi", etc.) + * linesize_log2 log2(size of cache line in bytes) + * addr register containing start address of region (clobbered) + * asize register containing size of the region in bytes (clobbered) + * askew unique register used as temporary + * + * Note: A possible optimization to this macro is to apply the operation + * to the entire cache if the region exceeds the size of the cache + * by some empirically determined amount or factor. Some experimentation + * is required to determine the appropriate factors, which also need + * to be tunable if required. + */ + + .macro cache_hit_region cainst, linesize_log2, addr, asize, askew + + // Make \asize the number of iterations: + extui \askew, \addr, 0, \linesize_log2 // get unalignment amount of \addr + add \asize, \asize, \askew // ... and add it to \asize + addi \asize, \asize, (1 << \linesize_log2) - 1 // round up! + srli \asize, \asize, \linesize_log2 + + // Iterate over region: + floopnez \asize, cacheh\@ + \cainst \addr, 0 + addi \addr, \addr, (1 << \linesize_log2) // move to next line + floopend \asize, cacheh\@ + + .endm + + + + + +/*************************** INSTRUCTION CACHE ***************************/ + + +/* + * Reset/initialize the instruction cache by simply invalidating it: + * (need to unlock first also, if cache locking implemented): + * + * Parameters: + * aa, ab unique address registers (temporaries) + */ + .macro icache_reset aa, ab, loopokay=0 + icache_unlock_all \aa, \ab, \loopokay + icache_invalidate_all \aa, \ab, \loopokay + .endm + + +/* + * Synchronize after an instruction cache operation, + * to be sure everything is in sync with memory as to be + * expected following any previous instruction cache control operations. + * + * Even if a config doesn't have caches, an isync is still needed + * when instructions in any memory are modified, whether by a loader + * or self-modifying code. Therefore, this macro always produces + * an isync, whether or not an icache is present. + * + * Parameters are: + * ar an address register (temporary) (currently unused, but may be used in future) + */ + .macro icache_sync ar + isync + .endm + + + +/* + * Invalidate a single line of the instruction cache. + * Parameters are: + * ar address register that contains (virtual) address to invalidate + * (may get clobbered in a future implementation, but not currently) + * offset (optional) offset to add to \ar to compute effective address to invalidate + * (note: some number of lsbits are ignored) + */ + .macro icache_invalidate_line ar, offset +#if XCHAL_ICACHE_SIZE > 0 + ihi \ar, \offset // invalidate icache line + /* + * NOTE: in some early version of a test chip silicon (SiChip1), + * 'ihi' didn't work, so software had to replace it with + * the much more draconian 'iii' + * (which would just invalidate more than it should, + * which should be okay other than the performance hit + * because cache locking did not exist in that version, + * unless user somehow relies on something being cached). + * + * #if ... targeting this ancient, now non-existent, test chip silicon ... + * iii \ar, \offset + * #endif + */ + icache_sync \ar +#endif + .endm + + + + +/* + * Invalidate instruction cache entries that cache a specified portion of memory. + * Parameters are: + * astart start address (register gets clobbered) + * asize size of the region in bytes (register gets clobbered) + * ac unique register used as temporary + */ + .macro icache_invalidate_region astart, asize, ac +#if XCHAL_ICACHE_SIZE > 0 + // Instruction cache region invalidation: + cache_hit_region ihi, XCHAL_ICACHE_LINEWIDTH, \astart, \asize, \ac + icache_sync \ac + // End of instruction cache region invalidation +#endif + .endm + + + +/* + * Invalidate entire instruction cache. + * + * Parameters: + * aa, ab unique address registers (temporaries) + */ + .macro icache_invalidate_all aa, ab, loopokay=1 +#if XCHAL_ICACHE_SIZE > 0 + // Instruction cache invalidation: + cache_index_all iii, XCHAL_ICACHE_SIZE, XCHAL_ICACHE_LINESIZE, XCHAL_ICACHE_WAYS, \aa, \ab, \loopokay, 1020 + icache_sync \aa + // End of instruction cache invalidation +#endif + .endm + + + +/* + * Lock (prefetch & lock) a single line of the instruction cache. + * + * Parameters are: + * ar address register that contains (virtual) address to lock + * (may get clobbered in a future implementation, but not currently) + * offset offset to add to \ar to compute effective address to lock + * (note: some number of lsbits are ignored) + */ + .macro icache_lock_line ar, offset +#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE + ipfl \ar, \offset /* prefetch and lock icache line */ + icache_sync \ar +#endif + .endm + + + +/* + * Lock (prefetch & lock) a specified portion of memory into the instruction cache. + * Parameters are: + * astart start address (register gets clobbered) + * asize size of the region in bytes (register gets clobbered) + * ac unique register used as temporary + */ + .macro icache_lock_region astart, asize, ac +#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE + // Instruction cache region lock: + cache_hit_region ipfl, XCHAL_ICACHE_LINEWIDTH, \astart, \asize, \ac + icache_sync \ac + // End of instruction cache region lock +#endif + .endm + + + +/* + * Unlock a single line of the instruction cache. + * + * Parameters are: + * ar address register that contains (virtual) address to unlock + * (may get clobbered in a future implementation, but not currently) + * offset offset to add to \ar to compute effective address to unlock + * (note: some number of lsbits are ignored) + */ + .macro icache_unlock_line ar, offset +#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE + ihu \ar, \offset /* unlock icache line */ + icache_sync \ar +#endif + .endm + + + +/* + * Unlock a specified portion of memory from the instruction cache. + * Parameters are: + * astart start address (register gets clobbered) + * asize size of the region in bytes (register gets clobbered) + * ac unique register used as temporary + */ + .macro icache_unlock_region astart, asize, ac +#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE + // Instruction cache region unlock: + cache_hit_region ihu, XCHAL_ICACHE_LINEWIDTH, \astart, \asize, \ac + icache_sync \ac + // End of instruction cache region unlock +#endif + .endm + + + +/* + * Unlock entire instruction cache. + * + * Parameters: + * aa, ab unique address registers (temporaries) + */ + .macro icache_unlock_all aa, ab, loopokay=1 +#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE + // Instruction cache unlock: + cache_index_all iiu, XCHAL_ICACHE_SIZE, XCHAL_ICACHE_LINESIZE, 1, \aa, \ab, \loopokay + icache_sync \aa + // End of instruction cache unlock +#endif + .endm + + + + + +/*************************** DATA CACHE ***************************/ + + + +/* + * Reset/initialize the data cache by simply invalidating it + * (need to unlock first also, if cache locking implemented): + * + * Parameters: + * aa, ab unique address registers (temporaries) + */ + .macro dcache_reset aa, ab, loopokay=0 + dcache_unlock_all \aa, \ab, \loopokay + dcache_invalidate_all \aa, \ab, \loopokay + .endm + + + + +/* + * Synchronize after a data cache operation, + * to be sure everything is in sync with memory as to be + * expected following any previous data cache control operations. + * + * Parameters are: + * ar an address register (temporary) (currently unused, but may be used in future) + */ + .macro dcache_sync ar +#if XCHAL_DCACHE_SIZE > 0 + // This previous sequence errs on the conservative side (too much so); a DSYNC should be sufficient: + //memw // synchronize data cache changes relative to subsequent memory accesses + //isync // be conservative and ISYNC as well (just to be sure) + + dsync +#endif + .endm + + + +/* + * Opt into cache coherence. + * + * Parameters are: + * ar,at two scratch address registers (both clobbered) + */ + .macro cache_coherence_on ar at +#if XCHAL_HAVE_EXTERN_REGS && XCHAL_DCACHE_IS_COHERENT + movi \ar, 1 + movi \at, XER_CCON + wer \ar, \at + extw +# endif + .endm + + + +/* + * Opt out of cache coherence. + * NOTE: this is generally preceded by emptying the cache; + * see xthal_cache_coherence_optout() in hal/coherence.c for details. + * + * Parameters are: + * ar,at two scratch address registers (both clobbered) + */ + .macro cache_coherence_off ar at +#if XCHAL_HAVE_EXTERN_REGS && XCHAL_DCACHE_IS_COHERENT + extw + movi \at, 0 + movi \ar, XER_CCON + wer \at, \ar + extw +#endif + .endm + + + +/* + * Synchronize after a data store operation, + * to be sure the stored data is completely off the processor + * (and assuming there is no buffering outside the processor, + * that the data is in memory). This may be required to + * ensure that the processor's write buffers are emptied. + * A MEMW followed by a read guarantees this, by definition. + * We also try to make sure the read itself completes. + * + * Parameters are: + * ar an address register (temporary) + */ + .macro write_sync ar + memw // ensure previous memory accesses are complete prior to subsequent memory accesses + l32i \ar, sp, 0 // completing this read ensures any previous write has completed, because of MEMW + //slot + add \ar, \ar, \ar // use the result of the read to help ensure the read completes (in future architectures) + .endm + + +/* + * Invalidate a single line of the data cache. + * Parameters are: + * ar address register that contains (virtual) address to invalidate + * (may get clobbered in a future implementation, but not currently) + * offset (optional) offset to add to \ar to compute effective address to invalidate + * (note: some number of lsbits are ignored) + */ + .macro dcache_invalidate_line ar, offset +#if XCHAL_DCACHE_SIZE > 0 + dhi \ar, \offset + dcache_sync \ar +#endif + .endm + + + + + +/* + * Invalidate data cache entries that cache a specified portion of memory. + * Parameters are: + * astart start address (register gets clobbered) + * asize size of the region in bytes (register gets clobbered) + * ac unique register used as temporary + */ + .macro dcache_invalidate_region astart, asize, ac +#if XCHAL_DCACHE_SIZE > 0 + // Data cache region invalidation: + cache_hit_region dhi, XCHAL_DCACHE_LINEWIDTH, \astart, \asize, \ac + dcache_sync \ac + // End of data cache region invalidation +#endif + .endm + + + +#if 0 +/* + * This is a work-around for a bug in SiChip1. + * To enable the work-around, uncomment this and replace 'dii' + * with 'dii_s1' everywhere, eg. in the dcache_invalidate_all + * macro below. + */ + .macro dii_s1 ar, offset + dii \ar, \offset + or \ar, \ar, \ar + or \ar, \ar, \ar + or \ar, \ar, \ar + or \ar, \ar, \ar + .endm +#endif + + +/* + * Invalidate entire data cache. + * + * Parameters: + * aa, ab unique address registers (temporaries) + */ + .macro dcache_invalidate_all aa, ab, loopokay=1 +#if XCHAL_DCACHE_SIZE > 0 + // Data cache invalidation: + cache_index_all dii, XCHAL_DCACHE_SIZE, XCHAL_DCACHE_LINESIZE, XCHAL_DCACHE_WAYS, \aa, \ab, \loopokay, 1020 + dcache_sync \aa + // End of data cache invalidation +#endif + .endm + + + +/* + * Writeback a single line of the data cache. + * Parameters are: + * ar address register that contains (virtual) address to writeback + * (may get clobbered in a future implementation, but not currently) + * offset offset to add to \ar to compute effective address to writeback + * (note: some number of lsbits are ignored) + */ + .macro dcache_writeback_line ar, offset +#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_IS_WRITEBACK + dhwb \ar, \offset + dcache_sync \ar +#endif + .endm + + + +/* + * Writeback dirty data cache entries that cache a specified portion of memory. + * Parameters are: + * astart start address (register gets clobbered) + * asize size of the region in bytes (register gets clobbered) + * ac unique register used as temporary + */ + .macro dcache_writeback_region astart, asize, ac +#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_IS_WRITEBACK + // Data cache region writeback: + cache_hit_region dhwb, XCHAL_DCACHE_LINEWIDTH, \astart, \asize, \ac + dcache_sync \ac + // End of data cache region writeback +#endif + .endm + + + +/* + * Writeback entire data cache. + * Parameters: + * aa, ab unique address registers (temporaries) + */ + .macro dcache_writeback_all aa, ab, loopokay=1 +#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_IS_WRITEBACK + // Data cache writeback: + cache_index_all diwb, XCHAL_DCACHE_SIZE, XCHAL_DCACHE_LINESIZE, 1, \aa, \ab, \loopokay + dcache_sync \aa + // End of data cache writeback +#endif + .endm + + + +/* + * Writeback and invalidate a single line of the data cache. + * Parameters are: + * ar address register that contains (virtual) address to writeback and invalidate + * (may get clobbered in a future implementation, but not currently) + * offset offset to add to \ar to compute effective address to writeback and invalidate + * (note: some number of lsbits are ignored) + */ + .macro dcache_writeback_inv_line ar, offset +#if XCHAL_DCACHE_SIZE > 0 + dhwbi \ar, \offset /* writeback and invalidate dcache line */ + dcache_sync \ar +#endif + .endm + + + +/* + * Writeback and invalidate data cache entries that cache a specified portion of memory. + * Parameters are: + * astart start address (register gets clobbered) + * asize size of the region in bytes (register gets clobbered) + * ac unique register used as temporary + */ + .macro dcache_writeback_inv_region astart, asize, ac +#if XCHAL_DCACHE_SIZE > 0 + // Data cache region writeback and invalidate: + cache_hit_region dhwbi, XCHAL_DCACHE_LINEWIDTH, \astart, \asize, \ac + dcache_sync \ac + // End of data cache region writeback and invalidate +#endif + .endm + + + +/* + * Writeback and invalidate entire data cache. + * Parameters: + * aa, ab unique address registers (temporaries) + */ + .macro dcache_writeback_inv_all aa, ab, loopokay=1 +#if XCHAL_DCACHE_SIZE > 0 + // Data cache writeback and invalidate: +#if XCHAL_DCACHE_IS_WRITEBACK + cache_index_all diwbi, XCHAL_DCACHE_SIZE, XCHAL_DCACHE_LINESIZE, 1, \aa, \ab, \loopokay + dcache_sync \aa +#else /*writeback*/ + // Data cache does not support writeback, so just invalidate: */ + dcache_invalidate_all \aa, \ab, \loopokay +#endif /*writeback*/ + // End of data cache writeback and invalidate +#endif + .endm + + + + +/* + * Lock (prefetch & lock) a single line of the data cache. + * + * Parameters are: + * ar address register that contains (virtual) address to lock + * (may get clobbered in a future implementation, but not currently) + * offset offset to add to \ar to compute effective address to lock + * (note: some number of lsbits are ignored) + */ + .macro dcache_lock_line ar, offset +#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE + dpfl \ar, \offset /* prefetch and lock dcache line */ + dcache_sync \ar +#endif + .endm + + + +/* + * Lock (prefetch & lock) a specified portion of memory into the data cache. + * Parameters are: + * astart start address (register gets clobbered) + * asize size of the region in bytes (register gets clobbered) + * ac unique register used as temporary + */ + .macro dcache_lock_region astart, asize, ac +#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE + // Data cache region lock: + cache_hit_region dpfl, XCHAL_DCACHE_LINEWIDTH, \astart, \asize, \ac + dcache_sync \ac + // End of data cache region lock +#endif + .endm + + + +/* + * Unlock a single line of the data cache. + * + * Parameters are: + * ar address register that contains (virtual) address to unlock + * (may get clobbered in a future implementation, but not currently) + * offset offset to add to \ar to compute effective address to unlock + * (note: some number of lsbits are ignored) + */ + .macro dcache_unlock_line ar, offset +#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE + dhu \ar, \offset /* unlock dcache line */ + dcache_sync \ar +#endif + .endm + + + +/* + * Unlock a specified portion of memory from the data cache. + * Parameters are: + * astart start address (register gets clobbered) + * asize size of the region in bytes (register gets clobbered) + * ac unique register used as temporary + */ + .macro dcache_unlock_region astart, asize, ac +#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE + // Data cache region unlock: + cache_hit_region dhu, XCHAL_DCACHE_LINEWIDTH, \astart, \asize, \ac + dcache_sync \ac + // End of data cache region unlock +#endif + .endm + + + +/* + * Unlock entire data cache. + * + * Parameters: + * aa, ab unique address registers (temporaries) + */ + .macro dcache_unlock_all aa, ab, loopokay=1 +#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE + // Data cache unlock: + cache_index_all diu, XCHAL_DCACHE_SIZE, XCHAL_DCACHE_LINESIZE, 1, \aa, \ab, \loopokay + dcache_sync \aa + // End of data cache unlock +#endif + .endm + + +#endif /*XTENSA_CACHEASM_H*/ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/cacheattrasm.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/cacheattrasm.h new file mode 100644 index 0000000..6e2f0ab --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/cacheattrasm.h @@ -0,0 +1,436 @@ +/* + * xtensa/cacheattrasm.h -- assembler-specific CACHEATTR register related definitions + * that depend on CORE configuration + * + * This file is logically part of xtensa/coreasm.h (or perhaps xtensa/cacheasm.h), + * but is kept separate for modularity / compilation-performance. + */ + +/* + * Copyright (c) 2001-2009 Tensilica Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef XTENSA_CACHEATTRASM_H +#define XTENSA_CACHEATTRASM_H + +#include + +/* Determine whether cache attributes are controlled using eight 512MB entries: */ +#define XCHAL_CA_8X512 (XCHAL_HAVE_CACHEATTR || XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR \ + || (XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY)) + + +/* + * This header file defines assembler macros of the form: + * cacheattr_ + * where: + * is 'i', 'd' or absent for instruction, data + * or both caches; and + * indicates the function of the macro. + * + * The following functions are defined: + * + * icacheattr_get + * Reads I-cache CACHEATTR into a2 (clobbers a3-a5). + * + * dcacheattr_get + * Reads D-cache CACHEATTR into a2 (clobbers a3-a5). + * (Note: for configs with a real CACHEATTR register, the + * above two macros are identical.) + * + * cacheattr_set + * Writes both I-cache and D-cache CACHEATTRs from a2 (a3-a8 clobbered). + * Works even when changing one's own code's attributes. + * + * icacheattr_is_enabled label + * Branches to \label if I-cache appears to have been enabled + * (eg. if CACHEATTR contains a cache-enabled attribute). + * (clobbers a2-a5,SAR) + * + * dcacheattr_is_enabled label + * Branches to \label if D-cache appears to have been enabled + * (eg. if CACHEATTR contains a cache-enabled attribute). + * (clobbers a2-a5,SAR) + * + * cacheattr_is_enabled label + * Branches to \label if either I-cache or D-cache appears to have been enabled + * (eg. if CACHEATTR contains a cache-enabled attribute). + * (clobbers a2-a5,SAR) + * + * The following macros are only defined under certain conditions: + * + * icacheattr_set (if XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR) + * Writes I-cache CACHEATTR from a2 (a3-a8 clobbered). + * + * dcacheattr_set (if XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR) + * Writes D-cache CACHEATTR from a2 (a3-a8 clobbered). + */ + + + +/*************************** GENERIC -- ALL CACHES ***************************/ + +/* + * _cacheattr_get + * + * (Internal macro.) + * Returns value of CACHEATTR register (or closest equivalent) in a2. + * + * Entry: + * (none) + * Exit: + * a2 value read from CACHEATTR + * a3-a5 clobbered (temporaries) + */ + .macro _cacheattr_get tlb +#if XCHAL_HAVE_CACHEATTR + rsr a2, CACHEATTR +#elif XCHAL_CA_8X512 + // We have a config that "mimics" CACHEATTR using a simplified + // "MMU" composed of a single statically-mapped way. + // DTLB and ITLB are independent, so there's no single + // cache attribute that can describe both. So for now + // just return the DTLB state. + movi a5, 0xE0000000 + movi a2, 0 + movi a3, XCHAL_SPANNING_WAY +1: add a3, a3, a5 // next segment + r&tlb&1 a4, a3 // get PPN+CA of segment at 0xE0000000, 0xC0000000, ..., 0 + dsync // interlock??? + slli a2, a2, 4 + extui a4, a4, 0, 4 // extract CA + or a2, a2, a4 + bgeui a3, 16, 1b +#else + // This macro isn't applicable to arbitrary MMU configurations. + // Just return zero. + movi a2, 0 +#endif + .endm + + .macro icacheattr_get + _cacheattr_get itlb + .endm + + .macro dcacheattr_get + _cacheattr_get dtlb + .endm + + +/* Default (powerup/reset) value of CACHEATTR, + all BYPASS mode (ie. disabled/bypassed caches): */ +#if XCHAL_HAVE_PTP_MMU +# define XCHAL_CACHEATTR_ALL_BYPASS 0x33333333 +#else +# define XCHAL_CACHEATTR_ALL_BYPASS 0x22222222 +#endif + +#if XCHAL_CA_8X512 + +#if XCHAL_HAVE_PTP_MMU +# define XCHAL_FCA_ENAMASK 0x0AA0 /* bitmap of fetch attributes that require enabled icache */ +# define XCHAL_LCA_ENAMASK 0x0FF0 /* bitmap of load attributes that require enabled dcache */ +# define XCHAL_SCA_ENAMASK 0x0CC0 /* bitmap of store attributes that require enabled dcache */ +#else +# define XCHAL_FCA_ENAMASK 0x003A /* bitmap of fetch attributes that require enabled icache */ +# define XCHAL_LCA_ENAMASK 0x0033 /* bitmap of load attributes that require enabled dcache */ +# define XCHAL_SCA_ENAMASK 0x0033 /* bitmap of store attributes that require enabled dcache */ +#endif +#define XCHAL_LSCA_ENAMASK (XCHAL_LCA_ENAMASK|XCHAL_SCA_ENAMASK) /* l/s attrs requiring enabled dcache */ +#define XCHAL_ALLCA_ENAMASK (XCHAL_FCA_ENAMASK|XCHAL_LSCA_ENAMASK) /* all attrs requiring enabled caches */ + +/* + * _cacheattr_is_enabled + * + * (Internal macro.) + * Branches to \label if CACHEATTR in a2 indicates an enabled + * cache, using mask in a3. + * + * Parameters: + * label where to branch to if cache is enabled + * Entry: + * a2 contains CACHEATTR value used to determine whether + * caches are enabled + * a3 16-bit constant where each bit correspond to + * one of the 16 possible CA values (in a CACHEATTR mask); + * CA values that indicate the cache is enabled + * have their corresponding bit set in this mask + * (eg. use XCHAL_xCA_ENAMASK , above) + * Exit: + * a2,a4,a5 clobbered + * SAR clobbered + */ + .macro _cacheattr_is_enabled label + movi a4, 8 // loop 8 times +.Lcaife\@: + extui a5, a2, 0, 4 // get CA nibble + ssr a5 // index into mask according to CA... + srl a5, a3 // ...and get CA's mask bit in a5 bit 0 + bbsi.l a5, 0, \label // if CA indicates cache enabled, jump to label + srli a2, a2, 4 // next nibble + addi a4, a4, -1 + bnez a4, .Lcaife\@ // loop for each nibble + .endm + +#else /* XCHAL_CA_8X512 */ + .macro _cacheattr_is_enabled label + j \label // macro not applicable, assume caches always enabled + .endm +#endif /* XCHAL_CA_8X512 */ + + + +/* + * icacheattr_is_enabled + * + * Branches to \label if I-cache is enabled. + * + * Parameters: + * label where to branch to if icache is enabled + * Entry: + * (none) + * Exit: + * a2-a5, SAR clobbered (temporaries) + */ + .macro icacheattr_is_enabled label +#if XCHAL_CA_8X512 + icacheattr_get + movi a3, XCHAL_FCA_ENAMASK +#endif + _cacheattr_is_enabled \label + .endm + +/* + * dcacheattr_is_enabled + * + * Branches to \label if D-cache is enabled. + * + * Parameters: + * label where to branch to if dcache is enabled + * Entry: + * (none) + * Exit: + * a2-a5, SAR clobbered (temporaries) + */ + .macro dcacheattr_is_enabled label +#if XCHAL_CA_8X512 + dcacheattr_get + movi a3, XCHAL_LSCA_ENAMASK +#endif + _cacheattr_is_enabled \label + .endm + +/* + * cacheattr_is_enabled + * + * Branches to \label if either I-cache or D-cache is enabled. + * + * Parameters: + * label where to branch to if a cache is enabled + * Entry: + * (none) + * Exit: + * a2-a5, SAR clobbered (temporaries) + */ + .macro cacheattr_is_enabled label +#if XCHAL_HAVE_CACHEATTR + rsr a2, CACHEATTR + movi a3, XCHAL_ALLCA_ENAMASK +#elif XCHAL_CA_8X512 + icacheattr_get + movi a3, XCHAL_FCA_ENAMASK + _cacheattr_is_enabled \label + dcacheattr_get + movi a3, XCHAL_LSCA_ENAMASK +#endif + _cacheattr_is_enabled \label + .endm + + + +/* + * The ISA does not have a defined way to change the + * instruction cache attributes of the running code, + * ie. of the memory area that encloses the current PC. + * However, each micro-architecture (or class of + * configurations within a micro-architecture) + * provides a way to deal with this issue. + * + * Here are a few macros used to implement the relevant + * approach taken. + */ + +#if XCHAL_CA_8X512 && !XCHAL_HAVE_CACHEATTR + // We have a config that "mimics" CACHEATTR using a simplified + // "MMU" composed of a single statically-mapped way. + +/* + * icacheattr_set + * + * Entry: + * a2 cacheattr value to set + * Exit: + * a2 unchanged + * a3-a8 clobbered (temporaries) + */ + .macro icacheattr_set + + movi a5, 0xE0000000 // mask of upper 3 bits + movi a6, 3f // PC where ITLB is set + movi a3, XCHAL_SPANNING_WAY // start at region 0 (0 .. 7) + mov a7, a2 // copy a2 so it doesn't get clobbered + and a6, a6, a5 // upper 3 bits of local PC area + j 3f + + // Use micro-architecture specific method. + // The following 4-instruction sequence is aligned such that + // it all fits within a single I-cache line. Sixteen byte + // alignment is sufficient for this (using XCHAL_ICACHE_LINESIZE + // actually causes problems because that can be greater than + // the alignment of the reset vector, where this macro is often + // invoked, which would cause the linker to align the reset + // vector code away from the reset vector!!). + .begin no-transform + .align 16 /*XCHAL_ICACHE_LINESIZE*/ +1: witlb a4, a3 // write wired PTE (CA, no PPN) of 512MB segment to ITLB + isync + .end no-transform + nop + nop + + sub a3, a3, a5 // next segment (add 0x20000000) + bltui a3, 16, 4f // done? + + // Note that in the WITLB loop, we don't do any load/stores + // (may not be an issue here, but it is important in the DTLB case). +2: srli a7, a7, 4 // next CA +3: +# if XCHAL_HAVE_MIMIC_CACHEATTR + extui a4, a7, 0, 4 // extract CA to set +# else /* have translation, preserve it: */ + ritlb1 a8, a3 // get current PPN+CA of segment + //dsync // interlock??? + extui a4, a7, 0, 4 // extract CA to set + srli a8, a8, 4 // clear CA but keep PPN ... + slli a8, a8, 4 // ... + add a4, a4, a8 // combine new CA with PPN to preserve +# endif + beq a3, a6, 1b // current PC's region? if so, do it in a safe way + witlb a4, a3 // write wired PTE (CA [+PPN]) of 512MB segment to ITLB + sub a3, a3, a5 // next segment (add 0x20000000) + bgeui a3, 16, 2b + isync // make sure all ifetch changes take effect +4: + .endm // icacheattr_set + + +/* + * dcacheattr_set + * + * Entry: + * a2 cacheattr value to set + * Exit: + * a2 unchanged + * a3-a8 clobbered (temporaries) + */ + + .macro dcacheattr_set + + movi a5, 0xE0000000 // mask of upper 3 bits + movi a3, XCHAL_SPANNING_WAY // start at region 0 (0 .. 7) + mov a7, a2 // copy a2 so it doesn't get clobbered + // Note that in the WDTLB loop, we don't do any load/stores +2: // (including implicit l32r via movi) because it isn't safe. +# if XCHAL_HAVE_MIMIC_CACHEATTR + extui a4, a7, 0, 4 // extract CA to set +# else /* have translation, preserve it: */ + rdtlb1 a8, a3 // get current PPN+CA of segment + //dsync // interlock??? + extui a4, a7, 0, 4 // extract CA to set + srli a8, a8, 4 // clear CA but keep PPN ... + slli a8, a8, 4 // ... + add a4, a4, a8 // combine new CA with PPN to preserve +# endif + wdtlb a4, a3 // write wired PTE (CA [+PPN]) of 512MB segment to DTLB + sub a3, a3, a5 // next segment (add 0x20000000) + srli a7, a7, 4 // next CA + bgeui a3, 16, 2b + dsync // make sure all data path changes take effect + .endm // dcacheattr_set + +#endif /* XCHAL_CA_8X512 && !XCHAL_HAVE_CACHEATTR */ + + + +/* + * cacheattr_set + * + * Macro that sets the current CACHEATTR safely + * (both i and d) according to the current contents of a2. + * It works even when changing the cache attributes of + * the currently running code. + * + * Entry: + * a2 cacheattr value to set + * Exit: + * a2 unchanged + * a3-a8 clobbered (temporaries) + */ + .macro cacheattr_set + +#if XCHAL_HAVE_CACHEATTR +# if XCHAL_ICACHE_LINESIZE < 4 + // No i-cache, so can always safely write to CACHEATTR: + wsr a2, CACHEATTR +# else + // The Athens micro-architecture, when using the old + // exception architecture option (ie. with the CACHEATTR register) + // allows changing the cache attributes of the running code + // using the following exact sequence aligned to be within + // an instruction cache line. (NOTE: using XCHAL_ICACHE_LINESIZE + // alignment actually causes problems because that can be greater + // than the alignment of the reset vector, where this macro is often + // invoked, which would cause the linker to align the reset + // vector code away from the reset vector!!). + j 1f + .begin no-transform + .align 16 /*XCHAL_ICACHE_LINESIZE*/ // align to within an I-cache line +1: wsr a2, CACHEATTR + isync + .end no-transform + nop + nop +# endif +#elif XCHAL_CA_8X512 + // DTLB and ITLB are independent, but to keep semantics + // of this macro we simply write to both. + icacheattr_set + dcacheattr_set +#else + // This macro isn't applicable to arbitrary MMU configurations. + // Do nothing in this case. +#endif + .endm + + +#endif /*XTENSA_CACHEATTRASM_H*/ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/core-isa.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/core-isa.h new file mode 100644 index 0000000..a1045a2 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/core-isa.h @@ -0,0 +1,459 @@ +/* + * xtensa/config/core-isa.h -- HAL definitions that are dependent on Xtensa + * processor CORE configuration + * + * See , which includes this file, for more details. + */ + +/* Xtensa processor core configuration information. + + Customer ID=7011; Build=0x2b6f6; Copyright (c) 1999-2010 Tensilica Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _XTENSA_CORE_CONFIGURATION_H +#define _XTENSA_CORE_CONFIGURATION_H + + +/**************************************************************************** + Parameters Useful for Any Code, USER or PRIVILEGED + ****************************************************************************/ + +/* + * Note: Macros of the form XCHAL_HAVE_*** have a value of 1 if the option is + * configured, and a value of 0 otherwise. These macros are always defined. + */ + + +/*---------------------------------------------------------------------- + ISA + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_BE 0 /* big-endian byte ordering */ +#define XCHAL_HAVE_WINDOWED 0 /* windowed registers option */ +#define XCHAL_NUM_AREGS 16 /* num of physical addr regs */ +#define XCHAL_NUM_AREGS_LOG2 4 /* log2(XCHAL_NUM_AREGS) */ +#define XCHAL_MAX_INSTRUCTION_SIZE 3 /* max instr bytes (3..8) */ +#define XCHAL_HAVE_DEBUG 1 /* debug option */ +#define XCHAL_HAVE_DENSITY 1 /* 16-bit instructions */ +#define XCHAL_HAVE_LOOPS 0 /* zero-overhead loops */ +#define XCHAL_HAVE_NSA 1 /* NSA/NSAU instructions */ +#define XCHAL_HAVE_MINMAX 0 /* MIN/MAX instructions */ +#define XCHAL_HAVE_SEXT 0 /* SEXT instruction */ +#define XCHAL_HAVE_CLAMPS 0 /* CLAMPS instruction */ +#define XCHAL_HAVE_MUL16 1 /* MUL16S/MUL16U instructions */ +#define XCHAL_HAVE_MUL32 1 /* MULL instruction */ +#define XCHAL_HAVE_MUL32_HIGH 0 /* MULUH/MULSH instructions */ +#define XCHAL_HAVE_DIV32 0 /* QUOS/QUOU/REMS/REMU instructions */ +#define XCHAL_HAVE_L32R 1 /* L32R instruction */ +#define XCHAL_HAVE_ABSOLUTE_LITERALS 1 /* non-PC-rel (extended) L32R */ +#define XCHAL_HAVE_CONST16 0 /* CONST16 instruction */ +#define XCHAL_HAVE_ADDX 1 /* ADDX#/SUBX# instructions */ +#define XCHAL_HAVE_WIDE_BRANCHES 0 /* B*.W18 or B*.W15 instr's */ +#define XCHAL_HAVE_PREDICTED_BRANCHES 0 /* B[EQ/EQZ/NE/NEZ]T instr's */ +#define XCHAL_HAVE_CALL4AND12 0 /* (obsolete option) */ +#define XCHAL_HAVE_ABS 1 /* ABS instruction */ +/*#define XCHAL_HAVE_POPC 0*/ /* POPC instruction */ +/*#define XCHAL_HAVE_CRC 0*/ /* CRC instruction */ +#define XCHAL_HAVE_RELEASE_SYNC 0 /* L32AI/S32RI instructions */ +#define XCHAL_HAVE_S32C1I 0 /* S32C1I instruction */ +#define XCHAL_HAVE_SPECULATION 0 /* speculation */ +#define XCHAL_HAVE_FULL_RESET 1 /* all regs/state reset */ +#define XCHAL_NUM_CONTEXTS 1 /* */ +#define XCHAL_NUM_MISC_REGS 0 /* num of scratch regs (0..4) */ +#define XCHAL_HAVE_TAP_MASTER 0 /* JTAG TAP control instr's */ +#define XCHAL_HAVE_PRID 1 /* processor ID register */ +#define XCHAL_HAVE_EXTERN_REGS 1 /* WER/RER instructions */ +#define XCHAL_HAVE_MP_INTERRUPTS 0 /* interrupt distributor port */ +#define XCHAL_HAVE_MP_RUNSTALL 0 /* core RunStall control port */ +#define XCHAL_HAVE_THREADPTR 0 /* THREADPTR register */ +#define XCHAL_HAVE_BOOLEANS 0 /* boolean registers */ +#define XCHAL_HAVE_CP 0 /* CPENABLE reg (coprocessor) */ +#define XCHAL_CP_MAXCFG 0 /* max allowed cp id plus one */ +#define XCHAL_HAVE_MAC16 0 /* MAC16 package */ +#define XCHAL_HAVE_VECTORFPU2005 0 /* vector floating-point pkg */ +#define XCHAL_HAVE_FP 0 /* floating point pkg */ +#define XCHAL_HAVE_DFP 0 /* double precision FP pkg */ +#define XCHAL_HAVE_DFP_accel 0 /* double precision FP acceleration pkg */ +#define XCHAL_HAVE_VECTRA1 0 /* Vectra I pkg */ +#define XCHAL_HAVE_VECTRALX 0 /* Vectra LX pkg */ +#define XCHAL_HAVE_HIFIPRO 0 /* HiFiPro Audio Engine pkg */ +#define XCHAL_HAVE_HIFI2 0 /* HiFi2 Audio Engine pkg */ +#define XCHAL_HAVE_CONNXD2 0 /* ConnX D2 pkg */ + + +/*---------------------------------------------------------------------- + MISC + ----------------------------------------------------------------------*/ + +#define XCHAL_NUM_WRITEBUFFER_ENTRIES 1 /* size of write buffer */ +#define XCHAL_INST_FETCH_WIDTH 4 /* instr-fetch width in bytes */ +#define XCHAL_DATA_WIDTH 4 /* data width in bytes */ +/* In T1050, applies to selected core load and store instructions (see ISA): */ +#define XCHAL_UNALIGNED_LOAD_EXCEPTION 1 /* unaligned loads cause exc. */ +#define XCHAL_UNALIGNED_STORE_EXCEPTION 1 /* unaligned stores cause exc.*/ +#define XCHAL_UNALIGNED_LOAD_HW 0 /* unaligned loads work in hw */ +#define XCHAL_UNALIGNED_STORE_HW 0 /* unaligned stores work in hw*/ + +#define XCHAL_SW_VERSION 800001 /* sw version of this header */ + +#define XCHAL_CORE_ID "lx106" /* alphanum core name + (CoreID) set in the Xtensa + Processor Generator */ + +#define XCHAL_BUILD_UNIQUE_ID 0x0002B6F6 /* 22-bit sw build ID */ + +/* + * These definitions describe the hardware targeted by this software. + */ +#define XCHAL_HW_CONFIGID0 0xC28CDAFA /* ConfigID hi 32 bits*/ +#define XCHAL_HW_CONFIGID1 0x1082B6F6 /* ConfigID lo 32 bits*/ +#define XCHAL_HW_VERSION_NAME "LX3.0.1" /* full version name */ +#define XCHAL_HW_VERSION_MAJOR 2300 /* major ver# of targeted hw */ +#define XCHAL_HW_VERSION_MINOR 1 /* minor ver# of targeted hw */ +#define XCHAL_HW_VERSION 230001 /* major*100+minor */ +#define XCHAL_HW_REL_LX3 1 +#define XCHAL_HW_REL_LX3_0 1 +#define XCHAL_HW_REL_LX3_0_1 1 +#define XCHAL_HW_CONFIGID_RELIABLE 1 +/* If software targets a *range* of hardware versions, these are the bounds: */ +#define XCHAL_HW_MIN_VERSION_MAJOR 2300 /* major v of earliest tgt hw */ +#define XCHAL_HW_MIN_VERSION_MINOR 1 /* minor v of earliest tgt hw */ +#define XCHAL_HW_MIN_VERSION 230001 /* earliest targeted hw */ +#define XCHAL_HW_MAX_VERSION_MAJOR 2300 /* major v of latest tgt hw */ +#define XCHAL_HW_MAX_VERSION_MINOR 1 /* minor v of latest tgt hw */ +#define XCHAL_HW_MAX_VERSION 230001 /* latest targeted hw */ + + +/*---------------------------------------------------------------------- + CACHE + ----------------------------------------------------------------------*/ + +#define XCHAL_ICACHE_LINESIZE 4 /* I-cache line size in bytes */ +#define XCHAL_DCACHE_LINESIZE 4 /* D-cache line size in bytes */ +#define XCHAL_ICACHE_LINEWIDTH 2 /* log2(I line size in bytes) */ +#define XCHAL_DCACHE_LINEWIDTH 2 /* log2(D line size in bytes) */ + +#define XCHAL_ICACHE_SIZE 0 /* I-cache size in bytes or 0 */ +#define XCHAL_DCACHE_SIZE 0 /* D-cache size in bytes or 0 */ + +#define XCHAL_DCACHE_IS_WRITEBACK 0 /* writeback feature */ +#define XCHAL_DCACHE_IS_COHERENT 0 /* MP coherence feature */ + +#define XCHAL_HAVE_PREFETCH 0 /* PREFCTL register */ + + + + +/**************************************************************************** + Parameters Useful for PRIVILEGED (Supervisory or Non-Virtualized) Code + ****************************************************************************/ + + +#ifndef XTENSA_HAL_NON_PRIVILEGED_ONLY + +/*---------------------------------------------------------------------- + CACHE + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_PIF 1 /* any outbound PIF present */ + +/* If present, cache size in bytes == (ways * 2^(linewidth + setwidth)). */ + +/* Number of cache sets in log2(lines per way): */ +#define XCHAL_ICACHE_SETWIDTH 0 +#define XCHAL_DCACHE_SETWIDTH 0 + +/* Cache set associativity (number of ways): */ +#define XCHAL_ICACHE_WAYS 1 +#define XCHAL_DCACHE_WAYS 1 + +/* Cache features: */ +#define XCHAL_ICACHE_LINE_LOCKABLE 0 +#define XCHAL_DCACHE_LINE_LOCKABLE 0 +#define XCHAL_ICACHE_ECC_PARITY 0 +#define XCHAL_DCACHE_ECC_PARITY 0 + +/* Cache access size in bytes (affects operation of SICW instruction): */ +#define XCHAL_ICACHE_ACCESS_SIZE 1 +#define XCHAL_DCACHE_ACCESS_SIZE 1 + +/* Number of encoded cache attr bits (see for decoded bits): */ +#define XCHAL_CA_BITS 4 + + +/*---------------------------------------------------------------------- + INTERNAL I/D RAM/ROMs and XLMI + ----------------------------------------------------------------------*/ + +#define XCHAL_NUM_INSTROM 1 /* number of core instr. ROMs */ +#define XCHAL_NUM_INSTRAM 2 /* number of core instr. RAMs */ +#define XCHAL_NUM_DATAROM 1 /* number of core data ROMs */ +#define XCHAL_NUM_DATARAM 2 /* number of core data RAMs */ +#define XCHAL_NUM_URAM 0 /* number of core unified RAMs*/ +#define XCHAL_NUM_XLMI 1 /* number of core XLMI ports */ + +/* Instruction ROM 0: */ +#define XCHAL_INSTROM0_VADDR 0x40200000 +#define XCHAL_INSTROM0_PADDR 0x40200000 +#define XCHAL_INSTROM0_SIZE 1048576 +#define XCHAL_INSTROM0_ECC_PARITY 0 + +/* Instruction RAM 0: */ +#define XCHAL_INSTRAM0_VADDR 0x40000000 +#define XCHAL_INSTRAM0_PADDR 0x40000000 +#define XCHAL_INSTRAM0_SIZE 1048576 +#define XCHAL_INSTRAM0_ECC_PARITY 0 + +/* Instruction RAM 1: */ +#define XCHAL_INSTRAM1_VADDR 0x40100000 +#define XCHAL_INSTRAM1_PADDR 0x40100000 +#define XCHAL_INSTRAM1_SIZE 1048576 +#define XCHAL_INSTRAM1_ECC_PARITY 0 + +/* Data ROM 0: */ +#define XCHAL_DATAROM0_VADDR 0x3FF40000 +#define XCHAL_DATAROM0_PADDR 0x3FF40000 +#define XCHAL_DATAROM0_SIZE 262144 +#define XCHAL_DATAROM0_ECC_PARITY 0 + +/* Data RAM 0: */ +#define XCHAL_DATARAM0_VADDR 0x3FFC0000 +#define XCHAL_DATARAM0_PADDR 0x3FFC0000 +#define XCHAL_DATARAM0_SIZE 262144 +#define XCHAL_DATARAM0_ECC_PARITY 0 + +/* Data RAM 1: */ +#define XCHAL_DATARAM1_VADDR 0x3FF80000 +#define XCHAL_DATARAM1_PADDR 0x3FF80000 +#define XCHAL_DATARAM1_SIZE 262144 +#define XCHAL_DATARAM1_ECC_PARITY 0 + +/* XLMI Port 0: */ +#define XCHAL_XLMI0_VADDR 0x3FF00000 +#define XCHAL_XLMI0_PADDR 0x3FF00000 +#define XCHAL_XLMI0_SIZE 262144 +#define XCHAL_XLMI0_ECC_PARITY 0 + + +/*---------------------------------------------------------------------- + INTERRUPTS and TIMERS + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_INTERRUPTS 1 /* interrupt option */ +#define XCHAL_HAVE_HIGHPRI_INTERRUPTS 1 /* med/high-pri. interrupts */ +#define XCHAL_HAVE_NMI 1 /* non-maskable interrupt */ +#define XCHAL_HAVE_CCOUNT 1 /* CCOUNT reg. (timer option) */ +#define XCHAL_NUM_TIMERS 1 /* number of CCOMPAREn regs */ +#define XCHAL_NUM_INTERRUPTS 15 /* number of interrupts */ +#define XCHAL_NUM_INTERRUPTS_LOG2 4 /* ceil(log2(NUM_INTERRUPTS)) */ +#define XCHAL_NUM_EXTINTERRUPTS 13 /* num of external interrupts */ +#define XCHAL_NUM_INTLEVELS 2 /* number of interrupt levels + (not including level zero) */ +#define XCHAL_EXCM_LEVEL 1 /* level masked by PS.EXCM */ + /* (always 1 in XEA1; levels 2 .. EXCM_LEVEL are "medium priority") */ + +/* Masks of interrupts at each interrupt level: */ +#define XCHAL_INTLEVEL1_MASK 0x00003FFF +#define XCHAL_INTLEVEL2_MASK 0x00000000 +#define XCHAL_INTLEVEL3_MASK 0x00004000 +#define XCHAL_INTLEVEL4_MASK 0x00000000 +#define XCHAL_INTLEVEL5_MASK 0x00000000 +#define XCHAL_INTLEVEL6_MASK 0x00000000 +#define XCHAL_INTLEVEL7_MASK 0x00000000 + +/* Masks of interrupts at each range 1..n of interrupt levels: */ +#define XCHAL_INTLEVEL1_ANDBELOW_MASK 0x00003FFF +#define XCHAL_INTLEVEL2_ANDBELOW_MASK 0x00003FFF +#define XCHAL_INTLEVEL3_ANDBELOW_MASK 0x00007FFF +#define XCHAL_INTLEVEL4_ANDBELOW_MASK 0x00007FFF +#define XCHAL_INTLEVEL5_ANDBELOW_MASK 0x00007FFF +#define XCHAL_INTLEVEL6_ANDBELOW_MASK 0x00007FFF +#define XCHAL_INTLEVEL7_ANDBELOW_MASK 0x00007FFF + +/* Level of each interrupt: */ +#define XCHAL_INT0_LEVEL 1 +#define XCHAL_INT1_LEVEL 1 +#define XCHAL_INT2_LEVEL 1 +#define XCHAL_INT3_LEVEL 1 +#define XCHAL_INT4_LEVEL 1 +#define XCHAL_INT5_LEVEL 1 +#define XCHAL_INT6_LEVEL 1 +#define XCHAL_INT7_LEVEL 1 +#define XCHAL_INT8_LEVEL 1 +#define XCHAL_INT9_LEVEL 1 +#define XCHAL_INT10_LEVEL 1 +#define XCHAL_INT11_LEVEL 1 +#define XCHAL_INT12_LEVEL 1 +#define XCHAL_INT13_LEVEL 1 +#define XCHAL_INT14_LEVEL 3 +#define XCHAL_DEBUGLEVEL 2 /* debug interrupt level */ +#define XCHAL_HAVE_DEBUG_EXTERN_INT 1 /* OCD external db interrupt */ +#define XCHAL_NMILEVEL 3 /* NMI "level" (for use with + EXCSAVE/EPS/EPC_n, RFI n) */ + +/* Type of each interrupt: */ +#define XCHAL_INT0_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT1_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT2_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT3_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT4_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT5_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT6_TYPE XTHAL_INTTYPE_TIMER +#define XCHAL_INT7_TYPE XTHAL_INTTYPE_SOFTWARE +#define XCHAL_INT8_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT9_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT10_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT11_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT12_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT13_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT14_TYPE XTHAL_INTTYPE_NMI + +/* Masks of interrupts for each type of interrupt: */ +#define XCHAL_INTTYPE_MASK_UNCONFIGURED 0xFFFF8000 +#define XCHAL_INTTYPE_MASK_SOFTWARE 0x00000080 +#define XCHAL_INTTYPE_MASK_EXTERN_EDGE 0x00003F00 +#define XCHAL_INTTYPE_MASK_EXTERN_LEVEL 0x0000003F +#define XCHAL_INTTYPE_MASK_TIMER 0x00000040 +#define XCHAL_INTTYPE_MASK_NMI 0x00004000 +#define XCHAL_INTTYPE_MASK_WRITE_ERROR 0x00000000 + +/* Interrupt numbers assigned to specific interrupt sources: */ +#define XCHAL_TIMER0_INTERRUPT 6 /* CCOMPARE0 */ +#define XCHAL_TIMER1_INTERRUPT XTHAL_TIMER_UNCONFIGURED +#define XCHAL_TIMER2_INTERRUPT XTHAL_TIMER_UNCONFIGURED +#define XCHAL_TIMER3_INTERRUPT XTHAL_TIMER_UNCONFIGURED +#define XCHAL_NMI_INTERRUPT 14 /* non-maskable interrupt */ + +/* Interrupt numbers for levels at which only one interrupt is configured: */ +#define XCHAL_INTLEVEL3_NUM 14 +/* (There are many interrupts each at level(s) 1.) */ + + +/* + * External interrupt vectors/levels. + * These macros describe how Xtensa processor interrupt numbers + * (as numbered internally, eg. in INTERRUPT and INTENABLE registers) + * map to external BInterrupt pins, for those interrupts + * configured as external (level-triggered, edge-triggered, or NMI). + * See the Xtensa processor databook for more details. + */ + +/* Core interrupt numbers mapped to each EXTERNAL interrupt number: */ +#define XCHAL_EXTINT0_NUM 0 /* (intlevel 1) */ +#define XCHAL_EXTINT1_NUM 1 /* (intlevel 1) */ +#define XCHAL_EXTINT2_NUM 2 /* (intlevel 1) */ +#define XCHAL_EXTINT3_NUM 3 /* (intlevel 1) */ +#define XCHAL_EXTINT4_NUM 4 /* (intlevel 1) */ +#define XCHAL_EXTINT5_NUM 5 /* (intlevel 1) */ +#define XCHAL_EXTINT6_NUM 8 /* (intlevel 1) */ +#define XCHAL_EXTINT7_NUM 9 /* (intlevel 1) */ +#define XCHAL_EXTINT8_NUM 10 /* (intlevel 1) */ +#define XCHAL_EXTINT9_NUM 11 /* (intlevel 1) */ +#define XCHAL_EXTINT10_NUM 12 /* (intlevel 1) */ +#define XCHAL_EXTINT11_NUM 13 /* (intlevel 1) */ +#define XCHAL_EXTINT12_NUM 14 /* (intlevel 3) */ + + +/*---------------------------------------------------------------------- + EXCEPTIONS and VECTORS + ----------------------------------------------------------------------*/ + +#define XCHAL_XEA_VERSION 2 /* Xtensa Exception Architecture + number: 1 == XEA1 (old) + 2 == XEA2 (new) + 0 == XEAX (extern) */ +#define XCHAL_HAVE_XEA1 0 /* Exception Architecture 1 */ +#define XCHAL_HAVE_XEA2 1 /* Exception Architecture 2 */ +#define XCHAL_HAVE_XEAX 0 /* External Exception Arch. */ +#define XCHAL_HAVE_EXCEPTIONS 1 /* exception option */ +#define XCHAL_HAVE_MEM_ECC_PARITY 0 /* local memory ECC/parity */ +#define XCHAL_HAVE_VECTOR_SELECT 1 /* relocatable vectors */ +#define XCHAL_HAVE_VECBASE 1 /* relocatable vectors */ +#define XCHAL_VECBASE_RESET_VADDR 0x40000000 /* VECBASE reset value */ +#define XCHAL_VECBASE_RESET_PADDR 0x40000000 +#define XCHAL_RESET_VECBASE_OVERLAP 0 + +#define XCHAL_RESET_VECTOR0_VADDR 0x50000000 +#define XCHAL_RESET_VECTOR0_PADDR 0x50000000 +#define XCHAL_RESET_VECTOR1_VADDR 0x40000080 +#define XCHAL_RESET_VECTOR1_PADDR 0x40000080 +#define XCHAL_RESET_VECTOR_VADDR 0x50000000 +#define XCHAL_RESET_VECTOR_PADDR 0x50000000 +#define XCHAL_USER_VECOFS 0x00000050 +#define XCHAL_USER_VECTOR_VADDR 0x40000050 +#define XCHAL_USER_VECTOR_PADDR 0x40000050 +#define XCHAL_KERNEL_VECOFS 0x00000030 +#define XCHAL_KERNEL_VECTOR_VADDR 0x40000030 +#define XCHAL_KERNEL_VECTOR_PADDR 0x40000030 +#define XCHAL_DOUBLEEXC_VECOFS 0x00000070 +#define XCHAL_DOUBLEEXC_VECTOR_VADDR 0x40000070 +#define XCHAL_DOUBLEEXC_VECTOR_PADDR 0x40000070 +#define XCHAL_INTLEVEL2_VECOFS 0x00000010 +#define XCHAL_INTLEVEL2_VECTOR_VADDR 0x40000010 +#define XCHAL_INTLEVEL2_VECTOR_PADDR 0x40000010 +#define XCHAL_DEBUG_VECOFS XCHAL_INTLEVEL2_VECOFS +#define XCHAL_DEBUG_VECTOR_VADDR XCHAL_INTLEVEL2_VECTOR_VADDR +#define XCHAL_DEBUG_VECTOR_PADDR XCHAL_INTLEVEL2_VECTOR_PADDR +#define XCHAL_NMI_VECOFS 0x00000020 +#define XCHAL_NMI_VECTOR_VADDR 0x40000020 +#define XCHAL_NMI_VECTOR_PADDR 0x40000020 +#define XCHAL_INTLEVEL3_VECOFS XCHAL_NMI_VECOFS +#define XCHAL_INTLEVEL3_VECTOR_VADDR XCHAL_NMI_VECTOR_VADDR +#define XCHAL_INTLEVEL3_VECTOR_PADDR XCHAL_NMI_VECTOR_PADDR + + +/*---------------------------------------------------------------------- + DEBUG + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_OCD 1 /* OnChipDebug option */ +#define XCHAL_NUM_IBREAK 1 /* number of IBREAKn regs */ +#define XCHAL_NUM_DBREAK 1 /* number of DBREAKn regs */ +#define XCHAL_HAVE_OCD_DIR_ARRAY 0 /* faster OCD option */ + + +/*---------------------------------------------------------------------- + MMU + ----------------------------------------------------------------------*/ + +/* See core-matmap.h header file for more details. */ + +#define XCHAL_HAVE_TLBS 1 /* inverse of HAVE_CACHEATTR */ +#define XCHAL_HAVE_SPANNING_WAY 1 /* one way maps I+D 4GB vaddr */ +#define XCHAL_SPANNING_WAY 0 /* TLB spanning way number */ +#define XCHAL_HAVE_IDENTITY_MAP 1 /* vaddr == paddr always */ +#define XCHAL_HAVE_CACHEATTR 0 /* CACHEATTR register present */ +#define XCHAL_HAVE_MIMIC_CACHEATTR 1 /* region protection */ +#define XCHAL_HAVE_XLT_CACHEATTR 0 /* region prot. w/translation */ +#define XCHAL_HAVE_PTP_MMU 0 /* full MMU (with page table + [autorefill] and protection) + usable for an MMU-based OS */ +/* If none of the above last 4 are set, it's a custom TLB configuration. */ + +#define XCHAL_MMU_ASID_BITS 0 /* number of bits in ASIDs */ +#define XCHAL_MMU_RINGS 1 /* number of rings (1..4) */ +#define XCHAL_MMU_RING_BITS 0 /* num of bits in RING field */ + +#endif /* !XTENSA_HAL_NON_PRIVILEGED_ONLY */ + + +#endif /* _XTENSA_CORE_CONFIGURATION_H */ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/core-matmap.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/core-matmap.h new file mode 100644 index 0000000..8e31a27 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/core-matmap.h @@ -0,0 +1,316 @@ +/* + * xtensa/config/core-matmap.h -- Memory access and translation mapping + * parameters (CHAL) of the Xtensa processor core configuration. + * + * If you are using Xtensa Tools, see (which includes + * this file) for more details. + * + * In the Xtensa processor products released to date, all parameters + * defined in this file are derivable (at least in theory) from + * information contained in the core-isa.h header file. + * In particular, the following core configuration parameters are relevant: + * XCHAL_HAVE_CACHEATTR + * XCHAL_HAVE_MIMIC_CACHEATTR + * XCHAL_HAVE_XLT_CACHEATTR + * XCHAL_HAVE_PTP_MMU + * XCHAL_ITLB_ARF_ENTRIES_LOG2 + * XCHAL_DTLB_ARF_ENTRIES_LOG2 + * XCHAL_DCACHE_IS_WRITEBACK + * XCHAL_ICACHE_SIZE (presence of I-cache) + * XCHAL_DCACHE_SIZE (presence of D-cache) + * XCHAL_HW_VERSION_MAJOR + * XCHAL_HW_VERSION_MINOR + */ + +/* Customer ID=7011; Build=0x2b6f6; Copyright (c) 1999-2010 Tensilica Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + + +#ifndef XTENSA_CONFIG_CORE_MATMAP_H +#define XTENSA_CONFIG_CORE_MATMAP_H + + +/*---------------------------------------------------------------------- + CACHE (MEMORY ACCESS) ATTRIBUTES + ----------------------------------------------------------------------*/ + + +/* Cache Attribute encodings -- lists of access modes for each cache attribute: */ +#define XCHAL_FCA_LIST XTHAL_FAM_EXCEPTION XCHAL_SEP \ + XTHAL_FAM_BYPASS XCHAL_SEP \ + XTHAL_FAM_BYPASS XCHAL_SEP \ + XTHAL_FAM_BYPASS XCHAL_SEP \ + XTHAL_FAM_BYPASS XCHAL_SEP \ + XTHAL_FAM_BYPASS XCHAL_SEP \ + XTHAL_FAM_EXCEPTION XCHAL_SEP \ + XTHAL_FAM_EXCEPTION XCHAL_SEP \ + XTHAL_FAM_EXCEPTION XCHAL_SEP \ + XTHAL_FAM_EXCEPTION XCHAL_SEP \ + XTHAL_FAM_EXCEPTION XCHAL_SEP \ + XTHAL_FAM_EXCEPTION XCHAL_SEP \ + XTHAL_FAM_EXCEPTION XCHAL_SEP \ + XTHAL_FAM_EXCEPTION XCHAL_SEP \ + XTHAL_FAM_EXCEPTION XCHAL_SEP \ + XTHAL_FAM_EXCEPTION +#define XCHAL_LCA_LIST XTHAL_LAM_BYPASSG XCHAL_SEP \ + XTHAL_LAM_BYPASSG XCHAL_SEP \ + XTHAL_LAM_BYPASSG XCHAL_SEP \ + XTHAL_LAM_EXCEPTION XCHAL_SEP \ + XTHAL_LAM_BYPASSG XCHAL_SEP \ + XTHAL_LAM_BYPASSG XCHAL_SEP \ + XTHAL_LAM_EXCEPTION XCHAL_SEP \ + XTHAL_LAM_EXCEPTION XCHAL_SEP \ + XTHAL_LAM_EXCEPTION XCHAL_SEP \ + XTHAL_LAM_EXCEPTION XCHAL_SEP \ + XTHAL_LAM_EXCEPTION XCHAL_SEP \ + XTHAL_LAM_EXCEPTION XCHAL_SEP \ + XTHAL_LAM_EXCEPTION XCHAL_SEP \ + XTHAL_LAM_EXCEPTION XCHAL_SEP \ + XTHAL_LAM_BYPASSG XCHAL_SEP \ + XTHAL_LAM_EXCEPTION +#define XCHAL_SCA_LIST XTHAL_SAM_BYPASS XCHAL_SEP \ + XTHAL_SAM_BYPASS XCHAL_SEP \ + XTHAL_SAM_BYPASS XCHAL_SEP \ + XTHAL_SAM_EXCEPTION XCHAL_SEP \ + XTHAL_SAM_BYPASS XCHAL_SEP \ + XTHAL_SAM_BYPASS XCHAL_SEP \ + XTHAL_SAM_EXCEPTION XCHAL_SEP \ + XTHAL_SAM_EXCEPTION XCHAL_SEP \ + XTHAL_SAM_EXCEPTION XCHAL_SEP \ + XTHAL_SAM_EXCEPTION XCHAL_SEP \ + XTHAL_SAM_EXCEPTION XCHAL_SEP \ + XTHAL_SAM_EXCEPTION XCHAL_SEP \ + XTHAL_SAM_EXCEPTION XCHAL_SEP \ + XTHAL_SAM_EXCEPTION XCHAL_SEP \ + XTHAL_SAM_BYPASS XCHAL_SEP \ + XTHAL_SAM_EXCEPTION + + +/* + * Specific encoded cache attribute values of general interest. + * If a specific cache mode is not available, the closest available + * one is returned instead (eg. writethru instead of writeback, + * bypass instead of writethru). + */ +#define XCHAL_CA_BYPASS 2 /* cache disabled (bypassed) mode */ +#define XCHAL_CA_WRITETHRU 2 /* cache enabled (write-through) mode */ +#define XCHAL_CA_WRITEBACK 2 /* cache enabled (write-back) mode */ +#define XCHAL_CA_WRITEBACK_NOALLOC 2 /* cache enabled (write-back no-allocate) mode */ +#define XCHAL_CA_BYPASS_RW 0 /* cache disabled (bypassed) mode (no exec) */ +#define XCHAL_CA_WRITETHRU_RW 0 /* cache enabled (write-through) mode (no exec) */ +#define XCHAL_CA_WRITEBACK_RW 0 /* cache enabled (write-back) mode (no exec) */ +#define XCHAL_CA_WRITEBACK_NOALLOC_RW 0 /* cache enabled (write-back no-allocate) mode (no exec) */ +#define XCHAL_CA_ILLEGAL 15 /* no access allowed (all cause exceptions) mode */ +#define XCHAL_CA_ISOLATE 0 /* cache isolate (accesses go to cache not memory) mode */ + + +/*---------------------------------------------------------------------- + MMU + ----------------------------------------------------------------------*/ + +/* + * General notes on MMU parameters. + * + * Terminology: + * ASID = address-space ID (acts as an "extension" of virtual addresses) + * VPN = virtual page number + * PPN = physical page number + * CA = encoded cache attribute (access modes) + * TLB = translation look-aside buffer (term is stretched somewhat here) + * I = instruction (fetch accesses) + * D = data (load and store accesses) + * way = each TLB (ITLB and DTLB) consists of a number of "ways" + * that simultaneously match the virtual address of an access; + * a TLB successfully translates a virtual address if exactly + * one way matches the vaddr; if none match, it is a miss; + * if multiple match, one gets a "multihit" exception; + * each way can be independently configured in terms of number of + * entries, page sizes, which fields are writable or constant, etc. + * set = group of contiguous ways with exactly identical parameters + * ARF = auto-refill; hardware services a 1st-level miss by loading a PTE + * from the page table and storing it in one of the auto-refill ways; + * if this PTE load also misses, a miss exception is posted for s/w. + * min-wired = a "min-wired" way can be used to map a single (minimum-sized) + * page arbitrarily under program control; it has a single entry, + * is non-auto-refill (some other way(s) must be auto-refill), + * all its fields (VPN, PPN, ASID, CA) are all writable, and it + * supports the XCHAL_MMU_MIN_PTE_PAGE_SIZE page size (a current + * restriction is that this be the only page size it supports). + * + * TLB way entries are virtually indexed. + * TLB ways that support multiple page sizes: + * - must have all writable VPN and PPN fields; + * - can only use one page size at any given time (eg. setup at startup), + * selected by the respective ITLBCFG or DTLBCFG special register, + * whose bits n*4+3 .. n*4 index the list of page sizes for way n + * (XCHAL_xTLB_SETm_PAGESZ_LOG2_LIST for set m corresponding to way n); + * this list may be sparse for auto-refill ways because auto-refill + * ways have independent lists of supported page sizes sharing a + * common encoding with PTE entries; the encoding is the index into + * this list; unsupported sizes for a given way are zero in the list; + * selecting unsupported sizes results in undefined hardware behaviour; + * - is only possible for ways 0 thru 7 (due to ITLBCFG/DTLBCFG definition). + */ + +#define XCHAL_MMU_ASID_INVALID 0 /* ASID value indicating invalid address space */ +#define XCHAL_MMU_ASID_KERNEL 0 /* ASID value indicating kernel (ring 0) address space */ +#define XCHAL_MMU_SR_BITS 0 /* number of size-restriction bits supported */ +#define XCHAL_MMU_CA_BITS 4 /* number of bits needed to hold cache attribute encoding */ +#define XCHAL_MMU_MAX_PTE_PAGE_SIZE 29 /* max page size in a PTE structure (log2) */ +#define XCHAL_MMU_MIN_PTE_PAGE_SIZE 29 /* min page size in a PTE structure (log2) */ + + +/*** Instruction TLB: ***/ + +#define XCHAL_ITLB_WAY_BITS 0 /* number of bits holding the ways */ +#define XCHAL_ITLB_WAYS 1 /* number of ways (n-way set-associative TLB) */ +#define XCHAL_ITLB_ARF_WAYS 0 /* number of auto-refill ways */ +#define XCHAL_ITLB_SETS 1 /* number of sets (groups of ways with identical settings) */ + +/* Way set to which each way belongs: */ +#define XCHAL_ITLB_WAY0_SET 0 + +/* Ways sets that are used by hardware auto-refill (ARF): */ +#define XCHAL_ITLB_ARF_SETS 0 /* number of auto-refill sets */ + +/* Way sets that are "min-wired" (see terminology comment above): */ +#define XCHAL_ITLB_MINWIRED_SETS 0 /* number of "min-wired" sets */ + + +/* ITLB way set 0 (group of ways 0 thru 0): */ +#define XCHAL_ITLB_SET0_WAY 0 /* index of first way in this way set */ +#define XCHAL_ITLB_SET0_WAYS 1 /* number of (contiguous) ways in this way set */ +#define XCHAL_ITLB_SET0_ENTRIES_LOG2 3 /* log2(number of entries in this way) */ +#define XCHAL_ITLB_SET0_ENTRIES 8 /* number of entries in this way (always a power of 2) */ +#define XCHAL_ITLB_SET0_ARF 0 /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */ +#define XCHAL_ITLB_SET0_PAGESIZES 1 /* number of supported page sizes in this way */ +#define XCHAL_ITLB_SET0_PAGESZ_BITS 0 /* number of bits to encode the page size */ +#define XCHAL_ITLB_SET0_PAGESZ_LOG2_MIN 29 /* log2(minimum supported page size) */ +#define XCHAL_ITLB_SET0_PAGESZ_LOG2_MAX 29 /* log2(maximum supported page size) */ +#define XCHAL_ITLB_SET0_PAGESZ_LOG2_LIST 29 /* list of log2(page size)s, separated by XCHAL_SEP; + 2^PAGESZ_BITS entries in list, unsupported entries are zero */ +#define XCHAL_ITLB_SET0_ASID_CONSTMASK 0 /* constant ASID bits; 0 if all writable */ +#define XCHAL_ITLB_SET0_VPN_CONSTMASK 0x00000000 /* constant VPN bits, not including entry index bits; 0 if all writable */ +#define XCHAL_ITLB_SET0_PPN_CONSTMASK 0xE0000000 /* constant PPN bits, including entry index bits; 0 if all writable */ +#define XCHAL_ITLB_SET0_CA_CONSTMASK 0 /* constant CA bits; 0 if all writable */ +#define XCHAL_ITLB_SET0_ASID_RESET 0 /* 1 if ASID reset values defined (and all writable); 0 otherwise */ +#define XCHAL_ITLB_SET0_VPN_RESET 0 /* 1 if VPN reset values defined (and all writable); 0 otherwise */ +#define XCHAL_ITLB_SET0_PPN_RESET 0 /* 1 if PPN reset values defined (and all writable); 0 otherwise */ +#define XCHAL_ITLB_SET0_CA_RESET 1 /* 1 if CA reset values defined (and all writable); 0 otherwise */ +/* Constant VPN values for each entry of ITLB way set 0 (because VPN_CONSTMASK is non-zero): */ +#define XCHAL_ITLB_SET0_E0_VPN_CONST 0x00000000 +#define XCHAL_ITLB_SET0_E1_VPN_CONST 0x20000000 +#define XCHAL_ITLB_SET0_E2_VPN_CONST 0x40000000 +#define XCHAL_ITLB_SET0_E3_VPN_CONST 0x60000000 +#define XCHAL_ITLB_SET0_E4_VPN_CONST 0x80000000 +#define XCHAL_ITLB_SET0_E5_VPN_CONST 0xA0000000 +#define XCHAL_ITLB_SET0_E6_VPN_CONST 0xC0000000 +#define XCHAL_ITLB_SET0_E7_VPN_CONST 0xE0000000 +/* Constant PPN values for each entry of ITLB way set 0 (because PPN_CONSTMASK is non-zero): */ +#define XCHAL_ITLB_SET0_E0_PPN_CONST 0x00000000 +#define XCHAL_ITLB_SET0_E1_PPN_CONST 0x20000000 +#define XCHAL_ITLB_SET0_E2_PPN_CONST 0x40000000 +#define XCHAL_ITLB_SET0_E3_PPN_CONST 0x60000000 +#define XCHAL_ITLB_SET0_E4_PPN_CONST 0x80000000 +#define XCHAL_ITLB_SET0_E5_PPN_CONST 0xA0000000 +#define XCHAL_ITLB_SET0_E6_PPN_CONST 0xC0000000 +#define XCHAL_ITLB_SET0_E7_PPN_CONST 0xE0000000 +/* Reset CA values for each entry of ITLB way set 0 (because SET0_CA_RESET is non-zero): */ +#define XCHAL_ITLB_SET0_E0_CA_RESET 0x02 +#define XCHAL_ITLB_SET0_E1_CA_RESET 0x02 +#define XCHAL_ITLB_SET0_E2_CA_RESET 0x02 +#define XCHAL_ITLB_SET0_E3_CA_RESET 0x02 +#define XCHAL_ITLB_SET0_E4_CA_RESET 0x02 +#define XCHAL_ITLB_SET0_E5_CA_RESET 0x02 +#define XCHAL_ITLB_SET0_E6_CA_RESET 0x02 +#define XCHAL_ITLB_SET0_E7_CA_RESET 0x02 + + +/*** Data TLB: ***/ + +#define XCHAL_DTLB_WAY_BITS 0 /* number of bits holding the ways */ +#define XCHAL_DTLB_WAYS 1 /* number of ways (n-way set-associative TLB) */ +#define XCHAL_DTLB_ARF_WAYS 0 /* number of auto-refill ways */ +#define XCHAL_DTLB_SETS 1 /* number of sets (groups of ways with identical settings) */ + +/* Way set to which each way belongs: */ +#define XCHAL_DTLB_WAY0_SET 0 + +/* Ways sets that are used by hardware auto-refill (ARF): */ +#define XCHAL_DTLB_ARF_SETS 0 /* number of auto-refill sets */ + +/* Way sets that are "min-wired" (see terminology comment above): */ +#define XCHAL_DTLB_MINWIRED_SETS 0 /* number of "min-wired" sets */ + + +/* DTLB way set 0 (group of ways 0 thru 0): */ +#define XCHAL_DTLB_SET0_WAY 0 /* index of first way in this way set */ +#define XCHAL_DTLB_SET0_WAYS 1 /* number of (contiguous) ways in this way set */ +#define XCHAL_DTLB_SET0_ENTRIES_LOG2 3 /* log2(number of entries in this way) */ +#define XCHAL_DTLB_SET0_ENTRIES 8 /* number of entries in this way (always a power of 2) */ +#define XCHAL_DTLB_SET0_ARF 0 /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */ +#define XCHAL_DTLB_SET0_PAGESIZES 1 /* number of supported page sizes in this way */ +#define XCHAL_DTLB_SET0_PAGESZ_BITS 0 /* number of bits to encode the page size */ +#define XCHAL_DTLB_SET0_PAGESZ_LOG2_MIN 29 /* log2(minimum supported page size) */ +#define XCHAL_DTLB_SET0_PAGESZ_LOG2_MAX 29 /* log2(maximum supported page size) */ +#define XCHAL_DTLB_SET0_PAGESZ_LOG2_LIST 29 /* list of log2(page size)s, separated by XCHAL_SEP; + 2^PAGESZ_BITS entries in list, unsupported entries are zero */ +#define XCHAL_DTLB_SET0_ASID_CONSTMASK 0 /* constant ASID bits; 0 if all writable */ +#define XCHAL_DTLB_SET0_VPN_CONSTMASK 0x00000000 /* constant VPN bits, not including entry index bits; 0 if all writable */ +#define XCHAL_DTLB_SET0_PPN_CONSTMASK 0xE0000000 /* constant PPN bits, including entry index bits; 0 if all writable */ +#define XCHAL_DTLB_SET0_CA_CONSTMASK 0 /* constant CA bits; 0 if all writable */ +#define XCHAL_DTLB_SET0_ASID_RESET 0 /* 1 if ASID reset values defined (and all writable); 0 otherwise */ +#define XCHAL_DTLB_SET0_VPN_RESET 0 /* 1 if VPN reset values defined (and all writable); 0 otherwise */ +#define XCHAL_DTLB_SET0_PPN_RESET 0 /* 1 if PPN reset values defined (and all writable); 0 otherwise */ +#define XCHAL_DTLB_SET0_CA_RESET 1 /* 1 if CA reset values defined (and all writable); 0 otherwise */ +/* Constant VPN values for each entry of DTLB way set 0 (because VPN_CONSTMASK is non-zero): */ +#define XCHAL_DTLB_SET0_E0_VPN_CONST 0x00000000 +#define XCHAL_DTLB_SET0_E1_VPN_CONST 0x20000000 +#define XCHAL_DTLB_SET0_E2_VPN_CONST 0x40000000 +#define XCHAL_DTLB_SET0_E3_VPN_CONST 0x60000000 +#define XCHAL_DTLB_SET0_E4_VPN_CONST 0x80000000 +#define XCHAL_DTLB_SET0_E5_VPN_CONST 0xA0000000 +#define XCHAL_DTLB_SET0_E6_VPN_CONST 0xC0000000 +#define XCHAL_DTLB_SET0_E7_VPN_CONST 0xE0000000 +/* Constant PPN values for each entry of DTLB way set 0 (because PPN_CONSTMASK is non-zero): */ +#define XCHAL_DTLB_SET0_E0_PPN_CONST 0x00000000 +#define XCHAL_DTLB_SET0_E1_PPN_CONST 0x20000000 +#define XCHAL_DTLB_SET0_E2_PPN_CONST 0x40000000 +#define XCHAL_DTLB_SET0_E3_PPN_CONST 0x60000000 +#define XCHAL_DTLB_SET0_E4_PPN_CONST 0x80000000 +#define XCHAL_DTLB_SET0_E5_PPN_CONST 0xA0000000 +#define XCHAL_DTLB_SET0_E6_PPN_CONST 0xC0000000 +#define XCHAL_DTLB_SET0_E7_PPN_CONST 0xE0000000 +/* Reset CA values for each entry of DTLB way set 0 (because SET0_CA_RESET is non-zero): */ +#define XCHAL_DTLB_SET0_E0_CA_RESET 0x02 +#define XCHAL_DTLB_SET0_E1_CA_RESET 0x02 +#define XCHAL_DTLB_SET0_E2_CA_RESET 0x02 +#define XCHAL_DTLB_SET0_E3_CA_RESET 0x02 +#define XCHAL_DTLB_SET0_E4_CA_RESET 0x02 +#define XCHAL_DTLB_SET0_E5_CA_RESET 0x02 +#define XCHAL_DTLB_SET0_E6_CA_RESET 0x02 +#define XCHAL_DTLB_SET0_E7_CA_RESET 0x02 + + + + +#endif /*XTENSA_CONFIG_CORE_MATMAP_H*/ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/core.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/core.h new file mode 100644 index 0000000..f4593fb --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/core.h @@ -0,0 +1,1328 @@ +/* + * xtensa/config/core.h -- HAL definitions dependent on CORE configuration + * + * This header file is sometimes referred to as the "compile-time HAL" or CHAL. + * It pulls definitions tailored for a specific Xtensa processor configuration. + * + * Sources for binaries meant to be configuration-independent generally avoid + * including this file (they may use the configuration-specific HAL library). + * It is normal for the HAL library source itself to include this file. + */ + +/* + * Copyright (c) 2005-2010 Tensilica Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#ifndef XTENSA_CONFIG_CORE_H +#define XTENSA_CONFIG_CORE_H + +/* CONFIGURATION INDEPENDENT DEFINITIONS: */ +#ifdef __XTENSA__ +#include +#else +#include "../hal.h" +#endif + +/* CONFIGURATION SPECIFIC DEFINITIONS: */ +#ifdef __XTENSA__ +#include +#include +#include +#else +#include "core-isa.h" +#include "core-matmap.h" +#include "tie.h" +#endif + +#if defined (_ASMLANGUAGE) || defined (__ASSEMBLER__) +#ifdef __XTENSA__ +#include +#else +#include "tie-asm.h" +#endif +#endif /*_ASMLANGUAGE or __ASSEMBLER__*/ + + +/*---------------------------------------------------------------------- + GENERAL + ----------------------------------------------------------------------*/ + +/* + * Separators for macros that expand into arrays. + * These can be predefined by files that #include this one, + * when different separators are required. + */ +/* Element separator for macros that expand into 1-dimensional arrays: */ +#ifndef XCHAL_SEP +#define XCHAL_SEP , +#endif +/* Array separator for macros that expand into 2-dimensional arrays: */ +#ifndef XCHAL_SEP2 +#define XCHAL_SEP2 },{ +#endif + + + +/*---------------------------------------------------------------------- + ISA + ----------------------------------------------------------------------*/ + +#if XCHAL_HAVE_BE +# define XCHAL_HAVE_LE 0 +# define XCHAL_MEMORY_ORDER XTHAL_BIGENDIAN +#else +# define XCHAL_HAVE_LE 1 +# define XCHAL_MEMORY_ORDER XTHAL_LITTLEENDIAN +#endif + + + +/*---------------------------------------------------------------------- + INTERRUPTS + ----------------------------------------------------------------------*/ + +/* Indexing macros: */ +#define _XCHAL_INTLEVEL_MASK(n) XCHAL_INTLEVEL ## n ## _MASK +#define XCHAL_INTLEVEL_MASK(n) _XCHAL_INTLEVEL_MASK(n) /* n = 0 .. 15 */ +#define _XCHAL_INTLEVEL_ANDBELOWMASK(n) XCHAL_INTLEVEL ## n ## _ANDBELOW_MASK +#define XCHAL_INTLEVEL_ANDBELOW_MASK(n) _XCHAL_INTLEVEL_ANDBELOWMASK(n) /* n = 0 .. 15 */ +#define _XCHAL_INTLEVEL_NUM(n) XCHAL_INTLEVEL ## n ## _NUM +#define XCHAL_INTLEVEL_NUM(n) _XCHAL_INTLEVEL_NUM(n) /* n = 0 .. 15 */ +#define _XCHAL_INT_LEVEL(n) XCHAL_INT ## n ## _LEVEL +#define XCHAL_INT_LEVEL(n) _XCHAL_INT_LEVEL(n) /* n = 0 .. 31 */ +#define _XCHAL_INT_TYPE(n) XCHAL_INT ## n ## _TYPE +#define XCHAL_INT_TYPE(n) _XCHAL_INT_TYPE(n) /* n = 0 .. 31 */ +#define _XCHAL_TIMER_INTERRUPT(n) XCHAL_TIMER ## n ## _INTERRUPT +#define XCHAL_TIMER_INTERRUPT(n) _XCHAL_TIMER_INTERRUPT(n) /* n = 0 .. 3 */ + + +#define XCHAL_HAVE_HIGHLEVEL_INTERRUPTS XCHAL_HAVE_HIGHPRI_INTERRUPTS +#define XCHAL_NUM_LOWPRI_LEVELS 1 /* number of low-priority interrupt levels (always 1) */ +#define XCHAL_FIRST_HIGHPRI_LEVEL (XCHAL_NUM_LOWPRI_LEVELS+1) /* level of first high-priority interrupt (always 2) */ +/* Note: 1 <= LOWPRI_LEVELS <= EXCM_LEVEL < DEBUGLEVEL <= NUM_INTLEVELS < NMILEVEL <= 15 */ + +/* These values are constant for existing Xtensa processor implementations: */ +#define XCHAL_INTLEVEL0_MASK 0x00000000 +#define XCHAL_INTLEVEL8_MASK 0x00000000 +#define XCHAL_INTLEVEL9_MASK 0x00000000 +#define XCHAL_INTLEVEL10_MASK 0x00000000 +#define XCHAL_INTLEVEL11_MASK 0x00000000 +#define XCHAL_INTLEVEL12_MASK 0x00000000 +#define XCHAL_INTLEVEL13_MASK 0x00000000 +#define XCHAL_INTLEVEL14_MASK 0x00000000 +#define XCHAL_INTLEVEL15_MASK 0x00000000 + +/* Array of masks of interrupts at each interrupt level: */ +#define XCHAL_INTLEVEL_MASKS XCHAL_INTLEVEL0_MASK \ + XCHAL_SEP XCHAL_INTLEVEL1_MASK \ + XCHAL_SEP XCHAL_INTLEVEL2_MASK \ + XCHAL_SEP XCHAL_INTLEVEL3_MASK \ + XCHAL_SEP XCHAL_INTLEVEL4_MASK \ + XCHAL_SEP XCHAL_INTLEVEL5_MASK \ + XCHAL_SEP XCHAL_INTLEVEL6_MASK \ + XCHAL_SEP XCHAL_INTLEVEL7_MASK \ + XCHAL_SEP XCHAL_INTLEVEL8_MASK \ + XCHAL_SEP XCHAL_INTLEVEL9_MASK \ + XCHAL_SEP XCHAL_INTLEVEL10_MASK \ + XCHAL_SEP XCHAL_INTLEVEL11_MASK \ + XCHAL_SEP XCHAL_INTLEVEL12_MASK \ + XCHAL_SEP XCHAL_INTLEVEL13_MASK \ + XCHAL_SEP XCHAL_INTLEVEL14_MASK \ + XCHAL_SEP XCHAL_INTLEVEL15_MASK + +/* These values are constant for existing Xtensa processor implementations: */ +#define XCHAL_INTLEVEL0_ANDBELOW_MASK 0x00000000 +#define XCHAL_INTLEVEL8_ANDBELOW_MASK XCHAL_INTLEVEL7_ANDBELOW_MASK +#define XCHAL_INTLEVEL9_ANDBELOW_MASK XCHAL_INTLEVEL7_ANDBELOW_MASK +#define XCHAL_INTLEVEL10_ANDBELOW_MASK XCHAL_INTLEVEL7_ANDBELOW_MASK +#define XCHAL_INTLEVEL11_ANDBELOW_MASK XCHAL_INTLEVEL7_ANDBELOW_MASK +#define XCHAL_INTLEVEL12_ANDBELOW_MASK XCHAL_INTLEVEL7_ANDBELOW_MASK +#define XCHAL_INTLEVEL13_ANDBELOW_MASK XCHAL_INTLEVEL7_ANDBELOW_MASK +#define XCHAL_INTLEVEL14_ANDBELOW_MASK XCHAL_INTLEVEL7_ANDBELOW_MASK +#define XCHAL_INTLEVEL15_ANDBELOW_MASK XCHAL_INTLEVEL7_ANDBELOW_MASK + +/* Mask of all low-priority interrupts: */ +#define XCHAL_LOWPRI_MASK XCHAL_INTLEVEL1_ANDBELOW_MASK + +/* Mask of all interrupts masked by PS.EXCM (or CEXCM): */ +#define XCHAL_EXCM_MASK XCHAL_INTLEVEL_ANDBELOW_MASK(XCHAL_EXCM_LEVEL) + +/* Array of masks of interrupts at each range 1..n of interrupt levels: */ +#define XCHAL_INTLEVEL_ANDBELOW_MASKS XCHAL_INTLEVEL0_ANDBELOW_MASK \ + XCHAL_SEP XCHAL_INTLEVEL1_ANDBELOW_MASK \ + XCHAL_SEP XCHAL_INTLEVEL2_ANDBELOW_MASK \ + XCHAL_SEP XCHAL_INTLEVEL3_ANDBELOW_MASK \ + XCHAL_SEP XCHAL_INTLEVEL4_ANDBELOW_MASK \ + XCHAL_SEP XCHAL_INTLEVEL5_ANDBELOW_MASK \ + XCHAL_SEP XCHAL_INTLEVEL6_ANDBELOW_MASK \ + XCHAL_SEP XCHAL_INTLEVEL7_ANDBELOW_MASK \ + XCHAL_SEP XCHAL_INTLEVEL8_ANDBELOW_MASK \ + XCHAL_SEP XCHAL_INTLEVEL9_ANDBELOW_MASK \ + XCHAL_SEP XCHAL_INTLEVEL10_ANDBELOW_MASK \ + XCHAL_SEP XCHAL_INTLEVEL11_ANDBELOW_MASK \ + XCHAL_SEP XCHAL_INTLEVEL12_ANDBELOW_MASK \ + XCHAL_SEP XCHAL_INTLEVEL13_ANDBELOW_MASK \ + XCHAL_SEP XCHAL_INTLEVEL14_ANDBELOW_MASK \ + XCHAL_SEP XCHAL_INTLEVEL15_ANDBELOW_MASK + +#if 0 /*XCHAL_HAVE_NMI*/ +/* NMI "interrupt level" (for use with EXCSAVE_n, EPS_n, EPC_n, RFI n): */ +# define XCHAL_NMILEVEL (XCHAL_NUM_INTLEVELS+1) +#endif + +/* Array of levels of each possible interrupt: */ +#define XCHAL_INT_LEVELS XCHAL_INT0_LEVEL \ + XCHAL_SEP XCHAL_INT1_LEVEL \ + XCHAL_SEP XCHAL_INT2_LEVEL \ + XCHAL_SEP XCHAL_INT3_LEVEL \ + XCHAL_SEP XCHAL_INT4_LEVEL \ + XCHAL_SEP XCHAL_INT5_LEVEL \ + XCHAL_SEP XCHAL_INT6_LEVEL \ + XCHAL_SEP XCHAL_INT7_LEVEL \ + XCHAL_SEP XCHAL_INT8_LEVEL \ + XCHAL_SEP XCHAL_INT9_LEVEL \ + XCHAL_SEP XCHAL_INT10_LEVEL \ + XCHAL_SEP XCHAL_INT11_LEVEL \ + XCHAL_SEP XCHAL_INT12_LEVEL \ + XCHAL_SEP XCHAL_INT13_LEVEL \ + XCHAL_SEP XCHAL_INT14_LEVEL \ + XCHAL_SEP XCHAL_INT15_LEVEL \ + XCHAL_SEP XCHAL_INT16_LEVEL \ + XCHAL_SEP XCHAL_INT17_LEVEL \ + XCHAL_SEP XCHAL_INT18_LEVEL \ + XCHAL_SEP XCHAL_INT19_LEVEL \ + XCHAL_SEP XCHAL_INT20_LEVEL \ + XCHAL_SEP XCHAL_INT21_LEVEL \ + XCHAL_SEP XCHAL_INT22_LEVEL \ + XCHAL_SEP XCHAL_INT23_LEVEL \ + XCHAL_SEP XCHAL_INT24_LEVEL \ + XCHAL_SEP XCHAL_INT25_LEVEL \ + XCHAL_SEP XCHAL_INT26_LEVEL \ + XCHAL_SEP XCHAL_INT27_LEVEL \ + XCHAL_SEP XCHAL_INT28_LEVEL \ + XCHAL_SEP XCHAL_INT29_LEVEL \ + XCHAL_SEP XCHAL_INT30_LEVEL \ + XCHAL_SEP XCHAL_INT31_LEVEL + +/* Array of types of each possible interrupt: */ +#define XCHAL_INT_TYPES XCHAL_INT0_TYPE \ + XCHAL_SEP XCHAL_INT1_TYPE \ + XCHAL_SEP XCHAL_INT2_TYPE \ + XCHAL_SEP XCHAL_INT3_TYPE \ + XCHAL_SEP XCHAL_INT4_TYPE \ + XCHAL_SEP XCHAL_INT5_TYPE \ + XCHAL_SEP XCHAL_INT6_TYPE \ + XCHAL_SEP XCHAL_INT7_TYPE \ + XCHAL_SEP XCHAL_INT8_TYPE \ + XCHAL_SEP XCHAL_INT9_TYPE \ + XCHAL_SEP XCHAL_INT10_TYPE \ + XCHAL_SEP XCHAL_INT11_TYPE \ + XCHAL_SEP XCHAL_INT12_TYPE \ + XCHAL_SEP XCHAL_INT13_TYPE \ + XCHAL_SEP XCHAL_INT14_TYPE \ + XCHAL_SEP XCHAL_INT15_TYPE \ + XCHAL_SEP XCHAL_INT16_TYPE \ + XCHAL_SEP XCHAL_INT17_TYPE \ + XCHAL_SEP XCHAL_INT18_TYPE \ + XCHAL_SEP XCHAL_INT19_TYPE \ + XCHAL_SEP XCHAL_INT20_TYPE \ + XCHAL_SEP XCHAL_INT21_TYPE \ + XCHAL_SEP XCHAL_INT22_TYPE \ + XCHAL_SEP XCHAL_INT23_TYPE \ + XCHAL_SEP XCHAL_INT24_TYPE \ + XCHAL_SEP XCHAL_INT25_TYPE \ + XCHAL_SEP XCHAL_INT26_TYPE \ + XCHAL_SEP XCHAL_INT27_TYPE \ + XCHAL_SEP XCHAL_INT28_TYPE \ + XCHAL_SEP XCHAL_INT29_TYPE \ + XCHAL_SEP XCHAL_INT30_TYPE \ + XCHAL_SEP XCHAL_INT31_TYPE + +/* Array of masks of interrupts for each type of interrupt: */ +#define XCHAL_INTTYPE_MASKS XCHAL_INTTYPE_MASK_UNCONFIGURED \ + XCHAL_SEP XCHAL_INTTYPE_MASK_SOFTWARE \ + XCHAL_SEP XCHAL_INTTYPE_MASK_EXTERN_EDGE \ + XCHAL_SEP XCHAL_INTTYPE_MASK_EXTERN_LEVEL \ + XCHAL_SEP XCHAL_INTTYPE_MASK_TIMER \ + XCHAL_SEP XCHAL_INTTYPE_MASK_NMI \ + XCHAL_SEP XCHAL_INTTYPE_MASK_WRITE_ERROR + +/* Interrupts that can be cleared using the INTCLEAR special register: */ +#define XCHAL_INTCLEARABLE_MASK (XCHAL_INTTYPE_MASK_SOFTWARE+XCHAL_INTTYPE_MASK_EXTERN_EDGE+XCHAL_INTTYPE_MASK_WRITE_ERROR) +/* Interrupts that can be triggered using the INTSET special register: */ +#define XCHAL_INTSETTABLE_MASK XCHAL_INTTYPE_MASK_SOFTWARE + +/* Array of interrupts assigned to each timer (CCOMPARE0 to CCOMPARE3): */ +#define XCHAL_TIMER_INTERRUPTS XCHAL_TIMER0_INTERRUPT \ + XCHAL_SEP XCHAL_TIMER1_INTERRUPT \ + XCHAL_SEP XCHAL_TIMER2_INTERRUPT \ + XCHAL_SEP XCHAL_TIMER3_INTERRUPT + + + +/* For backward compatibility and for the array macros, define macros for + * each unconfigured interrupt number (unfortunately, the value of + * XTHAL_INTTYPE_UNCONFIGURED is not zero): */ +#if XCHAL_NUM_INTERRUPTS == 0 +# define XCHAL_INT0_LEVEL 0 +# define XCHAL_INT0_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 1 +# define XCHAL_INT1_LEVEL 0 +# define XCHAL_INT1_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 2 +# define XCHAL_INT2_LEVEL 0 +# define XCHAL_INT2_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 3 +# define XCHAL_INT3_LEVEL 0 +# define XCHAL_INT3_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 4 +# define XCHAL_INT4_LEVEL 0 +# define XCHAL_INT4_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 5 +# define XCHAL_INT5_LEVEL 0 +# define XCHAL_INT5_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 6 +# define XCHAL_INT6_LEVEL 0 +# define XCHAL_INT6_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 7 +# define XCHAL_INT7_LEVEL 0 +# define XCHAL_INT7_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 8 +# define XCHAL_INT8_LEVEL 0 +# define XCHAL_INT8_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 9 +# define XCHAL_INT9_LEVEL 0 +# define XCHAL_INT9_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 10 +# define XCHAL_INT10_LEVEL 0 +# define XCHAL_INT10_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 11 +# define XCHAL_INT11_LEVEL 0 +# define XCHAL_INT11_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 12 +# define XCHAL_INT12_LEVEL 0 +# define XCHAL_INT12_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 13 +# define XCHAL_INT13_LEVEL 0 +# define XCHAL_INT13_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 14 +# define XCHAL_INT14_LEVEL 0 +# define XCHAL_INT14_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 15 +# define XCHAL_INT15_LEVEL 0 +# define XCHAL_INT15_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 16 +# define XCHAL_INT16_LEVEL 0 +# define XCHAL_INT16_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 17 +# define XCHAL_INT17_LEVEL 0 +# define XCHAL_INT17_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 18 +# define XCHAL_INT18_LEVEL 0 +# define XCHAL_INT18_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 19 +# define XCHAL_INT19_LEVEL 0 +# define XCHAL_INT19_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 20 +# define XCHAL_INT20_LEVEL 0 +# define XCHAL_INT20_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 21 +# define XCHAL_INT21_LEVEL 0 +# define XCHAL_INT21_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 22 +# define XCHAL_INT22_LEVEL 0 +# define XCHAL_INT22_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 23 +# define XCHAL_INT23_LEVEL 0 +# define XCHAL_INT23_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 24 +# define XCHAL_INT24_LEVEL 0 +# define XCHAL_INT24_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 25 +# define XCHAL_INT25_LEVEL 0 +# define XCHAL_INT25_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 26 +# define XCHAL_INT26_LEVEL 0 +# define XCHAL_INT26_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 27 +# define XCHAL_INT27_LEVEL 0 +# define XCHAL_INT27_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 28 +# define XCHAL_INT28_LEVEL 0 +# define XCHAL_INT28_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 29 +# define XCHAL_INT29_LEVEL 0 +# define XCHAL_INT29_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 30 +# define XCHAL_INT30_LEVEL 0 +# define XCHAL_INT30_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif +#if XCHAL_NUM_INTERRUPTS <= 31 +# define XCHAL_INT31_LEVEL 0 +# define XCHAL_INT31_TYPE XTHAL_INTTYPE_UNCONFIGURED +#endif + + +/* + * Masks and levels corresponding to each *external* interrupt. + */ + +#define XCHAL_EXTINT0_MASK (1 << XCHAL_EXTINT0_NUM) +#define XCHAL_EXTINT0_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT0_NUM) +#define XCHAL_EXTINT1_MASK (1 << XCHAL_EXTINT1_NUM) +#define XCHAL_EXTINT1_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT1_NUM) +#define XCHAL_EXTINT2_MASK (1 << XCHAL_EXTINT2_NUM) +#define XCHAL_EXTINT2_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT2_NUM) +#define XCHAL_EXTINT3_MASK (1 << XCHAL_EXTINT3_NUM) +#define XCHAL_EXTINT3_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT3_NUM) +#define XCHAL_EXTINT4_MASK (1 << XCHAL_EXTINT4_NUM) +#define XCHAL_EXTINT4_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT4_NUM) +#define XCHAL_EXTINT5_MASK (1 << XCHAL_EXTINT5_NUM) +#define XCHAL_EXTINT5_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT5_NUM) +#define XCHAL_EXTINT6_MASK (1 << XCHAL_EXTINT6_NUM) +#define XCHAL_EXTINT6_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT6_NUM) +#define XCHAL_EXTINT7_MASK (1 << XCHAL_EXTINT7_NUM) +#define XCHAL_EXTINT7_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT7_NUM) +#define XCHAL_EXTINT8_MASK (1 << XCHAL_EXTINT8_NUM) +#define XCHAL_EXTINT8_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT8_NUM) +#define XCHAL_EXTINT9_MASK (1 << XCHAL_EXTINT9_NUM) +#define XCHAL_EXTINT9_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT9_NUM) +#define XCHAL_EXTINT10_MASK (1 << XCHAL_EXTINT10_NUM) +#define XCHAL_EXTINT10_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT10_NUM) +#define XCHAL_EXTINT11_MASK (1 << XCHAL_EXTINT11_NUM) +#define XCHAL_EXTINT11_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT11_NUM) +#define XCHAL_EXTINT12_MASK (1 << XCHAL_EXTINT12_NUM) +#define XCHAL_EXTINT12_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT12_NUM) +#define XCHAL_EXTINT13_MASK (1 << XCHAL_EXTINT13_NUM) +#define XCHAL_EXTINT13_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT13_NUM) +#define XCHAL_EXTINT14_MASK (1 << XCHAL_EXTINT14_NUM) +#define XCHAL_EXTINT14_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT14_NUM) +#define XCHAL_EXTINT15_MASK (1 << XCHAL_EXTINT15_NUM) +#define XCHAL_EXTINT15_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT15_NUM) +#define XCHAL_EXTINT16_MASK (1 << XCHAL_EXTINT16_NUM) +#define XCHAL_EXTINT16_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT16_NUM) +#define XCHAL_EXTINT17_MASK (1 << XCHAL_EXTINT17_NUM) +#define XCHAL_EXTINT17_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT17_NUM) +#define XCHAL_EXTINT18_MASK (1 << XCHAL_EXTINT18_NUM) +#define XCHAL_EXTINT18_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT18_NUM) +#define XCHAL_EXTINT19_MASK (1 << XCHAL_EXTINT19_NUM) +#define XCHAL_EXTINT19_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT19_NUM) +#define XCHAL_EXTINT20_MASK (1 << XCHAL_EXTINT20_NUM) +#define XCHAL_EXTINT20_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT20_NUM) +#define XCHAL_EXTINT21_MASK (1 << XCHAL_EXTINT21_NUM) +#define XCHAL_EXTINT21_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT21_NUM) +#define XCHAL_EXTINT22_MASK (1 << XCHAL_EXTINT22_NUM) +#define XCHAL_EXTINT22_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT22_NUM) +#define XCHAL_EXTINT23_MASK (1 << XCHAL_EXTINT23_NUM) +#define XCHAL_EXTINT23_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT23_NUM) +#define XCHAL_EXTINT24_MASK (1 << XCHAL_EXTINT24_NUM) +#define XCHAL_EXTINT24_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT24_NUM) +#define XCHAL_EXTINT25_MASK (1 << XCHAL_EXTINT25_NUM) +#define XCHAL_EXTINT25_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT25_NUM) +#define XCHAL_EXTINT26_MASK (1 << XCHAL_EXTINT26_NUM) +#define XCHAL_EXTINT26_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT26_NUM) +#define XCHAL_EXTINT27_MASK (1 << XCHAL_EXTINT27_NUM) +#define XCHAL_EXTINT27_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT27_NUM) +#define XCHAL_EXTINT28_MASK (1 << XCHAL_EXTINT28_NUM) +#define XCHAL_EXTINT28_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT28_NUM) +#define XCHAL_EXTINT29_MASK (1 << XCHAL_EXTINT29_NUM) +#define XCHAL_EXTINT29_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT29_NUM) +#define XCHAL_EXTINT30_MASK (1 << XCHAL_EXTINT30_NUM) +#define XCHAL_EXTINT30_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT30_NUM) +#define XCHAL_EXTINT31_MASK (1 << XCHAL_EXTINT31_NUM) +#define XCHAL_EXTINT31_LEVEL XCHAL_INT_LEVEL(XCHAL_EXTINT31_NUM) + + +/*---------------------------------------------------------------------- + EXCEPTIONS and VECTORS + ----------------------------------------------------------------------*/ + +/* For backward compatibility ONLY -- DO NOT USE (will be removed in future release): */ +#define XCHAL_HAVE_OLD_EXC_ARCH XCHAL_HAVE_XEA1 /* (DEPRECATED) 1 if old exception architecture (XEA1), 0 otherwise (eg. XEA2) */ +#define XCHAL_HAVE_EXCM XCHAL_HAVE_XEA2 /* (DEPRECATED) 1 if PS.EXCM bit exists (currently equals XCHAL_HAVE_TLBS) */ +#ifdef XCHAL_USER_VECTOR_VADDR +#define XCHAL_PROGRAMEXC_VECTOR_VADDR XCHAL_USER_VECTOR_VADDR +#define XCHAL_USEREXC_VECTOR_VADDR XCHAL_USER_VECTOR_VADDR +#endif +#ifdef XCHAL_USER_VECTOR_PADDR +# define XCHAL_PROGRAMEXC_VECTOR_PADDR XCHAL_USER_VECTOR_PADDR +# define XCHAL_USEREXC_VECTOR_PADDR XCHAL_USER_VECTOR_PADDR +#endif +#ifdef XCHAL_KERNEL_VECTOR_VADDR +# define XCHAL_STACKEDEXC_VECTOR_VADDR XCHAL_KERNEL_VECTOR_VADDR +# define XCHAL_KERNELEXC_VECTOR_VADDR XCHAL_KERNEL_VECTOR_VADDR +#endif +#ifdef XCHAL_KERNEL_VECTOR_PADDR +# define XCHAL_STACKEDEXC_VECTOR_PADDR XCHAL_KERNEL_VECTOR_PADDR +# define XCHAL_KERNELEXC_VECTOR_PADDR XCHAL_KERNEL_VECTOR_PADDR +#endif + +#if 0 +#if XCHAL_HAVE_DEBUG +# define XCHAL_DEBUG_VECTOR_VADDR XCHAL_INTLEVEL_VECTOR_VADDR(XCHAL_DEBUGLEVEL) +/* This one should only get defined if the corresponding intlevel paddr macro exists: */ +# define XCHAL_DEBUG_VECTOR_PADDR XCHAL_INTLEVEL_VECTOR_PADDR(XCHAL_DEBUGLEVEL) +#endif +#endif + +/* Indexing macros: */ +#define _XCHAL_INTLEVEL_VECTOR_VADDR(n) XCHAL_INTLEVEL ## n ## _VECTOR_VADDR +#define XCHAL_INTLEVEL_VECTOR_VADDR(n) _XCHAL_INTLEVEL_VECTOR_VADDR(n) /* n = 0 .. 15 */ + +/* + * General Exception Causes + * (values of EXCCAUSE special register set by general exceptions, + * which vector to the user, kernel, or double-exception vectors). + * + * DEPRECATED. Please use the equivalent EXCCAUSE_xxx macros + * defined in . (Note that these have slightly + * different names, they don't just have the XCHAL_ prefix removed.) + */ +#define XCHAL_EXCCAUSE_ILLEGAL_INSTRUCTION 0 /* Illegal Instruction */ +#define XCHAL_EXCCAUSE_SYSTEM_CALL 1 /* System Call */ +#define XCHAL_EXCCAUSE_INSTRUCTION_FETCH_ERROR 2 /* Instruction Fetch Error */ +#define XCHAL_EXCCAUSE_LOAD_STORE_ERROR 3 /* Load Store Error */ +#define XCHAL_EXCCAUSE_LEVEL1_INTERRUPT 4 /* Level 1 Interrupt */ +#define XCHAL_EXCCAUSE_ALLOCA 5 /* Stack Extension Assist */ +#define XCHAL_EXCCAUSE_INTEGER_DIVIDE_BY_ZERO 6 /* Integer Divide by Zero */ +#define XCHAL_EXCCAUSE_SPECULATION 7 /* Speculation */ +#define XCHAL_EXCCAUSE_PRIVILEGED 8 /* Privileged Instruction */ +#define XCHAL_EXCCAUSE_UNALIGNED 9 /* Unaligned Load Store */ +/*10..15 reserved*/ +#define XCHAL_EXCCAUSE_ITLB_MISS 16 /* ITlb Miss Exception */ +#define XCHAL_EXCCAUSE_ITLB_MULTIHIT 17 /* ITlb Mutltihit Exception */ +#define XCHAL_EXCCAUSE_ITLB_PRIVILEGE 18 /* ITlb Privilege Exception */ +#define XCHAL_EXCCAUSE_ITLB_SIZE_RESTRICTION 19 /* ITlb Size Restriction Exception */ +#define XCHAL_EXCCAUSE_FETCH_CACHE_ATTRIBUTE 20 /* Fetch Cache Attribute Exception */ +/*21..23 reserved*/ +#define XCHAL_EXCCAUSE_DTLB_MISS 24 /* DTlb Miss Exception */ +#define XCHAL_EXCCAUSE_DTLB_MULTIHIT 25 /* DTlb Multihit Exception */ +#define XCHAL_EXCCAUSE_DTLB_PRIVILEGE 26 /* DTlb Privilege Exception */ +#define XCHAL_EXCCAUSE_DTLB_SIZE_RESTRICTION 27 /* DTlb Size Restriction Exception */ +#define XCHAL_EXCCAUSE_LOAD_CACHE_ATTRIBUTE 28 /* Load Cache Attribute Exception */ +#define XCHAL_EXCCAUSE_STORE_CACHE_ATTRIBUTE 29 /* Store Cache Attribute Exception */ +/*30..31 reserved*/ +#define XCHAL_EXCCAUSE_COPROCESSOR0_DISABLED 32 /* Coprocessor 0 disabled */ +#define XCHAL_EXCCAUSE_COPROCESSOR1_DISABLED 33 /* Coprocessor 1 disabled */ +#define XCHAL_EXCCAUSE_COPROCESSOR2_DISABLED 34 /* Coprocessor 2 disabled */ +#define XCHAL_EXCCAUSE_COPROCESSOR3_DISABLED 35 /* Coprocessor 3 disabled */ +#define XCHAL_EXCCAUSE_COPROCESSOR4_DISABLED 36 /* Coprocessor 4 disabled */ +#define XCHAL_EXCCAUSE_COPROCESSOR5_DISABLED 37 /* Coprocessor 5 disabled */ +#define XCHAL_EXCCAUSE_COPROCESSOR6_DISABLED 38 /* Coprocessor 6 disabled */ +#define XCHAL_EXCCAUSE_COPROCESSOR7_DISABLED 39 /* Coprocessor 7 disabled */ +#define XCHAL_EXCCAUSE_FLOATING_POINT 40 /* Floating Point Exception */ +/*40..63 reserved*/ + + +/* + * Miscellaneous special register fields. + * + * For each special register, and each field within each register: + * XCHAL__VALIDMASK is the set of bits defined in the register. + * XCHAL___BITS is the number of bits in the field. + * XCHAL___NUM is 2^bits, the number of possible values + * of the field. + * XCHAL___SHIFT is the position of the field within + * the register, starting from the least significant bit. + * + * DEPRECATED. Please use the equivalent macros defined in + * . (Note that these have different names.) + */ + +/* DBREAKC (special register number 160): */ +#define XCHAL_DBREAKC_VALIDMASK 0xC000003F +#define XCHAL_DBREAKC_MASK_BITS 6 +#define XCHAL_DBREAKC_MASK_NUM 64 +#define XCHAL_DBREAKC_MASK_SHIFT 0 +#define XCHAL_DBREAKC_MASK_MASK 0x0000003F +#define XCHAL_DBREAKC_LOADBREAK_BITS 1 +#define XCHAL_DBREAKC_LOADBREAK_NUM 2 +#define XCHAL_DBREAKC_LOADBREAK_SHIFT 30 +#define XCHAL_DBREAKC_LOADBREAK_MASK 0x40000000 +#define XCHAL_DBREAKC_STOREBREAK_BITS 1 +#define XCHAL_DBREAKC_STOREBREAK_NUM 2 +#define XCHAL_DBREAKC_STOREBREAK_SHIFT 31 +#define XCHAL_DBREAKC_STOREBREAK_MASK 0x80000000 +/* PS (special register number 230): */ +#define XCHAL_PS_VALIDMASK 0x00070F3F +#define XCHAL_PS_INTLEVEL_BITS 4 +#define XCHAL_PS_INTLEVEL_NUM 16 +#define XCHAL_PS_INTLEVEL_SHIFT 0 +#define XCHAL_PS_INTLEVEL_MASK 0x0000000F +#define XCHAL_PS_EXCM_BITS 1 +#define XCHAL_PS_EXCM_NUM 2 +#define XCHAL_PS_EXCM_SHIFT 4 +#define XCHAL_PS_EXCM_MASK 0x00000010 +#define XCHAL_PS_UM_BITS 1 +#define XCHAL_PS_UM_NUM 2 +#define XCHAL_PS_UM_SHIFT 5 +#define XCHAL_PS_UM_MASK 0x00000020 +#define XCHAL_PS_RING_BITS 2 +#define XCHAL_PS_RING_NUM 4 +#define XCHAL_PS_RING_SHIFT 6 +#define XCHAL_PS_RING_MASK 0x000000C0 +#define XCHAL_PS_OWB_BITS 4 +#define XCHAL_PS_OWB_NUM 16 +#define XCHAL_PS_OWB_SHIFT 8 +#define XCHAL_PS_OWB_MASK 0x00000F00 +#define XCHAL_PS_CALLINC_BITS 2 +#define XCHAL_PS_CALLINC_NUM 4 +#define XCHAL_PS_CALLINC_SHIFT 16 +#define XCHAL_PS_CALLINC_MASK 0x00030000 +#define XCHAL_PS_WOE_BITS 1 +#define XCHAL_PS_WOE_NUM 2 +#define XCHAL_PS_WOE_SHIFT 18 +#define XCHAL_PS_WOE_MASK 0x00040000 +/* EXCCAUSE (special register number 232): */ +#define XCHAL_EXCCAUSE_VALIDMASK 0x0000003F +#define XCHAL_EXCCAUSE_BITS 6 +#define XCHAL_EXCCAUSE_NUM 64 +#define XCHAL_EXCCAUSE_SHIFT 0 +#define XCHAL_EXCCAUSE_MASK 0x0000003F +/* DEBUGCAUSE (special register number 233): */ +#define XCHAL_DEBUGCAUSE_VALIDMASK 0x0000003F +#define XCHAL_DEBUGCAUSE_ICOUNT_BITS 1 +#define XCHAL_DEBUGCAUSE_ICOUNT_NUM 2 +#define XCHAL_DEBUGCAUSE_ICOUNT_SHIFT 0 +#define XCHAL_DEBUGCAUSE_ICOUNT_MASK 0x00000001 +#define XCHAL_DEBUGCAUSE_IBREAK_BITS 1 +#define XCHAL_DEBUGCAUSE_IBREAK_NUM 2 +#define XCHAL_DEBUGCAUSE_IBREAK_SHIFT 1 +#define XCHAL_DEBUGCAUSE_IBREAK_MASK 0x00000002 +#define XCHAL_DEBUGCAUSE_DBREAK_BITS 1 +#define XCHAL_DEBUGCAUSE_DBREAK_NUM 2 +#define XCHAL_DEBUGCAUSE_DBREAK_SHIFT 2 +#define XCHAL_DEBUGCAUSE_DBREAK_MASK 0x00000004 +#define XCHAL_DEBUGCAUSE_BREAK_BITS 1 +#define XCHAL_DEBUGCAUSE_BREAK_NUM 2 +#define XCHAL_DEBUGCAUSE_BREAK_SHIFT 3 +#define XCHAL_DEBUGCAUSE_BREAK_MASK 0x00000008 +#define XCHAL_DEBUGCAUSE_BREAKN_BITS 1 +#define XCHAL_DEBUGCAUSE_BREAKN_NUM 2 +#define XCHAL_DEBUGCAUSE_BREAKN_SHIFT 4 +#define XCHAL_DEBUGCAUSE_BREAKN_MASK 0x00000010 +#define XCHAL_DEBUGCAUSE_DEBUGINT_BITS 1 +#define XCHAL_DEBUGCAUSE_DEBUGINT_NUM 2 +#define XCHAL_DEBUGCAUSE_DEBUGINT_SHIFT 5 +#define XCHAL_DEBUGCAUSE_DEBUGINT_MASK 0x00000020 + + + + +/*---------------------------------------------------------------------- + TIMERS + ----------------------------------------------------------------------*/ + +/*#define XCHAL_HAVE_TIMERS XCHAL_HAVE_CCOUNT*/ + + + +/*---------------------------------------------------------------------- + INTERNAL I/D RAM/ROMs and XLMI + ----------------------------------------------------------------------*/ + +#define XCHAL_NUM_IROM XCHAL_NUM_INSTROM /* (DEPRECATED) */ +#define XCHAL_NUM_IRAM XCHAL_NUM_INSTRAM /* (DEPRECATED) */ +#define XCHAL_NUM_DROM XCHAL_NUM_DATAROM /* (DEPRECATED) */ +#define XCHAL_NUM_DRAM XCHAL_NUM_DATARAM /* (DEPRECATED) */ + +#define XCHAL_IROM0_VADDR XCHAL_INSTROM0_VADDR /* (DEPRECATED) */ +#define XCHAL_IROM0_PADDR XCHAL_INSTROM0_PADDR /* (DEPRECATED) */ +#define XCHAL_IROM0_SIZE XCHAL_INSTROM0_SIZE /* (DEPRECATED) */ +#define XCHAL_IROM1_VADDR XCHAL_INSTROM1_VADDR /* (DEPRECATED) */ +#define XCHAL_IROM1_PADDR XCHAL_INSTROM1_PADDR /* (DEPRECATED) */ +#define XCHAL_IROM1_SIZE XCHAL_INSTROM1_SIZE /* (DEPRECATED) */ +#define XCHAL_IRAM0_VADDR XCHAL_INSTRAM0_VADDR /* (DEPRECATED) */ +#define XCHAL_IRAM0_PADDR XCHAL_INSTRAM0_PADDR /* (DEPRECATED) */ +#define XCHAL_IRAM0_SIZE XCHAL_INSTRAM0_SIZE /* (DEPRECATED) */ +#define XCHAL_IRAM1_VADDR XCHAL_INSTRAM1_VADDR /* (DEPRECATED) */ +#define XCHAL_IRAM1_PADDR XCHAL_INSTRAM1_PADDR /* (DEPRECATED) */ +#define XCHAL_IRAM1_SIZE XCHAL_INSTRAM1_SIZE /* (DEPRECATED) */ +#define XCHAL_DROM0_VADDR XCHAL_DATAROM0_VADDR /* (DEPRECATED) */ +#define XCHAL_DROM0_PADDR XCHAL_DATAROM0_PADDR /* (DEPRECATED) */ +#define XCHAL_DROM0_SIZE XCHAL_DATAROM0_SIZE /* (DEPRECATED) */ +#define XCHAL_DROM1_VADDR XCHAL_DATAROM1_VADDR /* (DEPRECATED) */ +#define XCHAL_DROM1_PADDR XCHAL_DATAROM1_PADDR /* (DEPRECATED) */ +#define XCHAL_DROM1_SIZE XCHAL_DATAROM1_SIZE /* (DEPRECATED) */ +#define XCHAL_DRAM0_VADDR XCHAL_DATARAM0_VADDR /* (DEPRECATED) */ +#define XCHAL_DRAM0_PADDR XCHAL_DATARAM0_PADDR /* (DEPRECATED) */ +#define XCHAL_DRAM0_SIZE XCHAL_DATARAM0_SIZE /* (DEPRECATED) */ +#define XCHAL_DRAM1_VADDR XCHAL_DATARAM1_VADDR /* (DEPRECATED) */ +#define XCHAL_DRAM1_PADDR XCHAL_DATARAM1_PADDR /* (DEPRECATED) */ +#define XCHAL_DRAM1_SIZE XCHAL_DATARAM1_SIZE /* (DEPRECATED) */ + + + +/*---------------------------------------------------------------------- + CACHE + ----------------------------------------------------------------------*/ + + +/* Default PREFCTL value to enable prefetch. */ +#define XCHAL_CACHE_PREFCTL_DEFAULT 0x44 + + +/* Max for both I-cache and D-cache (used for general alignment): */ +#if XCHAL_ICACHE_LINESIZE > XCHAL_DCACHE_LINESIZE +# define XCHAL_CACHE_LINEWIDTH_MAX XCHAL_ICACHE_LINEWIDTH +# define XCHAL_CACHE_LINESIZE_MAX XCHAL_ICACHE_LINESIZE +#else +# define XCHAL_CACHE_LINEWIDTH_MAX XCHAL_DCACHE_LINEWIDTH +# define XCHAL_CACHE_LINESIZE_MAX XCHAL_DCACHE_LINESIZE +#endif + +#define XCHAL_ICACHE_SETSIZE (1< XCHAL_DCACHE_SETWIDTH +# define XCHAL_CACHE_SETWIDTH_MAX XCHAL_ICACHE_SETWIDTH +# define XCHAL_CACHE_SETSIZE_MAX XCHAL_ICACHE_SETSIZE +#else +# define XCHAL_CACHE_SETWIDTH_MAX XCHAL_DCACHE_SETWIDTH +# define XCHAL_CACHE_SETSIZE_MAX XCHAL_DCACHE_SETSIZE +#endif + +/* Instruction cache tag bits: */ +#define XCHAL_ICACHE_TAG_V_SHIFT 0 +#define XCHAL_ICACHE_TAG_V 0x1 /* valid bit */ +#if XCHAL_ICACHE_WAYS > 1 +# define XCHAL_ICACHE_TAG_F_SHIFT 1 +# define XCHAL_ICACHE_TAG_F 0x2 /* fill (LRU) bit */ +#else +# define XCHAL_ICACHE_TAG_F_SHIFT 0 +# define XCHAL_ICACHE_TAG_F 0 /* no fill (LRU) bit */ +#endif +#if XCHAL_ICACHE_LINE_LOCKABLE +# define XCHAL_ICACHE_TAG_L_SHIFT (XCHAL_ICACHE_TAG_F_SHIFT+1) +# define XCHAL_ICACHE_TAG_L (1 << XCHAL_ICACHE_TAG_L_SHIFT) /* lock bit */ +#else +# define XCHAL_ICACHE_TAG_L_SHIFT XCHAL_ICACHE_TAG_F_SHIFT +# define XCHAL_ICACHE_TAG_L 0 /* no lock bit */ +#endif +/* Data cache tag bits: */ +#define XCHAL_DCACHE_TAG_V_SHIFT 0 +#define XCHAL_DCACHE_TAG_V 0x1 /* valid bit */ +#if XCHAL_DCACHE_WAYS > 1 +# define XCHAL_DCACHE_TAG_F_SHIFT 1 +# define XCHAL_DCACHE_TAG_F 0x2 /* fill (LRU) bit */ +#else +# define XCHAL_DCACHE_TAG_F_SHIFT 0 +# define XCHAL_DCACHE_TAG_F 0 /* no fill (LRU) bit */ +#endif +#if XCHAL_DCACHE_IS_WRITEBACK +# define XCHAL_DCACHE_TAG_D_SHIFT (XCHAL_DCACHE_TAG_F_SHIFT+1) +# define XCHAL_DCACHE_TAG_D (1 << XCHAL_DCACHE_TAG_D_SHIFT) /* dirty bit */ +#else +# define XCHAL_DCACHE_TAG_D_SHIFT XCHAL_DCACHE_TAG_F_SHIFT +# define XCHAL_DCACHE_TAG_D 0 /* no dirty bit */ +#endif +#if XCHAL_DCACHE_LINE_LOCKABLE +# define XCHAL_DCACHE_TAG_L_SHIFT (XCHAL_DCACHE_TAG_D_SHIFT+1) +# define XCHAL_DCACHE_TAG_L (1 << XCHAL_DCACHE_TAG_D_SHIFT) /* lock bit */ +#else +# define XCHAL_DCACHE_TAG_L_SHIFT XCHAL_DCACHE_TAG_D_SHIFT +# define XCHAL_DCACHE_TAG_L 0 /* no lock bit */ +#endif + + +/*---------------------------------------------------------------------- + MMU + ----------------------------------------------------------------------*/ + +/* See for more details. */ + +/* Has different semantic in open source headers (where it means HAVE_PTP_MMU), + so comment out starting with RB-2008.3 release; later, might get + get reintroduced as a synonym for XCHAL_HAVE_PTP_MMU instead: */ +/*#define XCHAL_HAVE_MMU XCHAL_HAVE_TLBS*/ /* (DEPRECATED; use XCHAL_HAVE_TLBS instead) */ + +/* Indexing macros: */ +#define _XCHAL_ITLB_SET(n,_what) XCHAL_ITLB_SET ## n ## _what +#define XCHAL_ITLB_SET(n,what) _XCHAL_ITLB_SET(n, _ ## what ) +#define _XCHAL_ITLB_SET_E(n,i,_what) XCHAL_ITLB_SET ## n ## _E ## i ## _what +#define XCHAL_ITLB_SET_E(n,i,what) _XCHAL_ITLB_SET_E(n,i, _ ## what ) +#define _XCHAL_DTLB_SET(n,_what) XCHAL_DTLB_SET ## n ## _what +#define XCHAL_DTLB_SET(n,what) _XCHAL_DTLB_SET(n, _ ## what ) +#define _XCHAL_DTLB_SET_E(n,i,_what) XCHAL_DTLB_SET ## n ## _E ## i ## _what +#define XCHAL_DTLB_SET_E(n,i,what) _XCHAL_DTLB_SET_E(n,i, _ ## what ) +/* + * Example use: XCHAL_ITLB_SET(XCHAL_ITLB_ARF_SET0,ENTRIES) + * to get the value of XCHAL_ITLB_SET_ENTRIES where is the first auto-refill set. + */ + +/* Number of entries per autorefill way: */ +#define XCHAL_ITLB_ARF_ENTRIES (1< 0 && XCHAL_DTLB_ARF_WAYS > 0 && XCHAL_MMU_RINGS >= 2 +# define XCHAL_HAVE_PTP_MMU 1 /* have full MMU (with page table [autorefill] and protection) */ +#else +# define XCHAL_HAVE_PTP_MMU 0 /* don't have full MMU */ +#endif +#endif + +/* + * For full MMUs, report kernel RAM segment and kernel I/O segment static page mappings: + */ +#if XCHAL_HAVE_PTP_MMU && !XCHAL_HAVE_SPANNING_WAY +#define XCHAL_KSEG_CACHED_VADDR 0xD0000000 /* virt.addr of kernel RAM cached static map */ +#define XCHAL_KSEG_CACHED_PADDR 0x00000000 /* phys.addr of kseg_cached */ +#define XCHAL_KSEG_CACHED_SIZE 0x08000000 /* size in bytes of kseg_cached (assumed power of 2!!!) */ +#define XCHAL_KSEG_BYPASS_VADDR 0xD8000000 /* virt.addr of kernel RAM bypass (uncached) static map */ +#define XCHAL_KSEG_BYPASS_PADDR 0x00000000 /* phys.addr of kseg_bypass */ +#define XCHAL_KSEG_BYPASS_SIZE 0x08000000 /* size in bytes of kseg_bypass (assumed power of 2!!!) */ + +#define XCHAL_KIO_CACHED_VADDR 0xE0000000 /* virt.addr of kernel I/O cached static map */ +#define XCHAL_KIO_CACHED_PADDR 0xF0000000 /* phys.addr of kio_cached */ +#define XCHAL_KIO_CACHED_SIZE 0x10000000 /* size in bytes of kio_cached (assumed power of 2!!!) */ +#define XCHAL_KIO_BYPASS_VADDR 0xF0000000 /* virt.addr of kernel I/O bypass (uncached) static map */ +#define XCHAL_KIO_BYPASS_PADDR 0xF0000000 /* phys.addr of kio_bypass */ +#define XCHAL_KIO_BYPASS_SIZE 0x10000000 /* size in bytes of kio_bypass (assumed power of 2!!!) */ + +#define XCHAL_SEG_MAPPABLE_VADDR 0x00000000 /* start of largest non-static-mapped virtual addr area */ +#define XCHAL_SEG_MAPPABLE_SIZE 0xD0000000 /* size in bytes of " */ +/* define XCHAL_SEG_MAPPABLE2_xxx if more areas present, sorted in order of descending size. */ +#endif + + +/*---------------------------------------------------------------------- + MISC + ----------------------------------------------------------------------*/ + +/* Data alignment required if used for instructions: */ +#if XCHAL_INST_FETCH_WIDTH > XCHAL_DATA_WIDTH +# define XCHAL_ALIGN_MAX XCHAL_INST_FETCH_WIDTH +#else +# define XCHAL_ALIGN_MAX XCHAL_DATA_WIDTH +#endif + +/* + * Names kept for backward compatibility. + * (Here "RELEASE" is now a misnomer; these are product *versions*, not the releases + * under which they are released. In the T10##.# era there was no distinction.) + */ +#define XCHAL_HW_RELEASE_MAJOR XCHAL_HW_VERSION_MAJOR +#define XCHAL_HW_RELEASE_MINOR XCHAL_HW_VERSION_MINOR +#define XCHAL_HW_RELEASE_NAME XCHAL_HW_VERSION_NAME + + + + +/*---------------------------------------------------------------------- + COPROCESSORS and EXTRA STATE + ----------------------------------------------------------------------*/ + +#define XCHAL_EXTRA_SA_SIZE XCHAL_NCP_SA_SIZE +#define XCHAL_EXTRA_SA_ALIGN XCHAL_NCP_SA_ALIGN +#define XCHAL_CPEXTRA_SA_SIZE XCHAL_TOTAL_SA_SIZE +#define XCHAL_CPEXTRA_SA_ALIGN XCHAL_TOTAL_SA_ALIGN + +#if defined (_ASMLANGUAGE) || defined (__ASSEMBLER__) + + /* Invoked at start of save area load/store sequence macro to setup macro + * internal offsets. Not usually invoked directly. + * continue 0 for 1st sequence, 1 for subsequent consecutive ones. + * totofs offset from original ptr to next load/store location. + */ + .macro xchal_sa_start continue totofs + .ifeq \continue + .set .Lxchal_pofs_, 0 /* offset from original ptr to current \ptr */ + .set .Lxchal_ofs_, 0 /* offset from current \ptr to next load/store location */ + .endif + .if \totofs + 1 /* if totofs specified (not -1) */ + .set .Lxchal_ofs_, \totofs - .Lxchal_pofs_ /* specific offset from original ptr */ + .endif + .endm + + /* Align portion of save area and bring ptr in range if necessary. + * Used by save area load/store sequences. Not usually invoked directly. + * Allows combining multiple (sub-)sequences arbitrarily. + * ptr pointer to save area (may be off, see .Lxchal_pofs_) + * minofs,maxofs range of offset from cur ptr to next load/store loc; + * minofs <= 0 <= maxofs (0 must always be valid offset) + * range must be within +/- 30kB or so. + * ofsalign alignment granularity of minofs .. maxofs (pow of 2) + * (restriction on offset from ptr to next load/store loc) + * totalign align from orig ptr to next load/store loc (pow of 2) + */ + .macro xchal_sa_align ptr minofs maxofs ofsalign totalign + .set .Lxchal_ofs_, ((.Lxchal_pofs_ + .Lxchal_ofs_ + \totalign - 1) & -\totalign) - .Lxchal_pofs_ + /* If necessary, adjust \ptr to bring .Lxchal_ofs_ in acceptable range: */ + .if (((\maxofs) - .Lxchal_ofs_) & 0xC0000000) | ((.Lxchal_ofs_ - (\minofs)) & 0xC0000000) | (.Lxchal_ofs_ & (\ofsalign-1)) + .set .Ligmask, 0xFFFFFFFF /* TODO: optimize to addmi, per aligns and .Lxchal_ofs_ */ + addi \ptr, \ptr, (.Lxchal_ofs_ & .Ligmask) + .set .Lxchal_pofs_, .Lxchal_pofs_ + (.Lxchal_ofs_ & .Ligmask) + .set .Lxchal_ofs_, (.Lxchal_ofs_ & ~.Ligmask) + .endif + .endm + /* + * We could optimize for addi to expand to only addmi instead of + * "addmi;addi", where possible. Here's a partial example how: + * .set .Lmaxmask, -(\ofsalign) & -(\totalign) + * .if (((\maxofs) + ~.Lmaxmask + 1) & 0xFFFFFF00) && ((.Lxchal_ofs_ & ~.Lmaxmask) == 0) + * .set .Ligmask, 0xFFFFFF00 + * .elif ... ditto for negative ofs range ... + * .set .Ligmask, 0xFFFFFF00 + * .set ... adjust per offset ... + * .else + * .set .Ligmask, 0xFFFFFFFF + * .endif + */ + + /* Invoke this after xchal_XXX_{load,store} macros to restore \ptr. */ + .macro xchal_sa_ptr_restore ptr + .if .Lxchal_pofs_ + addi \ptr, \ptr, - .Lxchal_pofs_ + .set .Lxchal_ofs_, .Lxchal_ofs_ + .Lxchal_pofs_ + .set .Lxchal_pofs_, 0 + .endif + .endm + + /* + * Use as eg: + * xchal_atmps_store a1, SOMEOFS, XCHAL_SA_NUM_ATMPS, a4, a5 + * xchal_ncp_load a2, a0,a3,a4,a5 + * xchal_atmps_load a1, SOMEOFS, XCHAL_SA_NUM_ATMPS, a4, a5 + * + * Specify only the ARs you *haven't* saved/restored already, up to 4. + * They *must* be the *last* ARs (in same order) specified to save area + * load/store sequences. In the example above, a0 and a3 were already + * saved/restored and unused (thus available) but a4 and a5 were not. + */ +#define xchal_atmps_store xchal_atmps_loadstore s32i, +#define xchal_atmps_load xchal_atmps_loadstore l32i, + .macro xchal_atmps_loadstore inst ptr offset nreq aa=0 ab=0 ac=0 ad=0 + .set .Lnsaved_, 0 + .irp reg,\aa,\ab,\ac,\ad + .ifeq 0x\reg ; .set .Lnsaved_,.Lnsaved_+1 ; .endif + .endr + .set .Laofs_, 0 + .irp reg,\aa,\ab,\ac,\ad + .ifgt (\nreq)-.Lnsaved_ + \inst \reg, \ptr, .Laofs_+\offset + .set .Laofs_,.Laofs_+4 + .set .Lnsaved_,.Lnsaved_+1 + .endif + .endr + .endm + +/*#define xchal_ncp_load_a2 xchal_ncp_load a2,a3,a4,a5,a6*/ +/*#define xchal_ncp_store_a2 xchal_ncp_store a2,a3,a4,a5,a6*/ +#define xchal_extratie_load xchal_ncptie_load +#define xchal_extratie_store xchal_ncptie_store +#define xchal_extratie_load_a2 xchal_ncptie_load a2,a3,a4,a5,a6 +#define xchal_extratie_store_a2 xchal_ncptie_store a2,a3,a4,a5,a6 +#define xchal_extra_load xchal_ncp_load +#define xchal_extra_store xchal_ncp_store +#define xchal_extra_load_a2 xchal_ncp_load a2,a3,a4,a5,a6 +#define xchal_extra_store_a2 xchal_ncp_store a2,a3,a4,a5,a6 +#define xchal_extra_load_funcbody xchal_ncp_load a2,a3,a4,a5,a6 +#define xchal_extra_store_funcbody xchal_ncp_store a2,a3,a4,a5,a6 +#define xchal_cp0_store_a2 xchal_cp0_store a2,a3,a4,a5,a6 +#define xchal_cp0_load_a2 xchal_cp0_load a2,a3,a4,a5,a6 +#define xchal_cp1_store_a2 xchal_cp1_store a2,a3,a4,a5,a6 +#define xchal_cp1_load_a2 xchal_cp1_load a2,a3,a4,a5,a6 +#define xchal_cp2_store_a2 xchal_cp2_store a2,a3,a4,a5,a6 +#define xchal_cp2_load_a2 xchal_cp2_load a2,a3,a4,a5,a6 +#define xchal_cp3_store_a2 xchal_cp3_store a2,a3,a4,a5,a6 +#define xchal_cp3_load_a2 xchal_cp3_load a2,a3,a4,a5,a6 +#define xchal_cp4_store_a2 xchal_cp4_store a2,a3,a4,a5,a6 +#define xchal_cp4_load_a2 xchal_cp4_load a2,a3,a4,a5,a6 +#define xchal_cp5_store_a2 xchal_cp5_store a2,a3,a4,a5,a6 +#define xchal_cp5_load_a2 xchal_cp5_load a2,a3,a4,a5,a6 +#define xchal_cp6_store_a2 xchal_cp6_store a2,a3,a4,a5,a6 +#define xchal_cp6_load_a2 xchal_cp6_load a2,a3,a4,a5,a6 +#define xchal_cp7_store_a2 xchal_cp7_store a2,a3,a4,a5,a6 +#define xchal_cp7_load_a2 xchal_cp7_load a2,a3,a4,a5,a6 + +/* Empty placeholder macros for undefined coprocessors: */ +#if (XCHAL_CP_MASK & ~XCHAL_CP_PORT_MASK) == 0 +# if XCHAL_CP0_SA_SIZE == 0 + .macro xchal_cp0_store p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp0_load p a b c d continue=0 ofs=-1 select=-1 ; .endm +# endif +# if XCHAL_CP1_SA_SIZE == 0 + .macro xchal_cp1_store p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp1_load p a b c d continue=0 ofs=-1 select=-1 ; .endm +# endif +# if XCHAL_CP2_SA_SIZE == 0 + .macro xchal_cp2_store p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp2_load p a b c d continue=0 ofs=-1 select=-1 ; .endm +# endif +# if XCHAL_CP3_SA_SIZE == 0 + .macro xchal_cp3_store p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp3_load p a b c d continue=0 ofs=-1 select=-1 ; .endm +# endif +# if XCHAL_CP4_SA_SIZE == 0 + .macro xchal_cp4_store p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp4_load p a b c d continue=0 ofs=-1 select=-1 ; .endm +# endif +# if XCHAL_CP5_SA_SIZE == 0 + .macro xchal_cp5_store p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp5_load p a b c d continue=0 ofs=-1 select=-1 ; .endm +# endif +# if XCHAL_CP6_SA_SIZE == 0 + .macro xchal_cp6_store p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp6_load p a b c d continue=0 ofs=-1 select=-1 ; .endm +# endif +# if XCHAL_CP7_SA_SIZE == 0 + .macro xchal_cp7_store p a b c d continue=0 ofs=-1 select=-1 ; .endm + .macro xchal_cp7_load p a b c d continue=0 ofs=-1 select=-1 ; .endm +# endif +#endif + + /******************** + * Macros to create functions that save and restore the state of *any* TIE + * coprocessor (by dynamic index). + */ + + /* + * Macro that expands to the body of a function + * that stores the selected coprocessor's state (registers etc). + * Entry: a2 = ptr to save area in which to save cp state + * a3 = coprocessor number + * Exit: any register a2-a15 (?) may have been clobbered. + */ + .macro xchal_cpi_store_funcbody +#if (XCHAL_CP_MASK & ~XCHAL_CP_PORT_MASK) +# if XCHAL_CP0_SA_SIZE + bnez a3, 99f + xchal_cp0_store_a2 + j 90f +99: +# endif +# if XCHAL_CP1_SA_SIZE + bnei a3, 1, 99f + xchal_cp1_store_a2 + j 90f +99: +# endif +# if XCHAL_CP2_SA_SIZE + bnei a3, 2, 99f + xchal_cp2_store_a2 + j 90f +99: +# endif +# if XCHAL_CP3_SA_SIZE + bnei a3, 3, 99f + xchal_cp3_store_a2 + j 90f +99: +# endif +# if XCHAL_CP4_SA_SIZE + bnei a3, 4, 99f + xchal_cp4_store_a2 + j 90f +99: +# endif +# if XCHAL_CP5_SA_SIZE + bnei a3, 5, 99f + xchal_cp5_store_a2 + j 90f +99: +# endif +# if XCHAL_CP6_SA_SIZE + bnei a3, 6, 99f + xchal_cp6_store_a2 + j 90f +99: +# endif +# if XCHAL_CP7_SA_SIZE + bnei a3, 7, 99f + xchal_cp7_store_a2 + j 90f +99: +# endif +90: +#endif + .endm + + /* + * Macro that expands to the body of a function + * that loads the selected coprocessor's state (registers etc). + * Entry: a2 = ptr to save area from which to restore cp state + * a3 = coprocessor number + * Exit: any register a2-a15 (?) may have been clobbered. + */ + .macro xchal_cpi_load_funcbody +#if (XCHAL_CP_MASK & ~XCHAL_CP_PORT_MASK) +# if XCHAL_CP0_SA_SIZE + bnez a3, 99f + xchal_cp0_load_a2 + j 90f +99: +# endif +# if XCHAL_CP1_SA_SIZE + bnei a3, 1, 99f + xchal_cp1_load_a2 + j 90f +99: +# endif +# if XCHAL_CP2_SA_SIZE + bnei a3, 2, 99f + xchal_cp2_load_a2 + j 90f +99: +# endif +# if XCHAL_CP3_SA_SIZE + bnei a3, 3, 99f + xchal_cp3_load_a2 + j 90f +99: +# endif +# if XCHAL_CP4_SA_SIZE + bnei a3, 4, 99f + xchal_cp4_load_a2 + j 90f +99: +# endif +# if XCHAL_CP5_SA_SIZE + bnei a3, 5, 99f + xchal_cp5_load_a2 + j 90f +99: +# endif +# if XCHAL_CP6_SA_SIZE + bnei a3, 6, 99f + xchal_cp6_load_a2 + j 90f +99: +# endif +# if XCHAL_CP7_SA_SIZE + bnei a3, 7, 99f + xchal_cp7_load_a2 + j 90f +99: +# endif +90: +#endif + .endm + +#endif /*_ASMLANGUAGE or __ASSEMBLER__*/ + + +/* Other default macros for undefined coprocessors: */ +#ifndef XCHAL_CP0_NAME +# define XCHAL_CP0_NAME 0 +# define XCHAL_CP0_SA_CONTENTS_LIBDB_NUM 0 +# define XCHAL_CP0_SA_CONTENTS_LIBDB /* empty */ +#endif +#ifndef XCHAL_CP1_NAME +# define XCHAL_CP1_NAME 0 +# define XCHAL_CP1_SA_CONTENTS_LIBDB_NUM 0 +# define XCHAL_CP1_SA_CONTENTS_LIBDB /* empty */ +#endif +#ifndef XCHAL_CP2_NAME +# define XCHAL_CP2_NAME 0 +# define XCHAL_CP2_SA_CONTENTS_LIBDB_NUM 0 +# define XCHAL_CP2_SA_CONTENTS_LIBDB /* empty */ +#endif +#ifndef XCHAL_CP3_NAME +# define XCHAL_CP3_NAME 0 +# define XCHAL_CP3_SA_CONTENTS_LIBDB_NUM 0 +# define XCHAL_CP3_SA_CONTENTS_LIBDB /* empty */ +#endif +#ifndef XCHAL_CP4_NAME +# define XCHAL_CP4_NAME 0 +# define XCHAL_CP4_SA_CONTENTS_LIBDB_NUM 0 +# define XCHAL_CP4_SA_CONTENTS_LIBDB /* empty */ +#endif +#ifndef XCHAL_CP5_NAME +# define XCHAL_CP5_NAME 0 +# define XCHAL_CP5_SA_CONTENTS_LIBDB_NUM 0 +# define XCHAL_CP5_SA_CONTENTS_LIBDB /* empty */ +#endif +#ifndef XCHAL_CP6_NAME +# define XCHAL_CP6_NAME 0 +# define XCHAL_CP6_SA_CONTENTS_LIBDB_NUM 0 +# define XCHAL_CP6_SA_CONTENTS_LIBDB /* empty */ +#endif +#ifndef XCHAL_CP7_NAME +# define XCHAL_CP7_NAME 0 +# define XCHAL_CP7_SA_CONTENTS_LIBDB_NUM 0 +# define XCHAL_CP7_SA_CONTENTS_LIBDB /* empty */ +#endif + +#if XCHAL_CP_MASK == 0 +/* Filler info for unassigned coprocessors, to simplify arrays etc: */ +#define XCHAL_CP0_SA_SIZE 0 +#define XCHAL_CP0_SA_ALIGN 1 +#define XCHAL_CP1_SA_SIZE 0 +#define XCHAL_CP1_SA_ALIGN 1 +#define XCHAL_CP2_SA_SIZE 0 +#define XCHAL_CP2_SA_ALIGN 1 +#define XCHAL_CP3_SA_SIZE 0 +#define XCHAL_CP3_SA_ALIGN 1 +#define XCHAL_CP4_SA_SIZE 0 +#define XCHAL_CP4_SA_ALIGN 1 +#define XCHAL_CP5_SA_SIZE 0 +#define XCHAL_CP5_SA_ALIGN 1 +#define XCHAL_CP6_SA_SIZE 0 +#define XCHAL_CP6_SA_ALIGN 1 +#define XCHAL_CP7_SA_SIZE 0 +#define XCHAL_CP7_SA_ALIGN 1 +#endif + + +/* Indexing macros: */ +#define _XCHAL_CP_SA_SIZE(n) XCHAL_CP ## n ## _SA_SIZE +#define XCHAL_CP_SA_SIZE(n) _XCHAL_CP_SA_SIZE(n) /* n = 0 .. 7 */ +#define _XCHAL_CP_SA_ALIGN(n) XCHAL_CP ## n ## _SA_ALIGN +#define XCHAL_CP_SA_ALIGN(n) _XCHAL_CP_SA_ALIGN(n) /* n = 0 .. 7 */ + +#define XCHAL_CPEXTRA_SA_SIZE_TOR2 XCHAL_CPEXTRA_SA_SIZE /* Tor2Beta only - do not use */ + +/* Link-time HAL global variables that report coprocessor numbers by name + (names are case-preserved from the original TIE): */ +#if !defined(_ASMLANGUAGE) && !defined(_NOCLANGUAGE) && !defined(__ASSEMBLER__) +# define _XCJOIN(a,b) a ## b +# define XCJOIN(a,b) _XCJOIN(a,b) +# ifdef XCHAL_CP0_NAME +extern const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP0_IDENT); +extern const unsigned int XCJOIN(Xthal_cp_mask_,XCHAL_CP0_IDENT); +# endif +# ifdef XCHAL_CP1_NAME +extern const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP1_IDENT); +extern const unsigned int XCJOIN(Xthal_cp_mask_,XCHAL_CP1_IDENT); +# endif +# ifdef XCHAL_CP2_NAME +extern const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP2_IDENT); +extern const unsigned int XCJOIN(Xthal_cp_mask_,XCHAL_CP2_IDENT); +# endif +# ifdef XCHAL_CP3_NAME +extern const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP3_IDENT); +extern const unsigned int XCJOIN(Xthal_cp_mask_,XCHAL_CP3_IDENT); +# endif +# ifdef XCHAL_CP4_NAME +extern const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP4_IDENT); +extern const unsigned int XCJOIN(Xthal_cp_mask_,XCHAL_CP4_IDENT); +# endif +# ifdef XCHAL_CP5_NAME +extern const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP5_IDENT); +extern const unsigned int XCJOIN(Xthal_cp_mask_,XCHAL_CP5_IDENT); +# endif +# ifdef XCHAL_CP6_NAME +extern const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP6_IDENT); +extern const unsigned int XCJOIN(Xthal_cp_mask_,XCHAL_CP6_IDENT); +# endif +# ifdef XCHAL_CP7_NAME +extern const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP7_IDENT); +extern const unsigned int XCJOIN(Xthal_cp_mask_,XCHAL_CP7_IDENT); +# endif +#endif + + + + +/*---------------------------------------------------------------------- + DERIVED + ----------------------------------------------------------------------*/ + +#if XCHAL_HAVE_BE +#define XCHAL_INST_ILLN 0xD60F /* 2-byte illegal instruction, msb-first */ +#define XCHAL_INST_ILLN_BYTE0 0xD6 /* 2-byte illegal instruction, 1st byte */ +#define XCHAL_INST_ILLN_BYTE1 0x0F /* 2-byte illegal instruction, 2nd byte */ +#else +#define XCHAL_INST_ILLN 0xF06D /* 2-byte illegal instruction, lsb-first */ +#define XCHAL_INST_ILLN_BYTE0 0x6D /* 2-byte illegal instruction, 1st byte */ +#define XCHAL_INST_ILLN_BYTE1 0xF0 /* 2-byte illegal instruction, 2nd byte */ +#endif +/* Belongs in xtensa/hal.h: */ +#define XTHAL_INST_ILL 0x000000 /* 3-byte illegal instruction */ + + +/* + * Because information as to exactly which hardware version is targeted + * by a given software build is not always available, compile-time HAL + * Hardware-Release "_AT" macros are fuzzy (return 0, 1, or XCHAL_MAYBE): + * (Here "RELEASE" is now a misnomer; these are product *versions*, not the releases + * under which they are released. In the T10##.# era there was no distinction.) + */ +#if XCHAL_HW_CONFIGID_RELIABLE +# define XCHAL_HW_RELEASE_AT_OR_BELOW(major,minor) (XTHAL_REL_LE( XCHAL_HW_VERSION_MAJOR,XCHAL_HW_VERSION_MINOR, major,minor ) ? 1 : 0) +# define XCHAL_HW_RELEASE_AT_OR_ABOVE(major,minor) (XTHAL_REL_GE( XCHAL_HW_VERSION_MAJOR,XCHAL_HW_VERSION_MINOR, major,minor ) ? 1 : 0) +# define XCHAL_HW_RELEASE_AT(major,minor) (XTHAL_REL_EQ( XCHAL_HW_VERSION_MAJOR,XCHAL_HW_VERSION_MINOR, major,minor ) ? 1 : 0) +# define XCHAL_HW_RELEASE_MAJOR_AT(major) ((XCHAL_HW_VERSION_MAJOR == (major)) ? 1 : 0) +#else +# define XCHAL_HW_RELEASE_AT_OR_BELOW(major,minor) ( ((major) < 1040 && XCHAL_HAVE_XEA2) ? 0 \ + : ((major) > 1050 && XCHAL_HAVE_XEA1) ? 1 \ + : XTHAL_MAYBE ) +# define XCHAL_HW_RELEASE_AT_OR_ABOVE(major,minor) ( ((major) >= 2000 && XCHAL_HAVE_XEA1) ? 0 \ + : (XTHAL_REL_LE(major,minor, 1040,0) && XCHAL_HAVE_XEA2) ? 1 \ + : XTHAL_MAYBE ) +# define XCHAL_HW_RELEASE_AT(major,minor) ( (((major) < 1040 && XCHAL_HAVE_XEA2) || \ + ((major) >= 2000 && XCHAL_HAVE_XEA1)) ? 0 : XTHAL_MAYBE) +# define XCHAL_HW_RELEASE_MAJOR_AT(major) XCHAL_HW_RELEASE_AT(major,0) +#endif + +/* + * Specific errata: + */ + +/* + * Erratum T1020.H13, T1030.H7, T1040.H10, T1050.H4 (fixed in T1040.3 and T1050.1; + * relevant only in XEA1, kernel-vector mode, level-one interrupts and overflows enabled): + */ +#define XCHAL_MAYHAVE_ERRATUM_XEA1KWIN (XCHAL_HAVE_XEA1 && \ + (XCHAL_HW_RELEASE_AT_OR_BELOW(1040,2) != 0 \ + || XCHAL_HW_RELEASE_AT(1050,0))) + + + +#endif /*XTENSA_CONFIG_CORE_H*/ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/defs.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/defs.h new file mode 100644 index 0000000..d81c242 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/defs.h @@ -0,0 +1,37 @@ +/* Definitions for Xtensa instructions, types, and protos. */ + +/* Customer ID=7011; Build=0x2b6f6; Copyright (c) 2003-2004 Tensilica Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* NOTE: This file exists only for backward compatibility with T1050 + and earlier Xtensa releases. It includes only a subset of the + available header files. */ + +#ifndef _XTENSA_BASE_HEADER +#define _XTENSA_BASE_HEADER + +#ifdef __XTENSA__ + +#include +#include + +#endif /* __XTENSA__ */ +#endif /* !_XTENSA_BASE_HEADER */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/specreg.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/specreg.h new file mode 100644 index 0000000..e49ecc5 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/specreg.h @@ -0,0 +1,80 @@ +/* + * Xtensa Special Register symbolic names + */ + +/* $Id: //depot/rel/Boreal/Xtensa/SWConfig/hal/specreg.h.tpp#2 $ */ + +/* Customer ID=7011; Build=0x2b6f6; Copyright (c) 1998-2002 Tensilica Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef XTENSA_SPECREG_H +#define XTENSA_SPECREG_H + +/* Include these special register bitfield definitions, for historical reasons: */ +#include + + +/* Special registers: */ +#define SAR 3 +#define LITBASE 5 +#define IBREAKENABLE 96 +#define DDR 104 +#define IBREAKA_0 128 +#define DBREAKA_0 144 +#define DBREAKC_0 160 +#define EPC_1 177 +#define EPC_2 178 +#define EPC_3 179 +#define DEPC 192 +#define EPS_2 194 +#define EPS_3 195 +#define EXCSAVE_1 209 +#define EXCSAVE_2 210 +#define EXCSAVE_3 211 +#define INTERRUPT 226 +#define INTENABLE 228 +#define PS 230 +#define VECBASE 231 +#define EXCCAUSE 232 +#define DEBUGCAUSE 233 +#define CCOUNT 234 +#define PRID 235 +#define ICOUNT 236 +#define ICOUNTLEVEL 237 +#define EXCVADDR 238 +#define CCOMPARE_0 240 + +/* Special cases (bases of special register series): */ +#define IBREAKA 128 +#define DBREAKA 144 +#define DBREAKC 160 +#define EPC 176 +#define EPS 192 +#define EXCSAVE 208 +#define CCOMPARE 240 + +/* Special names for read-only and write-only interrupt registers: */ +#define INTREAD 226 +#define INTSET 226 +#define INTCLEAR 227 + +#endif /* XTENSA_SPECREG_H */ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/system.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/system.h new file mode 100644 index 0000000..9d16ce5 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/system.h @@ -0,0 +1,252 @@ +/* + * xtensa/config/system.h -- HAL definitions that are dependent on SYSTEM configuration + * + * NOTE: The location and contents of this file are highly subject to change. + * + * Source for configuration-independent binaries (which link in a + * configuration-specific HAL library) must NEVER include this file. + * The HAL itself has historically included this file in some instances, + * but this is not appropriate either, because the HAL is meant to be + * core-specific but system independent. + */ + +/* Customer ID=7011; Build=0x2b6f6; Copyright (c) 2000-2007 Tensilica Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + + +#ifndef XTENSA_CONFIG_SYSTEM_H +#define XTENSA_CONFIG_SYSTEM_H + +/*#include */ + + + +/*---------------------------------------------------------------------- + CONFIGURED SOFTWARE OPTIONS + ----------------------------------------------------------------------*/ + +#define XSHAL_USE_ABSOLUTE_LITERALS 0 /* (sw-only option, whether software uses absolute literals) */ + +#define XSHAL_ABI XTHAL_ABI_CALL0 /* (sw-only option, selected ABI) */ +/* The above maps to one of the following constants: */ +#define XTHAL_ABI_WINDOWED 0 +#define XTHAL_ABI_CALL0 1 +/* Alternatives: */ +/*#define XSHAL_WINDOWED_ABI 0*/ /* set if windowed ABI selected */ +/*#define XSHAL_CALL0_ABI 1*/ /* set if call0 ABI selected */ + +#define XSHAL_CLIB XTHAL_CLIB_NEWLIB /* (sw-only option, selected C library) */ +/* The above maps to one of the following constants: */ +#define XTHAL_CLIB_NEWLIB 0 +#define XTHAL_CLIB_UCLIBC 1 +/* Alternatives: */ +/*#define XSHAL_NEWLIB 1*/ /* set if newlib C library selected */ +/*#define XSHAL_UCLIBC 0*/ /* set if uCLibC C library selected */ + +#define XSHAL_USE_FLOATING_POINT 1 + +/*---------------------------------------------------------------------- + DEVICE ADDRESSES + ----------------------------------------------------------------------*/ + +/* + * Strange place to find these, but the configuration GUI + * allows moving these around to account for various core + * configurations. Specific boards (and their BSP software) + * will have specific meanings for these components. + */ + +/* I/O Block areas: */ +#define XSHAL_IOBLOCK_CACHED_VADDR 0x70000000 +#define XSHAL_IOBLOCK_CACHED_PADDR 0x70000000 +#define XSHAL_IOBLOCK_CACHED_SIZE 0x0E000000 + +#define XSHAL_IOBLOCK_BYPASS_VADDR 0x90000000 +#define XSHAL_IOBLOCK_BYPASS_PADDR 0x90000000 +#define XSHAL_IOBLOCK_BYPASS_SIZE 0x0E000000 + +/* System ROM: */ +#define XSHAL_ROM_VADDR 0x50000000 +#define XSHAL_ROM_PADDR 0x50000000 +#define XSHAL_ROM_SIZE 0x01000000 +/* Largest available area (free of vectors): */ +#define XSHAL_ROM_AVAIL_VADDR 0x50000300 +#define XSHAL_ROM_AVAIL_VSIZE 0x00FFFD00 + +/* System RAM: */ +#define XSHAL_RAM_VADDR 0x60000000 +#define XSHAL_RAM_PADDR 0x60000000 +#define XSHAL_RAM_VSIZE 0x04000000 +#define XSHAL_RAM_PSIZE 0x04000000 +#define XSHAL_RAM_SIZE XSHAL_RAM_PSIZE +/* Largest available area (free of vectors): */ +#define XSHAL_RAM_AVAIL_VADDR 0x60000000 +#define XSHAL_RAM_AVAIL_VSIZE 0x04000000 + +/* + * Shadow system RAM (same device as system RAM, at different address). + * (Emulation boards need this for the SONIC Ethernet driver + * when data caches are configured for writeback mode.) + * NOTE: on full MMU configs, this points to the BYPASS virtual address + * of system RAM, ie. is the same as XSHAL_RAM_* except that virtual + * addresses are viewed through the BYPASS static map rather than + * the CACHED static map. + */ +#define XSHAL_RAM_BYPASS_VADDR 0xA0000000 +#define XSHAL_RAM_BYPASS_PADDR 0xA0000000 +#define XSHAL_RAM_BYPASS_PSIZE 0x04000000 + +/* Alternate system RAM (different device than system RAM): */ +/*#define XSHAL_ALTRAM_[VP]ADDR ...not configured...*/ +/*#define XSHAL_ALTRAM_SIZE ...not configured...*/ + +/* Some available location in which to place devices in a simulation (eg. XTMP): */ +#define XSHAL_SIMIO_CACHED_VADDR 0xC0000000 +#define XSHAL_SIMIO_BYPASS_VADDR 0xC0000000 +#define XSHAL_SIMIO_PADDR 0xC0000000 +#define XSHAL_SIMIO_SIZE 0x20000000 + + +/*---------------------------------------------------------------------- + * DEVICE-ADDRESS DEPENDENT... + * + * Values written to CACHEATTR special register (or its equivalent) + * to enable and disable caches in various modes. + *----------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------- + BACKWARD COMPATIBILITY ... + ----------------------------------------------------------------------*/ + +/* + * NOTE: the following two macros are DEPRECATED. Use the latter + * board-specific macros instead, which are specially tuned for the + * particular target environments' memory maps. + */ +#define XSHAL_CACHEATTR_BYPASS XSHAL_XT2000_CACHEATTR_BYPASS /* disable caches in bypass mode */ +#define XSHAL_CACHEATTR_DEFAULT XSHAL_XT2000_CACHEATTR_DEFAULT /* default setting to enable caches (no writeback!) */ + +/*---------------------------------------------------------------------- + GENERIC + ----------------------------------------------------------------------*/ + +/* For the following, a 512MB region is used if it contains a system (PIF) RAM, + * system (PIF) ROM, local memory, or XLMI. */ + +/* These set any unused 512MB region to cache-BYPASS attribute: */ +#define XSHAL_ALLVALID_CACHEATTR_WRITEBACK 0x22221112 /* enable caches in write-back mode */ +#define XSHAL_ALLVALID_CACHEATTR_WRITEALLOC 0x22221112 /* enable caches in write-allocate mode */ +#define XSHAL_ALLVALID_CACHEATTR_WRITETHRU 0x22221112 /* enable caches in write-through mode */ +#define XSHAL_ALLVALID_CACHEATTR_BYPASS 0x22222222 /* disable caches in bypass mode */ +#define XSHAL_ALLVALID_CACHEATTR_DEFAULT XSHAL_ALLVALID_CACHEATTR_WRITEBACK /* default setting to enable caches */ + +/* These set any unused 512MB region to ILLEGAL attribute: */ +#define XSHAL_STRICT_CACHEATTR_WRITEBACK 0xFFFF111F /* enable caches in write-back mode */ +#define XSHAL_STRICT_CACHEATTR_WRITEALLOC 0xFFFF111F /* enable caches in write-allocate mode */ +#define XSHAL_STRICT_CACHEATTR_WRITETHRU 0xFFFF111F /* enable caches in write-through mode */ +#define XSHAL_STRICT_CACHEATTR_BYPASS 0xFFFF222F /* disable caches in bypass mode */ +#define XSHAL_STRICT_CACHEATTR_DEFAULT XSHAL_STRICT_CACHEATTR_WRITEBACK /* default setting to enable caches */ + +/* These set the first 512MB, if unused, to ILLEGAL attribute to help catch + * NULL-pointer dereference bugs; all other unused 512MB regions are set + * to cache-BYPASS attribute: */ +#define XSHAL_TRAPNULL_CACHEATTR_WRITEBACK 0x2222111F /* enable caches in write-back mode */ +#define XSHAL_TRAPNULL_CACHEATTR_WRITEALLOC 0x2222111F /* enable caches in write-allocate mode */ +#define XSHAL_TRAPNULL_CACHEATTR_WRITETHRU 0x2222111F /* enable caches in write-through mode */ +#define XSHAL_TRAPNULL_CACHEATTR_BYPASS 0x2222222F /* disable caches in bypass mode */ +#define XSHAL_TRAPNULL_CACHEATTR_DEFAULT XSHAL_TRAPNULL_CACHEATTR_WRITEBACK /* default setting to enable caches */ + +/*---------------------------------------------------------------------- + ISS (Instruction Set Simulator) SPECIFIC ... + ----------------------------------------------------------------------*/ + +/* For now, ISS defaults to the TRAPNULL settings: */ +#define XSHAL_ISS_CACHEATTR_WRITEBACK XSHAL_TRAPNULL_CACHEATTR_WRITEBACK +#define XSHAL_ISS_CACHEATTR_WRITEALLOC XSHAL_TRAPNULL_CACHEATTR_WRITEALLOC +#define XSHAL_ISS_CACHEATTR_WRITETHRU XSHAL_TRAPNULL_CACHEATTR_WRITETHRU +#define XSHAL_ISS_CACHEATTR_BYPASS XSHAL_TRAPNULL_CACHEATTR_BYPASS +#define XSHAL_ISS_CACHEATTR_DEFAULT XSHAL_TRAPNULL_CACHEATTR_WRITEBACK + +#define XSHAL_ISS_PIPE_REGIONS 0 +#define XSHAL_ISS_SDRAM_REGIONS 0 + + +/*---------------------------------------------------------------------- + XT2000 BOARD SPECIFIC ... + ----------------------------------------------------------------------*/ + +/* For the following, a 512MB region is used if it contains any system RAM, + * system ROM, local memory, XLMI, or other XT2000 board device or memory. + * Regions containing devices are forced to cache-BYPASS mode regardless + * of whether the macro is _WRITEBACK vs. _BYPASS etc. */ + +/* These set any 512MB region unused on the XT2000 to ILLEGAL attribute: */ +#define XSHAL_XT2000_CACHEATTR_WRITEBACK 0xFF22111F /* enable caches in write-back mode */ +#define XSHAL_XT2000_CACHEATTR_WRITEALLOC 0xFF22111F /* enable caches in write-allocate mode */ +#define XSHAL_XT2000_CACHEATTR_WRITETHRU 0xFF22111F /* enable caches in write-through mode */ +#define XSHAL_XT2000_CACHEATTR_BYPASS 0xFF22222F /* disable caches in bypass mode */ +#define XSHAL_XT2000_CACHEATTR_DEFAULT XSHAL_XT2000_CACHEATTR_WRITEBACK /* default setting to enable caches */ + +#define XSHAL_XT2000_PIPE_REGIONS 0x00000000 /* BusInt pipeline regions */ +#define XSHAL_XT2000_SDRAM_REGIONS 0x00000440 /* BusInt SDRAM regions */ + + +/*---------------------------------------------------------------------- + VECTOR INFO AND SIZES + ----------------------------------------------------------------------*/ + +#define XSHAL_VECTORS_PACKED 0 +#define XSHAL_STATIC_VECTOR_SELECT 0 +#define XSHAL_RESET_VECTOR_VADDR 0x50000000 +#define XSHAL_RESET_VECTOR_PADDR 0x50000000 + +/* + * Sizes allocated to vectors by the system (memory map) configuration. + * These sizes are constrained by core configuration (eg. one vector's + * code cannot overflow into another vector) but are dependent on the + * system or board (or LSP) memory map configuration. + * + * Whether or not each vector happens to be in a system ROM is also + * a system configuration matter, sometimes useful, included here also: + */ +#define XSHAL_RESET_VECTOR_SIZE 0x00000300 +#define XSHAL_RESET_VECTOR_ISROM 1 +#define XSHAL_USER_VECTOR_SIZE 0x0000001C +#define XSHAL_USER_VECTOR_ISROM 0 +#define XSHAL_PROGRAMEXC_VECTOR_SIZE XSHAL_USER_VECTOR_SIZE /* for backward compatibility */ +#define XSHAL_USEREXC_VECTOR_SIZE XSHAL_USER_VECTOR_SIZE /* for backward compatibility */ +#define XSHAL_KERNEL_VECTOR_SIZE 0x0000001C +#define XSHAL_KERNEL_VECTOR_ISROM 0 +#define XSHAL_STACKEDEXC_VECTOR_SIZE XSHAL_KERNEL_VECTOR_SIZE /* for backward compatibility */ +#define XSHAL_KERNELEXC_VECTOR_SIZE XSHAL_KERNEL_VECTOR_SIZE /* for backward compatibility */ +#define XSHAL_DOUBLEEXC_VECTOR_SIZE 0x00000010 +#define XSHAL_DOUBLEEXC_VECTOR_ISROM 0 +#define XSHAL_INTLEVEL2_VECTOR_SIZE 0x0000000C +#define XSHAL_INTLEVEL2_VECTOR_ISROM 0 +#define XSHAL_DEBUG_VECTOR_SIZE XSHAL_INTLEVEL2_VECTOR_SIZE +#define XSHAL_DEBUG_VECTOR_ISROM XSHAL_INTLEVEL2_VECTOR_ISROM +#define XSHAL_NMI_VECTOR_SIZE 0x0000000C +#define XSHAL_NMI_VECTOR_ISROM 0 +#define XSHAL_INTLEVEL3_VECTOR_SIZE XSHAL_NMI_VECTOR_SIZE + + +#endif /*XTENSA_CONFIG_SYSTEM_H*/ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/tie-asm.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/tie-asm.h new file mode 100644 index 0000000..854aa17 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/tie-asm.h @@ -0,0 +1,77 @@ +/* + * tie-asm.h -- compile-time HAL assembler definitions dependent on CORE & TIE + * + * NOTE: This header file is not meant to be included directly. + */ + +/* This header file contains assembly-language definitions (assembly + macros, etc.) for this specific Xtensa processor's TIE extensions + and options. It is customized to this Xtensa processor configuration. + + Customer ID=7011; Build=0x2b6f6; Copyright (c) 1999-2010 Tensilica Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _XTENSA_CORE_TIE_ASM_H +#define _XTENSA_CORE_TIE_ASM_H + +/* Selection parameter values for save-area save/restore macros: */ +/* Option vs. TIE: */ +#define XTHAL_SAS_TIE 0x0001 /* custom extension or coprocessor */ +#define XTHAL_SAS_OPT 0x0002 /* optional (and not a coprocessor) */ +/* Whether used automatically by compiler: */ +#define XTHAL_SAS_NOCC 0x0004 /* not used by compiler w/o special opts/code */ +#define XTHAL_SAS_CC 0x0008 /* used by compiler without special opts/code */ +/* ABI handling across function calls: */ +#define XTHAL_SAS_CALR 0x0010 /* caller-saved */ +#define XTHAL_SAS_CALE 0x0020 /* callee-saved */ +#define XTHAL_SAS_GLOB 0x0040 /* global across function calls (in thread) */ +/* Misc */ +#define XTHAL_SAS_ALL 0xFFFF /* include all default NCP contents */ + + + +/* Macro to save all non-coprocessor (extra) custom TIE and optional state + * (not including zero-overhead loop registers). + * Save area ptr (clobbered): ptr (1 byte aligned) + * Scratch regs (clobbered): at1..at4 (only first XCHAL_NCP_NUM_ATMPS needed) + */ + .macro xchal_ncp_store ptr at1 at2 at3 at4 continue=0 ofs=-1 select=XTHAL_SAS_ALL + xchal_sa_start \continue, \ofs + .endm // xchal_ncp_store + +/* Macro to save all non-coprocessor (extra) custom TIE and optional state + * (not including zero-overhead loop registers). + * Save area ptr (clobbered): ptr (1 byte aligned) + * Scratch regs (clobbered): at1..at4 (only first XCHAL_NCP_NUM_ATMPS needed) + */ + .macro xchal_ncp_load ptr at1 at2 at3 at4 continue=0 ofs=-1 select=XTHAL_SAS_ALL + xchal_sa_start \continue, \ofs + .endm // xchal_ncp_load + + + +#define XCHAL_NCP_NUM_ATMPS 0 + + +#define XCHAL_SA_NUM_ATMPS 0 + +#endif /*_XTENSA_CORE_TIE_ASM_H*/ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/tie.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/tie.h new file mode 100644 index 0000000..e2a30f1 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/config/tie.h @@ -0,0 +1,119 @@ +/* + * tie.h -- compile-time HAL definitions dependent on CORE & TIE configuration + * + * NOTE: This header file is not meant to be included directly. + */ + +/* This header file describes this specific Xtensa processor's TIE extensions + that extend basic Xtensa core functionality. It is customized to this + Xtensa processor configuration. + + Customer ID=7011; Build=0x2b6f6; Copyright (c) 1999-2010 Tensilica Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _XTENSA_CORE_TIE_H +#define _XTENSA_CORE_TIE_H + +#define XCHAL_CP_NUM 0 /* number of coprocessors */ +#define XCHAL_CP_MAX 0 /* max CP ID + 1 (0 if none) */ +#define XCHAL_CP_MASK 0x00 /* bitmask of all CPs by ID */ +#define XCHAL_CP_PORT_MASK 0x00 /* bitmask of only port CPs */ + +/* Save area for non-coprocessor optional and custom (TIE) state: */ +#define XCHAL_NCP_SA_SIZE 0 +#define XCHAL_NCP_SA_ALIGN 1 + +/* Total save area for optional and custom state (NCP + CPn): */ +#define XCHAL_TOTAL_SA_SIZE 0 /* with 16-byte align padding */ +#define XCHAL_TOTAL_SA_ALIGN 1 /* actual minimum alignment */ + +/* + * Detailed contents of save areas. + * NOTE: caller must define the XCHAL_SA_REG macro (not defined here) + * before expanding the XCHAL_xxx_SA_LIST() macros. + * + * XCHAL_SA_REG(s,ccused,abikind,kind,opt,name,galign,align,asize, + * dbnum,base,regnum,bitsz,gapsz,reset,x...) + * + * s = passed from XCHAL_*_LIST(s), eg. to select how to expand + * ccused = set if used by compiler without special options or code + * abikind = 0 (caller-saved), 1 (callee-saved), or 2 (thread-global) + * kind = 0 (special reg), 1 (TIE user reg), or 2 (TIE regfile reg) + * opt = 0 (custom TIE extension or coprocessor), or 1 (optional reg) + * name = lowercase reg name (no quotes) + * galign = group byte alignment (power of 2) (galign >= align) + * align = register byte alignment (power of 2) + * asize = allocated size in bytes (asize*8 == bitsz + gapsz + padsz) + * (not including any pad bytes required to galign this or next reg) + * dbnum = unique target number f/debug (see ) + * base = reg shortname w/o index (or sr=special, ur=TIE user reg) + * regnum = reg index in regfile, or special/TIE-user reg number + * bitsz = number of significant bits (regfile width, or ur/sr mask bits) + * gapsz = intervening bits, if bitsz bits not stored contiguously + * (padsz = pad bits at end [TIE regfile] or at msbits [ur,sr] of asize) + * reset = register reset value (or 0 if undefined at reset) + * x = reserved for future use (0 until then) + * + * To filter out certain registers, e.g. to expand only the non-global + * registers used by the compiler, you can do something like this: + * + * #define XCHAL_SA_REG(s,ccused,p...) SELCC##ccused(p) + * #define SELCC0(p...) + * #define SELCC1(abikind,p...) SELAK##abikind(p) + * #define SELAK0(p...) REG(p) + * #define SELAK1(p...) REG(p) + * #define SELAK2(p...) + * #define REG(kind,tie,name,galn,aln,asz,csz,dbnum,base,rnum,bsz,rst,x...) \ + * ...what you want to expand... + */ + +#define XCHAL_NCP_SA_NUM 0 +#define XCHAL_NCP_SA_LIST(s) /* empty */ + +#define XCHAL_CP0_SA_NUM 0 +#define XCHAL_CP0_SA_LIST(s) /* empty */ + +#define XCHAL_CP1_SA_NUM 0 +#define XCHAL_CP1_SA_LIST(s) /* empty */ + +#define XCHAL_CP2_SA_NUM 0 +#define XCHAL_CP2_SA_LIST(s) /* empty */ + +#define XCHAL_CP3_SA_NUM 0 +#define XCHAL_CP3_SA_LIST(s) /* empty */ + +#define XCHAL_CP4_SA_NUM 0 +#define XCHAL_CP4_SA_LIST(s) /* empty */ + +#define XCHAL_CP5_SA_NUM 0 +#define XCHAL_CP5_SA_LIST(s) /* empty */ + +#define XCHAL_CP6_SA_NUM 0 +#define XCHAL_CP6_SA_LIST(s) /* empty */ + +#define XCHAL_CP7_SA_NUM 0 +#define XCHAL_CP7_SA_LIST(s) /* empty */ + +/* Byte length of instruction from its first nibble (op0 field), per FLIX. */ +#define XCHAL_OP0_FORMAT_LENGTHS 3,3,3,3,3,3,3,3,2,2,2,2,2,2,3,3 + +#endif /*_XTENSA_CORE_TIE_H*/ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/coreasm.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/coreasm.h new file mode 100644 index 0000000..591ba01 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/coreasm.h @@ -0,0 +1,914 @@ +/* + * xtensa/coreasm.h -- assembler-specific definitions that depend on CORE configuration + * + * Source for configuration-independent binaries (which link in a + * configuration-specific HAL library) must NEVER include this file. + * It is perfectly normal, however, for the HAL itself to include this file. + * + * This file must NOT include xtensa/config/system.h. Any assembler + * header file that depends on system information should likely go + * in a new systemasm.h (or sysasm.h) header file. + * + * NOTE: macro beqi32 is NOT configuration-dependent, and is placed + * here until we have a proper configuration-independent header file. + */ + +/* $Id: //depot/rel/Boreal/Xtensa/OS/include/xtensa/coreasm.h#2 $ */ + +/* + * Copyright (c) 2000-2007 Tensilica Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef XTENSA_COREASM_H +#define XTENSA_COREASM_H + +/* + * Tell header files this is assembly source, so they can avoid non-assembler + * definitions (eg. C types etc): + */ +#ifndef _ASMLANGUAGE /* conditionalize to avoid cpp warnings (3rd parties might use same macro) */ +#define _ASMLANGUAGE +#endif + +#include +#include + +/* + * Assembly-language specific definitions (assembly macros, etc.). + */ + +/*---------------------------------------------------------------------- + * find_ms_setbit + * + * This macro finds the most significant bit that is set in + * and return its index + in , or - 1 if is zero. + * The index counts starting at zero for the lsbit, so the return + * value ranges from -1 (no bit set) to +31 (msbit set). + * + * Parameters: + * destination address register (any register) + * source address register + * temporary address register (must be different than ) + * constant value added to result (usually 0 or 1) + * On entry: + * = undefined if different than + * = value whose most significant set bit is to be found + * = undefined + * no other registers are used by this macro. + * On exit: + * = + index of msbit set in original , + * = - 1 if original was zero. + * clobbered (if not ) + * clobbered (if not ) + * Example: + * find_ms_setbit a0, a4, a0, 0 -- return in a0 index of msbit set in a4 + */ + + .macro find_ms_setbit ad, as, at, base +#if XCHAL_HAVE_NSA + movi \at, 31+\base + nsau \as, \as // get index of \as, numbered from msbit (32 if absent) + sub \ad, \at, \as // get numbering from lsbit (0..31, -1 if absent) +#else /* XCHAL_HAVE_NSA */ + movi \at, \base // start with result of 0 (point to lsbit of 32) + + beqz \as, 2f // special case for zero argument: return -1 + bltui \as, 0x10000, 1f // is it one of the 16 lsbits? (if so, check lower 16 bits) + addi \at, \at, 16 // no, increment result to upper 16 bits (of 32) + //srli \as, \as, 16 // check upper half (shift right 16 bits) + extui \as, \as, 16, 16 // check upper half (shift right 16 bits) +1: bltui \as, 0x100, 1f // is it one of the 8 lsbits? (if so, check lower 8 bits) + addi \at, \at, 8 // no, increment result to upper 8 bits (of 16) + srli \as, \as, 8 // shift right to check upper 8 bits +1: bltui \as, 0x10, 1f // is it one of the 4 lsbits? (if so, check lower 4 bits) + addi \at, \at, 4 // no, increment result to upper 4 bits (of 8) + srli \as, \as, 4 // shift right 4 bits to check upper half +1: bltui \as, 0x4, 1f // is it one of the 2 lsbits? (if so, check lower 2 bits) + addi \at, \at, 2 // no, increment result to upper 2 bits (of 4) + srli \as, \as, 2 // shift right 2 bits to check upper half +1: bltui \as, 0x2, 1f // is it the lsbit? + addi \at, \at, 2 // no, increment result to upper bit (of 2) +2: addi \at, \at, -1 // (from just above: add 1; from beqz: return -1) + //srli \as, \as, 1 +1: // done! \at contains index of msbit set (or -1 if none set) + .if 0x\ad - 0x\at // destination different than \at ? (works because regs are a0-a15) + mov \ad, \at // then move result to \ad + .endif +#endif /* XCHAL_HAVE_NSA */ + .endm // find_ms_setbit + +/*---------------------------------------------------------------------- + * find_ls_setbit + * + * This macro finds the least significant bit that is set in , + * and return its index in . + * Usage is the same as for the find_ms_setbit macro. + * Example: + * find_ls_setbit a0, a4, a0, 0 -- return in a0 index of lsbit set in a4 + */ + + .macro find_ls_setbit ad, as, at, base + neg \at, \as // keep only the least-significant bit that is set... + and \as, \at, \as // ... in \as + find_ms_setbit \ad, \as, \at, \base + .endm // find_ls_setbit + +/*---------------------------------------------------------------------- + * find_ls_one + * + * Same as find_ls_setbit with base zero. + * Source (as) and destination (ad) registers must be different. + * Provided for backward compatibility. + */ + + .macro find_ls_one ad, as + find_ls_setbit \ad, \as, \ad, 0 + .endm // find_ls_one + +/*---------------------------------------------------------------------- + * floop, floopnez, floopgtz, floopend + * + * These macros are used for fast inner loops that + * work whether or not the Loops options is configured. + * If the Loops option is configured, they simply use + * the zero-overhead LOOP instructions; otherwise + * they use explicit decrement and branch instructions. + * + * They are used in pairs, with floop, floopnez or floopgtz + * at the beginning of the loop, and floopend at the end. + * + * Each pair of loop macro calls must be given the loop count + * address register and a unique label for that loop. + * + * Example: + * + * movi a3, 16 // loop 16 times + * floop a3, myloop1 + * : + * bnez a7, end1 // exit loop if a7 != 0 + * : + * floopend a3, myloop1 + * end1: + * + * Like the LOOP instructions, these macros cannot be + * nested, must include at least one instruction, + * cannot call functions inside the loop, etc. + * The loop can be exited by jumping to the instruction + * following floopend (or elsewhere outside the loop), + * or continued by jumping to a NOP instruction placed + * immediately before floopend. + * + * Unlike LOOP instructions, the register passed to floop* + * cannot be used inside the loop, because it is used as + * the loop counter if the Loops option is not configured. + * And its value is undefined after exiting the loop. + * And because the loop counter register is active inside + * the loop, you can't easily use this construct to loop + * across a register file using ROTW as you might with LOOP + * instructions, unless you copy the loop register along. + */ + + /* Named label version of the macros: */ + + .macro floop ar, endlabel + floop_ \ar, .Lfloopstart_\endlabel, .Lfloopend_\endlabel + .endm + + .macro floopnez ar, endlabel + floopnez_ \ar, .Lfloopstart_\endlabel, .Lfloopend_\endlabel + .endm + + .macro floopgtz ar, endlabel + floopgtz_ \ar, .Lfloopstart_\endlabel, .Lfloopend_\endlabel + .endm + + .macro floopend ar, endlabel + floopend_ \ar, .Lfloopstart_\endlabel, .Lfloopend_\endlabel + .endm + + /* Numbered local label version of the macros: */ +#if 0 /*UNTESTED*/ + .macro floop89 ar + floop_ \ar, 8, 9f + .endm + + .macro floopnez89 ar + floopnez_ \ar, 8, 9f + .endm + + .macro floopgtz89 ar + floopgtz_ \ar, 8, 9f + .endm + + .macro floopend89 ar + floopend_ \ar, 8b, 9 + .endm +#endif /*0*/ + + /* Underlying version of the macros: */ + + .macro floop_ ar, startlabel, endlabelref + .ifdef _infloop_ + .if _infloop_ + .err // Error: floop cannot be nested + .endif + .endif + .set _infloop_, 1 +#if XCHAL_HAVE_LOOPS + loop \ar, \endlabelref +#else /* XCHAL_HAVE_LOOPS */ +\startlabel: + addi \ar, \ar, -1 +#endif /* XCHAL_HAVE_LOOPS */ + .endm // floop_ + + .macro floopnez_ ar, startlabel, endlabelref + .ifdef _infloop_ + .if _infloop_ + .err // Error: floopnez cannot be nested + .endif + .endif + .set _infloop_, 1 +#if XCHAL_HAVE_LOOPS + loopnez \ar, \endlabelref +#else /* XCHAL_HAVE_LOOPS */ + beqz \ar, \endlabelref +\startlabel: + addi \ar, \ar, -1 +#endif /* XCHAL_HAVE_LOOPS */ + .endm // floopnez_ + + .macro floopgtz_ ar, startlabel, endlabelref + .ifdef _infloop_ + .if _infloop_ + .err // Error: floopgtz cannot be nested + .endif + .endif + .set _infloop_, 1 +#if XCHAL_HAVE_LOOPS + loopgtz \ar, \endlabelref +#else /* XCHAL_HAVE_LOOPS */ + bltz \ar, \endlabelref + beqz \ar, \endlabelref +\startlabel: + addi \ar, \ar, -1 +#endif /* XCHAL_HAVE_LOOPS */ + .endm // floopgtz_ + + + .macro floopend_ ar, startlabelref, endlabel + .ifndef _infloop_ + .err // Error: floopend without matching floopXXX + .endif + .ifeq _infloop_ + .err // Error: floopend without matching floopXXX + .endif + .set _infloop_, 0 +#if ! XCHAL_HAVE_LOOPS + bnez \ar, \startlabelref +#endif /* XCHAL_HAVE_LOOPS */ +\endlabel: + .endm // floopend_ + +/*---------------------------------------------------------------------- + * crsil -- conditional RSIL (read/set interrupt level) + * + * Executes the RSIL instruction if it exists, else just reads PS. + * The RSIL instruction does not exist in the new exception architecture + * if the interrupt option is not selected. + */ + + .macro crsil ar, newlevel +#if XCHAL_HAVE_OLD_EXC_ARCH || XCHAL_HAVE_INTERRUPTS + rsil \ar, \newlevel +#else + rsr \ar, PS +#endif + .endm // crsil + +/*---------------------------------------------------------------------- + * safe_movi_a0 -- move constant into a0 when L32R is not safe + * + * This macro is typically used by interrupt/exception handlers. + * Loads a 32-bit constant in a0, without using any other register, + * and without corrupting the LITBASE register, even when the + * value of the LITBASE register is unknown (eg. when application + * code and interrupt/exception handling code are built independently, + * and thus with independent values of the LITBASE register; + * debug monitors are one example of this). + * + * Worst-case size of resulting code: 17 bytes. + */ + + .macro safe_movi_a0 constant +#if XCHAL_HAVE_ABSOLUTE_LITERALS + /* Contort a PC-relative literal load even though we may be in litbase-relative mode: */ + j 1f + .begin no-transform // ensure what follows is assembled exactly as-is + .align 4 // ensure constant and call0 target ... + .byte 0 // ... are 4-byte aligned (call0 instruction is 3 bytes long) +1: call0 2f // read PC (that follows call0) in a0 + .long \constant // 32-bit constant to load into a0 +2: + .end no-transform + l32i a0, a0, 0 // load constant +#else + movi a0, \constant // no LITBASE, can assume PC-relative L32R +#endif + .endm + + + + +/*---------------------------------------------------------------------- + * window_spill{4,8,12} + * + * These macros spill callers' register windows to the stack. + * They work for both privileged and non-privileged tasks. + * Must be called from a windowed ABI context, eg. within + * a windowed ABI function (ie. valid stack frame, window + * exceptions enabled, not in exception mode, etc). + * + * This macro requires a single invocation of the window_spill_common + * macro in the same assembly unit and section. + * + * Note that using window_spill{4,8,12} macros is more efficient + * than calling a function implemented using window_spill_function, + * because the latter needs extra code to figure out the size of + * the call to the spilling function. + * + * Example usage: + * + * .text + * .align 4 + * .global some_function + * .type some_function,@function + * some_function: + * entry a1, 16 + * : + * : + * + * window_spill4 // Spill windows of some_function's callers; preserves a0..a3 only; + * // to use window_spill{8,12} in this example function we'd have + * // to increase space allocated by the entry instruction, because + * // 16 bytes only allows call4; 32 or 48 bytes (+locals) are needed + * // for call8/window_spill8 or call12/window_spill12 respectively. + * + * : + * + * retw + * + * window_spill_common // instantiates code used by window_spill4 + * + * + * On entry: + * none (if window_spill4) + * stack frame has enough space allocated for call8 (if window_spill8) + * stack frame has enough space allocated for call12 (if window_spill12) + * On exit: + * a4..a15 clobbered (if window_spill4) + * a8..a15 clobbered (if window_spill8) + * a12..a15 clobbered (if window_spill12) + * no caller windows are in live registers + */ + + .macro window_spill4 +#if XCHAL_HAVE_WINDOWED +# if XCHAL_NUM_AREGS == 16 + movi a15, 0 // for 16-register files, no need to call to reach the end +# elif XCHAL_NUM_AREGS == 32 + call4 .L__wdwspill_assist28 // call deep enough to clear out any live callers +# elif XCHAL_NUM_AREGS == 64 + call4 .L__wdwspill_assist60 // call deep enough to clear out any live callers +# endif +#endif + .endm // window_spill4 + + .macro window_spill8 +#if XCHAL_HAVE_WINDOWED +# if XCHAL_NUM_AREGS == 16 + movi a15, 0 // for 16-register files, no need to call to reach the end +# elif XCHAL_NUM_AREGS == 32 + call8 .L__wdwspill_assist24 // call deep enough to clear out any live callers +# elif XCHAL_NUM_AREGS == 64 + call8 .L__wdwspill_assist56 // call deep enough to clear out any live callers +# endif +#endif + .endm // window_spill8 + + .macro window_spill12 +#if XCHAL_HAVE_WINDOWED +# if XCHAL_NUM_AREGS == 16 + movi a15, 0 // for 16-register files, no need to call to reach the end +# elif XCHAL_NUM_AREGS == 32 + call12 .L__wdwspill_assist20 // call deep enough to clear out any live callers +# elif XCHAL_NUM_AREGS == 64 + call12 .L__wdwspill_assist52 // call deep enough to clear out any live callers +# endif +#endif + .endm // window_spill12 + + +/*---------------------------------------------------------------------- + * window_spill_function + * + * This macro outputs a function that will spill its caller's callers' + * register windows to the stack. Eg. it could be used to implement + * a version of xthal_window_spill() that works in non-privileged tasks. + * This works for both privileged and non-privileged tasks. + * + * Typical usage: + * + * .text + * .align 4 + * .global my_spill_function + * .type my_spill_function,@function + * my_spill_function: + * window_spill_function + * + * On entry to resulting function: + * none + * On exit from resulting function: + * none (no caller windows are in live registers) + */ + + .macro window_spill_function +#if XCHAL_HAVE_WINDOWED +# if XCHAL_NUM_AREGS == 32 + entry sp, 48 + bbci.l a0, 31, 1f // branch if called with call4 + bbsi.l a0, 30, 2f // branch if called with call12 + call8 .L__wdwspill_assist16 // called with call8, only need another 8 + retw +1: call12 .L__wdwspill_assist16 // called with call4, only need another 12 + retw +2: call4 .L__wdwspill_assist16 // called with call12, only need another 4 + retw +# elif XCHAL_NUM_AREGS == 64 + entry sp, 48 + bbci.l a0, 31, 1f // branch if called with call4 + bbsi.l a0, 30, 2f // branch if called with call12 + call4 .L__wdwspill_assist52 // called with call8, only need a call4 + retw +1: call8 .L__wdwspill_assist52 // called with call4, only need a call8 + retw +2: call12 .L__wdwspill_assist40 // called with call12, can skip a call12 + retw +# elif XCHAL_NUM_AREGS == 16 + entry sp, 16 + bbci.l a0, 31, 1f // branch if called with call4 + bbsi.l a0, 30, 2f // branch if called with call12 + movi a7, 0 // called with call8 + retw +1: movi a11, 0 // called with call4 +2: retw // if called with call12, everything already spilled + +// movi a15, 0 // trick to spill all but the direct caller +// j 1f +// // The entry instruction is magical in the assembler (gets auto-aligned) +// // so we have to jump to it to avoid falling through the padding. +// // We need entry/retw to know where to return. +//1: entry sp, 16 +// retw +# else +# error "unrecognized address register file size" +# endif + +#endif /* XCHAL_HAVE_WINDOWED */ + window_spill_common + .endm // window_spill_function + +/*---------------------------------------------------------------------- + * window_spill_common + * + * Common code used by any number of invocations of the window_spill## + * and window_spill_function macros. + * + * Must be instantiated exactly once within a given assembly unit, + * within call/j range of and same section as window_spill## + * macro invocations for that assembly unit. + * (Is automatically instantiated by the window_spill_function macro.) + */ + + .macro window_spill_common +#if XCHAL_HAVE_WINDOWED && (XCHAL_NUM_AREGS == 32 || XCHAL_NUM_AREGS == 64) + .ifndef .L__wdwspill_defined +# if XCHAL_NUM_AREGS >= 64 +.L__wdwspill_assist60: + entry sp, 32 + call8 .L__wdwspill_assist52 + retw +.L__wdwspill_assist56: + entry sp, 16 + call4 .L__wdwspill_assist52 + retw +.L__wdwspill_assist52: + entry sp, 48 + call12 .L__wdwspill_assist40 + retw +.L__wdwspill_assist40: + entry sp, 48 + call12 .L__wdwspill_assist28 + retw +# endif +.L__wdwspill_assist28: + entry sp, 48 + call12 .L__wdwspill_assist16 + retw +.L__wdwspill_assist24: + entry sp, 32 + call8 .L__wdwspill_assist16 + retw +.L__wdwspill_assist20: + entry sp, 16 + call4 .L__wdwspill_assist16 + retw +.L__wdwspill_assist16: + entry sp, 16 + movi a15, 0 + retw + .set .L__wdwspill_defined, 1 + .endif +#endif /* XCHAL_HAVE_WINDOWED with 32 or 64 aregs */ + .endm // window_spill_common + +/*---------------------------------------------------------------------- + * beqi32 + * + * macro implements version of beqi for arbitrary 32-bit immediate value + * + * beqi32 ax, ay, imm32, label + * + * Compares value in register ax with imm32 value and jumps to label if + * equal. Clobbers register ay if needed + * + */ + .macro beqi32 ax, ay, imm, label + .ifeq ((\imm-1) & ~7) // 1..8 ? + beqi \ax, \imm, \label + .else + .ifeq (\imm+1) // -1 ? + beqi \ax, \imm, \label + .else + .ifeq (\imm) // 0 ? + beqz \ax, \label + .else + // We could also handle immediates 10,12,16,32,64,128,256 + // but it would be a long macro... + movi \ay, \imm + beq \ax, \ay, \label + .endif + .endif + .endif + .endm // beqi32 + +/*---------------------------------------------------------------------- + * isync_retw_nop + * + * This macro must be invoked immediately after ISYNC if ISYNC + * would otherwise be immediately followed by RETW (or other instruction + * modifying WindowBase or WindowStart), in a context where + * kernel vector mode may be selected, and level-one interrupts + * and window overflows may be enabled, on an XEA1 configuration. + * + * On hardware with erratum "XEA1KWIN" (see for details), + * XEA1 code must have at least one instruction between ISYNC and RETW if + * run in kernel vector mode with interrupts and window overflows enabled. + */ + .macro isync_retw_nop +#if XCHAL_MAYHAVE_ERRATUM_XEA1KWIN + nop +#endif + .endm + + + +/*---------------------------------------------------------------------- + * abs + * + * implements abs on machines that do not have it configured + */ + +#if !XCHAL_HAVE_ABS + .macro abs arr, ars + .ifc \arr, \ars + //src equal dest is less efficient + bgez \arr, 1f + neg \arr, \arr +1: + .else + neg \arr, \ars + movgez \arr, \ars, \ars + .endif + .endm +#endif /* !XCHAL_HAVE_ABS */ + + +/*---------------------------------------------------------------------- + * addx2 + * + * implements addx2 on machines that do not have it configured + * + */ + +#if !XCHAL_HAVE_ADDX + .macro addx2 arr, ars, art + .ifc \arr, \art + .ifc \arr, \ars + // addx2 a, a, a (not common) + .err + .else + add \arr, \ars, \art + add \arr, \ars, \art + .endif + .else + //addx2 a, b, c + //addx2 a, a, b + //addx2 a, b, b + slli \arr, \ars, 1 + add \arr, \arr, \art + .endif + .endm +#endif /* !XCHAL_HAVE_ADDX */ + +/*---------------------------------------------------------------------- + * addx4 + * + * implements addx4 on machines that do not have it configured + * + */ + +#if !XCHAL_HAVE_ADDX + .macro addx4 arr, ars, art + .ifc \arr, \art + .ifc \arr, \ars + // addx4 a, a, a (not common) + .err + .else + //# addx4 a, b, a + add \arr, \ars, \art + add \arr, \ars, \art + add \arr, \ars, \art + add \arr, \ars, \art + .endif + .else + //addx4 a, b, c + //addx4 a, a, b + //addx4 a, b, b + slli \arr, \ars, 2 + add \arr, \arr, \art + .endif + .endm +#endif /* !XCHAL_HAVE_ADDX */ + +/*---------------------------------------------------------------------- + * addx8 + * + * implements addx8 on machines that do not have it configured + * + */ + +#if !XCHAL_HAVE_ADDX + .macro addx8 arr, ars, art + .ifc \arr, \art + .ifc \arr, \ars + //addx8 a, a, a (not common) + .err + .else + //addx8 a, b, a + add \arr, \ars, \art + add \arr, \ars, \art + add \arr, \ars, \art + add \arr, \ars, \art + add \arr, \ars, \art + add \arr, \ars, \art + add \arr, \ars, \art + add \arr, \ars, \art + .endif + .else + //addx8 a, b, c + //addx8 a, a, b + //addx8 a, b, b + slli \arr, \ars, 3 + add \arr, \arr, \art + .endif + .endm +#endif /* !XCHAL_HAVE_ADDX */ + + +/*---------------------------------------------------------------------- + * rfe_rfue + * + * Maps to RFUE on XEA1, and RFE on XEA2. No mapping on XEAX. + */ + +#if XCHAL_HAVE_XEA1 + .macro rfe_rfue + rfue + .endm +#elif XCHAL_HAVE_XEA2 + .macro rfe_rfue + rfe + .endm +#endif + + +/*---------------------------------------------------------------------- + * abi_entry + * + * Generate proper function entry sequence for the current ABI + * (windowed or call0). Takes care of allocating stack space (up to 1kB) + * and saving the return PC, if necessary. The corresponding abi_return + * macro does the corresponding stack deallocation and restoring return PC. + * + * Parameters are: + * + * locsize Number of bytes to allocate on the stack + * for local variables (and for args to pass to + * callees, if any calls are made). Defaults to zero. + * The macro rounds this up to a multiple of 16. + * NOTE: large values are allowed (e.g. up to 1 GB). + * + * callsize Maximum call size made by this function. + * Leave zero (default) for leaf functions, i.e. if + * this function makes no calls to other functions. + * Otherwise must be set to 4, 8, or 12 according + * to whether the "largest" call made is a call[x]4, + * call[x]8, or call[x]12 (for call0 ABI, it makes + * no difference whether this is set to 4, 8 or 12, + * but it must be set to one of these values). + * + * NOTE: It is up to the caller to align the entry point, declare the + * function symbol, make it global, etc. + * + * NOTE: This macro relies on assembler relaxation for large values + * of locsize. It might not work with the no-transform directive. + * NOTE: For the call0 ABI, this macro ensures SP is allocated or + * de-allocated cleanly, i.e. without temporarily allocating too much + * (or allocating negatively!) due to addi relaxation. + * + * NOTE: Generating the proper sequence and register allocation for + * making calls in an ABI independent manner is a separate topic not + * covered by this macro. + * + * NOTE: To access arguments, you can't use a fixed offset from SP. + * The offset depends on the ABI, whether the function is leaf, etc. + * The simplest method is probably to use the .locsz symbol, which + * is set by this macro to the actual number of bytes allocated on + * the stack, in other words, to the offset from SP to the arguments. + * E.g. for a function whose arguments are all 32-bit integers, you + * can get the 7th and 8th arguments (1st and 2nd args stored on stack) + * using: + * l32i a2, sp, .locsz + * l32i a3, sp, .locsz+4 + * (this example works as long as locsize is under L32I's offset limit + * of 1020 minus up to 48 bytes of ABI-specific stack usage; + * otherwise you might first need to do "addi a?, sp, .locsz" + * or similar sequence). + * + * NOTE: For call0 ABI, this macro (and abi_return) may clobber a9 + * (a caller-saved register). + * + * Examples: + * abi_entry + * abi_entry 5 + * abi_entry 22, 8 + * abi_entry 0, 4 + */ + + /* + * Compute .locsz and .callsz without emitting any instructions. + * Used by both abi_entry and abi_return. + * Assumes locsize >= 0. + */ + .macro abi_entry_size locsize=0, callsize=0 +#if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__ + .ifeq \callsize + .set .callsz, 16 + .else + .ifeq \callsize-4 + .set .callsz, 16 + .else + .ifeq \callsize-8 + .set .callsz, 32 + .else + .ifeq \callsize-12 + .set .callsz, 48 + .else + .error "abi_entry: invalid call size \callsize" + .endif + .endif + .endif + .endif + .set .locsz, .callsz + ((\locsize + 15) & -16) +#else + .set .callsz, \callsize + .if .callsz /* if calls, need space for return PC */ + .set .locsz, (\locsize + 4 + 15) & -16 + .else + .set .locsz, (\locsize + 15) & -16 + .endif +#endif + .endm + + .macro abi_entry locsize=0, callsize=0 + .iflt \locsize + .error "abi_entry: invalid negative size of locals (\locsize)" + .endif + abi_entry_size \locsize, \callsize +#if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__ + .ifgt .locsz - 32760 /* .locsz > 32760 (ENTRY's max range)? */ + /* Funky computation to try to have assembler use addmi efficiently if possible: */ + entry sp, 0x7F00 + (.locsz & 0xF0) + addi a12, sp, - ((.locsz & -0x100) - 0x7F00) + movsp sp, a12 + .else + entry sp, .locsz + .endif +#else + .if .locsz + .ifle .locsz - 128 /* if locsz <= 128 */ + addi sp, sp, -.locsz + .if .callsz + s32i a0, sp, .locsz - 4 + .endif + .elseif .callsz /* locsz > 128, with calls: */ + movi a9, .locsz - 16 /* note: a9 is caller-saved */ + addi sp, sp, -16 + s32i a0, sp, 12 + sub sp, sp, a9 + .else /* locsz > 128, no calls: */ + movi a9, .locsz + sub sp, sp, a9 + .endif /* end */ + .endif +#endif + .endm + + + +/*---------------------------------------------------------------------- + * abi_return + * + * Generate proper function exit sequence for the current ABI + * (windowed or call0). Takes care of freeing stack space and + * restoring the return PC, if necessary. + * NOTE: This macro MUST be invoked following a corresponding + * abi_entry macro invocation. For call0 ABI in particular, + * all stack and PC restoration are done according to the last + * abi_entry macro invoked before this macro in the assembly file. + * + * Normally this macro takes no arguments. However to allow + * for placing abi_return *before* abi_entry (as must be done + * for some highly optimized assembly), it optionally takes + * exactly the same arguments as abi_entry. + */ + + .macro abi_return locsize=-1, callsize=0 + .ifge \locsize + abi_entry_size \locsize, \callsize + .endif +#if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__ + retw +#else + .if .locsz + .iflt .locsz - 128 /* if locsz < 128 */ + .if .callsz + l32i a0, sp, .locsz - 4 + .endif + addi sp, sp, .locsz + .elseif .callsz /* locsz >= 128, with calls: */ + addi a9, sp, .locsz - 16 + l32i a0, a9, 12 + addi sp, a9, 16 + .else /* locsz >= 128, no calls: */ + movi a9, .locsz + add sp, sp, a9 + .endif /* end */ + .endif + ret +#endif + .endm + + +#endif /*XTENSA_COREASM_H*/ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/corebits.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/corebits.h new file mode 100644 index 0000000..9f5154c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/corebits.h @@ -0,0 +1,164 @@ +/* + * xtensa/corebits.h - Xtensa Special Register field positions, masks, values. + * + * (In previous releases, these were defined in specreg.h, a generated file. + * This file is not generated, ie. it is processor configuration independent.) + */ + +/* $Id: //depot/rel/Boreal/Xtensa/OS/include/xtensa/corebits.h#2 $ */ + +/* + * Copyright (c) 2005-2007 Tensilica Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef XTENSA_COREBITS_H +#define XTENSA_COREBITS_H + +/* EXCCAUSE register fields: */ +#define EXCCAUSE_EXCCAUSE_SHIFT 0 +#define EXCCAUSE_EXCCAUSE_MASK 0x3F +/* EXCCAUSE register values: */ +/* + * General Exception Causes + * (values of EXCCAUSE special register set by general exceptions, + * which vector to the user, kernel, or double-exception vectors). + */ +#define EXCCAUSE_ILLEGAL 0 /* Illegal Instruction */ +#define EXCCAUSE_SYSCALL 1 /* System Call (SYSCALL instruction) */ +#define EXCCAUSE_INSTR_ERROR 2 /* Instruction Fetch Error */ +# define EXCCAUSE_IFETCHERROR 2 /* (backward compatibility macro, deprecated, avoid) */ +#define EXCCAUSE_LOAD_STORE_ERROR 3 /* Load Store Error */ +# define EXCCAUSE_LOADSTOREERROR 3 /* (backward compatibility macro, deprecated, avoid) */ +#define EXCCAUSE_LEVEL1_INTERRUPT 4 /* Level 1 Interrupt */ +# define EXCCAUSE_LEVEL1INTERRUPT 4 /* (backward compatibility macro, deprecated, avoid) */ +#define EXCCAUSE_ALLOCA 5 /* Stack Extension Assist (MOVSP instruction) for alloca */ +#define EXCCAUSE_DIVIDE_BY_ZERO 6 /* Integer Divide by Zero */ +#define EXCCAUSE_SPECULATION 7 /* Use of Failed Speculative Access (not implemented) */ +#define EXCCAUSE_PRIVILEGED 8 /* Privileged Instruction */ +#define EXCCAUSE_UNALIGNED 9 /* Unaligned Load or Store */ +/* Reserved 10..11 */ +#define EXCCAUSE_INSTR_DATA_ERROR 12 /* PIF Data Error on Instruction Fetch (RB-200x and later) */ +#define EXCCAUSE_LOAD_STORE_DATA_ERROR 13 /* PIF Data Error on Load or Store (RB-200x and later) */ +#define EXCCAUSE_INSTR_ADDR_ERROR 14 /* PIF Address Error on Instruction Fetch (RB-200x and later) */ +#define EXCCAUSE_LOAD_STORE_ADDR_ERROR 15 /* PIF Address Error on Load or Store (RB-200x and later) */ +#define EXCCAUSE_ITLB_MISS 16 /* ITLB Miss (no ITLB entry matches, hw refill also missed) */ +#define EXCCAUSE_ITLB_MULTIHIT 17 /* ITLB Multihit (multiple ITLB entries match) */ +#define EXCCAUSE_INSTR_RING 18 /* Ring Privilege Violation on Instruction Fetch */ +/* Reserved 19 */ /* Size Restriction on IFetch (not implemented) */ +#define EXCCAUSE_INSTR_PROHIBITED 20 /* Cache Attribute does not allow Instruction Fetch */ +/* Reserved 21..23 */ +#define EXCCAUSE_DTLB_MISS 24 /* DTLB Miss (no DTLB entry matches, hw refill also missed) */ +#define EXCCAUSE_DTLB_MULTIHIT 25 /* DTLB Multihit (multiple DTLB entries match) */ +#define EXCCAUSE_LOAD_STORE_RING 26 /* Ring Privilege Violation on Load or Store */ +/* Reserved 27 */ /* Size Restriction on Load/Store (not implemented) */ +#define EXCCAUSE_LOAD_PROHIBITED 28 /* Cache Attribute does not allow Load */ +#define EXCCAUSE_STORE_PROHIBITED 29 /* Cache Attribute does not allow Store */ +/* Reserved 30..31 */ +#define EXCCAUSE_CP_DISABLED(n) (32+(n)) /* Access to Coprocessor 'n' when disabled */ +#define EXCCAUSE_CP0_DISABLED 32 /* Access to Coprocessor 0 when disabled */ +#define EXCCAUSE_CP1_DISABLED 33 /* Access to Coprocessor 1 when disabled */ +#define EXCCAUSE_CP2_DISABLED 34 /* Access to Coprocessor 2 when disabled */ +#define EXCCAUSE_CP3_DISABLED 35 /* Access to Coprocessor 3 when disabled */ +#define EXCCAUSE_CP4_DISABLED 36 /* Access to Coprocessor 4 when disabled */ +#define EXCCAUSE_CP5_DISABLED 37 /* Access to Coprocessor 5 when disabled */ +#define EXCCAUSE_CP6_DISABLED 38 /* Access to Coprocessor 6 when disabled */ +#define EXCCAUSE_CP7_DISABLED 39 /* Access to Coprocessor 7 when disabled */ +/*#define EXCCAUSE_FLOATING_POINT 40*/ /* Floating Point Exception (not implemented) */ +/* Reserved 40..63 */ + +/* PS register fields: */ +#define PS_WOE_SHIFT 18 +#define PS_WOE_MASK 0x00040000 +#define PS_WOE PS_WOE_MASK +#define PS_CALLINC_SHIFT 16 +#define PS_CALLINC_MASK 0x00030000 +#define PS_CALLINC(n) (((n)&3)<4) 0 2 or >3 (TBD) + * T1030.0 0 1 (HAL beta) + * T1030.{1,2} 0 3 Equivalent to first release. + * T1030.n (n>=3) 0 >= 3 (TBD) + * T1040.n 1040 n Full CHAL available from T1040.2 + * T1050.n 1050 n . + * 6.0.n 6000 n Xtensa Tools v6 (RA-200x.n) + * 7.0.n 7000 n Xtensa Tools v7 (RB-200x.n) + * 7.1.n 7010 n Xtensa Tools v7.1 (RB-200x.(n+2)) + * + * + * Note: there is a distinction between the software version with + * which something is compiled (accessible using XTHAL_RELEASE_* macros) + * and the software version with which the HAL library was compiled + * (accessible using Xthal_release_* global variables). This + * distinction is particularly relevant for vendors that distribute + * configuration-independent binaries (eg. an OS), where their customer + * might link it with a HAL of a different Xtensa software version. + * In this case, it may be appropriate for the OS to verify at run-time + * whether XTHAL_RELEASE_* and Xthal_release_* are compatible. + * [Guidelines as to which version is compatible with which are not + * currently provided explicitly, but might be inferred from reading + * OSKit documentation for all releases -- compatibility is also highly + * dependent on which HAL features are used. Each version is usually + * backward compatible, with very few exceptions if any.] + * + * Notes: + * Tornado 2.0 supported in T1020.3+, T1030.1+, and T1040.{0,1} only. + * Tornado 2.0.2 supported in T1040.2+, T1050, and 6.0. + * Compile-time HAL port of NucleusPlus supported by T1040.2 and later. + */ + +/* Version comparison operators (among major/minor pairs): */ +#define XTHAL_REL_GE(maja,mina, majb,minb) ((maja) > (majb) || \ + ((maja) == (majb) && (mina) >= (minb))) +#define XTHAL_REL_GT(maja,mina, majb,minb) ((maja) > (majb) || \ + ((maja) == (majb) && (mina) > (minb))) +#define XTHAL_REL_LE(maja,mina, majb,minb) ((maja) < (majb) || \ + ((maja) == (majb) && (mina) <= (minb))) +#define XTHAL_REL_LT(maja,mina, majb,minb) ((maja) < (majb) || \ + ((maja) == (majb) && (mina) < (minb))) +#define XTHAL_REL_EQ(maja,mina, majb,minb) ((maja) == (majb) && (mina) == (minb)) + +/* Fuzzy (3-way) logic operators: */ +#define XTHAL_MAYBE -1 /* 0=NO, 1=YES, -1=MAYBE */ +#define XTHAL_FUZZY_AND(a,b) (((a)==0 || (b)==0) ? 0 : ((a)==1 && (b)==1) ? 1 : XTHAL_MAYBE) +#define XTHAL_FUZZY_OR(a,b) (((a)==1 || (b)==1) ? 1 : ((a)==0 && (b)==0) ? 0 : XTHAL_MAYBE) +#define XTHAL_FUZZY_NOT(a) (((a)==0 || (a)==1) ? (1-(a)) : XTHAL_MAYBE) + + +/* + * Architectural limit, independent of configuration: + */ +#define XTHAL_MAX_CPS 8 /* max number of coprocessors (0..7) */ + +/* Misc: */ +#define XTHAL_LITTLEENDIAN 0 +#define XTHAL_BIGENDIAN 1 + + + +#if !defined(_ASMLANGUAGE) && !defined(_NOCLANGUAGE) && !defined(__ASSEMBLER__) +#ifdef __cplusplus +extern "C" { +#endif + +/*---------------------------------------------------------------------- + HAL + ----------------------------------------------------------------------*/ + +/* Constant to be checked in build = (XTHAL_MAJOR_REV<<16)|XTHAL_MINOR_REV */ +extern const unsigned int Xthal_rev_no; + + +/*---------------------------------------------------------------------- + Optional/Custom Processor State + ----------------------------------------------------------------------*/ + +/* save & restore the extra processor state */ +extern void xthal_save_extra(void *base); +extern void xthal_restore_extra(void *base); + +extern void xthal_save_cpregs(void *base, int); +extern void xthal_restore_cpregs(void *base, int); +/* versions specific to each coprocessor id */ +extern void xthal_save_cp0(void *base); +extern void xthal_save_cp1(void *base); +extern void xthal_save_cp2(void *base); +extern void xthal_save_cp3(void *base); +extern void xthal_save_cp4(void *base); +extern void xthal_save_cp5(void *base); +extern void xthal_save_cp6(void *base); +extern void xthal_save_cp7(void *base); +extern void xthal_restore_cp0(void *base); +extern void xthal_restore_cp1(void *base); +extern void xthal_restore_cp2(void *base); +extern void xthal_restore_cp3(void *base); +extern void xthal_restore_cp4(void *base); +extern void xthal_restore_cp5(void *base); +extern void xthal_restore_cp6(void *base); +extern void xthal_restore_cp7(void *base); +/* pointers to each of the functions above */ +extern void* Xthal_cpregs_save_fn[XTHAL_MAX_CPS]; +extern void* Xthal_cpregs_restore_fn[XTHAL_MAX_CPS]; +/* similarly for non-windowed ABI (may be same or different) */ +extern void* Xthal_cpregs_save_nw_fn[XTHAL_MAX_CPS]; +extern void* Xthal_cpregs_restore_nw_fn[XTHAL_MAX_CPS]; + +/*extern void xthal_save_all_extra(void *base);*/ +/*extern void xthal_restore_all_extra(void *base);*/ + +/* space for processor state */ +extern const unsigned int Xthal_extra_size; +extern const unsigned int Xthal_extra_align; +extern const unsigned int Xthal_cpregs_size[XTHAL_MAX_CPS]; +extern const unsigned int Xthal_cpregs_align[XTHAL_MAX_CPS]; +extern const unsigned int Xthal_all_extra_size; +extern const unsigned int Xthal_all_extra_align; +/* coprocessor names */ +extern const char * const Xthal_cp_names[XTHAL_MAX_CPS]; + +/* initialize the extra processor */ +/*extern void xthal_init_extra(void);*/ +/* initialize the TIE coprocessor */ +/*extern void xthal_init_cp(int);*/ + +/* initialize the extra processor */ +extern void xthal_init_mem_extra(void *); +/* initialize the TIE coprocessor */ +extern void xthal_init_mem_cp(void *, int); + +/* the number of TIE coprocessors contiguous from zero (for Tor2) */ +extern const unsigned int Xthal_num_coprocessors; + +/* actual number of coprocessors */ +extern const unsigned char Xthal_cp_num; +/* index of highest numbered coprocessor, plus one */ +extern const unsigned char Xthal_cp_max; +/* index of highest allowed coprocessor number, per cfg, plus one */ +/*extern const unsigned char Xthal_cp_maxcfg;*/ +/* bitmask of which coprocessors are present */ +extern const unsigned int Xthal_cp_mask; + +/* read & write extra state register */ +/*extern int xthal_read_extra(void *base, unsigned reg, unsigned *value);*/ +/*extern int xthal_write_extra(void *base, unsigned reg, unsigned value);*/ + +/* read & write a TIE coprocessor register */ +/*extern int xthal_read_cpreg(void *base, int cp, unsigned reg, unsigned *value);*/ +/*extern int xthal_write_cpreg(void *base, int cp, unsigned reg, unsigned value);*/ + +/* return coprocessor number based on register */ +/*extern int xthal_which_cp(unsigned reg);*/ + + +/*---------------------------------------------------------------------- + Register Windows + ----------------------------------------------------------------------*/ + +/* number of registers in register window */ +extern const unsigned int Xthal_num_aregs; +extern const unsigned char Xthal_num_aregs_log2; + + +/*---------------------------------------------------------------------- + Cache + ----------------------------------------------------------------------*/ + +/* size of the cache lines in log2(bytes) */ +extern const unsigned char Xthal_icache_linewidth; +extern const unsigned char Xthal_dcache_linewidth; +/* size of the cache lines in bytes (2^linewidth) */ +extern const unsigned short Xthal_icache_linesize; +extern const unsigned short Xthal_dcache_linesize; + +/* size of the caches in bytes (ways * 2^(linewidth + setwidth)) */ +extern const unsigned int Xthal_icache_size; +extern const unsigned int Xthal_dcache_size; +/* cache features */ +extern const unsigned char Xthal_dcache_is_writeback; + +/* invalidate the caches */ +extern void xthal_icache_region_invalidate( void *addr, unsigned size ); +extern void xthal_dcache_region_invalidate( void *addr, unsigned size ); +extern void xthal_icache_line_invalidate(void *addr); +extern void xthal_dcache_line_invalidate(void *addr); +/* write dirty data back */ +extern void xthal_dcache_region_writeback( void *addr, unsigned size ); +extern void xthal_dcache_line_writeback(void *addr); +/* write dirty data back and invalidate */ +extern void xthal_dcache_region_writeback_inv( void *addr, unsigned size ); +extern void xthal_dcache_line_writeback_inv(void *addr); + +/* sync icache and memory */ +extern void xthal_icache_sync( void ); +/* sync dcache and memory */ +extern void xthal_dcache_sync( void ); + +/* coherency (low-level -- not normally called directly) */ +extern void xthal_cache_coherence_on( void ); +extern void xthal_cache_coherence_off( void ); +/* coherency (high-level) */ +extern void xthal_cache_coherence_optin( void ); +extern void xthal_cache_coherence_optout( void ); + +/* prefetch */ +#define XTHAL_PREFETCH_ENABLE -1 +#define XTHAL_PREFETCH_DISABLE 0 +extern int xthal_set_cache_prefetch( int ); +extern int xthal_get_cache_prefetch( void ); + + +/*---------------------------------------------------------------------- + Debug + ----------------------------------------------------------------------*/ + +/* 1 if debug option configured, 0 if not: */ +extern const int Xthal_debug_configured; + +/* Set (plant) and remove software breakpoint, both synchronizing cache: */ +extern unsigned int xthal_set_soft_break(void *addr); +extern void xthal_remove_soft_break(void *addr, unsigned int); + + +/*---------------------------------------------------------------------- + Disassembler + ----------------------------------------------------------------------*/ + +/* Max expected size of the return buffer for a disassembled instruction (hint only): */ +#define XTHAL_DISASM_BUFSIZE 80 + +/* Disassembly option bits for selecting what to return: */ +#define XTHAL_DISASM_OPT_ADDR 0x0001 /* display address */ +#define XTHAL_DISASM_OPT_OPHEX 0x0002 /* display opcode bytes in hex */ +#define XTHAL_DISASM_OPT_OPCODE 0x0004 /* display opcode name (mnemonic) */ +#define XTHAL_DISASM_OPT_PARMS 0x0008 /* display parameters */ +#define XTHAL_DISASM_OPT_ALL 0x0FFF /* display everything */ + +/* routine to get a string for the disassembled instruction */ +extern int xthal_disassemble( unsigned char *instr_buf, void *tgt_addr, + char *buffer, unsigned buflen, unsigned options ); + +/* routine to get the size of the next instruction. Returns 0 for + illegal instruction */ +extern int xthal_disassemble_size( unsigned char *instr_buf ); + + +/*---------------------------------------------------------------------- + Instruction/Data RAM/ROM Access + ----------------------------------------------------------------------*/ + +extern void* xthal_memcpy(void *dst, const void *src, unsigned len); +extern void* xthal_bcopy(const void *src, void *dst, unsigned len); + + +/*---------------------------------------------------------------------- + MP Synchronization + ----------------------------------------------------------------------*/ + +extern int xthal_compare_and_set( int *addr, int test_val, int compare_val ); + +/*extern const char Xthal_have_s32c1i;*/ + + +/*---------------------------------------------------------------------- + Miscellaneous + ----------------------------------------------------------------------*/ + +extern const unsigned int Xthal_release_major; +extern const unsigned int Xthal_release_minor; +extern const char * const Xthal_release_name; +extern const char * const Xthal_release_internal; + +extern const unsigned char Xthal_memory_order; +extern const unsigned char Xthal_have_windowed; +extern const unsigned char Xthal_have_density; +extern const unsigned char Xthal_have_booleans; +extern const unsigned char Xthal_have_loops; +extern const unsigned char Xthal_have_nsa; +extern const unsigned char Xthal_have_minmax; +extern const unsigned char Xthal_have_sext; +extern const unsigned char Xthal_have_clamps; +extern const unsigned char Xthal_have_mac16; +extern const unsigned char Xthal_have_mul16; +extern const unsigned char Xthal_have_fp; +extern const unsigned char Xthal_have_speculation; +extern const unsigned char Xthal_have_threadptr; + +extern const unsigned char Xthal_have_pif; +extern const unsigned short Xthal_num_writebuffer_entries; + +extern const unsigned int Xthal_build_unique_id; +/* Version info for hardware targeted by software upgrades: */ +extern const unsigned int Xthal_hw_configid0; +extern const unsigned int Xthal_hw_configid1; +extern const unsigned int Xthal_hw_release_major; +extern const unsigned int Xthal_hw_release_minor; +extern const char * const Xthal_hw_release_name; +extern const char * const Xthal_hw_release_internal; + +#ifdef __cplusplus +} +#endif +#endif /*!_ASMLANGUAGE && !_NOCLANGUAGE && !__ASSEMBLER__ */ + + + + + +/**************************************************************************** + Definitions Useful for PRIVILEGED (Supervisory or Non-Virtualized) Code + ****************************************************************************/ + + +#ifndef XTENSA_HAL_NON_PRIVILEGED_ONLY + +/*---------------------------------------------------------------------- + Constant Definitions (shared with assembly) + ----------------------------------------------------------------------*/ + +/* + * Architectural limits, independent of configuration. + * Note that these are ISA-defined limits, not micro-architecture implementation + * limits enforced by the Xtensa Processor Generator (which may be stricter than + * these below). + */ +#define XTHAL_MAX_INTERRUPTS 32 /* max number of interrupts (0..31) */ +#define XTHAL_MAX_INTLEVELS 16 /* max number of interrupt levels (0..15) */ + /* (as of T1040, implementation limit is 7: 0..6) */ +#define XTHAL_MAX_TIMERS 4 /* max number of timers (CCOMPARE0..CCOMPARE3) */ + /* (as of T1040, implementation limit is 3: 0..2) */ + +/* Interrupt types: */ +#define XTHAL_INTTYPE_UNCONFIGURED 0 +#define XTHAL_INTTYPE_SOFTWARE 1 +#define XTHAL_INTTYPE_EXTERN_EDGE 2 +#define XTHAL_INTTYPE_EXTERN_LEVEL 3 +#define XTHAL_INTTYPE_TIMER 4 +#define XTHAL_INTTYPE_NMI 5 +#define XTHAL_INTTYPE_WRITE_ERROR 6 +#define XTHAL_MAX_INTTYPES 7 /* number of interrupt types */ + +/* Timer related: */ +#define XTHAL_TIMER_UNCONFIGURED -1 /* Xthal_timer_interrupt[] value for non-existent timers */ +#define XTHAL_TIMER_UNASSIGNED XTHAL_TIMER_UNCONFIGURED /* (for backwards compatibility only) */ + +/* Local Memory ECC/Parity: */ +#define XTHAL_MEMEP_PARITY 1 +#define XTHAL_MEMEP_ECC 2 +/* Flags parameter to xthal_memep_inject_error(): */ +#define XTHAL_MEMEP_F_LOCAL 0 /* local memory (default) */ +#define XTHAL_MEMEP_F_DCACHE_DATA 4 /* data cache data */ +#define XTHAL_MEMEP_F_DCACHE_TAG 5 /* data cache tag */ +#define XTHAL_MEMEP_F_ICACHE_DATA 6 /* instruction cache data */ +#define XTHAL_MEMEP_F_ICACHE_TAG 7 /* instruction cache tag */ +#define XTHAL_MEMEP_F_CORRECTABLE 16 /* inject correctable error + (default is non-corr.) */ + + +/* Access Mode bits (tentative): */ /* bit abbr unit short_name PPC equ - Description */ +#define XTHAL_AMB_EXCEPTION 0 /* 001 E EX fls: EXception none + exception on any access (aka "illegal") */ +#define XTHAL_AMB_HITCACHE 1 /* 002 C CH fls: use Cache on Hit ~(I CI) + [or H HC] way from tag match; + [or U UC] (ISA: same except Isolate case) */ +#define XTHAL_AMB_ALLOCATE 2 /* 004 A AL fl?: ALlocate none + [or F FI fill] refill cache on miss, way from LRU + (ISA: Read/Write Miss Refill) */ +#define XTHAL_AMB_WRITETHRU 3 /* 008 W WT --s: WriteThrough W WT + store immediately to memory (ISA: same) */ +#define XTHAL_AMB_ISOLATE 4 /* 010 I IS fls: ISolate none + use cache regardless of hit-vs-miss, + way from vaddr (ISA: use-cache-on-miss+hit) */ +#define XTHAL_AMB_GUARD 5 /* 020 G GU ?l?: GUard G * + non-speculative; spec/replay refs not permitted */ +#define XTHAL_AMB_COHERENT 6 /* 040 M MC ?ls: Mem/MP Coherent M + on read, other CPU/bus-master may need to supply data; + on write, maybe redirect to or flush other CPU dirty line; etc */ +#if 0 +#define XTHAL_AMB_ORDERED x /* 000 O OR fls: ORdered G * + mem accesses cannot be out of order */ +#define XTHAL_AMB_FUSEWRITES x /* 000 F FW --s: FuseWrites none + allow combining/merging/coalescing multiple writes + (to same datapath data unit) into one + (implied by writeback) */ +#define XTHAL_AMB_TRUSTED x /* 000 T TR ?l?: TRusted none + memory will not bus error (if it does, + handle as fatal imprecise interrupt) */ +#define XTHAL_AMB_PREFETCH x /* 000 P PR fl?: PRefetch none + on refill, read line+1 into prefetch buffers */ +#define XTHAL_AMB_STREAM x /* 000 S ST ???: STreaming none + access one of N stream buffers */ +#endif /*0*/ + +#define XTHAL_AM_EXCEPTION (1< = bit is set + * '-' = bit is clear + * '.' = bit is irrelevant / don't care, as follows: + * E=1 makes all others irrelevant + * W,F relevant only for stores + * "2345" + * Indicates which Xtensa releases support the corresponding + * access mode. Releases for each character column are: + * 2 = prior to T1020.2: T1015 (V1.5), T1020.0, T1020.1 + * 3 = T1020.2 and later: T1020.2+, T1030 + * 4 = T1040 + * 5 = T1050 (maybe), LX1, LX2, LX2.1 + * 7 = LX2.2 + * 8 = LX3.0 + * And the character column contents are: + * = supported by release(s) + * "." = unsupported by release(s) + * "?" = support unknown + */ + /* FOMGIWACE 234578 */ +/* For instruction fetch: */ +#define XTHAL_FAM_EXCEPTION 0x001 /* ........E 234578 exception */ +/*efine XTHAL_FAM_ISOLATE*/ /*0x012*/ /* .---I.-C- ...... isolate */ +#define XTHAL_FAM_BYPASS 0x000 /* .----.--- 234578 bypass */ +/*efine XTHAL_FAM_NACACHED*/ /*0x002*/ /* .----.-C- ...... cached no-allocate (frozen) */ +#define XTHAL_FAM_CACHED 0x006 /* .----.AC- 234578 cached */ +/* For data load: */ +#define XTHAL_LAM_EXCEPTION 0x001 /* ........E 234578 exception */ +#define XTHAL_LAM_ISOLATE 0x012 /* .---I.-C- 234578 isolate */ +#define XTHAL_LAM_BYPASS 0x000 /* .O---.--- 2..... bypass speculative */ +#define XTHAL_LAM_BYPASSG 0x020 /* .O-G-.--- .34578 bypass guarded */ +#define XTHAL_LAM_CACHED_NOALLOC 0x002 /* .O---.-C- 234578 cached no-allocate speculative */ +#define XTHAL_LAM_NACACHED XTHAL_LAM_CACHED_NOALLOC +#define XTHAL_LAM_NACACHEDG 0x022 /* .O-G-.-C- .?.... cached no-allocate guarded */ +#define XTHAL_LAM_CACHED 0x006 /* .----.AC- 234578 cached speculative */ +#define XTHAL_LAM_COHCACHED 0x046 /* .-M--.AC- ....*8 cached speculative MP-coherent */ +/* For data store: */ +#define XTHAL_SAM_EXCEPTION 0x001 /* ........E 234578 exception */ +#define XTHAL_SAM_ISOLATE 0x032 /* .--GI--C- 234578 isolate */ +#define XTHAL_SAM_BYPASS 0x028 /* -O-G-W--- 234578 bypass */ +#define XTHAL_SAM_WRITETHRU 0x02A /* -O-G-W-C- 234578 writethrough */ +/*efine XTHAL_SAM_WRITETHRU_ALLOC*/ /*0x02E*/ /* -O-G-WAC- ...... writethrough allocate */ +#define XTHAL_SAM_WRITEBACK 0x026 /* F-MG--AC- ...578 writeback */ +#define XTHAL_SAM_COHWRITEBACK 0x066 /* F-MG--AC- ....*8 writeback MP-coherent */ +#define XTHAL_SAM_WRITEBACK_NOALLOC 0x022 /* ?--G---C- .....8 writeback no-allocate */ + +#if 0 +/* + Cache attribute encoding for CACHEATTR (per ISA): + (Note: if this differs from ISA Ref Manual, ISA has precedence) + + Inst-fetches Loads Stores + ------------- ------------ ------------- +0x0 FCA_EXCEPTION LCA_NACACHED SCA_WRITETHRU cached no-allocate (previously misnamed "uncached") +0x1 FCA_CACHED LCA_CACHED SCA_WRITETHRU cached +0x2 FCA_BYPASS LCA_BYPASS_G* SCA_BYPASS bypass cache (what most people call uncached) +0x3 FCA_CACHED LCA_CACHED SCA_WRITEALLOCF write-allocate + or LCA_EXCEPTION SCA_EXCEPTION (if unimplemented) +0x4 FCA_CACHED LCA_CACHED SCA_WRITEBACK[M] write-back [MP-coherent] + or LCA_EXCEPTION SCA_EXCEPTION (if unimplemented) +0x5 FCA_CACHED LCA_CACHED SCA_WRITEBACK_NOALLOC write-back no-allocate + or FCA_EXCEPTION LCA_EXCEPTION SCA_EXCEPTION (if unimplemented) +0x6..D FCA_EXCEPTION LCA_EXCEPTION SCA_EXCEPTION (reserved) +0xE FCA_EXCEPTION LCA_ISOLATE SCA_ISOLATE isolate +0xF FCA_EXCEPTION LCA_EXCEPTION SCA_EXCEPTION illegal + * Prior to T1020.2?, guard feature not supported, this defaulted to speculative (no _G) +*/ +#endif /*0*/ + + +#if !defined(_ASMLANGUAGE) && !defined(_NOCLANGUAGE) && !defined(__ASSEMBLER__) +#ifdef __cplusplus +extern "C" { +#endif + + +/*---------------------------------------------------------------------- + Register Windows + ----------------------------------------------------------------------*/ + +/* This spill any live register windows (other than the caller's): + * (NOTE: current implementation require privileged code, but + * a user-callable implementation is possible.) */ +extern void xthal_window_spill( void ); + + +/*---------------------------------------------------------------------- + Optional/Custom Processor State + ----------------------------------------------------------------------*/ + +/* validate & invalidate the TIE register file */ +extern void xthal_validate_cp(int); +extern void xthal_invalidate_cp(int); + +/* read and write cpenable register */ +extern void xthal_set_cpenable(unsigned); +extern unsigned xthal_get_cpenable(void); + + +/*---------------------------------------------------------------------- + Interrupts + ----------------------------------------------------------------------*/ + +/* the number of interrupt levels */ +extern const unsigned char Xthal_num_intlevels; +/* the number of interrupts */ +extern const unsigned char Xthal_num_interrupts; + +/* mask for level of interrupts */ +extern const unsigned int Xthal_intlevel_mask[XTHAL_MAX_INTLEVELS]; +/* mask for level 0 to N interrupts */ +extern const unsigned int Xthal_intlevel_andbelow_mask[XTHAL_MAX_INTLEVELS]; + +/* level of each interrupt */ +extern const unsigned char Xthal_intlevel[XTHAL_MAX_INTERRUPTS]; + +/* type per interrupt */ +extern const unsigned char Xthal_inttype[XTHAL_MAX_INTERRUPTS]; + +/* masks of each type of interrupt */ +extern const unsigned int Xthal_inttype_mask[XTHAL_MAX_INTTYPES]; + +/* interrupt numbers assigned to each timer interrupt */ +extern const int Xthal_timer_interrupt[XTHAL_MAX_TIMERS]; + +/* INTENABLE,INTERRUPT,INTSET,INTCLEAR register access functions: */ +extern unsigned xthal_get_intenable( void ); +extern void xthal_set_intenable( unsigned ); +extern unsigned xthal_get_interrupt( void ); +#define xthal_get_intread xthal_get_interrupt /* backward compatibility */ +extern void xthal_set_intset( unsigned ); +extern void xthal_set_intclear( unsigned ); + + +/*---------------------------------------------------------------------- + Debug + ----------------------------------------------------------------------*/ + +/* Number of instruction and data break registers: */ +extern const int Xthal_num_ibreak; +extern const int Xthal_num_dbreak; + + +/*---------------------------------------------------------------------- + Core Counter + ----------------------------------------------------------------------*/ + +/* counter info */ +extern const unsigned char Xthal_have_ccount; /* set if CCOUNT register present */ +extern const unsigned char Xthal_num_ccompare; /* number of CCOMPAREn registers */ + +/* get CCOUNT register (if not present return 0) */ +extern unsigned xthal_get_ccount(void); + +/* set and get CCOMPAREn registers (if not present, get returns 0) */ +extern void xthal_set_ccompare(int, unsigned); +extern unsigned xthal_get_ccompare(int); + + +/*---------------------------------------------------------------------- + Miscellaneous + ----------------------------------------------------------------------*/ + +extern const unsigned char Xthal_have_prid; +extern const unsigned char Xthal_have_exceptions; +extern const unsigned char Xthal_xea_version; +extern const unsigned char Xthal_have_interrupts; +extern const unsigned char Xthal_have_highlevel_interrupts; +extern const unsigned char Xthal_have_nmi; + +extern unsigned xthal_get_prid( void ); + + +/*---------------------------------------------------------------------- + Virtual interrupt prioritization (DEPRECATED) + ----------------------------------------------------------------------*/ + +/* Convert between interrupt levels (as per PS.INTLEVEL) and virtual interrupt priorities: */ +extern unsigned xthal_vpri_to_intlevel(unsigned vpri); +extern unsigned xthal_intlevel_to_vpri(unsigned intlevel); + +/* Enables/disables given set (mask) of interrupts; returns previous enabled-mask of all ints: */ +extern unsigned xthal_int_enable(unsigned); +extern unsigned xthal_int_disable(unsigned); + +/* Set/get virtual priority of an interrupt: */ +extern int xthal_set_int_vpri(int intnum, int vpri); +extern int xthal_get_int_vpri(int intnum); + +/* Set/get interrupt lockout level for exclusive access to virtual priority data structures: */ +extern void xthal_set_vpri_locklevel(unsigned intlevel); +extern unsigned xthal_get_vpri_locklevel(void); + +/* Set/get current virtual interrupt priority: */ +extern unsigned xthal_set_vpri(unsigned vpri); +extern unsigned xthal_get_vpri(void); +extern unsigned xthal_set_vpri_intlevel(unsigned intlevel); +extern unsigned xthal_set_vpri_lock(void); + + +/*---------------------------------------------------------------------- + Generic Interrupt Trampolining Support (DEPRECATED) + ----------------------------------------------------------------------*/ + +typedef void (XtHalVoidFunc)(void); + +/* Bitmask of interrupts currently trampolining down: */ +extern unsigned Xthal_tram_pending; + +/* + * Bitmask of which interrupts currently trampolining down synchronously are + * actually enabled; this bitmask is necessary because INTENABLE cannot hold + * that state (sync-trampolining interrupts must be kept disabled while + * trampolining); in the current implementation, any bit set here is not set + * in INTENABLE, and vice-versa; once a sync-trampoline is handled (at level + * one), its enable bit must be moved from here to INTENABLE: + */ +extern unsigned Xthal_tram_enabled; + +/* Bitmask of interrupts configured for sync trampolining: */ +extern unsigned Xthal_tram_sync; + +/* Trampoline support functions: */ +extern unsigned xthal_tram_pending_to_service( void ); +extern void xthal_tram_done( unsigned serviced_mask ); +extern int xthal_tram_set_sync( int intnum, int sync ); +extern XtHalVoidFunc* xthal_set_tram_trigger_func( XtHalVoidFunc *trigger_fn ); + + +/*---------------------------------------------------------------------- + Internal Memories + ----------------------------------------------------------------------*/ + +extern const unsigned char Xthal_num_instrom; +extern const unsigned char Xthal_num_instram; +extern const unsigned char Xthal_num_datarom; +extern const unsigned char Xthal_num_dataram; +extern const unsigned char Xthal_num_xlmi; + +/* Each of the following arrays contains at least one entry, + * or as many entries as needed if more than one: */ +extern const unsigned int Xthal_instrom_vaddr[]; +extern const unsigned int Xthal_instrom_paddr[]; +extern const unsigned int Xthal_instrom_size []; +extern const unsigned int Xthal_instram_vaddr[]; +extern const unsigned int Xthal_instram_paddr[]; +extern const unsigned int Xthal_instram_size []; +extern const unsigned int Xthal_datarom_vaddr[]; +extern const unsigned int Xthal_datarom_paddr[]; +extern const unsigned int Xthal_datarom_size []; +extern const unsigned int Xthal_dataram_vaddr[]; +extern const unsigned int Xthal_dataram_paddr[]; +extern const unsigned int Xthal_dataram_size []; +extern const unsigned int Xthal_xlmi_vaddr[]; +extern const unsigned int Xthal_xlmi_paddr[]; +extern const unsigned int Xthal_xlmi_size []; + + +/*---------------------------------------------------------------------- + Cache + ----------------------------------------------------------------------*/ + +/* number of cache sets in log2(lines per way) */ +extern const unsigned char Xthal_icache_setwidth; +extern const unsigned char Xthal_dcache_setwidth; +/* cache set associativity (number of ways) */ +extern const unsigned int Xthal_icache_ways; +extern const unsigned int Xthal_dcache_ways; +/* cache features */ +extern const unsigned char Xthal_icache_line_lockable; +extern const unsigned char Xthal_dcache_line_lockable; + +/* cache attribute register control (used by other HAL routines) */ +extern unsigned xthal_get_cacheattr( void ); +extern unsigned xthal_get_icacheattr( void ); +extern unsigned xthal_get_dcacheattr( void ); +extern void xthal_set_cacheattr( unsigned ); +extern void xthal_set_icacheattr( unsigned ); +extern void xthal_set_dcacheattr( unsigned ); +/* set cache attribute (access modes) for a range of memory */ +extern int xthal_set_region_attribute( void *addr, unsigned size, + unsigned cattr, unsigned flags ); +/* Bits of flags parameter to xthal_set_region_attribute(): */ +#define XTHAL_CAFLAG_EXPAND 0x000100 /* only expand allowed access to range, don't reduce it */ +#define XTHAL_CAFLAG_EXACT 0x000200 /* return error if can't apply change to exact range specified */ +#define XTHAL_CAFLAG_NO_PARTIAL 0x000400 /* don't apply change to regions partially covered by range */ +#define XTHAL_CAFLAG_NO_AUTO_WB 0x000800 /* don't writeback data after leaving writeback attribute */ +#define XTHAL_CAFLAG_NO_AUTO_INV 0x001000 /* don't invalidate after disabling cache (entering bypass) */ + +/* enable caches */ +extern void xthal_icache_enable( void ); /* DEPRECATED */ +extern void xthal_dcache_enable( void ); /* DEPRECATED */ +/* disable caches */ +extern void xthal_icache_disable( void ); /* DEPRECATED */ +extern void xthal_dcache_disable( void ); /* DEPRECATED */ + +/* invalidate the caches */ +extern void xthal_icache_all_invalidate( void ); +extern void xthal_dcache_all_invalidate( void ); +/* write dirty data back */ +extern void xthal_dcache_all_writeback( void ); +/* write dirty data back and invalidate */ +extern void xthal_dcache_all_writeback_inv( void ); +/* prefetch and lock specified memory range into cache */ +extern void xthal_icache_region_lock( void *addr, unsigned size ); +extern void xthal_dcache_region_lock( void *addr, unsigned size ); +extern void xthal_icache_line_lock(void *addr); +extern void xthal_dcache_line_lock(void *addr); +/* unlock from cache */ +extern void xthal_icache_all_unlock( void ); +extern void xthal_dcache_all_unlock( void ); +extern void xthal_icache_region_unlock( void *addr, unsigned size ); +extern void xthal_dcache_region_unlock( void *addr, unsigned size ); +extern void xthal_icache_line_unlock(void *addr); +extern void xthal_dcache_line_unlock(void *addr); + + + +/*---------------------------------------------------------------------- + Local Memory ECC/Parity + ----------------------------------------------------------------------*/ + +/* Inject memory errors; flags is bit combination of XTHAL_MEMEP_F_xxx: */ +extern void xthal_memep_inject_error(void *addr, int size, int flags); + + + +/*---------------------------------------------------------------------- + Memory Management Unit + ----------------------------------------------------------------------*/ + +extern const unsigned char Xthal_have_spanning_way; +extern const unsigned char Xthal_have_identity_map; +extern const unsigned char Xthal_have_mimic_cacheattr; +extern const unsigned char Xthal_have_xlt_cacheattr; +extern const unsigned char Xthal_have_cacheattr; +extern const unsigned char Xthal_have_tlbs; + +extern const unsigned char Xthal_mmu_asid_bits; /* 0 .. 8 */ +extern const unsigned char Xthal_mmu_asid_kernel; +extern const unsigned char Xthal_mmu_rings; /* 1 .. 4 (perhaps 0 if no MMU and/or no protection?) */ +extern const unsigned char Xthal_mmu_ring_bits; +extern const unsigned char Xthal_mmu_sr_bits; +extern const unsigned char Xthal_mmu_ca_bits; +extern const unsigned int Xthal_mmu_max_pte_page_size; +extern const unsigned int Xthal_mmu_min_pte_page_size; + +extern const unsigned char Xthal_itlb_way_bits; +extern const unsigned char Xthal_itlb_ways; +extern const unsigned char Xthal_itlb_arf_ways; +extern const unsigned char Xthal_dtlb_way_bits; +extern const unsigned char Xthal_dtlb_ways; +extern const unsigned char Xthal_dtlb_arf_ways; + +/* Convert between virtual and physical addresses (through static maps only): */ +/*** WARNING: these two functions may go away in a future release; don't depend on them! ***/ +extern int xthal_static_v2p( unsigned vaddr, unsigned *paddrp ); +extern int xthal_static_p2v( unsigned paddr, unsigned *vaddrp, unsigned cached ); + + +#ifdef __cplusplus +} +#endif +#endif /*!_ASMLANGUAGE && !_NOCLANGUAGE && !__ASSEMBLER__ */ + +#endif /* !XTENSA_HAL_NON_PRIVILEGED_ONLY */ + + + + +/**************************************************************************** + EXPERIMENTAL and DEPRECATED Definitions + ****************************************************************************/ + + +#if !defined(_ASMLANGUAGE) && !defined(_NOCLANGUAGE) && !defined(__ASSEMBLER__) +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef INCLUDE_DEPRECATED_HAL_CODE +extern const unsigned char Xthal_have_old_exc_arch; +extern const unsigned char Xthal_have_mmu; +extern const unsigned int Xthal_num_regs; +extern const unsigned char Xthal_num_iroms; +extern const unsigned char Xthal_num_irams; +extern const unsigned char Xthal_num_droms; +extern const unsigned char Xthal_num_drams; +extern const unsigned int Xthal_configid0; +extern const unsigned int Xthal_configid1; +#endif + +#ifdef INCLUDE_DEPRECATED_HAL_DEBUG_CODE +#define XTHAL_24_BIT_BREAK 0x80000000 +#define XTHAL_16_BIT_BREAK 0x40000000 +extern const unsigned short Xthal_ill_inst_16[16]; +#define XTHAL_DEST_REG 0xf0000000 /* Mask for destination register */ +#define XTHAL_DEST_REG_INST 0x08000000 /* Branch address is in register */ +#define XTHAL_DEST_REL_INST 0x04000000 /* Branch address is relative */ +#define XTHAL_RFW_INST 0x00000800 +#define XTHAL_RFUE_INST 0x00000400 +#define XTHAL_RFI_INST 0x00000200 +#define XTHAL_RFE_INST 0x00000100 +#define XTHAL_RET_INST 0x00000080 +#define XTHAL_BREAK_INST 0x00000040 +#define XTHAL_SYSCALL_INST 0x00000020 +#define XTHAL_LOOP_END 0x00000010 /* Not set by xthal_inst_type */ +#define XTHAL_JUMP_INST 0x00000008 /* Call or jump instruction */ +#define XTHAL_BRANCH_INST 0x00000004 /* Branch instruction */ +#define XTHAL_24_BIT_INST 0x00000002 +#define XTHAL_16_BIT_INST 0x00000001 +typedef struct xthal_state { + unsigned pc; + unsigned ar[16]; + unsigned lbeg; + unsigned lend; + unsigned lcount; + unsigned extra_ptr; + unsigned cpregs_ptr[XTHAL_MAX_CPS]; +} XTHAL_STATE; +extern unsigned int xthal_inst_type(void *addr); +extern unsigned int xthal_branch_addr(void *addr); +extern unsigned int xthal_get_npc(XTHAL_STATE *user_state); +#endif /* INCLUDE_DEPRECATED_HAL_DEBUG_CODE */ + +#ifdef __cplusplus +} +#endif +#endif /*!_ASMLANGUAGE && !_NOCLANGUAGE && !__ASSEMBLER__ */ + +#endif /*XTENSA_HAL_H*/ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/sim.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/sim.h new file mode 100644 index 0000000..53d810b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/sim.h @@ -0,0 +1,60 @@ +/* Copyright (c) 2004-2006 by Tensilica Inc. ALL RIGHTS RESERVED. +/ These coded instructions, statements, and computer programs are the +/ copyrighted works and confidential proprietary information of Tensilica Inc. +/ They may not be modified, copied, reproduced, distributed, or disclosed to +/ third parties in any manner, medium, or form, in whole or in part, without +/ the prior written consent of Tensilica Inc. +*/ + +/* sim.h + * + * Definitions and prototypes for specific ISS SIMCALLs + * (ie. outside the standard C library). + */ + +#ifndef _INC_SIM_H_ +#define _INC_SIM_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Shortcuts for enabling/disabling profiling in the Xtensa ISS */ +extern void xt_iss_profile_enable(void); +extern void xt_iss_profile_disable(void); + +/* Shortcut for setting the trace level in the Xtensa ISS */ +extern void xt_iss_trace_level(unsigned level); + +/* Generic interface for passing client commands in the Xtensa ISS: + * returns 0 on success, -1 on failure. + */ +extern int xt_iss_client_command(const char *client, const char *command); + +/* Interface for switching simulation modes in the Xtensa ISS: + * returns 0 on success, -1 on failure. + */ +#define XT_ISS_CYCLE_ACCURATE 0 +#define XT_ISS_FUNCTIONAL 1 +extern int xt_iss_switch_mode(int mode); + + +/* Interface for waiting on a system synchronization event */ +extern void xt_iss_event_wait(unsigned event_id); + +/* Interface for firing a system synchronization event */ +extern void xt_iss_event_fire(unsigned event_id); + +/* Interface for invoking a user simcall action, + * which can be registered in XTMP or XTSC. + */ +extern int xt_iss_simcall(int arg1, int arg2, int arg3, + int arg4, int arg5, int arg6); + + +#ifdef __cplusplus +} +#endif + +#endif /*_INC_SIM_H_*/ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/simcall-errno.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/simcall-errno.h new file mode 100644 index 0000000..a642012 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/simcall-errno.h @@ -0,0 +1,139 @@ +/* Error numbers for Xtensa ISS semihosting. */ + +/* Copyright (c) 2003 by Tensilica Inc. ALL RIGHTS RESERVED. + These coded instructions, statements, and computer programs are the + copyrighted works and confidential proprietary information of Tensilica Inc. + They may not be modified, copied, reproduced, distributed, or disclosed to + third parties in any manner, medium, or form, in whole or in part, without + the prior written consent of Tensilica Inc. */ + +#ifndef _SIMCALL_ERRNO_H +#define _SIMCALL_ERRNO_H + +/* Define the error numbers (using the default newlib values) with prefixes + so they can be used in ISS without conflicting with the host values. */ + +#define _SIMC_EPERM 1 +#define _SIMC_ENOENT 2 +#define _SIMC_ESRCH 3 +#define _SIMC_EINTR 4 +#define _SIMC_EIO 5 +#define _SIMC_ENXIO 6 +#define _SIMC_E2BIG 7 +#define _SIMC_ENOEXEC 8 +#define _SIMC_EBADF 9 +#define _SIMC_ECHILD 10 +#define _SIMC_EAGAIN 11 +#define _SIMC_ENOMEM 12 +#define _SIMC_EACCES 13 +#define _SIMC_EFAULT 14 +#define _SIMC_ENOTBLK 15 +#define _SIMC_EBUSY 16 +#define _SIMC_EEXIST 17 +#define _SIMC_EXDEV 18 +#define _SIMC_ENODEV 19 +#define _SIMC_ENOTDIR 20 +#define _SIMC_EISDIR 21 +#define _SIMC_EINVAL 22 +#define _SIMC_ENFILE 23 +#define _SIMC_EMFILE 24 +#define _SIMC_ENOTTY 25 +#define _SIMC_ETXTBSY 26 +#define _SIMC_EFBIG 27 +#define _SIMC_ENOSPC 28 +#define _SIMC_ESPIPE 29 +#define _SIMC_EROFS 30 +#define _SIMC_EMLINK 31 +#define _SIMC_EPIPE 32 +#define _SIMC_EDOM 33 +#define _SIMC_ERANGE 34 +#define _SIMC_ENOMSG 35 +#define _SIMC_EIDRM 36 +#define _SIMC_ECHRNG 37 +#define _SIMC_EL2NSYNC 38 +#define _SIMC_EL3HLT 39 +#define _SIMC_EL3RST 40 +#define _SIMC_ELNRNG 41 +#define _SIMC_EUNATCH 42 +#define _SIMC_ENOCSI 43 +#define _SIMC_EL2HLT 44 +#define _SIMC_EDEADLK 45 +#define _SIMC_ENOLCK 46 +#define _SIMC_EBADE 50 +#define _SIMC_EBADR 51 +#define _SIMC_EXFULL 52 +#define _SIMC_ENOANO 53 +#define _SIMC_EBADRQC 54 +#define _SIMC_EBADSLT 55 +#define _SIMC_EDEADLOCK 56 +#define _SIMC_EBFONT 57 +#define _SIMC_ENOSTR 60 +#define _SIMC_ENODATA 61 +#define _SIMC_ETIME 62 +#define _SIMC_ENOSR 63 +#define _SIMC_ENONET 64 +#define _SIMC_ENOPKG 65 +#define _SIMC_EREMOTE 66 +#define _SIMC_ENOLINK 67 +#define _SIMC_EADV 68 +#define _SIMC_ESRMNT 69 +#define _SIMC_ECOMM 70 +#define _SIMC_EPROTO 71 +#define _SIMC_EMULTIHOP 74 +#define _SIMC_ELBIN 75 +#define _SIMC_EDOTDOT 76 +#define _SIMC_EBADMSG 77 +#define _SIMC_EFTYPE 79 +#define _SIMC_ENOTUNIQ 80 +#define _SIMC_EBADFD 81 +#define _SIMC_EREMCHG 82 +#define _SIMC_ELIBACC 83 +#define _SIMC_ELIBBAD 84 +#define _SIMC_ELIBSCN 85 +#define _SIMC_ELIBMAX 86 +#define _SIMC_ELIBEXEC 87 +#define _SIMC_ENOSYS 88 +#define _SIMC_ENMFILE 89 +#define _SIMC_ENOTEMPTY 90 +#define _SIMC_ENAMETOOLONG 91 +#define _SIMC_ELOOP 92 +#define _SIMC_EOPNOTSUPP 95 +#define _SIMC_EPFNOSUPPORT 96 +#define _SIMC_ECONNRESET 104 +#define _SIMC_ENOBUFS 105 +#define _SIMC_EAFNOSUPPORT 106 +#define _SIMC_EPROTOTYPE 107 +#define _SIMC_ENOTSOCK 108 +#define _SIMC_ENOPROTOOPT 109 +#define _SIMC_ESHUTDOWN 110 +#define _SIMC_ECONNREFUSED 111 +#define _SIMC_EADDRINUSE 112 +#define _SIMC_ECONNABORTED 113 +#define _SIMC_ENETUNREACH 114 +#define _SIMC_ENETDOWN 115 +#define _SIMC_ETIMEDOUT 116 +#define _SIMC_EHOSTDOWN 117 +#define _SIMC_EHOSTUNREACH 118 +#define _SIMC_EINPROGRESS 119 +#define _SIMC_EALREADY 120 +#define _SIMC_EDESTADDRREQ 121 +#define _SIMC_EMSGSIZE 122 +#define _SIMC_EPROTONOSUPPORT 123 +#define _SIMC_ESOCKTNOSUPPORT 124 +#define _SIMC_EADDRNOTAVAIL 125 +#define _SIMC_ENETRESET 126 +#define _SIMC_EISCONN 127 +#define _SIMC_ENOTCONN 128 +#define _SIMC_ETOOMANYREFS 129 +#define _SIMC_EPROCLIM 130 +#define _SIMC_EUSERS 131 +#define _SIMC_EDQUOT 132 +#define _SIMC_ESTALE 133 +#define _SIMC_ENOTSUP 134 +#define _SIMC_ENOMEDIUM 135 +#define _SIMC_ENOSHARE 136 +#define _SIMC_ECASECLASH 137 +#define _SIMC_EILSEQ 138 +#define _SIMC_EOVERFLOW 139 + +#endif /* ! _SIMCALL_ERRNO_H */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/simcall-fcntl.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/simcall-fcntl.h new file mode 100644 index 0000000..ce33466 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/simcall-fcntl.h @@ -0,0 +1,21 @@ +/* File control operations for Xtensa ISS semihosting. */ + +/* Copyright (c) 2003 by Tensilica Inc. ALL RIGHTS RESERVED. + These coded instructions, statements, and computer programs are the + copyrighted works and confidential proprietary information of Tensilica Inc. + They may not be modified, copied, reproduced, distributed, or disclosed to + third parties in any manner, medium, or form, in whole or in part, without + the prior written consent of Tensilica Inc. */ + +#ifndef _SIMCALL_FCNTL_H +#define _SIMCALL_FCNTL_H + +#define _SIMC_O_APPEND 0x0008 +#define _SIMC_O_NONBLOCK 0x0080 +#define _SIMC_O_CREAT 0x0100 +#define _SIMC_O_TRUNC 0x0200 +#define _SIMC_O_EXCL 0x0400 +#define _SIMC_O_TEXT 0x4000 +#define _SIMC_O_BINARY 0x8000 + +#endif /* ! _SIMCALL_FCNTL_H */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/simcall.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/simcall.h new file mode 100644 index 0000000..9645370 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/simcall.h @@ -0,0 +1,188 @@ +/* + * simcall.h - Simulator call numbers + * + * Software that runs on a simulated Xtensa processor using + * the instruction set simulator (ISS) can invoke simulator + * services using the SIMCALL instruction. The a2 register + * is set prior to executing SIMCALL to a "simcall number", + * indicating which service to invoke. This file defines the + * simcall numbers defined and/or supported by the Xtensa ISS. + * + * IMPORTANT NOTE: These numbers are highly subject to change! + * + * Copyright (c) 2002-2007 by Tensilica Inc. ALL RIGHTS RESERVED. + * These coded instructions, statements, and computer programs are the + * copyrighted works and confidential proprietary information of Tensilica Inc. + * They may not be modified, copied, reproduced, distributed, or disclosed to + * third parties in any manner, medium, or form, in whole or in part, without + * the prior written consent of Tensilica Inc. + */ + +#ifndef SIMCALL_INCLUDED +#define SIMCALL_INCLUDED + +/* + * System call like services offered by the simulator host. + * These are modeled after the Linux 2.4 kernel system calls + * for Xtensa processors. However not all system calls and + * not all functionality of a given system call are implemented, + * or necessarily have well defined or equivalent semantics in + * the context of a simulation (as opposed to a Unix kernel). + * + * These services behave largely as if they had been invoked + * as a task in the simulator host's operating system + * (eg. files accessed are those of the simulator host). + * However, these SIMCALLs model a virtual operating system + * so that various definitions, bit assignments etc + * (eg. open mode bits, errno values, etc) are independent + * of the host operating system used to run the simulation. + * Rather these definitions are specific to the Xtensa ISS. + * This way Xtensa ISA code written to use these SIMCALLs + * can (in principle) be simulated on any host. + * + * Up to 6 parameters are passed in registers a3 to a8 + * (note the 6th parameter isn't passed on the stack, + * unlike windowed function calling conventions). + * The return value is in a2. A negative value in the + * range -4096 to -1 indicates a negated error code to be + * reported in errno with a return value of -1, otherwise + * the value in a2 is returned as is. + */ + +/* These #defines need to match what's in Xtensa/OS/vxworks/xtiss/simcalls.c */ + +#define SYS_nop 0 /* n/a - setup; used to flush register windows */ +#define SYS_exit 1 /*x*/ +#define SYS_fork 2 +#define SYS_read 3 /*x*/ +#define SYS_write 4 /*x*/ +#define SYS_open 5 /*x*/ +#define SYS_close 6 /*x*/ +#define SYS_rename 7 /*x 38 - waitpid */ +#define SYS_creat 8 /*x*/ +#define SYS_link 9 /*x (not implemented on WIN32) */ +#define SYS_unlink 10 /*x*/ +#define SYS_execv 11 /* n/a - execve */ +#define SYS_execve 12 /* 11 - chdir */ +#define SYS_pipe 13 /* 42 - time */ +#define SYS_stat 14 /* 106 - mknod */ +#define SYS_chmod 15 +#define SYS_chown 16 /* 202 - lchown */ +#define SYS_utime 17 /* 30 - break */ +#define SYS_wait 18 /* n/a - oldstat */ +#define SYS_lseek 19 /*x*/ +#define SYS_getpid 20 +#define SYS_isatty 21 /* n/a - mount */ +#define SYS_fstat 22 /* 108 - oldumount */ +#define SYS_time 23 /* 13 - setuid */ +#define SYS_gettimeofday 24 /*x 78 - getuid (not implemented on WIN32) */ +#define SYS_times 25 /*X 43 - stime (Xtensa-specific implementation) */ +#define SYS_socket 26 +#define SYS_sendto 27 +#define SYS_recvfrom 28 +#define SYS_select_one 29 /* not compitible select, one file descriptor at the time */ +#define SYS_bind 30 +#define SYS_ioctl 31 + +/* + * Other... + */ +#define SYS_iss_argc 1000 /* returns value of argc */ +#define SYS_iss_argv_size 1001 /* bytes needed for argv & arg strings */ +#define SYS_iss_set_argv 1002 /* saves argv & arg strings at given addr */ + +#define SYS_memset 1004 /* fill a range of memory (fast) */ + +/* + * SIMCALLs for the ferret memory debugger. All are invoked by + * libferret.a ... ( Xtensa/Target-Libs/ferret ) + */ +#define SYS_ferret 1010 +#define SYS_malloc 1011 +#define SYS_free 1012 +#define SYS_more_heap 1013 +#define SYS_no_heap 1014 +#define SYS_enter_ferret 1015 +#define SYS_leave_ferret 1016 + +/* + * SIMCALLs for ISS client commands + */ +#define SYS_profile_enable 1020 +#define SYS_profile_disable 1021 +#define SYS_trace_level 1022 +#define SYS_client_command 1023 + +/* + * SIMCALL for simulation mode switching + */ +#define SYS_sim_mode_switch 1030 + +/* + * SIMCALLs for XTMP/XTSC event notify and core stall + */ +#define SYS_event_fire 1040 +#define SYS_event_stall 1041 + +/* + * SIMCALLs for callbacks registered in XTMP/XTSC + */ +#define SYS_callback_first 100 +#define SYS_callback_last 999 + +/* + * User defined simcall + */ +#define SYS_user_simcall 100 + +#define SYS_xmpa_errinfo 200 +#define SYS_xmpa_proc_status 201 +#define SYS_xmpa_proc_start 202 +#define SYS_xmpa_proc_stop 203 +#define SYS_xmpa_proc_mem_read 204 +#define SYS_xmpa_proc_mem_write 205 +#define SYS_xmpa_proc_mem_fill 206 +#define SYS_xmpa_proc_reg_read 207 +#define SYS_xmpa_proc_reg_write 208 + + +/* + * Extra SIMCALLs for GDB: + */ +#define SYS_gdb_break -1 /* invoked by XTOS on user exceptions if EPC points + to a break.n/break, regardless of cause! */ +#define SYS_xmon_out -2 /* invoked by XMON: ... */ +#define SYS_xmon_in -3 /* invoked by XMON: ... */ +#define SYS_xmon_flush -4 /* invoked by XMON: ... */ +#define SYS_gdb_abort -5 /* invoked by XTOS in _xtos_panic() */ +#define SYS_gdb_illegal_inst -6 /* invoked by XTOS for illegal instructions (too deeply) */ +#define SYS_xmon_init -7 /* invoked by XMON: ... */ +#define SYS_gdb_enter_sktloop -8 /* invoked by XTOS on debug exceptions */ +#define SYS_unhandled_kernel_exc -9 /* invoked by XTOS for unhandled kernel exceptions */ +#define SYS_unhandled_user_exc -10 /* invoked by XTOS for unhandled user exceptions */ +#define SYS_unhandled_double_exc -11 /* invoked by XTOS for unhandled double exceptions */ +#define SYS_unhandled_highpri_interrupt -12 /* invoked by XTOS for unhandled high-priority interrupts */ + +/* + * SIMCALLs for vxWorks xtiss BSP: + */ +#define SYS_setup_ppp_pipes -83 +#define SYS_log_msg -84 + +/* + * SYS_select_one specifiers + */ +#define XTISS_SELECT_ONE_READ 1 +#define XTISS_SELECT_ONE_WRITE 2 +#define XTISS_SELECT_ONE_EXCEPT 3 + +/* + * SIMCALL for client calling arbitrary code in a client plug in. + * see clients/xcc_instr to see how this works. + */ + +#define SYS_client 0xC0DECAFE + + + +#endif /* !SIMCALL_INCLUDED */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/specreg.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/specreg.h new file mode 100644 index 0000000..8df479c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/specreg.h @@ -0,0 +1,138 @@ +/* + * Xtensa Special Register symbolic names + */ + +/* $Id: //depot/rel/Boreal/Xtensa/OS/include/xtensa/specreg.h#2 $ */ + +/* + * Copyright (c) 2005-2010 Tensilica Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef XTENSA_SPECREG_H +#define XTENSA_SPECREG_H + +/* Special registers: */ +#define LBEG 0 +#define LEND 1 +#define LCOUNT 2 +#define SAR 3 +#define BR 4 +#define LITBASE 5 +#define SCOMPARE1 12 +#define ACCLO 16 +#define ACCHI 17 +#define MR_0 32 +#define MR_1 33 +#define MR_2 34 +#define MR_3 35 +#define PREFCTL 40 +#define WINDOWBASE 72 +#define WINDOWSTART 73 +#define PTEVADDR 83 +#define RASID 90 +#define ITLBCFG 91 +#define DTLBCFG 92 +#define IBREAKENABLE 96 +#define CACHEATTR 98 +#define DDR 104 +#define IBREAKA_0 128 +#define IBREAKA_1 129 +#define DBREAKA_0 144 +#define DBREAKA_1 145 +#define DBREAKC_0 160 +#define DBREAKC_1 161 +#define EPC_1 177 +#define EPC_2 178 +#define EPC_3 179 +#define EPC_4 180 +#define EPC_5 181 +#define EPC_6 182 +#define EPC_7 183 +#define DEPC 192 +#define EPS_2 194 +#define EPS_3 195 +#define EPS_4 196 +#define EPS_5 197 +#define EPS_6 198 +#define EPS_7 199 +#define EXCSAVE_1 209 +#define EXCSAVE_2 210 +#define EXCSAVE_3 211 +#define EXCSAVE_4 212 +#define EXCSAVE_5 213 +#define EXCSAVE_6 214 +#define EXCSAVE_7 215 +#define CPENABLE 224 +#define INTERRUPT 226 +#define INTREAD INTERRUPT /* alternate name for backward compatibility */ +#define INTSET INTERRUPT /* alternate name for backward compatibility */ +#define INTCLEAR 227 +#define INTENABLE 228 +#define PS 230 +#define VECBASE 231 +#define EXCCAUSE 232 +#define DEBUGCAUSE 233 +#define CCOUNT 234 +#define PRID 235 +#define ICOUNT 236 +#define ICOUNTLEVEL 237 +#define EXCVADDR 238 +#define CCOMPARE_0 240 +#define CCOMPARE_1 241 +#define CCOMPARE_2 242 +#define MISC_REG_0 244 +#define MISC_REG_1 245 +#define MISC_REG_2 246 +#define MISC_REG_3 247 + +/* Special cases (bases of special register series): */ +#define MR 32 +#define IBREAKA 128 +#define DBREAKA 144 +#define DBREAKC 160 +#define EPC 176 +#define EPS 192 +#define EXCSAVE 208 +#define CCOMPARE 240 +#define MISC_REG 244 + +/* Tensilica-defined user registers: */ +#if 0 +/*#define ... 21..24 */ /* (545CK) */ +/*#define ... 140..143 */ /* (545CK) */ +#define EXPSTATE 230 /* Diamond */ +#define THREADPTR 231 /* threadptr option */ +#define FCR 232 /* FPU */ +#define FSR 233 /* FPU */ +#define AE_OVF_SAR 240 /* HiFi2 */ +#define AE_BITHEAD 241 /* HiFi2 */ +#define AE_TS_FTS_BU_BP 242 /* HiFi2 */ +#define AE_SD_NO 243 /* HiFi2 */ +#define VSAR 240 /* VectraLX */ +#define ROUND_LO 242 /* VectraLX */ +#define ROUND_HI 243 /* VectraLX */ +#define CBEGIN 246 /* VectraLX */ +#define CEND 247 /* VectraLX */ +#endif + +#endif /* XTENSA_SPECREG_H */ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_MUL32.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_MUL32.h new file mode 100644 index 0000000..a2dea41 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_MUL32.h @@ -0,0 +1,24 @@ +/* Definitions for the 32-bit Integer Multiply Option. */ + +/* + * Customer ID=7011; Build=0x2b6f6; Copyright (c) 2009 by Tensilica Inc. ALL RIGHTS RESERVED. + * These coded instructions, statements, and computer programs are the + * copyrighted works and confidential proprietary information of Tensilica Inc. + * They may not be modified, copied, reproduced, distributed, or disclosed to + * third parties in any manner, medium, or form, in whole or in part, without + * the prior written consent of Tensilica Inc. + */ + +/* NOTE: This file exists only for backward compatibility with RB-200X.x + and earlier Xtensa releases. Starting with RC-2009.0 you should use + . */ + +#ifndef _XTENSA_xt_MUL32_HEADER +#define _XTENSA_xt_MUL32_HEADER + +#ifdef __XTENSA__ + +#include + +#endif /* __XTENSA__ */ +#endif /* !_XTENSA_xt_MUL32_HEADER */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_core.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_core.h new file mode 100644 index 0000000..796f73f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_core.h @@ -0,0 +1,254 @@ +/* Definitions for the xt_core TIE package */ + +/* + * Customer ID=7011; Build=0x2b6f6; Copyright (c) 2004 by Tensilica Inc. ALL RIGHTS RESERVED. + * These coded instructions, statements, and computer programs are the + * copyrighted works and confidential proprietary information of Tensilica Inc. + * They may not be modified, copied, reproduced, distributed, or disclosed to + * third parties in any manner, medium, or form, in whole or in part, without + * the prior written consent of Tensilica Inc. + */ + +/* Do not modify. This is automatically generated.*/ + +#ifndef _XTENSA_xt_core_HEADER +#define _XTENSA_xt_core_HEADER + +#ifdef __XTENSA__ +#ifdef __XCC__ + + +/* + * The following prototypes describe intrinsic functions + * corresponding to TIE instructions. Some TIE instructions + * may produce multiple results (designated as "out" operands + * in the iclass section) or may have operands used as both + * inputs and outputs (designated as "inout"). However, the C + * and C++ languages do not provide syntax that can express + * the in/out/inout constraints of TIE intrinsics. + * Nevertheless, the compiler understands these constraints + * and will check that the intrinsic functions are used + * correctly. To improve the readability of these prototypes, + * the "out" and "inout" parameters are marked accordingly + * with comments. + */ + +extern void _TIE_xt_core_ILL(void); +extern void _TIE_xt_core_NOP(void); +extern void _TIE_xt_core_MEMW(void); +extern void _TIE_xt_core_EXTW(void); +extern void _TIE_xt_core_ISYNC(void); +extern void _TIE_xt_core_DSYNC(void); +extern void _TIE_xt_core_ESYNC(void); +extern void _TIE_xt_core_RSYNC(void); +extern unsigned _TIE_xt_core_RSR_176(void); +extern void _TIE_xt_core_WSR_176(unsigned art); +extern unsigned _TIE_xt_core_RSR_208(void); +extern unsigned _TIE_xt_core_uint32_loadi(const unsigned * p, immediate o); +extern void _TIE_xt_core_uint32_storei(unsigned c, unsigned * p, immediate o); +extern unsigned _TIE_xt_core_uint32_move(unsigned b); +extern int _TIE_xt_core_ADDI(int s, immediate i); +extern int _TIE_xt_core_OR(int s, int t); +extern int _TIE_xt_core_L32I(const int * p, immediate i); +extern void _TIE_xt_core_S32I(int r, int * p, immediate i); +extern unsigned char _TIE_xt_core_L8UI(const unsigned char * p, immediate i); +extern void _TIE_xt_core_S8I(signed char r, signed char * p, immediate i); +extern unsigned short _TIE_xt_core_L16UI(const unsigned short * p, immediate i); +extern short _TIE_xt_core_L16SI(const short * p, immediate i); +extern void _TIE_xt_core_S16I(short r, short * p, immediate i); +extern int _TIE_xt_core_ADDMI(int s, immediate i); +extern int _TIE_xt_core_ADD(int s, int t); +extern int _TIE_xt_core_ADDX2(int s, int t); +extern int _TIE_xt_core_ADDX4(int s, int t); +extern int _TIE_xt_core_ADDX8(int s, int t); +extern int _TIE_xt_core_SUB(int s, int t); +extern int _TIE_xt_core_SUBX2(int s, int t); +extern int _TIE_xt_core_SUBX4(int s, int t); +extern int _TIE_xt_core_SUBX8(int s, int t); +extern int _TIE_xt_core_AND(int s, int t); +extern int _TIE_xt_core_XOR(int s, int t); +extern unsigned _TIE_xt_core_EXTUI(unsigned t, immediate i, immediate o); +extern int _TIE_xt_core_MOVI(immediate i); +extern void _TIE_xt_core_MOVEQZ(int r /*inout*/, int s, int t); +extern void _TIE_xt_core_MOVNEZ(int r /*inout*/, int s, int t); +extern void _TIE_xt_core_MOVLTZ(int r /*inout*/, int s, int t); +extern void _TIE_xt_core_MOVGEZ(int r /*inout*/, int s, int t); +extern int _TIE_xt_core_NEG(int t); +extern int _TIE_xt_core_ABS(int t); +extern void _TIE_xt_core_SSR(int s); +extern void _TIE_xt_core_SSL(int s); +extern void _TIE_xt_core_SSA8L(int s); +extern void _TIE_xt_core_SSA8B(int s); +extern void _TIE_xt_core_SSAI(immediate i); +extern int _TIE_xt_core_SLL(int s); +extern int _TIE_xt_core_SRC(int s, int t); +extern unsigned _TIE_xt_core_SRL(unsigned t); +extern int _TIE_xt_core_SRA(int t); +extern int _TIE_xt_core_SLLI(int s, immediate i); +extern int _TIE_xt_core_SRAI(int t, immediate i); +extern unsigned _TIE_xt_core_SRLI(unsigned t, immediate i); +extern int _TIE_xt_core_SSAI_SRC(int src1, int src2, immediate amount); +extern int _TIE_xt_core_SSR_SRC(int src1, int src2, int amount); +extern int _TIE_xt_core_WSR_SAR_SRC(int src1, int src2, int amount); +extern int _TIE_xt_core_SSR_SRA(int src, int amount); +extern unsigned _TIE_xt_core_SSR_SRL(unsigned src, int amount); +extern int _TIE_xt_core_SSL_SLL(int src, int amount); +extern int _TIE_xt_core_RSIL(immediate t); +extern unsigned _TIE_xt_core_RSR_SAR(void); +extern void _TIE_xt_core_WSR_SAR(unsigned t); +extern void _TIE_xt_core_XSR_SAR(unsigned t /*inout*/); +extern unsigned _TIE_xt_core_RSR_LITBASE(void); +extern void _TIE_xt_core_WSR_LITBASE(unsigned t); +extern void _TIE_xt_core_XSR_LITBASE(unsigned t /*inout*/); +extern unsigned _TIE_xt_core_RSR_PS(void); +extern void _TIE_xt_core_WSR_PS(unsigned t); +extern void _TIE_xt_core_XSR_PS(unsigned t /*inout*/); +extern unsigned _TIE_xt_core_RSR_EPC1(void); +extern void _TIE_xt_core_WSR_EPC1(unsigned t); +extern void _TIE_xt_core_XSR_EPC1(unsigned t /*inout*/); +extern unsigned _TIE_xt_core_RSR_EXCSAVE1(void); +extern void _TIE_xt_core_WSR_EXCSAVE1(unsigned t); +extern void _TIE_xt_core_XSR_EXCSAVE1(unsigned t /*inout*/); +extern unsigned _TIE_xt_core_RSR_EPC2(void); +extern void _TIE_xt_core_WSR_EPC2(unsigned t); +extern void _TIE_xt_core_XSR_EPC2(unsigned t /*inout*/); +extern unsigned _TIE_xt_core_RSR_EXCSAVE2(void); +extern void _TIE_xt_core_WSR_EXCSAVE2(unsigned t); +extern void _TIE_xt_core_XSR_EXCSAVE2(unsigned t /*inout*/); +extern unsigned _TIE_xt_core_RSR_EPC3(void); +extern void _TIE_xt_core_WSR_EPC3(unsigned t); +extern void _TIE_xt_core_XSR_EPC3(unsigned t /*inout*/); +extern unsigned _TIE_xt_core_RSR_EXCSAVE3(void); +extern void _TIE_xt_core_WSR_EXCSAVE3(unsigned t); +extern void _TIE_xt_core_XSR_EXCSAVE3(unsigned t /*inout*/); +extern unsigned _TIE_xt_core_RSR_VECBASE(void); +extern void _TIE_xt_core_WSR_VECBASE(unsigned t); +extern void _TIE_xt_core_XSR_VECBASE(unsigned t /*inout*/); +extern unsigned _TIE_xt_core_RSR_EPS2(void); +extern void _TIE_xt_core_WSR_EPS2(unsigned t); +extern void _TIE_xt_core_XSR_EPS2(unsigned t /*inout*/); +extern unsigned _TIE_xt_core_RSR_EPS3(void); +extern void _TIE_xt_core_WSR_EPS3(unsigned t); +extern void _TIE_xt_core_XSR_EPS3(unsigned t /*inout*/); +extern unsigned _TIE_xt_core_RSR_EXCCAUSE(void); +extern void _TIE_xt_core_WSR_EXCCAUSE(unsigned t); +extern void _TIE_xt_core_XSR_EXCCAUSE(unsigned t /*inout*/); +extern unsigned _TIE_xt_core_RSR_EXCVADDR(void); +extern void _TIE_xt_core_WSR_EXCVADDR(unsigned t); +extern void _TIE_xt_core_XSR_EXCVADDR(unsigned t /*inout*/); +extern unsigned _TIE_xt_core_RSR_DEPC(void); +extern void _TIE_xt_core_WSR_DEPC(unsigned t); +extern void _TIE_xt_core_XSR_DEPC(unsigned t /*inout*/); +extern int _TIE_xt_core_RSR_PRID(void); +#define XT_ILL _TIE_xt_core_ILL +#define XT_NOP _TIE_xt_core_NOP +#define XT_MEMW _TIE_xt_core_MEMW +#define XT_EXTW _TIE_xt_core_EXTW +#define XT_ISYNC _TIE_xt_core_ISYNC +#define XT_DSYNC _TIE_xt_core_DSYNC +#define XT_ESYNC _TIE_xt_core_ESYNC +#define XT_RSYNC _TIE_xt_core_RSYNC +#define XT_RSR_176 _TIE_xt_core_RSR_176 +#define XT_WSR_176 _TIE_xt_core_WSR_176 +#define XT_RSR_208 _TIE_xt_core_RSR_208 +#define XT_uint32_loadi _TIE_xt_core_uint32_loadi +#define XT_uint32_storei _TIE_xt_core_uint32_storei +#define XT_uint32_move _TIE_xt_core_uint32_move +#define XT_ADDI _TIE_xt_core_ADDI +#define XT_OR _TIE_xt_core_OR +#define XT_L32I _TIE_xt_core_L32I +#define XT_S32I _TIE_xt_core_S32I +#define XT_L8UI _TIE_xt_core_L8UI +#define XT_S8I _TIE_xt_core_S8I +#define XT_L16UI _TIE_xt_core_L16UI +#define XT_L16SI _TIE_xt_core_L16SI +#define XT_S16I _TIE_xt_core_S16I +#define XT_ADDMI _TIE_xt_core_ADDMI +#define XT_ADD _TIE_xt_core_ADD +#define XT_ADDX2 _TIE_xt_core_ADDX2 +#define XT_ADDX4 _TIE_xt_core_ADDX4 +#define XT_ADDX8 _TIE_xt_core_ADDX8 +#define XT_SUB _TIE_xt_core_SUB +#define XT_SUBX2 _TIE_xt_core_SUBX2 +#define XT_SUBX4 _TIE_xt_core_SUBX4 +#define XT_SUBX8 _TIE_xt_core_SUBX8 +#define XT_AND _TIE_xt_core_AND +#define XT_XOR _TIE_xt_core_XOR +#define XT_EXTUI _TIE_xt_core_EXTUI +#define XT_MOVI _TIE_xt_core_MOVI +#define XT_MOVEQZ _TIE_xt_core_MOVEQZ +#define XT_MOVNEZ _TIE_xt_core_MOVNEZ +#define XT_MOVLTZ _TIE_xt_core_MOVLTZ +#define XT_MOVGEZ _TIE_xt_core_MOVGEZ +#define XT_NEG _TIE_xt_core_NEG +#define XT_ABS _TIE_xt_core_ABS +#define XT_SSR _TIE_xt_core_SSR +#define XT_SSL _TIE_xt_core_SSL +#define XT_SSA8L _TIE_xt_core_SSA8L +#define XT_SSA8B _TIE_xt_core_SSA8B +#define XT_SSAI _TIE_xt_core_SSAI +#define XT_SLL _TIE_xt_core_SLL +#define XT_SRC _TIE_xt_core_SRC +#define XT_SRL _TIE_xt_core_SRL +#define XT_SRA _TIE_xt_core_SRA +#define XT_SLLI _TIE_xt_core_SLLI +#define XT_SRAI _TIE_xt_core_SRAI +#define XT_SRLI _TIE_xt_core_SRLI +#define XT_SSAI_SRC _TIE_xt_core_SSAI_SRC +#define XT_SSR_SRC _TIE_xt_core_SSR_SRC +#define XT_WSR_SAR_SRC _TIE_xt_core_WSR_SAR_SRC +#define XT_SSR_SRA _TIE_xt_core_SSR_SRA +#define XT_SSR_SRL _TIE_xt_core_SSR_SRL +#define XT_SSL_SLL _TIE_xt_core_SSL_SLL +#define XT_RSIL _TIE_xt_core_RSIL +#define XT_RSR_SAR _TIE_xt_core_RSR_SAR +#define XT_WSR_SAR _TIE_xt_core_WSR_SAR +#define XT_XSR_SAR _TIE_xt_core_XSR_SAR +#define XT_RSR_LITBASE _TIE_xt_core_RSR_LITBASE +#define XT_WSR_LITBASE _TIE_xt_core_WSR_LITBASE +#define XT_XSR_LITBASE _TIE_xt_core_XSR_LITBASE +#define XT_RSR_PS _TIE_xt_core_RSR_PS +#define XT_WSR_PS _TIE_xt_core_WSR_PS +#define XT_XSR_PS _TIE_xt_core_XSR_PS +#define XT_RSR_EPC1 _TIE_xt_core_RSR_EPC1 +#define XT_WSR_EPC1 _TIE_xt_core_WSR_EPC1 +#define XT_XSR_EPC1 _TIE_xt_core_XSR_EPC1 +#define XT_RSR_EXCSAVE1 _TIE_xt_core_RSR_EXCSAVE1 +#define XT_WSR_EXCSAVE1 _TIE_xt_core_WSR_EXCSAVE1 +#define XT_XSR_EXCSAVE1 _TIE_xt_core_XSR_EXCSAVE1 +#define XT_RSR_EPC2 _TIE_xt_core_RSR_EPC2 +#define XT_WSR_EPC2 _TIE_xt_core_WSR_EPC2 +#define XT_XSR_EPC2 _TIE_xt_core_XSR_EPC2 +#define XT_RSR_EXCSAVE2 _TIE_xt_core_RSR_EXCSAVE2 +#define XT_WSR_EXCSAVE2 _TIE_xt_core_WSR_EXCSAVE2 +#define XT_XSR_EXCSAVE2 _TIE_xt_core_XSR_EXCSAVE2 +#define XT_RSR_EPC3 _TIE_xt_core_RSR_EPC3 +#define XT_WSR_EPC3 _TIE_xt_core_WSR_EPC3 +#define XT_XSR_EPC3 _TIE_xt_core_XSR_EPC3 +#define XT_RSR_EXCSAVE3 _TIE_xt_core_RSR_EXCSAVE3 +#define XT_WSR_EXCSAVE3 _TIE_xt_core_WSR_EXCSAVE3 +#define XT_XSR_EXCSAVE3 _TIE_xt_core_XSR_EXCSAVE3 +#define XT_RSR_VECBASE _TIE_xt_core_RSR_VECBASE +#define XT_WSR_VECBASE _TIE_xt_core_WSR_VECBASE +#define XT_XSR_VECBASE _TIE_xt_core_XSR_VECBASE +#define XT_RSR_EPS2 _TIE_xt_core_RSR_EPS2 +#define XT_WSR_EPS2 _TIE_xt_core_WSR_EPS2 +#define XT_XSR_EPS2 _TIE_xt_core_XSR_EPS2 +#define XT_RSR_EPS3 _TIE_xt_core_RSR_EPS3 +#define XT_WSR_EPS3 _TIE_xt_core_WSR_EPS3 +#define XT_XSR_EPS3 _TIE_xt_core_XSR_EPS3 +#define XT_RSR_EXCCAUSE _TIE_xt_core_RSR_EXCCAUSE +#define XT_WSR_EXCCAUSE _TIE_xt_core_WSR_EXCCAUSE +#define XT_XSR_EXCCAUSE _TIE_xt_core_XSR_EXCCAUSE +#define XT_RSR_EXCVADDR _TIE_xt_core_RSR_EXCVADDR +#define XT_WSR_EXCVADDR _TIE_xt_core_WSR_EXCVADDR +#define XT_XSR_EXCVADDR _TIE_xt_core_XSR_EXCVADDR +#define XT_RSR_DEPC _TIE_xt_core_RSR_DEPC +#define XT_WSR_DEPC _TIE_xt_core_WSR_DEPC +#define XT_XSR_DEPC _TIE_xt_core_XSR_DEPC +#define XT_RSR_PRID _TIE_xt_core_RSR_PRID + +#endif /* __XCC__ */ + +#endif /* __XTENSA__ */ +#endif /* !_XTENSA_xt_core_HEADER */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_debug.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_debug.h new file mode 100644 index 0000000..7d57acf --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_debug.h @@ -0,0 +1,93 @@ +/* Definitions for the xt_debug TIE package */ + +/* + * Customer ID=7011; Build=0x2b6f6; Copyright (c) 2004 by Tensilica Inc. ALL RIGHTS RESERVED. + * These coded instructions, statements, and computer programs are the + * copyrighted works and confidential proprietary information of Tensilica Inc. + * They may not be modified, copied, reproduced, distributed, or disclosed to + * third parties in any manner, medium, or form, in whole or in part, without + * the prior written consent of Tensilica Inc. + */ + +/* Do not modify. This is automatically generated.*/ + +#ifndef _XTENSA_xt_debug_HEADER +#define _XTENSA_xt_debug_HEADER + +#ifdef __XTENSA__ +#ifdef __XCC__ + +#include + +/* + * The following prototypes describe intrinsic functions + * corresponding to TIE instructions. Some TIE instructions + * may produce multiple results (designated as "out" operands + * in the iclass section) or may have operands used as both + * inputs and outputs (designated as "inout"). However, the C + * and C++ languages do not provide syntax that can express + * the in/out/inout constraints of TIE intrinsics. + * Nevertheless, the compiler understands these constraints + * and will check that the intrinsic functions are used + * correctly. To improve the readability of these prototypes, + * the "out" and "inout" parameters are marked accordingly + * with comments. + */ + +extern void _TIE_xt_debug_BREAK(immediate imms, immediate immt); +extern void _TIE_xt_debug_BREAK_N(immediate imms); +extern unsigned _TIE_xt_debug_RSR_DBREAKA0(void); +extern void _TIE_xt_debug_WSR_DBREAKA0(unsigned art); +extern void _TIE_xt_debug_XSR_DBREAKA0(unsigned art /*inout*/); +extern unsigned _TIE_xt_debug_RSR_DBREAKC0(void); +extern void _TIE_xt_debug_WSR_DBREAKC0(unsigned art); +extern void _TIE_xt_debug_XSR_DBREAKC0(unsigned art /*inout*/); +extern unsigned _TIE_xt_debug_RSR_IBREAKA0(void); +extern void _TIE_xt_debug_WSR_IBREAKA0(unsigned art); +extern void _TIE_xt_debug_XSR_IBREAKA0(unsigned art /*inout*/); +extern unsigned _TIE_xt_debug_RSR_IBREAKENABLE(void); +extern void _TIE_xt_debug_WSR_IBREAKENABLE(unsigned art); +extern void _TIE_xt_debug_XSR_IBREAKENABLE(unsigned art /*inout*/); +extern unsigned _TIE_xt_debug_RSR_DEBUGCAUSE(void); +extern void _TIE_xt_debug_WSR_DEBUGCAUSE(unsigned art); +extern void _TIE_xt_debug_XSR_DEBUGCAUSE(unsigned art /*inout*/); +extern unsigned _TIE_xt_debug_RSR_ICOUNT(void); +extern void _TIE_xt_debug_WSR_ICOUNT(unsigned art); +extern void _TIE_xt_debug_XSR_ICOUNT(unsigned art /*inout*/); +extern unsigned _TIE_xt_debug_RSR_ICOUNTLEVEL(void); +extern void _TIE_xt_debug_WSR_ICOUNTLEVEL(unsigned art); +extern void _TIE_xt_debug_XSR_ICOUNTLEVEL(unsigned art /*inout*/); +extern unsigned _TIE_xt_debug_RSR_DDR(void); +extern void _TIE_xt_debug_WSR_DDR(unsigned art); +extern void _TIE_xt_debug_XSR_DDR(unsigned art /*inout*/); +#define XT_BREAK _TIE_xt_debug_BREAK +#define XT_BREAK_N _TIE_xt_debug_BREAK_N +#define XT_RSR_DBREAKA0 _TIE_xt_debug_RSR_DBREAKA0 +#define XT_WSR_DBREAKA0 _TIE_xt_debug_WSR_DBREAKA0 +#define XT_XSR_DBREAKA0 _TIE_xt_debug_XSR_DBREAKA0 +#define XT_RSR_DBREAKC0 _TIE_xt_debug_RSR_DBREAKC0 +#define XT_WSR_DBREAKC0 _TIE_xt_debug_WSR_DBREAKC0 +#define XT_XSR_DBREAKC0 _TIE_xt_debug_XSR_DBREAKC0 +#define XT_RSR_IBREAKA0 _TIE_xt_debug_RSR_IBREAKA0 +#define XT_WSR_IBREAKA0 _TIE_xt_debug_WSR_IBREAKA0 +#define XT_XSR_IBREAKA0 _TIE_xt_debug_XSR_IBREAKA0 +#define XT_RSR_IBREAKENABLE _TIE_xt_debug_RSR_IBREAKENABLE +#define XT_WSR_IBREAKENABLE _TIE_xt_debug_WSR_IBREAKENABLE +#define XT_XSR_IBREAKENABLE _TIE_xt_debug_XSR_IBREAKENABLE +#define XT_RSR_DEBUGCAUSE _TIE_xt_debug_RSR_DEBUGCAUSE +#define XT_WSR_DEBUGCAUSE _TIE_xt_debug_WSR_DEBUGCAUSE +#define XT_XSR_DEBUGCAUSE _TIE_xt_debug_XSR_DEBUGCAUSE +#define XT_RSR_ICOUNT _TIE_xt_debug_RSR_ICOUNT +#define XT_WSR_ICOUNT _TIE_xt_debug_WSR_ICOUNT +#define XT_XSR_ICOUNT _TIE_xt_debug_XSR_ICOUNT +#define XT_RSR_ICOUNTLEVEL _TIE_xt_debug_RSR_ICOUNTLEVEL +#define XT_WSR_ICOUNTLEVEL _TIE_xt_debug_WSR_ICOUNTLEVEL +#define XT_XSR_ICOUNTLEVEL _TIE_xt_debug_XSR_ICOUNTLEVEL +#define XT_RSR_DDR _TIE_xt_debug_RSR_DDR +#define XT_WSR_DDR _TIE_xt_debug_WSR_DDR +#define XT_XSR_DDR _TIE_xt_debug_XSR_DDR + +#endif /* __XCC__ */ + +#endif /* __XTENSA__ */ +#endif /* !_XTENSA_xt_debug_HEADER */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_density.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_density.h new file mode 100644 index 0000000..04ffabb --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_density.h @@ -0,0 +1,57 @@ +/* Definitions for the xt_density TIE package */ + +/* + * Customer ID=7011; Build=0x2b6f6; Copyright (c) 2004 by Tensilica Inc. ALL RIGHTS RESERVED. + * These coded instructions, statements, and computer programs are the + * copyrighted works and confidential proprietary information of Tensilica Inc. + * They may not be modified, copied, reproduced, distributed, or disclosed to + * third parties in any manner, medium, or form, in whole or in part, without + * the prior written consent of Tensilica Inc. + */ + +/* Do not modify. This is automatically generated.*/ + +#ifndef _XTENSA_xt_density_HEADER +#define _XTENSA_xt_density_HEADER + +#ifdef __XTENSA__ +#ifdef __XCC__ + +#include + +/* + * The following prototypes describe intrinsic functions + * corresponding to TIE instructions. Some TIE instructions + * may produce multiple results (designated as "out" operands + * in the iclass section) or may have operands used as both + * inputs and outputs (designated as "inout"). However, the C + * and C++ languages do not provide syntax that can express + * the in/out/inout constraints of TIE intrinsics. + * Nevertheless, the compiler understands these constraints + * and will check that the intrinsic functions are used + * correctly. To improve the readability of these prototypes, + * the "out" and "inout" parameters are marked accordingly + * with comments. + */ + +extern void _TIE_xt_density_ILL_N(void); +extern void _TIE_xt_density_NOP_N(void); +extern int _TIE_xt_density_L32I_N(const int * p, immediate i); +extern void _TIE_xt_density_S32I_N(int t, int * p, immediate i); +extern int _TIE_xt_density_ADD_N(int s, int t); +extern int _TIE_xt_density_ADDI_N(int s, immediate i); +extern int _TIE_xt_density_MOV_N(int s); +extern int _TIE_xt_density_MOVI_N(immediate i); +#define XT_ILL_N _TIE_xt_density_ILL_N +#define XT_NOP_N _TIE_xt_density_NOP_N +#define XT_L32I_N _TIE_xt_density_L32I_N +#define XT_S32I_N _TIE_xt_density_S32I_N +#define XT_ADD_N _TIE_xt_density_ADD_N +#define XT_ADDI_N _TIE_xt_density_ADDI_N +#define XT_MOV_N _TIE_xt_density_MOV_N +#define XT_MOVI_N _TIE_xt_density_MOVI_N + +#endif /* __XCC__ */ + +#endif /* __XTENSA__ */ +#endif /* !_XTENSA_xt_density_HEADER */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_exceptions.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_exceptions.h new file mode 100644 index 0000000..f632a4c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_exceptions.h @@ -0,0 +1,46 @@ +/* Definitions for the xt_exceptions TIE package */ + +/* + * Customer ID=7011; Build=0x2b6f6; Copyright (c) 2004 by Tensilica Inc. ALL RIGHTS RESERVED. + * These coded instructions, statements, and computer programs are the + * copyrighted works and confidential proprietary information of Tensilica Inc. + * They may not be modified, copied, reproduced, distributed, or disclosed to + * third parties in any manner, medium, or form, in whole or in part, without + * the prior written consent of Tensilica Inc. + */ + +/* Do not modify. This is automatically generated.*/ + +#ifndef _XTENSA_xt_exceptions_HEADER +#define _XTENSA_xt_exceptions_HEADER + +#ifdef __XTENSA__ +#ifdef __XCC__ + + +/* + * The following prototypes describe intrinsic functions + * corresponding to TIE instructions. Some TIE instructions + * may produce multiple results (designated as "out" operands + * in the iclass section) or may have operands used as both + * inputs and outputs (designated as "inout"). However, the C + * and C++ languages do not provide syntax that can express + * the in/out/inout constraints of TIE intrinsics. + * Nevertheless, the compiler understands these constraints + * and will check that the intrinsic functions are used + * correctly. To improve the readability of these prototypes, + * the "out" and "inout" parameters are marked accordingly + * with comments. + */ + +extern void _TIE_xt_exceptions_EXCW(void); +extern void _TIE_xt_exceptions_SYSCALL(void); +extern void _TIE_xt_exceptions_SIMCALL(void); +#define XT_EXCW _TIE_xt_exceptions_EXCW +#define XT_SYSCALL _TIE_xt_exceptions_SYSCALL +#define XT_SIMCALL _TIE_xt_exceptions_SIMCALL + +#endif /* __XCC__ */ + +#endif /* __XTENSA__ */ +#endif /* !_XTENSA_xt_exceptions_HEADER */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_externalregisters.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_externalregisters.h new file mode 100644 index 0000000..51913d5 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_externalregisters.h @@ -0,0 +1,44 @@ +/* Definitions for the xt_externalregisters TIE package */ + +/* + * Customer ID=7011; Build=0x2b6f6; Copyright (c) 2004 by Tensilica Inc. ALL RIGHTS RESERVED. + * These coded instructions, statements, and computer programs are the + * copyrighted works and confidential proprietary information of Tensilica Inc. + * They may not be modified, copied, reproduced, distributed, or disclosed to + * third parties in any manner, medium, or form, in whole or in part, without + * the prior written consent of Tensilica Inc. + */ + +/* Do not modify. This is automatically generated.*/ + +#ifndef _XTENSA_xt_externalregisters_HEADER +#define _XTENSA_xt_externalregisters_HEADER + +#ifdef __XTENSA__ +#ifdef __XCC__ + + +/* + * The following prototypes describe intrinsic functions + * corresponding to TIE instructions. Some TIE instructions + * may produce multiple results (designated as "out" operands + * in the iclass section) or may have operands used as both + * inputs and outputs (designated as "inout"). However, the C + * and C++ languages do not provide syntax that can express + * the in/out/inout constraints of TIE intrinsics. + * Nevertheless, the compiler understands these constraints + * and will check that the intrinsic functions are used + * correctly. To improve the readability of these prototypes, + * the "out" and "inout" parameters are marked accordingly + * with comments. + */ + +extern void _TIE_xt_externalregisters_RER(void); +extern void _TIE_xt_externalregisters_WER(void); +#define XT_RER _TIE_xt_externalregisters_RER +#define XT_WER _TIE_xt_externalregisters_WER + +#endif /* __XCC__ */ + +#endif /* __XTENSA__ */ +#endif /* !_XTENSA_xt_externalregisters_HEADER */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_interrupt.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_interrupt.h new file mode 100644 index 0000000..f6ffb6e --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_interrupt.h @@ -0,0 +1,55 @@ +/* Definitions for the xt_interrupt TIE package */ + +/* + * Customer ID=7011; Build=0x2b6f6; Copyright (c) 2004 by Tensilica Inc. ALL RIGHTS RESERVED. + * These coded instructions, statements, and computer programs are the + * copyrighted works and confidential proprietary information of Tensilica Inc. + * They may not be modified, copied, reproduced, distributed, or disclosed to + * third parties in any manner, medium, or form, in whole or in part, without + * the prior written consent of Tensilica Inc. + */ + +/* Do not modify. This is automatically generated.*/ + +#ifndef _XTENSA_xt_interrupt_HEADER +#define _XTENSA_xt_interrupt_HEADER + +#ifdef __XTENSA__ +#ifdef __XCC__ + +#include + +/* + * The following prototypes describe intrinsic functions + * corresponding to TIE instructions. Some TIE instructions + * may produce multiple results (designated as "out" operands + * in the iclass section) or may have operands used as both + * inputs and outputs (designated as "inout"). However, the C + * and C++ languages do not provide syntax that can express + * the in/out/inout constraints of TIE intrinsics. + * Nevertheless, the compiler understands these constraints + * and will check that the intrinsic functions are used + * correctly. To improve the readability of these prototypes, + * the "out" and "inout" parameters are marked accordingly + * with comments. + */ + +extern void _TIE_xt_interrupt_WAITI(immediate s); +extern unsigned _TIE_xt_interrupt_RSR_INTERRUPT(void); +extern void _TIE_xt_interrupt_WSR_INTSET(unsigned art); +extern void _TIE_xt_interrupt_WSR_INTCLEAR(unsigned art); +extern unsigned _TIE_xt_interrupt_RSR_INTENABLE(void); +extern void _TIE_xt_interrupt_WSR_INTENABLE(unsigned art); +extern void _TIE_xt_interrupt_XSR_INTENABLE(unsigned art /*inout*/); +#define XT_WAITI _TIE_xt_interrupt_WAITI +#define XT_RSR_INTERRUPT _TIE_xt_interrupt_RSR_INTERRUPT +#define XT_WSR_INTSET _TIE_xt_interrupt_WSR_INTSET +#define XT_WSR_INTCLEAR _TIE_xt_interrupt_WSR_INTCLEAR +#define XT_RSR_INTENABLE _TIE_xt_interrupt_RSR_INTENABLE +#define XT_WSR_INTENABLE _TIE_xt_interrupt_WSR_INTENABLE +#define XT_XSR_INTENABLE _TIE_xt_interrupt_XSR_INTENABLE + +#endif /* __XCC__ */ + +#endif /* __XTENSA__ */ +#endif /* !_XTENSA_xt_interrupt_HEADER */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_misc.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_misc.h new file mode 100644 index 0000000..2d8fcf0 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_misc.h @@ -0,0 +1,45 @@ +/* Definitions for the xt_misc TIE package */ + +/* + * Customer ID=7011; Build=0x2b6f6; Copyright (c) 2004 by Tensilica Inc. ALL RIGHTS RESERVED. + * These coded instructions, statements, and computer programs are the + * copyrighted works and confidential proprietary information of Tensilica Inc. + * They may not be modified, copied, reproduced, distributed, or disclosed to + * third parties in any manner, medium, or form, in whole or in part, without + * the prior written consent of Tensilica Inc. + */ + +/* Do not modify. This is automatically generated.*/ + +#ifndef _XTENSA_xt_misc_HEADER +#define _XTENSA_xt_misc_HEADER + +#ifdef __XTENSA__ +#ifdef __XCC__ + +#include + +/* + * The following prototypes describe intrinsic functions + * corresponding to TIE instructions. Some TIE instructions + * may produce multiple results (designated as "out" operands + * in the iclass section) or may have operands used as both + * inputs and outputs (designated as "inout"). However, the C + * and C++ languages do not provide syntax that can express + * the in/out/inout constraints of TIE intrinsics. + * Nevertheless, the compiler understands these constraints + * and will check that the intrinsic functions are used + * correctly. To improve the readability of these prototypes, + * the "out" and "inout" parameters are marked accordingly + * with comments. + */ + +extern int _TIE_xt_misc_NSA(int s); +extern unsigned _TIE_xt_misc_NSAU(unsigned s); +#define XT_NSA _TIE_xt_misc_NSA +#define XT_NSAU _TIE_xt_misc_NSAU + +#endif /* __XCC__ */ + +#endif /* __XTENSA__ */ +#endif /* !_XTENSA_xt_misc_HEADER */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_mmu.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_mmu.h new file mode 100644 index 0000000..4ecd59e --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_mmu.h @@ -0,0 +1,61 @@ +/* Definitions for the xt_mmu TIE package */ + +/* + * Customer ID=7011; Build=0x2b6f6; Copyright (c) 2004 by Tensilica Inc. ALL RIGHTS RESERVED. + * These coded instructions, statements, and computer programs are the + * copyrighted works and confidential proprietary information of Tensilica Inc. + * They may not be modified, copied, reproduced, distributed, or disclosed to + * third parties in any manner, medium, or form, in whole or in part, without + * the prior written consent of Tensilica Inc. + */ + +/* Do not modify. This is automatically generated.*/ + +#ifndef _XTENSA_xt_mmu_HEADER +#define _XTENSA_xt_mmu_HEADER + +#ifdef __XTENSA__ +#ifdef __XCC__ + +#include + +/* + * The following prototypes describe intrinsic functions + * corresponding to TIE instructions. Some TIE instructions + * may produce multiple results (designated as "out" operands + * in the iclass section) or may have operands used as both + * inputs and outputs (designated as "inout"). However, the C + * and C++ languages do not provide syntax that can express + * the in/out/inout constraints of TIE intrinsics. + * Nevertheless, the compiler understands these constraints + * and will check that the intrinsic functions are used + * correctly. To improve the readability of these prototypes, + * the "out" and "inout" parameters are marked accordingly + * with comments. + */ + +extern void _TIE_xt_mmu_IDTLB(unsigned ars); +extern unsigned _TIE_xt_mmu_RDTLB1(unsigned ars); +extern unsigned _TIE_xt_mmu_RDTLB0(unsigned ars); +extern unsigned _TIE_xt_mmu_PDTLB(unsigned ars); +extern void _TIE_xt_mmu_WDTLB(unsigned art, unsigned ars); +extern void _TIE_xt_mmu_IITLB(unsigned ars); +extern unsigned _TIE_xt_mmu_RITLB1(unsigned ars); +extern unsigned _TIE_xt_mmu_RITLB0(unsigned ars); +extern unsigned _TIE_xt_mmu_PITLB(unsigned ars); +extern void _TIE_xt_mmu_WITLB(unsigned art, unsigned ars); +#define XT_IDTLB _TIE_xt_mmu_IDTLB +#define XT_RDTLB1 _TIE_xt_mmu_RDTLB1 +#define XT_RDTLB0 _TIE_xt_mmu_RDTLB0 +#define XT_PDTLB _TIE_xt_mmu_PDTLB +#define XT_WDTLB _TIE_xt_mmu_WDTLB +#define XT_IITLB _TIE_xt_mmu_IITLB +#define XT_RITLB1 _TIE_xt_mmu_RITLB1 +#define XT_RITLB0 _TIE_xt_mmu_RITLB0 +#define XT_PITLB _TIE_xt_mmu_PITLB +#define XT_WITLB _TIE_xt_mmu_WITLB + +#endif /* __XCC__ */ + +#endif /* __XTENSA__ */ +#endif /* !_XTENSA_xt_mmu_HEADER */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_mul.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_mul.h new file mode 100644 index 0000000..42599f2 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_mul.h @@ -0,0 +1,47 @@ +/* Definitions for the xt_mul TIE package */ + +/* + * Customer ID=7011; Build=0x2b6f6; Copyright (c) 2004 by Tensilica Inc. ALL RIGHTS RESERVED. + * These coded instructions, statements, and computer programs are the + * copyrighted works and confidential proprietary information of Tensilica Inc. + * They may not be modified, copied, reproduced, distributed, or disclosed to + * third parties in any manner, medium, or form, in whole or in part, without + * the prior written consent of Tensilica Inc. + */ + +/* Do not modify. This is automatically generated.*/ + +#ifndef _XTENSA_xt_mul_HEADER +#define _XTENSA_xt_mul_HEADER + +#ifdef __XTENSA__ +#ifdef __XCC__ + +#include + +/* + * The following prototypes describe intrinsic functions + * corresponding to TIE instructions. Some TIE instructions + * may produce multiple results (designated as "out" operands + * in the iclass section) or may have operands used as both + * inputs and outputs (designated as "inout"). However, the C + * and C++ languages do not provide syntax that can express + * the in/out/inout constraints of TIE intrinsics. + * Nevertheless, the compiler understands these constraints + * and will check that the intrinsic functions are used + * correctly. To improve the readability of these prototypes, + * the "out" and "inout" parameters are marked accordingly + * with comments. + */ + +extern int _TIE_xt_mul_MUL16S(short s, short t); +extern unsigned _TIE_xt_mul_MUL16U(unsigned short s, unsigned short t); +extern int _TIE_xt_mul_MULL(int s, int t); +#define XT_MUL16S _TIE_xt_mul_MUL16S +#define XT_MUL16U _TIE_xt_mul_MUL16U +#define XT_MULL _TIE_xt_mul_MULL + +#endif /* __XCC__ */ + +#endif /* __XTENSA__ */ +#endif /* !_XTENSA_xt_mul_HEADER */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_timer.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_timer.h new file mode 100644 index 0000000..a30d3fb --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_timer.h @@ -0,0 +1,53 @@ +/* Definitions for the xt_timer TIE package */ + +/* + * Customer ID=7011; Build=0x2b6f6; Copyright (c) 2004 by Tensilica Inc. ALL RIGHTS RESERVED. + * These coded instructions, statements, and computer programs are the + * copyrighted works and confidential proprietary information of Tensilica Inc. + * They may not be modified, copied, reproduced, distributed, or disclosed to + * third parties in any manner, medium, or form, in whole or in part, without + * the prior written consent of Tensilica Inc. + */ + +/* Do not modify. This is automatically generated.*/ + +#ifndef _XTENSA_xt_timer_HEADER +#define _XTENSA_xt_timer_HEADER + +#ifdef __XTENSA__ +#ifdef __XCC__ + +#include + +/* + * The following prototypes describe intrinsic functions + * corresponding to TIE instructions. Some TIE instructions + * may produce multiple results (designated as "out" operands + * in the iclass section) or may have operands used as both + * inputs and outputs (designated as "inout"). However, the C + * and C++ languages do not provide syntax that can express + * the in/out/inout constraints of TIE intrinsics. + * Nevertheless, the compiler understands these constraints + * and will check that the intrinsic functions are used + * correctly. To improve the readability of these prototypes, + * the "out" and "inout" parameters are marked accordingly + * with comments. + */ + +extern unsigned _TIE_xt_timer_RSR_CCOUNT(void); +extern void _TIE_xt_timer_WSR_CCOUNT(unsigned art); +extern void _TIE_xt_timer_XSR_CCOUNT(unsigned art /*inout*/); +extern unsigned _TIE_xt_timer_RSR_CCOMPARE0(void); +extern void _TIE_xt_timer_WSR_CCOMPARE0(unsigned art); +extern void _TIE_xt_timer_XSR_CCOMPARE0(unsigned art /*inout*/); +#define XT_RSR_CCOUNT _TIE_xt_timer_RSR_CCOUNT +#define XT_WSR_CCOUNT _TIE_xt_timer_WSR_CCOUNT +#define XT_XSR_CCOUNT _TIE_xt_timer_XSR_CCOUNT +#define XT_RSR_CCOMPARE0 _TIE_xt_timer_RSR_CCOMPARE0 +#define XT_WSR_CCOMPARE0 _TIE_xt_timer_WSR_CCOMPARE0 +#define XT_XSR_CCOMPARE0 _TIE_xt_timer_XSR_CCOMPARE0 + +#endif /* __XCC__ */ + +#endif /* __XTENSA__ */ +#endif /* !_XTENSA_xt_timer_HEADER */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_trace.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_trace.h new file mode 100644 index 0000000..9f26438 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/tie/xt_trace.h @@ -0,0 +1,43 @@ +/* Definitions for the xt_trace TIE package */ + +/* + * Customer ID=7011; Build=0x2b6f6; Copyright (c) 2004 by Tensilica Inc. ALL RIGHTS RESERVED. + * These coded instructions, statements, and computer programs are the + * copyrighted works and confidential proprietary information of Tensilica Inc. + * They may not be modified, copied, reproduced, distributed, or disclosed to + * third parties in any manner, medium, or form, in whole or in part, without + * the prior written consent of Tensilica Inc. + */ + +/* Do not modify. This is automatically generated.*/ + +#ifndef _XTENSA_xt_trace_HEADER +#define _XTENSA_xt_trace_HEADER + +#ifdef __XTENSA__ +#ifdef __XCC__ + +#include + +/* + * The following prototypes describe intrinsic functions + * corresponding to TIE instructions. Some TIE instructions + * may produce multiple results (designated as "out" operands + * in the iclass section) or may have operands used as both + * inputs and outputs (designated as "inout"). However, the C + * and C++ languages do not provide syntax that can express + * the in/out/inout constraints of TIE intrinsics. + * Nevertheless, the compiler understands these constraints + * and will check that the intrinsic functions are used + * correctly. To improve the readability of these prototypes, + * the "out" and "inout" parameters are marked accordingly + * with comments. + */ + +extern void _TIE_xt_trace_WSR_MMID(unsigned art); +#define XT_WSR_MMID _TIE_xt_trace_WSR_MMID + +#endif /* __XCC__ */ + +#endif /* __XTENSA__ */ +#endif /* !_XTENSA_xt_trace_HEADER */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/xtensa-libdb-macros.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/xtensa-libdb-macros.h new file mode 100644 index 0000000..7f5f8f3 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/xtensa-libdb-macros.h @@ -0,0 +1,165 @@ +/* + * xtensa-libdb-macros.h + */ + +/* $Id: //depot/rel/Boreal/Xtensa/Software/libdb/xtensa-libdb-macros.h#2 $ */ + +/* Copyright (c) 2004-2008 Tensilica Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef __H_LIBDB_MACROS +#define __H_LIBDB_MACROS + +/* + * This header file provides macros used to construct, identify and use + * "target numbers" that are assigned to various types of Xtensa processor + * registers and states. These target numbers are used by GDB in the remote + * protocol, and are thus used by all GDB debugger agents (targets). + * They are also used in ELF debugger information sections (stabs, dwarf, etc). + * + * These macros are separated from xtensa-libdb.h because they are needed + * by certain debugger agents that do not use or have access to libdb, + * e.g. the OCD daemon, RedBoot, XMON, etc. + * + * For the time being, for compatibility with certain 3rd party debugger + * software vendors, target numbers are limited to 16 bits. It is + * conceivable that this will be extended in the future to 32 bits. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef uint32 + #define uint32 unsigned int +#endif +#ifndef int32 + #define int32 int +#endif + + +/* + * Macros to form register "target numbers" for various standard registers/states: + */ +#define XTENSA_DBREGN_INVALID -1 /* not a valid target number */ +#define XTENSA_DBREGN_A(n) (0x0000+(n)) /* address registers a0..a15 */ +#define XTENSA_DBREGN_B(n) (0x0010+(n)) /* boolean bits b0..b15 */ +#define XTENSA_DBREGN_PC 0x0020 /* program counter */ + /* 0x0021 RESERVED for use by Tensilica */ +#define XTENSA_DBREGN_BO(n) (0x0022+(n)) /* boolean octuple-bits bo0..bo1 */ +#define XTENSA_DBREGN_BQ(n) (0x0024+(n)) /* boolean quadruple-bits bq0..bq3 */ +#define XTENSA_DBREGN_BD(n) (0x0028+(n)) /* boolean double-bits bd0..bd7 */ +#define XTENSA_DBREGN_F(n) (0x0030+(n)) /* floating point registers f0..f15 */ +#define XTENSA_DBREGN_VEC(n) (0x0040+(n)) /* Vectra vec regs v0..v15 */ +#define XTENSA_DBREGN_VSEL(n) (0x0050+(n)) /* Vectra sel s0..s3 (V1) ..s7 (V2) */ +#define XTENSA_DBREGN_VALIGN(n) (0x0058+(n)) /* Vectra valign regs u0..u3 */ +#define XTENSA_DBREGN_VCOEFF(n) (0x005C+(n)) /* Vectra I vcoeff regs c0..c1 */ + /* 0x005E..0x005F RESERVED for use by Tensilica */ +#define XTENSA_DBREGN_AEP(n) (0x0060+(n)) /* HiFi2 Audio Engine regs aep0..aep7 */ +#define XTENSA_DBREGN_AEQ(n) (0x0068+(n)) /* HiFi2 Audio Engine regs aeq0..aeq3 */ + /* 0x006C..0x006F RESERVED for use by Tensilica */ +#define XTENSA_DBREGN_DF(n) (0x0070+(n)) /* double floating point registers df0..df15 */ + /* 0x0080..0x00FF RESERVED for use by Tensilica */ +#define XTENSA_DBREGN_AR(n) (0x0100+(n)) /* physical address regs ar0..ar63 + (note: only with window option) */ + /* 0x0140..0x01FF RESERVED for use by Tensilica */ +#define XTENSA_DBREGN_SREG(n) (0x0200+(n)) /* special registers 0..255 (core) */ +#define XTENSA_DBREGN_BR XTENSA_DBREGN_SREG(0x04) /* all 16 boolean bits, BR */ +#define XTENSA_DBREGN_MR(n) XTENSA_DBREGN_SREG(0x20+(n)) /* MAC16 registers m0..m3 */ +#define XTENSA_DBREGN_UREG(n) (0x0300+(n)) /* user registers 0..255 (TIE) */ + /* 0x0400..0x0FFF RESERVED for use by Tensilica */ + /* 0x1000..0x1FFF user-defined regfiles */ + /* 0x2000..0xEFFF other states (and regfiles) */ +#define XTENSA_DBREGN_DBAGENT(n) (0xF000+(n)) /* non-processor "registers" 0..4095 for + 3rd-party debugger agent defined use */ + /* > 0xFFFF (32-bit) RESERVED for use by Tensilica */ +/*#define XTENSA_DBREGN_CONTEXT(n) (0x02000000+((n)<<20))*/ /* add this macro's value to a target + number to identify a specific context 0..31 + for context-replicated registers */ +#define XTENSA_DBREGN_MASK 0xFFFF /* mask of valid target_number bits */ +#define XTENSA_DBREGN_WRITE_SIDE 0x04000000 /* flag to request write half of a register + split into distinct read and write entries + with the same target number (currently only + valid in a couple of libdb API functions; + see xtensa-libdb.h for details) */ + +/* + * Macros to identify specific ranges of target numbers (formed above): + * NOTE: any context number (or other upper 12 bits) are considered + * modifiers and are thus stripped out for identification purposes. + */ +#define XTENSA_DBREGN_IS_VALID(tn) (((tn) & ~0xFFFF) == 0) /* just tests it's 16-bit unsigned */ +#define XTENSA_DBREGN_IS_A(tn) (((tn) & 0xFFF0)==0x0000) /* is a0..a15 */ +#define XTENSA_DBREGN_IS_B(tn) (((tn) & 0xFFF0)==0x0010) /* is b0..b15 */ +#define XTENSA_DBREGN_IS_PC(tn) (((tn) & 0xFFFF)==0x0020) /* is program counter */ +#define XTENSA_DBREGN_IS_BO(tn) (((tn) & 0xFFFE)==0x0022) /* is bo0..bo1 */ +#define XTENSA_DBREGN_IS_BQ(tn) (((tn) & 0xFFFC)==0x0024) /* is bq0..bq3 */ +#define XTENSA_DBREGN_IS_BD(tn) (((tn) & 0xFFF8)==0x0028) /* is bd0..bd7 */ +#define XTENSA_DBREGN_IS_F(tn) (((tn) & 0xFFF0)==0x0030) /* is f0..f15 */ +#define XTENSA_DBREGN_IS_VEC(tn) (((tn) & 0xFFF0)==0x0040) /* is v0..v15 */ +#define XTENSA_DBREGN_IS_VSEL(tn) (((tn) & 0xFFF8)==0x0050) /* is s0..s7 (s0..s3 in V1) */ +#define XTENSA_DBREGN_IS_VALIGN(tn) (((tn) & 0xFFFC)==0x0058) /* is u0..u3 */ +#define XTENSA_DBREGN_IS_VCOEFF(tn) (((tn) & 0xFFFE)==0x005C) /* is c0..c1 */ +#define XTENSA_DBREGN_IS_AEP(tn) (((tn) & 0xFFF8)==0x0060) /* is aep0..aep7 */ +#define XTENSA_DBREGN_IS_AEQ(tn) (((tn) & 0xFFFC)==0x0068) /* is aeq0..aeq3 */ +#define XTENSA_DBREGN_IS_DF(tn) (((tn) & 0xFFF0)==0x0070) /* is df0..df15 */ +#define XTENSA_DBREGN_IS_AR(tn) (((tn) & 0xFFC0)==0x0100) /* is ar0..ar63 */ +#define XTENSA_DBREGN_IS_SREG(tn) (((tn) & 0xFF00)==0x0200) /* is special register */ +#define XTENSA_DBREGN_IS_BR(tn) (((tn) & 0xFFFF)==XTENSA_DBREGN_SREG(0x04)) /* is BR */ +#define XTENSA_DBREGN_IS_MR(tn) (((tn) & 0xFFFC)==XTENSA_DBREGN_SREG(0x20)) /* m0..m3 */ +#define XTENSA_DBREGN_IS_UREG(tn) (((tn) & 0xFF00)==0x0300) /* is user register */ +#define XTENSA_DBREGN_IS_DBAGENT(tn) (((tn) & 0xF000)==0xF000) /* is non-processor */ +/*#define XTENSA_DBREGN_IS_CONTEXT(tn) (((tn) & 0x02000000) != 0)*/ /* specifies context # */ + +/* + * Macros to extract register index from a register "target number" + * when a specific range has been identified using one of the _IS_ macros above. + * These macros only return a useful value if the corresponding _IS_ macro returns true. + */ +#define XTENSA_DBREGN_A_INDEX(tn) ((tn) & 0x0F) /* 0..15 for a0..a15 */ +#define XTENSA_DBREGN_B_INDEX(tn) ((tn) & 0x0F) /* 0..15 for b0..b15 */ +#define XTENSA_DBREGN_BO_INDEX(tn) ((tn) & 0x01) /* 0..1 for bo0..bo1 */ +#define XTENSA_DBREGN_BQ_INDEX(tn) ((tn) & 0x03) /* 0..3 for bq0..bq3 */ +#define XTENSA_DBREGN_BD_INDEX(tn) ((tn) & 0x07) /* 0..7 for bd0..bd7 */ +#define XTENSA_DBREGN_F_INDEX(tn) ((tn) & 0x0F) /* 0..15 for f0..f15 */ +#define XTENSA_DBREGN_VEC_INDEX(tn) ((tn) & 0x0F) /* 0..15 for v0..v15 */ +#define XTENSA_DBREGN_VSEL_INDEX(tn) ((tn) & 0x07) /* 0..7 for s0..s7 */ +#define XTENSA_DBREGN_VALIGN_INDEX(tn) ((tn) & 0x03) /* 0..3 for u0..u3 */ +#define XTENSA_DBREGN_VCOEFF_INDEX(tn) ((tn) & 0x01) /* 0..1 for c0..c1 */ +#define XTENSA_DBREGN_AEP_INDEX(tn) ((tn) & 0x07) /* 0..7 for aep0..aep7 */ +#define XTENSA_DBREGN_AEQ_INDEX(tn) ((tn) & 0x03) /* 0..3 for aeq0..aeq3 */ +#define XTENSA_DBREGN_DF_INDEX(tn) ((tn) & 0x0F) /* 0..15 for df0..df15 */ +#define XTENSA_DBREGN_AR_INDEX(tn) ((tn) & 0x3F) /* 0..63 for ar0..ar63 */ +#define XTENSA_DBREGN_SREG_INDEX(tn) ((tn) & 0xFF) /* 0..255 for special registers */ +#define XTENSA_DBREGN_MR_INDEX(tn) ((tn) & 0x03) /* 0..3 for m0..m3 */ +#define XTENSA_DBREGN_UREG_INDEX(tn) ((tn) & 0xFF) /* 0..255 for user registers */ +#define XTENSA_DBREGN_DBAGENT_INDEX(tn) ((tn) & 0xFFF) /* 0..4095 for non-processor */ +/*#define XTENSA_DBREGN_CONTEXT_INDEX(tn) (((tn) >> 20) & 0x1F)*/ /* 0..31 context numbers */ + + + + +#ifdef __cplusplus +} +#endif + +#endif /* __H_LIBDB_MACROS */ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/xtensa-xer.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/xtensa-xer.h new file mode 100644 index 0000000..9098c7d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/xtensa-xer.h @@ -0,0 +1,149 @@ +/* xer-constants.h -- various constants describing external registers accessed + via wer and rer. + + TODO: find a better prefix. Also conditionalize certain constants based + on number of cores and interrupts actually present. +*/ + +/* + * Copyright (c) 1999-2008 Tensilica Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#define NUM_INTERRUPTS 27 +#define NUM_CORES 4 + +/* Routing of NMI (BInterrupt2) and interrupts 0..n-1 (BInterrupt3+) + RER reads + WER writes + */ + +#define XER_MIROUT 0x0000 +#define XER_MIROUT_LAST (XER_MIROUT + NUM_INTERRUPTS) + + +/* IPI to core M (all 16 causes). + + RER reads + WER clears + */ +#define XER_MIPICAUSE 0x0100 +#define XER_MIPICAUSE_FIELD_A_FIRST 0x0 +#define XER_MIPICAUSE_FIELD_A_LAST 0x0 +#define XER_MIPICAUSE_FIELD_B_FIRST 0x1 +#define XER_MIPICAUSE_FIELD_B_LAST 0x3 +#define XER_MIPICAUSE_FIELD_C_FIRST 0x4 +#define XER_MIPICAUSE_FIELD_C_LAST 0x7 +#define XER_MIPICAUSE_FIELD_D_FIRST 0x8 +#define XER_MIPICAUSE_FIELD_D_LAST 0xF + + +/* IPI from cause bit 0..15 + + RER invalid + WER sets +*/ +#define XER_MIPISET 0x0140 +#define XER_MIPISET_LAST 0x014F + + +/* Global enable + + RER read + WER clear +*/ +#define XER_MIENG 0x0180 + + +/* Global enable + + RER invalid + WER set +*/ +#define XER_MIENG_SET 0x0184 + +/* Global assert + + RER read + WER clear +*/ +#define XER_MIASG 0x0188 + + +/* Global enable + + RER invalid + WER set +*/ +#define XER_MIASG_SET 0x018C + + +/* IPI partition register + + RER read + WER write +*/ +#define XER_PART 0x0190 +#define XER_IPI0 0x0 +#define XER_IPI1 0x1 +#define XER_IPI2 0x2 +#define XER_IPI3 0x3 + +#define XER_PART_ROUTE_IPI(NUM, FIELD) ((NUM) << ((FIELD) << 2)) + +#define XER_PART_ROUTE_IPI_CAUSE(TO_A, TO_B, TO_C, TO_D) \ + (XER_PART_ROUTE_IPI(TO_A, XER_IPI0) | \ + XER_PART_ROUTE_IPI(TO_B, XER_IPI1) | \ + XER_PART_ROUTE_IPI(TO_C, XER_IPI2) | \ + XER_PART_ROUTE_IPI(TO_D, XER_IPI3)) + +#define XER_IPI_WAKE_EXT_INTERRUPT XCHAL_EXTINT0_NUM +#define XER_IPI_WAKE_CAUSE XER_MIPICAUSE_FIELD_C_FIRST +#define XER_IPI_WAKE_ADDRESS (XER_MIPISET + XER_IPI_WAKE_CAUSE) +#define XER_DEFAULT_IPI_ROUTING XER_PART_ROUTE_IPI_CAUSE(XER_IPI1, XER_IPI0, XER_IPI2, XER_IPI3) + + +/* System configuration ID + + RER read + WER invalid +*/ +#define XER_SYSCFGID 0x01A0 + + +/* RunStall to slave processors + + RER read + WER write +*/ +#define XER_MPSCORE 0x0200 + + +/* Cache coherency ON + + RER read + WER write +*/ +#define XER_CCON 0x0220 + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/xtruntime-frames.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/xtruntime-frames.h new file mode 100644 index 0000000..793a69f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/xtruntime-frames.h @@ -0,0 +1,160 @@ +/* xtruntime-frames.h - exception stack frames for single-threaded run-time */ +/* $Id: //depot/rel/Boreal/Xtensa/OS/include/xtensa/xtruntime-frames.h#2 $ */ + +/* + * Copyright (c) 2002-2007 Tensilica Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _XTRUNTIME_FRAMES_H_ +#define _XTRUNTIME_FRAMES_H_ + +#include + +/* Macros that help define structures for both C and assembler: */ +#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__) +#define STRUCT_BEGIN .pushsection .text; .struct 0 +#define STRUCT_FIELD(ctype,size,pre,name) pre##name: .space size +#define STRUCT_AFIELD(ctype,size,pre,name,n) pre##name: .space (size)*(n) +#define STRUCT_END(sname) sname##Size:; .popsection +#else /*_ASMLANGUAGE||__ASSEMBLER__*/ +#define STRUCT_BEGIN typedef struct { +#define STRUCT_FIELD(ctype,size,pre,name) ctype name; +#define STRUCT_AFIELD(ctype,size,pre,name,n) ctype name[n]; +#define STRUCT_END(sname) } sname; +#endif /*_ASMLANGUAGE||__ASSEMBLER__*/ + + +/* + * Kernel vector mode exception stack frame. + * + * NOTE: due to the limited range of addi used in the current + * kernel exception vector, and the fact that historically + * the vector is limited to 12 bytes, the size of this + * stack frame is limited to 128 bytes (currently at 64). + */ +STRUCT_BEGIN +STRUCT_FIELD (long,4,KEXC_,pc) /* "parm" */ +STRUCT_FIELD (long,4,KEXC_,ps) +STRUCT_AFIELD(long,4,KEXC_,areg, 4) /* a12 .. a15 */ +STRUCT_FIELD (long,4,KEXC_,sar) /* "save" */ +#if XCHAL_HAVE_LOOPS +STRUCT_FIELD (long,4,KEXC_,lcount) +STRUCT_FIELD (long,4,KEXC_,lbeg) +STRUCT_FIELD (long,4,KEXC_,lend) +#endif +#if XCHAL_HAVE_MAC16 +STRUCT_FIELD (long,4,KEXC_,acclo) +STRUCT_FIELD (long,4,KEXC_,acchi) +STRUCT_AFIELD(long,4,KEXC_,mr, 4) +#endif +STRUCT_END(KernelFrame) + + +/* + * User vector mode exception stack frame: + * + * WARNING: if you modify this structure, you MUST modify the + * computation of the pad size (ALIGNPAD) accordingly. + */ +STRUCT_BEGIN +STRUCT_FIELD (long,4,UEXC_,pc) +STRUCT_FIELD (long,4,UEXC_,ps) +STRUCT_FIELD (long,4,UEXC_,sar) +STRUCT_FIELD (long,4,UEXC_,vpri) +#ifdef __XTENSA_CALL0_ABI__ +STRUCT_FIELD (long,4,UEXC_,a0) +#endif +STRUCT_FIELD (long,4,UEXC_,a2) +STRUCT_FIELD (long,4,UEXC_,a3) +STRUCT_FIELD (long,4,UEXC_,a4) +STRUCT_FIELD (long,4,UEXC_,a5) +#ifdef __XTENSA_CALL0_ABI__ +STRUCT_FIELD (long,4,UEXC_,a6) +STRUCT_FIELD (long,4,UEXC_,a7) +STRUCT_FIELD (long,4,UEXC_,a8) +STRUCT_FIELD (long,4,UEXC_,a9) +STRUCT_FIELD (long,4,UEXC_,a10) +STRUCT_FIELD (long,4,UEXC_,a11) +STRUCT_FIELD (long,4,UEXC_,a12) +STRUCT_FIELD (long,4,UEXC_,a13) +STRUCT_FIELD (long,4,UEXC_,a14) +STRUCT_FIELD (long,4,UEXC_,a15) +#endif +STRUCT_FIELD (long,4,UEXC_,exccause) /* NOTE: can probably rid of this one (pass direct) */ +#if XCHAL_HAVE_LOOPS +STRUCT_FIELD (long,4,UEXC_,lcount) +STRUCT_FIELD (long,4,UEXC_,lbeg) +STRUCT_FIELD (long,4,UEXC_,lend) +#endif +#if XCHAL_HAVE_MAC16 +STRUCT_FIELD (long,4,UEXC_,acclo) +STRUCT_FIELD (long,4,UEXC_,acchi) +STRUCT_AFIELD(long,4,UEXC_,mr, 4) +#endif +/* ALIGNPAD is the 16-byte alignment padding. */ +#ifdef __XTENSA_CALL0_ABI__ +# define CALL0_ABI 1 +#else +# define CALL0_ABI 0 +#endif +#define ALIGNPAD ((3 + XCHAL_HAVE_LOOPS*1 + XCHAL_HAVE_MAC16*2 + CALL0_ABI*1) & 3) +#if ALIGNPAD +STRUCT_AFIELD(long,4,UEXC_,pad, ALIGNPAD) /* 16-byte alignment padding */ +#endif +/*STRUCT_AFIELD(char,1,UEXC_,ureg, (XCHAL_CPEXTRA_SA_SIZE_TOR2+3)&-4)*/ /* not used, and doesn't take alignment into account */ +STRUCT_END(UserFrame) + + +#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__) + + +/* Check for UserFrameSize small enough not to require rounding...: */ + /* Skip 16-byte save area, then 32-byte space for 8 regs of call12 + * (which overlaps with 16-byte GCC nested func chaining area), + * then exception stack frame: */ + .set UserFrameTotalSize, 16+32+UserFrameSize + /* Greater than 112 bytes? (max range of ADDI, both signs, when aligned to 16 bytes): */ + .ifgt UserFrameTotalSize-112 + /* Round up to 256-byte multiple to accelerate immediate adds: */ + .set UserFrameTotalSize, ((UserFrameTotalSize+255) & 0xFFFFFF00) + .endif +# define ESF_TOTALSIZE UserFrameTotalSize + +#endif /* _ASMLANGUAGE || __ASSEMBLER__ */ + + +#if XCHAL_NUM_CONTEXTS > 1 +/* Structure of info stored on new context's stack for setup: */ +STRUCT_BEGIN +STRUCT_FIELD (long,4,INFO_,sp) +STRUCT_FIELD (long,4,INFO_,arg1) +STRUCT_FIELD (long,4,INFO_,funcpc) +STRUCT_FIELD (long,4,INFO_,prevps) +STRUCT_END(SetupInfo) +#endif + + +#define KERNELSTACKSIZE 1024 + + +#endif /* _XTRUNTIME_FRAMES_H_ */ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/xtruntime.h b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/xtruntime.h new file mode 100644 index 0000000..7ca6bd3 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/extra_include/xtensa/xtruntime.h @@ -0,0 +1,184 @@ +/* + * xtruntime.h -- general C definitions for single-threaded run-time + * + * Copyright (c) 2002-2008 Tensilica Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef XTRUNTIME_H +#define XTRUNTIME_H + +#include +#include + +#ifndef XTSTR +#define _XTSTR(x) # x +#define XTSTR(x) _XTSTR(x) +#endif + +#define _xtos_set_execption_handler _xtos_set_exception_handler /* backward compatibility */ +#define _xtos_set_saved_intenable _xtos_ints_on /* backward compatibility */ +#define _xtos_clear_saved_intenable _xtos_ints_off /* backward compatibility */ + +#if !defined(_ASMLANGUAGE) && !defined(__ASSEMBLER__) + +#ifdef __cplusplus +extern "C" { +#endif + +/*typedef void (_xtos_timerdelta_func)(int);*/ +#ifdef __cplusplus +typedef void (_xtos_handler_func)(...); +#else +typedef void (_xtos_handler_func)(); +#endif +typedef _xtos_handler_func *_xtos_handler; + +/* + * unsigned XTOS_SET_INTLEVEL(int intlevel); + * This macro sets the current interrupt level. + * The 'intlevel' parameter must be a constant. + * This macro returns a 32-bit value that must be passed to + * XTOS_RESTORE_INTLEVEL() to restore the previous interrupt level. + * XTOS_RESTORE_JUST_INTLEVEL() also does this, but in XEA2 configs + * it restores only PS.INTLEVEL rather than the entire PS register + * and thus is slower. + */ +#if !XCHAL_HAVE_INTERRUPTS +# define XTOS_SET_INTLEVEL(intlevel) 0 +# define XTOS_SET_MIN_INTLEVEL(intlevel) 0 +# define XTOS_RESTORE_INTLEVEL(restoreval) +# define XTOS_RESTORE_JUST_INTLEVEL(restoreval) +#elif XCHAL_HAVE_XEA2 +/* In XEA2, we can simply safely set PS.INTLEVEL directly: */ +/* NOTE: these asm macros don't modify memory, but they are marked + * as such to act as memory access barriers to the compiler because + * these macros are sometimes used to delineate critical sections; + * function calls are natural barriers (the compiler does not know + * whether a function modifies memory) unless declared to be inlined. */ +# define XTOS_SET_INTLEVEL(intlevel) ({ unsigned __tmp; \ + __asm__ __volatile__( "rsil %0, " XTSTR(intlevel) "\n" \ + : "=a" (__tmp) : : "memory" ); \ + __tmp;}) +# define XTOS_SET_MIN_INTLEVEL(intlevel) ({ unsigned __tmp, __tmp2, __tmp3; \ + __asm__ __volatile__( "rsr %0, " XTSTR(PS) "\n" /* get old (current) PS.INTLEVEL */ \ + "movi %2, " XTSTR(intlevel) "\n" \ + "extui %1, %0, 0, 4\n" /* keep only INTLEVEL bits of parameter */ \ + "blt %2, %1, 1f\n" \ + "rsil %0, " XTSTR(intlevel) "\n" \ + "1:\n" \ + : "=a" (__tmp), "=&a" (__tmp2), "=&a" (__tmp3) : : "memory" ); \ + __tmp;}) +# define XTOS_RESTORE_INTLEVEL(restoreval) do{ unsigned __tmp = (restoreval); \ + __asm__ __volatile__( "wsr %0, " XTSTR(PS) " ; rsync\n" \ + : : "a" (__tmp) : "memory" ); \ + }while(0) +# define XTOS_RESTORE_JUST_INTLEVEL(restoreval) _xtos_set_intlevel(restoreval) +#else +/* In XEA1, we have to rely on INTENABLE register virtualization: */ +extern unsigned _xtos_set_vpri( unsigned vpri ); +extern unsigned _xtos_vpri_enabled; /* current virtual priority */ +# define XTOS_SET_INTLEVEL(intlevel) _xtos_set_vpri(~XCHAL_INTLEVEL_ANDBELOW_MASK(intlevel)) +# define XTOS_SET_MIN_INTLEVEL(intlevel) _xtos_set_vpri(_xtos_vpri_enabled & ~XCHAL_INTLEVEL_ANDBELOW_MASK(intlevel)) +# define XTOS_RESTORE_INTLEVEL(restoreval) _xtos_set_vpri(restoreval) +# define XTOS_RESTORE_JUST_INTLEVEL(restoreval) _xtos_set_vpri(restoreval) +#endif + +/* + * The following macros build upon the above. They are generally used + * instead of invoking the SET_INTLEVEL and SET_MIN_INTLEVEL macros directly. + * They all return a value that can be used with XTOS_RESTORE_INTLEVEL() + * or _xtos_restore_intlevel() or _xtos_restore_just_intlevel() to restore + * the effective interrupt level to what it was before the macro was invoked. + * In XEA2, the DISABLE macros are much faster than the MASK macros + * (in all configs, DISABLE sets the effective interrupt level, whereas MASK + * makes ensures the effective interrupt level is at least the level given + * without lowering it; in XEA2 with INTENABLE virtualization, these macros + * affect PS.INTLEVEL only, not the virtual priority, so DISABLE has partial + * MASK semantics). + * + * A typical critical section sequence might be: + * unsigned rval = XTOS_DISABLE_EXCM_INTERRUPTS; + * ... critical section ... + * XTOS_RESTORE_INTLEVEL(rval); + */ +/* Enable all interrupts (those activated with _xtos_ints_on()): */ +#define XTOS_ENABLE_INTERRUPTS XTOS_SET_INTLEVEL(0) +/* Disable low priority level interrupts (they can interact with the OS): */ +#define XTOS_DISABLE_LOWPRI_INTERRUPTS XTOS_SET_INTLEVEL(XCHAL_NUM_LOWPRI_LEVELS) +#define XTOS_MASK_LOWPRI_INTERRUPTS XTOS_SET_MIN_INTLEVEL(XCHAL_NUM_LOWPRI_LEVELS) +/* Disable interrupts that can interact with the OS: */ +#define XTOS_DISABLE_EXCM_INTERRUPTS XTOS_SET_INTLEVEL(XCHAL_EXCM_LEVEL) +#define XTOS_MASK_EXCM_INTERRUPTS XTOS_SET_MIN_INTLEVEL(XCHAL_EXCM_LEVEL) +#if 0 /* XTOS_LOCK_LEVEL is not exported to applications */ +/* Disable interrupts that can interact with the OS, or manipulate virtual INTENABLE: */ +#define XTOS_DISABLE_LOCK_INTERRUPTS XTOS_SET_INTLEVEL(XTOS_LOCK_LEVEL) +#define XTOS_MASK_LOCK_INTERRUPTS XTOS_SET_MIN_INTLEVEL(XTOS_LOCK_LEVEL) +#endif +/* Disable ALL interrupts (not for common use, particularly if one's processor + * configuration has high-level interrupts and one cares about their latency): */ +#define XTOS_DISABLE_ALL_INTERRUPTS XTOS_SET_INTLEVEL(15) + + +extern unsigned int _xtos_ints_off( unsigned int mask ); +extern unsigned int _xtos_ints_on( unsigned int mask ); +extern unsigned _xtos_set_intlevel( int intlevel ); +extern unsigned _xtos_set_min_intlevel( int intlevel ); +extern unsigned _xtos_restore_intlevel( unsigned restoreval ); +extern unsigned _xtos_restore_just_intlevel( unsigned restoreval ); +extern _xtos_handler _xtos_set_interrupt_handler( int n, _xtos_handler f ); +extern _xtos_handler _xtos_set_interrupt_handler_arg( int n, _xtos_handler f, void *arg ); +extern _xtos_handler _xtos_set_exception_handler( int n, _xtos_handler f ); + +extern void _xtos_memep_initrams( void ); +extern void _xtos_memep_enable( int flags ); + +/* Deprecated (but kept because they were documented): */ +extern unsigned int _xtos_read_ints( void ); /* use xthal_get_interrupt() instead */ +extern void _xtos_clear_ints( unsigned int mask ); /* use xthal_set_intclear() instead */ + +#if XCHAL_NUM_CONTEXTS > 1 +extern unsigned _xtos_init_context(int context_num, int stack_size, + _xtos_handler_func *start_func, int arg1); +#endif + +/* Deprecated: */ +#if XCHAL_NUM_TIMERS > 0 +extern void _xtos_timer_0_delta( int cycles ); +#endif +#if XCHAL_NUM_TIMERS > 1 +extern void _xtos_timer_1_delta( int cycles ); +#endif +#if XCHAL_NUM_TIMERS > 2 +extern void _xtos_timer_2_delta( int cycles ); +#endif +#if XCHAL_NUM_TIMERS > 3 +extern void _xtos_timer_3_delta( int cycles ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* !_ASMLANGUAGE && !__ASSEMBLER__ */ + +#endif /* XTRUNTIME_H */ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/espressif/airkiss.h b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/airkiss.h new file mode 100644 index 0000000..79d2d9a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/airkiss.h @@ -0,0 +1,150 @@ +/* + * 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; + +/** \defgroup WiFi_APIs WiFi Related APIs + * @brief WiFi APIs + */ + +/** @addtogroup WiFi_APIs + * @{ + */ + +/** \defgroup AirKiss_APIs AirKiss APIs + * @brief AirKiss APIs + * + * API airkiss_lan_recv and airkiss_lan_pack are provided for the function that AirKiss can detect + * the ESP8266 devices in LAN, more details about AirKiss please refer to WeChat : http://iot.weixin.qq.com. + * + * Workflow : Create a UDP transmission. When UDP data is received, call API airkiss_lan_recv and + * input the UDP data, if the airkiss_lan_recv returns AIRKISS_LAN_SSDP_REQ, airkiss_lan_pack + * can be called to make a response packet. + * + */ + +/** @addtogroup AirKiss_APIs + * @{ + */ + +/** + * @brief Get the version information of AirKiss lib. + * + * @attention The lenth of version is unknown + * + * @param null. + * + * @return the version information of AirKiss lib + */ + +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 Parse the UDP packet sent by AirKiss. + * + * @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. + * + * @param airkiss_lan_cmdid_t ak_lan_cmdid : type of the packet. + * @param void* appid : Vendor's Wechat public number id, got from WeChat. + * @param void* deviceid : device model id, got from WeChat. + * @param void* _datain : user data waiting for packet assembly. + * @param unsigned short inlength : the lenth of user data. + * @param void* _dataout : data buffer addr, to store the packet got by _datain packet assembly. + * @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/Distrib/ESPressif/RTOS/1.5.0/include/espressif/c_types.h b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/c_types.h new file mode 100644 index 0000000..7893416 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/c_types.h @@ -0,0 +1,114 @@ +/* + * ESPRSSIF 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 _C_TYPES_H_ +#define _C_TYPES_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef uint8_t u8_t; +typedef int8_t s8_t; +typedef uint16_t u16_t; +typedef int16_t s16_t; +typedef uint32_t u32_t; +typedef int32_t s32_t; + +typedef uint8_t uint8; +typedef uint8_t u8; +typedef int8_t sint8; +typedef int8_t int8; +typedef int8_t s8; +typedef uint16_t uint16; +typedef uint16_t u16; +typedef int16_t sint16; +typedef int16_t s16; +typedef uint32_t uint32; +typedef uint32_t u_int; +typedef uint32_t u32; +typedef int32_t sint32; +typedef int32_t s32; +typedef int32_t int32; +typedef int64_t sint64; +typedef uint64_t uint64; +typedef uint64_t u64; +typedef float real32; +typedef double real64; + +#define __le16 u16 + +#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_WRITE(_r, _v) (*(volatile uint32 *)(_r)) = (_v) +#define REG_READ(_r) (*(volatile uint32 *)(_r)) + +#define REG_SET_BIT(_r, _b) (*(volatile uint32 *)(_r) |= (_b)) +#define REG_CLR_BIT(_r, _b) (*(volatile uint32 *)(_r) &= ~(_b)) + +#define __packed __attribute__((packed)) +#define STORE_ATTR __attribute__((aligned(4))) + +#define SHMEM_ATTR + +#ifdef ICACHE_FLASH +#define ICACHE_FLASH_ATTR __attribute__((section(".irom0.text"))) +#else +#define ICACHE_FLASH_ATTR +#endif + +#define DMEM_ATTR __attribute__((section(".bss"))) +#define IRAM_ATTR __attribute__((section(".text"))) +#define ICACHE_RODATA_ATTR __attribute__((section(".irom.text"))) + +#ifndef __cplusplus +#define BOOL bool +#define TRUE true +#define FALSE false +#endif /* !__cplusplus */ + +#ifdef __cplusplus +} +#endif + +#endif /* _C_TYPES_H_ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/eagle_soc.h b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/eagle_soc.h new file mode 100644 index 0000000..9f6f351 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/eagle_soc.h @@ -0,0 +1,126 @@ +/* + * ESPRSSIF 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 _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 *)ETS_UNCACHED_ADDR(addr))) +#define WRITE_PERI_REG(addr, val) (*((volatile uint32 *)ETS_UNCACHED_ADDR(addr))) = (uint32)(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 CPU_CLK_FREQ 80 * 1000000 // unit: Hz +#define APB_CLK_FREQ CPU_CLK_FREQ +#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_RTC_BASEADDR 0x60000700 +//}} + +//DPORT{{ +#define HOST_INF_SEL (PERIPHS_DPORT_BASEADDR + 0x28) +#define DPORT_LINK_DEVICE_SEL 0x000000FF +#define DPORT_LINK_DEVICE_SEL_S 8 +#define DPORT_PERI_IO_SWAP 0x000000FF +#define DPORT_PERI_IO_SWAP_S 0 +#define PERI_IO_CSPI_OVERLAP (BIT(7)) // two spi masters on cspi +#define PERI_IO_HSPI_OVERLAP (BIT(6)) // two spi masters on hspi +#define PERI_IO_HSPI_PRIO (BIT(5)) // hspi is with the higher prior +#define PERI_IO_UART1_PIN_SWAP (BIT(3)) // swap uart1 pins (u1rxd <-> u1cts), (u1txd <-> u1rts) +#define PERI_IO_UART0_PIN_SWAP (BIT(2)) // swap uart0 pins (u0rxd <-> u0cts), (u0txd <-> u0rts) +#define PERI_IO_SPI_PORT_SWAP (BIT(1)) // swap two spi +#define PERI_IO_UART_PORT_SWAP (BIT(0)) // swap two uart +//}} + +//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) +//}} + +//RTC reg {{ +#define REG_RTC_BASE PERIPHS_RTC_BASEADDR + +#define RTC_SLP_VAL (REG_RTC_BASE + 0x004) // the target value of RTC_COUNTER for wakeup from light-sleep/deep-sleep +#define RTC_SLP_CNT_VAL (REG_RTC_BASE + 0x01C) // the current value of RTC_COUNTER + +#define RTC_SCRATCH0 (REG_RTC_BASE + 0x030) // the register for software to save some values for watchdog reset +#define RTC_SCRATCH1 (REG_RTC_BASE + 0x034) // the register for software to save some values for watchdog reset +#define RTC_SCRATCH2 (REG_RTC_BASE + 0x038) // the register for software to save some values for watchdog reset +#define RTC_SCRATCH3 (REG_RTC_BASE + 0x03C) // the register for software to save some values for watchdog reset + +#define RTC_GPIO_OUT (REG_RTC_BASE + 0x068) // used by gpio16 +#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) +//}} + +#endif //_EAGLE_SOC_H_ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/esp8266.h b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/esp8266.h new file mode 100644 index 0000000..1eb417f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/esp8266.h @@ -0,0 +1,37 @@ +/* + * ESPRSSIF 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 __ESP8266_H__ +#define __ESP8266_H__ + +#include "ets_sys.h" +#include "eagle_soc.h" +#include "gpio_register.h" +#include "pin_mux_register.h" +#include "spi_register.h" +#include "timer_register.h" +#include "uart_register.h" + +#endif + diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/ets_sys.h b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/ets_sys.h new file mode 100644 index 0000000..28736eb --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/ets_sys.h @@ -0,0 +1,63 @@ +/* + * ESPRSSIF 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 __ETS_SYS_H__ +#define __ETS_SYS_H__ + +/* interrupt related */ +#define ETS_SPI_INUM 2 +#define ETS_GPIO_INUM 4 +#define ETS_UART_INUM 5 +#define ETS_MAX_INUM 6 +#define ETS_SOFT_INUM 7 +#define ETS_WDT_INUM 8 +#define ETS_FRC_TIMER1_INUM 9 + +extern char NMIIrqIsOn; +extern uint32 WDEV_INTEREST_EVENT; + +#define INT_ENA_WDEV 0x3ff20c18 +#define WDEV_TSF0_REACH_INT (BIT(27)) + +#define ETS_INTR_LOCK() do { \ + if (NMIIrqIsOn == 0) { \ + vPortEnterCritical(); \ + char m = 10; \ + do { \ + REG_WRITE(INT_ENA_WDEV, 0); \ + m = 10; \ + for (; m > 0; m--) {} \ + REG_WRITE(INT_ENA_WDEV, WDEV_TSF0_REACH_INT); \ + } while(0); \ + } \ + } while(0) + +#define ETS_INTR_UNLOCK() do { \ + if (NMIIrqIsOn == 0) { \ + REG_WRITE(INT_ENA_WDEV, WDEV_INTEREST_EVENT); \ + vPortExitCritical(); \ + } \ + } while(0) + +#endif /* _ETS_SYS_H */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/gpio_register.h b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/gpio_register.h new file mode 100644 index 0000000..9098812 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/gpio_register.h @@ -0,0 +1,338 @@ +/* + * ESPRSSIF 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 _GPIO_REGISTER_H_ +#define _GPIO_REGISTER_H_ + +#define PERIPHS_GPIO_BASEADDR 0x60000300 + +#define GPIO_OUT_ADDRESS 0x00 +#define GPIO_BT_SEL 0x0000ffff +#define GPIO_BT_SEL_S 16 +#define GPIO_OUT_DATA 0x0000ffff +#define GPIO_OUT_DATA_S 0 + +#define GPIO_OUT_W1TS_ADDRESS 0x04 +#define GPIO_OUT_DATA_W1TS 0x0000ffff +#define GPIO_OUT_DATA_W1TS_S 0 + +#define GPIO_OUT_W1TC_ADDRESS 0x08 +#define GPIO_OUT_DATA_W1TC 0x0000ffff +#define GPIO_OUT_DATA_W1TC_S 0 +#define GPIO_OUT_DATA_MASK 0x0000ffff + +#define GPIO_ENABLE_ADDRESS 0x0c +#define GPIO_SDIO_SEL 0x0000003f +#define GPIO_SDIO_SEL_S 16 +#define GPIO_ENABLE_DATA 0x0000ffff +#define GPIO_ENABLE_DATA_S 0 + +#define GPIO_ENABLE_W1TS_ADDRESS 0x10 +#define GPIO_ENABLE_DATA_W1TS 0x0000ffff +#define GPIO_ENABLE_DATA_W1TS_s 0 + +#define GPIO_ENABLE_W1TC_ADDRESS 0x14 +#define GPIO_ENABLE_DATA_W1TC 0x0000ffff +#define GPIO_ENABLE_DATA_W1TC_S 0 +#define GPIO_ENABLE_DATA_DATA_MASK 0x0000ffff + +#define GPIO_IN_ADDRESS 0x18 +#define GPIO_STRAPPING 0x0000ffff +#define GPIO_STRAPPING_S 16 +#define GPIO_IN_DATA 0x0000ffff +#define GPIO_IN_DATA_S 0 + +#define GPIO_STATUS_ADDRESS 0x1c +#define GPIO_STATUS_INTERRUPT 0x0000ffff +#define GPIO_STATUS_INTERRUPT_S 0 + +#define GPIO_STATUS_W1TS_ADDRESS 0x20 +#define GPIO_STATUS_INTERRUPT_W1TS 0x0000ffff +#define GPIO_STATUS_INTERRUPT_W1TS_S 0 + +#define GPIO_STATUS_W1TC_ADDRESS 0x24 +#define GPIO_STATUS_INTERRUPT_W1TC 0x0000ffff +#define GPIO_STATUS_INTERRUPT_W1TC_S 0 +#define GPIO_STATUS_INTERRUPT_DATA_MASK 0x0000ffff + +//Region1: used for gpio config for GPIO_PIN0_ADDRESS~GPIO_PIN15_ADDRESS +#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 (0x00000003<> 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 (0x00000001<> GPIO_PIN_CONFIG_LSB) +#define GPIO_PIN_WAKEUP_ENABLE_SET(x) (((x) << GPIO_PIN_WAKEUP_ENABLE_LSB) & GPIO_PIN_WAKEUP_ENABLE_MASK) + +#define GPIO_PIN_INT_TYPE_MSB 9 +#define GPIO_PIN_INT_TYPE_LSB 7 +#define GPIO_PIN_INT_TYPE_MASK (0x00000007<> 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_DRIVER_MSB 2 +#define GPIO_PIN_DRIVER_LSB 2 +#define GPIO_PIN_DRIVER_MASK (0x00000001<> GPIO_PIN_INT_TYPE_LSB) +#define GPIO_PIN_PAD_DRIVER_SET(x) (((x) << GPIO_PIN_DRIVER_LSB) & GPIO_PIN_DRIVER_MASK) + +#define GPIO_PIN_SOURCE_MSB 0 +#define GPIO_PIN_SOURCE_LSB 0 +#define GPIO_PIN_SOURCE_MASK (0x00000001<> GPIO_PIN_INT_TYPE_LSB) +#define GPIO_PIN_SOURCE_SET(x) (((x) << GPIO_PIN_SOURCE_LSB) & GPIO_PIN_SOURCE_MASK) +//end of region1 + +#define GPIO_PIN0_ADDRESS 0x28 +#define GPIO_PIN0_CONFIG 0x00000003 +#define GPIO_PIN0_CONFIG_S 11 +#define GPIO_PIN0_WAKEUP_ENABLE BIT10 +#define GPIO_PIN0_WAKEUP_ENABLE_S 10 +#define GPIO_PIN0_INT_TYPE 0x00000007 +#define GPIO_PIN0_INT_TYPE_S 7 +#define GPIO_PIN0_DRIVER BIT2 +#define GPIO_PIN0_DRIVER_S 2 +#define GPIO_PIN0_SOURCE BIT0 +#define GPIO_PIN0_SOURCE_S 0 + +#define GPIO_PIN1_ADDRESS 0x2c +#define GPIO_PIN1_CONFIG 0x00000003 +#define GPIO_PIN1_CONFIG_S 11 +#define GPIO_PIN1_WAKEUP_ENABLE BIT10 +#define GPIO_PIN1_WAKEUP_ENABLE_S 10 +#define GPIO_PIN1_INT_TYPE 0x00000007 +#define GPIO_PIN1_INT_TYPE_S 7 +#define GPIO_PIN1_DRIVER BIT2 +#define GPIO_PIN1_DRIVER_S 2 +#define GPIO_PIN1_SOURCE BIT0 +#define GPIO_PIN1_SOURCE_S 0 + +#define GPIO_PIN2_ADDRESS 0x30 +#define GPIO_PIN2_CONFIG 0x00000003 +#define GPIO_PIN2_CONFIG_S 11 +#define GPIO_PIN2_WAKEUP_ENABLE BIT10 +#define GPIO_PIN2_WAKEUP_ENABLE_S 10 +#define GPIO_PIN2_INT_TYPE 0x00000007 +#define GPIO_PIN2_INT_TYPE_S 7 +#define GPIO_PIN2_DRIVER BIT2 +#define GPIO_PIN2_DRIVER_S 2 +#define GPIO_PIN2_SOURCE BIT0 +#define GPIO_PIN2_SOURCE_S 0 + +#define GPIO_PIN3_ADDRESS 0x34 +#define GPIO_PIN3_CONFIG 0x00000003 +#define GPIO_PIN3_CONFIG_S 11 +#define GPIO_PIN3_WAKEUP_ENABLE BIT10 +#define GPIO_PIN3_WAKEUP_ENABLE_S 10 +#define GPIO_PIN3_INT_TYPE 0x00000007 +#define GPIO_PIN3_INT_TYPE_S 7 +#define GPIO_PIN3_DRIVER BIT2 +#define GPIO_PIN3_DRIVER_S 2 +#define GPIO_PIN3_SOURCE BIT0 +#define GPIO_PIN3_SOURCE_S 0 + +#define GPIO_PIN4_ADDRESS 0x38 +#define GPIO_PIN4_CONFIG 0x00000003 +#define GPIO_PIN4_CONFIG_S 11 +#define GPIO_PIN4_WAKEUP_ENABLE BIT10 +#define GPIO_PIN4_WAKEUP_ENABLE_S 10 +#define GPIO_PIN4_INT_TYPE 0x00000007 +#define GPIO_PIN4_INT_TYPE_S 7 +#define GPIO_PIN4_DRIVER BIT2 +#define GPIO_PIN4_DRIVER_S 2 +#define GPIO_PIN4_SOURCE BIT0 +#define GPIO_PIN4_SOURCE_S 0 + +#define GPIO_PIN5_ADDRESS 0x3c +#define GPIO_PIN5_CONFIG 0x00000003 +#define GPIO_PIN5_CONFIG_S 11 +#define GPIO_PIN5_WAKEUP_ENABLE BIT10 +#define GPIO_PIN5_WAKEUP_ENABLE_S 10 +#define GPIO_PIN5_INT_TYPE 0x00000007 +#define GPIO_PIN5_INT_TYPE_S 7 +#define GPIO_PIN5_DRIVER BIT2 +#define GPIO_PIN5_DRIVER_S 2 +#define GPIO_PIN5_SOURCE BIT0 +#define GPIO_PIN5_SOURCE_S 0 + +#define GPIO_PIN6_ADDRESS 0x40 +#define GPIO_PIN6_CONFIG 0x00000003 +#define GPIO_PIN6_CONFIG_S 11 +#define GPIO_PIN6_WAKEUP_ENABLE BIT10 +#define GPIO_PIN6_WAKEUP_ENABLE_S 10 +#define GPIO_PIN6_INT_TYPE 0x00000007 +#define GPIO_PIN6_INT_TYPE_S 7 +#define GPIO_PIN6_DRIVER BIT2 +#define GPIO_PIN6_DRIVER_S 2 +#define GPIO_PIN6_SOURCE BIT0 +#define GPIO_PIN6_SOURCE_S 0 + +#define GPIO_PIN7_ADDRESS 0x44 +#define GPIO_PIN7_CONFIG 0x00000003 +#define GPIO_PIN7_CONFIG_S 11 +#define GPIO_PIN7_WAKEUP_ENABLE BIT10 +#define GPIO_PIN7_WAKEUP_ENABLE_S 10 +#define GPIO_PIN7_INT_TYPE 0x00000007 +#define GPIO_PIN7_INT_TYPE_S 7 +#define GPIO_PIN7_DRIVER BIT2 +#define GPIO_PIN7_DRIVER_S 2 +#define GPIO_PIN7_SOURCE BIT0 +#define GPIO_PIN7_SOURCE_S 0 + +#define GPIO_PIN8_ADDRESS 0x48 +#define GPIO_PIN8_CONFIG 0x00000003 +#define GPIO_PIN8_CONFIG_S 11 +#define GPIO_PIN8_WAKEUP_ENABLE BIT10 +#define GPIO_PIN8_WAKEUP_ENABLE_S 10 +#define GPIO_PIN8_INT_TYPE 0x00000007 +#define GPIO_PIN8_INT_TYPE_S 7 +#define GPIO_PIN8_DRIVER BIT2 +#define GPIO_PIN8_DRIVER_S 2 +#define GPIO_PIN8_SOURCE BIT0 +#define GPIO_PIN8_SOURCE_S 0 + +#define GPIO_PIN9_ADDRESS 0x4c +#define GPIO_PIN9_CONFIG 0x00000003 +#define GPIO_PIN9_CONFIG_S 11 +#define GPIO_PIN9_WAKEUP_ENABLE BIT10 +#define GPIO_PIN9_WAKEUP_ENABLE_S 10 +#define GPIO_PIN9_INT_TYPE 0x00000007 +#define GPIO_PIN9_INT_TYPE_S 7 +#define GPIO_PIN9_DRIVER BIT2 +#define GPIO_PIN9_DRIVER_S 2 +#define GPIO_PIN9_SOURCE BIT0 +#define GPIO_PIN9_SOURCE_S 0 + +#define GPIO_PIN10_ADDRESS 0x50 +#define GPIO_PIN10_CONFIG 0x00000003 +#define GPIO_PIN10_CONFIG_S 11 +#define GPIO_PIN10_WAKEUP_ENABLE BIT10 +#define GPIO_PIN10_WAKEUP_ENABLE_S 10 +#define GPIO_PIN10_INT_TYPE 0x00000007 +#define GPIO_PIN10_INT_TYPE_S 7 +#define GPIO_PIN10_DRIVER BIT2 +#define GPIO_PIN10_DRIVER_S 2 +#define GPIO_PIN10_SOURCE BIT0 +#define GPIO_PIN10_SOURCE_S 0 + +#define GPIO_PIN11_ADDRESS 0x54 +#define GPIO_PIN11_CONFIG 0x00000003 +#define GPIO_PIN11_CONFIG_S 11 +#define GPIO_PIN11_WAKEUP_ENABLE BIT10 +#define GPIO_PIN11_WAKEUP_ENABLE_S 10 +#define GPIO_PIN11_INT_TYPE 0x00000007 +#define GPIO_PIN11_INT_TYPE_S 7 +#define GPIO_PIN11_DRIVER BIT2 +#define GPIO_PIN11_DRIVER_S 2 +#define GPIO_PIN11_SOURCE BIT0 +#define GPIO_PIN11_SOURCE_S 0 + +#define GPIO_PIN12_ADDRESS 0x58 +#define GPIO_PIN12_CONFIG 0x00000003 +#define GPIO_PIN12_CONFIG_S 11 +#define GPIO_PIN12_WAKEUP_ENABLE BIT10 +#define GPIO_PIN12_WAKEUP_ENABLE_S 10 +#define GPIO_PIN12_INT_TYPE 0x00000007 +#define GPIO_PIN12_INT_TYPE_S 7 +#define GPIO_PIN12_DRIVER BIT2 +#define GPIO_PIN12_DRIVER_S 2 +#define GPIO_PIN12_SOURCE BIT0 +#define GPIO_PIN12_SOURCE_S 0 + +#define GPIO_PIN13_ADDRESS 0x5c +#define GPIO_PIN13_CONFIG 0x00000003 +#define GPIO_PIN13_CONFIG_S 11 +#define GPIO_PIN13_WAKEUP_ENABLE BIT10 +#define GPIO_PIN13_WAKEUP_ENABLE_S 10 +#define GPIO_PIN13_INT_TYPE 0x00000007 +#define GPIO_PIN13_INT_TYPE_S 7 +#define GPIO_PIN13_DRIVER BIT2 +#define GPIO_PIN13_DRIVER_S 2 +#define GPIO_PIN13_SOURCE BIT0 +#define GPIO_PIN13_SOURCE_S 0 + +#define GPIO_PIN14_ADDRESS 0x60 +#define GPIO_PIN14_CONFIG 0x00000003 +#define GPIO_PIN14_CONFIG_S 11 +#define GPIO_PIN14_WAKEUP_ENABLE BIT10 +#define GPIO_PIN14_WAKEUP_ENABLE_S 10 +#define GPIO_PIN14_INT_TYPE 0x00000007 +#define GPIO_PIN14_INT_TYPE_S 7 +#define GPIO_PIN14_DRIVER BIT2 +#define GPIO_PIN14_DRIVER_S 2 +#define GPIO_PIN14_SOURCE BIT0 +#define GPIO_PIN14_SOURCE_S 0 + +#define GPIO_PIN15_ADDRESS 0x64 +#define GPIO_PIN15_CONFIG 0x00000003 +#define GPIO_PIN15_CONFIG_S 11 +#define GPIO_PIN15_WAKEUP_ENABLE BIT10 +#define GPIO_PIN15_WAKEUP_ENABLE_S 10 +#define GPIO_PIN15_INT_TYPE 0x00000007 +#define GPIO_PIN15_INT_TYPE_S 7 +#define GPIO_PIN15_DRIVER BIT2 +#define GPIO_PIN15_DRIVER_S 2 +#define GPIO_PIN15_SOURCE BIT0 +#define GPIO_PIN15_SOURCE_S 0 + +#define GPIO_SIGMA_DELTA_ADDRESS 0x68 +#define SIGMA_DELTA_ENABLE BIT16 +#define SIGMA_DELTA_ENABLE_S 16 +#define SIGMA_DELTA_PRESCALAR 0x000000ff +#define SIGMA_DELTA_PRESCALAR_S 8 +#define SIGMA_DELTA_TARGET 0x000000ff +#define SIGMA_DELTA_TARGET_S 0 + +#define GPIO_RTC_CALIB_SYNC_ADDRESS 0x6c +#define RTC_CALIB_START BIT31 +#define RTC_CALIB_START_S 31 +#define RTC_PERIOD_NUM 0x000003ff +#define RTC_PERIOD_NUM_S 0 + +#define GPIO_RTC_CALIB_VALUE_ADDRESS 0x70 +#define RTC_CALIB_RDY BIT31 +#define RTC_CALIB_RDY_S 31 +#define RTC_CALIB_RDY_REAL BIT30 +#define RTC_CALIB_RDY_REAL_S 30 +#define RTC_CALIB_VALUE 0x000fffff +#define RTC_CALIB_VALUE_S 0 + +#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) + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/pin_mux_register.h b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/pin_mux_register.h new file mode 100644 index 0000000..33a2e76 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/pin_mux_register.h @@ -0,0 +1,152 @@ +/* + * ESPRSSIF 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 _PIN_MUX_H_ +#define _PIN_MUX_H_ + +#define PERIPHS_IO_MUX 0x60000800 + +#define PERIPHS_IO_MUX_FUNC 0x13 +#define PERIPHS_IO_MUX_FUNC_S 4 +#define PERIPHS_IO_MUX_PULLUP BIT7 +#define PERIPHS_IO_MUX_PULLDWN BIT6 +#define PERIPHS_IO_MUX_SLEEP_PULLUP BIT3 +#define PERIPHS_IO_MUX_SLEEP_PULLDWN 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_MTDI 0 +#define FUNC_I2SI_DATA 1 +#define FUNC_HSPIQ_MISO 2 +#define FUNC_GPIO12 3 +#define FUNC_UART0_DTR 4 + +#define PERIPHS_IO_MUX_MTCK_U (PERIPHS_IO_MUX + 0x08) +#define FUNC_MTCK 0 +#define FUNC_I2SI_BCK 1 +#define FUNC_HSPID_MOSI 2 +#define FUNC_GPIO13 3 +#define FUNC_UART0_CTS 4 + +#define PERIPHS_IO_MUX_MTMS_U (PERIPHS_IO_MUX + 0x0C) +#define FUNC_MTMS 0 +#define FUNC_I2SI_WS 1 +#define FUNC_HSPI_CLK 2 +#define FUNC_GPIO14 3 +#define FUNC_UART0_DSR 4 + +#define PERIPHS_IO_MUX_MTDO_U (PERIPHS_IO_MUX + 0x10) +#define FUNC_MTDO 0 +#define FUNC_I2SO_BCK 1 +#define FUNC_HSPI_CS0 2 +#define FUNC_GPIO15 3 +#define FUNC_U0RTS 4 +#define FUNC_UART0_RTS 4 + +#define PERIPHS_IO_MUX_U0RXD_U (PERIPHS_IO_MUX + 0x14) +#define FUNC_U0RXD 0 +#define FUNC_I2SO_DATA 1 +#define FUNC_GPIO3 3 +#define FUNC_CLK_XTAL_BK 4 + +#define PERIPHS_IO_MUX_U0TXD_U (PERIPHS_IO_MUX + 0x18) +#define FUNC_U0TXD 0 +#define FUNC_SPICS1 1 +#define FUNC_GPIO1 3 +#define FUNC_CLK_RTC_BK 4 + +#define PERIPHS_IO_MUX_SD_CLK_U (PERIPHS_IO_MUX + 0x1c) +#define FUNC_SDCLK 0 +#define FUNC_SPICLK 1 +#define FUNC_GPIO6 3 +#define UART1_CTS 4 + +#define PERIPHS_IO_MUX_SD_DATA0_U (PERIPHS_IO_MUX + 0x20) +#define FUNC_SDDATA0 0 +#define FUNC_SPIQ_MISO 1 +#define FUNC_GPIO7 3 +#define FUNC_U1TXD 4 +#define FUNC_UART1_TXD 4 + +#define PERIPHS_IO_MUX_SD_DATA1_U (PERIPHS_IO_MUX + 0x24) +#define FUNC_SDDATA1 0 +#define FUNC_SPID_MOSI 1 +#define FUNC_GPIO8 3 +#define FUNC_U1RXD 4 +#define FUNC_UART1_RXD 4 + +#define PERIPHS_IO_MUX_SD_DATA2_U (PERIPHS_IO_MUX + 0x28) +#define FUNC_SDDATA2 0 +#define FUNC_SPIHD 1 +#define FUNC_GPIO9 3 +#define UFNC_HSPIHD 4 + +#define PERIPHS_IO_MUX_SD_DATA3_U (PERIPHS_IO_MUX + 0x2c) +#define FUNC_SDDATA3 0 +#define FUNC_SPIWP 1 +#define FUNC_GPIO10 3 +#define FUNC_HSPIWP 4 + +#define PERIPHS_IO_MUX_SD_CMD_U (PERIPHS_IO_MUX + 0x30) +#define FUNC_SDCMD 0 +#define FUNC_SPICS0 1 +#define FUNC_GPIO11 3 +#define U1RTS 4 +#define UART1_RTS 4 + +#define PERIPHS_IO_MUX_GPIO0_U (PERIPHS_IO_MUX + 0x34) +#define FUNC_GPIO0 0 +#define FUNC_SPICS2 1 +#define FUNC_CLK_OUT 4 + +#define PERIPHS_IO_MUX_GPIO2_U (PERIPHS_IO_MUX + 0x38) +#define FUNC_GPIO2 0 +#define FUNC_I2SO_WS 1 +#define FUNC_U1TXD_BK 2 +#define FUNC_UART1_TXD_BK 2 +#define FUNC_U0TXD_BK 4 +#define FUNC_UART0_TXD_BK 4 + +#define PERIPHS_IO_MUX_GPIO4_U (PERIPHS_IO_MUX + 0x3C) +#define FUNC_GPIO4 0 +#define FUNC_CLK_XTAL 1 + +#define PERIPHS_IO_MUX_GPIO5_U (PERIPHS_IO_MUX + 0x40) +#define FUNC_GPIO5 0 +#define FUNC_CLK_RTC 1 + +#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 { \ + CLEAR_PERI_REG_MASK(PIN_NAME, (PERIPHS_IO_MUX_FUNC << PERIPHS_IO_MUX_FUNC_S)); \ + SET_PERI_REG_MASK(PIN_NAME, (((FUNC & BIT2) << 2) | (FUNC & 0x3)) << PERIPHS_IO_MUX_FUNC_S); \ + } while (0) + +#endif //_PIN_MUX_H_ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/spi_register.h b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/spi_register.h new file mode 100644 index 0000000..4b7f76d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/spi_register.h @@ -0,0 +1,193 @@ +/* + * ESPRSSIF 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 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_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_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_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/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/timer_register.h b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/timer_register.h new file mode 100644 index 0000000..2406220 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/timer_register.h @@ -0,0 +1,93 @@ +/* + * ESPRSSIF 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 _TIMER_REGISTER_H_ +#define _TIMER_REGISTER_H_ + +#define PERIPHS_TIMER_BASEDDR 0x60000600 + +#define FRC1_LOAD_ADDRESS (PERIPHS_TIMER_BASEDDR + 0x0) +#define TIMER_FRC1_LOAD_VALUE 0x007FFFFF +#define TIMER_FRC1_LOAD_VALUE_S 0 +#define FRC1_LOAD_DATA_MSB 22 +#define FRC1_LOAD_DATA_LSB 0 +#define FRC1_LOAD_DATA_MASK 0x007fffff + +#define FRC1_COUNT_ADDRESS (PERIPHS_TIMER_BASEDDR + 0x4) +#define TIMER_FRC1_COUNT 0x007FFFFF +#define TIMER_FRC1_COUNT_S 0 +#define FRC1_COUNT_DATA_MSB 22 +#define FRC1_COUNT_DATA_LSB 0 +#define FRC1_COUNT_DATA_MASK 0x007fffff + +#define FRC1_CTRL_ADDRESS (PERIPHS_TIMER_BASEDDR + 0x8) +#define TIMER_FRC1_INT (BIT(8)) +#define TIMER_FRC1_CTRL 0x000000FF +#define TIMER_FRC1_CTRL_S 0 +#define FRC1_CTRL_DATA_MSB 7 +#define FRC1_CTRL_DATA_LSB 0 +#define FRC1_CTRL_DATA_MASK 0x000000ff + +#define FRC1_INT_ADDRESS (PERIPHS_TIMER_BASEDDR + 0xC) +#define TIMER_FRC1_INT_CLR_MASK (BIT(0)) +#define FRC1_INT_CLR_MSB 0 +#define FRC1_INT_CLR_LSB 0 +#define FRC1_INT_CLR_MASK 0x00000001 + +#define FRC2_LOAD_ADDRESS (PERIPHS_TIMER_BASEDDR + 0x20) +#define TIMER_FRC2_LOAD_VALUE 0xFFFFFFFF +#define TIMER_FRC2_LOAD_VALUE_S 0 +#define FRC2_LOAD_DATA_MSB 31 +#define FRC2_LOAD_DATA_LSB 0 +#define FRC2_LOAD_DATA_MASK 0xffffffff + +#define FRC2_COUNT_ADDRESS (PERIPHS_TIMER_BASEDDR + 0x24) +#define TIMER_FRC2_COUNT 0xFFFFFFFF +#define TIMER_FRC2_COUNT_S 0 +#define FRC2_COUNT_DATA_MSB 31 +#define FRC2_COUNT_DATA_LSB 0 +#define FRC2_COUNT_DATA_MASK 0xffffffff + +#define FRC2_CTRL_ADDRESS (PERIPHS_TIMER_BASEDDR + 0x28) +#define TIMER_FRC2_INT (BIT(8)) +#define TIMER_FRC2_CTRL 0x000000FF +#define TIMER_FRC2_CTRL_S 0 +#define FRC2_CTRL_DATA_MSB 7 +#define FRC2_CTRL_DATA_LSB 0 +#define FRC2_CTRL_DATA_MASK 0x000000ff + +#define FRC2_INT_ADDRESS (PERIPHS_TIMER_BASEDDR + 0x2C) +#define TIMER_FRC2_INT_CLR_MASK (BIT(0)) +#define FRC2_INT_CLR_MSB 0 +#define FRC2_INT_CLR_LSB 0 +#define FRC2_INT_CLR_MASK 0x00000001 + +#define FRC2_ALARM_ADDRESS (PERIPHS_TIMER_BASEDDR + 0x30) +#define TIMER_FRC2_ALARM 0xFFFFFFFF +#define TIMER_FRC2_ALARM_S 0 +#define FRC2_ALARM_DATA_MSB 31 +#define FRC2_ALARM_DATA_LSB 0 +#define FRC2_ALARM_DATA_MASK 0xffffffff + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/uart_register.h b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/uart_register.h new file mode 100644 index 0000000..a6a1a2a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp8266/uart_register.h @@ -0,0 +1,154 @@ +/* + * ESPRSSIF 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 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 (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/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_common.h b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_common.h new file mode 100644 index 0000000..12df16d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_common.h @@ -0,0 +1,111 @@ +/* + * ESPRSSIF 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 __ESP_COMMON_H__ +#define __ESP_COMMON_H__ + +/** \mainpage ESP8266_RTOS_SDK + * + * - Misc APIs : misc APIs + * - WiFi APIs : WiFi related APIs + * - SoftAP APIs : ESP8266 Soft-AP APIs + * - Station APIs : ESP8266 station APIs + * - Common APIs : WiFi common APIs + * - Force Sleep APIs : WiFi Force Sleep APIs + * - Rate Control APIs : WiFi Rate Control APIs + * - User IE APIs : WiFi User IE APIs + * - Sniffer APIs : WiFi sniffer APIs + * - WPS APIs : WiFi WPS APIs + * - Smartconfig APIs : SmartConfig APIs + * - AirKiss APIs : AirKiss APIs + * - Spiffs APIs : Spiffs APIs + * - SSC APIs : Simple Serial Command APIs + * - System APIs : System APIs + * - Boot APIs : Boot mode APIs + * - Upgrade APIs : Firmware upgrade (FOTA) APIs + * - Software timer APIs : Software timer APIs + * - Network Espconn APIs : Network espconn APIs + * - ESP-NOW APIs : ESP-NOW APIs + * - Mesh APIs : Mesh APIs + * - Driver APIs : Driver APIs + * - PWM Driver APIs : PWM driver APIs + * - UART Driver APIs : UART driver APIs + * - GPIO Driver APIs : GPIO driver APIs + * - SPI Driver APIs : SPI Flash APIs + * - Hardware timer APIs : Hardware timer APIs + * + * void user_init(void) is the entrance function of the application. + * @attention 1. It is recommended that users set the timer to the periodic mode + * for periodic checks. + * @attention (1). In freeRTOS timer or os_timer, do not delay by while(1) or + * in the manner that will block the thread. + * @attention (2). The timer callback should not occupy CPU more than 15ms. + * @attention (3). os_timer_t should not define a local variable, it has to be global varialbe + * or memory got by malloc. + * + * @attention 2. Since esp_iot_rtos_sdk_v1.0.4, functions are stored in CACHE by + * default, need not be added ICACHE_FLASH_ATTR any more. The interrupt + * functions can also be stored in CACHE. If users want to store some + * frequently called functions in RAM, please add IRAM_ATTR before + * functions' name. + * + * @attention 3. Network programming use socket, please do not bind to the same port. + * @attention (1). If users want to create 3 or more than 3 TCP connections, please add + * "TCP_WND = 2 x TCP_MSS;" in "user_init". + * + * @attention 4. Priority of the RTOS SDK is 15. xTaskCreate is an interface of + * freeRTOS. For details of the freeRTOS and APIs of the system, + * please visit http://www.freertos.org + * @attention (1). When using xTaskCreate to create a task, the task stack range is [176, 512]. + * @attention (2). If an array whose length is over 60 bytes is used in a task, + * it is suggested that users use malloc and free rather than local + * variable to allocate array. Large local variables could lead to + * task stack overflow. + * @attention (3). The RTOS SDK takes some priorities. Priority of the pp task is + * 13; priority of precise timer(ms) thread is 12; priority of the + * TCP/IP task is 10; priority of the freeRTOS timer is 2; priority of + * the idle task is 0. + * @attention (4). Users can use tasks with priorities from 1 to 9. + * @attention (5). Do not revise FreeRTOSConfig.h, configurations are decided by source code + * inside the RTOS SDK, users can not change it. + */ + +#include "c_types.h" +#include "esp_libc.h" +#include "esp_misc.h" +#include "esp_wifi.h" +#include "esp_softap.h" +#include "esp_sta.h" +#include "esp_system.h" +#include "esp_timer.h" +#include "esp_ssc.h" +#include "esp_spiffs.h" + +#include "esp8266/esp8266.h" + +#include "smartconfig.h" +#include "spi_flash.h" +#include "pwm.h" + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_libc.h b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_libc.h new file mode 100644 index 0000000..8f7c957 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_libc.h @@ -0,0 +1,137 @@ +/* + * ESPRSSIF 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 __ESP_LIBC_H__ +#define __ESP_LIBC_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +char *strcpy(char *dst, const char *src); +char *strncpy(char *dst, const char *src, size_t n); +int strcmp(const char *s1, const char *s2); +int strncmp(const char *s1, const char *s2, size_t n); +size_t strlen(const char *s); +char *strstr(const char *s1, const char *s2); +char *strcat(char *dst, const char *src); +char *strncat(char *dst, const char *src, size_t count); +size_t strspn(const char *s, const char *accept); +size_t strcspn(const char *s, const char *reject); +char *strtok_r(char *s, const char *delim, char **ptrptr); +char *strtok(char *s, const char *delim); +char *strrchr(const char *s, int c); +char *strdup(const char *s); +char *strchr(const char *s, int c); +long strtol(const char *str, char **endptr, int base); + +void bzero(void *s, size_t n); + +void *memcpy(void *dst, const void *src, size_t n); +void *memset(void *dst, int c, size_t n); +int memcmp(const void *m1, const void *m2, size_t n); +void *memmove(void *dst, const void *src, size_t n); + +int rand(void); + +int printf(const char *format, ...); +int sprintf(char *out, const char *format, ...); +int snprintf(char *buf, unsigned int count, const char *format, ...); +int puts(const char *str); + +void *malloc(size_t n); +void free(void *p); +void *calloc(size_t c, size_t n); +void *zalloc(size_t n); +void *realloc(void *p, size_t n); + +int atoi(const char *s); +long atol(const char *s); + +unsigned long os_random(void); +int os_get_random(unsigned char *buf, size_t len); + +/* NOTE: don't use printf_opt in irq handler, for test */ +#define os_printf(fmt, ...) do { \ + static const char flash_str[] ICACHE_RODATA_ATTR STORE_ATTR = fmt; \ + printf(flash_str, ##__VA_ARGS__); \ + } while(0) + +/* Note: check_memleak_debug_enable is a weak function inside SDK. + * please copy following codes to user_main.c. +#include "esp_libc.h" + +bool ICACHE_FLASH_ATTR check_memleak_debug_enable(void) +{ + return MEMLEAK_DEBUG_ENABLE; +} +*/ + +#ifndef MEMLEAK_DEBUG +#define MEMLEAK_DEBUG_ENABLE 0 +#define os_free(s) free(s) +#define os_malloc(s) malloc(s) +#define os_calloc(p, s) calloc(p, s); +#define os_realloc(p, s) realloc(p, s) +#define os_zalloc(s) zalloc(s) +#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(p, s) \ + ({ \ + static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; \ + pvPortCalloc(p, 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 + +#ifdef __cplusplus +} +#endif + +#endif /* __LIBC_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_misc.h b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_misc.h new file mode 100644 index 0000000..177ee1e --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_misc.h @@ -0,0 +1,108 @@ +/* + * ESPRSSIF 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 __ESP_MISC_H__ +#define __ESP_MISC_H__ + +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup Misc_APIs Misc APIs + * @brief misc APIs + */ + +/** @addtogroup Misc_APIs + * @{ + */ + +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" + +#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" + +/** + * @brief Delay function, maximum value: 65535 us. + * + * @param uint16 us : delay time, uint: us, maximum value: 65535 us + * + * @return null + */ +void os_delay_us(uint16 us); + +/** + * @brief Register the print output function. + * + * @attention os_install_putc1((void *)uart1_write_char) in uart_init will set + * printf to print from UART 1, otherwise, printf will start from + * UART 0 by default. + * + * @param void(*p)(char c) - pointer of print function + * + * @return null + */ +void os_install_putc1(void (*p)(char c)); + +/** + * @brief Print a character. Start from from UART0 by default. + * + * @param char c - character to be printed + * + * @return null + */ +void os_putc(char c); + +enum dhcp_status { + DHCP_STOPPED, /**< disable DHCP */ + DHCP_STARTED /**< enable DHCP */ +}; + +struct dhcps_lease { + bool enable; /**< enable DHCP lease or not */ + struct ip_addr start_ip; /**< start IP of IP range */ + struct ip_addr end_ip; /**< end IP of IP range */ +}; + +enum dhcps_offer_option { + OFFER_START = 0x00, /**< DHCP offer option start */ + OFFER_ROUTER = 0x01, /**< DHCP offer router, only support this option now */ + OFFER_END /**< DHCP offer option start */ +}; + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_softap.h b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_softap.h new file mode 100644 index 0000000..962b9ec --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_softap.h @@ -0,0 +1,290 @@ +/* + * ESPRSSIF 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 __ESP_SOFTAP_H__ +#define __ESP_SOFTAP_H__ + +#include "queue.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup WiFi_APIs WiFi Related APIs + * @brief WiFi APIs + */ + +/** @addtogroup WiFi_APIs + * @{ + */ + +/** \defgroup SoftAP_APIs SoftAP APIs + * @brief ESP8266 Soft-AP APIs + * @attention To call APIs related to ESP8266 soft-AP has to enable soft-AP mode first (wifi_set_opmode) + */ + +/** @addtogroup SoftAP_APIs + * @{ + */ + +struct softap_config { + uint8 ssid[32]; /**< SSID of ESP8266 soft-AP */ + uint8 password[64]; /**< Password of ESP8266 soft-AP */ + uint8 ssid_len; /**< Length of SSID. If softap_config.ssid_len==0, check the SSID until there is a termination character; otherwise, set the SSID length according to softap_config.ssid_len. */ + uint8 channel; /**< Channel of ESP8266 soft-AP */ + AUTH_MODE authmode; /**< Auth mode of ESP8266 soft-AP. Do not support AUTH_WEP in soft-AP mode */ + uint8 ssid_hidden; /**< Broadcast SSID or not, default 0, broadcast the SSID */ + uint8 max_connection; /**< Max number of stations allowed to connect in, default 4, max 4 */ + uint16 beacon_interval; /**< Beacon interval, 100 ~ 60000 ms, default 100 */ +}; + +struct station_info { + STAILQ_ENTRY(station_info) next; /**< Information of next AP */ + + uint8 bssid[6]; /**< BSSID of AP */ + struct ip_addr ip; /**< IP address of AP */ +}; + +/** + * @brief Get the current configuration of the ESP8266 WiFi soft-AP + * + * @param struct softap_config *config : ESP8266 soft-AP configuration + * + * @return true : succeed + * @return false : fail + */ +bool wifi_softap_get_config(struct softap_config *config); + +/** + * @brief Get the configuration of the ESP8266 WiFi soft-AP saved in the flash + * + * @param struct softap_config *config : ESP8266 soft-AP configuration + * + * @return true : succeed + * @return false : fail + */ +bool wifi_softap_get_config_default(struct softap_config *config); + +/** + * @brief Set the configuration of the WiFi soft-AP and save it to the Flash. + * + * @attention 1. This configuration will be saved in flash system parameter area if changed + * @attention 2. The ESP8266 is limited to only one channel, so when in the soft-AP+station mode, + * the soft-AP will adjust its channel automatically to be the same as + * the channel of the ESP8266 station. + * + * @param struct softap_config *config : ESP8266 soft-AP configuration + * + * @return true : succeed + * @return false : fail + */ +bool wifi_softap_set_config(struct softap_config *config); + +/** + * @brief Set the configuration of the WiFi soft-AP; the configuration will + * not be saved to the Flash. + * + * @attention The ESP8266 is limited to only one channel, so when in the soft-AP+station mode, + * the soft-AP will adjust its channel automatically to be the same as + * the channel of the ESP8266 station. + * + * @param struct softap_config *config : ESP8266 soft-AP configuration + * + * @return true : succeed + * @return false : fail + */ +bool wifi_softap_set_config_current(struct softap_config *config); + +/** + * @brief Get the number of stations connected to the ESP8266 soft-AP. + * + * @attention The ESP8266 is limited to only one channel, so when in the soft-AP+station mode, + * the soft-AP will adjust its channel automatically to be the same as + * the channel of the ESP8266 station. + * + * @param null + * + * @return the number of stations connected to the ESP8266 soft-AP + */ +uint8 wifi_softap_get_station_num(void); + +/** + * @brief Get the information of stations connected to the ESP8266 soft-AP, + * including MAC and IP. + * + * @attention wifi_softap_get_station_info depends on DHCP, it can only + * be used when DHCP is enabled, so it can not get the static IP. + * + * @param null + * + * @return struct station_info* : station information structure + */ +struct station_info *wifi_softap_get_station_info(void); + +/** + * @brief Free the space occupied by station_info when wifi_softap_get_station_info is called. + * + * @attention The ESP8266 is limited to only one channel, so when in the soft-AP+station mode, + * the soft-AP will adjust its channel automatically to be the same as + * the channel of the ESP8266 station. + * + * @param null + * + * @return null + */ +void wifi_softap_free_station_info(void); + +/** + * @brief Enable the ESP8266 soft-AP DHCP server. + * + * @attention 1. The DHCP is enabled by default. + * @attention 2. The DHCP and the static IP related API (wifi_set_ip_info) influence + * each other, if the DHCP is enabled, the static IP will be disabled; + * if the static IP is enabled, the DHCP will be disabled. + * It depends on the latest configuration. + * + * @param null + * + * @return true : succeed + * @return false : fail + */ +bool wifi_softap_dhcps_start(void); + +/** + * @brief Disable the ESP8266 soft-AP DHCP server. The DHCP is enabled by default. + * + * @param null + * + * @return true : succeed + * @return false : fail + */ +bool wifi_softap_dhcps_stop(void); + +/** + * @brief Get the ESP8266 soft-AP DHCP server status. + * + * @param null + * + * @return enum dhcp_status + */ +enum dhcp_status wifi_softap_dhcps_status(void); + +/** + * @brief Query the IP range that can be got from the ESP8266 soft-AP DHCP server. + * + * @attention This API can only be called during ESP8266 soft-AP DHCP server enabled. + * + * @param struct dhcps_lease *please : IP range of the ESP8266 soft-AP DHCP server. + * + * @return true : succeed + * @return false : fail + */ +bool wifi_softap_get_dhcps_lease(struct dhcps_lease *please); + +/** + * @brief Set the IP range of the ESP8266 soft-AP DHCP server. + * + * @attention 1. The IP range should be in the same sub-net with the ESP8266 + * soft-AP IP address. + * @attention 2. This API should only be called when the DHCP server is disabled + * (wifi_softap_dhcps_stop). + * @attention 3. This configuration will only take effect the next time when the + * DHCP server is enabled (wifi_softap_dhcps_start). + * - If the DHCP server is disabled again, this API should be called to set the IP range. + * - Otherwise, when the DHCP server is enabled later, the default IP range will be used. + * + * @param struct dhcps_lease *please : IP range of the ESP8266 soft-AP DHCP server. + * + * @return true : succeed + * @return false : fail + */ +bool wifi_softap_set_dhcps_lease(struct dhcps_lease *please); + +/** + * @brief Get ESP8266 soft-AP DHCP server lease time. + * + * @attention This API can only be called during ESP8266 soft-AP DHCP server enabled. + * + * @param null + * + * @return lease time, uint: minute. + */ +uint32 wifi_softap_get_dhcps_lease_time(void); + +/** + * @brief Set ESP8266 soft-AP DHCP server lease time, default is 120 minutes. + * + * @attention This API can only be called during ESP8266 soft-AP DHCP server enabled. + * + * @param uint32 minute : lease time, uint: minute, range:[1, 2880]. + * + * @return true : succeed + * @return false : fail + */ +bool wifi_softap_set_dhcps_lease_time(uint32 minute); + +/** + * @brief Reset ESP8266 soft-AP DHCP server lease time which is 120 minutes by default. + * + * @attention This API can only be called during ESP8266 soft-AP DHCP server enabled. + * + * @param null + * + * @return true : succeed + * @return false : fail + */ +bool wifi_softap_reset_dhcps_lease_time(void); + +/** + * @brief Set the ESP8266 soft-AP DHCP server option. + * + * Example: + *
 
+  *         uint8 mode = 0;
+  *         wifi_softap_set_dhcps_offer_option(OFFER_ROUTER, &mode);
+  * 
+ * + * @param uint8 level : OFFER_ROUTER, set the router option. + * @param void* optarg : + * - bit0, 0 disable the router information; + * - bit0, 1 enable the router information. + * + * @return true : succeed + * @return false : fail + */ +bool wifi_softap_set_dhcps_offer_option(uint8 level, void *optarg); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_spiffs.h b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_spiffs.h new file mode 100644 index 0000000..2d83a5b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_spiffs.h @@ -0,0 +1,84 @@ +/* + * ESPRSSIF 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 __ESP_SPIFFS_H__ +#define __ESP_SPIFFS_H__ + +#include "spiffs/spiffs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup Spiffs_APIs Spiffs APIs + * @brief Spiffs APIs + * + * More details about spiffs on https://github.com/pellepl/spiffs + * + */ + +/** @addtogroup Spiffs_APIs + * @{ + */ + +struct esp_spiffs_config { + uint32 phys_size; /**< physical size of the SPI Flash */ + uint32 phys_addr; /**< physical offset in spi flash used for spiffs, must be on block boundary */ + uint32 phys_erase_block; /**< physical size when erasing a block */ + + uint32 log_block_size; /**< logical size of a block, must be on physical block size boundary and must never be less than a physical block */ + uint32 log_page_size; /**< logical size of a page, at least log_block_size/8 */ + + uint32 fd_buf_size; /**< file descriptor memory area size */ + uint32 cache_buf_size; /**< cache buffer size */ +}; + +/** + * @brief Initialize spiffs + * + * @param struct esp_spiffs_config *config : ESP8266 spiffs configuration + * + * @return 0 : succeed + * @return otherwise : fail + */ +sint32 esp_spiffs_init(struct esp_spiffs_config *config); + +/** + * @brief Deinitialize spiffs + * + * @param uint8 format : 0, only deinit; otherwise, deinit spiffs and format. + * + * @return null + */ +void esp_spiffs_deinit(uint8 format); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ESP_SPIFFS_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_ssc.h b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_ssc.h new file mode 100644 index 0000000..a214566 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_ssc.h @@ -0,0 +1,125 @@ +/* + * ESPRSSIF 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 __ESP_SSC_H__ +#define __ESP_SSC_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define CMD_T_ASYNC 0x01 +#define CMD_T_SYNC 0x02 + +typedef struct cmd_s { + char *cmd_str; + uint8 flag; + uint8 id; + void (* cmd_func)(void); + void (* cmd_callback)(void *arg); +} ssc_cmd_t; + +#define MAX_LINE_N 127 + +typedef enum { + SSC_BR_9600 = 9600, + SSC_BR_19200 = 19200, + SSC_BR_38400 = 38400, + SSC_BR_57600 = 57600, + SSC_BR_74880 = 74880, + SSC_BR_115200 = 115200, + SSC_BR_230400 = 230400, + SSC_BR_460800 = 460800, + SSC_BR_921600 = 921600 +} SscBaudRate; + +/** \defgroup SSC_APIs SSC APIs + * @brief SSC APIs + * + * SSC means simple serial command. + * SSC APIs allows users to define their own command, users can refer to spiffs_test/test_main.c. + * + */ + +/** @addtogroup SSC_APIs + * @{ + */ + +/** + * @brief Initial the ssc function. + * + * @param SscBaudRate bandrate : baud rate + * + * @return null + */ +void ssc_attach(SscBaudRate bandrate); + +/** + * @brief Get the length of the simple serial command. + * + * @param null + * + * @return length of the command. + */ +int ssc_param_len(void); + +/** + * @brief Get the simple serial command string. + * + * @param null + * + * @return the command. + */ +char *ssc_param_str(void); + +/** + * @brief Parse the simple serial command (ssc). + * + * @param char *pLine : [input] the ssc string + * @param char *argv[] : [output] parameters of the ssc + * + * @return the number of parameters. + */ +int ssc_parse_param(char *pLine, char *argv[]); + +/** + * @brief Register the user-defined simple serial command (ssc) set. + * + * @param ssc_cmd_t *cmdset : the ssc set + * @param uint8 cmdnum : number of commands + * @param void (* help)(void) : callback of user-guide + * + * @return null + */ +void ssc_register(ssc_cmd_t *cmdset, uint8 cmdnum, void (* help)(void)); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ESP_SSC_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_sta.h b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_sta.h new file mode 100644 index 0000000..c075170 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_sta.h @@ -0,0 +1,393 @@ +/* + * ESPRSSIF 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 __ESP_STA_H__ +#define __ESP_STA_H__ + +#include "queue.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup WiFi_APIs WiFi Related APIs + * @brief WiFi APIs + */ + +/** @addtogroup WiFi_APIs + * @{ + */ + +/** \defgroup Station_APIs Station APIs + * @brief ESP8266 station APIs + * @attention To call APIs related to ESP8266 station has to enable station mode + * first (wifi_set_opmode) + */ + +/** @addtogroup Station_APIs + * @{ + */ + +struct station_config { + uint8 ssid[32]; /**< SSID of target AP*/ + uint8 password[64]; /**< password of target AP*/ + uint8 bssid_set; /**< whether set MAC address of target AP or not. Generally, station_config.bssid_set needs to be 0; and it needs to be 1 only when users need to check the MAC address of the AP.*/ + uint8 bssid[6]; /**< MAC address of target AP*/ +}; + +/** + * @brief Get the current configuration of the ESP8266 WiFi station. + * + * @param struct station_config *config : ESP8266 station configuration + * + * @return true : succeed + * @return false : fail + */ +bool wifi_station_get_config(struct station_config *config); + +/** + * @brief Get the configuration parameters saved in the Flash of the ESP8266 WiFi station. + * + * @param struct station_config *config : ESP8266 station configuration + * + * @return true : succeed + * @return false : fail + */ +bool wifi_station_get_config_default(struct station_config *config); + +/** + * @brief Set the configuration of the ESP8266 station and save it to the Flash. + * + * @attention 1. This API can be called only when the ESP8266 station is enabled. + * @attention 2. If wifi_station_set_config is called in user_init , there is no + * need to call wifi_station_connect. + * The ESP8266 station will automatically connect to the AP (router) + * after the system initialization. Otherwise, wifi_station_connect should be called. + * @attention 3. Generally, station_config.bssid_set needs to be 0; and it needs + * to be 1 only when users need to check the MAC address of the AP. + * @attention 4. This configuration will be saved in the Flash system parameter area if changed. + * + * @param struct station_config *config : ESP8266 station configuration + * + * @return true : succeed + * @return false : fail + */ +bool wifi_station_set_config(struct station_config *config); + +/** + * @brief Set the configuration of the ESP8266 station. And the configuration + * will not be saved to the Flash. + * + * @attention 1. This API can be called only when the ESP8266 station is enabled. + * @attention 2. If wifi_station_set_config_current is called in user_init , there + * is no need to call wifi_station_connect. + * The ESP8266 station will automatically connect to the AP (router) + * after the system initialization. Otherwise, wifi_station_connect + * should be called. + * @attention 3. Generally, station_config.bssid_set needs to be 0; and it needs + * to be 1 only when users need to check the MAC address of the AP. + * + * @param struct station_config *config : ESP8266 station configuration + * + * @return true : succeed + * @return false : fail + */ +bool wifi_station_set_config_current(struct station_config *config); + +/** + * @brief Connect the ESP8266 WiFi station to the AP. + * + * @attention 1. This API should be called when the ESP8266 station is enabled, + * and the system initialization is completed. Do not call this API in user_init. + * @attention 2. If the ESP8266 is connected to an AP, call wifi_station_disconnect to disconnect. + * + * @param null + * + * @return true : succeed + * @return false : fail + */ +bool wifi_station_connect(void); + +/** + * @brief Disconnect the ESP8266 WiFi station from the AP. + * + * @attention This API should be called when the ESP8266 station is enabled, + * and the system initialization is completed. Do not call this API in user_init. + * + * @param null + * + * @return true : succeed + * @return false : fail + */ +bool wifi_station_disconnect(void); + +struct scan_config { + uint8 *ssid; /**< SSID of AP */ + uint8 *bssid; /**< MAC address of AP */ + uint8 channel; /**< channel, scan the specific channel */ + uint8 show_hidden; /**< enable to scan AP whose SSID is hidden */ +}; + +struct bss_info { + STAILQ_ENTRY(bss_info) next; /**< information of next AP */ + + uint8 bssid[6]; /**< MAC address of AP */ + uint8 ssid[32]; /**< SSID of AP */ + uint8 ssid_len; /**< SSID length */ + uint8 channel; /**< channel of AP */ + sint8 rssi; /**< single strength of AP */ + AUTH_MODE authmode; /**< authmode of AP */ + uint8 is_hidden; /**< SSID of current AP is hidden or not. */ + sint16 freq_offset; /**< frequency offset */ + sint16 freqcal_val; + uint8 *esp_mesh_ie; +}; + +/** + * @brief Callback function for wifi_station_scan. + * + * @param void *arg : information of APs that are found; save them as linked list; + * refer to struct bss_info + * @param STATUS status : status of scanning + * + * @return null + */ +typedef void (* scan_done_cb_t)(void *arg, STATUS status); + +/** + * @brief Scan all available APs. + * + * @attention This API should be called when the ESP8266 station is enabled, and + * the system initialization is completed. Do not call this API in user_init. + * + * @param struct scan_config *config : configuration of scanning + * @param struct scan_done_cb_t cb : callback of scanning + * + * @return true : succeed + * @return false : fail + */ +bool wifi_station_scan(struct scan_config *config, scan_done_cb_t cb); + +/** + * @brief Check if the ESP8266 station will connect to the recorded AP automatically + * when the power is on. + * + * @param null + * + * @return true : connect to the AP automatically + * @return false : not connect to the AP automatically + */ +bool wifi_station_get_auto_connect(void); + +/** + * @brief Set whether the ESP8266 station will connect to the recorded AP + * automatically when the power is on. It will do so by default. + * + * @attention 1. If this API is called in user_init, it is effective immediately + * after the power is on. If it is called in other places, it will + * be effective the next time when the power is on. + * @attention 2. This configuration will be saved in Flash system parameter area if changed. + * + * @param bool set : If it will automatically connect to the AP when the power is on + * - true : it will connect automatically + * - false: it will not connect automatically + * + * @return true : succeed + * @return false : fail + */ +bool wifi_station_set_auto_connect(bool set); + +/** + * @brief Check whether the ESP8266 station will reconnect to the AP after disconnection. + * + * @param null + * + * @return true : succeed + * @return false : fail + */ +bool wifi_station_get_reconnect_policy(void); + +/** + * @brief Set whether the ESP8266 station will reconnect to the AP after disconnection. + * It will do so by default. + * + * @attention If users want to call this API, it is suggested that users call this API in user_init. + * + * @param bool set : if it's true, it will enable reconnection; if it's false, + * it will disable reconnection. + * + * @return true : succeed + * @return false : fail + */ +bool wifi_station_set_reconnect_policy(bool set); + +typedef enum { + STATION_IDLE = 0, /**< ESP8266 station idle */ + STATION_CONNECTING, /**< ESP8266 station is connecting to AP*/ + STATION_WRONG_PASSWORD, /**< the password is wrong*/ + STATION_NO_AP_FOUND, /**< ESP8266 station can not find the target AP*/ + STATION_CONNECT_FAIL, /**< ESP8266 station fail to connect to AP*/ + STATION_GOT_IP /**< ESP8266 station got IP address from AP*/ +} STATION_STATUS; + +/** + * @brief Get the connection status of the ESP8266 WiFi station. + * + * @param null + * + * @return the status of connection + */ +STATION_STATUS wifi_station_get_connect_status(void); + +/** + * @brief Get the information of APs (5 at most) recorded by ESP8266 station. + * + * @param struct station_config config[] : information of the APs, the array size should be 5. + * + * @return The number of APs recorded. + */ +uint8 wifi_station_get_current_ap_id(void); + +/** + * @brief Switch the ESP8266 station connection to a recorded AP. + * + * @param uint8 new_ap_id : AP's record id, start counting from 0. + * + * @return true : succeed + * @return false : fail + */ +bool wifi_station_ap_change(uint8 current_ap_id); + +/** + * @brief Set the number of APs that can be recorded in the ESP8266 station. + * When the ESP8266 station is connected to an AP, the SSID and password + * of the AP will be recorded. + * + * @attention This configuration will be saved in the Flash system parameter area if changed. + * + * @param uint8 ap_number : the number of APs that can be recorded (MAX: 5) + * + * @return true : succeed + * @return false : fail + */ +bool wifi_station_ap_number_set(uint8 ap_number); + +/** + * @brief Get the information of APs (5 at most) recorded by ESP8266 station. + * + * Example: + *
 
+  *         struct station_config config[5];
+  *         nt i = wifi_station_get_ap_info(config);
+  * 
+ * + * @param struct station_config config[] : information of the APs, the array size should be 5. + * + * @return The number of APs recorded. + */ +uint8 wifi_station_get_ap_info(struct station_config config[]); + +/** + * @brief Get rssi of the AP which ESP8266 station connected to. + * + * @param null + * + * @return 31 : fail, invalid value. + * @return others : succeed, value of rssi. In general, rssi value < 10 + */ +sint8 wifi_station_get_rssi(void); + +/** + * @brief Enable the ESP8266 station DHCP client. + * + * @attention 1. The DHCP is enabled by default. + * @attention 2. The DHCP and the static IP API ((wifi_set_ip_info)) influence each other, + * and if the DHCP is enabled, the static IP will be disabled; + * if the static IP is enabled, the DHCP will be disabled. + * It depends on the latest configuration. + * + * @param null + * + * @return true : succeed + * @return false : fail + */ +bool wifi_station_dhcpc_start(void); + +/** + * @brief Disable the ESP8266 station DHCP client. + * + * @attention 1. The DHCP is enabled by default. + * @attention 2. The DHCP and the static IP API ((wifi_set_ip_info)) influence each other, + * and if the DHCP is enabled, the static IP will be disabled; + * if the static IP is enabled, the DHCP will be disabled. + * It depends on the latest configuration. + * + * @param null + * + * @return true : succeed + * @return false : fail + */ +bool wifi_station_dhcpc_stop(void); + +/** + * @brief Get the ESP8266 station DHCP client status. + * + * @param null + * + * @return enum dhcp_status + */ +enum dhcp_status wifi_station_dhcpc_status(void); + +/** + * @brief Set ESP8266 station DHCP hostname. + * + * @param char *name : hostname of ESP8266 station + * + * @return true : succeed + * @return false : fail + */ +bool wifi_station_set_hostname(char *name); + +/** + * @brief Get ESP8266 station DHCP hostname. + * + * @param null + * + * @return the hostname of ESP8266 station + */ +char* wifi_station_get_hostname(void); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_system.h b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_system.h new file mode 100644 index 0000000..2055e85 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_system.h @@ -0,0 +1,586 @@ +/* + * ESPRSSIF 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 __ESP_SYSTEM_H__ +#define __ESP_SYSTEM_H__ + +#include "c_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup System_APIs System APIs + * @brief System APIs + */ + +/** @addtogroup System_APIs + * @{ + */ + +typedef enum { + REASON_DEFAULT_RST = 0, /**< normal startup by power on */ + REASON_WDT_RST, /**< hardware watch dog reset */ + REASON_EXCEPTION_RST, /**< exception reset, GPIO status won't change */ + REASON_SOFT_WDT_RST, /**< software watch dog reset, GPIO status won't change */ + REASON_SOFT_RESTART, /**< software restart ,system_restart , GPIO status won't change */ + REASON_DEEP_SLEEP_AWAKE, /**< wake up from deep-sleep */ + REASON_EXT_SYS_RST /**< external system reset */ +} rst_reason; + +struct rst_info { + rst_reason reason; /**< enum rst_reason */ + uint32 exccause; + uint32 epc1; + uint32 epc2; + uint32 epc3; + uint32 excvaddr; + uint32 depc; + uint32 rtn_addr; +}; + +/** + * @brief Get the reason of restart. + * + * @param null + * + * @return struct rst_info* : information of the system restart + */ +struct rst_info *system_get_rst_info(void); + +/** + * @brief Get information of the SDK version. + * + * @param null + * + * @return Information of the SDK version. + */ +const char *system_get_sdk_version(void); + +/** + * @brief Reset to default settings. + * + * Reset to default settings of the following APIs : wifi_station_set_auto_connect, + * wifi_set_phy_mode, wifi_softap_set_config related, wifi_station_set_config + * related, and wifi_set_opmode. + * + * @param null + * + * @return null + */ +void system_restore(void); + +/** + * @brief Restart system. + * + * @param null + * + * @return null + */ +void system_restart(void); + +/** + * @brief Set the chip to deep-sleep mode. + * + * The device will automatically wake up after the deep-sleep time set + * by the users. Upon waking up, the device boots up from user_init. + * + * @attention 1. XPD_DCDC should be connected to EXT_RSTB through 0 ohm resistor + * in order to support deep-sleep wakeup. + * @attention 2. system_deep_sleep(0): there is no wake up timer; in order to wake + * up, connect a GPIO to pin RST, the chip will wake up by a falling-edge + * on pin RST + * + * @param uint32 time_in_us : deep-sleep time, unit: microsecond + * + * @return null + */ +void system_deep_sleep(uint32 time_in_us); + +/** + * @brief Call this API before system_deep_sleep to set the activity after the + * next deep-sleep wakeup. + * + * If this API is not called, default to be system_deep_sleep_set_option(1). + * + * @param uint8 option : + * @param 0 : Radio calibration after the deep-sleep wakeup is decided by byte + * 108 of esp_init_data_default.bin (0~127byte). + * @param 1 : Radio calibration will be done after the deep-sleep wakeup. This + * will lead to stronger current. + * @param 2 : Radio calibration will not be done after the deep-sleep wakeup. + * This will lead to weaker current. + * @param 4 : Disable radio calibration after the deep-sleep wakeup (the same + * as modem-sleep). This will lead to the weakest current, but the device + * can't receive or transmit data after waking up. + * + * @return true : succeed + * @return false : fail + */ +bool system_deep_sleep_set_option(uint8 option); + +/** + * @brief Get system time, unit: microsecond. + * + * @param null + * + * @return System time, unit: microsecond. + */ +uint32 system_get_time(void); + +/** + * @brief Print the system memory distribution, including data/rodata/bss/heap. + * + * @param null + * + * @return null + */ +void system_print_meminfo(void); + +/** + * @brief Get the size of available heap. + * + * @param null + * + * @return Available heap size. + */ +uint32 system_get_free_heap_size(void); + +/** + * @brief Get the chip ID. + * + * @param null + * + * @return The chip ID. + */ +uint32 system_get_chip_id(void); + +/** + * @brief Get the RTC clock cycle. + * + * @attention 1. The RTC clock cycle has decimal part. + * @attention 2. The RTC clock cycle will change according to the temperature, + * so RTC timer is not very precise. + * + * @param null + * + * @return RTC clock period (unit: microsecond), bit11~ bit0 are decimal. + */ +uint32 system_rtc_clock_cali_proc(void); + +/** + * @brief Get RTC time, unit: RTC clock cycle. + * + * Example: + * If system_get_rtc_time returns 10 (it means 10 RTC cycles), and + * system_rtc_clock_cali_proc returns 5.75 (it means 5.75 microseconds per RTC clock cycle), + * (then the actual time is 10 x 5.75 = 57.5 microseconds. + * + * @attention System time will return to zero because of system_restart, but the + * RTC time still goes on. If the chip is reset by pin EXT_RST or pin + * CHIP_EN (including the deep-sleep wakeup), situations are shown as below: + * @attention 1. reset by pin EXT_RST : RTC memory won't change, RTC timer returns to zero + * @attention 2. watchdog reset : RTC memory won't change, RTC timer won't change + * @attention 3. system_restart : RTC memory won't change, RTC timer won't change + * @attention 4. power on : RTC memory is random value, RTC timer starts from zero + * @attention 5. reset by pin CHIP_EN : RTC memory is random value, RTC timer starts from zero + * + * @param null + * + * @return RTC time. + */ +uint32 system_get_rtc_time(void); + +/** + * @brief Read user data from the RTC memory. + * + * The user data segment (512 bytes, as shown below) is used to store user data. + * + * |<---- system data(256 bytes) ---->|<----------- user data(512 bytes) --------->| + * + * @attention Read and write unit for data stored in the RTC memory is 4 bytes. + * @attention src_addr is the block number (4 bytes per block). So when reading data + * at the beginning of the user data segment, src_addr will be 256/4 = 64, + * n will be data length. + * + * @param uint8 src : source address of rtc memory, src_addr >= 64 + * @param void *dst : data pointer + * @param uint16 n : data length, unit: byte + * + * @return true : succeed + * @return false : fail + */ +bool system_rtc_mem_read(uint8 src, void *dst, uint16 n); + +/** + * @brief Write user data to the RTC memory. + * + * During deep-sleep, only RTC is working. So users can store their data + * in RTC memory if it is needed. The user data segment below (512 bytes) + * is used to store the user data. + * + * |<---- system data(256 bytes) ---->|<----------- user data(512 bytes) --------->| + * + * @attention Read and write unit for data stored in the RTC memory is 4 bytes. + * @attention src_addr is the block number (4 bytes per block). So when storing data + * at the beginning of the user data segment, src_addr will be 256/4 = 64, + * n will be data length. + * + * @param uint8 src : source address of rtc memory, src_addr >= 64 + * @param void *dst : data pointer + * @param uint16 n : data length, unit: byte + * + * @return true : succeed + * @return false : fail + */ +bool system_rtc_mem_write(uint8 dst, const void *src, uint16 n); + +/** + * @brief UART0 swap. + * + * Use MTCK as UART0 RX, MTDO as UART0 TX, so ROM log will not output from + * this new UART0. We also need to use MTDO (U0RTS) and MTCK (U0CTS) as UART0 in hardware. + * + * @param null + * + * @return null + */ +void system_uart_swap(void); + +/** + * @brief Disable UART0 swap. + * + * Use the original UART0, not MTCK and MTDO. + * + * @param null + * + * @return null + */ +void system_uart_de_swap(void); + +/** + * @brief Measure the input voltage of TOUT pin 6, unit : 1/1024 V. + * + * @attention 1. system_adc_read can only be called when the TOUT pin is connected + * to the external circuitry, and the TOUT pin input voltage should + * be limited to 0~1.0V. + * @attention 2. When the TOUT pin is connected to the external circuitry, the 107th + * byte (vdd33_const) of esp_init_data_default.bin(0~127byte) should be + * set as the real power voltage of VDD3P3 pin 3 and 4. + * @attention 3. The unit of vdd33_const is 0.1V, the effective value range is [18, 36]; + * if vdd33_const is in [0, 18) or (36, 255), 3.3V is used to optimize RF by default. + * + * @param null + * + * @return Input voltage of TOUT pin 6, unit : 1/1024 V + */ +uint16 system_adc_read(void); + +/** + * @brief Measure the power voltage of VDD3P3 pin 3 and 4, unit : 1/1024 V. + * + * @attention 1. system_get_vdd33 depends on RF, please do not use it if RF is disabled. + * @attention 2. system_get_vdd33 can only be called when TOUT pin is suspended. + * @attention 3. The 107th byte in esp_init_data_default.bin (0~127byte) is named + * as "vdd33_const", when TOUT pin is suspended vdd33_const must be + * set as 0xFF, that is 255. + * + * @param null + * + * @return Power voltage of VDD33, unit : 1/1024 V + */ +uint16 system_get_vdd33(void); + +/** + * @brief Write data into flash with protection. + * + * Flash read/write has to be 4-bytes aligned. + * + * Protection of flash read/write : + * use 3 sectors (4KBytes per sector) to save 4KB data with protect, + * sector 0 and sector 1 are data sectors, back up each other, + * save data alternately, sector 2 is flag sector, point out which sector + * is keeping the latest data, sector 0 or sector 1. + * + * @param uint16 start_sec : start sector (sector 0) of the 3 sectors which are + * used for flash read/write protection. + * - For example, in IOT_Demo we can use the 3 sectors (3 * 4KB) starting from flash + * 0x3D000 for flash read/write protection, so the parameter start_sec should be 0x3D + * @param void *param : pointer of the data to be written + * @param uint16 len : data length, should be less than a sector, which is 4 * 1024 + * + * @return true : succeed + * @return false : fail + */ +bool system_param_save_with_protect(uint16 start_sec, void *param, uint16 len); + +/** + * @brief Read the data saved into flash with the read/write protection. + * + * Flash read/write has to be 4-bytes aligned. + * + * Read/write protection of flash: + * use 3 sectors (4KB per sector) to save 4KB data with protect, sector + * 0 and sector 1 are data sectors, back up each other, save data alternately, + * sector 2 is flag sector, point out which sector is keeping the latest data, + * sector 0 or sector 1. + * + * @param uint16 start_sec : start sector (sector 0) of the 3 sectors used for + * flash read/write protection. It cannot be sector 1 or sector 2. + * - For example, in IOT_Demo, the 3 sectors (3 * 4KB) starting from flash 0x3D000 + * can be used for flash read/write protection. + * The parameter start_sec is 0x3D, and it cannot be 0x3E or 0x3F. + * @param uint16 offset : offset of data saved in sector + * @param void *param : data pointer + * @param uint16 len : data length, offset + len =< 4 * 1024 + * + * @return true : succeed + * @return false : fail + */ +bool system_param_load(uint16 start_sec, uint16 offset, void *param, uint16 len); + +/** + * @brief Set the maximum value of RF TX Power, unit : 0.25dBm. + * + * @param uint8 max_tpw : the maximum value of RF Tx Power, unit : 0.25dBm, range [0, 82]. + * It can be set refer to the 34th byte (target_power_qdb_0) + * of esp_init_data_default.bin(0~127byte) + * + * @return null + */ +void system_phy_set_max_tpw(uint8 max_tpw); + +/** + * @brief Adjust the RF TX Power according to VDD33, unit : 1/1024 V. + * + * @attention 1. When TOUT pin is suspended, VDD33 can be measured by system_get_vdd33. + * @attention 2. When TOUT pin is connected to the external circuitry, system_get_vdd33 + * can not be used to measure VDD33. + * + * @param uint16 vdd33 : VDD33, unit : 1/1024V, range [1900, 3300] + * + * @return null + */ +void system_phy_set_tpw_via_vdd33(uint16 vdd33); + +/** + * @brief Enable RF or not when wakeup from deep-sleep. + * + * @attention 1. This API can only be called in user_rf_pre_init. + * @attention 2. Function of this API is similar to system_deep_sleep_set_option, + * if they are both called, it will disregard system_deep_sleep_set_option + * which is called before deep-sleep, and refer to system_phy_set_rfoption + * which is called when deep-sleep wake up. + * @attention 3. Before calling this API, system_deep_sleep_set_option should be called + * once at least. + * + * @param uint8 option : + * - 0 : Radio calibration after deep-sleep wake up depends on esp_init_data_default.bin (0~127byte) byte 108. + * - 1 : Radio calibration is done after deep-sleep wake up; this increases the + * current consumption. + * - 2 : No radio calibration after deep-sleep wake up; this reduces the current consumption. + * - 4 : Disable RF after deep-sleep wake up, just like modem sleep; this has the + * least current consumption; the device is not able to transmit or receive + * data after wake up. + * + * @return null + */ +void system_phy_set_rfoption(uint8 option); + +/** @addtogroup Upgrade_APIs + * @{ + */ + +/** + * @brief Check the user bin. + * + * @param null + * + * @return 0x00 : UPGRADE_FW_BIN1, i.e. user1.bin + * @return 0x01 : UPGRADE_FW_BIN2, i.e. user2.bin + */ +uint8 system_upgrade_userbin_check(void); + +/** + * @brief Reboot system to use the new software. + * + * @param null + * + * @return null + */ +void system_upgrade_reboot(void); + +/** + * @brief Check the upgrade status flag. + * + * @param null + * + * @return #define UPGRADE_FLAG_IDLE 0x00 + * @return #define UPGRADE_FLAG_START 0x01 + * @return #define UPGRADE_FLAG_FINISH 0x02 + */ +uint8 system_upgrade_flag_check(); + +/** + * @brief Set the upgrade status flag. + * + * @attention After downloading new softwares, set the flag to UPGRADE_FLAG_FINISH + * and call system_upgrade_reboot to reboot the system in order to run + * the new software. + * + * @param uint8 flag: + * - UPGRADE_FLAG_IDLE 0x00 + * - UPGRADE_FLAG_START 0x01 + * - UPGRADE_FLAG_FINISH 0x02 + * + * @return null + */ +void system_upgrade_flag_set(uint8 flag); + +/** + * @} + */ + +/** \defgroup System_boot_APIs Boot APIs + * @brief boot APIs + */ + +/** @addtogroup System_boot_APIs + * @{ + */ + +#define SYS_BOOT_ENHANCE_MODE 0 /**< It can load and run firmware at any address, for Espressif factory test bin*/ +#define SYS_BOOT_NORMAL_MODE 1 /**< It can only load and run at some addresses of user1.bin (or user2.bin)*/ + +#define SYS_BOOT_NORMAL_BIN 0 /**< user1.bin or user2.bin*/ +#define SYS_BOOT_TEST_BIN 1 /**< can only be Espressif test bin*/ + +/** + * @brief Get information of the boot version. + * + * @attention If boot version >= 1.3 , users can enable the enhanced boot mode + * (refer to system_restart_enhance). + * + * @param null + * + * @return Information of the boot version. + */ +uint8 system_get_boot_version(void); + +/** + * @brief Get the address of the current running user bin (user1.bin or user2.bin). + * + * @param null + * + * @return The address of the current running user bin. + */ +uint32 system_get_userbin_addr(void); + +/** + * @brief Get the boot mode. + * + * @param null + * + * @return #define SYS_BOOT_ENHANCE_MODE 0 + * @return #define SYS_BOOT_NORMAL_MODE 1 + */ +uint8 system_get_boot_mode(void); + +/** + * @brief Restarts the system, and enters the enhanced boot mode. + * + * @attention SYS_BOOT_TEST_BIN is used for factory test during production; users + * can apply for the test bin from Espressif Systems. + * + * @param uint8 bin_type : type of bin + * - #define SYS_BOOT_NORMAL_BIN 0 // user1.bin or user2.bin + * - #define SYS_BOOT_TEST_BIN 1 // can only be Espressif test bin + * @param uint32 bin_addr : starting address of the bin file + * + * @return true : succeed + * @return false : fail + */ +bool system_restart_enhance(uint8 bin_type, uint32 bin_addr); + +typedef enum { + 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_map; + +/** + * @brief Get the current Flash size and Flash map. + * + * Flash map depends on the selection when compiling, more details in document + * "2A-ESP8266__IOT_SDK_User_Manual" + * + * @param null + * + * @return enum flash_size_map + */ +flash_size_map system_get_flash_size_map(void); + +#define SYS_CPU_80MHZ 80 +#define SYS_CPU_160MHZ 160 + +/** + * @brief Set CPU frequency. Default is 80MHz. + * + * System bus frequency is 80MHz, will not be affected by CPU frequency. + * The frequency of UART, SPI, or other peripheral devices, are divided + * from system bus frequency, so they will not be affected by CPU frequency either. + * + * @param uint8 freq : CPU frequency, 80 or 160. + * + * @return true : succeed + * @return false : fail + */ +bool system_update_cpu_freq(uint8 freq); + +/** + * @brief Get CPU frequency. + * + * @param null + * + * @return CPU frequency, unit : MHz. + */ +uint8 system_get_cpu_freq(void); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_timer.h b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_timer.h new file mode 100644 index 0000000..6fb6e1f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_timer.h @@ -0,0 +1,101 @@ +/* + * ESPRSSIF 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 __ESP_TIMER_H__ +#define __ESP_TIMER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* timer related */ +typedef void os_timer_func_t(void *timer_arg); + +typedef struct _os_timer_t { + struct _os_timer_t *timer_next; + void *timer_handle; + uint32 timer_expire; + uint32 timer_period; + os_timer_func_t *timer_func; + bool timer_repeat_flag; + void *timer_arg; +} os_timer_t; + +/** \defgroup Timer_APIs Software timer APIs + * @brief Software timer APIs + * + * Timers of the following interfaces are software timers. Functions of the timers are executed during the tasks. + * Since a task can be stopped, or be delayed because there are other tasks with higher priorities, the following os_timer interfaces cannot guarantee the precise execution of the timers. + * - For the same timer, os_timer_arm (or os_timer_arm_us) cannot be invoked repeatedly. os_timer_disarm should be invoked first. + * - os_timer_setfn can only be invoked when the timer is not enabled, i.e., after os_timer_disarm or before os_timer_arm (or os_timer_arm_us). + * + */ + +/** @addtogroup Timer_APIs + * @{ + */ + +/** + * @brief Set the timer callback function. + * + * @attention 1. The callback function must be set in order to enable the timer. + * @attention 2. Operating system scheduling is disabled in timer callback. + * + * @param os_timer_t *ptimer : Timer structure + * @param os_timer_func_t *pfunction : timer callback function + * @param void *parg : callback function parameter + * + * @return null + */ +void os_timer_setfn(os_timer_t *ptimer, os_timer_func_t *pfunction, void *parg); + +/** + * @brief Enable the millisecond timer. + * + * @param os_timer_t *ptimer : timer structure + * @param uint32_t milliseconds : Timing, unit: millisecond, range: 5 ~ 0x68DB8 + * @param bool repeat_flag : Whether the timer will be invoked repeatedly or not + * + * @return null + */ +void os_timer_arm(os_timer_t *ptimer, uint32 msec, bool repeat_flag); + +/** + * @brief Disarm the timer + * + * @param os_timer_t *ptimer : Timer structure + * + * @return null + */ +void os_timer_disarm(os_timer_t *ptimer); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_wifi.h b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_wifi.h new file mode 100644 index 0000000..2e48d91 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_wifi.h @@ -0,0 +1,989 @@ +/* + * ESPRSSIF 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 __ESP_WIFI_H__ +#define __ESP_WIFI_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup WiFi_APIs WiFi Related APIs + * @brief WiFi APIs + */ + +/** @addtogroup WiFi_APIs + * @{ + */ + +/** \defgroup WiFi_Common_APIs Common APIs + * @brief WiFi common APIs + * + * The Flash system parameter area is the last 16KB of the Flash. + * + */ + +/** @addtogroup WiFi_Common_APIs + * @{ + */ + +typedef enum { + NULL_MODE = 0, /**< null mode */ + STATION_MODE, /**< WiFi station mode */ + SOFTAP_MODE, /**< WiFi soft-AP mode */ + STATIONAP_MODE, /**< WiFi station + soft-AP mode */ + MAX_MODE +} WIFI_MODE; + +typedef enum { + AUTH_OPEN = 0, /**< authenticate mode : open */ + AUTH_WEP, /**< authenticate mode : WEP */ + AUTH_WPA_PSK, /**< authenticate mode : WPA_PSK */ + AUTH_WPA2_PSK, /**< authenticate mode : WPA2_PSK */ + AUTH_WPA_WPA2_PSK, /**< authenticate mode : WPA_WPA2_PSK */ + AUTH_MAX +} AUTH_MODE; + +/** + * @brief Get the current operating mode of the WiFi. + * + * @param null + * + * @return WiFi operating modes: + * - 0x01: station mode; + * - 0x02: soft-AP mode + * - 0x03: station+soft-AP mode + */ +WIFI_MODE wifi_get_opmode(void); + +/** + * @brief Get the operating mode of the WiFi saved in the Flash. + * + * @param null + * + * @return WiFi operating modes: + * - 0x01: station mode; + * - 0x02: soft-AP mode + * - 0x03: station+soft-AP mode + */ +WIFI_MODE wifi_get_opmode_default(void); + +/** + * @brief Set the WiFi operating mode, and save it to Flash. + * + * Set the WiFi operating mode as station, soft-AP or station+soft-AP, + * and save it to Flash. The default mode is soft-AP mode. + * + * @attention This configuration will be saved in the Flash system parameter area if changed. + * + * @param uint8 opmode : WiFi operating modes: + * - 0x01: station mode; + * - 0x02: soft-AP mode + * - 0x03: station+soft-AP mode + * + * @return true : succeed + * @return false : fail + */ +bool wifi_set_opmode(WIFI_MODE opmode); + +/** + * @brief Set the WiFi operating mode, and will not save it to Flash. + * + * Set the WiFi operating mode as station, soft-AP or station+soft-AP, and + * the mode won't be saved to the Flash. + * + * @param uint8 opmode : WiFi operating modes: + * - 0x01: station mode; + * - 0x02: soft-AP mode + * - 0x03: station+soft-AP mode + * + * @return true : succeed + * @return false : fail + */ +bool wifi_set_opmode_current(WIFI_MODE opmode); + +typedef enum { + STATION_IF = 0, /**< ESP8266 station interface */ + SOFTAP_IF, /**< ESP8266 soft-AP interface */ + MAX_IF +} WIFI_INTERFACE; + +struct ip_info { + struct ip_addr ip; /**< IP address */ + struct ip_addr netmask; /**< netmask */ + struct ip_addr gw; /**< gateway */ +}; + +/** + * @brief Get the IP address of the ESP8266 WiFi station or the soft-AP interface. + * + * @attention Users need to enable the target interface (station or soft-AP) by wifi_set_opmode first. + * + * @param WIFI_INTERFACE if_index : get the IP address of the station or the soft-AP interface, + * 0x00 for STATION_IF, 0x01 for SOFTAP_IF. + * @param struct ip_info *info : the IP information obtained. + * + * @return true : succeed + * @return false : fail + */ +bool wifi_get_ip_info(WIFI_INTERFACE if_index, struct ip_info *info); + +/** + * @brief Set the IP address of the ESP8266 WiFi station or the soft-AP interface. + * + * @attention 1. Users need to enable the target interface (station or soft-AP) by + * wifi_set_opmode first. + * @attention 2. To set static IP, users need to disable DHCP first (wifi_station_dhcpc_stop + * or wifi_softap_dhcps_stop): + * - If the DHCP is enabled, the static IP will be disabled; if the static IP is enabled, + * the DHCP will be disabled. It depends on the latest configuration. + * + * @param WIFI_INTERFACE if_index : get the IP address of the station or the soft-AP interface, + * 0x00 for STATION_IF, 0x01 for SOFTAP_IF. + * @param struct ip_info *info : the IP information obtained. + * + * @return true : succeed + * @return false : fail + */ +bool wifi_set_ip_info(WIFI_INTERFACE if_index, struct ip_info *info); + +/** + * @brief Get MAC address of the ESP8266 WiFi station or the soft-AP interface. + * + * @param WIFI_INTERFACE if_index : get the IP address of the station or the soft-AP interface, + * 0x00 for STATION_IF, 0x01 for SOFTAP_IF. + * @param uint8 *macaddr : the MAC address. + * + * @return true : succeed + * @return false : fail + */ +bool wifi_get_macaddr(WIFI_INTERFACE if_index, uint8 *macaddr); + +/** + * @brief Set MAC address of the ESP8266 WiFi station or the soft-AP interface. + * + * @attention 1. This API can only be called in user_init. + * @attention 2. Users need to enable the target interface (station or soft-AP) by wifi_set_opmode first. + * @attention 3. ESP8266 soft-AP and station have different MAC addresses, do not set them to be the same. + * - The bit0 of the first byte of ESP8266 MAC address can not be 1. For example, the MAC address + * can set to be "1a:XX:XX:XX:XX:XX", but can not be "15:XX:XX:XX:XX:XX". + * + * @param WIFI_INTERFACE if_index : get the IP address of the station or the soft-AP interface, + * 0x00 for STATION_IF, 0x01 for SOFTAP_IF. + * @param uint8 *macaddr : the MAC address. + * + * @return true : succeed + * @return false : fail + */ +bool wifi_set_macaddr(WIFI_INTERFACE if_index, uint8 *macaddr); + +/** + * @brief Install the WiFi status LED. + * + * @param uint8 gpio_id : GPIO ID + * @param uint8 gpio_name : GPIO mux name + * @param uint8 gpio_func : GPIO function + * + * @return null + */ +void wifi_status_led_install(uint8 gpio_id, uint32 gpio_name, uint8 gpio_func); + +/** + * @brief Uninstall the WiFi status LED. + * + * @param null + * + * @return null + */ +void wifi_status_led_uninstall(void); + +typedef enum { + PHY_MODE_11B = 1, /**< 802.11b */ + PHY_MODE_11G = 2, /**< 802.11g */ + PHY_MODE_11N = 3 /**< 802.11n */ +} WIFI_PHY_MODE; + +/** + * @brief Get the ESP8266 physical mode (802.11b/g/n). + * + * @param null + * + * @return enum WIFI_PHY_MODE + */ +WIFI_PHY_MODE wifi_get_phy_mode(void); + +/** + * @brief Set the ESP8266 physical mode (802.11b/g/n). + * + * @attention The ESP8266 soft-AP only supports bg. + * + * @param WIFI_PHY_MODE mode : physical mode + * + * @return true : succeed + * @return false : fail + */ +bool wifi_set_phy_mode(WIFI_PHY_MODE mode); + +typedef enum { + EVENT_STAMODE_SCAN_DONE = 0, /**< ESP8266 station finish scanning AP */ + EVENT_STAMODE_CONNECTED, /**< ESP8266 station connected to AP */ + EVENT_STAMODE_DISCONNECTED, /**< ESP8266 station disconnected to AP */ + EVENT_STAMODE_AUTHMODE_CHANGE, /**< the auth mode of AP connected by ESP8266 station changed */ + EVENT_STAMODE_GOT_IP, /**< ESP8266 station got IP from connected AP */ + EVENT_STAMODE_DHCP_TIMEOUT, /**< ESP8266 station dhcp client got IP timeout */ + EVENT_SOFTAPMODE_STACONNECTED, /**< a station connected to ESP8266 soft-AP */ + EVENT_SOFTAPMODE_STADISCONNECTED, /**< a station disconnected to ESP8266 soft-AP */ + EVENT_SOFTAPMODE_PROBEREQRECVED, /**< Receive probe request packet in soft-AP interface */ + EVENT_MAX +} SYSTEM_EVENT; + +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, + REASON_DISASSOC_SUPCHAN_BAD = 11, + REASON_IE_INVALID = 13, + REASON_MIC_FAILURE = 14, + REASON_4WAY_HANDSHAKE_TIMEOUT = 15, + REASON_GROUP_KEY_UPDATE_TIMEOUT = 16, + REASON_IE_IN_4WAY_DIFFERS = 17, + REASON_GROUP_CIPHER_INVALID = 18, + REASON_PAIRWISE_CIPHER_INVALID = 19, + REASON_AKMP_INVALID = 20, + REASON_UNSUPP_RSN_IE_VERSION = 21, + REASON_INVALID_RSN_IE_CAP = 22, + REASON_802_1X_AUTH_FAILED = 23, + REASON_CIPHER_SUITE_REJECTED = 24, + + REASON_BEACON_TIMEOUT = 200, + REASON_NO_AP_FOUND = 201, + REASON_AUTH_FAIL = 202, + REASON_ASSOC_FAIL = 203, + REASON_HANDSHAKE_TIMEOUT = 204, +}; + +typedef struct { + uint32 status; /**< status of scanning APs*/ + struct bss_info *bss; /**< list of APs found*/ +} Event_StaMode_ScanDone_t; + +typedef struct { + uint8 ssid[32]; /**< SSID of connected AP */ + uint8 ssid_len; /**< SSID length of connected AP */ + uint8 bssid[6]; /**< BSSID of connected AP*/ + uint8 channel; /**< channel of connected AP*/ +} Event_StaMode_Connected_t; + +typedef struct { + uint8 ssid[32]; /**< SSID of disconnected AP */ + uint8 ssid_len; /**< SSID length of disconnected AP */ + uint8 bssid[6]; /**< BSSID of disconnected AP */ + uint8 reason; /**< reason of disconnection */ +} Event_StaMode_Disconnected_t; + +typedef struct { + uint8 old_mode; /**< the old auth mode of AP */ + uint8 new_mode; /**< the new auth mode of AP */ +} Event_StaMode_AuthMode_Change_t; + +typedef struct { + struct ip_addr ip; /**< IP address that ESP8266 station got from connected AP */ + struct ip_addr mask; /**< netmask that ESP8266 station got from connected AP */ + struct ip_addr gw; /**< gateway that ESP8266 station got from connected AP */ +} Event_StaMode_Got_IP_t; + +typedef struct { + uint8 mac[6]; /**< MAC address of the station connected to ESP8266 soft-AP */ + uint8 aid; /**< the aid that ESP8266 soft-AP gives to the station connected to */ +} Event_SoftAPMode_StaConnected_t; + +typedef struct { + uint8 mac[6]; /**< MAC address of the station disconnects to ESP8266 soft-AP */ + uint8 aid; /**< the aid that ESP8266 soft-AP gave to the station disconnects to */ +} Event_SoftAPMode_StaDisconnected_t; + +typedef struct { + int rssi; /**< Received probe request signal strength */ + uint8 mac[6]; /**< MAC address of the station which send probe request */ +} Event_SoftAPMode_ProbeReqRecved_t; + +typedef union { + Event_StaMode_ScanDone_t scan_done; /**< ESP8266 station scan (APs) done */ + Event_StaMode_Connected_t connected; /**< ESP8266 station connected to AP */ + Event_StaMode_Disconnected_t disconnected; /**< ESP8266 station disconnected to AP */ + Event_StaMode_AuthMode_Change_t auth_change; /**< the auth mode of AP ESP8266 station connected to changed */ + Event_StaMode_Got_IP_t got_ip; /**< ESP8266 station got IP */ + Event_SoftAPMode_StaConnected_t sta_connected; /**< a station connected to ESP8266 soft-AP */ + Event_SoftAPMode_StaDisconnected_t sta_disconnected; /**< a station disconnected to ESP8266 soft-AP */ + Event_SoftAPMode_ProbeReqRecved_t ap_probereqrecved; /**< ESP8266 softAP receive probe request packet */ +} Event_Info_u; + +typedef struct _esp_event { + SYSTEM_EVENT event_id; /**< even ID */ + Event_Info_u event_info; /**< event information */ +} System_Event_t; + +/** + * @brief The Wi-Fi event handler. + * + * @attention No complex operations are allowed in callback. + * If users want to execute any complex operations, please post message to another task instead. + * + * @param System_Event_t *event : WiFi event + * + * @return null + */ +typedef void (* wifi_event_handler_cb_t)(System_Event_t *event); + +/** + * @brief Register the Wi-Fi event handler. + * + * @param wifi_event_handler_cb_t cb : callback function + * + * @return true : succeed + * @return false : fail + */ +bool wifi_set_event_handler_cb(wifi_event_handler_cb_t cb); + +/** + * @brief Callback of sending user-define 802.11 packets. + * + * @param uint8 status : 0, packet sending succeed; otherwise, fail. + * + * @return null + */ +typedef void (*freedom_outside_cb_t)(uint8 status); + +/** + * @brief Register a callback for sending user-define 802.11 packets. + * + * @attention Only after the previous packet was sent, entered the freedom_outside_cb_t, + * the next packet is allowed to send. + * + * @param freedom_outside_cb_t cb : sent callback + * + * @return 0, succeed; + * @return -1, fail. + */ +sint32 wifi_register_send_pkt_freedom_cb(freedom_outside_cb_t cb); + +/** + * @brief Unregister the callback for sending user-define 802.11 packets. + * + * @param null + * + * @return null + */ +void wifi_unregister_send_pkt_freedom_cb(void); + +/** + * @brief Send user-define 802.11 packets. + * + * @attention 1. Packet has to be the whole 802.11 packet, does not include the FCS. + * The length of the packet has to be longer than the minimum length + * of the header of 802.11 packet which is 24 bytes, and less than 1400 bytes. + * @attention 2. Duration area is invalid for user, it will be filled in SDK. + * @attention 3. The rate of sending packet is same as the management packet which + * is the same as the system rate of sending packets. + * @attention 4. Only after the previous packet was sent, entered the sent callback, + * the next packet is allowed to send. Otherwise, wifi_send_pkt_freedom + * will return fail. + * + * @param uint8 *buf : pointer of packet + * @param uint16 len : packet length + * @param bool sys_seq : follow the system's 802.11 packets sequence number or not, + * if it is true, the sequence number will be increased 1 every + * time a packet sent. + * + * @return 0, succeed; + * @return -1, fail. + */ +sint32 wifi_send_pkt_freedom(uint8 *buf, uint16 len, bool sys_seq); + +/** + * @brief Enable RFID LOCP (Location Control Protocol) to receive WDS packets. + * + * @param null + * + * @return 0, succeed; + * @return otherwise, fail. + */ +sint32 wifi_rfid_locp_recv_open(void); + +/** + * @brief Disable RFID LOCP (Location Control Protocol) . + * + * @param null + * + * @return null + */ +void wifi_rfid_locp_recv_close(void); + +/** + * @brief RFID LOCP (Location Control Protocol) receive callback . + * + * @param uint8 *frm : point to the head of 802.11 packet + * @param int len : packet length + * @param int rssi : signal strength + * + * @return null + */ +typedef void (*rfid_locp_cb_t)(uint8 *frm, int len, sint8 rssi); + +/** + * @brief Register a callback of receiving WDS packets. + * + * Register a callback of receiving WDS packets. Only if the first MAC + * address of the WDS packet is a multicast address. + * + * @param rfid_locp_cb_t cb : callback + * + * @return 0, succeed; + * @return otherwise, fail. + */ +sint32 wifi_register_rfid_locp_recv_cb(rfid_locp_cb_t cb); + +/** + * @brief Unregister the callback of receiving WDS packets. + * + * @param null + * + * @return null + */ +void wifi_unregister_rfid_locp_recv_cb(void); + +typedef enum { + NONE_SLEEP_T = 0, + LIGHT_SLEEP_T, + MODEM_SLEEP_T +} sleep_type; + +/** + * @brief Sets sleep type. + * + * Set NONE_SLEEP_T to disable sleep. Default to be Modem sleep. + * + * @attention Sleep function only takes effect in station-only mode. + * + * @param sleep_type type : sleep type + * + * @return true : succeed + * @return false : fail + */ +bool wifi_set_sleep_type(sleep_type type); + +/** + * @brief Gets sleep type. + * + * @param null + * + * @return sleep type + */ +sleep_type wifi_get_sleep_type(void); + +/** + * @} + */ + + +/** \defgroup WiFi_Force_Sleep_APIs Force Sleep APIs + * @brief WiFi Force Sleep APIs + */ + +/** @addtogroup WiFi_Force_Sleep_APIs + * @{ + */ + +/** + * @brief Enable force sleep function. + * + * @attention Force sleep function is disabled by default. + * + * @param null + * + * @return null + */ +void wifi_fpm_open(void); + +/** + * @brief Disable force sleep function. + * + * @param null + * + * @return null + */ +void wifi_fpm_close(void); + +/** + * @brief Wake ESP8266 up from MODEM_SLEEP_T force sleep. + * + * @attention This API can only be called when MODEM_SLEEP_T force sleep function + * is enabled, after calling wifi_fpm_open. + * This API can not be called after calling wifi_fpm_close. + * + * @param null + * + * @return null + */ +void wifi_fpm_do_wakeup(void); + +typedef void (*fpm_wakeup_cb)(void); + +/** + * @brief Set a callback of waken up from force sleep because of time out. + * + * @attention 1. This API can only be called when force sleep function is enabled, + * after calling wifi_fpm_open. This API can not be called after calling + * wifi_fpm_close. + * @attention 2. fpm_wakeup_cb_func will be called after system woke up only if the + * force sleep time out (wifi_fpm_do_sleep and the parameter is not 0xFFFFFFF). + * @attention 3. fpm_wakeup_cb_func will not be called if woke up by wifi_fpm_do_wakeup + * from MODEM_SLEEP_T type force sleep. + * + * @param void (*fpm_wakeup_cb_func)(void) : callback of waken up + * + * @return null + */ +void wifi_fpm_set_wakeup_cb(fpm_wakeup_cb cb); + +/** + * @brief Force ESP8266 enter sleep mode, and it will wake up automatically when time out. + * + * @attention 1. This API can only be called when force sleep function is enabled, after + * calling wifi_fpm_open. This API can not be called after calling wifi_fpm_close. + * @attention 2. If this API returned 0 means that the configuration is set successfully, + * but the ESP8266 will not enter sleep mode immediately, it is going to sleep + * in the system idle task. Please do not call other WiFi related function right + * after calling this API. + * + * @param uint32 sleep_time_in_us : sleep time, ESP8266 will wake up automatically + * when time out. Unit: us. Range: 10000 ~ 268435455(0xFFFFFFF). + * - If sleep_time_in_us is 0xFFFFFFF, the ESP8266 will sleep till + * - if wifi_fpm_set_sleep_type is set to be LIGHT_SLEEP_T, ESP8266 can wake up by GPIO. + * - if wifi_fpm_set_sleep_type is set to be MODEM_SLEEP_T, ESP8266 can wake up by wifi_fpm_do_wakeup. + * + * @return 0, setting succeed; + * @return -1, fail to sleep, sleep status error; + * @return -2, fail to sleep, force sleep function is not enabled. + */ +sint8 wifi_fpm_do_sleep(uint32 sleep_time_in_us); + +/** + * @brief Set sleep type for force sleep function. + * + * @attention This API can only be called before wifi_fpm_open. + * + * @param sleep_type type : sleep type + * + * @return null + */ +void wifi_fpm_set_sleep_type(sleep_type type); + +/** + * @brief Get sleep type of force sleep function. + * + * @param null + * + * @return sleep type + */ +sleep_type wifi_fpm_get_sleep_type(void); + +/** + * @} + */ + +/** \defgroup WiFi_Rate_Control_APIs Rate Control APIs + * @brief WiFi Rate Control APIs + */ + +/** @addtogroup WiFi_Rate_Control_APIs + * @{ + */ + +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 + +/** + * @brief Set the fixed rate and mask of sending data from ESP8266. + * + * @attention 1. Only if the corresponding bit in enable_mask is 1, ESP8266 station + * or soft-AP will send data in the fixed rate. + * @attention 2. If the enable_mask is 0, both ESP8266 station and soft-AP will not + * send data in the fixed rate. + * @attention 3. ESP8266 station and soft-AP share the same rate, they can not be + * set into the different rate. + * + * @param uint8 enable_mask : 0x00 - disable the fixed rate + * - 0x01 - use the fixed rate on ESP8266 station + * - 0x02 - use the fixed rate on ESP8266 soft-AP + * - 0x03 - use the fixed rate on ESP8266 station and soft-AP + * @param uint8 rate : value of the fixed rate + * + * @return 0 : succeed + * @return otherwise : fail + */ +sint32 wifi_set_user_fixed_rate(uint8 enable_mask, uint8 rate); + +/** + * @brief Get the fixed rate and mask of ESP8266. + * + * @param uint8 *enable_mask : pointer of the enable_mask + * @param uint8 *rate : pointer of the fixed rate + * + * @return 0 : succeed + * @return otherwise : fail + */ +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 +}; + +/** + * @brief Set the support rate of ESP8266. + * + * Set the rate range in the IE of support rate in ESP8266's beacon, + * probe req/resp and other packets. + * Tell other devices about the rate range supported by ESP8266 to limit + * the rate of sending packets from other devices. + * Example : wifi_set_user_sup_rate(RATE_11G6M, RATE_11G24M); + * + * @attention This API can only support 802.11g now, but it will support 802.11b in next version. + * + * @param uint8 min : the minimum value of the support rate, according to enum support_rate. + * @param uint8 max : the maximum value of the support rate, according to enum support_rate. + * + * @return 0 : succeed + * @return otherwise : fail + */ +sint32 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 + +/** + * @brief Limit the initial rate of sending data from ESP8266. + * + * Example: + * wifi_set_user_rate_limit(RC_LIMIT_11G, 0, RATE_11G_G18M, RATE_11G_G6M); + * + * @attention The rate of retransmission is not limited by this API. + * + * @param uint8 mode : WiFi mode + * - #define RC_LIMIT_11B 0 + * - #define RC_LIMIT_11G 1 + * - #define RC_LIMIT_11N 2 + * @param uint8 ifidx : interface of ESP8266 + * - 0x00 - ESP8266 station + * - 0x01 - ESP8266 soft-AP + * @param uint8 max : the maximum value of the rate, according to the enum rate + * corresponding to the first parameter mode. + * @param uint8 min : the minimum value of the rate, according to the enum rate + * corresponding to the first parameter mode. + * + * @return 0 : succeed + * @return otherwise : fail + */ +bool wifi_set_user_rate_limit(uint8 mode, uint8 ifidx, uint8 max, uint8 min); + +/** + * @brief Get the interfaces of ESP8266 whose rate of sending data is limited by + * wifi_set_user_rate_limit. + * + * @param null + * + * @return LIMIT_RATE_MASK_NONE - disable the limitation on both ESP8266 station and soft-AP + * @return LIMIT_RATE_MASK_STA - enable the limitation on ESP8266 station + * @return LIMIT_RATE_MASK_AP - enable the limitation on ESP8266 soft-AP + * @return LIMIT_RATE_MASK_ALL - enable the limitation on both ESP8266 station and soft-AP + */ +uint8 wifi_get_user_limit_rate_mask(void); + +/** + * @brief Set the interfaces of ESP8266 whose rate of sending packets is limited by + * wifi_set_user_rate_limit. + * + * @param uint8 enable_mask : + * - LIMIT_RATE_MASK_NONE - disable the limitation on both ESP8266 station and soft-AP + * - LIMIT_RATE_MASK_STA - enable the limitation on ESP8266 station + * - LIMIT_RATE_MASK_AP - enable the limitation on ESP8266 soft-AP + * - LIMIT_RATE_MASK_ALL - enable the limitation on both ESP8266 station and soft-AP + * + * @return true : succeed + * @return false : fail + */ +bool wifi_set_user_limit_rate_mask(uint8 enable_mask); + +/** + * @} + */ + + +/** \defgroup WiFi_User_IE_APIs User IE APIs + * @brief WiFi User IE APIs + */ + +/** @addtogroup WiFi_User_IE_APIs + * @{ + */ + +typedef enum { + USER_IE_BEACON = 0, + USER_IE_PROBE_REQ, + USER_IE_PROBE_RESP, + USER_IE_ASSOC_REQ, + USER_IE_ASSOC_RESP, + USER_IE_MAX +} user_ie_type; + +/** + * @brief User IE received callback. + * + * @param user_ie_type type : type of user IE. + * @param const uint8 sa[6] : source address of the packet. + * @param const uint8 m_oui[3] : factory tag. + * @param uint8 *user_ie : pointer of user IE. + * @param uint8 ie_len : length of user IE. + * @param sint32 rssi : signal strength. + * + * @return null + */ +typedef void (*user_ie_manufacturer_recv_cb_t)(user_ie_type type, const uint8 sa[6], const uint8 m_oui[3], uint8 *ie, uint8 ie_len, sint32 rssi); + +/** + * @brief Set user IE of ESP8266. + * + * The user IE will be added to the target packets of user_ie_type. + * + * @param bool enable : + * - true, enable the corresponding user IE function, all parameters below have to be set. + * - false, disable the corresponding user IE function and release the resource, + * only the parameter "type" below has to be set. + * @param uint8 *m_oui : factory tag, apply for it from Espressif System. + * @param user_ie_type type : IE type. If it is USER_IE_BEACON, please disable the + * IE function and enable again to take the configuration + * effect immediately . + * @param uint8 *user_ie : user-defined information elements, need not input the whole + * 802.11 IE, need only the user-define part. + * @param uint8 len : length of user IE, 247 bytes at most. + * + * @return true : succeed + * @return false : fail + */ + +bool wifi_set_user_ie(bool enable, uint8 *m_oui, user_ie_type type, uint8 *user_ie, uint8 len); + +/** + * @brief Register user IE received callback. + * + * @param user_ie_manufacturer_recv_cb_t cb : callback + * + * @return 0 : succeed + * @return -1 : fail + */ +sint32 wifi_register_user_ie_manufacturer_recv_cb(user_ie_manufacturer_recv_cb_t cb); + +/** + * @brief Unregister user IE received callback. + * + * @param null + * + * @return null + */ +void wifi_unregister_user_ie_manufacturer_recv_cb(void); + +/** + * @} + */ + +/** \defgroup WiFi_Sniffer_APIs Sniffer APIs + * @brief WiFi sniffer APIs + */ + +/** @addtogroup WiFi_Sniffer_APIs + * @{ + */ + +/** + * @brief The RX callback function in the promiscuous mode. + * + * Each time a packet is received, the callback function will be called. + * + * @param uint8 *buf : the data received + * @param uint16 len : data length + * + * @return null + */ +typedef void (* wifi_promiscuous_cb_t)(uint8 *buf, uint16 len); + +/** + * @brief Register the RX callback function in the promiscuous mode. + * + * Each time a packet is received, the registered callback function will be called. + * + * @param wifi_promiscuous_cb_t cb : callback + * + * @return null + */ +void wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb); + +/** + * @brief Get the channel number for sniffer functions. + * + * @param null + * + * @return channel number + */ +uint8 wifi_get_channel(void); + +/** + * @brief Set the channel number for sniffer functions. + * + * @param uint8 channel : channel number + * + * @return true : succeed + * @return false : fail + */ +bool wifi_set_channel(uint8 channel); + +/** + * @brief Set the MAC address filter for the sniffer mode. + * + * @attention This filter works only for the current sniffer mode. + * If users disable and then enable the sniffer mode, and then enable + * sniffer, they need to set the MAC address filter again. + * + * @param const uint8_t *address : MAC address + * + * @return true : succeed + * @return false : fail + */ +bool wifi_promiscuous_set_mac(const uint8_t *address); + +/** + * @brief Enable the promiscuous mode. + * + * @attention 1. The promiscuous mode can only be enabled in the ESP8266 station mode. Do not call this API in user_init. + * @attention 2. When in the promiscuous mode, the ESP8266 station and soft-AP are disabled. + * @attention 3. Call wifi_station_disconnect to disconnect before enabling the promiscuous mode. + * @attention 4. Don't call any other APIs when in the promiscuous mode. Call + * wifi_promiscuous_enable(0) to quit sniffer before calling other APIs. + * + * @param uint8 promiscuous : + * - 0: to disable the promiscuous mode + * - 1: to enable the promiscuous mode + * + * @return null + */ +void wifi_promiscuous_enable(uint8 promiscuous); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_wps.h b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_wps.h new file mode 100644 index 0000000..ca6ee95 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/esp_wps.h @@ -0,0 +1,139 @@ +/* + * ESPRSSIF 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 __ESPWPS_H__ +#define __ESPWPS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup WiFi_APIs WiFi Related APIs + * @brief WiFi APIs + */ + +/** @addtogroup WiFi_APIs + * @{ + */ + +/** \defgroup WPS_APIs WPS APIs + * @brief ESP8266 WPS APIs + * + * WPS can only be used when ESP8266 station is enabled. + * + */ + +/** @addtogroup WPS_APIs + * @{ + */ + +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 succeed */ + WPS_CB_ST_FAILED, /**< WPS fail */ + WPS_CB_ST_TIMEOUT, /**< WPS timeout, fail */ + WPS_CB_ST_WEP, /**< WPS failed because that WEP is not supported */ + WPS_CB_ST_SCAN_ERR, /**< can not find the target WPS AP */ +}; + +/** + * @brief Enable Wi-Fi WPS function. + * + * @attention WPS can only be used when ESP8266 station is enabled. + * + * @param WPS_TYPE_t wps_type : WPS type, so far only WPS_TYPE_PBC is supported + * + * @return true : succeed + * @return false : fail + */ +bool wifi_wps_enable(WPS_TYPE_t wps_type); + +/** + * @brief Disable Wi-Fi WPS function and release resource it taken. + * + * @param null + * + * @return true : succeed + * @return false : fail + */ +bool wifi_wps_disable(void); + +/** + * @brief WPS starts to work. + * + * @attention WPS can only be used when ESP8266 station is enabled. + * + * @param null + * + * @return true : WPS starts to work successfully, but does not mean WPS succeed. + * @return false : fail + */ +bool wifi_wps_start(void); + +/** + * @brief WPS callback. + * + * @param int status : status of WPS, enum wps_cb_status. + * - If parameter status == WPS_CB_ST_SUCCESS in WPS callback, it means WPS got AP's + * information, user can call wifi_wps_disable to disable WPS and release resource, + * then call wifi_station_connect to connect to target AP. + * - Otherwise, it means that WPS fail, user can create a timer to retry WPS by + * wifi_wps_start after a while, or call wifi_wps_disable to disable WPS and release resource. + * + * @return null + */ +typedef void (*wps_st_cb_t)(int status); + +/** + * @brief Set WPS callback. + * + * @attention WPS can only be used when ESP8266 station is enabled. + * + * @param wps_st_cb_t cb : callback. + * + * @return true : WPS starts to work successfully, but does not mean WPS succeed. + * @return false : fail + */ +bool wifi_set_wps_cb(wps_st_cb_t cb); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/espressif/espconn.h b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/espconn.h new file mode 100644 index 0000000..d2f43e1 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/espconn.h @@ -0,0 +1,704 @@ +/* + * ESPRSSIF 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 __ESPCONN_H__ +#define __ESPCONN_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef sint8 err_t; + +typedef void *espconn_handle; + +/** \defgroup Espconn_APIs Network Espconn APIs + * @brief Network espconn APIs + * + */ + +/** @addtogroup Espconn_APIs + * @{ + */ + +/** + * @brief Connect callback. + * + * Callback which will be called if successful listening (ESP8266 as TCP server) + * or connection (ESP8266 as TCP client) callback, register by espconn_regist_connectcb. + * + * @attention The pointer "void *arg" may be different in different callbacks, please don't + * use this pointer directly to distinguish one from another in multiple connections, + * use remote_ip and remote_port in espconn instead. + * + * @param void *arg : pointer corresponding structure espconn. + * + * @return null + */ +typedef void (* espconn_connect_callback)(void *arg); + +/** + * @brief Reconnect callback. + * + * Enter this callback when error occurred, TCP connection broke. This callback is + * registered by espconn_regist_reconcb. + * + * @attention The pointer "void *arg" may be different in different callbacks, please don't + * use this pointer directly to distinguish one from another in multiple connections, + * use remote_ip and remote_port in espconn instead. + * + * @param void *arg : pointer corresponding structure espconn. + * @param sint8 err : error code + * - ESCONN_TIMEOUT - Timeout + * - ESPCONN_ABRT - TCP connection aborted + * - ESPCONN_RST - TCP connection abort + * - ESPCONN_CLSD - TCP connection closed + * - ESPCONN_CONN - TCP connection + * - ESPCONN_HANDSHAKE - TCP SSL handshake fail + * - ESPCONN_PROTO_MSG - SSL application invalid + * + * @return null + */ +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. */ +#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 maximum limitation. */ + +#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. */ + +/** Protocol family and type of the espconn */ +enum espconn_type { + ESPCONN_INVALID = 0, /**< invalid type */ + ESPCONN_TCP = 0x10, /**< TCP */ + ESPCONN_UDP = 0x20, /**< UDP */ +}; + +/** Current state of the espconn. */ +enum espconn_state { + ESPCONN_NONE, /**< idle state, no connection */ + ESPCONN_WAIT, /**< ESP8266 is as TCP client, and waiting for connection */ + ESPCONN_LISTEN, /**< ESP8266 is as TCP server, and waiting for connection */ + ESPCONN_CONNECT, /**< connected */ + ESPCONN_WRITE, /**< sending data */ + ESPCONN_READ, /**< receiving data */ + ESPCONN_CLOSE /**< connection closed */ +}; + +typedef struct _esp_tcp { + int remote_port; /**< remote port of TCP connection */ + int local_port; /**< ESP8266's local port of TCP connection */ + uint8 local_ip[4]; /**< local IP of ESP8266 */ + uint8 remote_ip[4]; /**< remote IP of TCP connection */ + espconn_connect_callback connect_callback; /**< connected callback */ + espconn_reconnect_callback reconnect_callback; /**< as error handler, the TCP connection broke unexpectedly */ + espconn_connect_callback disconnect_callback; /**< disconnected callback */ + espconn_connect_callback write_finish_fn; /**< data send by espconn_send has wrote into buffer waiting for sending, or has sent successfully */ +} esp_tcp; + +typedef struct _esp_udp { + int remote_port; /**< remote port of UDP transmission */ + int local_port; /**< ESP8266's local port for UDP transmission */ + uint8 local_ip[4]; /**< local IP of ESP8266 */ + uint8 remote_ip[4]; /**< remote IP of UDP transmission */ +} esp_udp; + +typedef struct _remot_info { + enum espconn_state state; /**< state of espconn */ + int remote_port; /**< remote port */ + uint8 remote_ip[4]; /**< remote IP address */ +} 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 { + enum espconn_type type; /**< type of the espconn (TCP or UDP) */ + enum espconn_state state; /**< current state of the espconn */ + union { + esp_tcp *tcp; + esp_udp *udp; + } proto; + espconn_recv_callback recv_callback; /**< data received callback */ + espconn_sent_callback sent_callback; /**< data sent callback */ + uint8 link_cnt; /**< link count */ + void *reserve; /**< reserved for user data */ +}; + +enum espconn_option { + ESPCONN_START = 0x00, /**< no option, start enum. */ + ESPCONN_REUSEADDR = 0x01, /**< free memory after TCP disconnection happen, need not wait 2 minutes. */ + ESPCONN_NODELAY = 0x02, /**< disable nagle algorithm during TCP data transmission, quicken the data transmission. */ + ESPCONN_COPY = 0x04, /**< enable espconn_regist_write_finish, enter write_finish_callback means that the data espconn_send sending was written into 2920 bytes write-buffer waiting for sending or already sent. */ + ESPCONN_KEEPALIVE = 0x08, /**< enable TCP keep alive. */ + ESPCONN_END /**< no option, end enum. */ +}; + +enum espconn_level { + ESPCONN_KEEPIDLE, /**< TCP keep-alive interval, unit : second. */ + ESPCONN_KEEPINTVL, /**< packet interval during TCP keep-alive, unit : second. */ + ESPCONN_KEEPCNT /**< maximum packet retry count of TCP keep-alive. */ +}; + +enum { + ESPCONN_IDLE = 0, + ESPCONN_CLIENT, + ESPCONN_SERVER, + ESPCONN_BOTH, + ESPCONN_MAX +}; + +/** + * @brief espconn initialization. + * + * @attention Please call this API in user_init, if you need to use espconn functions. + * + * @param null + * + * @return null + */ +void espconn_init(void); + +/** + * @brief Connect to a TCP server (ESP8266 acting as TCP client). + * + * @attention If espconn_connect fail, returns non-0 value, there is no connection, so it + * won't enter any espconn callback. + * + * @param struct espconn *espconn : the network connection structure, the espconn 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 TCP connection + * according to structure espconn + */ +sint8 espconn_connect(struct espconn *espconn); + +/** + * @brief Disconnect a TCP connection. + * + * @attention Don't call this API in any espconn callback. If needed, please use system + * task to trigger espconn_disconnect. + * + * @param struct espconn *espconn : 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 + */ +sint8 espconn_disconnect(struct espconn *espconn); + +/** + * @brief Delete a transmission. + * + * @attention Corresponding creation API : + * - TCP: espconn_accept, + * - UDP: espconn_create + * + * @param struct espconn *espconn : the network connection structure + * + * @return 0 : succeed + * @return Non-0 : error code + * - ESPCONN_ARG - illegal argument, can't find the corresponding network according + * to structure espconn + * - ESPCONN_INPROGRESS - the connection is still in progress, please call espconn_disconnect + * to disconnect before delete it. + */ +sint8 espconn_delete(struct espconn *espconn); + +/** + * @brief Creates a TCP server (i.e. accepts connections). + * + * @param struct espconn *espconn : the network connection structure + * + * @return 0 : succeed + * @return Non-0 : error code + * - ESPCONN_MEM - Out of memory + * - ESPCONN_ISCONN - Already connected + * - ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection + * according to structure espconn + */ +sint8 espconn_accept(struct espconn *espconn); + +/** + * @brief Create UDP transmission. + * + * @attention Parameter remote_ip and remote_port need to be set, do not set to be 0. + * + * @param struct espconn *espconn : the UDP control block structure + * + * @return 0 : succeed + * @return Non-0 : error code + * - ESPCONN_MEM - Out of memory + * - ESPCONN_ISCONN - Already connected + * - ESPCONN_ARG - illegal argument, can't find the corresponding UDP transmission + * according to structure espconn + */ +sint8 espconn_create(struct espconn *espconn); + +/** + * @brief Get maximum number of how many TCP connections are allowed. + * + * @param null + * + * @return Maximum number of how many TCP connections are allowed. + */ +uint8 espconn_tcp_get_max_con(void); + +/** + * @brief Set the maximum number of how many TCP connection is allowed. + * + * @param uint8 num : Maximum number of how many TCP connection is allowed. + * + * @return 0 : succeed + * @return Non-0 : error code + * - ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection + * according to structure espconn + */ +sint8 espconn_tcp_set_max_con(uint8 num); + +/** + * @brief Get the maximum number of TCP clients which are allowed to connect to ESP8266 TCP server. + * + * @param struct espconn *espconn : the TCP server structure + * + * @return 0 : succeed + * @return Non-0 : error code + * - ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection according + * to structure espconn + */ +sint8 espconn_tcp_get_max_con_allow(struct espconn *espconn); + +/** + * @brief Set the maximum number of TCP clients allowed to connect to ESP8266 TCP server. + * + * @param struct espconn *espconn : the TCP server structure + * @param uint8 num : Maximum number of TCP clients which are allowed + * + * @return 0 : succeed + * @return Non-0 : error code + * - ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection according + * to structure espconn + */ +sint8 espconn_tcp_set_max_con_allow(struct espconn *espconn, uint8 num); + +/** + * @brief Register timeout interval of ESP8266 TCP server. + * + * @attention 1. If timeout is set to 0, timeout will be disable and ESP8266 TCP server will + * not disconnect TCP clients has stopped communication. This usage of timeout=0, + * is deprecated. + * @attention 2. This timeout interval is not very precise, only as reference. + * + * @param struct espconn *espconn : the TCP connection structure + * @param uint32 interval : timeout interval, unit: second, maximum: 7200 seconds + * @param uint8 type_flag : 0, set for all connections; 1, set for a specific connection + * - If the type_flag set to be 0, please call this API after espconn_accept, before listened + * a TCP connection. + * - If the type_flag set to be 1, the first parameter *espconn is the specific connection. + * + * @return 0 : succeed + * @return Non-0 : error code + * - ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection according + * to structure espconn + */ +sint8 espconn_regist_time(struct espconn *espconn, uint32 interval, uint8 type_flag); + +/** + * @brief Get the information about a TCP connection or UDP transmission. + * + * @param struct espconn *espconn : the network connection structure + * @param remot_info **pcon_info : connect to client info + * @param uint8 typeflags : 0, regular server; 1, ssl server + * + * @return 0 : succeed + * @return Non-0 : error code + * - ESPCONN_ARG - illegal argument, can't find the corresponding transmission according to + * structure espconn + */ +sint8 espconn_get_connection_info(struct espconn *pespconn, remot_info **pcon_info, uint8 typeflags); + +/** + * @brief Register data sent callback which will be called back when data are successfully sent. + * + * @param struct espconn *espconn : the network connection structure + * @param espconn_sent_callback sent_cb : registered callback function which will be called if + * the data is successfully sent + * + * @return 0 : succeed + * @return Non-0 : error code + * - ESPCONN_ARG - illegal argument, can't find the corresponding transmission according + * to structure espconn + */ +sint8 espconn_regist_sentcb(struct espconn *espconn, espconn_sent_callback sent_cb); + +/** + * @brief Register a callback which will be called when all sending TCP data is completely + * write into write-buffer or sent. + * + * Need to call espconn_set_opt to enable write-buffer first. + * + * @attention 1. write-buffer is used to keep TCP data that waiting to be sent, queue number + * of the write-buffer is 8 which means that it can keep 8 packets at most. + * The size of write-buffer is 2920 bytes. + * @attention 2. Users can enable it by using espconn_set_opt. + * @attention 3. Users can call espconn_send to send the next packet in write_finish_callback + * instead of using espconn_sent_callback. + * + * @param struct espconn *espconn : the network connection structure + * @param espconn_connect_callback write_finish_fn : registered callback function which will + * be called if the data is completely write + * into write buffer or sent. + * + * @return 0 : succeed + * @return Non-0 : error code + * - ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection according + * to structure espconn + */ +sint8 espconn_regist_write_finish(struct espconn *espconn, espconn_connect_callback write_finish_fn); + +/** + * @brief Send data through network. + * + * @attention 1. Please call espconn_send after espconn_sent_callback of the pre-packet. + * @attention 2. If it is a UDP transmission, it is suggested to set espconn->proto.udp->remote_ip + * and remote_port before every calling of espconn_send. + * + * @param struct espconn *espconn : the network connection structure + * @param uint8 *psent : pointer of data + * @param uint16 length : 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 + */ +sint8 espconn_send(struct espconn *espconn, uint8 *psent, uint16 length); + +/** + * @brief Send data through network. + * + * This API is deprecated, please use espconn_send instead. + * + * @attention 1. Please call espconn_sent after espconn_sent_callback of the pre-packet. + * @attention 2. If it is a UDP transmission, it is suggested to set espconn->proto.udp->remote_ip + * and remote_port before every calling of espconn_sent. + * + * @param struct espconn *espconn : the network connection structure + * @param uint8 *psent : pointer of data + * @param uint16 length : 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 + */ +sint8 espconn_sent(struct espconn *espconn, uint8 *psent, uint16 length); + +/** + * @brief Send UDP data. + * + * @param struct espconn *espconn : the UDP structure + * @param uint8 *psent : pointer of data + * @param uint16 length : data length + * + * @return 0 : succeed + * @return Non-0 : error code + * - ESPCONN_MEM - Out of memory + * - ESPCONN_MAXNUM - buffer of sending data is full + * - ESPCONN_IF - send UDP data fail + */ +sint16 espconn_sendto(struct espconn *espconn, uint8 *psent, uint16 length); + +/** + * @brief Register connection function which will be called back under successful TCP connection. + * + * @param struct espconn *espconn : the TCP connection structure + * @param espconn_connect_callback connect_cb : registered callback function + * + * @return 0 : succeed + * @return Non-0 : error code + * - ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection according + * to structure espconn + */ +sint8 espconn_regist_connectcb(struct espconn *espconn, espconn_connect_callback connect_cb); + +/** + * @brief register data receive function which will be called back when data are received. + * + * @param struct espconn *espconn : the network transmission structure + * @param espconn_recv_callback recv_cb : registered callback function + * + * @return 0 : succeed + * @return Non-0 : error code + * - ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection according + * to structure espconn + */ +sint8 espconn_regist_recvcb(struct espconn *espconn, espconn_recv_callback recv_cb); + +/** + * @brief Register reconnect callback. + * + * @attention espconn_reconnect_callback is more like a network-broken error handler; it handles + * errors that occurs in any phase of the connection. + * For instance, if espconn_send fails, espconn_reconnect_callback will be called + * because the network is broken. + * + * @param struct espconn *espconn : the TCP connection structure + * @param espconn_reconnect_callback recon_cb : registered callback function + * + * @return 0 : succeed + * @return Non-0 : error code + * - ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection according + * to structure espconn + */ +sint8 espconn_regist_reconcb(struct espconn *espconn, espconn_reconnect_callback recon_cb); + +/** + * @brief Register disconnection function which will be called back under successful TCP + * disconnection. + * + * @param struct espconn *espconn : the TCP connection structure + * @param espconn_connect_callback discon_cb : registered callback function + * + * @return 0 : succeed + * @return Non-0 : error code + * - ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection according + * to structure espconn + */ +sint8 espconn_regist_disconcb(struct espconn *espconn, espconn_connect_callback discon_cb); + +/** + * @brief Get an available port for network. + * + * @param null + * + * @return Port number. + */ +uint32 espconn_port(void); + +/** + * @brief Set option of TCP connection. + * + * @attention In general, we need not call this API. If call espconn_set_opt, please call + * it in espconn_connect_callback. + * + * @param struct espconn *espconn : the TCP connection structure + * @param uint8 opt : option of TCP connection, refer to enum espconn_option + * - bit 0: 1: free memory after TCP disconnection happen need not wait 2 minutes; + * - bit 1: 1: disable nagle algorithm during TCP data transmission, quiken the data transmission. + * - bit 2: 1: enable espconn_regist_write_finish, enter write finish callback means + * the data espconn_send sending was written into 2920 bytes write-buffer + * waiting for sending or already sent. + * - bit 3: 1: enable TCP keep alive + * + * @return 0 : succeed + * @return Non-0 : error code + * - ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection according + * to structure espconn + */ +sint8 espconn_set_opt(struct espconn *espconn, uint8 opt); + +/** + * @brief Clear option of TCP connection. + * + * @param struct espconn *espconn : the TCP connection structure + * @param uint8 opt : enum espconn_option + * + * @return 0 : succeed + * @return Non-0 : error code + * - ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection according + * to structure espconn + */ +sint8 espconn_clear_opt(struct espconn *espconn, uint8 opt); + +/** + * @brief Set configuration of TCP keep alive. + * + * @attention In general, we need not call this API. If needed, please call it in + * espconn_connect_callback and call espconn_set_opt to enable keep alive first. + * + * @param struct espconn *espconn : the TCP connection structure + * @param uint8 level : To do TCP keep-alive detection every ESPCONN_KEEPIDLE. If there + * is no response, retry ESPCONN_KEEPCNT times every ESPCONN_KEEPINTVL. + * If still no response, considers it as TCP connection broke, goes + * into espconn_reconnect_callback. Notice, keep alive interval is not + * precise, only for reference, it depends on priority. + * @param void* optarg : value of parameter + * + * @return 0 : succeed + * @return Non-0 : error code + * - ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection according + * to structure espconn + */ +sint8 espconn_set_keepalive(struct espconn *espconn, uint8 level, void *optarg); + +/** + * @brief Get configuration of TCP keep alive. + * + * @param struct espconn *espconn : the TCP connection structure + * @param uint8 level : enum espconn_level + * @param void* optarg : value of parameter + * + * @return 0 : succeed + * @return Non-0 : error code + * - ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection according + * to structure espconn + */ +sint8 espconn_get_keepalive(struct espconn *espconn, uint8 level, void *optarg); + +/** + * @brief Callback which is invoked when a hostname is found. + * + * @param const char *name : hostname + * @param ip_addr_t *ipaddr : IP address of the hostname, or to be NULL if the name could + * not be found (or on any other error). + * @param void *callback_arg : callback argument. + * + * @return null + */ +typedef void (*dns_found_callback)(const char *name, ip_addr_t *ipaddr, void *callback_arg); + +/** + * @brief DNS function. + * + * Parse a hostname (string) to an IP address. + * + * @param struct espconn *pespconn : espconn to parse a hostname. + * @param const char *hostname : the hostname. + * @param ip_addr_t *addr : IP address. + * @param dns_found_callback found : callback of DNS + * + * @return err_t : + * - ESPCONN_OK - succeed + * - ESPCONN_INPROGRESS - error code : already connected + * - ESPCONN_ARG - error code : illegal argument, can't find network transmission + * according to structure espconn + */ +err_t espconn_gethostbyname(struct espconn *pespconn, const char *hostname, ip_addr_t *addr, dns_found_callback found); + +/** + * @brief Join a multicast group. + * + * @attention This API can only be called after the ESP8266 station connects to a router. + * + * @param ip_addr_t *host_ip : IP of UDP host + * @param ip_addr_t *multicast_ip : IP of multicast group + * + * @return 0 : succeed + * @return Non-0 : error code + * - ESPCONN_MEM - Out of memory + */ +sint8 espconn_igmp_join(ip_addr_t *host_ip, ip_addr_t *multicast_ip); + +/** + * @brief Leave a multicast group. + * + * @attention This API can only be called after the ESP8266 station connects to a router. + * + * @param ip_addr_t *host_ip : IP of UDP host + * @param ip_addr_t *multicast_ip : IP of multicast group + * + * @return 0 : succeed + * @return Non-0 : error code + * - ESPCONN_MEM - Out of memory + */ +sint8 espconn_igmp_leave(ip_addr_t *host_ip, ip_addr_t *multicast_ip); + +/** + * @brief Puts in a request to block the TCP receive function. + * + * @attention The function does not act immediately; we recommend calling it while + * reserving 5*1460 bytes of memory. This API can be called more than once. + * + * @param struct espconn *espconn : corresponding TCP 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. + */ +sint8 espconn_recv_hold(struct espconn *pespconn); + +/** + * @brief Unblock TCP receiving data (i.e. undo espconn_recv_hold). + * + * @attention This API takes effect immediately. + * + * @param struct espconn *espconn : corresponding TCP 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. + */ +sint8 espconn_recv_unhold(struct espconn *pespconn); + +/** + * @brief Set default DNS server. Two DNS server is allowed to be set. + * + * @attention Only if ESP8266 DHCP client is disabled (wifi_station_dhcpc_stop), + * this API can be used. + * + * @param char numdns : DNS server ID, 0 or 1 + * @param ip_addr_t *dnsserver : DNS server IP + * + * @return null + */ +void espconn_dns_setserver(char numdns, ip_addr_t *dnsserver); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/espressif/espnow.h b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/espnow.h new file mode 100644 index 0000000..3519c76 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/espnow.h @@ -0,0 +1,351 @@ +/* + * ESPRSSIF 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 __ESPNOW_H__ +#define __ESPNOW_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup ESPNow_APIs ESP-NOW APIs + * @brief ESP-NOW APIs + * + * @attention 1. ESP-NOW do not support broadcast and multicast. + * @attention 2. ESP-NOW is targeted to Smart-Light project, so it is suggested + * that slave role corresponding to soft-AP or soft-AP+station mode, + * controller role corresponding to station mode. + * @attention 3. When ESP8266 is in soft-AP+station mode, it will communicate through + * station interface if it is in slave role, and communicate through + * soft-AP interface if it is in controller role. + * @attention 4. ESP-NOW can not wake ESP8266 up from sleep, so if the target ESP8266 + * station is in sleep, ESP-NOW communication will fail. + * @attention 5. In station mode, ESP8266 supports 10 encrypt ESP-NOW peers at most, + * with the unencrypted peers, it can be 20 peers in total at most. + * @attention 6. In the soft-AP mode or soft-AP + station mode, the ESP8266 supports + * 6 encrypt ESP-NOW peers at most, with the unencrypted peers, it can + * be 20 peers in total at most. + * + */ + +/** @addtogroup ESPNow_APIs + * @{ + */ + +enum esp_now_role { + ESP_NOW_ROLE_IDLE = 0, + ESP_NOW_ROLE_CONTROLLER, + ESP_NOW_ROLE_SLAVE, + ESP_NOW_ROLE_MAX, +}; + +/** + * @brief ESP-NOW send callback. + * + * @attention The status will be OK, if ESP-NOW send packet successfully. But users + * need to make sure by themselves that key of communication is correct. + * + * @param uint8 *mac_addr : MAC address of target device + * @param uint8 *data : data received + * @param uint8 len : data length + * + * @return null + */ +typedef void (*esp_now_recv_cb_t)(uint8 *mac_addr, uint8 *data, uint8 len); + +/** + * @brief ESP-NOW send callback. + * + * @attention The status will be OK, if ESP-NOW send packet successfully. But users + * need to make sure by themselves that key of communication is correct. + * + * @param uint8 *mac_addr : MAC address of target device + * @param uint8 status : status of ESP-NOW sending packet, 0, OK; 1, fail. + * + * @return null + */ +typedef void (*esp_now_send_cb_t)(uint8 *mac_addr, uint8 status); + +/** + * @brief ESP-NOW initialization. + * + * @param null + * + * @return 0 : succeed + * @return Non-0 : fail + */ +sint32 esp_now_init(void); + +/** + * @brief Deinitialize ESP-NOW. + * + * @param null + * + * @return 0 : succeed + * @return Non-0 : fail + */ +sint32 esp_now_deinit(void); + +/** + * @brief Register ESP-NOW send callback. + * + * @param esp_now_send_cb_t cb : send callback + * + * @return 0 : succeed + * @return Non-0 : fail + */ +sint32 esp_now_register_send_cb(esp_now_send_cb_t cb); + +/** + * @brief Unregister ESP-NOW send callback. + * + * @param null + * + * @return 0 : succeed + * @return Non-0 : fail + */ +sint32 esp_now_unregister_send_cb(void); + +/** + * @brief Register ESP-NOW receive callback. + * + * @param esp_now_recv_cb_t cb : receive callback + * + * @return 0 : succeed + * @return Non-0 : fail + */ +sint32 esp_now_register_recv_cb(esp_now_recv_cb_t cb); + +/** + * @brief Unregister ESP-NOW receive callback. + * + * @param null + * + * @return 0 : succeed + * @return Non-0 : fail + */ +sint32 esp_now_unregister_recv_cb(void); + +/** + * @brief Send ESP-NOW packet. + * + * @param uint8 *da : destination MAC address. + * If it's NULL, send packet to all MAC addresses recorded + * by ESP-NOW; otherwise, send packet to target MAC address. + * @param uint8 *data : data need to send + * @param uint8 len : data length + * + * @return 0 : succeed + * @return Non-0 : fail + */ +sint32 esp_now_send(uint8 *da, uint8 *data, uint8 len); + +/** + * @brief Add an ESP-NOW peer, store MAC address of target device into ESP-NOW MAC list. + * + * @param uint8 *mac_addr : MAC address of device + * @param uint8 role : role type of device, enum esp_now_role + * @param uint8 channel : channel of device + * @param uint8 *key : 16 bytes key which is needed for ESP-NOW communication + * @param uint8 key_len : length of key, has to be 16 bytes now + * + * @return 0 : succeed + * @return Non-0 : fail + */ +sint32 esp_now_add_peer(uint8 *mac_addr, uint8 role, uint8 channel, uint8 *key, uint8 key_len); + +/** + * @brief Delete an ESP-NOW peer, delete MAC address of the device from ESP-NOW MAC list. + * + * @param u8 *mac_addr : MAC address of device + * + * @return 0 : succeed + * @return Non-0 : fail + */ +sint32 esp_now_del_peer(uint8 *mac_addr); + +/** + * @brief Set ESP-NOW role of device itself. + * + * @param uint8 role : role type of device, enum esp_now_role. + * + * @return 0 : succeed + * @return Non-0 : fail + */ +sint32 esp_now_set_self_role(uint8 role); + +/** + * @brief Get ESP-NOW role of device itself. + * + * @param uint8 role : role type of device, enum esp_now_role. + * + * @return 0 : succeed + * @return Non-0 : fail + */ +sint32 esp_now_get_self_role(void); + +/** + * @brief Set ESP-NOW role for a target device. If it is set multiple times, + * new role will cover the old one. + * + * @param uint8 *mac_addr : MAC address of device. + * @param uint8 role : role type, enum esp_now_role. + * + * @return 0 : succeed + * @return Non-0 : fail + */ +sint32 esp_now_set_peer_role(uint8 *mac_addr, uint8 role); + +/** + * @brief Get ESP-NOW role of a target device. + * + * @param uint8 *mac_addr : MAC address of device. + * + * @return ESP_NOW_ROLE_CONTROLLER, role type : controller + * @return ESP_NOW_ROLE_SLAVE, role type : slave + * @return otherwise : fail + */ +sint32 esp_now_get_peer_role(uint8 *mac_addr); + +/** + * @brief Record channel information of a ESP-NOW device. + * + * When communicate with this device, + * - call esp_now_get_peer_channel to get its channel first, + * - then call wifi_set_channel to be in the same channel and do communication. + * + * @param uint8 *mac_addr : MAC address of target device. + * @param uint8 channel : channel, usually to be 1 ~ 13, some area may use channel 14. + * + * @return 0 : succeed + * @return Non-0 : fail + */ +sint32 esp_now_set_peer_channel(uint8 *mac_addr, uint8 channel); + +/** + * @brief Get channel information of a ESP-NOW device. + * + * @attention ESP-NOW communication needs to be at the same channel. + * + * @param uint8 *mac_addr : MAC address of target device. + * + * @return 1 ~ 13 (some area may get 14) : channel number + * @return Non-0 : fail + */ +sint32 esp_now_get_peer_channel(uint8 *mac_addr); + +/** + * @brief Set ESP-NOW key for a target device. + * + * If it is set multiple times, new key will cover the old one. + * + * @param uint8 *mac_addr : MAC address of target device. + * @param uint8 *key : 16 bytes key which is needed for ESP-NOW communication, + * if it is NULL, current key will be reset to be none. + * @param uint8 key_len : key length, has to be 16 bytes now + * + * @return 0 : succeed + * @return Non-0 : fail + */ +sint32 esp_now_set_peer_key(uint8 *mac_addr, uint8 *key, uint8 key_len); + +/** + * @brief Get ESP-NOW key of a target device. + * + * If it is set multiple times, new key will cover the old one. + * + * @param uint8 *mac_addr : MAC address of target device. + * @param uint8 *key : pointer of key, buffer size has to be 16 bytes at least + * @param uint8 key_len : key length + * + * @return 0 : succeed + * @return > 0 : find target device but can't get key + * @return < 0 : fail + */ +sint32 esp_now_get_peer_key(uint8 *mac_addr, uint8 *key, uint8 *key_len); + +/** + * @brief Get MAC address of ESP-NOW device. + * + * Get MAC address of ESP-NOW device which is pointed now, and move + * the pointer to next one in ESP-NOW MAC list or move the pointer to + * the first one in ESP-NOW MAC list. + * + * @attention 1. This API can not re-entry + * @attention 2. Parameter has to be true when you call it the first time. + * + * @param bool restart : true, move pointer to the first one in ESP-NOW MAC list; + * false, move pointer to the next one in ESP-NOW MAC list + * + * @return NULL, no ESP-NOW devices exist + * @return Otherwise, MAC address of ESP-NOW device which is pointed now + */ +uint8 *esp_now_fetch_peer(bool restart); + +/** + * @brief Check if target device exists or not. + * + * @param uint8 *mac_addr : MAC address of target device. + * + * @return 0 : device does not exist + * @return < 0 : error occur, check fail + * @return > 0 : device exists + */ +sint32 esp_now_is_peer_exist(uint8 *mac_addr); + +/** + * @brief Get the total number of ESP-NOW devices which are associated, and the + * number count of encrypted devices. + * + * @param uint8 *all_cnt : total number of ESP-NOW devices which are associated. + * @param uint8 *encryp_cnt : number count of encrypted devices + * + * @return 0 : succeed + * @return Non-0 : fail + */ +sint32 esp_now_get_cnt_info(uint8 *all_cnt, uint8 *encrypt_cnt); + +/** + * @brief Set the encrypt key of communication key. + * + * All ESP-NOW devices share the same encrypt key. If users do not set + * the encrypt key, ESP-NOW communication key will be encrypted by a default key. + * + * @param uint8 *key : pointer of encrypt key. + * @param uint8 len : key length, has to be 16 bytes now. + * + * @return 0 : succeed + * @return Non-0 : fail + */ +sint32 esp_now_set_kok(uint8 *key, uint8 len); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/espressif/mesh.h b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/mesh.h new file mode 100644 index 0000000..496560f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/mesh.h @@ -0,0 +1,274 @@ +/* + * ESPRSSIF 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 "lwip/ip_addr.h" +#include "espconn.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (* espconn_mesh_callback)(); + +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 disabled */ + MESH_WIFI_CONN, /**< WiFi connected */ + MESH_NET_CONN, /**< TCP connection OK */ + MESH_LOCAL_AVAIL, /**< local mesh is avaliable */ + MESH_ONLINE_AVAIL /**< online mesh is avaliable */ +}; + +enum mesh_node_type { + MESH_NODE_PARENT = 0, /**< get information of parent node */ + MESH_NODE_CHILD, /**< get information of child node(s) */ + MESH_NODE_ALL /**< get information of all nodes */ +}; + +/** + * @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 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 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 + */ +sint8 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 + */ + +sint8 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. + */ +sint8 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 + */ +sint8 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 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_init(); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/espressif/pwm.h b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/pwm.h new file mode 100644 index 0000000..e10bca2 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/pwm.h @@ -0,0 +1,142 @@ +/* + * ESPRSSIF 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 __PWM_H__ +#define __PWM_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup Driver_APIs Driver APIs + * @brief Driver APIs + */ + +/** @addtogroup Driver_APIs + * @{ + */ + +/** \defgroup PWM_Driver_APIs PWM Driver APIs + * @brief PWM driver APIs + */ + +/** @addtogroup PWM_Driver_APIs + * @{ + */ + +struct pwm_param { + uint32 period; /**< PWM period */ + uint32 freq; /**< PWM frequency */ + uint32 duty[8]; /**< PWM duty */ +}; + +#define PWM_DEPTH 1023 + +/** + * @brief PWM function initialization, including GPIO, frequency and duty cycle. + * + * @attention This API can be called only once. + * + * @param uint32 period : pwm frequency + * @param uint32 *duty : duty cycle + * @param uint32 pwm_channel_num : PWM channel number + * @param uint32 (*pin_info_list)[3] : GPIO parameter of PWM channel, it is a pointer + * of n x 3 array which defines GPIO register, IO + * reuse of corresponding pin and GPIO number. + * + * @return null + */ +void pwm_init(uint32 period, uint32 *duty, uint32 pwm_channel_num, uint32(*pin_info_list)[3]); + +/** + * @brief Set the duty cycle of a PWM channel. + * + * Set the time that high level signal will last, duty depends on period, + * the maximum value can be 1023. + * + * + * @attention After set configuration, pwm_start needs to be called to take effect. + * + * @param uint32 duty : duty cycle + * @param uint8 channel : PWM channel number + * + * @return null + */ +void pwm_set_duty(uint32 duty, uint8 channel); + +/** + * @brief Get the duty cycle of a PWM channel. + * + * @param uint8 channel : PWM channel number + * + * @return Duty cycle of PWM output. + */ +uint32 pwm_get_duty(uint8 channel); + +/** + * @brief Set PWM period, unit : us. + * + * For example, for 1KHz PWM, period is 1000 us. + * + * @attention After set configuration, pwm_start needs to be called to take effect. + * + * @param uint32 period : PWM period, unit : us. + * + * @return null + */ +void pwm_set_period(uint32 period); + +/** + * @brief Get PWM period, unit : us. + * + * @param null + * + * @return PWM period, unit : us. + */ +uint32 pwm_get_period(void); + +/** + * @brief Starts PWM. + * + * @attention This function needs to be called after PWM configuration is changed. + * + * @param null + * + * @return null + */ +void pwm_start(void); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/espressif/queue.h b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/queue.h new file mode 100644 index 0000000..6fab9ce --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/queue.h @@ -0,0 +1,236 @@ +/* + * ESPRSSIF 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 _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#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) + +#ifdef __cplusplus +} +#endif + +#endif /* !_SYS_QUEUE_H_ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/espressif/smartconfig.h b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/smartconfig.h new file mode 100644 index 0000000..5403e19 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/smartconfig.h @@ -0,0 +1,165 @@ +/* + * ESPRSSIF 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 __SMARTCONFIG_H__ +#define __SMARTCONFIG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup WiFi_APIs WiFi Related APIs + * @brief WiFi APIs + */ + +/** @addtogroup WiFi_APIs + * @{ + */ + +/** \defgroup Smartconfig_APIs Smartconfig APIs + * @brief SmartConfig APIs + * + * SmartConfig can only be enabled in station only mode. + * Please make sure the target AP is enabled before enable SmartConfig. + * + */ + +/** @addtogroup Smartconfig_APIs + * @{ + */ + +typedef enum { + SC_STATUS_WAIT = 0, /**< waiting, do not start connection in this phase */ + SC_STATUS_FIND_CHANNEL, /**< find target channel, start connection by APP in this phase */ + SC_STATUS_GETTING_SSID_PSWD, /**< getting SSID and password of target AP */ + SC_STATUS_LINK, /**< connecting to target AP */ + SC_STATUS_LINK_OVER, /**< got IP, connect to AP successfully */ +} sc_status; + +typedef enum { + SC_TYPE_ESPTOUCH = 0, /**< protocol: ESPTouch */ + SC_TYPE_AIRKISS, /**< protocol: AirKiss */ + SC_TYPE_ESPTOUCH_AIRKISS, /**< protocol: ESPTouch and AirKiss */ +} sc_type; + +/** + * @brief The callback of SmartConfig, executed when smart-config status changed. + * + * @param sc_status status : status of SmartConfig: + * - if status == SC_STATUS_GETTING_SSID_PSWD, parameter void *pdata is a pointer + of sc_type, means SmartConfig type: AirKiss or ESP-TOUCH. + * - if status == SC_STATUS_LINK, parameter void *pdata is a pointer of struct station_config; + * - if status == SC_STATUS_LINK_OVER, parameter void *pdata is a pointer of mobile + * phone's IP address, 4 bytes. This is only available in ESPTOUCH, otherwise, + * it is NULL. + * - otherwise, parameter void *pdata is NULL. + * @param void *pdata : data of SmartConfig + * + * @return null + */ +typedef void (*sc_callback_t)(sc_status status, void *pdata); + +/** + * @brief Get the version of SmartConfig. + * + * @param null + * + * @return SmartConfig version + */ +const char *smartconfig_get_version(void); + +/** + * @brief Start SmartConfig mode. + * + * Start SmartConfig mode, to connect ESP8266 station to AP, by sniffing + * for special packets from the air, containing SSID and password of desired AP. + * You need to broadcast the SSID and password (e.g. from mobile device or computer) + * with the SSID and password encoded. + * + * @attention 1. This api can only be called in station mode. + * @attention 2. During SmartConfig, ESP8266 station and soft-AP are disabled. + * @attention 3. Can not call smartconfig_start twice before it finish, please call + * smartconfig_stop first. + * @attention 4. Don't call any other APIs during SmartConfig, please call smartconfig_stop first. + * + * @param sc_callback_t cb : SmartConfig callback; executed when SmartConfig status changed; + * @param uint8 log : 1, UART output logs; otherwise, UART only outputs the result. + * + * @return true : succeed + * @return false : fail + */ +bool smartconfig_start(sc_callback_t cb, ...); + +/** + * @brief Stop SmartConfig, free the buffer taken by smartconfig_start. + * + * @attention Whether connect to AP succeed or not, this API should be called to free + * memory taken by smartconfig_start. + * + * @param null + * + * @return true : succeed + * @return false : fail + */ +bool smartconfig_stop(void); + +/** + * @brief Set timeout of SmartConfig. + * + * @attention SmartConfig timeout start at SC_STATUS_FIND_CHANNEL, SmartConfig will + * restart if timeout. + * + * @param uint8 time_s : range 15s~255s, offset:45s. + * + * @return true : succeed + * @return false : fail + */ +bool esptouch_set_timeout(uint8 time_s); + +/** + * @brief Set protocol type of SmartConfig. + * + * @attention If users need to set the SmartConfig type, please set it before calling + * smartconfig_start. + * + * @param sc_type type : AirKiss, ESP-TOUCH or both. + * + * @return true : succeed + * @return false : fail + */ +bool smartconfig_set_type(sc_type type); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/espressif/spi_flash.h b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/spi_flash.h new file mode 100644 index 0000000..4ede88a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/spi_flash.h @@ -0,0 +1,165 @@ +/* + * ESPRSSIF 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 __SPI_FLASH_H__ +#define __SPI_FLASH_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup Driver_APIs Driver APIs + * @brief Driver APIs + */ + +/** @addtogroup Driver_APIs + * @{ + */ + +/** \defgroup SPI_Driver_APIs SPI Driver APIs + * @brief SPI Flash APIs + */ + +/** @addtogroup SPI_Driver_APIs + * @{ + */ + +typedef enum { + SPI_FLASH_RESULT_OK, /**< SPI Flash operating OK */ + SPI_FLASH_RESULT_ERR, /**< SPI Flash operating fail */ + SPI_FLASH_RESULT_TIMEOUT /**< SPI Flash operating time out */ +} 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 /**< SPI Flash sector size */ + +/** + * @brief Get ID info of SPI Flash. + * + * @param null + * + * @return SPI Flash ID + */ +uint32 spi_flash_get_id(void); + +/** + * @brief Read state register of SPI Flash. + * + * @param uint32 *status : the read value (pointer) of state register. + * + * @return SpiFlashOpResult + */ +SpiFlashOpResult spi_flash_read_status(uint32 *status); + +/** + * @brief Write state register of SPI Flash. + * + * @param uint32 status_value : Write state register value. + * + * @return SpiFlashOpResult + */ +SpiFlashOpResult spi_flash_write_status(uint32 status_value); + +/** + * @brief Erase the Flash sector. + * + * @param uint16 sec : Sector number, the count starts at sector 0, 4KB per sector. + * + * @return SpiFlashOpResult + */ +SpiFlashOpResult spi_flash_erase_sector(uint16 sec); + +/** + * @brief Write data to Flash. + * + * @param uint32 des_addr : destination address in Flash. + * @param uint32 *src_addr : source address of the data. + * @param uint32 size : length of data + * + * @return SpiFlashOpResult + */ +SpiFlashOpResult spi_flash_write(uint32 des_addr, uint32 *src_addr, uint32 size); + +/** + * @brief Read data from Flash. + * + * @param uint32 src_addr : source address of the data. + * @param uint32 *des_addr : destination address in Flash. + * @param uint32 size : length of data + * + * @return SpiFlashOpResult + */ +SpiFlashOpResult spi_flash_read(uint32 src_addr, uint32 *des_addr, uint32 size); + +/** + * @brief Registered function for spi_flash_set_read_func. + * + * @attention used for sdk internal, don't need to care about params + * + * @param SpiFlashChip *spi : spi flash struct pointer. + * @param uint32 src_addr : source address of the data. + * @param uint32 *des_addr : destination address in Flash. + * @param uint32 size : length of data + * + * @return SpiFlashOpResult + */ +typedef SpiFlashOpResult (* user_spi_flash_read)( + SpiFlashChip *spi, + uint32 src_addr, + uint32 *des_addr, + uint32 size); + +/** + * @brief Register user-define SPI flash read API. + * + * @attention This API can be only used in SPI overlap mode, please refer to ESP8266_RTOS_SDK + * \examples\driver_lib\driver\spi_overlap.c + * + * @param user_spi_flash_read read : user-define SPI flash read API . + * + * @return none + */ +void spi_flash_set_read_func(user_spi_flash_read read); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/espressif/upgrade.h b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/upgrade.h new file mode 100644 index 0000000..974f655 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/espressif/upgrade.h @@ -0,0 +1,149 @@ +/* + * ESPRSSIF 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 __UPGRADE_H__ +#define __UPGRADE_H__ + +#include "lwip/sockets.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup System_APIs System APIs + * @brief System APIs + */ + +/** @addtogroup System_APIs + * @{ + */ + +/** \defgroup Upgrade_APIs Upgrade APIs + * @brief Firmware upgrade (FOTA) APIs + */ + +/** @addtogroup Upgrade_APIs + * @{ + */ + +#define SPI_FLASH_SEC_SIZE 4096 /**< SPI Flash sector size */ + +#define USER_BIN1 0x00 /**< firmware, user1.bin */ +#define USER_BIN2 0x01 /**< firmware, user2.bin */ + +#define UPGRADE_FLAG_IDLE 0x00 /**< flag of upgrading firmware, idle */ +#define UPGRADE_FLAG_START 0x01 /**< flag of upgrading firmware, start upgrade */ +#define UPGRADE_FLAG_FINISH 0x02 /**< flag of upgrading firmware, finish upgrading */ + +#define UPGRADE_FW_BIN1 0x00 /**< firmware, user1.bin */ +#define UPGRADE_FW_BIN2 0x01 /**< firmware, user2.bin */ + +/** + * @brief Callback of upgrading firmware through WiFi. + * + * @param void * arg : information about upgrading server + * + * @return null + */ +typedef void (*upgrade_states_check_callback)(void *arg); + +//#define UPGRADE_SSL_ENABLE + +struct upgrade_server_info { + struct sockaddr_in sockaddrin; /**< socket of upgrading */ + upgrade_states_check_callback check_cb; /**< callback of upgrading */ + uint32 check_times; /**< time out of upgrading, unit : ms */ + uint8 pre_version[16]; /**< previous version of firmware */ + uint8 upgrade_version[16]; /**< the new version of firmware */ + uint8 *url; /**< the url of upgrading server */ + void *pclient_param; + uint8 upgrade_flag; /**< true, upgrade succeed; false, upgrade fail */ +}; + +/** + * @brief Upgrade function initialization. + * + * @param null + * + * @return null + */ +void system_upgrade_init(); + +/** + * @brief Upgrade function de-initialization. + * + * @param null + * + * @return null + */ +void system_upgrade_deinit(); + +/** + * @brief Upgrade function de-initialization. + * + * @param uint8 *data : segment of the firmware bin data + * @param uint32 len : length of the segment bin data + * + * @return null + */ +bool system_upgrade(uint8 *data, uint32 len); + +#ifdef UPGRADE_SSL_ENABLE + +/** + * @brief Start upgrade firmware through WiFi with SSL connection. + * + * @param struct upgrade_server_info *server : the firmware upgrade server info + * + * @return true : succeed + * @return false : fail + */ +bool system_upgrade_start_ssl(struct upgrade_server_info *server); +#else + +/** + * @brief Start upgrade firmware through WiFi with normal connection. + * + * @param struct upgrade_server_info *server : the firmware upgrade server info + * + * @return true : succeed + * @return false : fail + */ + +bool system_upgrade_start(struct upgrade_server_info *server); +#endif + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/freertos/FreeRTOS.h b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/FreeRTOS.h new file mode 100644 index 0000000..624dee4 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/FreeRTOS.h @@ -0,0 +1,612 @@ +/* + FreeRTOS V7.5.2 - Copyright (C) 2013 Real Time Engineers Ltd. + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that has become a de facto standard. * + * * + * Help yourself get started quickly and support the FreeRTOS * + * project by purchasing a FreeRTOS tutorial book, reference * + * manual, or both from: http://www.FreeRTOS.org/Documentation * + * * + * Thank you! * + * * + *************************************************************************** + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + >>! NOTE: The modification to the GPL is included to allow you to distribute + >>! a combined work that includes FreeRTOS without being obliged to provide + >>! the source code for proprietary components outside of the FreeRTOS + >>! kernel. + + FreeRTOS 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. Full license text is available from the following + link: http://www.freertos.org/a00114.html + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef INC_FREERTOS_H +#define INC_FREERTOS_H + + +/* + * Include the generic headers required for the FreeRTOS port being used. + */ +#include + +/* Basic FreeRTOS definitions. */ +#include "projdefs.h" + +/* Application specific configuration options. */ +#include "FreeRTOSConfig.h" + +/* configUSE_PORT_OPTIMISED_TASK_SELECTION must be defined before portable.h +is included as it is used by the port layer. */ +#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION + #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#endif + +/* Definitions specific to the port being used. */ +#include "portable.h" + + +/* Defines the prototype to which the application task hook function must +conform. */ +typedef portBASE_TYPE (*pdTASK_HOOK_CODE)( void * ); + + + + + +/* + * Check all the required application specific macros have been defined. + * These macros are application specific and (as downloaded) are defined + * within FreeRTOSConfig.h. + */ + +#ifndef configUSE_PREEMPTION + #error Missing definition: configUSE_PREEMPTION should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. +#endif + +#ifndef configUSE_IDLE_HOOK + #error Missing definition: configUSE_IDLE_HOOK should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. +#endif + +#ifndef configUSE_TICK_HOOK + #error Missing definition: configUSE_TICK_HOOK should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. +#endif + +#ifndef configUSE_CO_ROUTINES + #error Missing definition: configUSE_CO_ROUTINES should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. +#endif + +#ifndef INCLUDE_vTaskPrioritySet + #error Missing definition: INCLUDE_vTaskPrioritySet should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. +#endif + +#ifndef INCLUDE_uxTaskPriorityGet + #error Missing definition: INCLUDE_uxTaskPriorityGet should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. +#endif + +#ifndef INCLUDE_vTaskDelete + #error Missing definition: INCLUDE_vTaskDelete should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. +#endif + +#ifndef INCLUDE_vTaskSuspend + #error Missing definition: INCLUDE_vTaskSuspend should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. +#endif + +#ifndef INCLUDE_vTaskDelayUntil + #error Missing definition: INCLUDE_vTaskDelayUntil should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. +#endif + +#ifndef INCLUDE_vTaskDelay + #error Missing definition: INCLUDE_vTaskDelay should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. +#endif + +#ifndef configUSE_16_BIT_TICKS + #error Missing definition: configUSE_16_BIT_TICKS should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. +#endif + +#ifndef INCLUDE_xTaskGetIdleTaskHandle + #define INCLUDE_xTaskGetIdleTaskHandle 0 +#endif + +#ifndef INCLUDE_xTimerGetTimerDaemonTaskHandle + #define INCLUDE_xTimerGetTimerDaemonTaskHandle 0 +#endif + +#ifndef INCLUDE_xQueueGetMutexHolder + #define INCLUDE_xQueueGetMutexHolder 0 +#endif + +#ifndef INCLUDE_xSemaphoreGetMutexHolder + #define INCLUDE_xSemaphoreGetMutexHolder INCLUDE_xQueueGetMutexHolder +#endif + +#ifndef INCLUDE_pcTaskGetTaskName + #define INCLUDE_pcTaskGetTaskName 0 +#endif + +#ifndef configUSE_APPLICATION_TASK_TAG + #define configUSE_APPLICATION_TASK_TAG 0 +#endif + +#ifndef INCLUDE_uxTaskGetStackHighWaterMark + #define INCLUDE_uxTaskGetStackHighWaterMark 0 +#endif + +#ifndef INCLUDE_eTaskGetState + #define INCLUDE_eTaskGetState 0 +#endif + +#ifndef configUSE_RECURSIVE_MUTEXES + #define configUSE_RECURSIVE_MUTEXES 0 +#endif + +#ifndef configUSE_MUTEXES + #define configUSE_MUTEXES 0 +#endif + +#ifndef configUSE_TIMERS + #define configUSE_TIMERS 0 +#endif + +#ifndef configUSE_COUNTING_SEMAPHORES + #define configUSE_COUNTING_SEMAPHORES 0 +#endif + +#ifndef configUSE_ALTERNATIVE_API + #define configUSE_ALTERNATIVE_API 0 +#endif + +#ifndef portCRITICAL_NESTING_IN_TCB + #define portCRITICAL_NESTING_IN_TCB 0 +#endif + +#ifndef configMAX_TASK_NAME_LEN + #define configMAX_TASK_NAME_LEN 16 +#endif + +#ifndef configIDLE_SHOULD_YIELD + #define configIDLE_SHOULD_YIELD 1 +#endif + +#if configMAX_TASK_NAME_LEN < 1 + #error configMAX_TASK_NAME_LEN must be set to a minimum of 1 in FreeRTOSConfig.h +#endif + +#ifndef INCLUDE_xTaskResumeFromISR + #define INCLUDE_xTaskResumeFromISR 1 +#endif + +#ifndef configASSERT + #define configASSERT( x ) + #define configASSERT_DEFINED 0 +#else + #define configASSERT_DEFINED 1 +#endif + +/* The timers module relies on xTaskGetSchedulerState(). */ +#if configUSE_TIMERS == 1 + + #ifndef configTIMER_TASK_PRIORITY + #error If configUSE_TIMERS is set to 1 then configTIMER_TASK_PRIORITY must also be defined. + #endif /* configTIMER_TASK_PRIORITY */ + + #ifndef configTIMER_QUEUE_LENGTH + #error If configUSE_TIMERS is set to 1 then configTIMER_QUEUE_LENGTH must also be defined. + #endif /* configTIMER_QUEUE_LENGTH */ + + #ifndef configTIMER_TASK_STACK_DEPTH + #error If configUSE_TIMERS is set to 1 then configTIMER_TASK_STACK_DEPTH must also be defined. + #endif /* configTIMER_TASK_STACK_DEPTH */ + +#endif /* configUSE_TIMERS */ + +#ifndef INCLUDE_xTaskGetSchedulerState + #define INCLUDE_xTaskGetSchedulerState 0 +#endif + +#ifndef INCLUDE_xTaskGetCurrentTaskHandle + #define INCLUDE_xTaskGetCurrentTaskHandle 0 +#endif + + +#ifndef portSET_INTERRUPT_MASK_FROM_ISR + #define portSET_INTERRUPT_MASK_FROM_ISR() 0 +#endif + +#ifndef portCLEAR_INTERRUPT_MASK_FROM_ISR + #define portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedStatusValue ) ( void ) uxSavedStatusValue +#endif + +#ifndef portCLEAN_UP_TCB + #define portCLEAN_UP_TCB( pxTCB ) ( void ) pxTCB +#endif + +#ifndef portSETUP_TCB + #define portSETUP_TCB( pxTCB ) ( void ) pxTCB +#endif + +#ifndef configQUEUE_REGISTRY_SIZE + #define configQUEUE_REGISTRY_SIZE 0U +#endif + +#if ( configQUEUE_REGISTRY_SIZE < 1 ) + #define vQueueAddToRegistry( xQueue, pcName ) + #define vQueueUnregisterQueue( xQueue ) +#endif + +#ifndef portPOINTER_SIZE_TYPE + #define portPOINTER_SIZE_TYPE unsigned long +#endif + +/* Remove any unused trace macros. */ +#ifndef traceSTART + /* Used to perform any necessary initialisation - for example, open a file + into which trace is to be written. */ + #define traceSTART() +#endif + +#ifndef traceEND + /* Use to close a trace, for example close a file into which trace has been + written. */ + #define traceEND() +#endif + +#ifndef traceTASK_SWITCHED_IN + /* Called after a task has been selected to run. pxCurrentTCB holds a pointer + to the task control block of the selected task. */ + #define traceTASK_SWITCHED_IN() +#endif + +#ifndef traceINCREASE_TICK_COUNT + /* Called before stepping the tick count after waking from tickless idle + sleep. */ + #define traceINCREASE_TICK_COUNT( x ) +#endif + +#ifndef traceLOW_POWER_IDLE_BEGIN + /* Called immediately before entering tickless idle. */ + #define traceLOW_POWER_IDLE_BEGIN() +#endif + +#ifndef traceLOW_POWER_IDLE_END + /* Called when returning to the Idle task after a tickless idle. */ + #define traceLOW_POWER_IDLE_END() +#endif + +#ifndef traceTASK_SWITCHED_OUT + /* Called before a task has been selected to run. pxCurrentTCB holds a pointer + to the task control block of the task being switched out. */ + #define traceTASK_SWITCHED_OUT() +#endif + +#ifndef traceTASK_PRIORITY_INHERIT + /* Called when a task attempts to take a mutex that is already held by a + lower priority task. pxTCBOfMutexHolder is a pointer to the TCB of the task + that holds the mutex. uxInheritedPriority is the priority the mutex holder + will inherit (the priority of the task that is attempting to obtain the + muted. */ + #define traceTASK_PRIORITY_INHERIT( pxTCBOfMutexHolder, uxInheritedPriority ) +#endif + +#ifndef traceTASK_PRIORITY_DISINHERIT + /* Called when a task releases a mutex, the holding of which had resulted in + the task inheriting the priority of a higher priority task. + pxTCBOfMutexHolder is a pointer to the TCB of the task that is releasing the + mutex. uxOriginalPriority is the task's configured (base) priority. */ + #define traceTASK_PRIORITY_DISINHERIT( pxTCBOfMutexHolder, uxOriginalPriority ) +#endif + +#ifndef traceBLOCKING_ON_QUEUE_RECEIVE + /* Task is about to block because it cannot read from a + queue/mutex/semaphore. pxQueue is a pointer to the queue/mutex/semaphore + upon which the read was attempted. pxCurrentTCB points to the TCB of the + task that attempted the read. */ + #define traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ) +#endif + +#ifndef traceBLOCKING_ON_QUEUE_SEND + /* Task is about to block because it cannot write to a + queue/mutex/semaphore. pxQueue is a pointer to the queue/mutex/semaphore + upon which the write was attempted. pxCurrentTCB points to the TCB of the + task that attempted the write. */ + #define traceBLOCKING_ON_QUEUE_SEND( pxQueue ) +#endif + +#ifndef configCHECK_FOR_STACK_OVERFLOW + #define configCHECK_FOR_STACK_OVERFLOW 0 +#endif + +/* The following event macros are embedded in the kernel API calls. */ + +#ifndef traceMOVED_TASK_TO_READY_STATE + #define traceMOVED_TASK_TO_READY_STATE( pxTCB ) +#endif + +#ifndef traceQUEUE_CREATE + #define traceQUEUE_CREATE( pxNewQueue ) +#endif + +#ifndef traceQUEUE_CREATE_FAILED + #define traceQUEUE_CREATE_FAILED( ucQueueType ) +#endif + +#ifndef traceCREATE_MUTEX + #define traceCREATE_MUTEX( pxNewQueue ) +#endif + +#ifndef traceCREATE_MUTEX_FAILED + #define traceCREATE_MUTEX_FAILED() +#endif + +#ifndef traceGIVE_MUTEX_RECURSIVE + #define traceGIVE_MUTEX_RECURSIVE( pxMutex ) +#endif + +#ifndef traceGIVE_MUTEX_RECURSIVE_FAILED + #define traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex ) +#endif + +#ifndef traceTAKE_MUTEX_RECURSIVE + #define traceTAKE_MUTEX_RECURSIVE( pxMutex ) +#endif + +#ifndef traceTAKE_MUTEX_RECURSIVE_FAILED + #define traceTAKE_MUTEX_RECURSIVE_FAILED( pxMutex ) +#endif + +#ifndef traceCREATE_COUNTING_SEMAPHORE + #define traceCREATE_COUNTING_SEMAPHORE() +#endif + +#ifndef traceCREATE_COUNTING_SEMAPHORE_FAILED + #define traceCREATE_COUNTING_SEMAPHORE_FAILED() +#endif + +#ifndef traceQUEUE_SEND + #define traceQUEUE_SEND( pxQueue ) +#endif + +#ifndef traceQUEUE_SEND_FAILED + #define traceQUEUE_SEND_FAILED( pxQueue ) +#endif + +#ifndef traceQUEUE_RECEIVE + #define traceQUEUE_RECEIVE( pxQueue ) +#endif + +#ifndef traceQUEUE_PEEK + #define traceQUEUE_PEEK( pxQueue ) +#endif + +#ifndef traceQUEUE_PEEK_FROM_ISR + #define traceQUEUE_PEEK_FROM_ISR( pxQueue ) +#endif + +#ifndef traceQUEUE_RECEIVE_FAILED + #define traceQUEUE_RECEIVE_FAILED( pxQueue ) +#endif + +#ifndef traceQUEUE_SEND_FROM_ISR + #define traceQUEUE_SEND_FROM_ISR( pxQueue ) +#endif + +#ifndef traceQUEUE_SEND_FROM_ISR_FAILED + #define traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue ) +#endif + +#ifndef traceQUEUE_RECEIVE_FROM_ISR + #define traceQUEUE_RECEIVE_FROM_ISR( pxQueue ) +#endif + +#ifndef traceQUEUE_RECEIVE_FROM_ISR_FAILED + #define traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue ) +#endif + +#ifndef traceQUEUE_PEEK_FROM_ISR_FAILED + #define traceQUEUE_PEEK_FROM_ISR_FAILED( pxQueue ) +#endif + +#ifndef traceQUEUE_DELETE + #define traceQUEUE_DELETE( pxQueue ) +#endif + +#ifndef traceTASK_CREATE + #define traceTASK_CREATE( pxNewTCB ) +#endif + +#ifndef traceTASK_CREATE_FAILED + #define traceTASK_CREATE_FAILED() +#endif + +#ifndef traceTASK_DELETE + #define traceTASK_DELETE( pxTaskToDelete ) +#endif + +#ifndef traceTASK_DELAY_UNTIL + #define traceTASK_DELAY_UNTIL() +#endif + +#ifndef traceTASK_DELAY + #define traceTASK_DELAY() +#endif + +#ifndef traceTASK_PRIORITY_SET + #define traceTASK_PRIORITY_SET( pxTask, uxNewPriority ) +#endif + +#ifndef traceTASK_SUSPEND + #define traceTASK_SUSPEND( pxTaskToSuspend ) +#endif + +#ifndef traceTASK_RESUME + #define traceTASK_RESUME( pxTaskToResume ) +#endif + +#ifndef traceTASK_RESUME_FROM_ISR + #define traceTASK_RESUME_FROM_ISR( pxTaskToResume ) +#endif + +#ifndef traceTASK_INCREMENT_TICK + #define traceTASK_INCREMENT_TICK( xTickCount ) +#endif + +#ifndef traceTIMER_CREATE + #define traceTIMER_CREATE( pxNewTimer ) +#endif + +#ifndef traceTIMER_CREATE_FAILED + #define traceTIMER_CREATE_FAILED() +#endif + +#ifndef traceTIMER_COMMAND_SEND + #define traceTIMER_COMMAND_SEND( xTimer, xMessageID, xMessageValueValue, xReturn ) +#endif + +#ifndef traceTIMER_EXPIRED + #define traceTIMER_EXPIRED( pxTimer ) +#endif + +#ifndef traceTIMER_COMMAND_RECEIVED + #define traceTIMER_COMMAND_RECEIVED( pxTimer, xMessageID, xMessageValue ) +#endif + +#ifndef configGENERATE_RUN_TIME_STATS + #define configGENERATE_RUN_TIME_STATS 0 +#endif + +#if ( configGENERATE_RUN_TIME_STATS == 1 ) + + #ifndef portCONFIGURE_TIMER_FOR_RUN_TIME_STATS + #error If configGENERATE_RUN_TIME_STATS is defined then portCONFIGURE_TIMER_FOR_RUN_TIME_STATS must also be defined. portCONFIGURE_TIMER_FOR_RUN_TIME_STATS should call a port layer function to setup a peripheral timer/counter that can then be used as the run time counter time base. + #endif /* portCONFIGURE_TIMER_FOR_RUN_TIME_STATS */ + + #ifndef portGET_RUN_TIME_COUNTER_VALUE + #ifndef portALT_GET_RUN_TIME_COUNTER_VALUE + #error If configGENERATE_RUN_TIME_STATS is defined then either portGET_RUN_TIME_COUNTER_VALUE or portALT_GET_RUN_TIME_COUNTER_VALUE must also be defined. See the examples provided and the FreeRTOS web site for more information. + #endif /* portALT_GET_RUN_TIME_COUNTER_VALUE */ + #endif /* portGET_RUN_TIME_COUNTER_VALUE */ + +#endif /* configGENERATE_RUN_TIME_STATS */ + +#ifndef portCONFIGURE_TIMER_FOR_RUN_TIME_STATS + #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() +#endif + +#ifndef configUSE_MALLOC_FAILED_HOOK + #define configUSE_MALLOC_FAILED_HOOK 0 +#endif + +#ifndef portPRIVILEGE_BIT + #define portPRIVILEGE_BIT ( ( unsigned portBASE_TYPE ) 0x00 ) +#endif + +#ifndef portYIELD_WITHIN_API + #define portYIELD_WITHIN_API portYIELD +#endif + +#ifndef pvPortMallocAligned + #define pvPortMallocAligned( x, puxStackBuffer ) ( ( ( puxStackBuffer ) == NULL ) ? ( os_malloc( ( x ) ) ) : ( puxStackBuffer ) ) +#endif + +#ifndef vPortFreeAligned + #define vPortFreeAligned( pvBlockToFree ) os_free( pvBlockToFree ) +#endif + +#ifndef portSUPPRESS_TICKS_AND_SLEEP + #define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) +#endif + +#ifndef configEXPECTED_IDLE_TIME_BEFORE_SLEEP + #define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 2 +#endif + +#if configEXPECTED_IDLE_TIME_BEFORE_SLEEP < 2 + #error configEXPECTED_IDLE_TIME_BEFORE_SLEEP must not be less than 2 +#endif + +#ifndef configUSE_TICKLESS_IDLE + #define configUSE_TICKLESS_IDLE 0 +#endif + +#ifndef configPRE_SLEEP_PROCESSING + #define configPRE_SLEEP_PROCESSING( x ) +#endif + +#ifndef configPOST_SLEEP_PROCESSING + #define configPOST_SLEEP_PROCESSING( x ) +#endif + +#ifndef configUSE_QUEUE_SETS + #define configUSE_QUEUE_SETS 0 +#endif + +#ifndef portTASK_USES_FLOATING_POINT + #define portTASK_USES_FLOATING_POINT() +#endif + +#ifndef configUSE_TIME_SLICING + #define configUSE_TIME_SLICING 1 +#endif + +#ifndef configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS + #define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 0 +#endif + +#ifndef configUSE_NEWLIB_REENTRANT + #define configUSE_NEWLIB_REENTRANT 0 +#endif + +#ifndef configUSE_STATS_FORMATTING_FUNCTIONS + #define configUSE_STATS_FORMATTING_FUNCTIONS 0 +#endif + +#ifndef portASSERT_IF_INTERRUPT_PRIORITY_INVALID + #define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() +#endif + +/* For backward compatability. */ +#define eTaskStateGet eTaskGetState + +#endif /* INC_FREERTOS_H */ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/freertos/FreeRTOSConfig.h b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/FreeRTOSConfig.h new file mode 100644 index 0000000..769b437 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/FreeRTOSConfig.h @@ -0,0 +1,144 @@ +/* + FreeRTOS V7.5.2 - Copyright (C) 2013 Real Time Engineers Ltd. + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that has become a de facto standard. * + * * + * Help yourself get started quickly and support the FreeRTOS * + * project by purchasing a FreeRTOS tutorial book, reference * + * manual, or both from: http://www.FreeRTOS.org/Documentation * + * * + * Thank you! * + * * + *************************************************************************** + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + >>! NOTE: The modification to the GPL is included to allow you to distribute + >>! a combined work that includes FreeRTOS without being obliged to provide + >>! the source code for proprietary components outside of the FreeRTOS + >>! kernel. + + FreeRTOS 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. Full license text is available from the following + link: http://www.freertos.org/a00114.html + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * + * See http://www.freertos.org/a00110.html. + *----------------------------------------------------------*/ + +#define configUSE_PREEMPTION 1 +#define configUSE_IDLE_HOOK 1 +#define configUSE_TICK_HOOK 0 +#define configUSE_TICKLESS_IDLE 1 +#define configCPU_CLOCK_HZ ( ( unsigned long ) 80000000 ) +#define configTICK_RATE_HZ ( ( portTickType ) 100 ) +#define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 15 ) +#define configMINIMAL_STACK_SIZE ( ( unsigned short )176 ) +//#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 17 * 1024 ) ) +#define configMAX_TASK_NAME_LEN ( 16 ) +#define configUSE_TRACE_FACILITY 0 +#define configUSE_STATS_FORMATTING_FUNCTIONS 0 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 + +#define INCLUDE_xTaskGetIdleTaskHandle 1 +#define INCLUDE_xTimerGetTimerDaemonTaskHandle 1 + +#define configCHECK_FOR_STACK_OVERFLOW 2 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_TIMERS 1 + +#if configUSE_TIMERS +#define configTIMER_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 ) +#define configTIMER_QUEUE_LENGTH (10) +#define configTIMER_TASK_STACK_DEPTH ( ( unsigned short ) 512 ) +#endif + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) + +/* Set the following definitions to 1 to include the API function, or zero +to exclude the API function. */ + +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 + +/*set the #define for debug info*/ +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 + +/* This is the raw value as per the Cortex-M3 NVIC. Values can be 255 +(lowest) to 0 (1?) (highest). */ +#define configKERNEL_INTERRUPT_PRIORITY 255 +/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!! +See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ +#define configMAX_SYSCALL_INTERRUPT_PRIORITY 191 /* equivalent to 0xb0, or priority 11. */ + + +/* This is the value being used as per the ST library which permits 16 +priority values, 0 to 15. This must correspond to the +configKERNEL_INTERRUPT_PRIORITY setting. Here 15 corresponds to the lowest +NVIC value of 255. */ +#define configLIBRARY_KERNEL_INTERRUPT_PRIORITY 15 + +#endif /* FREERTOS_CONFIG_H */ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/freertos/StackMacros.h b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/StackMacros.h new file mode 100644 index 0000000..7fa9503 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/StackMacros.h @@ -0,0 +1,179 @@ +/* + FreeRTOS V7.5.2 - Copyright (C) 2013 Real Time Engineers Ltd. + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that has become a de facto standard. * + * * + * Help yourself get started quickly and support the FreeRTOS * + * project by purchasing a FreeRTOS tutorial book, reference * + * manual, or both from: http://www.FreeRTOS.org/Documentation * + * * + * Thank you! * + * * + *************************************************************************** + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + >>! NOTE: The modification to the GPL is included to allow you to distribute + >>! a combined work that includes FreeRTOS without being obliged to provide + >>! the source code for proprietary components outside of the FreeRTOS + >>! kernel. + + FreeRTOS 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. Full license text is available from the following + link: http://www.freertos.org/a00114.html + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef STACK_MACROS_H +#define STACK_MACROS_H + +/* + * Call the stack overflow hook function if the stack of the task being swapped + * out is currently overflowed, or looks like it might have overflowed in the + * past. + * + * Setting configCHECK_FOR_STACK_OVERFLOW to 1 will cause the macro to check + * the current stack state only - comparing the current top of stack value to + * the stack limit. Setting configCHECK_FOR_STACK_OVERFLOW to greater than 1 + * will also cause the last few stack bytes to be checked to ensure the value + * to which the bytes were set when the task was created have not been + * overwritten. Note this second test does not guarantee that an overflowed + * stack will always be recognised. + */ + +/*-----------------------------------------------------------*/ + +#if( configCHECK_FOR_STACK_OVERFLOW == 0 ) + + /* FreeRTOSConfig.h is not set to check for stack overflows. */ + #define taskFIRST_CHECK_FOR_STACK_OVERFLOW() + #define taskSECOND_CHECK_FOR_STACK_OVERFLOW() + +#endif /* configCHECK_FOR_STACK_OVERFLOW == 0 */ +/*-----------------------------------------------------------*/ + +#if( configCHECK_FOR_STACK_OVERFLOW == 1 ) + + /* FreeRTOSConfig.h is only set to use the first method of + overflow checking. */ + #define taskSECOND_CHECK_FOR_STACK_OVERFLOW() + +#endif +/*-----------------------------------------------------------*/ + +#if( ( configCHECK_FOR_STACK_OVERFLOW > 0 ) && ( portSTACK_GROWTH < 0 ) ) + + /* Only the current stack state is to be checked. */ + #define taskFIRST_CHECK_FOR_STACK_OVERFLOW() \ + { \ + /* Is the currently saved stack pointer within the stack limit? */ \ + if( pxCurrentTCB->pxTopOfStack <= pxCurrentTCB->pxStack ) \ + { \ + vApplicationStackOverflowHook( ( xTaskHandle ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ + } \ + } + +#endif /* configCHECK_FOR_STACK_OVERFLOW > 0 */ +/*-----------------------------------------------------------*/ + +#if( ( configCHECK_FOR_STACK_OVERFLOW > 0 ) && ( portSTACK_GROWTH > 0 ) ) + + /* Only the current stack state is to be checked. */ + #define taskFIRST_CHECK_FOR_STACK_OVERFLOW() \ + { \ + \ + /* Is the currently saved stack pointer within the stack limit? */ \ + if( pxCurrentTCB->pxTopOfStack >= pxCurrentTCB->pxEndOfStack ) \ + { \ + vApplicationStackOverflowHook( ( xTaskHandle ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ + } \ + } + +#endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */ +/*-----------------------------------------------------------*/ + +#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH < 0 ) ) + + #define taskSECOND_CHECK_FOR_STACK_OVERFLOW() \ + { \ + static const unsigned char ucExpectedStackBytes[] = { tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ + tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ + tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ + tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ + tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE }; \ + \ + \ + /* Has the extremity of the task stack ever been written over? */ \ + if( memcmp( ( void * ) pxCurrentTCB->pxStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) != 0 ) \ + { \ + vApplicationStackOverflowHook( ( xTaskHandle ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ + } \ + } + +#endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */ +/*-----------------------------------------------------------*/ + +#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH > 0 ) ) + + #define taskSECOND_CHECK_FOR_STACK_OVERFLOW() \ + { \ + char *pcEndOfStack = ( char * ) pxCurrentTCB->pxEndOfStack; \ + static const unsigned char ucExpectedStackBytes[] = { tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ + tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ + tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ + tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ + tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE }; \ + \ + \ + pcEndOfStack -= sizeof( ucExpectedStackBytes ); \ + \ + /* Has the extremity of the task stack ever been written over? */ \ + if( memcmp( ( void * ) pcEndOfStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) != 0 ) \ + { \ + vApplicationStackOverflowHook( ( xTaskHandle ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ + } \ + } + +#endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */ +/*-----------------------------------------------------------*/ + +#endif /* STACK_MACROS_H */ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/freertos/croutine.h b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/croutine.h new file mode 100644 index 0000000..fa082e6 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/croutine.h @@ -0,0 +1,757 @@ +/* + FreeRTOS V7.5.2 - Copyright (C) 2013 Real Time Engineers Ltd. + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that has become a de facto standard. * + * * + * Help yourself get started quickly and support the FreeRTOS * + * project by purchasing a FreeRTOS tutorial book, reference * + * manual, or both from: http://www.FreeRTOS.org/Documentation * + * * + * Thank you! * + * * + *************************************************************************** + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + >>! NOTE: The modification to the GPL is included to allow you to distribute + >>! a combined work that includes FreeRTOS without being obliged to provide + >>! the source code for proprietary components outside of the FreeRTOS + >>! kernel. + + FreeRTOS 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. Full license text is available from the following + link: http://www.freertos.org/a00114.html + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef CO_ROUTINE_H +#define CO_ROUTINE_H + +#ifndef INC_FREERTOS_H + #error "include FreeRTOS.h must appear in source files before include croutine.h" +#endif + +#include "list.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Used to hide the implementation of the co-routine control block. The +control block structure however has to be included in the header due to +the macro implementation of the co-routine functionality. */ +typedef void * xCoRoutineHandle; + +/* Defines the prototype to which co-routine functions must conform. */ +typedef void (*crCOROUTINE_CODE)( xCoRoutineHandle, unsigned portBASE_TYPE ); + +typedef struct corCoRoutineControlBlock +{ + crCOROUTINE_CODE pxCoRoutineFunction; + xListItem xGenericListItem; /*< List item used to place the CRCB in ready and blocked queues. */ + xListItem xEventListItem; /*< List item used to place the CRCB in event lists. */ + unsigned portBASE_TYPE uxPriority; /*< The priority of the co-routine in relation to other co-routines. */ + unsigned portBASE_TYPE uxIndex; /*< Used to distinguish between co-routines when multiple co-routines use the same co-routine function. */ + unsigned short uxState; /*< Used internally by the co-routine implementation. */ +} corCRCB; /* Co-routine control block. Note must be identical in size down to uxPriority with tskTCB. */ + +/** + * croutine. h + *
+ portBASE_TYPE xCoRoutineCreate(
+                                 crCOROUTINE_CODE pxCoRoutineCode,
+                                 unsigned portBASE_TYPE uxPriority,
+                                 unsigned portBASE_TYPE uxIndex
+                               );
+ * + * Create a new co-routine and add it to the list of co-routines that are + * ready to run. + * + * @param pxCoRoutineCode Pointer to the co-routine function. Co-routine + * functions require special syntax - see the co-routine section of the WEB + * documentation for more information. + * + * @param uxPriority The priority with respect to other co-routines at which + * the co-routine will run. + * + * @param uxIndex Used to distinguish between different co-routines that + * execute the same function. See the example below and the co-routine section + * of the WEB documentation for further information. + * + * @return pdPASS if the co-routine was successfully created and added to a ready + * list, otherwise an error code defined with ProjDefs.h. + * + * Example usage: +
+ // Co-routine to be created.
+ void vFlashCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ // This may not be necessary for const variables.
+ static const char cLedToFlash[ 2 ] = { 5, 6 };
+ static const portTickType uxFlashRates[ 2 ] = { 200, 400 };
+
+     // Must start every co-routine with a call to crSTART();
+     crSTART( xHandle );
+
+     for( ;; )
+     {
+         // This co-routine just delays for a fixed period, then toggles
+         // an LED.  Two co-routines are created using this function, so
+         // the uxIndex parameter is used to tell the co-routine which
+         // LED to flash and how long to delay.  This assumes xQueue has
+         // already been created.
+         vParTestToggleLED( cLedToFlash[ uxIndex ] );
+         crDELAY( xHandle, uxFlashRates[ uxIndex ] );
+     }
+
+     // Must end every co-routine with a call to crEND();
+     crEND();
+ }
+
+ // Function that creates two co-routines.
+ void vOtherFunction( void )
+ {
+ unsigned char ucParameterToPass;
+ xTaskHandle xHandle;
+		
+     // Create two co-routines at priority 0.  The first is given index 0
+     // so (from the code above) toggles LED 5 every 200 ticks.  The second
+     // is given index 1 so toggles LED 6 every 400 ticks.
+     for( uxIndex = 0; uxIndex < 2; uxIndex++ )
+     {
+         xCoRoutineCreate( vFlashCoRoutine, 0, uxIndex );
+     }
+ }
+   
+ * \defgroup xCoRoutineCreate xCoRoutineCreate + * \ingroup Tasks + */ +signed portBASE_TYPE xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, unsigned portBASE_TYPE uxPriority, unsigned portBASE_TYPE uxIndex ); + + +/** + * croutine. h + *
+ void vCoRoutineSchedule( void );
+ * + * Run a co-routine. + * + * vCoRoutineSchedule() executes the highest priority co-routine that is able + * to run. The co-routine will execute until it either blocks, yields or is + * preempted by a task. Co-routines execute cooperatively so one + * co-routine cannot be preempted by another, but can be preempted by a task. + * + * If an application comprises of both tasks and co-routines then + * vCoRoutineSchedule should be called from the idle task (in an idle task + * hook). + * + * Example usage: +
+ // This idle task hook will schedule a co-routine each time it is called.
+ // The rest of the idle task will execute between co-routine calls.
+ void vApplicationIdleHook( void )
+ {
+	vCoRoutineSchedule();
+ }
+
+ // Alternatively, if you do not require any other part of the idle task to
+ // execute, the idle task hook can call vCoRoutineScheduler() within an
+ // infinite loop.
+ void vApplicationIdleHook( void )
+ {
+    for( ;; )
+    {
+        vCoRoutineSchedule();
+    }
+ }
+ 
+ * \defgroup vCoRoutineSchedule vCoRoutineSchedule + * \ingroup Tasks + */ +void vCoRoutineSchedule( void ); + +/** + * croutine. h + *
+ crSTART( xCoRoutineHandle xHandle );
+ * + * This macro MUST always be called at the start of a co-routine function. + * + * Example usage: +
+ // Co-routine to be created.
+ void vACoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ static long ulAVariable;
+
+     // Must start every co-routine with a call to crSTART();
+     crSTART( xHandle );
+
+     for( ;; )
+     {
+          // Co-routine functionality goes here.
+     }
+
+     // Must end every co-routine with a call to crEND();
+     crEND();
+ }
+ * \defgroup crSTART crSTART + * \ingroup Tasks + */ +#define crSTART( pxCRCB ) switch( ( ( corCRCB * )( pxCRCB ) )->uxState ) { case 0: + +/** + * croutine. h + *
+ crEND();
+ * + * This macro MUST always be called at the end of a co-routine function. + * + * Example usage: +
+ // Co-routine to be created.
+ void vACoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ static long ulAVariable;
+
+     // Must start every co-routine with a call to crSTART();
+     crSTART( xHandle );
+
+     for( ;; )
+     {
+          // Co-routine functionality goes here.
+     }
+
+     // Must end every co-routine with a call to crEND();
+     crEND();
+ }
+ * \defgroup crSTART crSTART + * \ingroup Tasks + */ +#define crEND() } + +/* + * These macros are intended for internal use by the co-routine implementation + * only. The macros should not be used directly by application writers. + */ +#define crSET_STATE0( xHandle ) ( ( corCRCB * )( xHandle ) )->uxState = (__LINE__ * 2); return; case (__LINE__ * 2): +#define crSET_STATE1( xHandle ) ( ( corCRCB * )( xHandle ) )->uxState = ((__LINE__ * 2)+1); return; case ((__LINE__ * 2)+1): + +/** + * croutine. h + *
+ crDELAY( xCoRoutineHandle xHandle, portTickType xTicksToDelay );
+ * + * Delay a co-routine for a fixed period of time. + * + * crDELAY can only be called from the co-routine function itself - not + * from within a function called by the co-routine function. This is because + * co-routines do not maintain their own stack. + * + * @param xHandle The handle of the co-routine to delay. This is the xHandle + * parameter of the co-routine function. + * + * @param xTickToDelay The number of ticks that the co-routine should delay + * for. The actual amount of time this equates to is defined by + * configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant portTICK_RATE_MS + * can be used to convert ticks to milliseconds. + * + * Example usage: +
+ // Co-routine to be created.
+ void vACoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ // This may not be necessary for const variables.
+ // We are to delay for 200ms.
+ static const xTickType xDelayTime = 200 / portTICK_RATE_MS;
+
+     // Must start every co-routine with a call to crSTART();
+     crSTART( xHandle );
+
+     for( ;; )
+     {
+        // Delay for 200ms.
+        crDELAY( xHandle, xDelayTime );
+
+        // Do something here.
+     }
+
+     // Must end every co-routine with a call to crEND();
+     crEND();
+ }
+ * \defgroup crDELAY crDELAY + * \ingroup Tasks + */ +#define crDELAY( xHandle, xTicksToDelay ) \ + if( ( xTicksToDelay ) > 0 ) \ + { \ + vCoRoutineAddToDelayedList( ( xTicksToDelay ), NULL ); \ + } \ + crSET_STATE0( ( xHandle ) ); + +/** + *
+ crQUEUE_SEND(
+                  xCoRoutineHandle xHandle,
+                  xQueueHandle pxQueue,
+                  void *pvItemToQueue,
+                  portTickType xTicksToWait,
+                  portBASE_TYPE *pxResult
+             )
+ * + * The macro's crQUEUE_SEND() and crQUEUE_RECEIVE() are the co-routine + * equivalent to the xQueueSend() and xQueueReceive() functions used by tasks. + * + * crQUEUE_SEND and crQUEUE_RECEIVE can only be used from a co-routine whereas + * xQueueSend() and xQueueReceive() can only be used from tasks. + * + * crQUEUE_SEND can only be called from the co-routine function itself - not + * from within a function called by the co-routine function. This is because + * co-routines do not maintain their own stack. + * + * See the co-routine section of the WEB documentation for information on + * passing data between tasks and co-routines and between ISR's and + * co-routines. + * + * @param xHandle The handle of the calling co-routine. This is the xHandle + * parameter of the co-routine function. + * + * @param pxQueue The handle of the queue on which the data will be posted. + * The handle is obtained as the return value when the queue is created using + * the xQueueCreate() API function. + * + * @param pvItemToQueue A pointer to the data being posted onto the queue. + * The number of bytes of each queued item is specified when the queue is + * created. This number of bytes is copied from pvItemToQueue into the queue + * itself. + * + * @param xTickToDelay The number of ticks that the co-routine should block + * to wait for space to become available on the queue, should space not be + * available immediately. The actual amount of time this equates to is defined + * by configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant + * portTICK_RATE_MS can be used to convert ticks to milliseconds (see example + * below). + * + * @param pxResult The variable pointed to by pxResult will be set to pdPASS if + * data was successfully posted onto the queue, otherwise it will be set to an + * error defined within ProjDefs.h. + * + * Example usage: +
+ // Co-routine function that blocks for a fixed period then posts a number onto
+ // a queue.
+ static void prvCoRoutineFlashTask( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ static portBASE_TYPE xNumberToPost = 0;
+ static portBASE_TYPE xResult;
+
+    // Co-routines must begin with a call to crSTART().
+    crSTART( xHandle );
+
+    for( ;; )
+    {
+        // This assumes the queue has already been created.
+        crQUEUE_SEND( xHandle, xCoRoutineQueue, &xNumberToPost, NO_DELAY, &xResult );
+
+        if( xResult != pdPASS )
+        {
+            // The message was not posted!
+        }
+
+        // Increment the number to be posted onto the queue.
+        xNumberToPost++;
+
+        // Delay for 100 ticks.
+        crDELAY( xHandle, 100 );
+    }
+
+    // Co-routines must end with a call to crEND().
+    crEND();
+ }
+ * \defgroup crQUEUE_SEND crQUEUE_SEND + * \ingroup Tasks + */ +#define crQUEUE_SEND( xHandle, pxQueue, pvItemToQueue, xTicksToWait, pxResult ) \ +{ \ + *( pxResult ) = xQueueCRSend( ( pxQueue) , ( pvItemToQueue) , ( xTicksToWait ) ); \ + if( *( pxResult ) == errQUEUE_BLOCKED ) \ + { \ + crSET_STATE0( ( xHandle ) ); \ + *pxResult = xQueueCRSend( ( pxQueue ), ( pvItemToQueue ), 0 ); \ + } \ + if( *pxResult == errQUEUE_YIELD ) \ + { \ + crSET_STATE1( ( xHandle ) ); \ + *pxResult = pdPASS; \ + } \ +} + +/** + * croutine. h + *
+  crQUEUE_RECEIVE(
+                     xCoRoutineHandle xHandle,
+                     xQueueHandle pxQueue,
+                     void *pvBuffer,
+                     portTickType xTicksToWait,
+                     portBASE_TYPE *pxResult
+                 )
+ * + * The macro's crQUEUE_SEND() and crQUEUE_RECEIVE() are the co-routine + * equivalent to the xQueueSend() and xQueueReceive() functions used by tasks. + * + * crQUEUE_SEND and crQUEUE_RECEIVE can only be used from a co-routine whereas + * xQueueSend() and xQueueReceive() can only be used from tasks. + * + * crQUEUE_RECEIVE can only be called from the co-routine function itself - not + * from within a function called by the co-routine function. This is because + * co-routines do not maintain their own stack. + * + * See the co-routine section of the WEB documentation for information on + * passing data between tasks and co-routines and between ISR's and + * co-routines. + * + * @param xHandle The handle of the calling co-routine. This is the xHandle + * parameter of the co-routine function. + * + * @param pxQueue The handle of the queue from which the data will be received. + * The handle is obtained as the return value when the queue is created using + * the xQueueCreate() API function. + * + * @param pvBuffer The buffer into which the received item is to be copied. + * The number of bytes of each queued item is specified when the queue is + * created. This number of bytes is copied into pvBuffer. + * + * @param xTickToDelay The number of ticks that the co-routine should block + * to wait for data to become available from the queue, should data not be + * available immediately. The actual amount of time this equates to is defined + * by configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant + * portTICK_RATE_MS can be used to convert ticks to milliseconds (see the + * crQUEUE_SEND example). + * + * @param pxResult The variable pointed to by pxResult will be set to pdPASS if + * data was successfully retrieved from the queue, otherwise it will be set to + * an error code as defined within ProjDefs.h. + * + * Example usage: +
+ // A co-routine receives the number of an LED to flash from a queue.  It
+ // blocks on the queue until the number is received.
+ static void prvCoRoutineFlashWorkTask( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ static portBASE_TYPE xResult;
+ static unsigned portBASE_TYPE uxLEDToFlash;
+
+    // All co-routines must start with a call to crSTART().
+    crSTART( xHandle );
+
+    for( ;; )
+    {
+        // Wait for data to become available on the queue.
+        crQUEUE_RECEIVE( xHandle, xCoRoutineQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );
+
+        if( xResult == pdPASS )
+        {
+            // We received the LED to flash - flash it!
+            vParTestToggleLED( uxLEDToFlash );
+        }
+    }
+
+    crEND();
+ }
+ * \defgroup crQUEUE_RECEIVE crQUEUE_RECEIVE + * \ingroup Tasks + */ +#define crQUEUE_RECEIVE( xHandle, pxQueue, pvBuffer, xTicksToWait, pxResult ) \ +{ \ + *( pxResult ) = xQueueCRReceive( ( pxQueue) , ( pvBuffer ), ( xTicksToWait ) ); \ + if( *( pxResult ) == errQUEUE_BLOCKED ) \ + { \ + crSET_STATE0( ( xHandle ) ); \ + *( pxResult ) = xQueueCRReceive( ( pxQueue) , ( pvBuffer ), 0 ); \ + } \ + if( *( pxResult ) == errQUEUE_YIELD ) \ + { \ + crSET_STATE1( ( xHandle ) ); \ + *( pxResult ) = pdPASS; \ + } \ +} + +/** + * croutine. h + *
+  crQUEUE_SEND_FROM_ISR(
+                            xQueueHandle pxQueue,
+                            void *pvItemToQueue,
+                            portBASE_TYPE xCoRoutinePreviouslyWoken
+                       )
+ * + * The macro's crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() are the + * co-routine equivalent to the xQueueSendFromISR() and xQueueReceiveFromISR() + * functions used by tasks. + * + * crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() can only be used to + * pass data between a co-routine and and ISR, whereas xQueueSendFromISR() and + * xQueueReceiveFromISR() can only be used to pass data between a task and and + * ISR. + * + * crQUEUE_SEND_FROM_ISR can only be called from an ISR to send data to a queue + * that is being used from within a co-routine. + * + * See the co-routine section of the WEB documentation for information on + * passing data between tasks and co-routines and between ISR's and + * co-routines. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param xCoRoutinePreviouslyWoken This is included so an ISR can post onto + * the same queue multiple times from a single interrupt. The first call + * should always pass in pdFALSE. Subsequent calls should pass in + * the value returned from the previous call. + * + * @return pdTRUE if a co-routine was woken by posting onto the queue. This is + * used by the ISR to determine if a context switch may be required following + * the ISR. + * + * Example usage: +
+ // A co-routine that blocks on a queue waiting for characters to be received.
+ static void vReceivingCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ char cRxedChar;
+ portBASE_TYPE xResult;
+
+     // All co-routines must start with a call to crSTART().
+     crSTART( xHandle );
+
+     for( ;; )
+     {
+         // Wait for data to become available on the queue.  This assumes the
+         // queue xCommsRxQueue has already been created!
+         crQUEUE_RECEIVE( xHandle, xCommsRxQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );
+
+         // Was a character received?
+         if( xResult == pdPASS )
+         {
+             // Process the character here.
+         }
+     }
+
+     // All co-routines must end with a call to crEND().
+     crEND();
+ }
+
+ // An ISR that uses a queue to send characters received on a serial port to
+ // a co-routine.
+ void vUART_ISR( void )
+ {
+ char cRxedChar;
+ portBASE_TYPE xCRWokenByPost = pdFALSE;
+
+     // We loop around reading characters until there are none left in the UART.
+     while( UART_RX_REG_NOT_EMPTY() )
+     {
+         // Obtain the character from the UART.
+         cRxedChar = UART_RX_REG;
+
+         // Post the character onto a queue.  xCRWokenByPost will be pdFALSE
+         // the first time around the loop.  If the post causes a co-routine
+         // to be woken (unblocked) then xCRWokenByPost will be set to pdTRUE.
+         // In this manner we can ensure that if more than one co-routine is
+         // blocked on the queue only one is woken by this ISR no matter how
+         // many characters are posted to the queue.
+         xCRWokenByPost = crQUEUE_SEND_FROM_ISR( xCommsRxQueue, &cRxedChar, xCRWokenByPost );
+     }
+ }
+ * \defgroup crQUEUE_SEND_FROM_ISR crQUEUE_SEND_FROM_ISR + * \ingroup Tasks + */ +#define crQUEUE_SEND_FROM_ISR( pxQueue, pvItemToQueue, xCoRoutinePreviouslyWoken ) xQueueCRSendFromISR( ( pxQueue ), ( pvItemToQueue ), ( xCoRoutinePreviouslyWoken ) ) + + +/** + * croutine. h + *
+  crQUEUE_SEND_FROM_ISR(
+                            xQueueHandle pxQueue,
+                            void *pvBuffer,
+                            portBASE_TYPE * pxCoRoutineWoken
+                       )
+ * + * The macro's crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() are the + * co-routine equivalent to the xQueueSendFromISR() and xQueueReceiveFromISR() + * functions used by tasks. + * + * crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() can only be used to + * pass data between a co-routine and and ISR, whereas xQueueSendFromISR() and + * xQueueReceiveFromISR() can only be used to pass data between a task and and + * ISR. + * + * crQUEUE_RECEIVE_FROM_ISR can only be called from an ISR to receive data + * from a queue that is being used from within a co-routine (a co-routine + * posted to the queue). + * + * See the co-routine section of the WEB documentation for information on + * passing data between tasks and co-routines and between ISR's and + * co-routines. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvBuffer A pointer to a buffer into which the received item will be + * placed. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from the queue into + * pvBuffer. + * + * @param pxCoRoutineWoken A co-routine may be blocked waiting for space to become + * available on the queue. If crQUEUE_RECEIVE_FROM_ISR causes such a + * co-routine to unblock *pxCoRoutineWoken will get set to pdTRUE, otherwise + * *pxCoRoutineWoken will remain unchanged. + * + * @return pdTRUE an item was successfully received from the queue, otherwise + * pdFALSE. + * + * Example usage: +
+ // A co-routine that posts a character to a queue then blocks for a fixed
+ // period.  The character is incremented each time.
+ static void vSendingCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ // cChar holds its value while this co-routine is blocked and must therefore
+ // be declared static.
+ static char cCharToTx = 'a';
+ portBASE_TYPE xResult;
+
+     // All co-routines must start with a call to crSTART().
+     crSTART( xHandle );
+
+     for( ;; )
+     {
+         // Send the next character to the queue.
+         crQUEUE_SEND( xHandle, xCoRoutineQueue, &cCharToTx, NO_DELAY, &xResult );
+
+         if( xResult == pdPASS )
+         {
+             // The character was successfully posted to the queue.
+         }
+		 else
+		 {
+			// Could not post the character to the queue.
+		 }
+
+         // Enable the UART Tx interrupt to cause an interrupt in this
+		 // hypothetical UART.  The interrupt will obtain the character
+		 // from the queue and send it.
+		 ENABLE_RX_INTERRUPT();
+
+		 // Increment to the next character then block for a fixed period.
+		 // cCharToTx will maintain its value across the delay as it is
+		 // declared static.
+		 cCharToTx++;
+		 if( cCharToTx > 'x' )
+		 {
+			cCharToTx = 'a';
+		 }
+		 crDELAY( 100 );
+     }
+
+     // All co-routines must end with a call to crEND().
+     crEND();
+ }
+
+ // An ISR that uses a queue to receive characters to send on a UART.
+ void vUART_ISR( void )
+ {
+ char cCharToTx;
+ portBASE_TYPE xCRWokenByPost = pdFALSE;
+
+     while( UART_TX_REG_EMPTY() )
+     {
+         // Are there any characters in the queue waiting to be sent?
+		 // xCRWokenByPost will automatically be set to pdTRUE if a co-routine
+		 // is woken by the post - ensuring that only a single co-routine is
+		 // woken no matter how many times we go around this loop.
+         if( crQUEUE_RECEIVE_FROM_ISR( pxQueue, &cCharToTx, &xCRWokenByPost ) )
+		 {
+			 SEND_CHARACTER( cCharToTx );
+		 }
+     }
+ }
+ * \defgroup crQUEUE_RECEIVE_FROM_ISR crQUEUE_RECEIVE_FROM_ISR + * \ingroup Tasks + */ +#define crQUEUE_RECEIVE_FROM_ISR( pxQueue, pvBuffer, pxCoRoutineWoken ) xQueueCRReceiveFromISR( ( pxQueue ), ( pvBuffer ), ( pxCoRoutineWoken ) ) + +/* + * This function is intended for internal use by the co-routine macros only. + * The macro nature of the co-routine implementation requires that the + * prototype appears here. The function should not be used by application + * writers. + * + * Removes the current co-routine from its ready list and places it in the + * appropriate delayed list. + */ +void vCoRoutineAddToDelayedList( portTickType xTicksToDelay, xList *pxEventList ); + +/* + * This function is intended for internal use by the queue implementation only. + * The function should not be used by application writers. + * + * Removes the highest priority co-routine from the event list and places it in + * the pending ready list. + */ +signed portBASE_TYPE xCoRoutineRemoveFromEventList( const xList *pxEventList ); + +#ifdef __cplusplus +} +#endif + +#endif /* CO_ROUTINE_H */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/freertos/list.h b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/list.h new file mode 100644 index 0000000..7511be3 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/list.h @@ -0,0 +1,378 @@ +/* + FreeRTOS V7.5.2 - Copyright (C) 2013 Real Time Engineers Ltd. + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that has become a de facto standard. * + * * + * Help yourself get started quickly and support the FreeRTOS * + * project by purchasing a FreeRTOS tutorial book, reference * + * manual, or both from: http://www.FreeRTOS.org/Documentation * + * * + * Thank you! * + * * + *************************************************************************** + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + >>! NOTE: The modification to the GPL is included to allow you to distribute + >>! a combined work that includes FreeRTOS without being obliged to provide + >>! the source code for proprietary components outside of the FreeRTOS + >>! kernel. + + FreeRTOS 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. Full license text is available from the following + link: http://www.freertos.org/a00114.html + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * This is the list implementation used by the scheduler. While it is tailored + * heavily for the schedulers needs, it is also available for use by + * application code. + * + * xLists can only store pointers to xListItems. Each xListItem contains a + * numeric value (xItemValue). Most of the time the lists are sorted in + * descending item value order. + * + * Lists are created already containing one list item. The value of this + * item is the maximum possible that can be stored, it is therefore always at + * the end of the list and acts as a marker. The list member pxHead always + * points to this marker - even though it is at the tail of the list. This + * is because the tail contains a wrap back pointer to the true head of + * the list. + * + * In addition to it's value, each list item contains a pointer to the next + * item in the list (pxNext), a pointer to the list it is in (pxContainer) + * and a pointer to back to the object that contains it. These later two + * pointers are included for efficiency of list manipulation. There is + * effectively a two way link between the object containing the list item and + * the list item itself. + * + * + * \page ListIntroduction List Implementation + * \ingroup FreeRTOSIntro + */ + + +#ifndef LIST_H +#define LIST_H + +/* + * The list structure members are modified from within interrupts, and therefore + * by rights should be declared volatile. However, they are only modified in a + * functionally atomic way (within critical sections of with the scheduler + * suspended) and are either passed by reference into a function or indexed via + * a volatile variable. Therefore, in all use cases tested so far, the volatile + * qualifier can be omitted in order to provide a moderate performance + * improvement without adversely affecting functional behaviour. The assembly + * instructions generated by the IAR, ARM and GCC compilers when the respective + * compiler's options were set for maximum optimisation has been inspected and + * deemed to be as intended. That said, as compiler technology advances, and + * especially if aggressive cross module optimisation is used (a use case that + * has not been exercised to any great extend) then it is feasible that the + * volatile qualifier will be needed for correct optimisation. It is expected + * that a compiler removing essential code because, without the volatile + * qualifier on the list structure members and with aggressive cross module + * optimisation, the compiler deemed the code unnecessary will result in + * complete and obvious failure of the scheduler. If this is ever experienced + * then the volatile qualifier can be inserted in the relevant places within the + * list structures by simply defining configLIST_VOLATILE to volatile in + * FreeRTOSConfig.h (as per the example at the bottom of this comment block). + * If configLIST_VOLATILE is not defined then the preprocessor directives below + * will simply #define configLIST_VOLATILE away completely. + * + * To use volatile list structure members then add the following line to + * FreeRTOSConfig.h (without the quotes): + * "#define configLIST_VOLATILE volatile" + */ +#ifndef configLIST_VOLATILE + #define configLIST_VOLATILE +#endif /* configSUPPORT_CROSS_MODULE_OPTIMISATION */ + +#ifdef __cplusplus +extern "C" { +#endif +/* + * Definition of the only type of object that a list can contain. + */ +struct xLIST_ITEM +{ + configLIST_VOLATILE portTickType xItemValue; /*< The value being listed. In most cases this is used to sort the list in descending order. */ + struct xLIST_ITEM * configLIST_VOLATILE pxNext; /*< Pointer to the next xListItem in the list. */ + struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;/*< Pointer to the previous xListItem in the list. */ + void * pvOwner; /*< Pointer to the object (normally a TCB) that contains the list item. There is therefore a two way link between the object containing the list item and the list item itself. */ + void * configLIST_VOLATILE pvContainer; /*< Pointer to the list in which this list item is placed (if any). */ +}; +typedef struct xLIST_ITEM xListItem; /* For some reason lint wants this as two separate definitions. */ + +struct xMINI_LIST_ITEM +{ + configLIST_VOLATILE portTickType xItemValue; + struct xLIST_ITEM * configLIST_VOLATILE pxNext; + struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; +}; +typedef struct xMINI_LIST_ITEM xMiniListItem; + +/* + * Definition of the type of queue used by the scheduler. + */ +typedef struct xLIST +{ + configLIST_VOLATILE unsigned portBASE_TYPE uxNumberOfItems; + xListItem * configLIST_VOLATILE pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to pvListGetOwnerOfNextEntry (). */ + xMiniListItem xListEnd; /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */ +} xList; + +/* + * Access macro to set the owner of a list item. The owner of a list item + * is the object (usually a TCB) that contains the list item. + * + * \page listSET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER + * \ingroup LinkedList + */ +#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner ) ( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) ) + +/* + * Access macro to get the owner of a list item. The owner of a list item + * is the object (usually a TCB) that contains the list item. + * + * \page listSET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER + * \ingroup LinkedList + */ +#define listGET_LIST_ITEM_OWNER( pxListItem ) ( pxListItem )->pvOwner + +/* + * Access macro to set the value of the list item. In most cases the value is + * used to sort the list in descending order. + * + * \page listSET_LIST_ITEM_VALUE listSET_LIST_ITEM_VALUE + * \ingroup LinkedList + */ +#define listSET_LIST_ITEM_VALUE( pxListItem, xValue ) ( ( pxListItem )->xItemValue = ( xValue ) ) + +/* + * Access macro to retrieve the value of the list item. The value can + * represent anything - for example a the priority of a task, or the time at + * which a task should be unblocked. + * + * \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE + * \ingroup LinkedList + */ +#define listGET_LIST_ITEM_VALUE( pxListItem ) ( ( pxListItem )->xItemValue ) + +/* + * Access macro the retrieve the value of the list item at the head of a given + * list. + * + * \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE + * \ingroup LinkedList + */ +#define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList ) ( (&( ( pxList )->xListEnd ))->pxNext->xItemValue ) + +/* + * Access macro to determine if a list contains any items. The macro will + * only have the value true if the list is empty. + * + * \page listLIST_IS_EMPTY listLIST_IS_EMPTY + * \ingroup LinkedList + */ +#define listLIST_IS_EMPTY( pxList ) ( ( portBASE_TYPE ) ( ( pxList )->uxNumberOfItems == ( unsigned portBASE_TYPE ) 0 ) ) + +/* + * Access macro to return the number of items in the list. + */ +#define listCURRENT_LIST_LENGTH( pxList ) ( ( pxList )->uxNumberOfItems ) + +/* + * Access function to obtain the owner of the next entry in a list. + * + * The list member pxIndex is used to walk through a list. Calling + * listGET_OWNER_OF_NEXT_ENTRY increments pxIndex to the next item in the list + * and returns that entries pxOwner parameter. Using multiple calls to this + * function it is therefore possible to move through every item contained in + * a list. + * + * The pxOwner parameter of a list item is a pointer to the object that owns + * the list item. In the scheduler this is normally a task control block. + * The pxOwner parameter effectively creates a two way link between the list + * item and its owner. + * + * @param pxList The list from which the next item owner is to be returned. + * + * \page listGET_OWNER_OF_NEXT_ENTRY listGET_OWNER_OF_NEXT_ENTRY + * \ingroup LinkedList + */ +#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList ) \ +{ \ +xList * const pxConstList = ( pxList ); \ + /* Increment the index to the next item and return the item, ensuring */ \ + /* we don't return the marker used at the end of the list. */ \ + ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \ + if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) ) \ + { \ + ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \ + } \ + ( pxTCB ) = ( pxConstList )->pxIndex->pvOwner; \ +} + + +/* + * Access function to obtain the owner of the first entry in a list. Lists + * are normally sorted in ascending item value order. + * + * This function returns the pxOwner member of the first item in the list. + * The pxOwner parameter of a list item is a pointer to the object that owns + * the list item. In the scheduler this is normally a task control block. + * The pxOwner parameter effectively creates a two way link between the list + * item and its owner. + * + * @param pxList The list from which the owner of the head item is to be + * returned. + * + * \page listGET_OWNER_OF_HEAD_ENTRY listGET_OWNER_OF_HEAD_ENTRY + * \ingroup LinkedList + */ +#define listGET_OWNER_OF_HEAD_ENTRY( pxList ) ( (&( ( pxList )->xListEnd ))->pxNext->pvOwner ) + +/* + * Check to see if a list item is within a list. The list item maintains a + * "container" pointer that points to the list it is in. All this macro does + * is check to see if the container and the list match. + * + * @param pxList The list we want to know if the list item is within. + * @param pxListItem The list item we want to know if is in the list. + * @return pdTRUE is the list item is in the list, otherwise pdFALSE. + * pointer against + */ +#define listIS_CONTAINED_WITHIN( pxList, pxListItem ) ( ( portBASE_TYPE ) ( ( pxListItem )->pvContainer == ( void * ) ( pxList ) ) ) + +/* + * Return the list a list item is contained within (referenced from). + * + * @param pxListItem The list item being queried. + * @return A pointer to the xList object that references the pxListItem + */ +#define listLIST_ITEM_CONTAINER( pxListItem ) ( ( pxListItem )->pvContainer ) + +/* + * This provides a crude means of knowing if a list has been initialised, as + * pxList->xListEnd.xItemValue is set to portMAX_DELAY by the vListInitialise() + * function. + */ +#define listLIST_IS_INITIALISED( pxList ) ( ( pxList )->xListEnd.xItemValue == portMAX_DELAY ) + +/* + * Must be called before a list is used! This initialises all the members + * of the list structure and inserts the xListEnd item into the list as a + * marker to the back of the list. + * + * @param pxList Pointer to the list being initialised. + * + * \page vListInitialise vListInitialise + * \ingroup LinkedList + */ +void vListInitialise( xList * const pxList ); + +/* + * Must be called before a list item is used. This sets the list container to + * null so the item does not think that it is already contained in a list. + * + * @param pxItem Pointer to the list item being initialised. + * + * \page vListInitialiseItem vListInitialiseItem + * \ingroup LinkedList + */ +void vListInitialiseItem( xListItem * const pxItem ); + +/* + * Insert a list item into a list. The item will be inserted into the list in + * a position determined by its item value (descending item value order). + * + * @param pxList The list into which the item is to be inserted. + * + * @param pxNewListItem The item to that is to be placed in the list. + * + * \page vListInsert vListInsert + * \ingroup LinkedList + */ +void vListInsert( xList * const pxList, xListItem * const pxNewListItem ); + +/* + * Insert a list item into a list. The item will be inserted in a position + * such that it will be the last item within the list returned by multiple + * calls to listGET_OWNER_OF_NEXT_ENTRY. + * + * The list member pvIndex is used to walk through a list. Calling + * listGET_OWNER_OF_NEXT_ENTRY increments pvIndex to the next item in the list. + * Placing an item in a list using vListInsertEnd effectively places the item + * in the list position pointed to by pvIndex. This means that every other + * item within the list will be returned by listGET_OWNER_OF_NEXT_ENTRY before + * the pvIndex parameter again points to the item being inserted. + * + * @param pxList The list into which the item is to be inserted. + * + * @param pxNewListItem The list item to be inserted into the list. + * + * \page vListInsertEnd vListInsertEnd + * \ingroup LinkedList + */ +void vListInsertEnd( xList * const pxList, xListItem * const pxNewListItem ); + +/* + * Remove an item from a list. The list item has a pointer to the list that + * it is in, so only the list item need be passed into the function. + * + * @param uxListRemove The item to be removed. The item will remove itself from + * the list pointed to by it's pxContainer parameter. + * + * @return The number of items that remain in the list after the list item has + * been removed. + * + * \page uxListRemove uxListRemove + * \ingroup LinkedList + */ +unsigned portBASE_TYPE uxListRemove( xListItem * const pxItemToRemove ); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/freertos/mpu_wrappers.h b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/mpu_wrappers.h new file mode 100644 index 0000000..e3e2246 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/mpu_wrappers.h @@ -0,0 +1,152 @@ +/* + FreeRTOS V7.5.2 - Copyright (C) 2013 Real Time Engineers Ltd. + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that has become a de facto standard. * + * * + * Help yourself get started quickly and support the FreeRTOS * + * project by purchasing a FreeRTOS tutorial book, reference * + * manual, or both from: http://www.FreeRTOS.org/Documentation * + * * + * Thank you! * + * * + *************************************************************************** + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + >>! NOTE: The modification to the GPL is included to allow you to distribute + >>! a combined work that includes FreeRTOS without being obliged to provide + >>! the source code for proprietary components outside of the FreeRTOS + >>! kernel. + + FreeRTOS 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. Full license text is available from the following + link: http://www.freertos.org/a00114.html + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef MPU_WRAPPERS_H +#define MPU_WRAPPERS_H + +/* This file redefines API functions to be called through a wrapper macro, but +only for ports that are using the MPU. */ +#ifdef portUSING_MPU_WRAPPERS + + /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE will be defined when this file is + included from queue.c or task.c to prevent it from having an effect within + those files. */ + #ifndef MPU_WRAPPERS_INCLUDED_FROM_API_FILE + + #define xTaskGenericCreate MPU_xTaskGenericCreate + #define vTaskAllocateMPURegions MPU_vTaskAllocateMPURegions + #define vTaskDelete MPU_vTaskDelete + #define vTaskDelayUntil MPU_vTaskDelayUntil + #define vTaskDelay MPU_vTaskDelay + #define uxTaskPriorityGet MPU_uxTaskPriorityGet + #define vTaskPrioritySet MPU_vTaskPrioritySet + #define eTaskGetState MPU_eTaskGetState + #define vTaskSuspend MPU_vTaskSuspend + #define xTaskIsTaskSuspended MPU_xTaskIsTaskSuspended + #define vTaskResume MPU_vTaskResume + #define vTaskSuspendAll MPU_vTaskSuspendAll + #define xTaskResumeAll MPU_xTaskResumeAll + #define xTaskGetTickCount MPU_xTaskGetTickCount + #define uxTaskGetNumberOfTasks MPU_uxTaskGetNumberOfTasks + #define vTaskList MPU_vTaskList + #define vTaskGetRunTimeStats MPU_vTaskGetRunTimeStats + #define vTaskSetApplicationTaskTag MPU_vTaskSetApplicationTaskTag + #define xTaskGetApplicationTaskTag MPU_xTaskGetApplicationTaskTag + #define xTaskCallApplicationTaskHook MPU_xTaskCallApplicationTaskHook + #define uxTaskGetStackHighWaterMark MPU_uxTaskGetStackHighWaterMark + #define xTaskGetCurrentTaskHandle MPU_xTaskGetCurrentTaskHandle + #define xTaskGetSchedulerState MPU_xTaskGetSchedulerState + #define xTaskGetIdleTaskHandle MPU_xTaskGetIdleTaskHandle + #define uxTaskGetSystemState MPU_uxTaskGetSystemState + + #define xQueueGenericCreate MPU_xQueueGenericCreate + #define xQueueCreateMutex MPU_xQueueCreateMutex + #define xQueueGiveMutexRecursive MPU_xQueueGiveMutexRecursive + #define xQueueTakeMutexRecursive MPU_xQueueTakeMutexRecursive + #define xQueueCreateCountingSemaphore MPU_xQueueCreateCountingSemaphore + #define xQueueGenericSend MPU_xQueueGenericSend + #define xQueueAltGenericSend MPU_xQueueAltGenericSend + #define xQueueAltGenericReceive MPU_xQueueAltGenericReceive + #define xQueueGenericReceive MPU_xQueueGenericReceive + #define uxQueueMessagesWaiting MPU_uxQueueMessagesWaiting + #define vQueueDelete MPU_vQueueDelete + #define xQueueGenericReset MPU_xQueueGenericReset + #define xQueueCreateSet MPU_xQueueCreateSet + #define xQueueSelectFromSet MPU_xQueueSelectFromSet + #define xQueueAddToSet MPU_xQueueAddToSet + #define xQueueRemoveFromSet MPU_xQueueRemoveFromSet + #define xQueuePeekFromISR MPU_xQueuePeekFromISR + + #define pvPortMalloc MPU_pvPortMalloc + #define vPortFree MPU_vPortFree + #define xPortGetFreeHeapSize MPU_xPortGetFreeHeapSize + #define vPortInitialiseBlocks MPU_vPortInitialiseBlocks + + #if configQUEUE_REGISTRY_SIZE > 0 + #define vQueueAddToRegistry MPU_vQueueAddToRegistry + #define vQueueUnregisterQueue MPU_vQueueUnregisterQueue + #endif + + /* Remove the privileged function macro. */ + #define PRIVILEGED_FUNCTION + + #else /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE */ + + /* Ensure API functions go in the privileged execution section. */ + #define PRIVILEGED_FUNCTION __attribute__((section("privileged_functions"))) + #define PRIVILEGED_DATA __attribute__((section("privileged_data"))) + + #endif /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE */ + +#else /* portUSING_MPU_WRAPPERS */ + + #define PRIVILEGED_FUNCTION + #define PRIVILEGED_DATA + #define portUSING_MPU_WRAPPERS 0 + +#endif /* portUSING_MPU_WRAPPERS */ + + +#endif /* MPU_WRAPPERS_H */ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/freertos/portable.h b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/portable.h new file mode 100644 index 0000000..31811b6 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/portable.h @@ -0,0 +1,408 @@ +/* + FreeRTOS V7.5.2 - Copyright (C) 2013 Real Time Engineers Ltd. + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that has become a de facto standard. * + * * + * Help yourself get started quickly and support the FreeRTOS * + * project by purchasing a FreeRTOS tutorial book, reference * + * manual, or both from: http://www.FreeRTOS.org/Documentation * + * * + * Thank you! * + * * + *************************************************************************** + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + >>! NOTE: The modification to the GPL is included to allow you to distribute + >>! a combined work that includes FreeRTOS without being obliged to provide + >>! the source code for proprietary components outside of the FreeRTOS + >>! kernel. + + FreeRTOS 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. Full license text is available from the following + link: http://www.freertos.org/a00114.html + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/*----------------------------------------------------------- + * Portable layer API. Each function must be defined for each port. + *----------------------------------------------------------*/ + +#ifndef PORTABLE_H +#define PORTABLE_H + +/* Include the macro file relevant to the port being used. */ + +#ifdef OPEN_WATCOM_INDUSTRIAL_PC_PORT + #include "..\..\Source\portable\owatcom\16bitdos\pc\portmacro.h" + typedef void ( __interrupt __far *pxISR )(); +#endif + +#ifdef OPEN_WATCOM_FLASH_LITE_186_PORT + #include "..\..\Source\portable\owatcom\16bitdos\flsh186\portmacro.h" + typedef void ( __interrupt __far *pxISR )(); +#endif + +#ifdef GCC_MEGA_AVR + #include "../portable/GCC/ATMega323/portmacro.h" +#endif + +#ifdef IAR_MEGA_AVR + #include "../portable/IAR/ATMega323/portmacro.h" +#endif + +#ifdef MPLAB_PIC24_PORT + #include "..\..\Source\portable\MPLAB\PIC24_dsPIC\portmacro.h" +#endif + +#ifdef MPLAB_DSPIC_PORT + #include "..\..\Source\portable\MPLAB\PIC24_dsPIC\portmacro.h" +#endif + +#ifdef MPLAB_PIC18F_PORT + #include "..\..\Source\portable\MPLAB\PIC18F\portmacro.h" +#endif + +#ifdef MPLAB_PIC32MX_PORT + #include "..\..\Source\portable\MPLAB\PIC32MX\portmacro.h" +#endif + +#ifdef _FEDPICC + #include "libFreeRTOS/Include/portmacro.h" +#endif + +#ifdef SDCC_CYGNAL + #include "../../Source/portable/SDCC/Cygnal/portmacro.h" +#endif + +#ifdef GCC_ARM7 + #include "../../Source/portable/GCC/ARM7_LPC2000/portmacro.h" +#endif + +#ifdef GCC_ARM7_ECLIPSE + #include "portmacro.h" +#endif + +#ifdef ROWLEY_LPC23xx + #include "../../Source/portable/GCC/ARM7_LPC23xx/portmacro.h" +#endif + +#ifdef IAR_MSP430 + #include "..\..\Source\portable\IAR\MSP430\portmacro.h" +#endif + +#ifdef GCC_MSP430 + #include "../../Source/portable/GCC/MSP430F449/portmacro.h" +#endif + +#ifdef ROWLEY_MSP430 + #include "../../Source/portable/Rowley/MSP430F449/portmacro.h" +#endif + +#ifdef ARM7_LPC21xx_KEIL_RVDS + #include "..\..\Source\portable\RVDS\ARM7_LPC21xx\portmacro.h" +#endif + +#ifdef SAM7_GCC + #include "../../Source/portable/GCC/ARM7_AT91SAM7S/portmacro.h" +#endif + +#ifdef SAM7_IAR + #include "..\..\Source\portable\IAR\AtmelSAM7S64\portmacro.h" +#endif + +#ifdef SAM9XE_IAR + #include "..\..\Source\portable\IAR\AtmelSAM9XE\portmacro.h" +#endif + +#ifdef LPC2000_IAR + #include "..\..\Source\portable\IAR\LPC2000\portmacro.h" +#endif + +#ifdef STR71X_IAR + #include "..\..\Source\portable\IAR\STR71x\portmacro.h" +#endif + +#ifdef STR75X_IAR + #include "..\..\Source\portable\IAR\STR75x\portmacro.h" +#endif + +#ifdef STR75X_GCC + #include "..\..\Source\portable\GCC\STR75x\portmacro.h" +#endif + +#ifdef STR91X_IAR + #include "..\..\Source\portable\IAR\STR91x\portmacro.h" +#endif + +#ifdef GCC_H8S + #include "../../Source/portable/GCC/H8S2329/portmacro.h" +#endif + +#ifdef GCC_AT91FR40008 + #include "../../Source/portable/GCC/ARM7_AT91FR40008/portmacro.h" +#endif + +#ifdef RVDS_ARMCM3_LM3S102 + #include "../../Source/portable/RVDS/ARM_CM3/portmacro.h" +#endif + +#ifdef GCC_ARMCM3_LM3S102 + #include "../../Source/portable/GCC/ARM_CM3/portmacro.h" +#endif + +#ifdef GCC_ARMCM3 + #include "../../Source/portable/GCC/ARM_CM3/portmacro.h" +#endif + +#ifdef IAR_ARM_CM3 + #include "../../Source/portable/IAR/ARM_CM3/portmacro.h" +#endif + +#ifdef IAR_ARMCM3_LM + #include "../../Source/portable/IAR/ARM_CM3/portmacro.h" +#endif + +#ifdef HCS12_CODE_WARRIOR + #include "../../Source/portable/CodeWarrior/HCS12/portmacro.h" +#endif + +#ifdef MICROBLAZE_GCC + #include "../../Source/portable/GCC/MicroBlaze/portmacro.h" +#endif + +#ifdef TERN_EE + #include "..\..\Source\portable\Paradigm\Tern_EE\small\portmacro.h" +#endif + +#ifdef GCC_HCS12 + #include "../../Source/portable/GCC/HCS12/portmacro.h" +#endif + +#ifdef GCC_MCF5235 + #include "../../Source/portable/GCC/MCF5235/portmacro.h" +#endif + +#ifdef COLDFIRE_V2_GCC + #include "../../../Source/portable/GCC/ColdFire_V2/portmacro.h" +#endif + +#ifdef COLDFIRE_V2_CODEWARRIOR + #include "../../Source/portable/CodeWarrior/ColdFire_V2/portmacro.h" +#endif + +#ifdef GCC_PPC405 + #include "../../Source/portable/GCC/PPC405_Xilinx/portmacro.h" +#endif + +#ifdef GCC_PPC440 + #include "../../Source/portable/GCC/PPC440_Xilinx/portmacro.h" +#endif + +#ifdef _16FX_SOFTUNE + #include "..\..\Source\portable\Softune\MB96340\portmacro.h" +#endif + +#ifdef BCC_INDUSTRIAL_PC_PORT + /* A short file name has to be used in place of the normal + FreeRTOSConfig.h when using the Borland compiler. */ + #include "frconfig.h" + #include "..\portable\BCC\16BitDOS\PC\prtmacro.h" + typedef void ( __interrupt __far *pxISR )(); +#endif + +#ifdef BCC_FLASH_LITE_186_PORT + /* A short file name has to be used in place of the normal + FreeRTOSConfig.h when using the Borland compiler. */ + #include "frconfig.h" + #include "..\portable\BCC\16BitDOS\flsh186\prtmacro.h" + typedef void ( __interrupt __far *pxISR )(); +#endif + +#ifdef __GNUC__ + #ifdef __AVR32_AVR32A__ + #include "portmacro.h" + #endif +#endif + +#ifdef __ICCAVR32__ + #ifdef __CORE__ + #if __CORE__ == __AVR32A__ + #include "portmacro.h" + #endif + #endif +#endif + +#ifdef __91467D + #include "portmacro.h" +#endif + +#ifdef __96340 + #include "portmacro.h" +#endif + + +#ifdef __IAR_V850ES_Fx3__ + #include "../../Source/portable/IAR/V850ES/portmacro.h" +#endif + +#ifdef __IAR_V850ES_Jx3__ + #include "../../Source/portable/IAR/V850ES/portmacro.h" +#endif + +#ifdef __IAR_V850ES_Jx3_L__ + #include "../../Source/portable/IAR/V850ES/portmacro.h" +#endif + +#ifdef __IAR_V850ES_Jx2__ + #include "../../Source/portable/IAR/V850ES/portmacro.h" +#endif + +#ifdef __IAR_V850ES_Hx2__ + #include "../../Source/portable/IAR/V850ES/portmacro.h" +#endif + +#ifdef __IAR_78K0R_Kx3__ + #include "../../Source/portable/IAR/78K0R/portmacro.h" +#endif + +#ifdef __IAR_78K0R_Kx3L__ + #include "../../Source/portable/IAR/78K0R/portmacro.h" +#endif + +/* Catch all to ensure portmacro.h is included in the build. Newer demos +have the path as part of the project options, rather than as relative from +the project location. If portENTER_CRITICAL() has not been defined then +portmacro.h has not yet been included - as every portmacro.h provides a +portENTER_CRITICAL() definition. Check the demo application for your demo +to find the path to the correct portmacro.h file. */ +#ifndef portENTER_CRITICAL + #include "portmacro.h" +#endif + +#if portBYTE_ALIGNMENT == 8 + #define portBYTE_ALIGNMENT_MASK ( 0x0007 ) +#endif + +#if portBYTE_ALIGNMENT == 4 + #define portBYTE_ALIGNMENT_MASK ( 0x0003 ) +#endif + +#if portBYTE_ALIGNMENT == 2 + #define portBYTE_ALIGNMENT_MASK ( 0x0001 ) +#endif + +#if portBYTE_ALIGNMENT == 1 + #define portBYTE_ALIGNMENT_MASK ( 0x0000 ) +#endif + +#ifndef portBYTE_ALIGNMENT_MASK + #error "Invalid portBYTE_ALIGNMENT definition" +#endif + +#ifndef portNUM_CONFIGURABLE_REGIONS + #define portNUM_CONFIGURABLE_REGIONS 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#include "mpu_wrappers.h" + +/* + * Setup the stack of a new task so it is ready to be placed under the + * scheduler control. The registers have to be placed on the stack in + * the order that the port expects to find them. + * + */ +#if( portUSING_MPU_WRAPPERS == 1 ) + portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters, portBASE_TYPE xRunPrivileged ) PRIVILEGED_FUNCTION; +#else + portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters ) PRIVILEGED_FUNCTION; +#endif + +/* + * Map to the memory management routines required for the port. + */ +/* for freeRTOS, MEMLEAK_DEBUG must be enabled. */ +#if 0 +void *pvPortMalloc( size_t xSize ) PRIVILEGED_FUNCTION; +void vPortFree( void *pv ) PRIVILEGED_FUNCTION; +#else +void *pvPortMalloc( size_t xSize, const char *file, unsigned line) PRIVILEGED_FUNCTION; +void vPortFree( void *pv, const char * file, unsigned line) PRIVILEGED_FUNCTION; +#endif + +void vPortInitialiseBlocks( void ) PRIVILEGED_FUNCTION; +size_t xPortGetFreeHeapSize( void ) PRIVILEGED_FUNCTION; + +/* + * Setup the hardware ready for the scheduler to take control. This generally + * sets up a tick interrupt and sets timers for the correct tick frequency. + */ +portBASE_TYPE xPortStartScheduler( void ) PRIVILEGED_FUNCTION; + +/* + * Undo any hardware/ISR setup that was performed by xPortStartScheduler() so + * the hardware is left in its original condition after the scheduler stops + * executing. + */ +void vPortEndScheduler( void ) PRIVILEGED_FUNCTION; + +/* + * The structures and methods of manipulating the MPU are contained within the + * port layer. + * + * Fills the xMPUSettings structure with the memory region information + * contained in xRegions. + */ +#if( portUSING_MPU_WRAPPERS == 1 ) + struct xMEMORY_REGION; + void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION * const xRegions, portSTACK_TYPE *pxBottomOfStack, unsigned short usStackDepth ) PRIVILEGED_FUNCTION; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* PORTABLE_H */ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/freertos/portmacro.h b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/portmacro.h new file mode 100644 index 0000000..6eec264 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/portmacro.h @@ -0,0 +1,199 @@ +/* + FreeRTOS V7.5.2 - Copyright (C) 2013 Real Time Engineers Ltd. + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that has become a de facto standard. * + * * + * Help yourself get started quickly and support the FreeRTOS * + * project by purchasing a FreeRTOS tutorial book, reference * + * manual, or both from: http://www.FreeRTOS.org/Documentation * + * * + * Thank you! * + * * + *************************************************************************** + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + >>! NOTE: The modification to the GPL is included to allow you to distribute + >>! a combined work that includes FreeRTOS without being obliged to provide + >>! the source code for proprietary components outside of the FreeRTOS + >>! kernel. + + FreeRTOS 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. Full license text is available from the following + link: http://www.freertos.org/a00114.html + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + + +#ifndef PORTMACRO_H +#define PORTMACRO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "c_types.h" +#include "espressif/esp_libc.h" +#include "esp8266/ets_sys.h" + +#include +#include "xtensa_rtos.h" + +/*----------------------------------------------------------- + * Port specific definitions. + * + * The settings in this file configure FreeRTOS correctly for the + * given hardware and compiler. + * + * These settings should not be altered. + *----------------------------------------------------------- + */ + +/* Type definitions. */ +#define portCHAR char +#define portFLOAT float +#define portDOUBLE double +#define portLONG long +#define portSHORT short +#define portSTACK_TYPE unsigned portLONG +#define portBASE_TYPE long + +typedef unsigned portLONG portTickType; +typedef unsigned int INT32U; +#define portMAX_DELAY ( portTickType ) 0xffffffff +/*-----------------------------------------------------------*/ + +/* Architecture specifics. */ +#define portSTACK_GROWTH ( -1 ) +#define portTICK_RATE_MS ( ( portTickType ) 1000 / configTICK_RATE_HZ ) +#define portBYTE_ALIGNMENT 8 +/*-----------------------------------------------------------*/ + +/* Scheduler utilities. */ +extern void PendSV(char req); +//#define portYIELD() vPortYield() +#define portYIELD() PendSV(1) + +#if 0 +#define portEND_SWITCHING_ISR( xSwitchRequired ) \ + if(xSwitchRequired) PendSV(1) +#endif + +#define HDL_MAC_SIG_IN_LV1_ISR() PendSV(2) + +/* Task utilities. */ +#define portEND_SWITCHING_ISR( xSwitchRequired ) \ +{ \ +extern void vTaskSwitchContext( void ); \ + \ + if( xSwitchRequired ) \ + { \ + vTaskSwitchContext(); \ + } \ +} + + +/*-----------------------------------------------------------*/ +extern unsigned cpu_sr; + +/* Critical section management. */ +extern void vPortEnterCritical( void ); +extern void vPortExitCritical( void ); + +//DYC_ISR_DBG +void PortDisableInt_NoNest( void ); +void PortEnableInt_NoNest( void ); + +/* Disable interrupts, saving previous state in cpu_sr */ +#define portDISABLE_INTERRUPTS() \ + __asm__ volatile ("rsil %0, " XTSTR(XCHAL_EXCM_LEVEL) : "=a" (cpu_sr) :: "memory") + +/* Restore interrupts to previous level saved in cpu_sr */ +#define portENABLE_INTERRUPTS() __asm__ volatile ("wsr %0, ps" :: "a" (cpu_sr) : "memory") + +#define portENTER_CRITICAL() vPortEnterCritical() +#define portEXIT_CRITICAL() vPortExitCritical() + +// no need to disable/enable lvl1 isr again in ISR +//#define portSET_INTERRUPT_MASK_FROM_ISR() PortDisableInt_NoNest() +//#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) PortEnableInt_NoNest() + + +/*-----------------------------------------------------------*/ + +/* Tickless idle/low power functionality. */ + +/*-----------------------------------------------------------*/ + +/* Port specific optimisations. */ + +/*-----------------------------------------------------------*/ + +/* Task function macros as described on the FreeRTOS.org WEB site. These are +not necessary for to use this port. They are defined so the common demo files +(which build with all the ports) will build. */ +#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters ) +#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters ) +/*-----------------------------------------------------------*/ + +void _xt_user_exit (void); +void _xt_tick_timer_init (void); +void _xt_isr_unmask (uint32 unmask); +void _xt_isr_mask (uint32 mask); +uint32 _xt_read_ints (void); +void _xt_clear_ints(uint32 mask); + +/* interrupt related */ +typedef void (* _xt_isr)(void *arg); + +void _xt_isr_attach (uint8 i, _xt_isr func, void *arg); + +typedef struct _xt_isr_entry_ { + _xt_isr handler; + void * arg; +} _xt_isr_entry; + +#ifdef __cplusplus +} +#endif + +#endif /* PORTMACRO_H */ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/freertos/projdefs.h b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/projdefs.h new file mode 100644 index 0000000..8a65e8b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/projdefs.h @@ -0,0 +1,88 @@ +/* + FreeRTOS V7.5.2 - Copyright (C) 2013 Real Time Engineers Ltd. + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that has become a de facto standard. * + * * + * Help yourself get started quickly and support the FreeRTOS * + * project by purchasing a FreeRTOS tutorial book, reference * + * manual, or both from: http://www.FreeRTOS.org/Documentation * + * * + * Thank you! * + * * + *************************************************************************** + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + >>! NOTE: The modification to the GPL is included to allow you to distribute + >>! a combined work that includes FreeRTOS without being obliged to provide + >>! the source code for proprietary components outside of the FreeRTOS + >>! kernel. + + FreeRTOS 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. Full license text is available from the following + link: http://www.freertos.org/a00114.html + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef PROJDEFS_H +#define PROJDEFS_H + +/* Defines the prototype to which task functions must conform. */ +typedef void (*pdTASK_CODE)( void * ); + +#define pdFALSE ( ( portBASE_TYPE ) 0 ) +#define pdTRUE ( ( portBASE_TYPE ) 1 ) + +#define pdPASS ( pdTRUE ) +#define pdFAIL ( pdFALSE ) +#define errQUEUE_EMPTY ( ( portBASE_TYPE ) 0 ) +#define errQUEUE_FULL ( ( portBASE_TYPE ) 0 ) + +/* Error definitions. */ +#define errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY ( -1 ) +#define errNO_TASK_TO_RUN ( -2 ) +#define errQUEUE_BLOCKED ( -4 ) +#define errQUEUE_YIELD ( -5 ) + +#endif /* PROJDEFS_H */ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/freertos/queue.h b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/queue.h new file mode 100644 index 0000000..c0f2630 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/queue.h @@ -0,0 +1,1667 @@ +/* + FreeRTOS V7.5.2 - Copyright (C) 2013 Real Time Engineers Ltd. + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that has become a de facto standard. * + * * + * Help yourself get started quickly and support the FreeRTOS * + * project by purchasing a FreeRTOS tutorial book, reference * + * manual, or both from: http://www.FreeRTOS.org/Documentation * + * * + * Thank you! * + * * + *************************************************************************** + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + >>! NOTE: The modification to the GPL is included to allow you to distribute + >>! a combined work that includes FreeRTOS without being obliged to provide + >>! the source code for proprietary components outside of the FreeRTOS + >>! kernel. + + FreeRTOS 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. Full license text is available from the following + link: http://www.freertos.org/a00114.html + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + + +#ifndef QUEUE_H +#define QUEUE_H + +#ifndef INC_FREERTOS_H + #error "include FreeRTOS.h" must appear in source files before "include queue.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * Type by which queues are referenced. For example, a call to xQueueCreate() + * returns an xQueueHandle variable that can then be used as a parameter to + * xQueueSend(), xQueueReceive(), etc. + */ +typedef void * xQueueHandle; + +/** + * Type by which queue sets are referenced. For example, a call to + * xQueueCreateSet() returns an xQueueSet variable that can then be used as a + * parameter to xQueueSelectFromSet(), xQueueAddToSet(), etc. + */ +typedef void * xQueueSetHandle; + +/** + * Queue sets can contain both queues and semaphores, so the + * xQueueSetMemberHandle is defined as a type to be used where a parameter or + * return value can be either an xQueueHandle or an xSemaphoreHandle. + */ +typedef void * xQueueSetMemberHandle; + +/* For internal use only. */ +#define queueSEND_TO_BACK ( ( portBASE_TYPE ) 0 ) +#define queueSEND_TO_FRONT ( ( portBASE_TYPE ) 1 ) +#define queueOVERWRITE ( ( portBASE_TYPE ) 2 ) + +/* For internal use only. These definitions *must* match those in queue.c. */ +#define queueQUEUE_TYPE_BASE ( ( unsigned char ) 0U ) +#define queueQUEUE_TYPE_SET ( ( unsigned char ) 0U ) +#define queueQUEUE_TYPE_MUTEX ( ( unsigned char ) 1U ) +#define queueQUEUE_TYPE_COUNTING_SEMAPHORE ( ( unsigned char ) 2U ) +#define queueQUEUE_TYPE_BINARY_SEMAPHORE ( ( unsigned char ) 3U ) +#define queueQUEUE_TYPE_RECURSIVE_MUTEX ( ( unsigned char ) 4U ) + +/** + * queue. h + *
+ xQueueHandle xQueueCreate(
+							  unsigned portBASE_TYPE uxQueueLength,
+							  unsigned portBASE_TYPE uxItemSize
+						  );
+ * 
+ * + * Creates a new queue instance. This allocates the storage required by the + * new queue and returns a handle for the queue. + * + * @param uxQueueLength The maximum number of items that the queue can contain. + * + * @param uxItemSize The number of bytes each item in the queue will require. + * Items are queued by copy, not by reference, so this is the number of bytes + * that will be copied for each posted item. Each item on the queue must be + * the same size. + * + * @return If the queue is successfully create then a handle to the newly + * created queue is returned. If the queue cannot be created then 0 is + * returned. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ };
+
+ void vATask( void *pvParameters )
+ {
+ xQueueHandle xQueue1, xQueue2;
+
+	// Create a queue capable of containing 10 unsigned long values.
+	xQueue1 = xQueueCreate( 10, sizeof( unsigned long ) );
+	if( xQueue1 == 0 )
+	{
+		// Queue was not created and must not be used.
+	}
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+	if( xQueue2 == 0 )
+	{
+		// Queue was not created and must not be used.
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueCreate xQueueCreate + * \ingroup QueueManagement + */ +#define xQueueCreate( uxQueueLength, uxItemSize ) xQueueGenericCreate( uxQueueLength, uxItemSize, queueQUEUE_TYPE_BASE ) + +/** + * queue. h + *
+ portBASE_TYPE xQueueSendToToFront(
+								   xQueueHandle	xQueue,
+								   const void	*	pvItemToQueue,
+								   portTickType	xTicksToWait
+							   );
+ * 
+ * + * This is a macro that calls xQueueGenericSend(). + * + * Post an item to the front of a queue. The item is queued by copy, not by + * reference. This function must not be called from an interrupt service + * routine. See xQueueSendFromISR () for an alternative which may be used + * in an ISR. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for space to become available on the queue, should it already + * be full. The call will return immediately if this is set to 0 and the + * queue is full. The time is defined in tick periods so the constant + * portTICK_RATE_MS should be used to convert to real time if this is required. + * + * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ } xMessage;
+
+ unsigned long ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ xQueueHandle xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+	// Create a queue capable of containing 10 unsigned long values.
+	xQueue1 = xQueueCreate( 10, sizeof( unsigned long ) );
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+	// ...
+
+	if( xQueue1 != 0 )
+	{
+		// Send an unsigned long.  Wait for 10 ticks for space to become
+		// available if necessary.
+		if( xQueueSendToFront( xQueue1, ( void * ) &ulVar, ( portTickType ) 10 ) != pdPASS )
+		{
+			// Failed to post the message, even after 10 ticks.
+		}
+	}
+
+	if( xQueue2 != 0 )
+	{
+		// Send a pointer to a struct AMessage object.  Don't block if the
+		// queue is already full.
+		pxMessage = & xMessage;
+		xQueueSendToFront( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0 );
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueSend xQueueSend + * \ingroup QueueManagement + */ +#define xQueueSendToFront( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_FRONT ) + +/** + * queue. h + *
+ portBASE_TYPE xQueueSendToBack(
+								   xQueueHandle	xQueue,
+								   const	void	*	pvItemToQueue,
+								   portTickType	xTicksToWait
+							   );
+ * 
+ * + * This is a macro that calls xQueueGenericSend(). + * + * Post an item to the back of a queue. The item is queued by copy, not by + * reference. This function must not be called from an interrupt service + * routine. See xQueueSendFromISR () for an alternative which may be used + * in an ISR. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for space to become available on the queue, should it already + * be full. The call will return immediately if this is set to 0 and the queue + * is full. The time is defined in tick periods so the constant + * portTICK_RATE_MS should be used to convert to real time if this is required. + * + * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ } xMessage;
+
+ unsigned long ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ xQueueHandle xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+	// Create a queue capable of containing 10 unsigned long values.
+	xQueue1 = xQueueCreate( 10, sizeof( unsigned long ) );
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+	// ...
+
+	if( xQueue1 != 0 )
+	{
+		// Send an unsigned long.  Wait for 10 ticks for space to become
+		// available if necessary.
+		if( xQueueSendToBack( xQueue1, ( void * ) &ulVar, ( portTickType ) 10 ) != pdPASS )
+		{
+			// Failed to post the message, even after 10 ticks.
+		}
+	}
+
+	if( xQueue2 != 0 )
+	{
+		// Send a pointer to a struct AMessage object.  Don't block if the
+		// queue is already full.
+		pxMessage = & xMessage;
+		xQueueSendToBack( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0 );
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueSend xQueueSend + * \ingroup QueueManagement + */ +#define xQueueSendToBack( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK ) + +/** + * queue. h + *
+ portBASE_TYPE xQueueSend(
+							  xQueueHandle xQueue,
+							  const void * pvItemToQueue,
+							  portTickType xTicksToWait
+						 );
+ * 
+ * + * This is a macro that calls xQueueGenericSend(). It is included for + * backward compatibility with versions of FreeRTOS.org that did not + * include the xQueueSendToFront() and xQueueSendToBack() macros. It is + * equivalent to xQueueSendToBack(). + * + * Post an item on a queue. The item is queued by copy, not by reference. + * This function must not be called from an interrupt service routine. + * See xQueueSendFromISR () for an alternative which may be used in an ISR. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for space to become available on the queue, should it already + * be full. The call will return immediately if this is set to 0 and the + * queue is full. The time is defined in tick periods so the constant + * portTICK_RATE_MS should be used to convert to real time if this is required. + * + * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ } xMessage;
+
+ unsigned long ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ xQueueHandle xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+	// Create a queue capable of containing 10 unsigned long values.
+	xQueue1 = xQueueCreate( 10, sizeof( unsigned long ) );
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+	// ...
+
+	if( xQueue1 != 0 )
+	{
+		// Send an unsigned long.  Wait for 10 ticks for space to become
+		// available if necessary.
+		if( xQueueSend( xQueue1, ( void * ) &ulVar, ( portTickType ) 10 ) != pdPASS )
+		{
+			// Failed to post the message, even after 10 ticks.
+		}
+	}
+
+	if( xQueue2 != 0 )
+	{
+		// Send a pointer to a struct AMessage object.  Don't block if the
+		// queue is already full.
+		pxMessage = & xMessage;
+		xQueueSend( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0 );
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueSend xQueueSend + * \ingroup QueueManagement + */ +#define xQueueSend( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK ) + +/** + * queue. h + *
+ portBASE_TYPE xQueueOverwrite(
+							  xQueueHandle xQueue,
+							  const void * pvItemToQueue
+						 );
+ * 
+ * + * Only for use with queues that have a length of one - so the queue is either + * empty or full. + * + * Post an item on a queue. If the queue is already full then overwrite the + * value held in the queue. The item is queued by copy, not by reference. + * + * This function must not be called from an interrupt service routine. + * See xQueueOverwriteFromISR () for an alternative which may be used in an ISR. + * + * @param xQueue The handle of the queue to which the data is being sent. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @return xQueueOverwrite() is a macro that calls xQueueGenericSend(), and + * therefore has the same return values as xQueueSendToFront(). However, pdPASS + * is the only value that can be returned because xQueueOverwrite() will write + * to the queue even when the queue is already full. + * + * Example usage: +
+
+ void vFunction( void *pvParameters )
+ {
+ xQueueHandle xQueue;
+ unsigned long ulVarToSend, ulValReceived;
+
+	// Create a queue to hold one unsigned long value.  It is strongly
+	// recommended *not* to use xQueueOverwrite() on queues that can
+	// contain more than one value, and doing so will trigger an assertion
+	// if configASSERT() is defined.
+	xQueue = xQueueCreate( 1, sizeof( unsigned long ) );
+
+	// Write the value 10 to the queue using xQueueOverwrite().
+	ulVarToSend = 10;
+	xQueueOverwrite( xQueue, &ulVarToSend );
+
+	// Peeking the queue should now return 10, but leave the value 10 in
+	// the queue.  A block time of zero is used as it is known that the
+	// queue holds a value.
+	ulValReceived = 0;
+	xQueuePeek( xQueue, &ulValReceived, 0 );
+
+	if( ulValReceived != 10 )
+	{
+		// Error unless the item was removed by a different task.
+	}
+
+	// The queue is still full.  Use xQueueOverwrite() to overwrite the
+	// value held in the queue with 100.
+	ulVarToSend = 100;
+	xQueueOverwrite( xQueue, &ulVarToSend );
+
+	// This time read from the queue, leaving the queue empty once more.
+	// A block time of 0 is used again.
+	xQueueReceive( xQueue, &ulValReceived, 0 );
+
+	// The value read should be the last value written, even though the
+	// queue was already full when the value was written.
+	if( ulValReceived != 100 )
+	{
+		// Error!
+	}
+
+	// ...
+}
+ 
+ * \defgroup xQueueOverwrite xQueueOverwrite + * \ingroup QueueManagement + */ +#define xQueueOverwrite( xQueue, pvItemToQueue ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), 0, queueOVERWRITE ) + + +/** + * queue. h + *
+ portBASE_TYPE xQueueGenericSend(
+									xQueueHandle xQueue,
+									const void * pvItemToQueue,
+									portTickType xTicksToWait
+									portBASE_TYPE xCopyPosition
+								);
+ * 
+ * + * It is preferred that the macros xQueueSend(), xQueueSendToFront() and + * xQueueSendToBack() are used in place of calling this function directly. + * + * Post an item on a queue. The item is queued by copy, not by reference. + * This function must not be called from an interrupt service routine. + * See xQueueSendFromISR () for an alternative which may be used in an ISR. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for space to become available on the queue, should it already + * be full. The call will return immediately if this is set to 0 and the + * queue is full. The time is defined in tick periods so the constant + * portTICK_RATE_MS should be used to convert to real time if this is required. + * + * @param xCopyPosition Can take the value queueSEND_TO_BACK to place the + * item at the back of the queue, or queueSEND_TO_FRONT to place the item + * at the front of the queue (for high priority messages). + * + * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ } xMessage;
+
+ unsigned long ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ xQueueHandle xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+	// Create a queue capable of containing 10 unsigned long values.
+	xQueue1 = xQueueCreate( 10, sizeof( unsigned long ) );
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+	// ...
+
+	if( xQueue1 != 0 )
+	{
+		// Send an unsigned long.  Wait for 10 ticks for space to become
+		// available if necessary.
+		if( xQueueGenericSend( xQueue1, ( void * ) &ulVar, ( portTickType ) 10, queueSEND_TO_BACK ) != pdPASS )
+		{
+			// Failed to post the message, even after 10 ticks.
+		}
+	}
+
+	if( xQueue2 != 0 )
+	{
+		// Send a pointer to a struct AMessage object.  Don't block if the
+		// queue is already full.
+		pxMessage = & xMessage;
+		xQueueGenericSend( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0, queueSEND_TO_BACK );
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueSend xQueueSend + * \ingroup QueueManagement + */ +signed portBASE_TYPE xQueueGenericSend( xQueueHandle xQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ) PRIVILEGED_FUNCTION; + +/** + * queue. h + *
+ portBASE_TYPE xQueuePeek(
+							 xQueueHandle xQueue,
+							 void *pvBuffer,
+							 portTickType xTicksToWait
+						 );
+ * + * This is a macro that calls the xQueueGenericReceive() function. + * + * Receive an item from a queue without removing the item from the queue. + * The item is received by copy so a buffer of adequate size must be + * provided. The number of bytes copied into the buffer was defined when + * the queue was created. + * + * Successfully received items remain on the queue so will be returned again + * by the next call, or a call to xQueueReceive(). + * + * This macro must not be used in an interrupt service routine. See + * xQueuePeekFromISR() for an alternative that can be called from an interrupt + * service routine. + * + * @param xQueue The handle to the queue from which the item is to be + * received. + * + * @param pvBuffer Pointer to the buffer into which the received item will + * be copied. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for an item to receive should the queue be empty at the time + * of the call. The time is defined in tick periods so the constant + * portTICK_RATE_MS should be used to convert to real time if this is required. + * xQueuePeek() will return immediately if xTicksToWait is 0 and the queue + * is empty. + * + * @return pdTRUE if an item was successfully received from the queue, + * otherwise pdFALSE. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ } xMessage;
+
+ xQueueHandle xQueue;
+
+ // Task to create a queue and post a value.
+ void vATask( void *pvParameters )
+ {
+ struct AMessage *pxMessage;
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
+	if( xQueue == 0 )
+	{
+		// Failed to create the queue.
+	}
+
+	// ...
+
+	// Send a pointer to a struct AMessage object.  Don't block if the
+	// queue is already full.
+	pxMessage = & xMessage;
+	xQueueSend( xQueue, ( void * ) &pxMessage, ( portTickType ) 0 );
+
+	// ... Rest of task code.
+ }
+
+ // Task to peek the data from the queue.
+ void vADifferentTask( void *pvParameters )
+ {
+ struct AMessage *pxRxedMessage;
+
+	if( xQueue != 0 )
+	{
+		// Peek a message on the created queue.  Block for 10 ticks if a
+		// message is not immediately available.
+		if( xQueuePeek( xQueue, &( pxRxedMessage ), ( portTickType ) 10 ) )
+		{
+			// pcRxedMessage now points to the struct AMessage variable posted
+			// by vATask, but the item still remains on the queue.
+		}
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueReceive xQueueReceive + * \ingroup QueueManagement + */ +#define xQueuePeek( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdTRUE ) + +/** + * queue. h + *
+ portBASE_TYPE xQueuePeekFromISR(
+									xQueueHandle xQueue,
+									void *pvBuffer,
+								);
+ * + * A version of xQueuePeek() that can be called from an interrupt service + * routine (ISR). + * + * Receive an item from a queue without removing the item from the queue. + * The item is received by copy so a buffer of adequate size must be + * provided. The number of bytes copied into the buffer was defined when + * the queue was created. + * + * Successfully received items remain on the queue so will be returned again + * by the next call, or a call to xQueueReceive(). + * + * @param xQueue The handle to the queue from which the item is to be + * received. + * + * @param pvBuffer Pointer to the buffer into which the received item will + * be copied. + * + * @return pdTRUE if an item was successfully received from the queue, + * otherwise pdFALSE. + * + * \defgroup xQueuePeekFromISR xQueuePeekFromISR + * \ingroup QueueManagement + */ +signed portBASE_TYPE xQueuePeekFromISR( xQueueHandle xQueue, const void * const pvBuffer ) PRIVILEGED_FUNCTION; + +/** + * queue. h + *
+ portBASE_TYPE xQueueReceive(
+								 xQueueHandle xQueue,
+								 void *pvBuffer,
+								 portTickType xTicksToWait
+							);
+ * + * This is a macro that calls the xQueueGenericReceive() function. + * + * Receive an item from a queue. The item is received by copy so a buffer of + * adequate size must be provided. The number of bytes copied into the buffer + * was defined when the queue was created. + * + * Successfully received items are removed from the queue. + * + * This function must not be used in an interrupt service routine. See + * xQueueReceiveFromISR for an alternative that can. + * + * @param xQueue The handle to the queue from which the item is to be + * received. + * + * @param pvBuffer Pointer to the buffer into which the received item will + * be copied. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for an item to receive should the queue be empty at the time + * of the call. xQueueReceive() will return immediately if xTicksToWait + * is zero and the queue is empty. The time is defined in tick periods so the + * constant portTICK_RATE_MS should be used to convert to real time if this is + * required. + * + * @return pdTRUE if an item was successfully received from the queue, + * otherwise pdFALSE. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ } xMessage;
+
+ xQueueHandle xQueue;
+
+ // Task to create a queue and post a value.
+ void vATask( void *pvParameters )
+ {
+ struct AMessage *pxMessage;
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
+	if( xQueue == 0 )
+	{
+		// Failed to create the queue.
+	}
+
+	// ...
+
+	// Send a pointer to a struct AMessage object.  Don't block if the
+	// queue is already full.
+	pxMessage = & xMessage;
+	xQueueSend( xQueue, ( void * ) &pxMessage, ( portTickType ) 0 );
+
+	// ... Rest of task code.
+ }
+
+ // Task to receive from the queue.
+ void vADifferentTask( void *pvParameters )
+ {
+ struct AMessage *pxRxedMessage;
+
+	if( xQueue != 0 )
+	{
+		// Receive a message on the created queue.  Block for 10 ticks if a
+		// message is not immediately available.
+		if( xQueueReceive( xQueue, &( pxRxedMessage ), ( portTickType ) 10 ) )
+		{
+			// pcRxedMessage now points to the struct AMessage variable posted
+			// by vATask.
+		}
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueReceive xQueueReceive + * \ingroup QueueManagement + */ +#define xQueueReceive( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdFALSE ) + + +/** + * queue. h + *
+ portBASE_TYPE xQueueGenericReceive(
+									   xQueueHandle	xQueue,
+									   void	*pvBuffer,
+									   portTickType	xTicksToWait
+									   portBASE_TYPE	xJustPeek
+									);
+ * + * It is preferred that the macro xQueueReceive() be used rather than calling + * this function directly. + * + * Receive an item from a queue. The item is received by copy so a buffer of + * adequate size must be provided. The number of bytes copied into the buffer + * was defined when the queue was created. + * + * This function must not be used in an interrupt service routine. See + * xQueueReceiveFromISR for an alternative that can. + * + * @param xQueue The handle to the queue from which the item is to be + * received. + * + * @param pvBuffer Pointer to the buffer into which the received item will + * be copied. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for an item to receive should the queue be empty at the time + * of the call. The time is defined in tick periods so the constant + * portTICK_RATE_MS should be used to convert to real time if this is required. + * xQueueGenericReceive() will return immediately if the queue is empty and + * xTicksToWait is 0. + * + * @param xJustPeek When set to true, the item received from the queue is not + * actually removed from the queue - meaning a subsequent call to + * xQueueReceive() will return the same item. When set to false, the item + * being received from the queue is also removed from the queue. + * + * @return pdTRUE if an item was successfully received from the queue, + * otherwise pdFALSE. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ } xMessage;
+
+ xQueueHandle xQueue;
+
+ // Task to create a queue and post a value.
+ void vATask( void *pvParameters )
+ {
+ struct AMessage *pxMessage;
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
+	if( xQueue == 0 )
+	{
+		// Failed to create the queue.
+	}
+
+	// ...
+
+	// Send a pointer to a struct AMessage object.  Don't block if the
+	// queue is already full.
+	pxMessage = & xMessage;
+	xQueueSend( xQueue, ( void * ) &pxMessage, ( portTickType ) 0 );
+
+	// ... Rest of task code.
+ }
+
+ // Task to receive from the queue.
+ void vADifferentTask( void *pvParameters )
+ {
+ struct AMessage *pxRxedMessage;
+
+	if( xQueue != 0 )
+	{
+		// Receive a message on the created queue.  Block for 10 ticks if a
+		// message is not immediately available.
+		if( xQueueGenericReceive( xQueue, &( pxRxedMessage ), ( portTickType ) 10 ) )
+		{
+			// pcRxedMessage now points to the struct AMessage variable posted
+			// by vATask.
+		}
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueReceive xQueueReceive + * \ingroup QueueManagement + */ +signed portBASE_TYPE xQueueGenericReceive( xQueueHandle xQueue, const void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeek ) PRIVILEGED_FUNCTION; + +/** + * queue. h + *
unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle xQueue );
+ * + * Return the number of messages stored in a queue. + * + * @param xQueue A handle to the queue being queried. + * + * @return The number of messages available in the queue. + * + * \defgroup uxQueueMessagesWaiting uxQueueMessagesWaiting + * \ingroup QueueManagement + */ +unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle xQueue ) PRIVILEGED_FUNCTION; + +/** + * queue. h + *
void vQueueDelete( xQueueHandle xQueue );
+ * + * Delete a queue - freeing all the memory allocated for storing of items + * placed on the queue. + * + * @param xQueue A handle to the queue to be deleted. + * + * \defgroup vQueueDelete vQueueDelete + * \ingroup QueueManagement + */ +void vQueueDelete( xQueueHandle xQueue ) PRIVILEGED_FUNCTION; + +/** + * queue. h + *
+ portBASE_TYPE xQueueSendToFrontFromISR(
+										 xQueueHandle xQueue,
+										 const void *pvItemToQueue,
+										 portBASE_TYPE *pxHigherPriorityTaskWoken
+									  );
+ 
+ * + * This is a macro that calls xQueueGenericSendFromISR(). + * + * Post an item to the front of a queue. It is safe to use this macro from + * within an interrupt service routine. + * + * Items are queued by copy not reference so it is preferable to only + * queue small items, especially when called from an ISR. In most cases + * it would be preferable to store a pointer to the item being queued. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param pxHigherPriorityTaskWoken xQueueSendToFrontFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task + * to unblock, and the unblocked task has a priority higher than the currently + * running task. If xQueueSendToFromFromISR() sets this value to pdTRUE then + * a context switch should be requested before the interrupt is exited. + * + * @return pdTRUE if the data was successfully sent to the queue, otherwise + * errQUEUE_FULL. + * + * Example usage for buffered IO (where the ISR can obtain more than one value + * per call): +
+ void vBufferISR( void )
+ {
+ char cIn;
+ portBASE_TYPE xHigherPrioritTaskWoken;
+
+	// We have not woken a task at the start of the ISR.
+	xHigherPriorityTaskWoken = pdFALSE;
+
+	// Loop until the buffer is empty.
+	do
+	{
+		// Obtain a byte from the buffer.
+		cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
+
+		// Post the byte.
+		xQueueSendToFrontFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWoken );
+
+	} while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+	// Now the buffer is empty we can switch context if necessary.
+	if( xHigherPriorityTaskWoken )
+	{
+		taskYIELD ();
+	}
+ }
+ 
+ * + * \defgroup xQueueSendFromISR xQueueSendFromISR + * \ingroup QueueManagement + */ +#define xQueueSendToFrontFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_FRONT ) + + +/** + * queue. h + *
+ portBASE_TYPE xQueueSendToBackFromISR(
+										 xQueueHandle xQueue,
+										 const void *pvItemToQueue,
+										 portBASE_TYPE *pxHigherPriorityTaskWoken
+									  );
+ 
+ * + * This is a macro that calls xQueueGenericSendFromISR(). + * + * Post an item to the back of a queue. It is safe to use this macro from + * within an interrupt service routine. + * + * Items are queued by copy not reference so it is preferable to only + * queue small items, especially when called from an ISR. In most cases + * it would be preferable to store a pointer to the item being queued. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param pxHigherPriorityTaskWoken xQueueSendToBackFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task + * to unblock, and the unblocked task has a priority higher than the currently + * running task. If xQueueSendToBackFromISR() sets this value to pdTRUE then + * a context switch should be requested before the interrupt is exited. + * + * @return pdTRUE if the data was successfully sent to the queue, otherwise + * errQUEUE_FULL. + * + * Example usage for buffered IO (where the ISR can obtain more than one value + * per call): +
+ void vBufferISR( void )
+ {
+ char cIn;
+ portBASE_TYPE xHigherPriorityTaskWoken;
+
+	// We have not woken a task at the start of the ISR.
+	xHigherPriorityTaskWoken = pdFALSE;
+
+	// Loop until the buffer is empty.
+	do
+	{
+		// Obtain a byte from the buffer.
+		cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
+
+		// Post the byte.
+		xQueueSendToBackFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWoken );
+
+	} while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+	// Now the buffer is empty we can switch context if necessary.
+	if( xHigherPriorityTaskWoken )
+	{
+		taskYIELD ();
+	}
+ }
+ 
+ * + * \defgroup xQueueSendFromISR xQueueSendFromISR + * \ingroup QueueManagement + */ +#define xQueueSendToBackFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK ) + +/** + * queue. h + *
+ portBASE_TYPE xQueueOverwriteFromISR(
+							  xQueueHandle xQueue,
+							  const void * pvItemToQueue,
+							  portBASE_TYPE *pxHigherPriorityTaskWoken
+						 );
+ * 
+ * + * A version of xQueueOverwrite() that can be used in an interrupt service + * routine (ISR). + * + * Only for use with queues that can hold a single item - so the queue is either + * empty or full. + * + * Post an item on a queue. If the queue is already full then overwrite the + * value held in the queue. The item is queued by copy, not by reference. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param pxHigherPriorityTaskWoken xQueueOverwriteFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task + * to unblock, and the unblocked task has a priority higher than the currently + * running task. If xQueueOverwriteFromISR() sets this value to pdTRUE then + * a context switch should be requested before the interrupt is exited. + * + * @return xQueueOverwriteFromISR() is a macro that calls + * xQueueGenericSendFromISR(), and therefore has the same return values as + * xQueueSendToFrontFromISR(). However, pdPASS is the only value that can be + * returned because xQueueOverwriteFromISR() will write to the queue even when + * the queue is already full. + * + * Example usage: +
+
+ xQueueHandle xQueue;
+ 
+ void vFunction( void *pvParameters )
+ {
+ 	// Create a queue to hold one unsigned long value.  It is strongly
+	// recommended *not* to use xQueueOverwriteFromISR() on queues that can
+	// contain more than one value, and doing so will trigger an assertion
+	// if configASSERT() is defined.
+	xQueue = xQueueCreate( 1, sizeof( unsigned long ) );
+}
+
+void vAnInterruptHandler( void )
+{
+// xHigherPriorityTaskWoken must be set to pdFALSE before it is used.
+portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
+unsigned long ulVarToSend, ulValReceived;
+
+	// Write the value 10 to the queue using xQueueOverwriteFromISR().
+	ulVarToSend = 10;
+	xQueueOverwriteFromISR( xQueue, &ulVarToSend, &xHigherPriorityTaskWoken );
+
+	// The queue is full, but calling xQueueOverwriteFromISR() again will still
+	// pass because the value held in the queue will be overwritten with the
+	// new value.
+	ulVarToSend = 100;
+	xQueueOverwriteFromISR( xQueue, &ulVarToSend, &xHigherPriorityTaskWoken );
+
+	// Reading from the queue will now return 100.
+
+	// ...
+	
+	if( xHigherPrioritytaskWoken == pdTRUE )
+	{
+		// Writing to the queue caused a task to unblock and the unblocked task
+		// has a priority higher than or equal to the priority of the currently
+		// executing task (the task this interrupt interrupted).  Perform a context
+		// switch so this interrupt returns directly to the unblocked task.
+		portYIELD_FROM_ISR(); // or portEND_SWITCHING_ISR() depending on the port.
+	}
+}
+ 
+ * \defgroup xQueueOverwriteFromISR xQueueOverwriteFromISR + * \ingroup QueueManagement + */ +#define xQueueOverwriteFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueOVERWRITE ) + +/** + * queue. h + *
+ portBASE_TYPE xQueueSendFromISR(
+									 xQueueHandle xQueue,
+									 const void *pvItemToQueue,
+									 portBASE_TYPE *pxHigherPriorityTaskWoken
+								);
+ 
+ * + * This is a macro that calls xQueueGenericSendFromISR(). It is included + * for backward compatibility with versions of FreeRTOS.org that did not + * include the xQueueSendToBackFromISR() and xQueueSendToFrontFromISR() + * macros. + * + * Post an item to the back of a queue. It is safe to use this function from + * within an interrupt service routine. + * + * Items are queued by copy not reference so it is preferable to only + * queue small items, especially when called from an ISR. In most cases + * it would be preferable to store a pointer to the item being queued. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param pxHigherPriorityTaskWoken xQueueSendFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task + * to unblock, and the unblocked task has a priority higher than the currently + * running task. If xQueueSendFromISR() sets this value to pdTRUE then + * a context switch should be requested before the interrupt is exited. + * + * @return pdTRUE if the data was successfully sent to the queue, otherwise + * errQUEUE_FULL. + * + * Example usage for buffered IO (where the ISR can obtain more than one value + * per call): +
+ void vBufferISR( void )
+ {
+ char cIn;
+ portBASE_TYPE xHigherPriorityTaskWoken;
+
+	// We have not woken a task at the start of the ISR.
+	xHigherPriorityTaskWoken = pdFALSE;
+
+	// Loop until the buffer is empty.
+	do
+	{
+		// Obtain a byte from the buffer.
+		cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
+
+		// Post the byte.
+		xQueueSendFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWoken );
+
+	} while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+	// Now the buffer is empty we can switch context if necessary.
+	if( xHigherPriorityTaskWoken )
+	{
+		// Actual macro used here is port specific.
+		taskYIELD_FROM_ISR ();
+	}
+ }
+ 
+ * + * \defgroup xQueueSendFromISR xQueueSendFromISR + * \ingroup QueueManagement + */ +#define xQueueSendFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK ) + +/** + * queue. h + *
+ portBASE_TYPE xQueueGenericSendFromISR(
+										   xQueueHandle		xQueue,
+										   const	void	*pvItemToQueue,
+										   portBASE_TYPE	*pxHigherPriorityTaskWoken,
+										   portBASE_TYPE	xCopyPosition
+									   );
+ 
+ * + * It is preferred that the macros xQueueSendFromISR(), + * xQueueSendToFrontFromISR() and xQueueSendToBackFromISR() be used in place + * of calling this function directly. + * + * Post an item on a queue. It is safe to use this function from within an + * interrupt service routine. + * + * Items are queued by copy not reference so it is preferable to only + * queue small items, especially when called from an ISR. In most cases + * it would be preferable to store a pointer to the item being queued. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param pxHigherPriorityTaskWoken xQueueGenericSendFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task + * to unblock, and the unblocked task has a priority higher than the currently + * running task. If xQueueGenericSendFromISR() sets this value to pdTRUE then + * a context switch should be requested before the interrupt is exited. + * + * @param xCopyPosition Can take the value queueSEND_TO_BACK to place the + * item at the back of the queue, or queueSEND_TO_FRONT to place the item + * at the front of the queue (for high priority messages). + * + * @return pdTRUE if the data was successfully sent to the queue, otherwise + * errQUEUE_FULL. + * + * Example usage for buffered IO (where the ISR can obtain more than one value + * per call): +
+ void vBufferISR( void )
+ {
+ char cIn;
+ portBASE_TYPE xHigherPriorityTaskWokenByPost;
+
+	// We have not woken a task at the start of the ISR.
+	xHigherPriorityTaskWokenByPost = pdFALSE;
+
+	// Loop until the buffer is empty.
+	do
+	{
+		// Obtain a byte from the buffer.
+		cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
+
+		// Post each byte.
+		xQueueGenericSendFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWokenByPost, queueSEND_TO_BACK );
+
+	} while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+	// Now the buffer is empty we can switch context if necessary.  Note that the
+	// name of the yield function required is port specific.
+	if( xHigherPriorityTaskWokenByPost )
+	{
+		taskYIELD_YIELD_FROM_ISR();
+	}
+ }
+ 
+ * + * \defgroup xQueueSendFromISR xQueueSendFromISR + * \ingroup QueueManagement + */ +signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle xQueue, const void * const pvItemToQueue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portBASE_TYPE xCopyPosition ) PRIVILEGED_FUNCTION; + +/** + * queue. h + *
+ portBASE_TYPE xQueueReceiveFromISR(
+									   xQueueHandle	xQueue,
+									   void	*pvBuffer,
+									   portBASE_TYPE *pxTaskWoken
+								   );
+ * 
+ * + * Receive an item from a queue. It is safe to use this function from within an + * interrupt service routine. + * + * @param xQueue The handle to the queue from which the item is to be + * received. + * + * @param pvBuffer Pointer to the buffer into which the received item will + * be copied. + * + * @param pxTaskWoken A task may be blocked waiting for space to become + * available on the queue. If xQueueReceiveFromISR causes such a task to + * unblock *pxTaskWoken will get set to pdTRUE, otherwise *pxTaskWoken will + * remain unchanged. + * + * @return pdTRUE if an item was successfully received from the queue, + * otherwise pdFALSE. + * + * Example usage: +
+
+ xQueueHandle xQueue;
+
+ // Function to create a queue and post some values.
+ void vAFunction( void *pvParameters )
+ {
+ char cValueToPost;
+ const portTickType xBlockTime = ( portTickType )0xff;
+
+	// Create a queue capable of containing 10 characters.
+	xQueue = xQueueCreate( 10, sizeof( char ) );
+	if( xQueue == 0 )
+	{
+		// Failed to create the queue.
+	}
+
+	// ...
+
+	// Post some characters that will be used within an ISR.  If the queue
+	// is full then this task will block for xBlockTime ticks.
+	cValueToPost = 'a';
+	xQueueSend( xQueue, ( void * ) &cValueToPost, xBlockTime );
+	cValueToPost = 'b';
+	xQueueSend( xQueue, ( void * ) &cValueToPost, xBlockTime );
+
+	// ... keep posting characters ... this task may block when the queue
+	// becomes full.
+
+	cValueToPost = 'c';
+	xQueueSend( xQueue, ( void * ) &cValueToPost, xBlockTime );
+ }
+
+ // ISR that outputs all the characters received on the queue.
+ void vISR_Routine( void )
+ {
+ portBASE_TYPE xTaskWokenByReceive = pdFALSE;
+ char cRxedChar;
+
+	while( xQueueReceiveFromISR( xQueue, ( void * ) &cRxedChar, &xTaskWokenByReceive) )
+	{
+		// A character was received.  Output the character now.
+		vOutputCharacter( cRxedChar );
+
+		// If removing the character from the queue woke the task that was
+		// posting onto the queue cTaskWokenByReceive will have been set to
+		// pdTRUE.  No matter how many times this loop iterates only one
+		// task will be woken.
+	}
+
+	if( cTaskWokenByPost != ( char ) pdFALSE;
+	{
+		taskYIELD ();
+	}
+ }
+ 
+ * \defgroup xQueueReceiveFromISR xQueueReceiveFromISR + * \ingroup QueueManagement + */ +signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle xQueue, const void * const pvBuffer, signed portBASE_TYPE *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION; + +/* + * Utilities to query queues that are safe to use from an ISR. These utilities + * should be used only from witin an ISR, or within a critical section. + */ +signed portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle xQueue ) PRIVILEGED_FUNCTION; +signed portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle xQueue ) PRIVILEGED_FUNCTION; +unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle xQueue ) PRIVILEGED_FUNCTION; + + +/* + * xQueueAltGenericSend() is an alternative version of xQueueGenericSend(). + * Likewise xQueueAltGenericReceive() is an alternative version of + * xQueueGenericReceive(). + * + * The source code that implements the alternative (Alt) API is much + * simpler because it executes everything from within a critical section. + * This is the approach taken by many other RTOSes, but FreeRTOS.org has the + * preferred fully featured API too. The fully featured API has more + * complex code that takes longer to execute, but makes much less use of + * critical sections. Therefore the alternative API sacrifices interrupt + * responsiveness to gain execution speed, whereas the fully featured API + * sacrifices execution speed to ensure better interrupt responsiveness. + */ +signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle xQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ); +signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle xQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking ); +#define xQueueAltSendToFront( xQueue, pvItemToQueue, xTicksToWait ) xQueueAltGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_FRONT ) +#define xQueueAltSendToBack( xQueue, pvItemToQueue, xTicksToWait ) xQueueAltGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK ) +#define xQueueAltReceive( xQueue, pvBuffer, xTicksToWait ) xQueueAltGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdFALSE ) +#define xQueueAltPeek( xQueue, pvBuffer, xTicksToWait ) xQueueAltGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdTRUE ) + +/* + * The functions defined above are for passing data to and from tasks. The + * functions below are the equivalents for passing data to and from + * co-routines. + * + * These functions are called from the co-routine macro implementation and + * should not be called directly from application code. Instead use the macro + * wrappers defined within croutine.h. + */ +signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle xQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken ); +signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle xQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken ); +signed portBASE_TYPE xQueueCRSend( xQueueHandle xQueue, const void *pvItemToQueue, portTickType xTicksToWait ); +signed portBASE_TYPE xQueueCRReceive( xQueueHandle xQueue, void *pvBuffer, portTickType xTicksToWait ); + +/* + * For internal use only. Use xSemaphoreCreateMutex(), + * xSemaphoreCreateCounting() or xSemaphoreGetMutexHolder() instead of calling + * these functions directly. + */ +xQueueHandle xQueueCreateMutex( unsigned char ucQueueType ) PRIVILEGED_FUNCTION; +xQueueHandle xQueueCreateCountingSemaphore( unsigned portBASE_TYPE uxCountValue, unsigned portBASE_TYPE uxInitialCount ) PRIVILEGED_FUNCTION; +void* xQueueGetMutexHolder( xQueueHandle xSemaphore ) PRIVILEGED_FUNCTION; + +/* + * For internal use only. Use xSemaphoreTakeMutexRecursive() or + * xSemaphoreGiveMutexRecursive() instead of calling these functions directly. + */ +portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle xMutex, portTickType xBlockTime ) PRIVILEGED_FUNCTION; +portBASE_TYPE xQueueGiveMutexRecursive( xQueueHandle pxMutex ) PRIVILEGED_FUNCTION; + +/* + * Reset a queue back to its original empty state. pdPASS is returned if the + * queue is successfully reset. pdFAIL is returned if the queue could not be + * reset because there are tasks blocked on the queue waiting to either + * receive from the queue or send to the queue. + */ +#define xQueueReset( xQueue ) xQueueGenericReset( xQueue, pdFALSE ) + +/* + * The registry is provided as a means for kernel aware debuggers to + * locate queues, semaphores and mutexes. Call vQueueAddToRegistry() add + * a queue, semaphore or mutex handle to the registry if you want the handle + * to be available to a kernel aware debugger. If you are not using a kernel + * aware debugger then this function can be ignored. + * + * configQUEUE_REGISTRY_SIZE defines the maximum number of handles the + * registry can hold. configQUEUE_REGISTRY_SIZE must be greater than 0 + * within FreeRTOSConfig.h for the registry to be available. Its value + * does not effect the number of queues, semaphores and mutexes that can be + * created - just the number that the registry can hold. + * + * @param xQueue The handle of the queue being added to the registry. This + * is the handle returned by a call to xQueueCreate(). Semaphore and mutex + * handles can also be passed in here. + * + * @param pcName The name to be associated with the handle. This is the + * name that the kernel aware debugger will display. + */ +#if configQUEUE_REGISTRY_SIZE > 0 + void vQueueAddToRegistry( xQueueHandle xQueue, signed char *pcName ) PRIVILEGED_FUNCTION; +#endif + +/* + * The registry is provided as a means for kernel aware debuggers to + * locate queues, semaphores and mutexes. Call vQueueAddToRegistry() add + * a queue, semaphore or mutex handle to the registry if you want the handle + * to be available to a kernel aware debugger, and vQueueUnregisterQueue() to + * remove the queue, semaphore or mutex from the register. If you are not using + * a kernel aware debugger then this function can be ignored. + * + * @param xQueue The handle of the queue being removed from the registry. + */ +#if configQUEUE_REGISTRY_SIZE > 0 + void vQueueUnregisterQueue( xQueueHandle xQueue ) PRIVILEGED_FUNCTION; +#endif + +/* + * Generic version of the queue creation function, which is in turn called by + * any queue, semaphore or mutex creation function or macro. + */ +xQueueHandle xQueueGenericCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize, unsigned char ucQueueType ) PRIVILEGED_FUNCTION; + +/* + * Queue sets provide a mechanism to allow a task to block (pend) on a read + * operation from multiple queues or semaphores simultaneously. + * + * See FreeRTOS/Source/Demo/Common/Minimal/QueueSet.c for an example using this + * function. + * + * A queue set must be explicitly created using a call to xQueueCreateSet() + * before it can be used. Once created, standard FreeRTOS queues and semaphores + * can be added to the set using calls to xQueueAddToSet(). + * xQueueSelectFromSet() is then used to determine which, if any, of the queues + * or semaphores contained in the set is in a state where a queue read or + * semaphore take operation would be successful. + * + * Note 1: See the documentation on http://wwwFreeRTOS.org/RTOS-queue-sets.html + * for reasons why queue sets are very rarely needed in practice as there are + * simpler methods of blocking on multiple objects. + * + * Note 2: Blocking on a queue set that contains a mutex will not cause the + * mutex holder to inherit the priority of the blocked task. + * + * Note 3: An additional 4 bytes of RAM is required for each space in a every + * queue added to a queue set. Therefore counting semaphores that have a high + * maximum count value should not be added to a queue set. + * + * Note 4: A receive (in the case of a queue) or take (in the case of a + * semaphore) operation must not be performed on a member of a queue set unless + * a call to xQueueSelectFromSet() has first returned a handle to that set member. + * + * @param uxEventQueueLength Queue sets store events that occur on + * the queues and semaphores contained in the set. uxEventQueueLength specifies + * the maximum number of events that can be queued at once. To be absolutely + * certain that events are not lost uxEventQueueLength should be set to the + * total sum of the length of the queues added to the set, where binary + * semaphores and mutexes have a length of 1, and counting semaphores have a + * length set by their maximum count value. Examples: + * + If a queue set is to hold a queue of length 5, another queue of length 12, + * and a binary semaphore, then uxEventQueueLength should be set to + * (5 + 12 + 1), or 18. + * + If a queue set is to hold three binary semaphores then uxEventQueueLength + * should be set to (1 + 1 + 1 ), or 3. + * + If a queue set is to hold a counting semaphore that has a maximum count of + * 5, and a counting semaphore that has a maximum count of 3, then + * uxEventQueueLength should be set to (5 + 3), or 8. + * + * @return If the queue set is created successfully then a handle to the created + * queue set is returned. Otherwise NULL is returned. + */ +xQueueSetHandle xQueueCreateSet( unsigned portBASE_TYPE uxEventQueueLength ) PRIVILEGED_FUNCTION; + +/* + * Adds a queue or semaphore to a queue set that was previously created by a + * call to xQueueCreateSet(). + * + * See FreeRTOS/Source/Demo/Common/Minimal/QueueSet.c for an example using this + * function. + * + * Note 1: A receive (in the case of a queue) or take (in the case of a + * semaphore) operation must not be performed on a member of a queue set unless + * a call to xQueueSelectFromSet() has first returned a handle to that set member. + * + * @param xQueueOrSemaphore The handle of the queue or semaphore being added to + * the queue set (cast to an xQueueSetMemberHandle type). + * + * @param xQueueSet The handle of the queue set to which the queue or semaphore + * is being added. + * + * @return If the queue or semaphore was successfully added to the queue set + * then pdPASS is returned. If the queue could not be successfully added to the + * queue set because it is already a member of a different queue set then pdFAIL + * is returned. + */ +portBASE_TYPE xQueueAddToSet( xQueueSetMemberHandle xQueueOrSemaphore, xQueueSetHandle xQueueSet ) PRIVILEGED_FUNCTION; + +/* + * Removes a queue or semaphore from a queue set. A queue or semaphore can only + * be removed from a set if the queue or semaphore is empty. + * + * See FreeRTOS/Source/Demo/Common/Minimal/QueueSet.c for an example using this + * function. + * + * @param xQueueOrSemaphore The handle of the queue or semaphore being removed + * from the queue set (cast to an xQueueSetMemberHandle type). + * + * @param xQueueSet The handle of the queue set in which the queue or semaphore + * is included. + * + * @return If the queue or semaphore was successfully removed from the queue set + * then pdPASS is returned. If the queue was not in the queue set, or the + * queue (or semaphore) was not empty, then pdFAIL is returned. + */ +portBASE_TYPE xQueueRemoveFromSet( xQueueSetMemberHandle xQueueOrSemaphore, xQueueSetHandle xQueueSet ) PRIVILEGED_FUNCTION; + +/* + * xQueueSelectFromSet() selects from the members of a queue set a queue or + * semaphore that either contains data (in the case of a queue) or is available + * to take (in the case of a semaphore). xQueueSelectFromSet() effectively + * allows a task to block (pend) on a read operation on all the queues and + * semaphores in a queue set simultaneously. + * + * See FreeRTOS/Source/Demo/Common/Minimal/QueueSet.c for an example using this + * function. + * + * Note 1: See the documentation on http://wwwFreeRTOS.org/RTOS-queue-sets.html + * for reasons why queue sets are very rarely needed in practice as there are + * simpler methods of blocking on multiple objects. + * + * Note 2: Blocking on a queue set that contains a mutex will not cause the + * mutex holder to inherit the priority of the blocked task. + * + * Note 3: A receive (in the case of a queue) or take (in the case of a + * semaphore) operation must not be performed on a member of a queue set unless + * a call to xQueueSelectFromSet() has first returned a handle to that set member. + * + * @param xQueueSet The queue set on which the task will (potentially) block. + * + * @param xBlockTimeTicks The maximum time, in ticks, that the calling task will + * remain in the Blocked state (with other tasks executing) to wait for a member + * of the queue set to be ready for a successful queue read or semaphore take + * operation. + * + * @return xQueueSelectFromSet() will return the handle of a queue (cast to + * a xQueueSetMemberHandle type) contained in the queue set that contains data, + * or the handle of a semaphore (cast to a xQueueSetMemberHandle type) contained + * in the queue set that is available, or NULL if no such queue or semaphore + * exists before before the specified block time expires. + */ +xQueueSetMemberHandle xQueueSelectFromSet( xQueueSetHandle xQueueSet, portTickType xBlockTimeTicks ) PRIVILEGED_FUNCTION; + +/* + * A version of xQueueSelectFromSet() that can be used from an ISR. + */ +xQueueSetMemberHandle xQueueSelectFromSetFromISR( xQueueSetHandle xQueueSet ) PRIVILEGED_FUNCTION; + +/* Not public API functions. */ +void vQueueWaitForMessageRestricted( xQueueHandle xQueue, portTickType xTicksToWait ) PRIVILEGED_FUNCTION; +portBASE_TYPE xQueueGenericReset( xQueueHandle xQueue, portBASE_TYPE xNewQueue ) PRIVILEGED_FUNCTION; +void vQueueSetQueueNumber( xQueueHandle xQueue, unsigned char ucQueueNumber ) PRIVILEGED_FUNCTION; +unsigned char ucQueueGetQueueNumber( xQueueHandle xQueue ) PRIVILEGED_FUNCTION; +unsigned char ucQueueGetQueueType( xQueueHandle xQueue ) PRIVILEGED_FUNCTION; + + +#ifdef __cplusplus +} +#endif + +#endif /* QUEUE_H */ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/freertos/semphr.h b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/semphr.h new file mode 100644 index 0000000..c1c7f61 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/semphr.h @@ -0,0 +1,785 @@ +/* + FreeRTOS V7.5.2 - Copyright (C) 2013 Real Time Engineers Ltd. + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that has become a de facto standard. * + * * + * Help yourself get started quickly and support the FreeRTOS * + * project by purchasing a FreeRTOS tutorial book, reference * + * manual, or both from: http://www.FreeRTOS.org/Documentation * + * * + * Thank you! * + * * + *************************************************************************** + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + >>! NOTE: The modification to the GPL is included to allow you to distribute + >>! a combined work that includes FreeRTOS without being obliged to provide + >>! the source code for proprietary components outside of the FreeRTOS + >>! kernel. + + FreeRTOS 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. Full license text is available from the following + link: http://www.freertos.org/a00114.html + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef SEMAPHORE_H +#define SEMAPHORE_H + +#ifndef INC_FREERTOS_H + #error "include FreeRTOS.h" must appear in source files before "include semphr.h" +#endif + +#include "queue.h" + +typedef xQueueHandle xSemaphoreHandle; + +#define semBINARY_SEMAPHORE_QUEUE_LENGTH ( ( unsigned char ) 1U ) +#define semSEMAPHORE_QUEUE_ITEM_LENGTH ( ( unsigned char ) 0U ) +#define semGIVE_BLOCK_TIME ( ( portTickType ) 0U ) + + +/** + * semphr. h + *
vSemaphoreCreateBinary( xSemaphoreHandle xSemaphore )
+ * + * Macro that implements a semaphore by using the existing queue mechanism. + * The queue length is 1 as this is a binary semaphore. The data size is 0 + * as we don't want to actually store any data - we just want to know if the + * queue is empty or full. + * + * This type of semaphore can be used for pure synchronisation between tasks or + * between an interrupt and a task. The semaphore need not be given back once + * obtained, so one task/interrupt can continuously 'give' the semaphore while + * another continuously 'takes' the semaphore. For this reason this type of + * semaphore does not use a priority inheritance mechanism. For an alternative + * that does use priority inheritance see xSemaphoreCreateMutex(). + * + * @param xSemaphore Handle to the created semaphore. Should be of type xSemaphoreHandle. + * + * Example usage: +
+ xSemaphoreHandle xSemaphore;
+
+ void vATask( void * pvParameters )
+ {
+    // Semaphore cannot be used before a call to vSemaphoreCreateBinary ().
+    // This is a macro so pass the variable in directly.
+    vSemaphoreCreateBinary( xSemaphore );
+
+    if( xSemaphore != NULL )
+    {
+        // The semaphore was created successfully.
+        // The semaphore can now be used.  
+    }
+ }
+ 
+ * \defgroup vSemaphoreCreateBinary vSemaphoreCreateBinary + * \ingroup Semaphores + */ +#define vSemaphoreCreateBinary( xSemaphore ) \ + { \ + ( xSemaphore ) = xQueueGenericCreate( ( unsigned portBASE_TYPE ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE ); \ + if( ( xSemaphore ) != NULL ) \ + { \ + ( void ) xSemaphoreGive( ( xSemaphore ) ); \ + } \ + } + +/** + * semphr. h + *
xSemaphoreTake( 
+ *                   xSemaphoreHandle xSemaphore, 
+ *                   portTickType xBlockTime 
+ *               )
+ * + * Macro to obtain a semaphore. The semaphore must have previously been + * created with a call to vSemaphoreCreateBinary(), xSemaphoreCreateMutex() or + * xSemaphoreCreateCounting(). + * + * @param xSemaphore A handle to the semaphore being taken - obtained when + * the semaphore was created. + * + * @param xBlockTime The time in ticks to wait for the semaphore to become + * available. The macro portTICK_RATE_MS can be used to convert this to a + * real time. A block time of zero can be used to poll the semaphore. A block + * time of portMAX_DELAY can be used to block indefinitely (provided + * INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h). + * + * @return pdTRUE if the semaphore was obtained. pdFALSE + * if xBlockTime expired without the semaphore becoming available. + * + * Example usage: +
+ xSemaphoreHandle xSemaphore = NULL;
+
+ // A task that creates a semaphore.
+ void vATask( void * pvParameters )
+ {
+    // Create the semaphore to guard a shared resource.
+    vSemaphoreCreateBinary( xSemaphore );
+ }
+
+ // A task that uses the semaphore.
+ void vAnotherTask( void * pvParameters )
+ {
+    // ... Do other things.
+
+    if( xSemaphore != NULL )
+    {
+        // See if we can obtain the semaphore.  If the semaphore is not available
+        // wait 10 ticks to see if it becomes free.	
+        if( xSemaphoreTake( xSemaphore, ( portTickType ) 10 ) == pdTRUE )
+        {
+            // We were able to obtain the semaphore and can now access the
+            // shared resource.
+
+            // ...
+
+            // We have finished accessing the shared resource.  Release the 
+            // semaphore.
+            xSemaphoreGive( xSemaphore );
+        }
+        else
+        {
+            // We could not obtain the semaphore and can therefore not access
+            // the shared resource safely.
+        }
+    }
+ }
+ 
+ * \defgroup xSemaphoreTake xSemaphoreTake + * \ingroup Semaphores + */ +#define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueGenericReceive( ( xQueueHandle ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE ) + +/** + * semphr. h + * xSemaphoreTakeRecursive( + * xSemaphoreHandle xMutex, + * portTickType xBlockTime + * ) + * + * Macro to recursively obtain, or 'take', a mutex type semaphore. + * The mutex must have previously been created using a call to + * xSemaphoreCreateRecursiveMutex(); + * + * configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h for this + * macro to be available. + * + * This macro must not be used on mutexes created using xSemaphoreCreateMutex(). + * + * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex + * doesn't become available again until the owner has called + * xSemaphoreGiveRecursive() for each successful 'take' request. For example, + * if a task successfully 'takes' the same mutex 5 times then the mutex will + * not be available to any other task until it has also 'given' the mutex back + * exactly five times. + * + * @param xMutex A handle to the mutex being obtained. This is the + * handle returned by xSemaphoreCreateRecursiveMutex(); + * + * @param xBlockTime The time in ticks to wait for the semaphore to become + * available. The macro portTICK_RATE_MS can be used to convert this to a + * real time. A block time of zero can be used to poll the semaphore. If + * the task already owns the semaphore then xSemaphoreTakeRecursive() will + * return immediately no matter what the value of xBlockTime. + * + * @return pdTRUE if the semaphore was obtained. pdFALSE if xBlockTime + * expired without the semaphore becoming available. + * + * Example usage: +
+ xSemaphoreHandle xMutex = NULL;
+
+ // A task that creates a mutex.
+ void vATask( void * pvParameters )
+ {
+    // Create the mutex to guard a shared resource.
+    xMutex = xSemaphoreCreateRecursiveMutex();
+ }
+
+ // A task that uses the mutex.
+ void vAnotherTask( void * pvParameters )
+ {
+    // ... Do other things.
+
+    if( xMutex != NULL )
+    {
+        // See if we can obtain the mutex.  If the mutex is not available
+        // wait 10 ticks to see if it becomes free.	
+        if( xSemaphoreTakeRecursive( xSemaphore, ( portTickType ) 10 ) == pdTRUE )
+        {
+            // We were able to obtain the mutex and can now access the
+            // shared resource.
+
+            // ...
+            // For some reason due to the nature of the code further calls to 
+			// xSemaphoreTakeRecursive() are made on the same mutex.  In real
+			// code these would not be just sequential calls as this would make
+			// no sense.  Instead the calls are likely to be buried inside
+			// a more complex call structure.
+            xSemaphoreTakeRecursive( xMutex, ( portTickType ) 10 );
+            xSemaphoreTakeRecursive( xMutex, ( portTickType ) 10 );
+
+            // The mutex has now been 'taken' three times, so will not be 
+			// available to another task until it has also been given back
+			// three times.  Again it is unlikely that real code would have
+			// these calls sequentially, but instead buried in a more complex
+			// call structure.  This is just for illustrative purposes.
+            xSemaphoreGiveRecursive( xMutex );
+			xSemaphoreGiveRecursive( xMutex );
+			xSemaphoreGiveRecursive( xMutex );
+
+			// Now the mutex can be taken by other tasks.
+        }
+        else
+        {
+            // We could not obtain the mutex and can therefore not access
+            // the shared resource safely.
+        }
+    }
+ }
+ 
+ * \defgroup xSemaphoreTakeRecursive xSemaphoreTakeRecursive + * \ingroup Semaphores + */ +#define xSemaphoreTakeRecursive( xMutex, xBlockTime ) xQueueTakeMutexRecursive( ( xMutex ), ( xBlockTime ) ) + + +/* + * xSemaphoreAltTake() is an alternative version of xSemaphoreTake(). + * + * The source code that implements the alternative (Alt) API is much + * simpler because it executes everything from within a critical section. + * This is the approach taken by many other RTOSes, but FreeRTOS.org has the + * preferred fully featured API too. The fully featured API has more + * complex code that takes longer to execute, but makes much less use of + * critical sections. Therefore the alternative API sacrifices interrupt + * responsiveness to gain execution speed, whereas the fully featured API + * sacrifices execution speed to ensure better interrupt responsiveness. + */ +#define xSemaphoreAltTake( xSemaphore, xBlockTime ) xQueueAltGenericReceive( ( xQueueHandle ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE ) + +/** + * semphr. h + *
xSemaphoreGive( xSemaphoreHandle xSemaphore )
+ * + * Macro to release a semaphore. The semaphore must have previously been + * created with a call to vSemaphoreCreateBinary(), xSemaphoreCreateMutex() or + * xSemaphoreCreateCounting(). and obtained using sSemaphoreTake(). + * + * This macro must not be used from an ISR. See xSemaphoreGiveFromISR () for + * an alternative which can be used from an ISR. + * + * This macro must also not be used on semaphores created using + * xSemaphoreCreateRecursiveMutex(). + * + * @param xSemaphore A handle to the semaphore being released. This is the + * handle returned when the semaphore was created. + * + * @return pdTRUE if the semaphore was released. pdFALSE if an error occurred. + * Semaphores are implemented using queues. An error can occur if there is + * no space on the queue to post a message - indicating that the + * semaphore was not first obtained correctly. + * + * Example usage: +
+ xSemaphoreHandle xSemaphore = NULL;
+
+ void vATask( void * pvParameters )
+ {
+    // Create the semaphore to guard a shared resource.
+    vSemaphoreCreateBinary( xSemaphore );
+
+    if( xSemaphore != NULL )
+    {
+        if( xSemaphoreGive( xSemaphore ) != pdTRUE )
+        {
+            // We would expect this call to fail because we cannot give
+            // a semaphore without first "taking" it!
+        }
+
+        // Obtain the semaphore - don't block if the semaphore is not
+        // immediately available.
+        if( xSemaphoreTake( xSemaphore, ( portTickType ) 0 ) )
+        {
+            // We now have the semaphore and can access the shared resource.
+
+            // ...
+
+            // We have finished accessing the shared resource so can free the
+            // semaphore.
+            if( xSemaphoreGive( xSemaphore ) != pdTRUE )
+            {
+                // We would not expect this call to fail because we must have
+                // obtained the semaphore to get here.
+            }
+        }
+    }
+ }
+ 
+ * \defgroup xSemaphoreGive xSemaphoreGive + * \ingroup Semaphores + */ +#define xSemaphoreGive( xSemaphore ) xQueueGenericSend( ( xQueueHandle ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK ) + +/** + * semphr. h + *
xSemaphoreGiveRecursive( xSemaphoreHandle xMutex )
+ * + * Macro to recursively release, or 'give', a mutex type semaphore. + * The mutex must have previously been created using a call to + * xSemaphoreCreateRecursiveMutex(); + * + * configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h for this + * macro to be available. + * + * This macro must not be used on mutexes created using xSemaphoreCreateMutex(). + * + * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex + * doesn't become available again until the owner has called + * xSemaphoreGiveRecursive() for each successful 'take' request. For example, + * if a task successfully 'takes' the same mutex 5 times then the mutex will + * not be available to any other task until it has also 'given' the mutex back + * exactly five times. + * + * @param xMutex A handle to the mutex being released, or 'given'. This is the + * handle returned by xSemaphoreCreateMutex(); + * + * @return pdTRUE if the semaphore was given. + * + * Example usage: +
+ xSemaphoreHandle xMutex = NULL;
+
+ // A task that creates a mutex.
+ void vATask( void * pvParameters )
+ {
+    // Create the mutex to guard a shared resource.
+    xMutex = xSemaphoreCreateRecursiveMutex();
+ }
+
+ // A task that uses the mutex.
+ void vAnotherTask( void * pvParameters )
+ {
+    // ... Do other things.
+
+    if( xMutex != NULL )
+    {
+        // See if we can obtain the mutex.  If the mutex is not available
+        // wait 10 ticks to see if it becomes free.	
+        if( xSemaphoreTakeRecursive( xMutex, ( portTickType ) 10 ) == pdTRUE )
+        {
+            // We were able to obtain the mutex and can now access the
+            // shared resource.
+
+            // ...
+            // For some reason due to the nature of the code further calls to 
+			// xSemaphoreTakeRecursive() are made on the same mutex.  In real
+			// code these would not be just sequential calls as this would make
+			// no sense.  Instead the calls are likely to be buried inside
+			// a more complex call structure.
+            xSemaphoreTakeRecursive( xMutex, ( portTickType ) 10 );
+            xSemaphoreTakeRecursive( xMutex, ( portTickType ) 10 );
+
+            // The mutex has now been 'taken' three times, so will not be 
+			// available to another task until it has also been given back
+			// three times.  Again it is unlikely that real code would have
+			// these calls sequentially, it would be more likely that the calls
+			// to xSemaphoreGiveRecursive() would be called as a call stack
+			// unwound.  This is just for demonstrative purposes.
+            xSemaphoreGiveRecursive( xMutex );
+			xSemaphoreGiveRecursive( xMutex );
+			xSemaphoreGiveRecursive( xMutex );
+
+			// Now the mutex can be taken by other tasks.
+        }
+        else
+        {
+            // We could not obtain the mutex and can therefore not access
+            // the shared resource safely.
+        }
+    }
+ }
+ 
+ * \defgroup xSemaphoreGiveRecursive xSemaphoreGiveRecursive + * \ingroup Semaphores + */ +#define xSemaphoreGiveRecursive( xMutex ) xQueueGiveMutexRecursive( ( xMutex ) ) + +/* + * xSemaphoreAltGive() is an alternative version of xSemaphoreGive(). + * + * The source code that implements the alternative (Alt) API is much + * simpler because it executes everything from within a critical section. + * This is the approach taken by many other RTOSes, but FreeRTOS.org has the + * preferred fully featured API too. The fully featured API has more + * complex code that takes longer to execute, but makes much less use of + * critical sections. Therefore the alternative API sacrifices interrupt + * responsiveness to gain execution speed, whereas the fully featured API + * sacrifices execution speed to ensure better interrupt responsiveness. + */ +#define xSemaphoreAltGive( xSemaphore ) xQueueAltGenericSend( ( xQueueHandle ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK ) + +/** + * semphr. h + *
+ xSemaphoreGiveFromISR( 
+                          xSemaphoreHandle xSemaphore, 
+                          signed portBASE_TYPE *pxHigherPriorityTaskWoken
+                      )
+ * + * Macro to release a semaphore. The semaphore must have previously been + * created with a call to vSemaphoreCreateBinary() or xSemaphoreCreateCounting(). + * + * Mutex type semaphores (those created using a call to xSemaphoreCreateMutex()) + * must not be used with this macro. + * + * This macro can be used from an ISR. + * + * @param xSemaphore A handle to the semaphore being released. This is the + * handle returned when the semaphore was created. + * + * @param pxHigherPriorityTaskWoken xSemaphoreGiveFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if giving the semaphore caused a task + * to unblock, and the unblocked task has a priority higher than the currently + * running task. If xSemaphoreGiveFromISR() sets this value to pdTRUE then + * a context switch should be requested before the interrupt is exited. + * + * @return pdTRUE if the semaphore was successfully given, otherwise errQUEUE_FULL. + * + * Example usage: +
+ \#define LONG_TIME 0xffff
+ \#define TICKS_TO_WAIT	10
+ xSemaphoreHandle xSemaphore = NULL;
+
+ // Repetitive task.
+ void vATask( void * pvParameters )
+ {
+    for( ;; )
+    {
+        // We want this task to run every 10 ticks of a timer.  The semaphore 
+        // was created before this task was started.
+
+        // Block waiting for the semaphore to become available.
+        if( xSemaphoreTake( xSemaphore, LONG_TIME ) == pdTRUE )
+        {
+            // It is time to execute.
+
+            // ...
+
+            // We have finished our task.  Return to the top of the loop where
+            // we will block on the semaphore until it is time to execute 
+            // again.  Note when using the semaphore for synchronisation with an
+			// ISR in this manner there is no need to 'give' the semaphore back.
+        }
+    }
+ }
+
+ // Timer ISR
+ void vTimerISR( void * pvParameters )
+ {
+ static unsigned char ucLocalTickCount = 0;
+ static signed portBASE_TYPE xHigherPriorityTaskWoken;
+
+    // A timer tick has occurred.
+
+    // ... Do other time functions.
+
+    // Is it time for vATask () to run?
+	xHigherPriorityTaskWoken = pdFALSE;
+    ucLocalTickCount++;
+    if( ucLocalTickCount >= TICKS_TO_WAIT )
+    {
+        // Unblock the task by releasing the semaphore.
+        xSemaphoreGiveFromISR( xSemaphore, &xHigherPriorityTaskWoken );
+
+        // Reset the count so we release the semaphore again in 10 ticks time.
+        ucLocalTickCount = 0;
+    }
+
+    if( xHigherPriorityTaskWoken != pdFALSE )
+    {
+        // We can force a context switch here.  Context switching from an
+        // ISR uses port specific syntax.  Check the demo task for your port
+        // to find the syntax required.
+    }
+ }
+ 
+ * \defgroup xSemaphoreGiveFromISR xSemaphoreGiveFromISR + * \ingroup Semaphores + */ +#define xSemaphoreGiveFromISR( xSemaphore, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueueHandle ) ( xSemaphore ), NULL, ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK ) + +/** + * semphr. h + *
+ xSemaphoreTakeFromISR( 
+                          xSemaphoreHandle xSemaphore, 
+                          signed portBASE_TYPE *pxHigherPriorityTaskWoken
+                      )
+ * + * Macro to take a semaphore from an ISR. The semaphore must have + * previously been created with a call to vSemaphoreCreateBinary() or + * xSemaphoreCreateCounting(). + * + * Mutex type semaphores (those created using a call to xSemaphoreCreateMutex()) + * must not be used with this macro. + * + * This macro can be used from an ISR, however taking a semaphore from an ISR + * is not a common operation. It is likely to only be useful when taking a + * counting semaphore when an interrupt is obtaining an object from a resource + * pool (when the semaphore count indicates the number of resources available). + * + * @param xSemaphore A handle to the semaphore being taken. This is the + * handle returned when the semaphore was created. + * + * @param pxHigherPriorityTaskWoken xSemaphoreTakeFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if taking the semaphore caused a task + * to unblock, and the unblocked task has a priority higher than the currently + * running task. If xSemaphoreTakeFromISR() sets this value to pdTRUE then + * a context switch should be requested before the interrupt is exited. + * + * @return pdTRUE if the semaphore was successfully taken, otherwise + * pdFALSE + */ +#define xSemaphoreTakeFromISR( xSemaphore, pxHigherPriorityTaskWoken ) xQueueReceiveFromISR( ( xQueueHandle ) ( xSemaphore ), NULL, ( pxHigherPriorityTaskWoken ) ) + +/** + * semphr. h + *
xSemaphoreHandle xSemaphoreCreateMutex( void )
+ * + * Macro that implements a mutex semaphore by using the existing queue + * mechanism. + * + * Mutexes created using this macro can be accessed using the xSemaphoreTake() + * and xSemaphoreGive() macros. The xSemaphoreTakeRecursive() and + * xSemaphoreGiveRecursive() macros should not be used. + * + * This type of semaphore uses a priority inheritance mechanism so a task + * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the + * semaphore it is no longer required. + * + * Mutex type semaphores cannot be used from within interrupt service routines. + * + * See vSemaphoreCreateBinary() for an alternative implementation that can be + * used for pure synchronisation (where one task or interrupt always 'gives' the + * semaphore and another always 'takes' the semaphore) and from within interrupt + * service routines. + * + * @return xSemaphore Handle to the created mutex semaphore. Should be of type + * xSemaphoreHandle. + * + * Example usage: +
+ xSemaphoreHandle xSemaphore;
+
+ void vATask( void * pvParameters )
+ {
+    // Semaphore cannot be used before a call to xSemaphoreCreateMutex().
+    // This is a macro so pass the variable in directly.
+    xSemaphore = xSemaphoreCreateMutex();
+
+    if( xSemaphore != NULL )
+    {
+        // The semaphore was created successfully.
+        // The semaphore can now be used.  
+    }
+ }
+ 
+ * \defgroup vSemaphoreCreateMutex vSemaphoreCreateMutex + * \ingroup Semaphores + */ +#define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX ) + + +/** + * semphr. h + *
xSemaphoreHandle xSemaphoreCreateRecursiveMutex( void )
+ * + * Macro that implements a recursive mutex by using the existing queue + * mechanism. + * + * Mutexes created using this macro can be accessed using the + * xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() macros. The + * xSemaphoreTake() and xSemaphoreGive() macros should not be used. + * + * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex + * doesn't become available again until the owner has called + * xSemaphoreGiveRecursive() for each successful 'take' request. For example, + * if a task successfully 'takes' the same mutex 5 times then the mutex will + * not be available to any other task until it has also 'given' the mutex back + * exactly five times. + * + * This type of semaphore uses a priority inheritance mechanism so a task + * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the + * semaphore it is no longer required. + * + * Mutex type semaphores cannot be used from within interrupt service routines. + * + * See vSemaphoreCreateBinary() for an alternative implementation that can be + * used for pure synchronisation (where one task or interrupt always 'gives' the + * semaphore and another always 'takes' the semaphore) and from within interrupt + * service routines. + * + * @return xSemaphore Handle to the created mutex semaphore. Should be of type + * xSemaphoreHandle. + * + * Example usage: +
+ xSemaphoreHandle xSemaphore;
+
+ void vATask( void * pvParameters )
+ {
+    // Semaphore cannot be used before a call to xSemaphoreCreateMutex().
+    // This is a macro so pass the variable in directly.
+    xSemaphore = xSemaphoreCreateRecursiveMutex();
+
+    if( xSemaphore != NULL )
+    {
+        // The semaphore was created successfully.
+        // The semaphore can now be used.  
+    }
+ }
+ 
+ * \defgroup vSemaphoreCreateMutex vSemaphoreCreateMutex + * \ingroup Semaphores + */ +#define xSemaphoreCreateRecursiveMutex() xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX ) + +/** + * semphr. h + *
xSemaphoreHandle xSemaphoreCreateCounting( unsigned portBASE_TYPE uxMaxCount, unsigned portBASE_TYPE uxInitialCount )
+ * + * Macro that creates a counting semaphore by using the existing + * queue mechanism. + * + * Counting semaphores are typically used for two things: + * + * 1) Counting events. + * + * In this usage scenario an event handler will 'give' a semaphore each time + * an event occurs (incrementing the semaphore count value), and a handler + * task will 'take' a semaphore each time it processes an event + * (decrementing the semaphore count value). The count value is therefore + * the difference between the number of events that have occurred and the + * number that have been processed. In this case it is desirable for the + * initial count value to be zero. + * + * 2) Resource management. + * + * In this usage scenario the count value indicates the number of resources + * available. To obtain control of a resource a task must first obtain a + * semaphore - decrementing the semaphore count value. When the count value + * reaches zero there are no free resources. When a task finishes with the + * resource it 'gives' the semaphore back - incrementing the semaphore count + * value. In this case it is desirable for the initial count value to be + * equal to the maximum count value, indicating that all resources are free. + * + * @param uxMaxCount The maximum count value that can be reached. When the + * semaphore reaches this value it can no longer be 'given'. + * + * @param uxInitialCount The count value assigned to the semaphore when it is + * created. + * + * @return Handle to the created semaphore. Null if the semaphore could not be + * created. + * + * Example usage: +
+ xSemaphoreHandle xSemaphore;
+
+ void vATask( void * pvParameters )
+ {
+ xSemaphoreHandle xSemaphore = NULL;
+
+    // Semaphore cannot be used before a call to xSemaphoreCreateCounting().
+    // The max value to which the semaphore can count should be 10, and the
+    // initial value assigned to the count should be 0.
+    xSemaphore = xSemaphoreCreateCounting( 10, 0 );
+
+    if( xSemaphore != NULL )
+    {
+        // The semaphore was created successfully.
+        // The semaphore can now be used.  
+    }
+ }
+ 
+ * \defgroup xSemaphoreCreateCounting xSemaphoreCreateCounting + * \ingroup Semaphores + */ +#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) ) + +/** + * semphr. h + *
void vSemaphoreDelete( xSemaphoreHandle xSemaphore );
+ * + * Delete a semaphore. This function must be used with care. For example, + * do not delete a mutex type semaphore if the mutex is held by a task. + * + * @param xSemaphore A handle to the semaphore to be deleted. + * + * \defgroup vSemaphoreDelete vSemaphoreDelete + * \ingroup Semaphores + */ +#define vSemaphoreDelete( xSemaphore ) vQueueDelete( ( xQueueHandle ) ( xSemaphore ) ) + +/** + * semphr.h + *
xTaskHandle xSemaphoreGetMutexHolder( xSemaphoreHandle xMutex );
+ * + * If xMutex is indeed a mutex type semaphore, return the current mutex holder. + * If xMutex is not a mutex type semaphore, or the mutex is available (not held + * by a task), return NULL. + * + * Note: This Is is a good way of determining if the calling task is the mutex + * holder, but not a good way of determining the identity of the mutex holder as + * the holder may change between the function exiting and the returned value + * being tested. + */ +#define xSemaphoreGetMutexHolder( xSemaphore ) xQueueGetMutexHolder( ( xSemaphore ) ) + +#endif /* SEMAPHORE_H */ + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/freertos/task.h b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/task.h new file mode 100644 index 0000000..51e7885 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/task.h @@ -0,0 +1,1521 @@ +/* + FreeRTOS V7.5.2 - Copyright (C) 2013 Real Time Engineers Ltd. + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that has become a de facto standard. * + * * + * Help yourself get started quickly and support the FreeRTOS * + * project by purchasing a FreeRTOS tutorial book, reference * + * manual, or both from: http://www.FreeRTOS.org/Documentation * + * * + * Thank you! * + * * + *************************************************************************** + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + >>! NOTE: The modification to the GPL is included to allow you to distribute + >>! a combined work that includes FreeRTOS without being obliged to provide + >>! the source code for proprietary components outside of the FreeRTOS + >>! kernel. + + FreeRTOS 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. Full license text is available from the following + link: http://www.freertos.org/a00114.html + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + + +#ifndef INC_TASK_H +#define INC_TASK_H + +#ifndef INC_FREERTOS_H + #error "include FreeRTOS.h must appear in source files before include task.h" +#endif + +#include "list.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*----------------------------------------------------------- + * MACROS AND DEFINITIONS + *----------------------------------------------------------*/ + +#define tskKERNEL_VERSION_NUMBER "V7.5.2" + +/** + * task. h + * + * Type by which tasks are referenced. For example, a call to xTaskCreate + * returns (via a pointer parameter) an xTaskHandle variable that can then + * be used as a parameter to vTaskDelete to delete the task. + * + * \defgroup xTaskHandle xTaskHandle + * \ingroup Tasks + */ +typedef void * xTaskHandle; + +/* Task states returned by eTaskGetState. */ +typedef enum +{ + eRunning = 0, /* A task is querying the state of itself, so must be running. */ + eReady, /* The task being queried is in a read or pending ready list. */ + eBlocked, /* The task being queried is in the Blocked state. */ + eSuspended, /* The task being queried is in the Suspended state, or is in the Blocked state with an infinite time out. */ + eDeleted /* The task being queried has been deleted, but its TCB has not yet been freed. */ +} eTaskState; + +/* + * Used internally only. + */ +typedef struct xTIME_OUT +{ + portBASE_TYPE xOverflowCount; + portTickType xTimeOnEntering; +} xTimeOutType; + +/* + * Defines the memory ranges allocated to the task when an MPU is used. + */ +typedef struct xMEMORY_REGION +{ + void *pvBaseAddress; + unsigned long ulLengthInBytes; + unsigned long ulParameters; +} xMemoryRegion; + +/* + * Parameters required to create an MPU protected task. + */ +typedef struct xTASK_PARAMTERS +{ + pdTASK_CODE pvTaskCode; + const signed char * const pcName; + unsigned short usStackDepth; + void *pvParameters; + unsigned portBASE_TYPE uxPriority; + portSTACK_TYPE *puxStackBuffer; + xMemoryRegion xRegions[ portNUM_CONFIGURABLE_REGIONS ]; +} xTaskParameters; + +/* Used with the uxTaskGetSystemState() function to return the state of each task +in the system. */ +typedef struct xTASK_STATUS +{ + xTaskHandle xHandle; /* The handle of the task to which the rest of the information in the structure relates. */ + const signed char *pcTaskName; /* A pointer to the task's name. This value will be invalid if the task was deleted since the structure was populated! */ + unsigned portBASE_TYPE xTaskNumber; /* A number unique to the task. */ + eTaskState eCurrentState; /* The state in which the task existed when the structure was populated. */ + unsigned portBASE_TYPE uxCurrentPriority; /* The priority at which the task was running (may be inherited) when the structure was populated. */ + unsigned portBASE_TYPE uxBasePriority; /* The priority to which the task will return if the task's current priority has been inherited to avoid unbounded priority inversion when obtaining a mutex. Only valid if configUSE_MUTEXES is defined as 1 in FreeRTOSConfig.h. */ + unsigned long ulRunTimeCounter; /* The total run time allocated to the task so far, as defined by the run time stats clock. See http://www.freertos.org/rtos-run-time-stats.html. Only valid when configGENERATE_RUN_TIME_STATS is defined as 1 in FreeRTOSConfig.h. */ + unsigned short usStackHighWaterMark; /* The minimum amount of stack space that has remained for the task since the task was created. The closer this value is to zero the closer the task has come to overflowing its stack. */ +} xTaskStatusType; + +/* Possible return values for eTaskConfirmSleepModeStatus(). */ +typedef enum +{ + eAbortSleep = 0, /* A task has been made ready or a context switch pended since portSUPPORESS_TICKS_AND_SLEEP() was called - abort entering a sleep mode. */ + eStandardSleep, /* Enter a sleep mode that will not last any longer than the expected idle time. */ + eNoTasksWaitingTimeout /* No tasks are waiting for a timeout so it is safe to enter a sleep mode that can only be exited by an external interrupt. */ +} eSleepModeStatus; + + +/* + * Defines the priority used by the idle task. This must not be modified. + * + * \ingroup TaskUtils + */ +#define tskIDLE_PRIORITY ( ( unsigned portBASE_TYPE ) 0U ) + +/** + * task. h + * + * Macro for forcing a context switch. + * + * \defgroup taskYIELD taskYIELD + * \ingroup SchedulerControl + */ +#define taskYIELD() portYIELD() + +/** + * task. h + * + * Macro to mark the start of a critical code region. Preemptive context + * switches cannot occur when in a critical region. + * + * NOTE: This may alter the stack (depending on the portable implementation) + * so must be used with care! + * + * \defgroup taskENTER_CRITICAL taskENTER_CRITICAL + * \ingroup SchedulerControl + */ +#define taskENTER_CRITICAL() portENTER_CRITICAL() + +/** + * task. h + * + * Macro to mark the end of a critical code region. Preemptive context + * switches cannot occur when in a critical region. + * + * NOTE: This may alter the stack (depending on the portable implementation) + * so must be used with care! + * + * \defgroup taskEXIT_CRITICAL taskEXIT_CRITICAL + * \ingroup SchedulerControl + */ +#define taskEXIT_CRITICAL() portEXIT_CRITICAL() + +/** + * task. h + * + * Macro to disable all maskable interrupts. + * + * \defgroup taskDISABLE_INTERRUPTS taskDISABLE_INTERRUPTS + * \ingroup SchedulerControl + */ +#define taskDISABLE_INTERRUPTS() portDISABLE_INTERRUPTS() + +/** + * task. h + * + * Macro to enable microcontroller interrupts. + * + * \defgroup taskENABLE_INTERRUPTS taskENABLE_INTERRUPTS + * \ingroup SchedulerControl + */ +#define taskENABLE_INTERRUPTS() portENABLE_INTERRUPTS() + +/* Definitions returned by xTaskGetSchedulerState(). */ +#define taskSCHEDULER_NOT_STARTED ( ( portBASE_TYPE ) 0 ) +#define taskSCHEDULER_RUNNING ( ( portBASE_TYPE ) 1 ) +#define taskSCHEDULER_SUSPENDED ( ( portBASE_TYPE ) 2 ) + +/*----------------------------------------------------------- + * TASK CREATION API + *----------------------------------------------------------*/ + +/** + * task. h + *
+ portBASE_TYPE xTaskCreate(
+							  pdTASK_CODE pvTaskCode,
+							  const char * const pcName,
+							  unsigned short usStackDepth,
+							  void *pvParameters,
+							  unsigned portBASE_TYPE uxPriority,
+							  xTaskHandle *pvCreatedTask
+						  );
+ * + * Create a new task and add it to the list of tasks that are ready to run. + * + * xTaskCreate() can only be used to create a task that has unrestricted + * access to the entire microcontroller memory map. Systems that include MPU + * support can alternatively create an MPU constrained task using + * xTaskCreateRestricted(). + * + * @param pvTaskCode Pointer to the task entry function. Tasks + * must be implemented to never return (i.e. continuous loop). + * + * @param pcName A descriptive name for the task. This is mainly used to + * facilitate debugging. Max length defined by tskMAX_TASK_NAME_LEN - default + * is 16. + * + * @param usStackDepth The size of the task stack specified as the number of + * variables the stack can hold - not the number of bytes. For example, if + * the stack is 16 bits wide and usStackDepth is defined as 100, 200 bytes + * will be allocated for stack storage. + * + * @param pvParameters Pointer that will be used as the parameter for the task + * being created. + * + * @param uxPriority The priority at which the task should run. Systems that + * include MPU support can optionally create tasks in a privileged (system) + * mode by setting bit portPRIVILEGE_BIT of the priority parameter. For + * example, to create a privileged task at priority 2 the uxPriority parameter + * should be set to ( 2 | portPRIVILEGE_BIT ). + * + * @param pvCreatedTask Used to pass back a handle by which the created task + * can be referenced. + * + * @return pdPASS if the task was successfully created and added to a ready + * list, otherwise an error code defined in the file errors. h + * + * Example usage: +
+ // Task to be created.
+ void vTaskCode( void * pvParameters )
+ {
+	 for( ;; )
+	 {
+		 // Task code goes here.
+	 }
+ }
+
+ // Function that creates a task.
+ void vOtherFunction( void )
+ {
+ static unsigned char ucParameterToPass;
+ xTaskHandle xHandle;
+
+	 // Create the task, storing the handle.  Note that the passed parameter ucParameterToPass
+	 // must exist for the lifetime of the task, so in this case is declared static.  If it was just an
+	 // an automatic stack variable it might no longer exist, or at least have been corrupted, by the time
+	 // the new task attempts to access it.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, &ucParameterToPass, tskIDLE_PRIORITY, &xHandle );
+
+	 // Use the handle to delete the task.
+	 vTaskDelete( xHandle );
+ }
+   
+ * \defgroup xTaskCreate xTaskCreate + * \ingroup Tasks + */ +#define xTaskCreate( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask ) xTaskGenericCreate( ( pvTaskCode ), ( pcName ), ( usStackDepth ), ( pvParameters ), ( uxPriority ), ( pxCreatedTask ), ( NULL ), ( NULL ) ) + +/** + * task. h + *
+ portBASE_TYPE xTaskCreateRestricted( xTaskParameters *pxTaskDefinition, xTaskHandle *pxCreatedTask );
+ * + * xTaskCreateRestricted() should only be used in systems that include an MPU + * implementation. + * + * Create a new task and add it to the list of tasks that are ready to run. + * The function parameters define the memory regions and associated access + * permissions allocated to the task. + * + * @param pxTaskDefinition Pointer to a structure that contains a member + * for each of the normal xTaskCreate() parameters (see the xTaskCreate() API + * documentation) plus an optional stack buffer and the memory region + * definitions. + * + * @param pxCreatedTask Used to pass back a handle by which the created task + * can be referenced. + * + * @return pdPASS if the task was successfully created and added to a ready + * list, otherwise an error code defined in the file errors. h + * + * Example usage: +
+// Create an xTaskParameters structure that defines the task to be created.
+static const xTaskParameters xCheckTaskParameters =
+{
+	vATask,		// pvTaskCode - the function that implements the task.
+	"ATask",	// pcName - just a text name for the task to assist debugging.
+	100,		// usStackDepth	- the stack size DEFINED IN WORDS.
+	NULL,		// pvParameters - passed into the task function as the function parameters.
+	( 1UL | portPRIVILEGE_BIT ),// uxPriority - task priority, set the portPRIVILEGE_BIT if the task should run in a privileged state.
+	cStackBuffer,// puxStackBuffer - the buffer to be used as the task stack.
+
+	// xRegions - Allocate up to three separate memory regions for access by
+	// the task, with appropriate access permissions.  Different processors have
+	// different memory alignment requirements - refer to the FreeRTOS documentation
+	// for full information.
+	{
+		// Base address					Length	Parameters
+        { cReadWriteArray,				32,		portMPU_REGION_READ_WRITE },
+        { cReadOnlyArray,				32,		portMPU_REGION_READ_ONLY },
+        { cPrivilegedOnlyAccessArray,	128,	portMPU_REGION_PRIVILEGED_READ_WRITE }
+	}
+};
+
+int main( void )
+{
+xTaskHandle xHandle;
+
+	// Create a task from the const structure defined above.  The task handle
+	// is requested (the second parameter is not NULL) but in this case just for
+	// demonstration purposes as its not actually used.
+	xTaskCreateRestricted( &xRegTest1Parameters, &xHandle );
+
+	// Start the scheduler.
+	vTaskStartScheduler();
+
+	// Will only get here if there was insufficient memory to create the idle
+	// task.
+	for( ;; );
+}
+   
+ * \defgroup xTaskCreateRestricted xTaskCreateRestricted + * \ingroup Tasks + */ +#define xTaskCreateRestricted( x, pxCreatedTask ) xTaskGenericCreate( ((x)->pvTaskCode), ((x)->pcName), ((x)->usStackDepth), ((x)->pvParameters), ((x)->uxPriority), (pxCreatedTask), ((x)->puxStackBuffer), ((x)->xRegions) ) + +/** + * task. h + *
+ void vTaskAllocateMPURegions( xTaskHandle xTask, const xMemoryRegion * const pxRegions );
+ * + * Memory regions are assigned to a restricted task when the task is created by + * a call to xTaskCreateRestricted(). These regions can be redefined using + * vTaskAllocateMPURegions(). + * + * @param xTask The handle of the task being updated. + * + * @param xRegions A pointer to an xMemoryRegion structure that contains the + * new memory region definitions. + * + * Example usage: +
+// Define an array of xMemoryRegion structures that configures an MPU region
+// allowing read/write access for 1024 bytes starting at the beginning of the
+// ucOneKByte array.  The other two of the maximum 3 definable regions are
+// unused so set to zero.
+static const xMemoryRegion xAltRegions[ portNUM_CONFIGURABLE_REGIONS ] =
+{
+	// Base address		Length		Parameters
+	{ ucOneKByte,		1024,		portMPU_REGION_READ_WRITE },
+	{ 0,				0,			0 },
+	{ 0,				0,			0 }
+};
+
+void vATask( void *pvParameters )
+{
+	// This task was created such that it has access to certain regions of
+	// memory as defined by the MPU configuration.  At some point it is
+	// desired that these MPU regions are replaced with that defined in the
+	// xAltRegions const struct above.  Use a call to vTaskAllocateMPURegions()
+	// for this purpose.  NULL is used as the task handle to indicate that this
+	// function should modify the MPU regions of the calling task.
+	vTaskAllocateMPURegions( NULL, xAltRegions );
+
+	// Now the task can continue its function, but from this point on can only
+	// access its stack and the ucOneKByte array (unless any other statically
+	// defined or shared regions have been declared elsewhere).
+}
+   
+ * \defgroup xTaskCreateRestricted xTaskCreateRestricted + * \ingroup Tasks + */ +void vTaskAllocateMPURegions( xTaskHandle xTask, const xMemoryRegion * const pxRegions ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskDelete( xTaskHandle xTask );
+ * + * INCLUDE_vTaskDelete must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Remove a task from the RTOS real time kernels management. The task being + * deleted will be removed from all ready, blocked, suspended and event lists. + * + * NOTE: The idle task is responsible for freeing the kernel allocated + * memory from tasks that have been deleted. It is therefore important that + * the idle task is not starved of microcontroller processing time if your + * application makes any calls to vTaskDelete (). Memory allocated by the + * task code is not automatically freed, and should be freed before the task + * is deleted. + * + * See the demo application file death.c for sample code that utilises + * vTaskDelete (). + * + * @param xTask The handle of the task to be deleted. Passing NULL will + * cause the calling task to be deleted. + * + * Example usage: +
+ void vOtherFunction( void )
+ {
+ xTaskHandle xHandle;
+
+	 // Create the task, storing the handle.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+	 // Use the handle to delete the task.
+	 vTaskDelete( xHandle );
+ }
+   
+ * \defgroup vTaskDelete vTaskDelete + * \ingroup Tasks + */ +void vTaskDelete( xTaskHandle xTaskToDelete ) PRIVILEGED_FUNCTION; + +/*----------------------------------------------------------- + * TASK CONTROL API + *----------------------------------------------------------*/ + +/** + * task. h + *
void vTaskDelay( portTickType xTicksToDelay );
+ * + * Delay a task for a given number of ticks. The actual time that the + * task remains blocked depends on the tick rate. The constant + * portTICK_RATE_MS can be used to calculate real time from the tick + * rate - with the resolution of one tick period. + * + * INCLUDE_vTaskDelay must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * + * vTaskDelay() specifies a time at which the task wishes to unblock relative to + * the time at which vTaskDelay() is called. For example, specifying a block + * period of 100 ticks will cause the task to unblock 100 ticks after + * vTaskDelay() is called. vTaskDelay() does not therefore provide a good method + * of controlling the frequency of a cyclical task as the path taken through the + * code, as well as other task and interrupt activity, will effect the frequency + * at which vTaskDelay() gets called and therefore the time at which the task + * next executes. See vTaskDelayUntil() for an alternative API function designed + * to facilitate fixed frequency execution. It does this by specifying an + * absolute time (rather than a relative time) at which the calling task should + * unblock. + * + * @param xTicksToDelay The amount of time, in tick periods, that + * the calling task should block. + * + * Example usage: + + void vTaskFunction( void * pvParameters ) + { + void vTaskFunction( void * pvParameters ) + { + // Block for 500ms. + const portTickType xDelay = 500 / portTICK_RATE_MS; + + for( ;; ) + { + // Simply toggle the LED every 500ms, blocking between each toggle. + vToggleLED(); + vTaskDelay( xDelay ); + } + } + + * \defgroup vTaskDelay vTaskDelay + * \ingroup TaskCtrl + */ +void vTaskDelay( portTickType xTicksToDelay ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskDelayUntil( portTickType *pxPreviousWakeTime, portTickType xTimeIncrement );
+ * + * INCLUDE_vTaskDelayUntil must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Delay a task until a specified time. This function can be used by cyclical + * tasks to ensure a constant execution frequency. + * + * This function differs from vTaskDelay () in one important aspect: vTaskDelay () will + * cause a task to block for the specified number of ticks from the time vTaskDelay () is + * called. It is therefore difficult to use vTaskDelay () by itself to generate a fixed + * execution frequency as the time between a task starting to execute and that task + * calling vTaskDelay () may not be fixed [the task may take a different path though the + * code between calls, or may get interrupted or preempted a different number of times + * each time it executes]. + * + * Whereas vTaskDelay () specifies a wake time relative to the time at which the function + * is called, vTaskDelayUntil () specifies the absolute (exact) time at which it wishes to + * unblock. + * + * The constant portTICK_RATE_MS can be used to calculate real time from the tick + * rate - with the resolution of one tick period. + * + * @param pxPreviousWakeTime Pointer to a variable that holds the time at which the + * task was last unblocked. The variable must be initialised with the current time + * prior to its first use (see the example below). Following this the variable is + * automatically updated within vTaskDelayUntil (). + * + * @param xTimeIncrement The cycle time period. The task will be unblocked at + * time *pxPreviousWakeTime + xTimeIncrement. Calling vTaskDelayUntil with the + * same xTimeIncrement parameter value will cause the task to execute with + * a fixed interface period. + * + * Example usage: +
+ // Perform an action every 10 ticks.
+ void vTaskFunction( void * pvParameters )
+ {
+ portTickType xLastWakeTime;
+ const portTickType xFrequency = 10;
+
+	 // Initialise the xLastWakeTime variable with the current time.
+	 xLastWakeTime = xTaskGetTickCount ();
+	 for( ;; )
+	 {
+		 // Wait for the next cycle.
+		 vTaskDelayUntil( &xLastWakeTime, xFrequency );
+
+		 // Perform action here.
+	 }
+ }
+   
+ * \defgroup vTaskDelayUntil vTaskDelayUntil + * \ingroup TaskCtrl + */ +void vTaskDelayUntil( portTickType * const pxPreviousWakeTime, portTickType xTimeIncrement ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle xTask );
+ * + * INCLUDE_xTaskPriorityGet must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Obtain the priority of any task. + * + * @param xTask Handle of the task to be queried. Passing a NULL + * handle results in the priority of the calling task being returned. + * + * @return The priority of xTask. + * + * Example usage: +
+ void vAFunction( void )
+ {
+ xTaskHandle xHandle;
+
+	 // Create a task, storing the handle.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+	 // ...
+
+	 // Use the handle to obtain the priority of the created task.
+	 // It was created with tskIDLE_PRIORITY, but may have changed
+	 // it itself.
+	 if( uxTaskPriorityGet( xHandle ) != tskIDLE_PRIORITY )
+	 {
+		 // The task has changed it's priority.
+	 }
+
+	 // ...
+
+	 // Is our priority higher than the created task?
+	 if( uxTaskPriorityGet( xHandle ) < uxTaskPriorityGet( NULL ) )
+	 {
+		 // Our priority (obtained using NULL handle) is higher.
+	 }
+ }
+   
+ * \defgroup uxTaskPriorityGet uxTaskPriorityGet + * \ingroup TaskCtrl + */ +unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle xTask ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
eTaskState eTaskGetState( xTaskHandle xTask );
+ * + * INCLUDE_eTaskGetState must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Obtain the state of any task. States are encoded by the eTaskState + * enumerated type. + * + * @param xTask Handle of the task to be queried. + * + * @return The state of xTask at the time the function was called. Note the + * state of the task might change between the function being called, and the + * functions return value being tested by the calling task. + */ +eTaskState eTaskGetState( xTaskHandle xTask ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskPrioritySet( xTaskHandle xTask, unsigned portBASE_TYPE uxNewPriority );
+ * + * INCLUDE_vTaskPrioritySet must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Set the priority of any task. + * + * A context switch will occur before the function returns if the priority + * being set is higher than the currently executing task. + * + * @param xTask Handle to the task for which the priority is being set. + * Passing a NULL handle results in the priority of the calling task being set. + * + * @param uxNewPriority The priority to which the task will be set. + * + * Example usage: +
+ void vAFunction( void )
+ {
+ xTaskHandle xHandle;
+
+	 // Create a task, storing the handle.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+	 // ...
+
+	 // Use the handle to raise the priority of the created task.
+	 vTaskPrioritySet( xHandle, tskIDLE_PRIORITY + 1 );
+
+	 // ...
+
+	 // Use a NULL handle to raise our priority to the same value.
+	 vTaskPrioritySet( NULL, tskIDLE_PRIORITY + 1 );
+ }
+   
+ * \defgroup vTaskPrioritySet vTaskPrioritySet + * \ingroup TaskCtrl + */ +void vTaskPrioritySet( xTaskHandle xTask, unsigned portBASE_TYPE uxNewPriority ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskSuspend( xTaskHandle xTaskToSuspend );
+ * + * INCLUDE_vTaskSuspend must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Suspend any task. When suspended a task will never get any microcontroller + * processing time, no matter what its priority. + * + * Calls to vTaskSuspend are not accumulative - + * i.e. calling vTaskSuspend () twice on the same task still only requires one + * call to vTaskResume () to ready the suspended task. + * + * @param xTaskToSuspend Handle to the task being suspended. Passing a NULL + * handle will cause the calling task to be suspended. + * + * Example usage: +
+ void vAFunction( void )
+ {
+ xTaskHandle xHandle;
+
+	 // Create a task, storing the handle.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+	 // ...
+
+	 // Use the handle to suspend the created task.
+	 vTaskSuspend( xHandle );
+
+	 // ...
+
+	 // The created task will not run during this period, unless
+	 // another task calls vTaskResume( xHandle ).
+
+	 //...
+
+
+	 // Suspend ourselves.
+	 vTaskSuspend( NULL );
+
+	 // We cannot get here unless another task calls vTaskResume
+	 // with our handle as the parameter.
+ }
+   
+ * \defgroup vTaskSuspend vTaskSuspend + * \ingroup TaskCtrl + */ +void vTaskSuspend( xTaskHandle xTaskToSuspend ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskResume( xTaskHandle xTaskToResume );
+ * + * INCLUDE_vTaskSuspend must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Resumes a suspended task. + * + * A task that has been suspended by one of more calls to vTaskSuspend () + * will be made available for running again by a single call to + * vTaskResume (). + * + * @param xTaskToResume Handle to the task being readied. + * + * Example usage: +
+ void vAFunction( void )
+ {
+ xTaskHandle xHandle;
+
+	 // Create a task, storing the handle.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+	 // ...
+
+	 // Use the handle to suspend the created task.
+	 vTaskSuspend( xHandle );
+
+	 // ...
+
+	 // The created task will not run during this period, unless
+	 // another task calls vTaskResume( xHandle ).
+
+	 //...
+
+
+	 // Resume the suspended task ourselves.
+	 vTaskResume( xHandle );
+
+	 // The created task will once again get microcontroller processing
+	 // time in accordance with it priority within the system.
+ }
+   
+ * \defgroup vTaskResume vTaskResume + * \ingroup TaskCtrl + */ +void vTaskResume( xTaskHandle xTaskToResume ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void xTaskResumeFromISR( xTaskHandle xTaskToResume );
+ * + * INCLUDE_xTaskResumeFromISR must be defined as 1 for this function to be + * available. See the configuration section for more information. + * + * An implementation of vTaskResume() that can be called from within an ISR. + * + * A task that has been suspended by one of more calls to vTaskSuspend () + * will be made available for running again by a single call to + * xTaskResumeFromISR (). + * + * @param xTaskToResume Handle to the task being readied. + * + * \defgroup vTaskResumeFromISR vTaskResumeFromISR + * \ingroup TaskCtrl + */ +portBASE_TYPE xTaskResumeFromISR( xTaskHandle xTaskToResume ) PRIVILEGED_FUNCTION; + +/*----------------------------------------------------------- + * SCHEDULER CONTROL + *----------------------------------------------------------*/ + +/** + * task. h + *
void vTaskStartScheduler( void );
+ * + * Starts the real time kernel tick processing. After calling the kernel + * has control over which tasks are executed and when. This function + * does not return until an executing task calls vTaskEndScheduler (). + * + * At least one task should be created via a call to xTaskCreate () + * before calling vTaskStartScheduler (). The idle task is created + * automatically when the first application task is created. + * + * See the demo application file main.c for an example of creating + * tasks and starting the kernel. + * + * Example usage: +
+ void vAFunction( void )
+ {
+	 // Create at least one task before starting the kernel.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
+
+	 // Start the real time kernel with preemption.
+	 vTaskStartScheduler ();
+
+	 // Will not get here unless a task calls vTaskEndScheduler ()
+ }
+   
+ * + * \defgroup vTaskStartScheduler vTaskStartScheduler + * \ingroup SchedulerControl + */ +void vTaskStartScheduler( void ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskEndScheduler( void );
+ * + * Stops the real time kernel tick. All created tasks will be automatically + * deleted and multitasking (either preemptive or cooperative) will + * stop. Execution then resumes from the point where vTaskStartScheduler () + * was called, as if vTaskStartScheduler () had just returned. + * + * See the demo application file main. c in the demo/PC directory for an + * example that uses vTaskEndScheduler (). + * + * vTaskEndScheduler () requires an exit function to be defined within the + * portable layer (see vPortEndScheduler () in port. c for the PC port). This + * performs hardware specific operations such as stopping the kernel tick. + * + * vTaskEndScheduler () will cause all of the resources allocated by the + * kernel to be freed - but will not free resources allocated by application + * tasks. + * + * Example usage: +
+ void vTaskCode( void * pvParameters )
+ {
+	 for( ;; )
+	 {
+		 // Task code goes here.
+
+		 // At some point we want to end the real time kernel processing
+		 // so call ...
+		 vTaskEndScheduler ();
+	 }
+ }
+
+ void vAFunction( void )
+ {
+	 // Create at least one task before starting the kernel.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
+
+	 // Start the real time kernel with preemption.
+	 vTaskStartScheduler ();
+
+	 // Will only get here when the vTaskCode () task has called
+	 // vTaskEndScheduler ().  When we get here we are back to single task
+	 // execution.
+ }
+   
+ * + * \defgroup vTaskEndScheduler vTaskEndScheduler + * \ingroup SchedulerControl + */ +void vTaskEndScheduler( void ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskSuspendAll( void );
+ * + * Suspends all real time kernel activity while keeping interrupts (including the + * kernel tick) enabled. + * + * After calling vTaskSuspendAll () the calling task will continue to execute + * without risk of being swapped out until a call to xTaskResumeAll () has been + * made. + * + * API functions that have the potential to cause a context switch (for example, + * vTaskDelayUntil(), xQueueSend(), etc.) must not be called while the scheduler + * is suspended. + * + * Example usage: +
+ void vTask1( void * pvParameters )
+ {
+	 for( ;; )
+	 {
+		 // Task code goes here.
+
+		 // ...
+
+		 // At some point the task wants to perform a long operation during
+		 // which it does not want to get swapped out.  It cannot use
+		 // taskENTER_CRITICAL ()/taskEXIT_CRITICAL () as the length of the
+		 // operation may cause interrupts to be missed - including the
+		 // ticks.
+
+		 // Prevent the real time kernel swapping out the task.
+		 vTaskSuspendAll ();
+
+		 // Perform the operation here.  There is no need to use critical
+		 // sections as we have all the microcontroller processing time.
+		 // During this time interrupts will still operate and the kernel
+		 // tick count will be maintained.
+
+		 // ...
+
+		 // The operation is complete.  Restart the kernel.
+		 xTaskResumeAll ();
+	 }
+ }
+   
+ * \defgroup vTaskSuspendAll vTaskSuspendAll + * \ingroup SchedulerControl + */ +void vTaskSuspendAll( void ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
char xTaskResumeAll( void );
+ * + * Resumes real time kernel activity following a call to vTaskSuspendAll (). + * After a call to vTaskSuspendAll () the kernel will take control of which + * task is executing at any time. + * + * @return If resuming the scheduler caused a context switch then pdTRUE is + * returned, otherwise pdFALSE is returned. + * + * Example usage: +
+ void vTask1( void * pvParameters )
+ {
+	 for( ;; )
+	 {
+		 // Task code goes here.
+
+		 // ...
+
+		 // At some point the task wants to perform a long operation during
+		 // which it does not want to get swapped out.  It cannot use
+		 // taskENTER_CRITICAL ()/taskEXIT_CRITICAL () as the length of the
+		 // operation may cause interrupts to be missed - including the
+		 // ticks.
+
+		 // Prevent the real time kernel swapping out the task.
+		 vTaskSuspendAll ();
+
+		 // Perform the operation here.  There is no need to use critical
+		 // sections as we have all the microcontroller processing time.
+		 // During this time interrupts will still operate and the real
+		 // time kernel tick count will be maintained.
+
+		 // ...
+
+		 // The operation is complete.  Restart the kernel.  We want to force
+		 // a context switch - but there is no point if resuming the scheduler
+		 // caused a context switch already.
+		 if( !xTaskResumeAll () )
+		 {
+			  taskYIELD ();
+		 }
+	 }
+ }
+   
+ * \defgroup xTaskResumeAll xTaskResumeAll + * \ingroup SchedulerControl + */ +signed portBASE_TYPE xTaskResumeAll( void ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
signed portBASE_TYPE xTaskIsTaskSuspended( const xTaskHandle xTask );
+ * + * Utility task that simply returns pdTRUE if the task referenced by xTask is + * currently in the Suspended state, or pdFALSE if the task referenced by xTask + * is in any other state. + * + */ +signed portBASE_TYPE xTaskIsTaskSuspended( xTaskHandle xTask ) PRIVILEGED_FUNCTION; + +/*----------------------------------------------------------- + * TASK UTILITIES + *----------------------------------------------------------*/ + +/** + * task. h + *
portTickType xTaskGetTickCount( void );
+ * + * @return The count of ticks since vTaskStartScheduler was called. + * + * \defgroup xTaskGetTickCount xTaskGetTickCount + * \ingroup TaskUtils + */ +portTickType xTaskGetTickCount( void ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
portTickType xTaskGetTickCountFromISR( void );
+ * + * @return The count of ticks since vTaskStartScheduler was called. + * + * This is a version of xTaskGetTickCount() that is safe to be called from an + * ISR - provided that portTickType is the natural word size of the + * microcontroller being used or interrupt nesting is either not supported or + * not being used. + * + * \defgroup xTaskGetTickCount xTaskGetTickCount + * \ingroup TaskUtils + */ +portTickType xTaskGetTickCountFromISR( void ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
unsigned short uxTaskGetNumberOfTasks( void );
+ * + * @return The number of tasks that the real time kernel is currently managing. + * This includes all ready, blocked and suspended tasks. A task that + * has been deleted but not yet freed by the idle task will also be + * included in the count. + * + * \defgroup uxTaskGetNumberOfTasks uxTaskGetNumberOfTasks + * \ingroup TaskUtils + */ +unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
signed char *pcTaskGetTaskName( xTaskHandle xTaskToQuery );
+ * + * @return The text (human readable) name of the task referenced by the handle + * xTaskToQueury. A task can query its own name by either passing in its own + * handle, or by setting xTaskToQuery to NULL. INCLUDE_pcTaskGetTaskName must be + * set to 1 in FreeRTOSConfig.h for pcTaskGetTaskName() to be available. + * + * \defgroup pcTaskGetTaskName pcTaskGetTaskName + * \ingroup TaskUtils + */ +signed char *pcTaskGetTaskName( xTaskHandle xTaskToQuery ); + +/** + * task.h + *
unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask );
+ * + * INCLUDE_uxTaskGetStackHighWaterMark must be set to 1 in FreeRTOSConfig.h for + * this function to be available. + * + * Returns the high water mark of the stack associated with xTask. That is, + * the minimum free stack space there has been (in words, so on a 32 bit machine + * a value of 1 means 4 bytes) since the task started. The smaller the returned + * number the closer the task has come to overflowing its stack. + * + * @param xTask Handle of the task associated with the stack to be checked. + * Set xTask to NULL to check the stack of the calling task. + * + * @return The smallest amount of free stack space there has been (in bytes) + * since the task referenced by xTask was created. + */ +unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask ) PRIVILEGED_FUNCTION; + +/* When using trace macros it is sometimes necessary to include tasks.h before +FreeRTOS.h. When this is done pdTASK_HOOK_CODE will not yet have been defined, +so the following two prototypes will cause a compilation error. This can be +fixed by simply guarding against the inclusion of these two prototypes unless +they are explicitly required by the configUSE_APPLICATION_TASK_TAG configuration +constant. */ +#ifdef configUSE_APPLICATION_TASK_TAG + #if configUSE_APPLICATION_TASK_TAG == 1 + /** + * task.h + *
void vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxHookFunction );
+ * + * Sets pxHookFunction to be the task hook function used by the task xTask. + * Passing xTask as NULL has the effect of setting the calling tasks hook + * function. + */ + void vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxHookFunction ) PRIVILEGED_FUNCTION; + + /** + * task.h + *
void xTaskGetApplicationTaskTag( xTaskHandle xTask );
+ * + * Returns the pxHookFunction value assigned to the task xTask. + */ + pdTASK_HOOK_CODE xTaskGetApplicationTaskTag( xTaskHandle xTask ) PRIVILEGED_FUNCTION; + #endif /* configUSE_APPLICATION_TASK_TAG ==1 */ +#endif /* ifdef configUSE_APPLICATION_TASK_TAG */ + +/** + * task.h + *
portBASE_TYPE xTaskCallApplicationTaskHook( xTaskHandle xTask, pdTASK_HOOK_CODE pxHookFunction );
+ * + * Calls the hook function associated with xTask. Passing xTask as NULL has + * the effect of calling the Running tasks (the calling task) hook function. + * + * pvParameter is passed to the hook function for the task to interpret as it + * wants. + */ +portBASE_TYPE xTaskCallApplicationTaskHook( xTaskHandle xTask, void *pvParameter ) PRIVILEGED_FUNCTION; + +/** + * xTaskGetIdleTaskHandle() is only available if + * INCLUDE_xTaskGetIdleTaskHandle is set to 1 in FreeRTOSConfig.h. + * + * Simply returns the handle of the idle task. It is not valid to call + * xTaskGetIdleTaskHandle() before the scheduler has been started. + */ +xTaskHandle xTaskGetIdleTaskHandle( void ); + +/** + * configUSE_TRACE_FACILITY must bet defined as 1 in FreeRTOSConfig.h for + * uxTaskGetSystemState() to be available. + * + * uxTaskGetSystemState() populates an xTaskStatusType structure for each task in + * the system. xTaskStatusType structures contain, among other things, members + * for the task handle, task name, task priority, task state, and total amount + * of run time consumed by the task. See the xTaskStatusType structure + * definition in this file for the full member list. + * + * NOTE: This function is intended for debugging use only as its use results in + * the scheduler remaining suspended for an extended period. + * + * @param pxTaskStatusArray A pointer to an array of xTaskStatusType structures. + * The array must contain at least one xTaskStatusType structure for each task + * that is under the control of the RTOS. The number of tasks under the control + * of the RTOS can be determined using the uxTaskGetNumberOfTasks() API function. + * + * @param uxArraySize The size of the array pointed to by the pxTaskStatusArray + * parameter. The size is specified as the number of indexes in the array, or + * the number of xTaskStatusType structures contained in the array, not by the + * number of bytes in the array. + * + * @param pulTotalRunTime If configGENERATE_RUN_TIME_STATS is set to 1 in + * FreeRTOSConfig.h then *pulTotalRunTime is set by uxTaskGetSystemState() to the + * total run time (as defined by the run time stats clock, see + * http://www.freertos.org/rtos-run-time-stats.html) since the target booted. + * pulTotalRunTime can be set to NULL to omit the total run time information. + * + * @return The number of xTaskStatusType structures that were populated by + * uxTaskGetSystemState(). This should equal the number returned by the + * uxTaskGetNumberOfTasks() API function, but will be zero if the value passed + * in the uxArraySize parameter was too small. + * + * Example usage: +
+    // This example demonstrates how a human readable table of run time stats
+	// information is generated from raw data provided by uxTaskGetSystemState().
+	// The human readable table is written to pcWriteBuffer
+	void vTaskGetRunTimeStats( signed char *pcWriteBuffer )
+	{
+	xTaskStatusType *pxTaskStatusArray;
+	volatile unsigned portBASE_TYPE uxArraySize, x;
+	unsigned long ulTotalRunTime, ulStatsAsPercentage;
+
+		// Make sure the write buffer does not contain a string.
+		*pcWriteBuffer = 0x00;
+
+		// Take a snapshot of the number of tasks in case it changes while this
+		// function is executing.
+		uxArraySize = uxCurrentNumberOfTasks();
+
+		// Allocate a xTaskStatusType structure for each task.  An array could be
+		// allocated statically at compile time.
+		pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( xTaskStatusType ) );
+
+		if( pxTaskStatusArray != NULL )
+		{
+			// Generate raw status information about each task.
+			uxArraySize = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, &ulTotalRunTime );
+
+			// For percentage calculations.
+			ulTotalRunTime /= 100UL;
+
+			// Avoid divide by zero errors.
+			if( ulTotalRunTime > 0 )
+			{
+				// For each populated position in the pxTaskStatusArray array,
+				// format the raw data as human readable ASCII data
+				for( x = 0; x < uxArraySize; x++ )
+				{
+					// What percentage of the total run time has the task used?
+					// This will always be rounded down to the nearest integer.
+					// ulTotalRunTimeDiv100 has already been divided by 100.
+					ulStatsAsPercentage = pxTaskStatusArray[ x ].ulRunTimeCounter / ulTotalRunTime;
+
+					if( ulStatsAsPercentage > 0UL )
+					{
+						sprintf( ( char * ) pcWriteBuffer, ( char * ) "%s\t\t%lu\t\t%lu%%\r\n", pxTaskStatusArray[ x ].pcTaskName, pxTaskStatusArray[ x ].ulRunTimeCounter, ulStatsAsPercentage );
+					}
+					else
+					{
+						// If the percentage is zero here then the task has
+						// consumed less than 1% of the total run time.
+						sprintf( ( char * ) pcWriteBuffer, ( char * ) "%s\t\t%lu\t\t<1%%\r\n", pxTaskStatusArray[ x ].pcTaskName, pxTaskStatusArray[ x ].ulRunTimeCounter );
+					}
+
+					pcWriteBuffer += strlen( ( char * ) pcWriteBuffer );
+				}
+			}
+
+			// The array is no longer needed, free the memory it consumes.
+			vPortFree( pxTaskStatusArray );
+		}
+	}
+	
+ */ +unsigned portBASE_TYPE uxTaskGetSystemState( xTaskStatusType *pxTaskStatusArray, unsigned portBASE_TYPE uxArraySize, unsigned long *pulTotalRunTime ); + +/** + * task. h + *
void vTaskList( char *pcWriteBuffer );
+ * + * configUSE_TRACE_FACILITY and configUSE_STATS_FORMATTING_FUNCTIONS must + * both be defined as 1 for this function to be available. See the + * configuration section of the FreeRTOS.org website for more information. + * + * NOTE 1: This function will disable interrupts for its duration. It is + * not intended for normal application runtime use but as a debug aid. + * + * Lists all the current tasks, along with their current state and stack + * usage high water mark. + * + * Tasks are reported as blocked ('B'), ready ('R'), deleted ('D') or + * suspended ('S'). + * + * PLEASE NOTE: + * + * This function is provided for convenience only, and is used by many of the + * demo applications. Do not consider it to be part of the scheduler. + * + * vTaskList() calls uxTaskGetSystemState(), then formats part of the + * uxTaskGetSystemState() output into a human readable table that displays task + * names, states and stack usage. + * + * vTaskList() has a dependency on the sprintf() C library function that might + * bloat the code size, use a lot of stack, and provide different results on + * different platforms. An alternative, tiny, third party, and limited + * functionality implementation of sprintf() is provided in many of the + * FreeRTOS/Demo sub-directories in a file called printf-stdarg.c (note + * printf-stdarg.c does not provide a full snprintf() implementation!). + * + * It is recommended that production systems call uxTaskGetSystemState() + * directly to get access to raw stats data, rather than indirectly through a + * call to vTaskList(). + * + * @param pcWriteBuffer A buffer into which the above mentioned details + * will be written, in ascii form. This buffer is assumed to be large + * enough to contain the generated report. Approximately 40 bytes per + * task should be sufficient. + * + * \defgroup vTaskList vTaskList + * \ingroup TaskUtils + */ +void vTaskList( signed char *pcWriteBuffer ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskGetRunTimeStats( char *pcWriteBuffer );
+ * + * configGENERATE_RUN_TIME_STATS and configUSE_STATS_FORMATTING_FUNCTIONS + * must both be defined as 1 for this function to be available. The application + * must also then provide definitions for + * portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() and portGET_RUN_TIME_COUNTER_VALUE + * to configure a peripheral timer/counter and return the timers current count + * value respectively. The counter should be at least 10 times the frequency of + * the tick count. + * + * NOTE 1: This function will disable interrupts for its duration. It is + * not intended for normal application runtime use but as a debug aid. + * + * Setting configGENERATE_RUN_TIME_STATS to 1 will result in a total + * accumulated execution time being stored for each task. The resolution + * of the accumulated time value depends on the frequency of the timer + * configured by the portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() macro. + * Calling vTaskGetRunTimeStats() writes the total execution time of each + * task into a buffer, both as an absolute count value and as a percentage + * of the total system execution time. + * + * NOTE 2: + * + * This function is provided for convenience only, and is used by many of the + * demo applications. Do not consider it to be part of the scheduler. + * + * vTaskGetRunTimeStats() calls uxTaskGetSystemState(), then formats part of the + * uxTaskGetSystemState() output into a human readable table that displays the + * amount of time each task has spent in the Running state in both absolute and + * percentage terms. + * + * vTaskGetRunTimeStats() has a dependency on the sprintf() C library function + * that might bloat the code size, use a lot of stack, and provide different + * results on different platforms. An alternative, tiny, third party, and + * limited functionality implementation of sprintf() is provided in many of the + * FreeRTOS/Demo sub-directories in a file called printf-stdarg.c (note + * printf-stdarg.c does not provide a full snprintf() implementation!). + * + * It is recommended that production systems call uxTaskGetSystemState() directly + * to get access to raw stats data, rather than indirectly through a call to + * vTaskGetRunTimeStats(). + * + * @param pcWriteBuffer A buffer into which the execution times will be + * written, in ascii form. This buffer is assumed to be large enough to + * contain the generated report. Approximately 40 bytes per task should + * be sufficient. + * + * \defgroup vTaskGetRunTimeStats vTaskGetRunTimeStats + * \ingroup TaskUtils + */ +void vTaskGetRunTimeStats( signed char *pcWriteBuffer ) PRIVILEGED_FUNCTION; + +/*----------------------------------------------------------- + * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES + *----------------------------------------------------------*/ + +/* + * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY + * INTENDED FOR USE WHEN IMPLEMENTING A PORT OF THE SCHEDULER AND IS + * AN INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER. + * + * Called from the real time kernel tick (either preemptive or cooperative), + * this increments the tick count and checks if any tasks that are blocked + * for a finite period required removing from a blocked list and placing on + * a ready list. If a non-zero value is returned then a context switch is + * required because either: + * + A task was removed from a blocked list because its timeout had expired, + * or + * + Time slicing is in use and there is a task of equal priority to the + * currently running task. + */ +portBASE_TYPE xTaskIncrementTick( void ) PRIVILEGED_FUNCTION; + +/* + * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN + * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER. + * + * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED. + * + * Removes the calling task from the ready list and places it both + * on the list of tasks waiting for a particular event, and the + * list of delayed tasks. The task will be removed from both lists + * and replaced on the ready list should either the event occur (and + * there be no higher priority tasks waiting on the same event) or + * the delay period expires. + * + * @param pxEventList The list containing tasks that are blocked waiting + * for the event to occur. + * + * @param xTicksToWait The maximum amount of time that the task should wait + * for the event to occur. This is specified in kernel ticks,the constant + * portTICK_RATE_MS can be used to convert kernel ticks into a real time + * period. + */ +void vTaskPlaceOnEventList( xList * const pxEventList, portTickType xTicksToWait ) PRIVILEGED_FUNCTION; + +/* + * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN + * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER. + * + * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED. + * + * This function performs nearly the same function as vTaskPlaceOnEventList(). + * The difference being that this function does not permit tasks to block + * indefinitely, whereas vTaskPlaceOnEventList() does. + * + * @return pdTRUE if the task being removed has a higher priority than the task + * making the call, otherwise pdFALSE. + */ +void vTaskPlaceOnEventListRestricted( xList * const pxEventList, portTickType xTicksToWait ) PRIVILEGED_FUNCTION; + +/* + * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN + * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER. + * + * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED. + * + * Removes a task from both the specified event list and the list of blocked + * tasks, and places it on a ready queue. + * + * xTaskRemoveFromEventList () will be called if either an event occurs to + * unblock a task, or the block timeout period expires. + * + * @return pdTRUE if the task being removed has a higher priority than the task + * making the call, otherwise pdFALSE. + */ +signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList ) PRIVILEGED_FUNCTION; + +/* + * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY + * INTENDED FOR USE WHEN IMPLEMENTING A PORT OF THE SCHEDULER AND IS + * AN INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER. + * + * Sets the pointer to the current TCB to the TCB of the highest priority task + * that is ready to run. + */ +void vTaskSwitchContext( void ) PRIVILEGED_FUNCTION; + +/* + * Return the handle of the calling task. + */ +xTaskHandle xTaskGetCurrentTaskHandle( void ) PRIVILEGED_FUNCTION; + +/* + * Capture the current time status for future reference. + */ +void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut ) PRIVILEGED_FUNCTION; + +/* + * Compare the time status now with that previously captured to see if the + * timeout has expired. + */ +portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType * const pxTimeOut, portTickType * const pxTicksToWait ) PRIVILEGED_FUNCTION; + +/* + * Shortcut used by the queue implementation to prevent unnecessary call to + * taskYIELD(); + */ +void vTaskMissedYield( void ) PRIVILEGED_FUNCTION; + +/* + * Returns the scheduler state as taskSCHEDULER_RUNNING, + * taskSCHEDULER_NOT_STARTED or taskSCHEDULER_SUSPENDED. + */ +portBASE_TYPE xTaskGetSchedulerState( void ) PRIVILEGED_FUNCTION; + +/* + * Raises the priority of the mutex holder to that of the calling task should + * the mutex holder have a priority less than the calling task. + */ +void vTaskPriorityInherit( xTaskHandle const pxMutexHolder ) PRIVILEGED_FUNCTION; + +/* + * Set the priority of a task back to its proper priority in the case that it + * inherited a higher priority while it was holding a semaphore. + */ +void vTaskPriorityDisinherit( xTaskHandle const pxMutexHolder ) PRIVILEGED_FUNCTION; + +/* + * Generic version of the task creation function which is in turn called by the + * xTaskCreate() and xTaskCreateRestricted() macros. + */ +signed portBASE_TYPE xTaskGenericCreate( pdTASK_CODE pxTaskCode, const signed char * const pcName, unsigned short usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask, portSTACK_TYPE *puxStackBuffer, const xMemoryRegion * const xRegions ) PRIVILEGED_FUNCTION; + +/* + * Get the uxTCBNumber assigned to the task referenced by the xTask parameter. + */ +unsigned portBASE_TYPE uxTaskGetTaskNumber( xTaskHandle xTask ); + +/* + * Set the uxTCBNumber of the task referenced by the xTask parameter to + * ucHandle. + */ +void vTaskSetTaskNumber( xTaskHandle xTask, unsigned portBASE_TYPE uxHandle ); + +/* + * If tickless mode is being used, or a low power mode is implemented, then + * the tick interrupt will not execute during idle periods. When this is the + * case, the tick count value maintained by the scheduler needs to be kept up + * to date with the actual execution time by being skipped forward by the by + * a time equal to the idle period. + */ +void vTaskStepTick( portTickType xTicksToJump ); + +portTickType prvGetExpectedIdleTime( void ); + +/* + * Provided for use within portSUPPRESS_TICKS_AND_SLEEP() to allow the port + * specific sleep function to determine if it is ok to proceed with the sleep, + * and if it is ok to proceed, if it is ok to sleep indefinitely. + * + * This function is necessary because portSUPPRESS_TICKS_AND_SLEEP() is only + * called with the scheduler suspended, not from within a critical section. It + * is therefore possible for an interrupt to request a context switch between + * portSUPPRESS_TICKS_AND_SLEEP() and the low power mode actually being + * entered. eTaskConfirmSleepModeStatus() should be called from a short + * critical section between the timer being stopped and the sleep mode being + * entered to ensure it is ok to proceed into the sleep mode. + */ +eSleepModeStatus eTaskConfirmSleepModeStatus( void ); + +#ifdef __cplusplus +} +#endif +#endif /* INC_TASK_H */ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/freertos/timers.h b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/timers.h new file mode 100644 index 0000000..5eb2033 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/timers.h @@ -0,0 +1,959 @@ +/* + FreeRTOS V7.5.2 - Copyright (C) 2013 Real Time Engineers Ltd. + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that has become a de facto standard. * + * * + * Help yourself get started quickly and support the FreeRTOS * + * project by purchasing a FreeRTOS tutorial book, reference * + * manual, or both from: http://www.FreeRTOS.org/Documentation * + * * + * Thank you! * + * * + *************************************************************************** + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + >>! NOTE: The modification to the GPL is included to allow you to distribute + >>! a combined work that includes FreeRTOS without being obliged to provide + >>! the source code for proprietary components outside of the FreeRTOS + >>! kernel. + + FreeRTOS 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. Full license text is available from the following + link: http://www.freertos.org/a00114.html + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + + +#ifndef TIMERS_H +#define TIMERS_H + +#ifndef INC_FREERTOS_H + #error "include FreeRTOS.h must appear in source files before include timers.h" +#endif + +/*lint -e537 This headers are only multiply included if the application code +happens to also be including task.h. */ +#include "task.h" +/*lint +e956 */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* IDs for commands that can be sent/received on the timer queue. These are to +be used solely through the macros that make up the public software timer API, +as defined below. */ +#define tmrCOMMAND_START ( ( portBASE_TYPE ) 0 ) +#define tmrCOMMAND_STOP ( ( portBASE_TYPE ) 1 ) +#define tmrCOMMAND_CHANGE_PERIOD ( ( portBASE_TYPE ) 2 ) +#define tmrCOMMAND_DELETE ( ( portBASE_TYPE ) 3 ) + +/*----------------------------------------------------------- + * MACROS AND DEFINITIONS + *----------------------------------------------------------*/ + + /** + * Type by which software timers are referenced. For example, a call to + * xTimerCreate() returns an xTimerHandle variable that can then be used to + * reference the subject timer in calls to other software timer API functions + * (for example, xTimerStart(), xTimerReset(), etc.). + */ +typedef void * xTimerHandle; + +/* Define the prototype to which timer callback functions must conform. */ +typedef void (*tmrTIMER_CALLBACK)( xTimerHandle xTimer ); + +/** + * xTimerHandle xTimerCreate( const signed char *pcTimerName, + * portTickType xTimerPeriodInTicks, + * unsigned portBASE_TYPE uxAutoReload, + * void * pvTimerID, + * tmrTIMER_CALLBACK pxCallbackFunction ); + * + * Creates a new software timer instance. This allocates the storage required + * by the new timer, initialises the new timers internal state, and returns a + * handle by which the new timer can be referenced. + * + * Timers are created in the dormant state. The xTimerStart(), xTimerReset(), + * xTimerStartFromISR(), xTimerResetFromISR(), xTimerChangePeriod() and + * xTimerChangePeriodFromISR() API functions can all be used to transition a timer into the + * active state. + * + * @param pcTimerName A text name that is assigned to the timer. This is done + * purely to assist debugging. The kernel itself only ever references a timer by + * its handle, and never by its name. + * + * @param xTimerPeriodInTicks The timer period. The time is defined in tick periods so + * the constant portTICK_RATE_MS can be used to convert a time that has been + * specified in milliseconds. For example, if the timer must expire after 100 + * ticks, then xTimerPeriodInTicks should be set to 100. Alternatively, if the timer + * must expire after 500ms, then xPeriod can be set to ( 500 / portTICK_RATE_MS ) + * provided configTICK_RATE_HZ is less than or equal to 1000. + * + * @param uxAutoReload If uxAutoReload is set to pdTRUE then the timer will + * expire repeatedly with a frequency set by the xTimerPeriodInTicks parameter. If + * uxAutoReload is set to pdFALSE then the timer will be a one-shot timer and + * enter the dormant state after it expires. + * + * @param pvTimerID An identifier that is assigned to the timer being created. + * Typically this would be used in the timer callback function to identify which + * timer expired when the same callback function is assigned to more than one + * timer. + * + * @param pxCallbackFunction The function to call when the timer expires. + * Callback functions must have the prototype defined by tmrTIMER_CALLBACK, + * which is "void vCallbackFunction( xTimerHandle xTimer );". + * + * @return If the timer is successfully create then a handle to the newly + * created timer is returned. If the timer cannot be created (because either + * there is insufficient FreeRTOS heap remaining to allocate the timer + * structures, or the timer period was set to 0) then 0 is returned. + * + * Example usage: + * @verbatim + * #define NUM_TIMERS 5 + * + * // An array to hold handles to the created timers. + * xTimerHandle xTimers[ NUM_TIMERS ]; + * + * // An array to hold a count of the number of times each timer expires. + * long lExpireCounters[ NUM_TIMERS ] = { 0 }; + * + * // Define a callback function that will be used by multiple timer instances. + * // The callback function does nothing but count the number of times the + * // associated timer expires, and stop the timer once the timer has expired + * // 10 times. + * void vTimerCallback( xTimerHandle pxTimer ) + * { + * long lArrayIndex; + * const long xMaxExpiryCountBeforeStopping = 10; + * + * // Optionally do something if the pxTimer parameter is NULL. + * configASSERT( pxTimer ); + * + * // Which timer expired? + * lArrayIndex = ( long ) pvTimerGetTimerID( pxTimer ); + * + * // Increment the number of times that pxTimer has expired. + * lExpireCounters[ lArrayIndex ] += 1; + * + * // If the timer has expired 10 times then stop it from running. + * if( lExpireCounters[ lArrayIndex ] == xMaxExpiryCountBeforeStopping ) + * { + * // Do not use a block time if calling a timer API function from a + * // timer callback function, as doing so could cause a deadlock! + * xTimerStop( pxTimer, 0 ); + * } + * } + * + * void main( void ) + * { + * long x; + * + * // Create then start some timers. Starting the timers before the scheduler + * // has been started means the timers will start running immediately that + * // the scheduler starts. + * for( x = 0; x < NUM_TIMERS; x++ ) + * { + * xTimers[ x ] = xTimerCreate( "Timer", // Just a text name, not used by the kernel. + * ( 100 * x ), // The timer period in ticks. + * pdTRUE, // The timers will auto-reload themselves when they expire. + * ( void * ) x, // Assign each timer a unique id equal to its array index. + * vTimerCallback // Each timer calls the same callback when it expires. + * ); + * + * if( xTimers[ x ] == NULL ) + * { + * // The timer was not created. + * } + * else + * { + * // Start the timer. No block time is specified, and even if one was + * // it would be ignored because the scheduler has not yet been + * // started. + * if( xTimerStart( xTimers[ x ], 0 ) != pdPASS ) + * { + * // The timer could not be set into the Active state. + * } + * } + * } + * + * // ... + * // Create tasks here. + * // ... + * + * // Starting the scheduler will start the timers running as they have already + * // been set into the active state. + * xTaskStartScheduler(); + * + * // Should not reach here. + * for( ;; ); + * } + * @endverbatim + */ +xTimerHandle xTimerCreate( const signed char * const pcTimerName, portTickType xTimerPeriodInTicks, unsigned portBASE_TYPE uxAutoReload, void * pvTimerID, tmrTIMER_CALLBACK pxCallbackFunction ) PRIVILEGED_FUNCTION; + +/** + * void *pvTimerGetTimerID( xTimerHandle xTimer ); + * + * Returns the ID assigned to the timer. + * + * IDs are assigned to timers using the pvTimerID parameter of the call to + * xTimerCreated() that was used to create the timer. + * + * If the same callback function is assigned to multiple timers then the timer + * ID can be used within the callback function to identify which timer actually + * expired. + * + * @param xTimer The timer being queried. + * + * @return The ID assigned to the timer being queried. + * + * Example usage: + * + * See the xTimerCreate() API function example usage scenario. + */ +void *pvTimerGetTimerID( xTimerHandle xTimer ) PRIVILEGED_FUNCTION; + +/** + * portBASE_TYPE xTimerIsTimerActive( xTimerHandle xTimer ); + * + * Queries a timer to see if it is active or dormant. + * + * A timer will be dormant if: + * 1) It has been created but not started, or + * 2) It is an expired on-shot timer that has not been restarted. + * + * Timers are created in the dormant state. The xTimerStart(), xTimerReset(), + * xTimerStartFromISR(), xTimerResetFromISR(), xTimerChangePeriod() and + * xTimerChangePeriodFromISR() API functions can all be used to transition a timer into the + * active state. + * + * @param xTimer The timer being queried. + * + * @return pdFALSE will be returned if the timer is dormant. A value other than + * pdFALSE will be returned if the timer is active. + * + * Example usage: + * @verbatim + * // This function assumes xTimer has already been created. + * void vAFunction( xTimerHandle xTimer ) + * { + * if( xTimerIsTimerActive( xTimer ) != pdFALSE ) // or more simply and equivalently "if( xTimerIsTimerActive( xTimer ) )" + * { + * // xTimer is active, do something. + * } + * else + * { + * // xTimer is not active, do something else. + * } + * } + * @endverbatim + */ +portBASE_TYPE xTimerIsTimerActive( xTimerHandle xTimer ) PRIVILEGED_FUNCTION; + +/** + * xTimerGetTimerDaemonTaskHandle() is only available if + * INCLUDE_xTimerGetTimerDaemonTaskHandle is set to 1 in FreeRTOSConfig.h. + * + * Simply returns the handle of the timer service/daemon task. It it not valid + * to call xTimerGetTimerDaemonTaskHandle() before the scheduler has been started. + */ +xTaskHandle xTimerGetTimerDaemonTaskHandle( void ); + +/** + * portBASE_TYPE xTimerStart( xTimerHandle xTimer, portTickType xBlockTime ); + * + * Timer functionality is provided by a timer service/daemon task. Many of the + * public FreeRTOS timer API functions send commands to the timer service task + * though a queue called the timer command queue. The timer command queue is + * private to the kernel itself and is not directly accessible to application + * code. The length of the timer command queue is set by the + * configTIMER_QUEUE_LENGTH configuration constant. + * + * xTimerStart() starts a timer that was previously created using the + * xTimerCreate() API function. If the timer had already been started and was + * already in the active state, then xTimerStart() has equivalent functionality + * to the xTimerReset() API function. + * + * Starting a timer ensures the timer is in the active state. If the timer + * is not stopped, deleted, or reset in the mean time, the callback function + * associated with the timer will get called 'n' ticks after xTimerStart() was + * called, where 'n' is the timers defined period. + * + * It is valid to call xTimerStart() before the scheduler has been started, but + * when this is done the timer will not actually start until the scheduler is + * started, and the timers expiry time will be relative to when the scheduler is + * started, not relative to when xTimerStart() was called. + * + * The configUSE_TIMERS configuration constant must be set to 1 for xTimerStart() + * to be available. + * + * @param xTimer The handle of the timer being started/restarted. + * + * @param xBlockTime Specifies the time, in ticks, that the calling task should + * be held in the Blocked state to wait for the start command to be successfully + * sent to the timer command queue, should the queue already be full when + * xTimerStart() was called. xBlockTime is ignored if xTimerStart() is called + * before the scheduler is started. + * + * @return pdFAIL will be returned if the start command could not be sent to + * the timer command queue even after xBlockTime ticks had passed. pdPASS will + * be returned if the command was successfully sent to the timer command queue. + * When the command is actually processed will depend on the priority of the + * timer service/daemon task relative to other tasks in the system, although the + * timers expiry time is relative to when xTimerStart() is actually called. The + * timer service/daemon task priority is set by the configTIMER_TASK_PRIORITY + * configuration constant. + * + * Example usage: + * + * See the xTimerCreate() API function example usage scenario. + * + */ +#define xTimerStart( xTimer, xBlockTime ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCount() ), NULL, ( xBlockTime ) ) + +/** + * portBASE_TYPE xTimerStop( xTimerHandle xTimer, portTickType xBlockTime ); + * + * Timer functionality is provided by a timer service/daemon task. Many of the + * public FreeRTOS timer API functions send commands to the timer service task + * though a queue called the timer command queue. The timer command queue is + * private to the kernel itself and is not directly accessible to application + * code. The length of the timer command queue is set by the + * configTIMER_QUEUE_LENGTH configuration constant. + * + * xTimerStop() stops a timer that was previously started using either of the + * The xTimerStart(), xTimerReset(), xTimerStartFromISR(), xTimerResetFromISR(), + * xTimerChangePeriod() or xTimerChangePeriodFromISR() API functions. + * + * Stopping a timer ensures the timer is not in the active state. + * + * The configUSE_TIMERS configuration constant must be set to 1 for xTimerStop() + * to be available. + * + * @param xTimer The handle of the timer being stopped. + * + * @param xBlockTime Specifies the time, in ticks, that the calling task should + * be held in the Blocked state to wait for the stop command to be successfully + * sent to the timer command queue, should the queue already be full when + * xTimerStop() was called. xBlockTime is ignored if xTimerStop() is called + * before the scheduler is started. + * + * @return pdFAIL will be returned if the stop command could not be sent to + * the timer command queue even after xBlockTime ticks had passed. pdPASS will + * be returned if the command was successfully sent to the timer command queue. + * When the command is actually processed will depend on the priority of the + * timer service/daemon task relative to other tasks in the system. The timer + * service/daemon task priority is set by the configTIMER_TASK_PRIORITY + * configuration constant. + * + * Example usage: + * + * See the xTimerCreate() API function example usage scenario. + * + */ +#define xTimerStop( xTimer, xBlockTime ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_STOP, 0U, NULL, ( xBlockTime ) ) + +/** + * portBASE_TYPE xTimerChangePeriod( xTimerHandle xTimer, + * portTickType xNewPeriod, + * portTickType xBlockTime ); + * + * Timer functionality is provided by a timer service/daemon task. Many of the + * public FreeRTOS timer API functions send commands to the timer service task + * though a queue called the timer command queue. The timer command queue is + * private to the kernel itself and is not directly accessible to application + * code. The length of the timer command queue is set by the + * configTIMER_QUEUE_LENGTH configuration constant. + * + * xTimerChangePeriod() changes the period of a timer that was previously + * created using the xTimerCreate() API function. + * + * xTimerChangePeriod() can be called to change the period of an active or + * dormant state timer. + * + * The configUSE_TIMERS configuration constant must be set to 1 for + * xTimerChangePeriod() to be available. + * + * @param xTimer The handle of the timer that is having its period changed. + * + * @param xNewPeriod The new period for xTimer. Timer periods are specified in + * tick periods, so the constant portTICK_RATE_MS can be used to convert a time + * that has been specified in milliseconds. For example, if the timer must + * expire after 100 ticks, then xNewPeriod should be set to 100. Alternatively, + * if the timer must expire after 500ms, then xNewPeriod can be set to + * ( 500 / portTICK_RATE_MS ) provided configTICK_RATE_HZ is less than + * or equal to 1000. + * + * @param xBlockTime Specifies the time, in ticks, that the calling task should + * be held in the Blocked state to wait for the change period command to be + * successfully sent to the timer command queue, should the queue already be + * full when xTimerChangePeriod() was called. xBlockTime is ignored if + * xTimerChangePeriod() is called before the scheduler is started. + * + * @return pdFAIL will be returned if the change period command could not be + * sent to the timer command queue even after xBlockTime ticks had passed. + * pdPASS will be returned if the command was successfully sent to the timer + * command queue. When the command is actually processed will depend on the + * priority of the timer service/daemon task relative to other tasks in the + * system. The timer service/daemon task priority is set by the + * configTIMER_TASK_PRIORITY configuration constant. + * + * Example usage: + * @verbatim + * // This function assumes xTimer has already been created. If the timer + * // referenced by xTimer is already active when it is called, then the timer + * // is deleted. If the timer referenced by xTimer is not active when it is + * // called, then the period of the timer is set to 500ms and the timer is + * // started. + * void vAFunction( xTimerHandle xTimer ) + * { + * if( xTimerIsTimerActive( xTimer ) != pdFALSE ) // or more simply and equivalently "if( xTimerIsTimerActive( xTimer ) )" + * { + * // xTimer is already active - delete it. + * xTimerDelete( xTimer ); + * } + * else + * { + * // xTimer is not active, change its period to 500ms. This will also + * // cause the timer to start. Block for a maximum of 100 ticks if the + * // change period command cannot immediately be sent to the timer + * // command queue. + * if( xTimerChangePeriod( xTimer, 500 / portTICK_RATE_MS, 100 ) == pdPASS ) + * { + * // The command was successfully sent. + * } + * else + * { + * // The command could not be sent, even after waiting for 100 ticks + * // to pass. Take appropriate action here. + * } + * } + * } + * @endverbatim + */ + #define xTimerChangePeriod( xTimer, xNewPeriod, xBlockTime ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_CHANGE_PERIOD, ( xNewPeriod ), NULL, ( xBlockTime ) ) + +/** + * portBASE_TYPE xTimerDelete( xTimerHandle xTimer, portTickType xBlockTime ); + * + * Timer functionality is provided by a timer service/daemon task. Many of the + * public FreeRTOS timer API functions send commands to the timer service task + * though a queue called the timer command queue. The timer command queue is + * private to the kernel itself and is not directly accessible to application + * code. The length of the timer command queue is set by the + * configTIMER_QUEUE_LENGTH configuration constant. + * + * xTimerDelete() deletes a timer that was previously created using the + * xTimerCreate() API function. + * + * The configUSE_TIMERS configuration constant must be set to 1 for + * xTimerDelete() to be available. + * + * @param xTimer The handle of the timer being deleted. + * + * @param xBlockTime Specifies the time, in ticks, that the calling task should + * be held in the Blocked state to wait for the delete command to be + * successfully sent to the timer command queue, should the queue already be + * full when xTimerDelete() was called. xBlockTime is ignored if xTimerDelete() + * is called before the scheduler is started. + * + * @return pdFAIL will be returned if the delete command could not be sent to + * the timer command queue even after xBlockTime ticks had passed. pdPASS will + * be returned if the command was successfully sent to the timer command queue. + * When the command is actually processed will depend on the priority of the + * timer service/daemon task relative to other tasks in the system. The timer + * service/daemon task priority is set by the configTIMER_TASK_PRIORITY + * configuration constant. + * + * Example usage: + * + * See the xTimerChangePeriod() API function example usage scenario. + */ +#define xTimerDelete( xTimer, xBlockTime ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_DELETE, 0U, NULL, ( xBlockTime ) ) + +/** + * portBASE_TYPE xTimerReset( xTimerHandle xTimer, portTickType xBlockTime ); + * + * Timer functionality is provided by a timer service/daemon task. Many of the + * public FreeRTOS timer API functions send commands to the timer service task + * though a queue called the timer command queue. The timer command queue is + * private to the kernel itself and is not directly accessible to application + * code. The length of the timer command queue is set by the + * configTIMER_QUEUE_LENGTH configuration constant. + * + * xTimerReset() re-starts a timer that was previously created using the + * xTimerCreate() API function. If the timer had already been started and was + * already in the active state, then xTimerReset() will cause the timer to + * re-evaluate its expiry time so that it is relative to when xTimerReset() was + * called. If the timer was in the dormant state then xTimerReset() has + * equivalent functionality to the xTimerStart() API function. + * + * Resetting a timer ensures the timer is in the active state. If the timer + * is not stopped, deleted, or reset in the mean time, the callback function + * associated with the timer will get called 'n' ticks after xTimerReset() was + * called, where 'n' is the timers defined period. + * + * It is valid to call xTimerReset() before the scheduler has been started, but + * when this is done the timer will not actually start until the scheduler is + * started, and the timers expiry time will be relative to when the scheduler is + * started, not relative to when xTimerReset() was called. + * + * The configUSE_TIMERS configuration constant must be set to 1 for xTimerReset() + * to be available. + * + * @param xTimer The handle of the timer being reset/started/restarted. + * + * @param xBlockTime Specifies the time, in ticks, that the calling task should + * be held in the Blocked state to wait for the reset command to be successfully + * sent to the timer command queue, should the queue already be full when + * xTimerReset() was called. xBlockTime is ignored if xTimerReset() is called + * before the scheduler is started. + * + * @return pdFAIL will be returned if the reset command could not be sent to + * the timer command queue even after xBlockTime ticks had passed. pdPASS will + * be returned if the command was successfully sent to the timer command queue. + * When the command is actually processed will depend on the priority of the + * timer service/daemon task relative to other tasks in the system, although the + * timers expiry time is relative to when xTimerStart() is actually called. The + * timer service/daemon task priority is set by the configTIMER_TASK_PRIORITY + * configuration constant. + * + * Example usage: + * @verbatim + * // When a key is pressed, an LCD back-light is switched on. If 5 seconds pass + * // without a key being pressed, then the LCD back-light is switched off. In + * // this case, the timer is a one-shot timer. + * + * xTimerHandle xBacklightTimer = NULL; + * + * // The callback function assigned to the one-shot timer. In this case the + * // parameter is not used. + * void vBacklightTimerCallback( xTimerHandle pxTimer ) + * { + * // The timer expired, therefore 5 seconds must have passed since a key + * // was pressed. Switch off the LCD back-light. + * vSetBacklightState( BACKLIGHT_OFF ); + * } + * + * // The key press event handler. + * void vKeyPressEventHandler( char cKey ) + * { + * // Ensure the LCD back-light is on, then reset the timer that is + * // responsible for turning the back-light off after 5 seconds of + * // key inactivity. Wait 10 ticks for the command to be successfully sent + * // if it cannot be sent immediately. + * vSetBacklightState( BACKLIGHT_ON ); + * if( xTimerReset( xBacklightTimer, 100 ) != pdPASS ) + * { + * // The reset command was not executed successfully. Take appropriate + * // action here. + * } + * + * // Perform the rest of the key processing here. + * } + * + * void main( void ) + * { + * long x; + * + * // Create then start the one-shot timer that is responsible for turning + * // the back-light off if no keys are pressed within a 5 second period. + * xBacklightTimer = xTimerCreate( "BacklightTimer", // Just a text name, not used by the kernel. + * ( 5000 / portTICK_RATE_MS), // The timer period in ticks. + * pdFALSE, // The timer is a one-shot timer. + * 0, // The id is not used by the callback so can take any value. + * vBacklightTimerCallback // The callback function that switches the LCD back-light off. + * ); + * + * if( xBacklightTimer == NULL ) + * { + * // The timer was not created. + * } + * else + * { + * // Start the timer. No block time is specified, and even if one was + * // it would be ignored because the scheduler has not yet been + * // started. + * if( xTimerStart( xBacklightTimer, 0 ) != pdPASS ) + * { + * // The timer could not be set into the Active state. + * } + * } + * + * // ... + * // Create tasks here. + * // ... + * + * // Starting the scheduler will start the timer running as it has already + * // been set into the active state. + * xTaskStartScheduler(); + * + * // Should not reach here. + * for( ;; ); + * } + * @endverbatim + */ +#define xTimerReset( xTimer, xBlockTime ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCount() ), NULL, ( xBlockTime ) ) + +/** + * portBASE_TYPE xTimerStartFromISR( xTimerHandle xTimer, + * portBASE_TYPE *pxHigherPriorityTaskWoken ); + * + * A version of xTimerStart() that can be called from an interrupt service + * routine. + * + * @param xTimer The handle of the timer being started/restarted. + * + * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most + * of its time in the Blocked state, waiting for messages to arrive on the timer + * command queue. Calling xTimerStartFromISR() writes a message to the timer + * command queue, so has the potential to transition the timer service/daemon + * task out of the Blocked state. If calling xTimerStartFromISR() causes the + * timer service/daemon task to leave the Blocked state, and the timer service/ + * daemon task has a priority equal to or greater than the currently executing + * task (the task that was interrupted), then *pxHigherPriorityTaskWoken will + * get set to pdTRUE internally within the xTimerStartFromISR() function. If + * xTimerStartFromISR() sets this value to pdTRUE then a context switch should + * be performed before the interrupt exits. + * + * @return pdFAIL will be returned if the start command could not be sent to + * the timer command queue. pdPASS will be returned if the command was + * successfully sent to the timer command queue. When the command is actually + * processed will depend on the priority of the timer service/daemon task + * relative to other tasks in the system, although the timers expiry time is + * relative to when xTimerStartFromISR() is actually called. The timer service/daemon + * task priority is set by the configTIMER_TASK_PRIORITY configuration constant. + * + * Example usage: + * @verbatim + * // This scenario assumes xBacklightTimer has already been created. When a + * // key is pressed, an LCD back-light is switched on. If 5 seconds pass + * // without a key being pressed, then the LCD back-light is switched off. In + * // this case, the timer is a one-shot timer, and unlike the example given for + * // the xTimerReset() function, the key press event handler is an interrupt + * // service routine. + * + * // The callback function assigned to the one-shot timer. In this case the + * // parameter is not used. + * void vBacklightTimerCallback( xTimerHandle pxTimer ) + * { + * // The timer expired, therefore 5 seconds must have passed since a key + * // was pressed. Switch off the LCD back-light. + * vSetBacklightState( BACKLIGHT_OFF ); + * } + * + * // The key press interrupt service routine. + * void vKeyPressEventInterruptHandler( void ) + * { + * portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; + * + * // Ensure the LCD back-light is on, then restart the timer that is + * // responsible for turning the back-light off after 5 seconds of + * // key inactivity. This is an interrupt service routine so can only + * // call FreeRTOS API functions that end in "FromISR". + * vSetBacklightState( BACKLIGHT_ON ); + * + * // xTimerStartFromISR() or xTimerResetFromISR() could be called here + * // as both cause the timer to re-calculate its expiry time. + * // xHigherPriorityTaskWoken was initialised to pdFALSE when it was + * // declared (in this function). + * if( xTimerStartFromISR( xBacklightTimer, &xHigherPriorityTaskWoken ) != pdPASS ) + * { + * // The start command was not executed successfully. Take appropriate + * // action here. + * } + * + * // Perform the rest of the key processing here. + * + * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch + * // should be performed. The syntax required to perform a context switch + * // from inside an ISR varies from port to port, and from compiler to + * // compiler. Inspect the demos for the port you are using to find the + * // actual syntax required. + * if( xHigherPriorityTaskWoken != pdFALSE ) + * { + * // Call the interrupt safe yield function here (actual function + * // depends on the FreeRTOS port being used. + * } + * } + * @endverbatim + */ +#define xTimerStartFromISR( xTimer, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCountFromISR() ), ( pxHigherPriorityTaskWoken ), 0U ) + +/** + * portBASE_TYPE xTimerStopFromISR( xTimerHandle xTimer, + * portBASE_TYPE *pxHigherPriorityTaskWoken ); + * + * A version of xTimerStop() that can be called from an interrupt service + * routine. + * + * @param xTimer The handle of the timer being stopped. + * + * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most + * of its time in the Blocked state, waiting for messages to arrive on the timer + * command queue. Calling xTimerStopFromISR() writes a message to the timer + * command queue, so has the potential to transition the timer service/daemon + * task out of the Blocked state. If calling xTimerStopFromISR() causes the + * timer service/daemon task to leave the Blocked state, and the timer service/ + * daemon task has a priority equal to or greater than the currently executing + * task (the task that was interrupted), then *pxHigherPriorityTaskWoken will + * get set to pdTRUE internally within the xTimerStopFromISR() function. If + * xTimerStopFromISR() sets this value to pdTRUE then a context switch should + * be performed before the interrupt exits. + * + * @return pdFAIL will be returned if the stop command could not be sent to + * the timer command queue. pdPASS will be returned if the command was + * successfully sent to the timer command queue. When the command is actually + * processed will depend on the priority of the timer service/daemon task + * relative to other tasks in the system. The timer service/daemon task + * priority is set by the configTIMER_TASK_PRIORITY configuration constant. + * + * Example usage: + * @verbatim + * // This scenario assumes xTimer has already been created and started. When + * // an interrupt occurs, the timer should be simply stopped. + * + * // The interrupt service routine that stops the timer. + * void vAnExampleInterruptServiceRoutine( void ) + * { + * portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; + * + * // The interrupt has occurred - simply stop the timer. + * // xHigherPriorityTaskWoken was set to pdFALSE where it was defined + * // (within this function). As this is an interrupt service routine, only + * // FreeRTOS API functions that end in "FromISR" can be used. + * if( xTimerStopFromISR( xTimer, &xHigherPriorityTaskWoken ) != pdPASS ) + * { + * // The stop command was not executed successfully. Take appropriate + * // action here. + * } + * + * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch + * // should be performed. The syntax required to perform a context switch + * // from inside an ISR varies from port to port, and from compiler to + * // compiler. Inspect the demos for the port you are using to find the + * // actual syntax required. + * if( xHigherPriorityTaskWoken != pdFALSE ) + * { + * // Call the interrupt safe yield function here (actual function + * // depends on the FreeRTOS port being used. + * } + * } + * @endverbatim + */ +#define xTimerStopFromISR( xTimer, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_STOP, 0, ( pxHigherPriorityTaskWoken ), 0U ) + +/** + * portBASE_TYPE xTimerChangePeriodFromISR( xTimerHandle xTimer, + * portTickType xNewPeriod, + * portBASE_TYPE *pxHigherPriorityTaskWoken ); + * + * A version of xTimerChangePeriod() that can be called from an interrupt + * service routine. + * + * @param xTimer The handle of the timer that is having its period changed. + * + * @param xNewPeriod The new period for xTimer. Timer periods are specified in + * tick periods, so the constant portTICK_RATE_MS can be used to convert a time + * that has been specified in milliseconds. For example, if the timer must + * expire after 100 ticks, then xNewPeriod should be set to 100. Alternatively, + * if the timer must expire after 500ms, then xNewPeriod can be set to + * ( 500 / portTICK_RATE_MS ) provided configTICK_RATE_HZ is less than + * or equal to 1000. + * + * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most + * of its time in the Blocked state, waiting for messages to arrive on the timer + * command queue. Calling xTimerChangePeriodFromISR() writes a message to the + * timer command queue, so has the potential to transition the timer service/ + * daemon task out of the Blocked state. If calling xTimerChangePeriodFromISR() + * causes the timer service/daemon task to leave the Blocked state, and the + * timer service/daemon task has a priority equal to or greater than the + * currently executing task (the task that was interrupted), then + * *pxHigherPriorityTaskWoken will get set to pdTRUE internally within the + * xTimerChangePeriodFromISR() function. If xTimerChangePeriodFromISR() sets + * this value to pdTRUE then a context switch should be performed before the + * interrupt exits. + * + * @return pdFAIL will be returned if the command to change the timers period + * could not be sent to the timer command queue. pdPASS will be returned if the + * command was successfully sent to the timer command queue. When the command + * is actually processed will depend on the priority of the timer service/daemon + * task relative to other tasks in the system. The timer service/daemon task + * priority is set by the configTIMER_TASK_PRIORITY configuration constant. + * + * Example usage: + * @verbatim + * // This scenario assumes xTimer has already been created and started. When + * // an interrupt occurs, the period of xTimer should be changed to 500ms. + * + * // The interrupt service routine that changes the period of xTimer. + * void vAnExampleInterruptServiceRoutine( void ) + * { + * portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; + * + * // The interrupt has occurred - change the period of xTimer to 500ms. + * // xHigherPriorityTaskWoken was set to pdFALSE where it was defined + * // (within this function). As this is an interrupt service routine, only + * // FreeRTOS API functions that end in "FromISR" can be used. + * if( xTimerChangePeriodFromISR( xTimer, &xHigherPriorityTaskWoken ) != pdPASS ) + * { + * // The command to change the timers period was not executed + * // successfully. Take appropriate action here. + * } + * + * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch + * // should be performed. The syntax required to perform a context switch + * // from inside an ISR varies from port to port, and from compiler to + * // compiler. Inspect the demos for the port you are using to find the + * // actual syntax required. + * if( xHigherPriorityTaskWoken != pdFALSE ) + * { + * // Call the interrupt safe yield function here (actual function + * // depends on the FreeRTOS port being used. + * } + * } + * @endverbatim + */ +#define xTimerChangePeriodFromISR( xTimer, xNewPeriod, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_CHANGE_PERIOD, ( xNewPeriod ), ( pxHigherPriorityTaskWoken ), 0U ) + +/** + * portBASE_TYPE xTimerResetFromISR( xTimerHandle xTimer, + * portBASE_TYPE *pxHigherPriorityTaskWoken ); + * + * A version of xTimerReset() that can be called from an interrupt service + * routine. + * + * @param xTimer The handle of the timer that is to be started, reset, or + * restarted. + * + * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most + * of its time in the Blocked state, waiting for messages to arrive on the timer + * command queue. Calling xTimerResetFromISR() writes a message to the timer + * command queue, so has the potential to transition the timer service/daemon + * task out of the Blocked state. If calling xTimerResetFromISR() causes the + * timer service/daemon task to leave the Blocked state, and the timer service/ + * daemon task has a priority equal to or greater than the currently executing + * task (the task that was interrupted), then *pxHigherPriorityTaskWoken will + * get set to pdTRUE internally within the xTimerResetFromISR() function. If + * xTimerResetFromISR() sets this value to pdTRUE then a context switch should + * be performed before the interrupt exits. + * + * @return pdFAIL will be returned if the reset command could not be sent to + * the timer command queue. pdPASS will be returned if the command was + * successfully sent to the timer command queue. When the command is actually + * processed will depend on the priority of the timer service/daemon task + * relative to other tasks in the system, although the timers expiry time is + * relative to when xTimerResetFromISR() is actually called. The timer service/daemon + * task priority is set by the configTIMER_TASK_PRIORITY configuration constant. + * + * Example usage: + * @verbatim + * // This scenario assumes xBacklightTimer has already been created. When a + * // key is pressed, an LCD back-light is switched on. If 5 seconds pass + * // without a key being pressed, then the LCD back-light is switched off. In + * // this case, the timer is a one-shot timer, and unlike the example given for + * // the xTimerReset() function, the key press event handler is an interrupt + * // service routine. + * + * // The callback function assigned to the one-shot timer. In this case the + * // parameter is not used. + * void vBacklightTimerCallback( xTimerHandle pxTimer ) + * { + * // The timer expired, therefore 5 seconds must have passed since a key + * // was pressed. Switch off the LCD back-light. + * vSetBacklightState( BACKLIGHT_OFF ); + * } + * + * // The key press interrupt service routine. + * void vKeyPressEventInterruptHandler( void ) + * { + * portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; + * + * // Ensure the LCD back-light is on, then reset the timer that is + * // responsible for turning the back-light off after 5 seconds of + * // key inactivity. This is an interrupt service routine so can only + * // call FreeRTOS API functions that end in "FromISR". + * vSetBacklightState( BACKLIGHT_ON ); + * + * // xTimerStartFromISR() or xTimerResetFromISR() could be called here + * // as both cause the timer to re-calculate its expiry time. + * // xHigherPriorityTaskWoken was initialised to pdFALSE when it was + * // declared (in this function). + * if( xTimerResetFromISR( xBacklightTimer, &xHigherPriorityTaskWoken ) != pdPASS ) + * { + * // The reset command was not executed successfully. Take appropriate + * // action here. + * } + * + * // Perform the rest of the key processing here. + * + * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch + * // should be performed. The syntax required to perform a context switch + * // from inside an ISR varies from port to port, and from compiler to + * // compiler. Inspect the demos for the port you are using to find the + * // actual syntax required. + * if( xHigherPriorityTaskWoken != pdFALSE ) + * { + * // Call the interrupt safe yield function here (actual function + * // depends on the FreeRTOS port being used. + * } + * } + * @endverbatim + */ +#define xTimerResetFromISR( xTimer, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCountFromISR() ), ( pxHigherPriorityTaskWoken ), 0U ) + +/* + * Functions beyond this part are not part of the public API and are intended + * for use by the kernel only. + */ +portBASE_TYPE xTimerCreateTimerTask( void ) PRIVILEGED_FUNCTION; +portBASE_TYPE xTimerGenericCommand( xTimerHandle xTimer, portBASE_TYPE xCommandID, portTickType xOptionalValue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portTickType xBlockTime ) PRIVILEGED_FUNCTION; + +#ifdef __cplusplus +} +#endif +#endif /* TIMERS_H */ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/freertos/xtensa_context.h b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/xtensa_context.h new file mode 100644 index 0000000..1ea12b9 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/xtensa_context.h @@ -0,0 +1,278 @@ +/******************************************************************************* +Copyright (c) 2006-2008 by Tensilica Inc. ALL RIGHTS RESERVED. +These coded instructions, statements, and computer programs are the +copyrighted works and confidential proprietary information of Tensilica Inc. +They may not be modified, copied, reproduced, distributed, or disclosed to +third parties in any manner, medium, or form, in whole or in part, without +the prior written consent of Tensilica Inc. +-------------------------------------------------------------------------------- + + XTENSA CONTEXT FRAMES AND MACROS FOR RTOS ASSEMBLER SOURCES + +This header contains definitions and macros for use primarily by Xtensa +RTOS assembly coded source files. It includes and uses the Xtensa hardware +abstraction layer (HAL) to deal with config specifics. It may also be +included in C source files. + +!! Supports only Xtensa Exception Architecture 2 (XEA2). XEA1 not supported. !! + +NOTE: The Xtensa architecture requires stack pointer alignment to 16 bytes. + +*******************************************************************************/ + +#ifndef XTENSA_CONTEXT_H +#define XTENSA_CONTEXT_H + +#ifdef __ASSEMBLER__ +#include +#endif + +#include +#include +#include + + +/* +Align a value up to nearest n-byte boundary, where n is a power of 2. +*/ +#define ALIGNUP(n, val) (((val) + (n)-1) & -(n)) + + +/******************************************************************************* + +INTERRUPT STACK FRAME FOR A THREAD OR NESTED INTERRUPT + +A stack frame of this structure is allocated for any interrupt or exception. +It goes on the current stack. If the RTOS has a system stack for handling +interrupts, every thread stack must allow space for just one interrupt stack +frame, then nested interrupt stack frames go on the system stack. + +The frame includes basic registers (explicit) and "extra" registers introduced +by user TIE or the use of the MAC16 option in the user's Xtensa config. +The frame size is minimized by omitting regs not applicable to user's config. + +For Windowed ABI, this stack frame includes the interruptee's base save area, +another base save area to manage gcc nested functions, and a little temporary +space to help manage the spilling of the register windows. + +*******************************************************************************/ + +#define XT_STK_EXIT 0x00 /* (offset 0) exit point for dispatch */ +#define XT_STK_PC 0x04 /* return address */ +#define XT_STK_PS 0x08 /* at level 1 PS.EXCM is set here */ +#define XT_STK_A0 0x0C +#define XT_STK_A1 0x10 /* stack ptr before interrupt */ +#define XT_STK_A2 0x14 +#define XT_STK_A3 0x18 +#define XT_STK_A4 0x1C +#define XT_STK_A5 0x20 +#define XT_STK_A6 0x24 +#define XT_STK_A7 0x28 +#define XT_STK_A8 0x2C +#define XT_STK_A9 0x30 +#define XT_STK_A10 0x34 +#define XT_STK_A11 0x38 +#define XT_STK_A12 0x3C /* Call0 callee-save */ +#define XT_STK_A13 0x40 /* Call0 callee-save */ +#define XT_STK_A14 0x44 /* Call0 callee-save */ +#define XT_STK_A15 0x48 /* Call0 callee-save */ +#define XT_STK_SAR 0x4C + +#if XCHAL_HAVE_LOOPS +#define XT_STK_LBEG 0x50 +#define XT_STK_LEND 0x54 +#define XT_STK_LCOUNT 0x58 +#define XT_STK_NEXT1 0x5C /* next unused offset */ +#else +#define XT_STK_NEXT1 0x50 /* next unused offset */ +#endif + /* there may be some unused space here */ +#if XCHAL_EXTRA_SA_SIZE != 0 +#define XT_STK_EXTRA ALIGNUP(XCHAL_EXTRA_SA_ALIGN, XT_STK_NEXT1) + +#define XT_STK_NEXT2 (XT_STK_EXTRA + XCHAL_EXTRA_SA_SIZE) +#else +#define XT_STK_NEXT2 XT_STK_NEXT1 +#endif + /* next unused offset */ + /* there may be some unused space here */ +#ifdef __XTENSA_CALL0_ABI__ +/* Call0 - no more stack frame needed */ +#define XT_STK_FRMSZ ALIGNUP(0x10, XT_STK_NEXT2) +#else +/* +Windowed - + Need some temp space for saving stuff during window spill. + Also add 16 bytes to skip over interruptee's base save area + and another 16 bytes in case of gcc nested functions: these + must be at physical top (logical base) of frame. +*/ +#define XT_STK_N_TMP 3 /* # of 4-byte temp. slots */ +#define XT_STK_TMP XT_STK_NEXT2 +#define XT_STK_NEXT3 XT_STK_TMP + (4 * XT_STK_N_TMP) +#define XT_STK_FRMSZ (ALIGNUP(0x10, XT_STK_NEXT3) + 0x20) +#endif + + +/******************************************************************************* + +SOLICTED STACK FRAME FOR A THREAD + +A stack frame of this structure is allocated whenever a thread enters the +RTOS kernel intentionally (and synchronously) to submit to thread scheduling. +It goes on the current thread's stack. + +The solicted frame only includes registers that are required to be preserved +by the callee according to the compiler's ABI conventions, some space to save +the return address for returning to the caller, and the caller's PS register. + +For Windowed ABI, this stack frame includes the caller's base save area. + +Note on XT_SOL_EXIT field: + It is necessary to distinguish a solicited from an interrupt stack frame. + This field corresponds to XT_STK_EXIT in the interrupt stack frame and is + always at the same offset (0). It can be written with a code (usually 0) + to distinguish a solicted frame from an interrupt frame. An RTOS port may + opt to ignore this field if it has another way of distinguishing frames. + +*******************************************************************************/ + +#ifdef __XTENSA_CALL0_ABI__ + +/* Call0 ABI: room to save callee-save regs and return address. */ +#define XT_SOL_EXIT XT_STK_EXIT /* code indicates solicited frame */ +#define XT_SOL_PC 0x04 /* return address */ +#define XT_SOL_PS 0x08 +#define XT_SOL_NEXT 0x0c /* next unused offset */ + /* there may be some unused space here */ +#define XT_SOL_A12 ALIGNUP(0x10, XT_SOL_NEXT) +#define XT_SOL_A13 XT_SOL_A12 + 4 +#define XT_SOL_A14 XT_SOL_A13 + 4 +#define XT_SOL_A15 XT_SOL_A14 + 4 +#define XT_SOL_FRMSZ ALIGNUP(0x10, XT_SOL_A15) + +#else + +/* Windowed ABI: room to spill base-save area and save return address. */ +#define XT_SOL_EXIT XT_STK_EXIT /* code indicates solicited frame */ +#define XT_SOL_PC 0x04 /* return address (b30-31=callinc) */ +#define XT_SOL_PS 0x08 +#define XT_SOL_NEXT 0x0c /* next unused offset */ + /* there may be some unused space here */ +#define XT_SOL_A0 ALIGNUP(0x10, XT_SOL_NEXT) +#define XT_SOL_A1 XT_SOL_A0 + 4 +#define XT_SOL_A2 XT_SOL_A1 + 4 +#define XT_SOL_A3 XT_SOL_A2 + 4 +#define XT_SOL_FRMSZ ALIGNUP(0x10, XT_SOL_A3) + +#endif + + +/******************************************************************************* + +CO-PROCESSOR STATE SAVE AREA FOR A THREAD + +The RTOS must provide an area per thread to save the state of co-processors +when that thread does not have control. Co-processors are context-switched +lazily (on demand) only when a new thread uses a co-processor instruction, +otherwise a thread retains ownership of the co-processor even when it loses +control of the processor. An Xtensa co-processor exception is triggered when +any co-processor instruction is executed by a thread that is not the owner, +and the context switch of that co-processor is then peformed by the handler. +Ownership represents which thread's state is currently in the co-processor. + +Co-processors may not be used by interrupt or exception handlers. If an +co-processor instruction is executed by an interrupt or exception handler, +the co-processor exception handler will trigger a kernel panic and freeze. +This restriction is introduced to reduce the overhead of saving and restoring +co-processor state (which can be quite large) and in particular remove that +overhead from interrupt handlers. + +The co-processor state save area may be in any convenient per-thread location +such as in the thread control block or above the thread stack area. It need +not be in the interrupt stack frame since interrupts don't use co-processors. + +Along with the save area for each co-processor, two bitmasks with flags per +co-processor (laid out as in the CPENABLE reg) help manage context-switching +co-processors as efficiently as possible: + +XT_CPENABLE + The contents of a non-running thread's CPENABLE register. + It represents the co-processors owned (and whose state is still needed) + by the thread. When a thread is preempted, its CPENABLE is saved here. + When a thread solicits a context-swtich, its CPENABLE is cleared - the + compiler has saved the (caller-saved) co-proc state if it needs to. + When a non-running thread loses ownership of a CP, its bit is cleared. + When a thread runs, it's XT_CPENABLE is loaded into the CPENABLE reg. + Avoids co-processor exceptions when no change of ownership is needed. + +XT_CPSTORED + A bitmask with the same layout as CPENABLE, a bit per co-processor. + Indicates whether the state of each co-processor is saved in the state + save area. When a thread enters the kernel, only the state of co-procs + still enabled in CPENABLE is saved. When the co-processor exception + handler assigns ownership of a co-processor to a thread, it restores + the saved state only if this bit is set, and clears this bit. + +*******************************************************************************/ + +#if XCHAL_CP_NUM > 0 +#define XT_CPENABLE 0 +#define XT_CPSTORED (XT_CPENABLE + 1) +#define XT_CP0_SA ALIGNUP(XCHAL_CP0_SA_ALIGN, XT_CPSTORED + 1) +#define XT_CP1_SA ALIGNUP(XCHAL_CP1_SA_ALIGN, XT_CP0_SA + XCHAL_CP0_SA_SIZE) +#define XT_CP2_SA ALIGNUP(XCHAL_CP2_SA_ALIGN, XT_CP1_SA + XCHAL_CP1_SA_SIZE) +#define XT_CP3_SA ALIGNUP(XCHAL_CP3_SA_ALIGN, XT_CP2_SA + XCHAL_CP2_SA_SIZE) +#define XT_CP4_SA ALIGNUP(XCHAL_CP4_SA_ALIGN, XT_CP3_SA + XCHAL_CP3_SA_SIZE) +#define XT_CP5_SA ALIGNUP(XCHAL_CP5_SA_ALIGN, XT_CP4_SA + XCHAL_CP4_SA_SIZE) +#define XT_CP6_SA ALIGNUP(XCHAL_CP6_SA_ALIGN, XT_CP5_SA + XCHAL_CP5_SA_SIZE) +#define XT_CP7_SA ALIGNUP(XCHAL_CP7_SA_ALIGN, XT_CP6_SA + XCHAL_CP6_SA_SIZE) +#define XT_CP_SIZE ALIGNUP(4 , XT_CP7_SA + XCHAL_CP7_SA_SIZE) +#else +#define XT_CP_SIZE 0 +#endif + + +/******************************************************************************* + +MACROS TO HANDLE ABI SPECIFICS OF FUNCTION ENTRY AND RETURN + +Convenient where the frame size requirements are the same for both ABIs. + ENTRY(sz), RET(sz) are for framed functions (have locals or make calls). + ENTRY0, RET0 are for frameless functions (no locals, no calls). +where size = size of stack frame in bytes (must be >0 and aligned to 16). +For framed functions the frame is created and the return address saved at +base of frame (Call0 ABI) or as determined by hardware (Windowed ABI). +For frameless functions, there is no frame and return address remains in a0. +Note: Because CPP macros expand to a single line, macros requiring multi-line +expansions are implemented as assembler macros. + +*******************************************************************************/ + +#ifdef __ASSEMBLER__ +#ifdef __XTENSA_CALL0_ABI__ + /* Call0 */ + #define ENTRY(sz) entry1 sz + .macro entry1 size=0x10 + addi sp, sp, -\size + s32i a0, sp, 0 + .endm + #define ENTRY0 + #define RET(sz) ret1 sz + .macro ret1 size=0x10 + l32i a0, sp, 0 + addi sp, sp, \size + ret + .endm + #define RET0 ret +#else + /* Windowed */ + #define ENTRY(sz) entry sp, sz + #define ENTRY0 entry sp, 0x10 + #define RET(sz) retw + #define RET0 retw +#endif +#endif + + +#endif /* XTENSA_CONTEXT_H */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/freertos/xtensa_rtos.h b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/xtensa_rtos.h new file mode 100644 index 0000000..f070279 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/xtensa_rtos.h @@ -0,0 +1,175 @@ +/******************************************************************************* +Copyright (c) 2006-2009 by Tensilica Inc. ALL RIGHTS RESERVED. +These coded instructions, statements, and computer programs are the +copyrighted works and confidential proprietary information of Tensilica Inc. +They may not be modified, copied, reproduced, distributed, or disclosed to +third parties in any manner, medium, or form, in whole or in part, without +the prior written consent of Tensilica Inc. +-------------------------------------------------------------------------------- + + RTOS-SPECIFIC INFORMATION FOR XTENSA RTOS ASSEMBLER SOURCES + +This header is the primary glue between generic Xtensa RTOS support +sources and a specific RTOS port for Xtensa. It contains definitions +and macros for use primarily by Xtensa assembly coded source files. + +Macros in this header map callouts from generic Xtensa files to specific +RTOS functions. It may also be included in C source files. + +Xtensa RTOS ports support all RTOS-compatible configurations of the Xtensa +architecture, using the Xtensa hardware abstraction layer (HAL) to deal +with configuration specifics. + +Should be included by all Xtensa generic and RTOS port-specific sources. + +*******************************************************************************/ + +#ifndef XTENSA_RTOS_H +#define XTENSA_RTOS_H + +#ifdef __ASSEMBLER__ +#include +#else +#include +#endif + +#include +#include +#include + +/* +Include any RTOS specific definitions that are needed by this header. +*/ + +#ifdef XCHAL_EXCM_LEVEL +#undef XCHAL_EXCM_LEVEL +#define XCHAL_EXCM_LEVEL 3 +#endif + +/* +Name of RTOS (for messages). +*/ +#define XT_RTOS_NAME FreeRTOS + +/* +Check some Xtensa configuration requirements and report error if not met. +Error messages can be customize to the RTOS port. +*/ + +#if !XCHAL_HAVE_XEA2 +#error "FreeRTOS/Xtensa requires XEA2 (exception architecture 2)." +#endif + + +/******************************************************************************* + +RTOS CALLOUT MACROS MAPPED TO RTOS PORT-SPECIFIC FUNCTIONS. + +Define callout macros used in generic Xtensa code to interact with the RTOS. +The macros are simply the function names for use in calls from assembler code. +Some of these functions may call back to generic functions in xtensa_context.h . + +*******************************************************************************/ + +/* +Inform RTOS of entry into an interrupt handler that will affect it. +Allows RTOS to manage switch to any system stack and count nesting level. +Called after minimal context has been saved, with interrupts disabled. +RTOS port can call0 _xt_context_save to save the rest of the context. +May only be called from assembly code by the 'call0' instruction. +*/ +// void XT_RTOS_INT_ENTER(void) +#define XT_RTOS_INT_ENTER _xt_int_enter + +/* +Inform RTOS of completion of an interrupt handler, and give control to +RTOS to perform thread/task scheduling, switch back from any system stack +and restore the context, and return to the exit dispatcher saved in the +stack frame at XT_STK_EXIT. RTOS port can call0 _xt_context_restore +to save the context saved in XT_RTOS_INT_ENTER via _xt_context_save, +leaving only a minimal part of the context to be restored by the exit +dispatcher. This function does not return to the place it was called from. +May only be called from assembly code by the 'call0' instruction. +*/ +// void XT_RTOS_INT_EXIT(void) +#define XT_RTOS_INT_EXIT _xt_int_exit + +/* +Inform RTOS of the occurrence of a tick timer interrupt. +If RTOS has no tick timer, leave XT_RTOS_TIMER_INT undefined. +May be coded in or called from C or assembly, per ABI conventions. +RTOS may optionally define XT_TICK_PER_SEC in its own way (eg. macro). +*/ +// void XT_RTOS_TIMER_INT(void) +#define XT_RTOS_TIMER_INT _xt_timer_int + +/* +Return in a15 the base address of the co-processor state save area for the +thread that triggered a co-processor exception, or 0 if no thread was running. +The state save area is structured as defined in xtensa_context.h and has size +XT_CP_SIZE. Co-processor instructions should only be used in thread code, never +in interrupt handlers or the RTOS kernel. May only be called from assembly code +and by the 'call0' instruction. A result of 0 indicates an unrecoverable error. +The implementation may use only a2-4, a15 (all other regs must be preserved). +*/ +// void* XT_RTOS_CP_STATE(void) + +/******************************************************************************* + +HOOKS TO DYNAMICALLY INSTALL INTERRUPT AND EXCEPTION HANDLERS PER LEVEL. + +This Xtensa RTOS port provides hooks for dynamically installing exception +and interrupt handlers to facilitate automated testing where each test +case can install its own handler for user exceptions and each interrupt +priority (level). This consists of an array of function pointers indexed +by interrupt priority, with index 0 being the user exception handler hook. +Each entry in the array is initially 0, and may be replaced by a function +pointer of type XT_INTEXC_HOOK. A handler may be uninstalled by installing 0. + +The handler for low and medium priority obeys ABI conventions so may be coded +in C. For the exception handler, the cause is the contents of the EXCCAUSE +reg, and the result is -1 if handled, else the cause (still needs handling). +For interrupt handlers, the cause is a mask of pending enabled interrupts at +that level, and the result is the same mask with the bits for the handled +interrupts cleared (those not cleared still need handling). This allows a test +case to either pre-handle or override the default handling for the exception +or interrupt level (see xtensa_vectors.S). + +High priority handlers (including NMI) must be coded in assembly, are always +called by 'call0' regardless of ABI, must preserve all registers except a0, +and must not use or modify the interrupted stack. The hook argument 'cause' +is not passed and the result is ignored, so as not to burden the caller with +saving and restoring a2 (it assumes only one interrupt per level - see the +discussion in high priority interrupts in xtensa_vectors.S). The handler +therefore should be coded to prototype 'void h(void)' even though it plugs +into an array of handlers of prototype 'unsigned h(unsigned)'. + +To enable interrupt/exception hooks, compile the RTOS with '-DXT_INTEXC_HOOKS'. + +*******************************************************************************/ + +#define XT_INTEXC_HOOK_NUM (1 + XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI) + +#ifndef __ASSEMBLER__ +typedef unsigned (*XT_INTEXC_HOOK)(unsigned cause); +extern volatile XT_INTEXC_HOOK _xt_intexc_hooks[XT_INTEXC_HOOK_NUM]; +#endif + + +/******************************************************************************* + +CONVENIENCE INCLUSIONS. + +Ensures RTOS specific files need only include this one Xtensa-generic header. +These headers are included last so they can use the RTOS definitions above. + +*******************************************************************************/ + +#include "xtensa_context.h" + +#ifdef XT_RTOS_TIMER_INT +#include "xtensa_timer.h" +#endif + + +#endif /* XTENSA_RTOS_H */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/freertos/xtensa_timer.h b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/xtensa_timer.h new file mode 100644 index 0000000..70da91f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/freertos/xtensa_timer.h @@ -0,0 +1,146 @@ +/******************************************************************************* +Copyright (c) 2006-2009 by Tensilica Inc. ALL RIGHTS RESERVED. +These coded instructions, statements, and computer programs are the +copyrighted works and confidential proprietary information of Tensilica Inc. +They may not be modified, copied, reproduced, distributed, or disclosed to +third parties in any manner, medium, or form, in whole or in part, without +the prior written consent of Tensilica Inc. +-------------------------------------------------------------------------------- + + XTENSA INFORMATION FOR RTOS TICK TIMER AND CLOCK FREQUENCY + +This header contains definitions and macros for use primarily by Xtensa +RTOS assembly coded source files. It includes and uses the Xtensa hardware +abstraction layer (HAL) to deal with config specifics. It may also be +included in C source files. + +User may edit to modify timer selection and to specify clock frequency and +tick duration to match timer interrupt to the real-time tick duration. + +If the RTOS has no timer interrupt, then there is no tick timer and the +clock frequency is irrelevant, so all of these macros are left undefined +and the Xtensa core configuration need not have a timer. + +*******************************************************************************/ + +#ifndef XTENSA_TIMER_H +#define XTENSA_TIMER_H + +#ifdef XT_RTOS_TIMER_INT /* skip all this stuff if no timer int */ + +#ifdef __ASSEMBLER__ +#include +#endif + +#include +#include + +#include "xtensa_rtos.h" /* in case this wasn't included directly */ + + +/* +Select timer to use for periodic tick, and determine its interrupt number +and priority. User may specify a timer by defining XT_TIMER_INDEX with -D, +in which case its validity is checked (it must exist in this core and must +not be on a high priority interrupt - an error will be reported in invalid). +Otherwise select the first low or medium priority interrupt timer available. +*/ +#ifndef XT_TIMER_INDEX + #if XCHAL_TIMER3_INTERRUPT != XTHAL_TIMER_UNCONFIGURED + #if XCHAL_INT_LEVEL(XCHAL_TIMER3_INTERRUPT) <= XCHAL_EXCM_LEVEL + #undef XT_TIMER_INDEX + #define XT_TIMER_INDEX 3 + #endif + #endif + #if XCHAL_TIMER2_INTERRUPT != XTHAL_TIMER_UNCONFIGURED + #if XCHAL_INT_LEVEL(XCHAL_TIMER2_INTERRUPT) <= XCHAL_EXCM_LEVEL + #undef XT_TIMER_INDEX + #define XT_TIMER_INDEX 2 + #endif + #endif + #if XCHAL_TIMER1_INTERRUPT != XTHAL_TIMER_UNCONFIGURED + #if XCHAL_INT_LEVEL(XCHAL_TIMER1_INTERRUPT) <= XCHAL_EXCM_LEVEL + #undef XT_TIMER_INDEX + #define XT_TIMER_INDEX 1 + #endif + #endif + #if XCHAL_TIMER0_INTERRUPT != XTHAL_TIMER_UNCONFIGURED + #if XCHAL_INT_LEVEL(XCHAL_TIMER0_INTERRUPT) <= XCHAL_EXCM_LEVEL + #undef XT_TIMER_INDEX + #define XT_TIMER_INDEX 0 + #endif + #endif +#endif +#ifndef XT_TIMER_INDEX + #error "There is no suitable timer in this Xtensa configuration." +#endif + +#define XT_CCOMPARE (CCOMPARE + XT_TIMER_INDEX) +#define XT_TIMER_INTNUM XCHAL_TIMER_INTERRUPT(XT_TIMER_INDEX) +#define XT_TIMER_INTPRI XCHAL_INT_LEVEL(XT_TIMER_INTNUM) +#define XT_TIMER_INTEN (1 << XT_TIMER_INTNUM) + +#if XT_TIMER_INTNUM == XTHAL_TIMER_UNCONFIGURED + #error "The timer selected by XT_TIMER_INDEX does not exist in this core." +#elif XT_TIMER_INTPRI > XCHAL_EXCM_LEVEL + #error "The timer interrupt cannot be high priority (use medium or low)." +#endif + +/* +Set processor clock frequency, used to determine clock divisor for timer tick. +User should BE SURE TO ADJUST THIS for the Xtensa platform being used. +If using a supported board via the board-independent API defined in xtbsp.h, +this may be left undefined and frequency and tick divisor will be computed +and cached during run-time initialization. + +NOTE ON SIMULATOR: +Under the Xtensa instruction set simulator, the frequency can only be estimated +because it depends on the speed of the host and the version of the simulator. +Also because it runs much slower than hardware, it is not possible to achieve +real-time performance for most applications under the simulator. A frequency +too low does not allow enough time between timer interrupts, starving threads. +To obtain a more convenient but non-real-time tick duration on the simulator, +compile with xt-xcc option "-DXT_SIMULATOR". +Adjust this frequency to taste (it's not real-time anyway!). +*/ +#if defined(XT_SIMULATOR) && !defined(XT_CLOCK_FREQ) +#define XT_CLOCK_FREQ 2000000 /* 2 MHz */ +#else +#ifdef XT_XT2000 /* deprecated */ +#define XT_CLOCK_FREQ 16500000 /* 16.5 MHz (XT2000 default) */ +#else +#define XT_CLOCK_FREQ 80000000 +#endif +#endif /* XT_SIMULATOR */ + +#if !defined(XT_CLOCK_FREQ) && !defined(XT_BOARD) + #error "XT_CLOCK_FREQ must be defined for the target platform." +#endif + +/* +Default number of timer "ticks" per second (default 100 for 10ms tick). +RTOS may define this in its own way (if applicable) in xtensa_rtos.h. +User may redefine this to an optimal value for the application, either by +editing this here or in xtensa_rtos.h, or compiling with xt-xcc option +"-DXT_TICKS_PER_SEC " where is a suitable number. +*/ +#ifndef XT_TICK_PER_SEC +#define XT_TICK_PER_SEC 100 /* 10 ms tick = 100 ticks per second */ +#endif + +/* +Derviation of clock divisor for timer tick and interrupt (one per tick). +*/ +#ifdef XT_CLOCK_FREQ +#define XT_TICK_DIVISOR (XT_CLOCK_FREQ / XT_TICK_PER_SEC) +#else +#ifndef __ASSEMBLER__ +extern unsigned _xt_tick_divisor; +extern void _xt_tick_divisor_init(void); +#endif +#define XT_TICK_DIVISOR _xt_tick_divisor +#endif + +#endif /* XT_RTOS_TIMER_INT */ +#endif /* XTENSA_TIMER_H */ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/json/cJSON.h b/Distrib/ESPressif/RTOS/1.5.0/include/json/cJSON.h new file mode 100644 index 0000000..466d10d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/json/cJSON.h @@ -0,0 +1,149 @@ +/* + Copyright (c) 2009 Dave Gamble + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef cJSON__h +#define cJSON__h + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* cJSON Types: */ +#define cJSON_False 0 +#define cJSON_True 1 +#define cJSON_NULL 2 +#define cJSON_Number 3 +#define cJSON_String 4 +#define cJSON_Array 5 +#define cJSON_Object 6 + +#define cJSON_IsReference 256 +#define cJSON_StringIsConst 512 + +/* The cJSON structure: */ +typedef struct cJSON { + struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ + + int type; /* The type of the item, as above. */ + + char *valuestring; /* The item's string, if type==cJSON_String */ + int valueint; /* The item's number, if type==cJSON_Number */ + double valuedouble; /* The item's number, if type==cJSON_Number */ + + char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ +} cJSON; + +typedef struct cJSON_Hooks { + void *(*malloc_fn)(size_t sz); + void (*free_fn)(void *ptr); +} cJSON_Hooks; + +/* Supply malloc, realloc and free functions to cJSON */ +extern void cJSON_InitHooks(cJSON_Hooks* hooks); + + +/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */ +extern cJSON *cJSON_Parse(const char *value); +/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */ +extern char *cJSON_Print(cJSON *item); +/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */ +extern char *cJSON_PrintUnformatted(cJSON *item); +/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ +extern char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt); +/* Delete a cJSON entity and all subentities. */ +extern void cJSON_Delete(cJSON *c); + +/* Returns the number of items in an array (or object). */ +extern int cJSON_GetArraySize(cJSON *array); +/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ +extern cJSON *cJSON_GetArrayItem(cJSON *array,int item); +/* Get item "string" from object. Case insensitive. */ +extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string); + +/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ +extern const char *cJSON_GetErrorPtr(void); + +/* These calls create a cJSON item of the appropriate type. */ +extern cJSON *cJSON_CreateNull(void); +extern cJSON *cJSON_CreateTrue(void); +extern cJSON *cJSON_CreateFalse(void); +extern cJSON *cJSON_CreateBool(int b); +extern cJSON *cJSON_CreateNumber(double num); +extern cJSON *cJSON_CreateString(const char *string); +extern cJSON *cJSON_CreateArray(void); +extern cJSON *cJSON_CreateObject(void); + +/* These utilities create an Array of count items. */ +extern cJSON *cJSON_CreateIntArray(const int *numbers,int count); +extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count); +extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count); +extern cJSON *cJSON_CreateStringArray(const char **strings,int count); + +/* Append item to the specified array/object. */ +extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); +extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); +extern void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item); /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object */ +/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ +extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); +extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item); + +/* Remove/Detatch items from Arrays/Objects. */ +extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which); +extern void cJSON_DeleteItemFromArray(cJSON *array,int which); +extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string); +extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string); + +/* Update array items. */ +extern void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem); /* Shifts pre-existing items to the right. */ +extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem); +extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); + +/* Duplicate a cJSON item */ +extern cJSON *cJSON_Duplicate(cJSON *item,int recurse); +/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will +need to be released. With recurse!=0, it will duplicate any children connected to the item. +The item->next and ->prev pointers are always zero on return from Duplicate. */ + +/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ +extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated); + +extern void cJSON_Minify(char *json); + +/* Macros for creating things quickly. */ +#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) +#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) +#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) +#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) +#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) +#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) + +/* When assigning an integer value, it needs to be propagated to valuedouble too. */ +#define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val)) +#define cJSON_SetNumberValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val)) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/apps/sntp.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/apps/sntp.h new file mode 100644 index 0000000..2a70ac2 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/apps/sntp.h @@ -0,0 +1,71 @@ +/* + * 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 "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); +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/Distrib/ESPressif/RTOS/1.5.0/include/lwip/apps/sntp_opts.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/apps/sntp_opts.h new file mode 100644 index 0000000..0e697e2 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/apps/sntp_opts.h @@ -0,0 +1,159 @@ +/* + * 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" + +/** 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. + */ +#ifndef SNTP_SET_SYSTEM_TIME +#define SNTP_SET_SYSTEM_TIME(sec) sntp_set_system_time(sec) +#endif + +/** The maximum number of SNTP servers that can be set */ +#ifndef SNTP_MAX_SERVERS +#define SNTP_MAX_SERVERS 1 +#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 +#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 + +/** One server address/name can be defined as default if SNTP_SERVER_DNS == 1: + * #define SNTP_SERVER_ADDRESS "pool.ntp.org" + */ + +/** + * SNTP_DEBUG: Enable debugging for SNTP. + */ +#ifndef SNTP_DEBUG +#define SNTP_DEBUG LWIP_DBG_OFF +#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 + +/** 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. Must not be beolw 15 seconds by specification (i.e. 15000) + */ +#ifndef SNTP_UPDATE_DELAY +#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. + */ +#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 + +#endif /* LWIP_HDR_APPS_SNTP_OPTS_H */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/apps/sntp_time.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/apps/sntp_time.h new file mode 100644 index 0000000..3a90c9a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/apps/sntp_time.h @@ -0,0 +1,61 @@ +/* + * sntp_time.h + * + * Created on: 2016-11-9 + * Author: LiuHan + */ + +#ifndef SNTP_TIME_H_ +#define SNTP_TIME_H_ + +#include "lwip/opt.h" +#include "lwip/timers.h" + +#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) + +typedef long sntp_time_t; + +typedef struct{ + 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; +}sntp_tm; + +typedef struct{ + char ch; + int m; + int n; + int d; + int s; + sntp_time_t change; + int offset; +}sntp_tm_type; + +void sntp_set_system_time(sntp_time_t GMT_Time); +bool sntp_set_timezone(s8_t timezone); +u32_t sntp_get_current_timestamp(void); +char* sntp_get_real_time(sntp_time_t t); + + +#endif /* SNTP_TIME_H_ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/apps/time.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/apps/time.h new file mode 100644 index 0000000..75e0d34 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/apps/time.h @@ -0,0 +1,57 @@ +/* + * time.h + * + * Created on: May 31, 2016 + * Author: liuhan + */ + +#ifndef TIME_H_ +#define TIME_H_ + +#include "c_types.h" +#include "esp8266/eagle_soc.h" + +#if !NO_SYS +#include "lwip/sockets.h" +#else +struct timeval { + unsigned long tv_sec; /* seconds */ + unsigned long tv_usec; /* and microseconds */ +}; +#endif + +/***************************RTC TIME OPTION***************************************/ +// daylight settings +// Base calculated with value obtained from NTP server (64 bits) +#define sntp_base (*((uint64_t*)RTC_SCRATCH0)) +// Timer value when base was obtained +#define TIM_REF_SET(value) WRITE_PERI_REG(RTC_SCRATCH2, value) +#define TIM_REF_GET() READ_PERI_REG(RTC_SCRATCH2) + +// Setters and getters for CAL, TZ and DST. +#define RTC_CAL_SET(val) do {uint32 value = READ_PERI_REG(RTC_SCRATCH3);\ + value |= ((val) & 0x0000FFFF);\ + WRITE_PERI_REG(RTC_SCRATCH3, value);\ + }while(0) +#define RTC_DST_SET(val) do {uint32 value = READ_PERI_REG(RTC_SCRATCH3);\ + value |= (((val)<<16) & 0x00010000);\ + WRITE_PERI_REG(RTC_SCRATCH3, value);\ + }while(0) +#define RTC_TZ_SET(val) do {uint32 value = READ_PERI_REG(RTC_SCRATCH3);\ + value |= (((val)<<24) & 0xFF000000);\ + WRITE_PERI_REG(RTC_SCRATCH3, value);\ + }while(0) + +#define RTC_CAL_GET() (READ_PERI_REG(RTC_SCRATCH3) & 0x0000FFFF) +#define RTC_DST_GET() ((READ_PERI_REG(RTC_SCRATCH3) & 0x00010000)>>16) +#define RTC_TZ_GET() ((((int)READ_PERI_REG(RTC_SCRATCH3)) & ((int)0xFF000000))>>24) +void system_update_rtc(time_t t, uint32 us); +time_t sntp_get_rtc_time(sint32 *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/Distrib/ESPressif/RTOS/1.5.0/include/lwip/arch/cc.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/arch/cc.h new file mode 100644 index 0000000..5a1f920 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/arch/cc.h @@ -0,0 +1,93 @@ +/* + * 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 "c_types.h" + +#define EFAULT 14 + +#define ERRNO +#define LWIP_PROVIDE_ERRNO + +#if (1) +#define BYTE_ORDER LITTLE_ENDIAN +#else +#define BYTE_ORDER BIG_ENDIAN +#endif + +typedef unsigned long mem_ptr_t; +typedef int sys_prot_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 + +#include + +#ifndef os_printf +#define os_printf(fmt, ...) do { \ + static const char flash_str[] ICACHE_RODATA_ATTR STORE_ATTR = fmt; \ + printf(flash_str, ##__VA_ARGS__); \ + } while(0) +#endif + +#ifdef LWIP_DEBUG +#define LWIP_PLATFORM_DIAG(x) do {os_printf x;} while(0) +#define LWIP_PLATFORM_ASSERT(x) do {os_printf(x); sys_arch_assert(__FILE__, __LINE__);} while(0) +#else +#define LWIP_PLATFORM_DIAG(x) +#define LWIP_PLATFORM_ASSERT(x) +#endif + +#ifndef LWIP_PLATFORM_BYTESWAP +#define LWIP_PLATFORM_BYTESWAP 1 +#endif + +#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) )) + +#endif /* __ARCH_CC_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/arch/perf.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/arch/perf.h new file mode 100644 index 0000000..089faca --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/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/Distrib/ESPressif/RTOS/1.5.0/include/lwip/arch/sys_arch.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/arch/sys_arch.h new file mode 100644 index 0000000..18feef8 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/arch/sys_arch.h @@ -0,0 +1,54 @@ +/* + * 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 __SYS_ARCH_H__ +#define __SYS_ARCH_H__ + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" + +typedef xSemaphoreHandle sys_sem_t; +typedef xSemaphoreHandle sys_mutex_t; +typedef xQueueHandle sys_mbox_t; +typedef xTaskHandle sys_thread_t; + +#define sys_mbox_valid( x ) ( ( ( *x ) == NULL) ? pdFALSE : pdTRUE ) +#define sys_mbox_set_invalid( x ) ( ( *x ) = NULL ) +#define sys_sem_valid( x ) ( ( ( *x ) == NULL) ? pdFALSE : pdTRUE ) +#define sys_sem_set_invalid( x ) ( ( *x ) = NULL ) + +#define LWIP_COMPAT_MUTEX 0 + +#endif /* __SYS_ARCH_H__ */ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv4/lwip/autoip.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv4/lwip/autoip.h new file mode 100644 index 0000000..064ef87 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv4/lwip/autoip.h @@ -0,0 +1,118 @@ +/** + * @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 */ +}; + + +#define autoip_init() /* Compatibility define, no init needed. */ + +/** 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/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv4/lwip/icmp.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv4/lwip/icmp.h new file mode 100644 index 0000000..fb19a9e --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv4/lwip/icmp.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS 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" + +#if LWIP_IPV6 && LWIP_ICMP6 +#include "lwip/icmp6.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define ICMP_ER 0 /* echo reply */ +#define ICMP_DUR 3 /* destination unreachable */ +#define ICMP_SQ 4 /* source quench */ +#define ICMP_RD 5 /* redirect */ +#define ICMP_ECHO 8 /* echo */ +#define ICMP_TE 11 /* time exceeded */ +#define ICMP_PP 12 /* parameter problem */ +#define ICMP_TS 13 /* timestamp */ +#define ICMP_TSR 14 /* timestamp reply */ +#define ICMP_IRQ 15 /* information request */ +#define ICMP_IR 16 /* information reply */ + +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. + */ +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 + +#define ICMPH_TYPE(hdr) ((hdr)->type) +#define ICMPH_CODE(hdr) ((hdr)->code) + +/** Combines type and code to an u16_t */ +#define ICMPH_TYPE_SET(hdr, t) ((hdr)->type = (t)) +#define ICMPH_CODE_SET(hdr, c) ((hdr)->code = (c)) + + +#if LWIP_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_ICMP */ + +#if (LWIP_IPV6 && 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) icmp_dest_unreach(pbuf, ICMP_DUR_PORT) +#else /* (LWIP_IPV6 && LWIP_ICMP6) || LWIP_ICMP*/ +#define icmp_port_unreach(isipv6, pbuf) +#endif /* (LWIP_IPV6 && LWIP_ICMP6) || LWIP_ICMP*/ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_ICMP_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv4/lwip/igmp.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv4/lwip/igmp.h new file mode 100644 index 0000000..7bb18ea --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv4/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); +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, ip_addr_t *addr); +void igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest); +err_t igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr); +err_t igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr); +void igmp_tmr(void); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IGMP */ + +#endif /* __LWIP_IGMP_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv4/lwip/inet.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv4/lwip/inet.h new file mode 100644 index 0000000..391a9d8 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv4/lwip/inet.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS 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 + +/* 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 +/** For compatibility with BSD code */ +struct in_addr { + in_addr_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/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv4/lwip/ip4.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv4/lwip/ip4.h new file mode 100644 index 0000000..7c0d864 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv4/lwip/ip4.h @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS 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_IP4_H__ +#define __LWIP_IP4_H__ + +#include "lwip/opt.h" + +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/ip6_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 + + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip_hdr { + /* version / header length */ + PACK_STRUCT_FIELD(u8_t _v_hl); + /* type of service */ + PACK_STRUCT_FIELD(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 /* dont fragment flag */ +#define IP_MF 0x2000U /* more fragments flag */ +#define IP_OFFMASK 0x1fffU /* 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) ((hdr)->_v_hl >> 4) +#define IPH_HL(hdr) ((hdr)->_v_hl & 0x0f) +#define IPH_TOS(hdr) ((hdr)->_tos) +#define IPH_LEN(hdr) ((hdr)->_len) +#define IPH_ID(hdr) ((hdr)->_id) +#define IPH_OFFSET(hdr) ((hdr)->_offset) +#define IPH_TTL(hdr) ((hdr)->_ttl) +#define IPH_PROTO(hdr) ((hdr)->_proto) +#define IPH_CHKSUM(hdr) ((hdr)->_chksum) + +#define IPH_VHL_SET(hdr, v, hl) (hdr)->_v_hl = (((v) << 4) | (hl)) +#define IPH_TOS_SET(hdr, tos) (hdr)->_tos = (tos) +#define IPH_LEN_SET(hdr, len) (hdr)->_len = (len) +#define IPH_ID_SET(hdr, id) (hdr)->_id = (id) +#define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off) +#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl = (u8_t)(ttl) +#define IPH_PROTO_SET(hdr, proto) (hdr)->_proto = (u8_t)(proto) +#define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum) + + +#define ip_init() /* Compatibility define, no init needed. */ +struct netif *ip_route(ip_addr_t *dest); +err_t ip_input(struct pbuf *p, struct netif *inp); +err_t ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto); +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 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); +#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); +#endif /* IP_OPTIONS_SEND */ + +#define ip_netif_get_local_ipX(netif) (((netif) != NULL) ? ip_2_ipX(&((netif)->ip_addr)) : NULL) + +#if IP_DEBUG +void ip_debug_print(struct pbuf *p); +#else +#define ip_debug_print(p) +#endif /* IP_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_IP_H__ */ + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv4/lwip/ip4_addr.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv4/lwip/ip4_addr.h new file mode 100644 index 0000000..35b307c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv4/lwip/ip4_addr.h @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS 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_IP4_ADDR_H__ +#define __LWIP_IP4_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); + +#define ip_addr_netmask_valid(netmask) ip4_addr_netmask_valid((netmask)->addr) +u8_t ip4_addr_netmask_valid(u32_t netmask); + +#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); +int ipaddr_aton(const char *cp, ip_addr_t *addr); +/** returns ptr to static buffer; not reentrant! */ +char *ipaddr_ntoa(const ip_addr_t *addr); +char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen); + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_IP_ADDR_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv4/lwip/ip_frag.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv4/lwip/ip_frag.h new file mode 100644 index 0000000..c78f2c5 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv4/lwip/ip_frag.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE 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); +void ip_reass_tmr(void); +struct pbuf * ip_reass(struct pbuf *p); +#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. */ +#ifndef __LWIP_PBUF_CUSTOM_REF__ +#define __LWIP_PBUF_CUSTOM_REF__ +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__ */ +#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); +#endif /* IP_FRAG */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_IP_FRAG_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/dhcp6.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/dhcp6.h new file mode 100644 index 0000000..8fec444 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/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_IP6_DHCP6_H__ +#define __LWIP_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_IP6_DHCP6_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/ethip6.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/ethip6.h new file mode 100644 index 0000000..d730267 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/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_ETHIP6_H__ +#define __LWIP_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, ip6_addr_t *ip6addr); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 && LWIP_ETHERNET */ + +#endif /* __LWIP_ETHIP6_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/icmp6.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/icmp6.h new file mode 100644 index 0000000..a40c5b4 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/icmp6.h @@ -0,0 +1,152 @@ +/** + * @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_ICMP6_H__ +#define __LWIP_ICMP6_H__ + +#include "lwip/opt.h" +#include "lwip/pbuf.h" +#include "lwip/ip6_addr.h" +#include "lwip/netif.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +enum icmp6_type { + ICMP6_TYPE_DUR = 1, /* Destination unreachable */ + ICMP6_TYPE_PTB = 2, /* Packet too big */ + ICMP6_TYPE_TE = 3, /* Time exceeded */ + ICMP6_TYPE_PP = 4, /* Parameter problem */ + ICMP6_TYPE_PE1 = 100, /* Private experimentation */ + ICMP6_TYPE_PE2 = 101, /* Private experimentation */ + ICMP6_TYPE_RSV_ERR = 127, /* Reserved for expansion of error messages */ + + ICMP6_TYPE_EREQ = 128, /* Echo request */ + ICMP6_TYPE_EREP = 129, /* Echo reply */ + ICMP6_TYPE_MLQ = 130, /* Multicast listener query */ + ICMP6_TYPE_MLR = 131, /* Multicast listener report */ + ICMP6_TYPE_MLD = 132, /* Multicast listener done */ + ICMP6_TYPE_RS = 133, /* Router solicitation */ + ICMP6_TYPE_RA = 134, /* Router advertisement */ + ICMP6_TYPE_NS = 135, /* Neighbor solicitation */ + ICMP6_TYPE_NA = 136, /* Neighbor advertisement */ + ICMP6_TYPE_RD = 137, /* Redirect */ + ICMP6_TYPE_MRA = 151, /* Multicast router advertisement */ + ICMP6_TYPE_MRS = 152, /* Multicast router solicitation */ + ICMP6_TYPE_MRT = 153, /* Multicast router termination */ + ICMP6_TYPE_PE3 = 200, /* Private experimentation */ + ICMP6_TYPE_PE4 = 201, /* Private experimentation */ + ICMP6_TYPE_RSV_INF = 255 /* Reserved for expansion of informational messages */ +}; + +enum icmp6_dur_code { + ICMP6_DUR_NO_ROUTE = 0, /* No route to destination */ + ICMP6_DUR_PROHIBITED = 1, /* Communication with destination administratively prohibited */ + ICMP6_DUR_SCOPE = 2, /* Beyond scope of source address */ + ICMP6_DUR_ADDRESS = 3, /* Address unreachable */ + ICMP6_DUR_PORT = 4, /* Port unreachable */ + ICMP6_DUR_POLICY = 5, /* Source address failed ingress/egress policy */ + ICMP6_DUR_REJECT_ROUTE = 6 /* Reject route to destination */ +}; + +enum icmp6_te_code { + ICMP6_TE_HL = 0, /* Hop limit exceeded in transit */ + ICMP6_TE_FRAG = 1 /* Fragment reassembly time exceeded */ +}; + +enum icmp6_pp_code { + ICMP6_PP_FIELD = 0, /* Erroneous header field encountered */ + ICMP6_PP_HEADER = 1, /* Unrecognized next header type encountered */ + ICMP6_PP_OPTION = 2 /* Unrecognized IPv6 option encountered */ +}; + +/** This is the standard ICMP6 header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct icmp6_hdr { + PACK_STRUCT_FIELD(u8_t type); + PACK_STRUCT_FIELD(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_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 + + +#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_ICMP6_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/inet6.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/inet6.h new file mode 100644 index 0000000..924a324 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/inet6.h @@ -0,0 +1,92 @@ +/** + * @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 + * + */ +#ifndef __LWIP_INET6_H__ +#define __LWIP_INET6_H__ + +#include "lwip/opt.h" + +#if LWIP_IPV6 && LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip6_addr.h" +#include "lwip/def.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** For compatibility with BSD code */ +struct in6_addr { + union { + u8_t u8_addr[16]; + u32_t u32_addr[4]; + } un; +#define s6_addr un.u8_addr +}; + +#define IN6ADDR_ANY_INIT {0,0,0,0} +#define IN6ADDR_LOOPBACK_INIT {0,0,0,PP_HTONL(1)} + + +#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((ip6_addr_t*)&(addr)) +#define inet6_ntoa_r(addr, buf, buflen) ip6addr_ntoa_r((ip6_addr_t*)&(addr), buf, buflen) + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 */ + +#endif /* __LWIP_INET6_H__ */ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/ip6.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/ip6.h new file mode 100644 index 0000000..f027022 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/ip6.h @@ -0,0 +1,196 @@ +/** + * @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_IP6_H__ +#define __LWIP_IP6_H__ + +#include "lwip/opt.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip6_addr.h" +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "lwip/netif.h" + +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define IP6_HLEN 40 + +#define IP6_NEXTH_HOPBYHOP 0 +#define IP6_NEXTH_TCP 6 +#define IP6_NEXTH_UDP 17 +#define IP6_NEXTH_ENCAPS 41 +#define IP6_NEXTH_ROUTING 43 +#define IP6_NEXTH_FRAGMENT 44 +#define IP6_NEXTH_ICMP6 58 +#define IP6_NEXTH_NONE 59 +#define IP6_NEXTH_DESTOPTS 60 +#define IP6_NEXTH_UDPLITE 136 + + +/* The IPv6 header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip6_hdr { + /* version / traffic class / flow label */ + PACK_STRUCT_FIELD(u32_t _v_tc_fl); + /* payload length */ + PACK_STRUCT_FIELD(u16_t _plen); + /* next header */ + PACK_STRUCT_FIELD(u8_t _nexth); + /* hop limit */ + PACK_STRUCT_FIELD(u8_t _hoplim); + /* source and destination IP addresses */ + PACK_STRUCT_FIELD(ip6_addr_p_t src); + PACK_STRUCT_FIELD(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_FIELD(u8_t _nexth); + /* header length */ + PACK_STRUCT_FIELD(u8_t _hlen); + /* router alert option type */ + PACK_STRUCT_FIELD(u8_t _ra_opt_type); + /* router alert option data len */ + PACK_STRUCT_FIELD(u8_t _ra_opt_dlen); + /* router alert option data */ + PACK_STRUCT_FIELD(u16_t _ra_opt_data); + /* PadN option type */ + PACK_STRUCT_FIELD(u8_t _padn_opt_type); + /* PadN option data len */ + PACK_STRUCT_FIELD(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_FIELD(u8_t _nexth); + /* reserved */ + PACK_STRUCT_FIELD(u8_t reserved); + /* fragment offset */ + PACK_STRUCT_FIELD(u16_t _fragment_offset); + /* fragmented packet identification */ + PACK_STRUCT_FIELD(u32_t _identification); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define IP6H_V(hdr) ((ntohl((hdr)->_v_tc_fl) >> 28) & 0x0f) +#define IP6H_TC(hdr) ((ntohl((hdr)->_v_tc_fl) >> 20) & 0xff) +#define IP6H_FL(hdr) (ntohl((hdr)->_v_tc_fl) & 0x000fffff) +#define IP6H_PLEN(hdr) (ntohs((hdr)->_plen)) +#define IP6H_NEXTH(hdr) ((hdr)->_nexth) +#define IP6H_NEXTH_P(hdr) ((u8_t *)(hdr) + 6) +#define IP6H_HOPLIM(hdr) ((hdr)->_hoplim) + +#define IP6H_VTCFL_SET(hdr, v, tc, fl) (hdr)->_v_tc_fl = (htonl(((v) << 28) | ((tc) << 20) | (fl))) +#define IP6H_PLEN_SET(hdr, plen) (hdr)->_plen = htons(plen) +#define IP6H_NEXTH_SET(hdr, nexth) (hdr)->_nexth = (nexth) +#define IP6H_HOPLIM_SET(hdr, hl) (hdr)->_hoplim = (u8_t)(hl) + + +#define ip6_init() /* TODO should we init current addresses and header pointer? */ +struct netif *ip6_route(struct ip6_addr *src, struct ip6_addr *dest); +ip6_addr_t *ip6_select_source_address(struct netif *netif, ip6_addr_t * dest); +err_t ip6_input(struct pbuf *p, struct netif *inp); +err_t ip6_output(struct pbuf *p, struct ip6_addr *src, struct ip6_addr *dest, + u8_t hl, u8_t tc, u8_t nexth); +err_t ip6_output_if(struct pbuf *p, struct ip6_addr *src, struct ip6_addr *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, ip6_addr_t *src, 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_ipX(netif, dest) (((netif) != NULL) ? \ + ip6_2_ipX(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_IP6_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/ip6_addr.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/ip6_addr.h new file mode 100644 index 0000000..511da7f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/ip6_addr.h @@ -0,0 +1,286 @@ +/** + * @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_IP6_ADDR_H__ +#define __LWIP_IP6_ADDR_H__ + +#include "lwip/opt.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* This is the aligned version of ip6_addr_t, + used as local variable, on the stack, etc. */ +struct ip6_addr { + u32_t addr[4]; +}; + +/* This is the packed version of ip6_addr_t, + used in network headers that are itself packed */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip6_addr_packed { + PACK_STRUCT_FIELD(u32_t addr[4]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** ip6_addr_t uses a struct for convenience only, so that the same defines can + * operate both on ip6_addr_t as well as on ip6_addr_p_t. */ +typedef struct ip6_addr ip6_addr_t; +typedef struct ip6_addr_packed ip6_addr_p_t; + + +/** IP6_ADDR_ANY can be used as a fixed IPv6 address + * for the wildcard + */ +extern const ip6_addr_t ip6_addr_any; +#define IP6_ADDR_ANY ((ip6_addr_t *)&ip6_addr_any) + + + + +#if BYTE_ORDER == BIG_ENDIAN +/** Set an IPv6 partial address given by byte-parts. */ +#define IP6_ADDR(ip6addr, index, a,b,c,d) \ + (ip6addr)->addr[index] = ((u32_t)((a) & 0xff) << 24) | \ + ((u32_t)((b) & 0xff) << 16) | \ + ((u32_t)((c) & 0xff) << 8) | \ + (u32_t)((d) & 0xff) +#else +/** Set an IPv6 partial address given by byte-parts. +Little-endian version, stored in network order (no htonl). */ +#define IP6_ADDR(ip6addr, index, a,b,c,d) \ + (ip6addr)->addr[index] = ((u32_t)((d) & 0xff) << 24) | \ + ((u32_t)((c) & 0xff) << 16) | \ + ((u32_t)((b) & 0xff) << 8) | \ + (u32_t)((a) & 0xff) +#endif + +/** Access address in 16-bit block */ +#define IP6_ADDR_BLOCK1(ip6addr) ((u16_t)(htonl((ip6addr)->addr[0]) >> 16) & 0xffff) +#define IP6_ADDR_BLOCK2(ip6addr) ((u16_t)(htonl((ip6addr)->addr[0])) & 0xffff) +#define IP6_ADDR_BLOCK3(ip6addr) ((u16_t)(htonl((ip6addr)->addr[1]) >> 16) & 0xffff) +#define IP6_ADDR_BLOCK4(ip6addr) ((u16_t)(htonl((ip6addr)->addr[1])) & 0xffff) +#define IP6_ADDR_BLOCK5(ip6addr) ((u16_t)(htonl((ip6addr)->addr[2]) >> 16) & 0xffff) +#define IP6_ADDR_BLOCK6(ip6addr) ((u16_t)(htonl((ip6addr)->addr[2])) & 0xffff) +#define IP6_ADDR_BLOCK7(ip6addr) ((u16_t)(htonl((ip6addr)->addr[3]) >> 16) & 0xffff) +#define IP6_ADDR_BLOCK8(ip6addr) ((u16_t)(htonl((ip6addr)->addr[3])) & 0xffff) + +/** Copy IPv6 address - faster than ip6_addr_set: no NULL check */ +#define ip6_addr_copy(dest, src) do{(dest).addr[0] = (src).addr[0]; \ + (dest).addr[1] = (src).addr[1]; \ + (dest).addr[2] = (src).addr[2]; \ + (dest).addr[3] = (src).addr[3];}while(0) +/** Safely copy one IPv6 address to another (src may be NULL) */ +#define ip6_addr_set(dest, src) do{(dest)->addr[0] = (src) == NULL ? 0 : (src)->addr[0]; \ + (dest)->addr[1] = (src) == NULL ? 0 : (src)->addr[1]; \ + (dest)->addr[2] = (src) == NULL ? 0 : (src)->addr[2]; \ + (dest)->addr[3] = (src) == NULL ? 0 : (src)->addr[3];}while(0) + +/** Set complete address to zero */ +#define ip6_addr_set_zero(ip6addr) do{(ip6addr)->addr[0] = 0; \ + (ip6addr)->addr[1] = 0; \ + (ip6addr)->addr[2] = 0; \ + (ip6addr)->addr[3] = 0;}while(0) + +/** Set address to ipv6 'any' (no need for htonl()) */ +#define ip6_addr_set_any(ip6addr) ip6_addr_set_zero(ip6addr) +/** Set address to ipv6 loopback address */ +#define ip6_addr_set_loopback(ip6addr) do{(ip6addr)->addr[0] = 0; \ + (ip6addr)->addr[1] = 0; \ + (ip6addr)->addr[2] = 0; \ + (ip6addr)->addr[3] = PP_HTONL(0x00000001UL);}while(0) +/** Safely copy one IPv6 address to another and change byte order + * from host- to network-order. */ +#define ip6_addr_set_hton(dest, src) do{(dest)->addr[0] = (src) == NULL ? 0 : htonl((src)->addr[0]); \ + (dest)->addr[1] = (src) == NULL ? 0 : htonl((src)->addr[1]); \ + (dest)->addr[2] = (src) == NULL ? 0 : htonl((src)->addr[2]); \ + (dest)->addr[3] = (src) == NULL ? 0 : htonl((src)->addr[3]);}while(0) + + + +/** + * Determine if two IPv6 address are on the same network. + * + * @arg addr1 IPv6 address 1 + * @arg addr2 IPv6 address 2 + * @return !0 if the network identifiers of both address match + */ +#define ip6_addr_netcmp(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \ + ((addr1)->addr[1] == (addr2)->addr[1])) + +#define ip6_addr_cmp(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \ + ((addr1)->addr[1] == (addr2)->addr[1]) && \ + ((addr1)->addr[2] == (addr2)->addr[2]) && \ + ((addr1)->addr[3] == (addr2)->addr[3])) + +#define ip6_get_subnet_id(ip6addr) (htonl((ip6addr)->addr[2]) & 0x0000ffffUL) + +#define ip6_addr_isany(ip6addr) (((ip6addr) == NULL) || \ + (((ip6addr)->addr[0] == 0) && \ + ((ip6addr)->addr[1] == 0) && \ + ((ip6addr)->addr[2] == 0) && \ + ((ip6addr)->addr[3] == 0))) + + +#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_ismulticast(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff000000UL)) == PP_HTONL(0xff000000UL)) +#define ip6_addr_multicast_transient_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00100000UL)) +#define ip6_addr_multicast_prefix_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00200000UL)) +#define ip6_addr_multicast_rendezvous_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00400000UL)) +#define ip6_addr_multicast_scope(ip6addr) ((htonl((ip6addr)->addr[0]) >> 16) & 0xf) +#define IP6_MULTICAST_SCOPE_RESERVED 0x0 +#define IP6_MULTICAST_SCOPE_RESERVED0 0x0 +#define IP6_MULTICAST_SCOPE_INTERFACE_LOCAL 0x1 +#define IP6_MULTICAST_SCOPE_LINK_LOCAL 0x2 +#define IP6_MULTICAST_SCOPE_RESERVED3 0x3 +#define IP6_MULTICAST_SCOPE_ADMIN_LOCAL 0x4 +#define IP6_MULTICAST_SCOPE_SITE_LOCAL 0x5 +#define IP6_MULTICAST_SCOPE_ORGANIZATION_LOCAL 0x8 +#define IP6_MULTICAST_SCOPE_GLOBAL 0xe +#define IP6_MULTICAST_SCOPE_RESERVEDF 0xf +#define ip6_addr_ismulticast_iflocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff010000UL)) +#define ip6_addr_ismulticast_linklocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff020000UL)) +#define ip6_addr_ismulticast_adminlocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff040000UL)) +#define ip6_addr_ismulticast_sitelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff050000UL)) +#define ip6_addr_ismulticast_orglocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff080000UL)) +#define ip6_addr_ismulticast_global(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == 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] = htonl(0xff000000UL | (htonl(if_id) & 0x00ffffffUL));}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] == htonl(0xff000000UL | (htonl((sn_addr)->addr[3]) & 0x00ffffffUL)))) + +/* IPv6 address states. */ +#define IP6_ADDR_INVALID 0x00 +#define IP6_ADDR_TENTATIVE 0x08 +#define IP6_ADDR_TENTATIVE_1 0x09 /* 1 probe sent */ +#define IP6_ADDR_TENTATIVE_2 0x0a /* 2 probes sent */ +#define IP6_ADDR_TENTATIVE_3 0x0b /* 3 probes sent */ +#define IP6_ADDR_TENTATIVE_4 0x0c /* 4 probes sent */ +#define IP6_ADDR_TENTATIVE_5 0x0d /* 5 probes sent */ +#define IP6_ADDR_TENTATIVE_6 0x0e /* 6 probes sent */ +#define IP6_ADDR_TENTATIVE_7 0x0f /* 7 probes sent */ +#define IP6_ADDR_VALID 0x10 +#define IP6_ADDR_PREFERRED 0x30 +#define IP6_ADDR_DEPRECATED 0x50 + +#define ip6_addr_isinvalid(addr_state) (addr_state == IP6_ADDR_INVALID) +#define ip6_addr_istentative(addr_state) (addr_state & IP6_ADDR_TENTATIVE) +#define ip6_addr_isvalid(addr_state) (addr_state & IP6_ADDR_VALID) /* Include valid, preferred, and deprecated. */ +#define ip6_addr_ispreferred(addr_state) (addr_state == IP6_ADDR_PREFERRED) +#define ip6_addr_isdeprecated(addr_state) (addr_state == IP6_ADDR_DEPRECATED) + +#define ip6_addr_debug_print(debug, ipaddr) \ + LWIP_DEBUGF(debug, ("%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F, \ + ipaddr != NULL ? IP6_ADDR_BLOCK1(ipaddr) : 0, \ + ipaddr != NULL ? IP6_ADDR_BLOCK2(ipaddr) : 0, \ + ipaddr != NULL ? IP6_ADDR_BLOCK3(ipaddr) : 0, \ + ipaddr != NULL ? IP6_ADDR_BLOCK4(ipaddr) : 0, \ + ipaddr != NULL ? IP6_ADDR_BLOCK5(ipaddr) : 0, \ + ipaddr != NULL ? IP6_ADDR_BLOCK6(ipaddr) : 0, \ + ipaddr != NULL ? IP6_ADDR_BLOCK7(ipaddr) : 0, \ + ipaddr != NULL ? IP6_ADDR_BLOCK8(ipaddr) : 0)) + +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_IP6_ADDR_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/ip6_frag.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/ip6_frag.h new file mode 100644 index 0000000..53c2eeb --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/ip6_frag.h @@ -0,0 +1,102 @@ +/** + * @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_IP6_FRAG_H__ +#define __LWIP_IP6_FRAG_H__ + +#include "lwip/opt.h" +#include "lwip/pbuf.h" +#include "lwip/ip6_addr.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#if LWIP_IPV6 && LWIP_IPV6_REASS /* don't build if not configured for use in lwipopts.h */ + +/* The IPv6 reassembly timer interval in milliseconds. */ +#define IP6_REASS_TMR_INTERVAL 1000 + +/* IPv6 reassembly helper struct. + * This is exported because memp needs to know the size. + */ +struct ip6_reassdata { + struct ip6_reassdata *next; + struct pbuf *p; + struct ip6_hdr * iphdr; + 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 */ + +/** 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. */ +#ifndef __LWIP_PBUF_CUSTOM_REF__ +#define __LWIP_PBUF_CUSTOM_REF__ +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__ */ + +err_t ip6_frag(struct pbuf *p, struct netif *netif, ip6_addr_t *dest); + +#endif /* LWIP_IPV6 && LWIP_IPV6_FRAG */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_IP6_FRAG_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/mld6.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/mld6.h new file mode 100644 index 0000000..963f96c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/mld6.h @@ -0,0 +1,118 @@ +/** + * @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_MLD6_H__ +#define __LWIP_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 + +struct mld_group { + /** next link */ + struct mld_group *next; + /** interface on which the group is active */ + struct netif *netif; + /** multicast address */ + ip6_addr_t group_address; + /** signifies we were the last person to report */ + u8_t last_reporter_flag; + /** current state of the group */ + u8_t group_state; + /** timer for reporting */ + u16_t timer; + /** counter of simultaneous uses */ + u8_t use; +}; + +/** Multicast listener report/query/done message header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct mld_header { + PACK_STRUCT_FIELD(u8_t type); + PACK_STRUCT_FIELD(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_FIELD(ip6_addr_p_t multicast_address); + /* Options follow. */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define MLD6_TMR_INTERVAL 100 /* Milliseconds */ + +/* MAC Filter Actions, these are passed to a netif's + * mld_mac_filter callback function. */ +#define MLD6_DEL_MAC_FILTER 0 +#define MLD6_ADD_MAC_FILTER 1 + + +#define mld6_init() /* TODO should we init tables? */ +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, ip6_addr_t *addr); +void mld6_input(struct pbuf *p, struct netif *inp); +err_t mld6_joingroup(ip6_addr_t *srcaddr, ip6_addr_t *groupaddr); +err_t mld6_leavegroup(ip6_addr_t *srcaddr, ip6_addr_t *groupaddr); + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6_MLD && LWIP_IPV6 */ + +#endif /* __LWIP_MLD6_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/nd6.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/nd6.h new file mode 100644 index 0000000..4974933 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/ipv6/lwip/nd6.h @@ -0,0 +1,369 @@ +/** + * @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_ND6_H__ +#define __LWIP_ND6_H__ + +#include "lwip/opt.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/netif.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Struct for tables. */ +struct nd6_neighbor_cache_entry { + ip6_addr_t next_hop_address; + struct netif * netif; + u8_t lladdr[NETIF_MAX_HWADDR_LEN]; + /*u32_t pmtu;*/ +#if LWIP_ND6_QUEUEING + /** Pointer to queue of pending outgoing packets on this entry. */ + struct nd6_q_entry *q; +#else /* LWIP_ND6_QUEUEING */ + /** Pointer to a single pending outgoing packet on this entry. */ + struct pbuf *q; +#endif /* LWIP_ND6_QUEUEING */ + u8_t state; + u8_t isrouter; + union { + u32_t reachable_time; + u32_t delay_time; + u32_t probes_sent; + u32_t stale_time; + } counter; +}; + +struct nd6_destination_cache_entry { + ip6_addr_t destination_addr; + ip6_addr_t next_hop_addr; + u32_t pmtu; + u32_t age; +}; + +struct nd6_prefix_list_entry { + ip6_addr_t prefix; + struct netif * netif; + u32_t invalidation_timer; +#if LWIP_IPV6_AUTOCONFIG + u8_t flags; +#define ND6_PREFIX_AUTOCONFIG_AUTONOMOUS 0x01 +#define ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED 0x02 +#define ND6_PREFIX_AUTOCONFIG_ADDRESS_DUPLICATE 0x04 +#endif /* LWIP_IPV6_AUTOCONFIG */ +}; + +struct nd6_router_list_entry { + struct nd6_neighbor_cache_entry * neighbor_entry; + u32_t invalidation_timer; + u8_t flags; +}; + + +enum nd6_neighbor_cache_entry_state { + ND6_NO_ENTRY = 0, + ND6_INCOMPLETE, + ND6_REACHABLE, + ND6_STALE, + ND6_DELAY, + ND6_PROBE +}; + +#if LWIP_ND6_QUEUEING +/** struct for queueing outgoing packets for unknown address + * defined here to be accessed by memp.h + */ +struct nd6_q_entry { + struct nd6_q_entry *next; + struct pbuf *p; +}; +#endif /* LWIP_ND6_QUEUEING */ + +/** Neighbor solicitation message header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ns_header { + PACK_STRUCT_FIELD(u8_t type); + PACK_STRUCT_FIELD(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u32_t reserved); + PACK_STRUCT_FIELD(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_FIELD(u8_t type); + PACK_STRUCT_FIELD(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u8_t flags); + PACK_STRUCT_FIELD(u8_t reserved[3]); + PACK_STRUCT_FIELD(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_FIELD(u8_t type); + PACK_STRUCT_FIELD(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_STATEFUL_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_FIELD(u8_t type); + PACK_STRUCT_FIELD(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u8_t current_hop_limit); + PACK_STRUCT_FIELD(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_FIELD(u8_t type); + PACK_STRUCT_FIELD(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u32_t reserved); + PACK_STRUCT_FIELD(ip6_addr_p_t target_address); + PACK_STRUCT_FIELD(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_FIELD(u8_t type); + PACK_STRUCT_FIELD(u8_t length); + PACK_STRUCT_FIELD(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_FIELD(u8_t type); + PACK_STRUCT_FIELD(u8_t length); + PACK_STRUCT_FIELD(u8_t prefix_length); + PACK_STRUCT_FIELD(u8_t flags); + PACK_STRUCT_FIELD(u32_t valid_lifetime); + PACK_STRUCT_FIELD(u32_t preferred_lifetime); + PACK_STRUCT_FIELD(u8_t reserved2[3]); + PACK_STRUCT_FIELD(u8_t site_prefix_length); + PACK_STRUCT_FIELD(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_FIELD(u8_t type); + PACK_STRUCT_FIELD(u8_t length); + PACK_STRUCT_FIELD(u8_t reserved[6]); + /* Portion of redirected packet follows. */ + /* PACK_STRUCT_FIELD(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_FIELD(u8_t type); + PACK_STRUCT_FIELD(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_FIELD(u8_t type); + PACK_STRUCT_FIELD(u8_t length); + PACK_STRUCT_FIELD(u8_t prefix_length); + PACK_STRUCT_FIELD(u8_t preference); + PACK_STRUCT_FIELD(u32_t route_lifetime); + PACK_STRUCT_FIELD(ip6_addr_p_t prefix); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* the possible states of an IP address */ +#define IP6_ADDRESS_STATE_INVALID (0) +#define IP6_ADDRESS_STATE_VALID (0x4) +#define IP6_ADDRESS_STATE_PREFERRED (0x5) /* includes valid */ +#define IP6_ADDRESS_STATE_DEPRECATED (0x6) /* includes valid */ +#define IP6_ADDRESS_STATE_TENTATIV (0x8) + +/** 1 second period */ +#define ND6_TMR_INTERVAL 1000 + +/* Router tables. */ +/* TODO make these static? and entries accessible through API? */ +extern struct nd6_neighbor_cache_entry neighbor_cache[]; +extern struct nd6_destination_cache_entry destination_cache[]; +extern struct nd6_prefix_list_entry prefix_list[]; +extern struct nd6_router_list_entry default_router_list[]; + +/* Default values, can be updated by a RA message. */ +extern u32_t reachable_time; +extern u32_t retrans_timer; + +#define nd6_init() /* TODO should we init tables? */ +void nd6_tmr(void); +void nd6_input(struct pbuf *p, struct netif *inp); +s8_t nd6_get_next_hop_entry(ip6_addr_t * ip6addr, struct netif * netif); +s8_t nd6_select_router(ip6_addr_t * ip6addr, struct netif * netif); +u16_t nd6_get_destination_mtu(ip6_addr_t * ip6addr, struct netif * netif); +err_t nd6_queue_packet(s8_t neighbor_index, struct pbuf * p); +#if LWIP_ND6_TCP_REACHABILITY_HINTS +void nd6_reachability_hint(ip6_addr_t * ip6addr); +#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 */ + +#endif /* __LWIP_ND6_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/api.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/api.h new file mode 100644 index 0000000..08b7b1d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/api.h @@ -0,0 +1,440 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS 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 +#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 */ + + //***********Code for WIFI_BLOCK from upper************** +#define NETCONN_FLAG_RECV_HOLD 0x80 + + +/* Helpers to process several netconn_types by the same code */ +#define NETCONNTYPE_GROUP(t) ((t)&0xF0) +#define NETCONNTYPE_DATAGRAM(t) ((t)&0xE0) +#if LWIP_IPV6 +#define NETCONN_TYPE_IPV6 0x08 +#define NETCONNTYPE_ISIPV6(t) ((t)&0x08) +#define NETCONNTYPE_ISUDPLITE(t) (((t)&0xF7) == NETCONN_UDPLITE) +#define NETCONNTYPE_ISUDPNOCHKSUM(t) (((t)&0xF7) == NETCONN_UDPNOCHKSUM) +#else /* LWIP_IPV6 */ +#define NETCONNTYPE_ISUDPLITE(t) ((t) == NETCONN_UDPLITE) +#define NETCONNTYPE_ISUDPNOCHKSUM(t) ((t) == NETCONN_UDPNOCHKSUM) +#endif /* LWIP_IPV6 */ + +/** Protocol family and type of the netconn */ +enum netconn_type { + NETCONN_INVALID = 0, + /* NETCONN_TCP Group */ + NETCONN_TCP = 0x10, +#if LWIP_IPV6 + NETCONN_TCP_IPV6 = NETCONN_TCP | NETCONN_TYPE_IPV6 /* 0x18 */, +#endif /* LWIP_IPV6 */ + /* NETCONN_UDP Group */ + NETCONN_UDP = 0x20, + NETCONN_UDPLITE = 0x21, + NETCONN_UDPNOCHKSUM = 0x22, +#if LWIP_IPV6 + NETCONN_UDP_IPV6 = NETCONN_UDP | NETCONN_TYPE_IPV6 /* 0x28 */, + NETCONN_UDPLITE_IPV6 = NETCONN_UDPLITE | NETCONN_TYPE_IPV6 /* 0x29 */, + NETCONN_UDPNOCHKSUM_IPV6 = NETCONN_UDPNOCHKSUM | NETCONN_TYPE_IPV6 /* 0x2a */, +#endif /* LWIP_IPV6 */ + /* NETCONN_RAW Group */ + NETCONN_RAW = 0x40 +#if LWIP_IPV6 + , + NETCONN_RAW_IPV6 = NETCONN_RAW | NETCONN_TYPE_IPV6 /* 0x48 */ +#endif /* LWIP_IPV6 */ +}; + +/** Current state of the netconn. Non-TCP netconns are always + * in state NETCONN_NONE! */ +enum netconn_state { + NETCONN_NONE, + NETCONN_WRITE, + NETCONN_LISTEN, + NETCONN_CONNECT, + NETCONN_CLOSE +}; + +/** Use to inform the callback function about changes */ +enum netconn_evt { + NETCONN_EVT_RCVPLUS, + NETCONN_EVT_RCVMINUS, + NETCONN_EVT_SENDPLUS, + NETCONN_EVT_SENDMINUS, + NETCONN_EVT_ERROR +}; + +#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) +/** Used for netconn_join_leave_group() */ +enum netconn_igmp { + NETCONN_JOIN, + NETCONN_LEAVE +}; +#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ + +/* 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; // + sys_sem_t snd_op_completed; //only for snd semphore + sys_sem_t ioctrl_completed; //only for IO ctrl semphore + /** 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) */ + s32_t send_timeout; +#endif /* LWIP_SO_RCVTIMEO */ +#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 + //***********Code for WIFI_BLOCK from upper************** + u32_t recv_holded_buf_Len; + /** 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; + +#if LWIP_SO_LINGER + /* add by DongHeng, to force to free TCP */ + s16_t linger; +#endif + +#ifdef SOCKETS_TCP_TRACE + u32_t recv_bytes[2]; + u32_t recv_bytes_err[2]; + + u32_t send_bytes[2]; + u32_t send_bytes_ok[2]; + u32_t send_bytes_nomem[2]; + +#define ADD_TCP_RECV_BYTES(s, b) \ +{ \ + if (s->recv_bytes[0] > 0xffff0000){ \ + s->recv_bytes[0] = b; \ + s->recv_bytes[1]++; \ + } else { \ + s->recv_bytes[0] += b; \ + } \ +} + +#define ADD_TCP_RECV_BYTES_ERR(s, b) \ +{ \ + if (s->recv_bytes_err[0] > 0xffff0000){ \ + s->recv_bytes_err[0] = b; \ + s->recv_bytes_err[1]++; \ + } else { \ + s->recv_bytes_err[0] += b; \ + } \ +} + +#define ADD_TCP_SEND_BYTES(s, b) \ +{ \ + if (s->send_bytes[0] > 0xffff0000){ \ + s->send_bytes[0] = b; \ + s->send_bytes[1]++; \ + } else { \ + s->send_bytes[0] += b; \ + } \ +} + +#define ADD_TCP_SEND_BYTES_OK(s, b) \ +{ \ + if (s->send_bytes_ok[0] > 0xffff0000){ \ + s->send_bytes_ok[0] = b; \ + s->send_bytes_ok[1]++; \ + } else { \ + s->send_bytes_ok[0] += b; \ + } \ +} + +#define ADD_TCP_SEND_BYTES_NOMEM(s, b) \ +{ \ + if (s->send_bytes_nomem[0] > 0xffff0000){ \ + s->send_bytes_nomem[0] = b; \ + s->send_bytes_nomem[1]++; \ + } else { \ + s->send_bytes_nomem[0] += b; \ + } \ +} + +#define ADD_TCP_RECV_BYTES_CLEAR(s) \ + (s)->recv_bytes[0] = (s)->recv_bytes[1] = 0; + +#define ADD_TCP_RECV_BYTES_ERR_CLEAR(s) \ + (s)->recv_bytes_err[0] = (s)->recv_bytes_err[1] = 0; + +#define ADD_TCP_SEND_BYTES_CLEAR(s) \ + (s)->send_bytes[0] = (s)->send_bytes[1] = 0; + +#define ADD_TCP_SEND_BYTES_OK_CLEAR(s) \ + (s)->send_bytes_ok[0] = (s)->send_bytes_ok[1] = 0; + +#define ADD_TCP_SEND_BYTES_NOMEM_CLEAR(s) \ + (s)->send_bytes_nomem[0] = (s)->send_bytes_nomem[1] = 0; + +#define ADD_TCP_RECV_BYTES_GET(s, b) \ + (b)[0] = (s)->recv_bytes[0]; (b)[1] = (s)->recv_bytes[1]; + +#define ADD_TCP_RECV_BYTES_ERR_GET(s, b) \ + (b)[0] = (s)->recv_bytes_err[0]; (b)[1] = (s)->recv_bytes_err[1]; + +#define ADD_TCP_SEND_BYTES_GET(s, b) \ + (b)[0] = (s)->send_bytes[0]; (b)[1] = (s)->send_bytes[1]; + +#define ADD_TCP_SEND_BYTES_OK_GET(s, b) \ + (b)[0] = (s)->send_bytes_ok[0]; (b)[1] = (s)->send_bytes_ok[1]; + +#define ADD_TCP_SEND_BYTES_NOMEM_GET(s, b) \ + (b)[0] = (s)->send_bytes_nomem[0]; (b)[1] = (s)->send_bytes_nomem[1]; + +#endif +}; + +/** 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_partly(struct netconn *conn, const void *dataptr, size_t size, + u8_t apiflags, size_t *bytes_written); +#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, ip_addr_t *multiaddr, + ip_addr_t *netif_addr, enum netconn_igmp join_or_leave); +#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ +#if LWIP_DNS +err_t netconn_gethostbyname(const char *name, ip_addr_t *addr); +#endif /* LWIP_DNS */ +#if LWIP_IPV6 + +#define netconn_bind_ip6(conn, ip6addr, port) (NETCONNTYPE_ISIPV6((conn)->type) ? \ + netconn_bind(conn, ip6_2_ip(ip6addr), port) : ERR_VAL) +#define netconn_connect_ip6(conn, ip6addr, port) (NETCONNTYPE_ISIPV6((conn)->type) ? \ + netconn_connect(conn, ip6_2_ip(ip6addr), port) : ERR_VAL) +#define netconn_sendto_ip6(conn, buf, ip6addr, port) (NETCONNTYPE_ISIPV6((conn)->type) ? \ + netconn_sendto(conn, buf, ip6_2_ip(ip6addr), port) : ERR_VAL) +#if LWIP_IPV6_MLD +#define netconn_join_leave_group_ip6(conn, multiaddr, srcaddr, join_or_leave) (NETCONNTYPE_ISIPV6((conn)->type) ? \ + netconn_join_leave_group(conn, ip6_2_ip(multiaddr), ip6_2_ip(srcaddr), join_or_leave) :\ + ERR_VAL) +#endif /* LWIP_IPV6_MLD*/ +#endif /* LWIP_IPV6 */ + +#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_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*/ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_NETCONN */ + +#endif /* __LWIP_API_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/api_msg.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/api_msg.h new file mode 100644 index 0000000..e5372aa --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/api_msg.h @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS 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 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 { + ip_addr_t *ipaddr; + u16_t port; + } bc; + /** used for lwip_netconn_do_getaddr */ + struct { + ipX_addr_t *ipaddr; + u16_t *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; + /** used for lwip_netconn_do_close (/shutdown) */ + struct { + u8_t shut; + } sd; +#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) + /** used for lwip_netconn_do_join_leave_group */ + struct { + ipX_addr_t *multiaddr; + ipX_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; +}; + +/** 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 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 */ + 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 lwip_netconn_do_newconn ( struct api_msg_msg *msg); +void lwip_netconn_do_delconn ( struct api_msg_msg *msg); +void lwip_netconn_do_bind ( struct api_msg_msg *msg); +void lwip_netconn_do_connect ( struct api_msg_msg *msg); +void lwip_netconn_do_disconnect ( struct api_msg_msg *msg); +void lwip_netconn_do_listen ( struct api_msg_msg *msg); +void lwip_netconn_do_send ( struct api_msg_msg *msg); +void lwip_netconn_do_recv ( struct api_msg_msg *msg); +void lwip_netconn_do_write ( struct api_msg_msg *msg); +void lwip_netconn_do_getaddr ( struct api_msg_msg *msg); +void lwip_netconn_do_close ( struct api_msg_msg *msg); +void lwip_netconn_do_shutdown ( struct api_msg_msg *msg); +#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) +void lwip_netconn_do_join_leave_group( struct api_msg_msg *msg); +#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 */ + +#endif /* __LWIP_API_MSG_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/arch.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/arch.h new file mode 100644 index 0000000..919a6cf --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/arch.h @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS 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 */ + +#ifndef errno +extern int errno; +#endif + +#endif /* LWIP_PROVIDE_ERRNO */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_ARCH_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/debug.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/debug.h new file mode 100644 index 0000000..7c4143a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/debug.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS 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" +#include "lwip/opt.h" + +/** lower two bits indicate debug level + * - 0 all + * - 1 warning + * - 2 serious + * - 3 severe + */ +#define LWIP_DBG_LEVEL_ALL 0x00 +#define LWIP_DBG_LEVEL_OFF LWIP_DBG_LEVEL_ALL /* compatibility define only */ +#define LWIP_DBG_LEVEL_WARNING 0x01 /* bad checksums, dropped packets, ... */ +#define LWIP_DBG_LEVEL_SERIOUS 0x02 /* memory allocation failures, ... */ +#define LWIP_DBG_LEVEL_SEVERE 0x03 +#define LWIP_DBG_MASK_LEVEL 0x03 + +/** flag for LWIP_DEBUGF to enable that debug message */ +#define LWIP_DBG_ON 0x80U +/** flag for LWIP_DEBUGF to disable that debug message */ +#define LWIP_DBG_OFF 0x00U + +/** flag for LWIP_DEBUGF indicating a tracing message (to follow program flow) */ +#define LWIP_DBG_TRACE 0x40U +/** flag for LWIP_DEBUGF indicating a state debug message (to follow module states) */ +#define LWIP_DBG_STATE 0x20U +/** flag for LWIP_DEBUGF indicating newly added code, not thoroughly tested yet */ +#define LWIP_DBG_FRESH 0x10U +/** flag for LWIP_DEBUGF to halt after printing this debug message */ +#define LWIP_DBG_HALT 0x08U + +#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/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/def.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/def.h new file mode 100644 index 0000000..0349cfe --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/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/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/dhcp.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/dhcp.h new file mode 100644 index 0000000..c8f95aa --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/dhcp.h @@ -0,0 +1,254 @@ +/** @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? */ +#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**/ +#ifdef LWIP_ESP8266 +#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 + +#endif +/** 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/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/dhcpserver.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/dhcpserver.h new file mode 100644 index 0000000..f959abb --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/dhcpserver.h @@ -0,0 +1,102 @@ +#ifndef __DHCPS_H__ +#define __DHCPS_H__ + +#define USE_DNS + +typedef struct dhcps_state{ + s16_t state; +} dhcps_state; + +// ����dhcpclient�Զ����һ��DHCP msg�ṹ�� +typedef struct dhcps_msg { + u8_t op, htype, hlen, hops; + u8_t xid[4]; + u16_t secs, flags; + u8_t ciaddr[4]; + u8_t yiaddr[4]; + u8_t siaddr[4]; + u8_t giaddr[4]; + u8_t chaddr[16]; + u8_t sname[64]; + u8_t file[128]; + u8_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 + +struct dhcps_pool{ + struct ip_addr ip; + u8_t mac[6]; + u32_t lease_timer; +}; + +typedef struct _list_node{ + void *pnode; + struct _list_node *pnext; +}list_node; + +extern u32_t 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/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/dns.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/dns.h new file mode 100644 index 0000000..dacc6be --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/dns.h @@ -0,0 +1,125 @@ +/** + * 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" +#include "lwip/err.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/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/err.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/err.h new file mode 100644 index 0000000..c1566b2 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/err.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_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_USE -8 /* Address in use. */ + +#ifdef LWIP_ESP8266 +#define ERR_ALREADY -9 /* Already connected. */ +#define ERR_ISCONN -10 /* Conn already established.*/ + +#define ERR_IS_FATAL(e) ((e) < ERR_ISCONN) + +#define ERR_ABRT -11 /* Connection aborted. */ +#define ERR_RST -12 /* Connection reset. */ +#define ERR_CLSD -13 /* Connection closed. */ +#define ERR_CONN -14 /* Not connected. */ + +#define ERR_ARG -15 /* Illegal argument. */ + +#define ERR_IF -16 /* Low-level netif error */ +#else +#define ERR_ISCONN -9 /* Already connected. */ + +#define ERR_IS_FATAL(e) ((e) < ERR_ISCONN) + +#define ERR_ABRT -10 /* Connection aborted. */ +#define ERR_RST -11 /* Connection reset. */ +#define ERR_CLSD -12 /* Connection closed. */ +#define ERR_CONN -13 /* Not connected. */ + +#define ERR_ARG -14 /* Illegal argument. */ + +#define ERR_IF -15 /* Low-level netif error */ +#endif + +#ifdef LWIP_DEBUG +extern const char *lwip_strerr(err_t err); +#else +#define lwip_strerr(x) "" +#endif /* LWIP_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_ERR_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/inet_chksum.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/inet_chksum.h new file mode 100644 index 0000000..f9a1723 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/inet_chksum.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS 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); +u16_t inet_chksum_pbuf(struct pbuf *p); +u16_t inet_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, + ip_addr_t *src, ip_addr_t *dest); +u16_t inet_chksum_pseudo_partial(struct pbuf *p, u8_t proto, + u16_t proto_len, u16_t chksum_len, ip_addr_t *src, ip_addr_t *dest); +#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_IPV6 +u16_t ip6_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, + ip6_addr_t *src, ip6_addr_t *dest); +u16_t ip6_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, + u16_t chksum_len, ip6_addr_t *src, ip6_addr_t *dest); + +#define ipX_chksum_pseudo(isipv6, p, proto, proto_len, src, dest) \ + ((isipv6) ? \ + ip6_chksum_pseudo(p, proto, proto_len, ipX_2_ip6(src), ipX_2_ip6(dest)) :\ + inet_chksum_pseudo(p, proto, proto_len, ipX_2_ip(src), ipX_2_ip(dest))) +#define ipX_chksum_pseudo_partial(isipv6, p, proto, proto_len, chksum_len, src, dest) \ + ((isipv6) ? \ + ip6_chksum_pseudo_partial(p, proto, proto_len, chksum_len, ipX_2_ip6(src), ipX_2_ip6(dest)) :\ + inet_chksum_pseudo_partial(p, proto, proto_len, chksum_len, ipX_2_ip(src), ipX_2_ip(dest))) + +#else /* LWIP_IPV6 */ + +#define ipX_chksum_pseudo(isipv6, p, proto, proto_len, src, dest) \ + inet_chksum_pseudo(p, proto, proto_len, src, dest) +#define ipX_chksum_pseudo_partial(isipv6, p, proto, proto_len, chksum_len, src, dest) \ + inet_chksum_pseudo_partial(p, proto, proto_len, chksum_len, src, dest) + +#endif /* LWIP_IPV6 */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_INET_H__ */ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/init.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/init.h new file mode 100644 index 0000000..c9d8300 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/init.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS 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 1U +/** 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 0U + +/** 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); + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_INIT_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/ip.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/ip.h new file mode 100644 index 0000000..c996954 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/ip.h @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS 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" +#include "lwip/ip4.h" +#include "lwip/ip6.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. */ +#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 */ + +#if LWIP_IPV6 +#define IP_PCB_ISIPV6_MEMBER u8_t isipv6; +#define IP_PCB_IPVER_EQ(pcb1, pcb2) ((pcb1)->isipv6 == (pcb2)->isipv6) +#define IP_PCB_IPVER_INPUT_MATCH(pcb) (ip_current_is_v6() ? \ + ((pcb)->isipv6 != 0) : \ + ((pcb)->isipv6 == 0)) +#define PCB_ISIPV6(pcb) ((pcb)->isipv6) +#else +#define IP_PCB_ISIPV6_MEMBER +#define IP_PCB_IPVER_EQ(pcb1, pcb2) 1 +#define IP_PCB_IPVER_INPUT_MATCH(pcb) 1 +#define PCB_ISIPV6(pcb) 0 +#endif /* LWIP_IPV6 */ + +/* 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_PCB_ISIPV6_MEMBER \ + /* ip addresses in network byte order */ \ + ipX_addr_t local_ip; \ + ipX_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 0x01U Unimplemented: turn on debugging info recording */ +#define SOF_ACCEPTCONN 0x02U /* socket has had listen() */ +#define SOF_REUSEADDR 0x04U /* allow local address reuse */ +#define SOF_KEEPALIVE 0x08U /* keep connections alive */ +/*#define SOF_DONTROUTE 0x10U Unimplemented: just use interface addresses */ +#define SOF_BROADCAST 0x20U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ +/*#define SOF_USELOOPBACK 0x40U Unimplemented: bypass hardware when possible */ +#define SOF_LINGER 0x80U /* linger on close if data present */ +/*#define SOF_OOBINLINE 0x0100U Unimplemented: leave received OOB data in line */ +/*#define SOF_REUSEPORT 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*/) + +/* Global variables of this module, kept in a struct for efficient access using base+index. */ +struct ip_globals +{ + /** 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_ip4_header; +#if LWIP_IPV6 + /** Header of the input IPv6 packet currently being processed. */ + const 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 */ + ipX_addr_t current_iphdr_src; + /** Destination IP address of current_header */ + ipX_addr_t current_iphdr_dest; +}; +extern struct ip_globals ip_data; + + +/** 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() (ip_data.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() (ip_data.current_ip4_header) +/** 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 ipX_current_src_addr() (&ip_data.current_iphdr_src) +/** Destination IP address of current_header */ +#define ipX_current_dest_addr() (&ip_data.current_iphdr_dest) + +#if 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() (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() (ipX_2_ip6(&ip_data.current_iphdr_src)) +/** Destination IPv6 address of current_header */ +#define ip6_current_dest_addr() (ipX_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(ip_current_header())) +/** Get the transport layer header */ +#define ipX_next_header_ptr() ((void*)((ip_current_is_v6() ? \ + (u8_t*)ip6_current_header() : (u8_t*)ip_current_header()) + ip_current_header_tot_len())) + +/** Set an IP_PCB to IPv6 (IPv4 is the default) */ +#define ip_set_v6(pcb, val) do{if(pcb != NULL) { pcb->isipv6 = val; }}while(0) + +/** Source IP4 address of current_header */ +#define ip_current_src_addr() (ipX_2_ip(&ip_data.current_iphdr_src)) +/** Destination IP4 address of current_header */ +#define ip_current_dest_addr() (ipX_2_ip(&ip_data.current_iphdr_dest)) + +#else /* LWIP_IPV6 */ + +/** Always returns FALSE when only supporting IPv4 */ +#define ip_current_is_v6() 0 +/** Get the transport layer protocol */ +#define ip_current_header_proto() IPH_PROTO(ip_current_header()) +/** Get the transport layer header */ +#define ipX_next_header_ptr() ((void*)((u8_t*)ip_current_header() + ip_current_header_tot_len())) +/** Source IP4 address of current_header */ +#define ip_current_src_addr() (&ip_data.current_iphdr_src) +/** Destination IP4 address of current_header */ +#define ip_current_dest_addr() (&ip_data.current_iphdr_dest) + +#endif /* LWIP_IPV6 */ + +/** Union source address of current_header */ +#define ipX_current_src_addr() (&ip_data.current_iphdr_src) +/** Union destination address of current_header */ +#define ipX_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_IPV6 +#define ipX_output(isipv6, p, src, dest, ttl, tos, proto) \ + ((isipv6) ? \ + ip6_output(p, ipX_2_ip6(src), ipX_2_ip6(dest), ttl, tos, proto) : \ + ip_output(p, ipX_2_ip(src), ipX_2_ip(dest), ttl, tos, proto)) +#define ipX_output_if(isipv6, p, src, dest, ttl, tos, proto, netif) \ + ((isipv6) ? \ + ip6_output_if(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto, netif) : \ + ip_output_if(p, (src), (dest), ttl, tos, proto, netif)) +#define ipX_output_hinted(isipv6, p, src, dest, ttl, tos, proto, addr_hint) \ + ((isipv6) ? \ + ip6_output_hinted(p, ipX_2_ip6(src), ipX_2_ip6(dest), ttl, tos, proto, addr_hint) : \ + ip_output_hinted(p, ipX_2_ip(src), ipX_2_ip(dest), ttl, tos, proto, addr_hint)) +#define ipX_route(isipv6, src, dest) \ + ((isipv6) ? \ + ip6_route(ipX_2_ip6(src), ipX_2_ip6(dest)) : \ + ip_route(ipX_2_ip(dest))) +#define ipX_netif_get_local_ipX(isipv6, netif, dest) \ + ((isipv6) ? \ + ip6_netif_get_local_ipX(netif, ipX_2_ip6(dest)) : \ + ip_netif_get_local_ipX(netif)) +#define ipX_debug_print(is_ipv6, p) ((is_ipv6) ? ip6_debug_print(p) : ip_debug_print(p)) +#else /* LWIP_IPV6 */ +#define ipX_output(isipv6, p, src, dest, ttl, tos, proto) \ + ip_output(p, src, dest, ttl, tos, proto) +#define ipX_output_if(isipv6, p, src, dest, ttl, tos, proto, netif) \ + ip_output_if(p, src, dest, ttl, tos, proto, netif) +#define ipX_output_hinted(isipv6, p, src, dest, ttl, tos, proto, addr_hint) \ + ip_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) +#define ipX_route(isipv6, src, dest) \ + ip_route(ipX_2_ip(dest)) +#define ipX_netif_get_local_ipX(isipv6, netif, dest) \ + ip_netif_get_local_ipX(netif) +#define ipX_debug_print(is_ipv6, p) ip_debug_print(p) +#endif /* LWIP_IPV6 */ + +#define ipX_route_get_local_ipX(isipv6, src, dest, netif, ipXaddr) do { \ + (netif) = ipX_route(isipv6, src, dest); \ + (ipXaddr) = ipX_netif_get_local_ipX(isipv6, netif, dest); \ +}while(0) + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_IP_H__ */ + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/ip_addr.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/ip_addr.h new file mode 100644 index 0000000..a78fef6 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/ip_addr.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS 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" + +#include "lwip/ip4_addr.h" +#include "lwip/ip6_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_IPV6 +/* A union struct for both IP version's addresses. */ +typedef union { + ip_addr_t ip4; + ip6_addr_t ip6; +} ipX_addr_t; + +/** These functions only exist for type-safe conversion from ip_addr_t to + ip6_addr_t and back */ +#ifdef LWIP_ALLOW_STATIC_FN_IN_HEADER +static ip6_addr_t* ip_2_ip6(ip_addr_t *ipaddr) +{ return (ip6_addr_t*)ipaddr;} +static ip_addr_t* ip6_2_ip(ip6_addr_t *ip6addr) +{ return (ip_addr_t*)ip6addr; } +static ipX_addr_t* ip_2_ipX(ip_addr_t *ipaddr) +{ return (ipX_addr_t*)ipaddr; } +static ipX_addr_t* ip6_2_ipX(ip6_addr_t *ip6addr) +{ return (ipX_addr_t*)ip6addr; } +#else /* LWIP_ALLOW_STATIC_FN_IN_HEADER */ +#define ip_2_ip6(ipaddr) ((ip6_addr_t*)(ipaddr)) +#define ip6_2_ip(ip6addr) ((ip_addr_t*)(ip6addr)) +#define ip_2_ipX(ipaddr) ((ipX_addr_t*)ipaddr) +#define ip6_2_ipX(ip6addr) ((ipX_addr_t*)ip6addr) +#endif /* LWIP_ALLOW_STATIC_FN_IN_HEADER*/ +#define ipX_2_ip6(ip6addr) (&((ip6addr)->ip6)) +#define ipX_2_ip(ipaddr) (&((ipaddr)->ip4)) + +#define ipX_addr_copy(is_ipv6, dest, src) do{if(is_ipv6){ \ + ip6_addr_copy((dest).ip6, (src).ip6); }else{ \ + ip_addr_copy((dest).ip4, (src).ip4); }}while(0) +#define ipX_addr_set(is_ipv6, dest, src) do{if(is_ipv6){ \ + ip6_addr_set(ipX_2_ip6(dest), ipX_2_ip6(src)); }else{ \ + ip_addr_set(ipX_2_ip(dest), ipX_2_ip(src)); }}while(0) +#define ipX_addr_set_ipaddr(is_ipv6, dest, src) do{if(is_ipv6){ \ + ip6_addr_set(ipX_2_ip6(dest), ip_2_ip6(src)); }else{ \ + ip_addr_set(ipX_2_ip(dest), src); }}while(0) +#define ipX_addr_set_zero(is_ipv6, ipaddr) do{if(is_ipv6){ \ + ip6_addr_set_zero(ipX_2_ip6(ipaddr)); }else{ \ + ip_addr_set_zero(ipX_2_ip(ipaddr)); }}while(0) +#define ipX_addr_set_any(is_ipv6, ipaddr) do{if(is_ipv6){ \ + ip6_addr_set_any(ipX_2_ip6(ipaddr)); }else{ \ + ip_addr_set_any(ipX_2_ip(ipaddr)); }}while(0) +#define ipX_addr_set_loopback(is_ipv6, ipaddr) do{if(is_ipv6){ \ + ip6_addr_set_loopback(ipX_2_ip6(ipaddr)); }else{ \ + ip_addr_set_loopback(ipX_2_ip(ipaddr)); }}while(0) +#define ipX_addr_set_hton(is_ipv6, dest, src) do{if(is_ipv6){ \ + ip6_addr_set_hton(ipX_2_ip6(ipaddr), (src)) ;}else{ \ + ip_addr_set_hton(ipX_2_ip(ipaddr), (src));}}while(0) +#define ipX_addr_cmp(is_ipv6, addr1, addr2) ((is_ipv6) ? \ + ip6_addr_cmp(ipX_2_ip6(addr1), ipX_2_ip6(addr2)) : \ + ip_addr_cmp(ipX_2_ip(addr1), ipX_2_ip(addr2))) +#define ipX_addr_isany(is_ipv6, ipaddr) ((is_ipv6) ? \ + ip6_addr_isany(ipX_2_ip6(ipaddr)) : \ + ip_addr_isany(ipX_2_ip(ipaddr))) +#define ipX_addr_ismulticast(is_ipv6, ipaddr) ((is_ipv6) ? \ + ip6_addr_ismulticast(ipX_2_ip6(ipaddr)) : \ + ip_addr_ismulticast(ipX_2_ip(ipaddr))) +#define ipX_addr_debug_print(is_ipv6, debug, ipaddr) do { if(is_ipv6) { \ + ip6_addr_debug_print(debug, ipX_2_ip6(ipaddr)); } else { \ + ip_addr_debug_print(debug, ipX_2_ip(ipaddr)); }}while(0) + +#else /* LWIP_IPV6 */ + +typedef ip_addr_t ipX_addr_t; +#define ipX_2_ip(ipaddr) (ipaddr) +#define ip_2_ipX(ipaddr) (ipaddr) + +#define ipX_addr_copy(is_ipv6, dest, src) ip_addr_copy(dest, src) +#define ipX_addr_set(is_ipv6, dest, src) ip_addr_set(dest, src) +#define ipX_addr_set_ipaddr(is_ipv6, dest, src) ip_addr_set(dest, src) +#define ipX_addr_set_zero(is_ipv6, ipaddr) ip_addr_set_zero(ipaddr) +#define ipX_addr_set_any(is_ipv6, ipaddr) ip_addr_set_any(ipaddr) +#define ipX_addr_set_loopback(is_ipv6, ipaddr) ip_addr_set_loopback(ipaddr) +#define ipX_addr_set_hton(is_ipv6, dest, src) ip_addr_set_hton(dest, src) +#define ipX_addr_cmp(is_ipv6, addr1, addr2) ip_addr_cmp(addr1, addr2) +#define ipX_addr_isany(is_ipv6, ipaddr) ip_addr_isany(ipaddr) +#define ipX_addr_ismulticast(is_ipv6, ipaddr) ip_addr_ismulticast(ipaddr) +#define ipX_addr_debug_print(is_ipv6, debug, ipaddr) ip_addr_debug_print(debug, ipaddr) + +#endif /* LWIP_IPV6 */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_IP_ADDR_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/mem.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/mem.h new file mode 100644 index 0000000..a90dd02 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/mem.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_MEM_H__ +#define __LWIP_MEM_H__ + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if MEM_LIBC_MALLOC + +#include /* for size_t */ + +typedef size_t mem_size_t; +#define MEM_SIZE_F SZT_F + +/* 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 + +#include "esp_libc.h" + +#ifndef mem_free +#define mem_free(s) free(s) +#endif +#ifndef mem_malloc +#define mem_malloc(s) malloc(s) +#endif +#ifndef mem_calloc +#define mem_calloc(s) calloc(s) +#endif +#ifndef mem_realloc +#define mem_realloc(p, s) realloc(p, s) +#endif +#ifndef mem_zalloc +#define mem_zalloc(s) zalloc(s) +#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 + +/* 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); +void *mem_trim(void *mem, mem_size_t size); +#endif /* MEM_USE_POOLS */ +void *mem_malloc(mem_size_t size); +void *mem_calloc(mem_size_t count, mem_size_t size); +void mem_free(void *mem); +#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/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/memp.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/memp.h new file mode 100644 index 0000000..a810640 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/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) 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); + +#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); + +#endif /* MEMP_MEM_MALLOC */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_MEMP_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/memp_std.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/memp_std.h new file mode 100644 index 0000000..ea1108b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/memp_std.h @@ -0,0 +1,135 @@ +/* + * 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) +#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 IP_REASSEMBLY +LWIP_MEMPOOL(REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip_reassdata), "REASSDATA") +#endif /* IP_REASSEMBLY */ +#if (IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF) || LWIP_IPV6_FRAG +LWIP_MEMPOOL(FRAG_PBUF, MEMP_NUM_FRAG_PBUF, sizeof(struct pbuf_custom_ref),"FRAG_PBUF") +#endif /* IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */ + +#if LWIP_NETCONN +LWIP_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 LWIP_ARP && ARP_QUEUEING +LWIP_MEMPOOL(ARP_QUEUE, MEMP_NUM_ARP_QUEUE, sizeof(struct etharp_q_entry), "ARP_QUEUE") +#endif /* 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 (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) /* LWIP_TIMERS */ +LWIP_MEMPOOL(SYS_TIMEOUT, MEMP_NUM_SYS_TIMEOUT, sizeof(struct sys_timeo), "SYS_TIMEOUT") +#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 */ + +#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/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/multi-threads/sockets_mt.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/multi-threads/sockets_mt.h new file mode 100644 index 0000000..02a4112 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/multi-threads/sockets_mt.h @@ -0,0 +1,98 @@ +#ifndef _SOCKETS_MT_H_ +#define _SOCKETS_MT_H_ + +#ifdef SOCKETS_MT + +int lwip_mt_init(void); +int lwip_socket_mt(int domain, int type, int protocol); +int lwip_bind_mt(int s, const struct sockaddr *name, socklen_t namelen); +int lwip_connect_mt(int s, const struct sockaddr *name, socklen_t namelen); +int lwip_listen_mt(int s, int backlog); +int lwip_accept_mt(int s, struct sockaddr *addr, socklen_t *addrlen); +int lwip_getpeername_mt(int s, struct sockaddr *name, socklen_t *namelen); +int lwip_getsockname_mt(int s, struct sockaddr *name, socklen_t *namelen); +int lwip_setsockopt_mt(int s, int level, int optname, const void *optval, socklen_t optlen); +int lwip_getsockopt_mt(int s, int level, int optname, void *optval, socklen_t *optlen); +int lwip_ioctl_mt(int s, long cmd, void *argp); +int lwip_sendto_mt(int s, const void *data, size_t size, int flags, + const struct sockaddr *to, socklen_t tolen); +int lwip_send_mt(int s, const void *data, size_t size, int flags); +int lwip_recvfrom_mt(int s, void *mem, size_t len, int flags, + struct sockaddr *from, socklen_t *fromlen); +int lwip_recv_mt(int s, void *mem, size_t len, int flags); +int lwip_read_mt(int s, void *mem, size_t len); +int lwip_write_mt(int s, const void *data, size_t size); +int lwip_shutdown_mt(int s, int how); +int lwip_close_mt(int s); +int lwip_select_mt(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, struct timeval *timeout); +int lwip_fcntl_mt(int s, int cmd, int val); + +#ifdef SOCKETS_TCP_TRACE +int lwip_trace_tcp(int s, int cmd, void *arg); +#endif + + +#if LWIP_COMPAT_SOCKETS + +#ifdef SOCKETS_MT_DBUG + +#define accept(a,b,c) lwip_accept_mt(a,b,c); os_printf("%s %d\n", __FUNCTION__, __LINE__); +#define bind(a,b,c) lwip_bind_mt(a,b,c); os_printf("%s %d\n", __FUNCTION__, __LINE__); +#define shutdown(a,b) lwip_shutdown_mt(a,b); os_printf("%s %d\n", __FUNCTION__, __LINE__); +#define closesocket(s) lwip_close_mt(s); os_printf("%s %d\n", __FUNCTION__, __LINE__); +#define connect(a,b,c) lwip_connect_mt(a,b,c); os_printf("%s %d\n", __FUNCTION__, __LINE__); +#define getsockname(a,b,c) lwip_getsockname_mt(a,b,c); os_printf("%s %d\n", __FUNCTION__, __LINE__); +#define getpeername(a,b,c) lwip_getpeername_mt(a,b,c); os_printf("%s %d\n", __FUNCTION__, __LINE__); +#define setsockopt(a,b,c,d,e) lwip_setsockopt_mt(a,b,c,d,e); os_printf("%s %d\n", __FUNCTION__, __LINE__); +#define getsockopt(a,b,c,d,e) lwip_getsockopt_mt(a,b,c,d,e); os_printf("%s %d\n", __FUNCTION__, __LINE__); +#define listen(a,b) lwip_listen_mt(a,b); os_printf("%s %d\n", __FUNCTION__, __LINE__); +#define recv(a,b,c,d) lwip_recv_mt(a,b,c,d); os_printf("%s %d\n", __FUNCTION__, __LINE__); +#define recvfrom(a,b,c,d,e,f) lwip_recvfrom_mt(a,b,c,d,e,f); os_printf("%s %d\n", __FUNCTION__, __LINE__); +#define send(a,b,c,d) lwip_send_mt(a,b,c,d); os_printf("%s %d\n", __FUNCTION__, __LINE__); +#define sendto(a,b,c,d,e,f) lwip_sendto_mt(a,b,c,d,e,f); os_printf("%s %d\n", __FUNCTION__, __LINE__); +#define socket(a,b,c) lwip_socket_mt(a,b,c); os_printf("%s %d\n", __FUNCTION__, __LINE__); +#define select(a,b,c,d,e) lwip_select_mt(a,b,c,d,e) +#define ioctlsocket(a,b,c) lwip_ioctl_mt(a,b,c) ; os_printf("%s %d\n", __FUNCTION__, __LINE__); + +#if LWIP_POSIX_SOCKETS_IO_NAMES +#define read(a,b,c) lwip_read_mt(a,b,c) +#define write(a,b,c) lwip_write_mt(a,b,c) +#define close(s) lwip_close_mt(s) +#define fcntl(a,b,c) lwip_fcntl_mt(a,b,c) +#endif /* LWIP_POSIX_SOCKETS_IO_NAMES */ + +#else /* SOCKETS_MT_DBUG */ + +#define accept(a,b,c) lwip_accept_mt(a,b,c) +#define bind(a,b,c) lwip_bind_mt(a,b,c) +#define shutdown(a,b) lwip_shutdown_mt(a,b) +#define closesocket(s) lwip_close_mt(s) +#define connect(a,b,c) lwip_connect_mt(a,b,c) +#define getsockname(a,b,c) lwip_getsockname_mt(a,b,c) +#define getpeername(a,b,c) lwip_getpeername_mt(a,b,c) +#define setsockopt(a,b,c,d,e) lwip_setsockopt_mt(a,b,c,d,e) +#define getsockopt(a,b,c,d,e) lwip_getsockopt_mt(a,b,c,d,e) +#define listen(a,b) lwip_listen_mt(a,b) +#define recv(a,b,c,d) lwip_recv_mt(a,b,c,d) +#define recvfrom(a,b,c,d,e,f) lwip_recvfrom_mt(a,b,c,d,e,f) +#define send(a,b,c,d) lwip_send_mt(a,b,c,d) +#define sendto(a,b,c,d,e,f) lwip_sendto_mt(a,b,c,d,e,f) +#define socket(a,b,c) lwip_socket_mt(a,b,c) +#define select(a,b,c,d,e) lwip_select_mt(a,b,c,d,e) +#define ioctlsocket(a,b,c) lwip_ioctl_mt(a,b,c) + +#if LWIP_POSIX_SOCKETS_IO_NAMES +#define read(a,b,c) lwip_read_mt(a,b,c) +#define write(a,b,c) lwip_write_mt(a,b,c) +#define close(s) lwip_close_mt(s) +#define fcntl(a,b,c) lwip_fcntl_mt(a,b,c) +#endif /* LWIP_POSIX_SOCKETS_IO_NAMES */ + + +#endif /* SOCKETS_MT_DBUG */ + +#endif /* LWIP_COMPAT_SOCKETS */ + +#endif /* SOCKETS_MT */ + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/netbuf.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/netbuf.h new file mode 100644 index 0000000..c086d81 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/netbuf.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS 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" +#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 + +struct netbuf { + struct pbuf *p, *ptr; + ipX_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 + ipX_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) (ipX_2_ip(&((buf)->addr))) +#define netbuf_set_fromaddr(buf, fromaddr) ip_addr_set(ipX_2_ip(&((buf)->addr)), fromaddr) +#define netbuf_fromport(buf) ((buf)->port) +#if LWIP_NETBUF_RECVINFO +#define netbuf_destaddr(buf) (ipX_2_ip(&((buf)->toaddr))) +#define netbuf_set_destaddr(buf, destaddr) ip_addr_set(ipX_2_ip(&((buf)->toaddr)), 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 */ + +#if LWIP_IPV6 +#define netbuf_fromaddr_ip6(buf) (ipX_2_ip6(&((buf)->addr))) +#define netbuf_set_fromaddr_ip6(buf, fromaddr) ip6_addr_set(ipX_2_ip6(&((buf)->addr)), fromaddr) +#define netbuf_destaddr_ip6(buf) (ipX_2_ip6(&((buf)->toaddr))) +#define netbuf_set_destaddr_ip6(buf, destaddr) ip6_addr_set(ipX_2_ip6(&((buf)->toaddr)), destaddr) +#endif /* LWIP_IPV6 */ + +#define netbuf_fromaddr_ipX(buf) (&((buf)->addr)) +#define netbuf_destaddr_ipX(buf) (&((buf)->toaddr)) + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_NETBUF_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/netdb.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/netdb.h new file mode 100644 index 0000000..4b7c07a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/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/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/netif.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/netif.h new file mode 100644 index 0000000..49084b3 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/netif.h @@ -0,0 +1,393 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS 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/ip6_addr.h" + +#include "lwip/def.h" +#include "lwip/pbuf.h" +#if LWIP_DHCP +struct dhcp; +#endif +#if LWIP_AUTOIP +struct autoip; +#endif +#if LWIP_IPV6_DHCP6 +#include "lwip/dhcp6.h" +#endif /* LWIP_IPV6_DHCP6 */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Throughout this file, IP addresses are expected to be in + * the same byte order as in IP_PCB. */ + +/** must be the maximum of all used hardware address lengths + across all types of interfaces in use */ +#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); +#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 'nd_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, + 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); +/** 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); +#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, + ip6_addr_t *group, u8_t action); +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ +/*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; + + ipX_addr_t link_local_addr; + +#if LWIP_IPV6 + /** Array of IPv6 addresses for this netif. */ + ip6_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; + /** This function is called by the IP module when it wants + * to send a packet on the interface. This function typically + * first resolves the hardware address, then sends the packet. */ + netif_output_fn output; + /** This function is called by the ARP module when it wants + * to send a packet on the interface. This function outputs + * the pbuf as-is on the link medium. */ + netif_linkoutput_fn linkoutput; +#if LWIP_IPV6 + /** This function is called by the IPv6 module when it wants + * to send a packet on the interface. This function typically + * first resolves the hardware address, then sends the packet. */ + netif_output_ip6_fn output_ip6; +#endif /* LWIP_IPV6 */ +#if LWIP_NETIF_STATUS_CALLBACK + /** This function is called when the netif state is set to up or down + */ + netif_status_callback_fn status_callback; +#endif /* LWIP_NETIF_STATUS_CALLBACK */ +#if LWIP_NETIF_LINK_CALLBACK + /** This function is called when the netif link is set to up or down + */ + netif_status_callback_fn link_callback; +#endif /* LWIP_NETIF_LINK_CALLBACK */ +#if LWIP_NETIF_REMOVE_CALLBACK + /** This function is called when the netif has been removed */ + netif_status_callback_fn remove_callback; +#endif /* LWIP_NETIF_REMOVE_CALLBACK */ + /** This field can be set by the device driver and could point + * to state information for the device. */ + void *state; +#if LWIP_DHCP + /** the DHCP client state information for this netif */ + struct dhcp *dhcp; + 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_IPV6_AUTOCONFIG + /** is this netif enabled for IPv6 autoconfiguration */ + u8_t ip6_autoconfig_enabled; +#endif /* LWIP_IPV6_AUTOCONFIG */ +#if LWIP_IPV6_SEND_ROUTER_SOLICIT + /** Number of Router Solicitation messages that remain to be sent. */ + u8_t rs_count; +#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ +#if LWIP_IPV6_DHCP6 + /** the DHCPv6 client state information for this netif */ + struct dhcp6 *dhcp6; +#endif /* LWIP_IPV6_DHCP6 */ +#if LWIP_NETIF_HOSTNAME + /* the hostname for this netif, NULL is a valid value */ + char* hostname; +#endif /* LWIP_NETIF_HOSTNAME */ + /** 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 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 an entry in the multicast + filter table of the ethernet MAC.*/ + netif_igmp_mac_filter_fn igmp_mac_filter; +#endif /* 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_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); + +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); + +void +netif_set_addr(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, + ip_addr_t *gw); +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(char *name); + +void netif_set_default(struct netif *netif); + +void netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr); +void netif_set_netmask(struct netif *netif, ip_addr_t *netmask); +void netif_set_gw(struct netif *netif, ip_addr_t *gw); + +void netif_set_up(struct netif *netif); +void netif_set_down(struct netif *netif); +/** Ask if an interface is up */ +#define netif_is_up(netif) (((netif)->flags & NETIF_FLAG_UP) ? (u8_t)1 : (u8_t)0) + +#if LWIP_NETIF_STATUS_CALLBACK +void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback); +#endif /* LWIP_NETIF_STATUS_CALLBACK */ +#if LWIP_NETIF_REMOVE_CALLBACK +void netif_set_remove_callback(struct netif *netif, netif_status_callback_fn remove_callback); +#endif /* LWIP_NETIF_REMOVE_CALLBACK */ + +void netif_set_link_up(struct netif *netif); +void netif_set_link_down(struct netif *netif); +/** Ask if a link is up */ +#define netif_is_link_up(netif) (((netif)->flags & NETIF_FLAG_LINK_UP) ? (u8_t)1 : (u8_t)0) + +#if LWIP_NETIF_LINK_CALLBACK +void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback); +#endif /* LWIP_NETIF_LINK_CALLBACK */ + +#if LWIP_NETIF_HOSTNAME +#define netif_set_hostname(netif, name) do { if((netif) != NULL) { (netif)->hostname = name; }}while(0) +#define netif_get_hostname(netif) (((netif) != NULL) ? ((netif)->hostname) : NULL) +#endif /* LWIP_NETIF_HOSTNAME */ + +#if LWIP_IGMP +#define netif_set_igmp_mac_filter(netif, function) do { if((netif) != NULL) { (netif)->igmp_mac_filter = function; }}while(0) +#define netif_get_igmp_mac_filter(netif) (((netif) != NULL) ? ((netif)->igmp_mac_filter) : NULL) +#endif /* LWIP_IGMP */ + +#if ENABLE_LOOPBACK +err_t netif_loop_output(struct netif *netif, struct pbuf *p, ip_addr_t *dest_ip); +void netif_poll(struct netif *netif); +#if !LWIP_NETIF_LOOPBACK_MULTITHREADING +void netif_poll_all(void); +#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ +#endif /* ENABLE_LOOPBACK */ + +#if LWIP_IPV6 +#define netif_ip6_addr(netif, i) (&((netif)->ip6_addr[(i)])) +#define netif_ip6_addr_state(netif, i) ((netif)->ip6_addr_state[(i)]) +#define netif_ip6_addr_set_state(netif, i, state) ((netif)->ip6_addr_state[(i)] = (state)) +s8_t netif_matches_ip6_addr(struct netif * netif, ip6_addr_t * ip6addr); +void netif_create_ip6_linklocal_address(struct netif * netif, u8_t from_mac_48bit); +#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_NETIF_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/netifapi.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/netifapi.h new file mode 100644 index 0000000..141ac14 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/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/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/opt.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/opt.h new file mode 100644 index 0000000..c97e24e --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/opt.h @@ -0,0 +1,2422 @@ +/** + * @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 0 +#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) 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) + * The default number of timeouts is calculated here for all enabled modules. + * The formula expects settings to be either '0' or '1'. + */ +#ifndef MEMP_NUM_SYS_TIMEOUT +#define 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)) +#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. + * 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. + */ +#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 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. + */ +#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 + +/** + * 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! + */ +#ifndef IP_FORWARD_ALLOW_TX_ON_RX_NETIF +#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. + */ +#ifndef LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS +#define LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS 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 + +#ifndef LWIP_SO_LINGER +#define LWIP_SO_LINGER 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). + * To achieve good performance, this should be at least 2 * TCP_MSS. + */ +#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 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). + */ +#ifndef TCP_SNDQUEUELOWAT +#define TCP_SNDQUEUELOWAT LWIP_MAX(((TCP_SND_QUEUELEN)/2), 5) +#endif + +/** + * TCP_OOSEQ_MAX_BYTES: The maximum number of bytes queued on ooseq per pcb. + * Default is 0 (no limit). Only valid for TCP_QUEUE_OOSEQ==0. + */ +#ifndef TCP_OOSEQ_MAX_BYTES +#define TCP_OOSEQ_MAX_BYTES 0 +#endif + +/** + * TCP_OOSEQ_MAX_PBUFS: The maximum number of pbufs queued on ooseq per pcb. + * Default is 0 (no limit). Only valid for TCP_QUEUE_OOSEQ==0. + */ +#ifndef TCP_OOSEQ_MAX_PBUFS +#define TCP_OOSEQ_MAX_PBUFS 0 +#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. This is the default. + */ +#if !defined(LWIP_EVENT_API) && !defined(LWIP_CALLBACK_API) +#define LWIP_EVENT_API 0 +#define LWIP_CALLBACK_API 1 +#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_REMOVE_CALLBACK==1: Support a callback function that is called + * when a netif has been removed + */ +#ifndef LWIP_NETIF_REMOVE_CALLBACK +#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. + */ +#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 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 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 1 +#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 1 +#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_SNDTIMEO==1: Enable send timeout for sockets/netconns and + * SO_SNDTIMEO processing. + */ +#ifndef LWIP_SO_SNDTIMEO +#define LWIP_SO_SNDTIMEO 0 +#endif + +/** + * LWIP_SO_RCVTIMEO==1: Enable receive timeout for sockets/netconns and + * 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 + +/** + * 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. + */ +#ifndef LWIP_FIONREAD_LINUXMODE +#define LWIP_FIONREAD_LINUXMODE 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 + +/** + * IP6_STATS==1: Enable IPv6 stats. + */ +#ifndef IP6_STATS +#define IP6_STATS (LWIP_IPV6) +#endif + +/** + * ICMP6_STATS==1: Enable ICMP for IPv6 stats. + */ +#ifndef ICMP6_STATS +#define ICMP6_STATS (LWIP_IPV6 && LWIP_ICMP6) +#endif + +/** + * IP6_FRAG_STATS==1: Enable IPv6 fragmentation stats. + */ +#ifndef IP6_FRAG_STATS +#define IP6_FRAG_STATS (LWIP_IPV6 && (LWIP_IPV6_FRAG || LWIP_IPV6_REASS)) +#endif + +/** + * MLD6_STATS==1: Enable MLD for IPv6 stats. + */ +#ifndef MLD6_STATS +#define MLD6_STATS (LWIP_IPV6 && LWIP_IPV6_MLD) +#endif + +/** + * ND6_STATS==1: Enable Neighbor discovery for IPv6 stats. + */ +#ifndef ND6_STATS +#define ND6_STATS (LWIP_IPV6) +#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 + +#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_GEN_ICMP==1: Generate checksums in software for outgoing ICMP packets. + */ +#ifndef CHECKSUM_GEN_ICMP +#define CHECKSUM_GEN_ICMP 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 + +/* + --------------------------------------- + ---------- IPv6 options --------------- + --------------------------------------- +*/ +/** + * LWIP_IPV6==1: Enable IPv6 + */ +#ifndef LWIP_IPV6 +#define LWIP_IPV6 0 +#endif + +/** + * LWIP_IPV6_NUM_ADDRESSES: Number of IPv6 addresses per netif. + */ +#ifndef LWIP_IPV6_NUM_ADDRESSES +#define LWIP_IPV6_NUM_ADDRESSES 3 +#endif + +/** + * LWIP_IPV6_FORWARD==1: Forward IPv6 packets across netifs + */ +#ifndef LWIP_IPV6_FORWARD +#define LWIP_IPV6_FORWARD 0 +#endif + +/** + * LWIP_ICMP6==1: Enable ICMPv6 (mandatory per RFC) + */ +#ifndef LWIP_ICMP6 +#define LWIP_ICMP6 (LWIP_IPV6) +#endif + +/** + * LWIP_ICMP6_DATASIZE: bytes from original packet to send back in + * ICMPv6 error messages. + */ +#ifndef LWIP_ICMP6_DATASIZE +#define LWIP_ICMP6_DATASIZE 8 +#endif + +/** + * LWIP_ICMP6_HL: default hop limit for ICMPv6 messages + */ +#ifndef LWIP_ICMP6_HL +#define LWIP_ICMP6_HL 255 +#endif + +/** + * LWIP_ICMP6_CHECKSUM_CHECK==1: verify checksum on ICMPv6 packets + */ +#ifndef LWIP_ICMP6_CHECKSUM_CHECK +#define LWIP_ICMP6_CHECKSUM_CHECK 1 +#endif + +/** + * LWIP_IPV6_MLD==1: Enable multicast listener discovery protocol. + */ +#ifndef LWIP_IPV6_MLD +#define LWIP_IPV6_MLD (LWIP_IPV6) +#endif + +/** + * MEMP_NUM_MLD6_GROUP: Max number of IPv6 multicast that can be joined. + */ +#ifndef MEMP_NUM_MLD6_GROUP +#define MEMP_NUM_MLD6_GROUP 4 +#endif + +/** + * LWIP_IPV6_FRAG==1: Fragment outgoing IPv6 packets that are too big. + */ +#ifndef LWIP_IPV6_FRAG +#define LWIP_IPV6_FRAG 0 +#endif + +/** + * LWIP_IPV6_REASS==1: reassemble incoming IPv6 packets that fragmented + */ +#ifndef LWIP_IPV6_REASS +#define LWIP_IPV6_REASS (LWIP_IPV6) +#endif + +/** + * LWIP_ND6_QUEUEING==1: queue outgoing IPv6 packets while MAC address + * is being resolved. + */ +#ifndef LWIP_ND6_QUEUEING +#define LWIP_ND6_QUEUEING (LWIP_IPV6) +#endif + +/** + * MEMP_NUM_ND6_QUEUE: Max number of IPv6 packets to queue during MAC resolution. + */ +#ifndef MEMP_NUM_ND6_QUEUE +#define MEMP_NUM_ND6_QUEUE 20 +#endif + +/** + * LWIP_ND6_NUM_NEIGHBORS: Number of entries in IPv6 neighbor cache + */ +#ifndef LWIP_ND6_NUM_NEIGHBORS +#define LWIP_ND6_NUM_NEIGHBORS 10 +#endif + +/** + * LWIP_ND6_NUM_DESTINATIONS: number of entries in IPv6 destination cache + */ +#ifndef LWIP_ND6_NUM_DESTINATIONS +#define LWIP_ND6_NUM_DESTINATIONS 10 +#endif + +/** + * LWIP_ND6_NUM_PREFIXES: number of entries in IPv6 on-link prefixes cache + */ +#ifndef LWIP_ND6_NUM_PREFIXES +#define LWIP_ND6_NUM_PREFIXES 5 +#endif + +/** + * LWIP_ND6_NUM_ROUTERS: number of entries in IPv6 default router cache + */ +#ifndef LWIP_ND6_NUM_ROUTERS +#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) + */ +#ifndef LWIP_ND6_MAX_MULTICAST_SOLICIT +#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. + */ +#ifndef LWIP_ND6_MAX_UNICAST_SOLICIT +#define LWIP_ND6_MAX_UNICAST_SOLICIT 3 +#endif + +/** + * Unused: See ND RFC (time in milliseconds). + */ +#ifndef LWIP_ND6_MAX_ANYCAST_DELAY_TIME +#define LWIP_ND6_MAX_ANYCAST_DELAY_TIME 1000 +#endif + +/** + * Unused: See ND RFC + */ +#ifndef LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT +#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. + */ +#ifndef LWIP_ND6_REACHABLE_TIME +#define LWIP_ND6_REACHABLE_TIME 30000 +#endif + +/** + * LWIP_ND6_RETRANS_TIMER: default retransmission timer for solicitation messages + */ +#ifndef LWIP_ND6_RETRANS_TIMER +#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. + */ +#ifndef LWIP_ND6_DELAY_FIRST_PROBE_TIME +#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. + */ +#ifndef LWIP_ND6_ALLOW_RA_UPDATES +#define LWIP_ND6_ALLOW_RA_UPDATES 1 +#endif + +/** + * LWIP_IPV6_SEND_ROUTER_SOLICIT==1: Send router solicitation messages during + * network startup. + */ +#ifndef LWIP_IPV6_SEND_ROUTER_SOLICIT +#define LWIP_IPV6_SEND_ROUTER_SOLICIT 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. + */ +#ifndef LWIP_ND6_TCP_REACHABILITY_HINTS +#define LWIP_ND6_TCP_REACHABILITY_HINTS 1 +#endif + +/** + * LWIP_IPV6_AUTOCONFIG==1: Enable stateless address autoconfiguration as per RFC 4862. + */ +#ifndef LWIP_IPV6_AUTOCONFIG +#define LWIP_IPV6_AUTOCONFIG (LWIP_IPV6) +#endif + +/** + * LWIP_IPV6_DUP_DETECT_ATTEMPTS: Number of duplicate address detection attempts. + */ +#ifndef LWIP_IPV6_DUP_DETECT_ATTEMPTS +#define LWIP_IPV6_DUP_DETECT_ATTEMPTS 1 +#endif + +/** + * LWIP_IPV6_DHCP6==1: enable DHCPv6 stateful address autoconfiguration. + */ +#ifndef LWIP_IPV6_DHCP6 +#define LWIP_IPV6_DHCP6 0 +#endif + +/* + --------------------------------------- + ---------- Hook options --------------- + --------------------------------------- +*/ + +/* Hooks are undefined by default, define them to a function if you need them. */ + +/** + * LWIP_HOOK_IP4_INPUT(pbuf, input_netif): + * - called from ip_input() (IPv4) + * - pbuf: received struct pbuf passed to ip_input() + * - input_netif: struct netif on which the packet has been received + * Return values: + * - 0: Hook has not consumed the packet, packet is processed as normal + * - != 0: Hook has consumed the packet. + * If the hook consumed the packet, 'pbuf' is in the responsibility of the hook + * (i.e. free it when done). + */ + +/** + * 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. + */ + +/* + --------------------------------------- + ---------- 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 + +/** + * IP6_DEBUG: Enable debugging for IPv6. + */ +#ifndef IP6_DEBUG +#define IP6_DEBUG LWIP_DBG_OFF +#endif + +#endif /* __LWIP_OPT_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/pbuf.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/pbuf.h new file mode 100644 index 0000000..1865f5c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/pbuf.h @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS 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) + +/* @todo: We need a mechanism to prevent wasting memory in every pbuf + (TCP vs. UDP, IPv4 vs. IPv6: UDP/IPv4 packets may waste up to 28 bytes) */ + +#define PBUF_TRANSPORT_HLEN 20 +#if LWIP_IPV6 +#define PBUF_IP_HLEN 40 +#else +#define PBUF_IP_HLEN 20 +#endif + +typedef enum { + PBUF_TRANSPORT, + PBUF_IP, + PBUF_LINK, + PBUF_RAW, + PBUF_MAC +} 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 +/** 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 + +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 */ + +#if LWIP_TCP && TCP_QUEUE_OOSEQ +/** 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 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) +#endif /* NO_SYS && PBUF_POOL_FREE_OOSEQ*/ +#endif /* LWIP_TCP && TCP_QUEUE_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); +void pbuf_ref(struct pbuf *p); +u8_t pbuf_free(struct pbuf *p); +u8_t pbuf_clen(struct pbuf *p); +void pbuf_cat(struct pbuf *head, struct pbuf *tail); +void pbuf_chain(struct pbuf *head, struct pbuf *tail); +struct pbuf *pbuf_dechain(struct pbuf *p); +err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from); +u16_t pbuf_copy_partial(struct pbuf *p, void *dataptr, u16_t len, u16_t offset); +err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len); +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 */ + +u8_t pbuf_get_at(struct pbuf* p, u16_t offset); +u16_t pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n); +u16_t pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset); +u16_t pbuf_strstr(struct pbuf* p, const char* substr); + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_PBUF_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/raw.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/raw.h new file mode 100644 index 0000000..ba4edd9 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/raw.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS 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" +#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, + ip_addr_t *addr); + +#if LWIP_IPV6 +/** Function prototype for raw pcb IPv6 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 IPv6 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_ip6_fn)(void *arg, struct raw_pcb *pcb, struct pbuf *p, + ip6_addr_t *addr); +#endif /* LWIP_IPV6 */ + +#if LWIP_IPV6 +#define RAW_PCB_RECV_IP6 raw_recv_ip6_fn ip6; +#else +#define RAW_PCB_RECV_IP6 +#endif /* LWIP_IPV6 */ + +struct raw_pcb { + /* Common members of all PCB types */ + IP_PCB; + + struct raw_pcb *next; + + u8_t protocol; + + /** receive callback function */ + union { + raw_recv_fn ip4; + RAW_PCB_RECV_IP6 + } 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); +void raw_remove (struct raw_pcb *pcb); +err_t raw_bind (struct raw_pcb *pcb, ip_addr_t *ipaddr); +err_t raw_connect (struct raw_pcb *pcb, ip_addr_t *ipaddr); + +void raw_recv (struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg); +err_t raw_sendto (struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr); +err_t raw_send (struct raw_pcb *pcb, struct pbuf *p); + +#if LWIP_IPV6 +struct raw_pcb * raw_new_ip6 (u8_t proto); +#define raw_bind_ip6(pcb, ip6addr) raw_bind(pcb, ip6_2_ip(ip6addr)) +#define raw_connect_ip6(pcb, ip6addr) raw_connect(pcb, ip6_2_ip(ip6addr)) +#define raw_recv_ip6(pcb, recv_ip6_fn, recv_arg) raw_recv(pcb, (raw_recv_fn)recv_ip6_fn, recv_arg) +#define raw_sendto_ip6(pcb, pbuf, ip6addr) raw_sendto(pcb, pbuf, ip6_2_ip(ip6addr)) +#endif /* LWIP_IPV6 */ + +/* 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, not init needed. */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_RAW */ + +#endif /* __LWIP_RAW_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/sio.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/sio.h new file mode 100644 index 0000000..39d778b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/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); +#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/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/snmp.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/snmp.h new file mode 100644 index 0000000..3548ba2 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/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/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/snmp_asn1.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/snmp_asn1.h new file mode 100644 index 0000000..fbfb68b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/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/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/snmp_msg.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/snmp_msg.h new file mode 100644 index 0000000..656924e --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/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/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/snmp_structs.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/snmp_structs.h new file mode 100644 index 0000000..f7193b9 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/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/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/sockets.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/sockets.h new file mode 100644 index 0000000..50c576c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/sockets.h @@ -0,0 +1,463 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS 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" +#include "lwip/inet6.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 + +/* 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]; +}; + +#if LWIP_IPV6 + +#define INET6_ADDRSTRLEN 46 + +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 */ +}; +#endif /* LWIP_IPV6 */ + +struct sockaddr { + u8_t sa_len; + sa_family_t sa_family; +#if LWIP_IPV6 + char sa_data[22]; +#else /* LWIP_IPV6 */ + char sa_data[14]; +#endif /* LWIP_IPV6 */ +}; + +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[2]; +#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 + +/* 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 +#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_TCP 6 +#define IPPROTO_UDP 17 +#if LWIP_IPV6 +#define IPPROTO_IPV6 41 +#endif /* LWIP_IPV6 */ +#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_IPV6 +/* + * Options for level IPPROTO_IPV6 + */ +#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_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); + + +/** + * set if lwip_close will use 4-handshake to close a tcp connection, + * + * @param req 1 , send rst pkt directly, when call lwip_close(),rather than 4-handshake. + * then all buffed PCB memory resource will be freed immediately + * 0, send Fin flag pkt other than rst pkt when call lwip_close(s) + * @return + */ +void lwip_force_close_set(char req); + +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 && !defined(SOCKETS_MT) +#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) +#define fcntl(a,b,c) lwip_fcntl(a,b,c) +#endif /* LWIP_POSIX_SOCKETS_IO_NAMES */ + +#if LWIP_IPV6 +#define inet_ntop(af,src,dst,size) \ + (((af) == AF_INET6) ? ip6addr_ntoa_r((const ip6_addr_t *)(src),(dst),(size)) \ + : (((af) == AF_INET) ? ipaddr_ntoa_r((const ip_addr_t *)(src),(dst),(size)) : NULL)) +#define inet_pton(af,src,dst) \ + (((af) == AF_INET6) ? inet6_aton((src),(const ip6_addr_t *)(dst)) \ + : (((af) == AF_INET) ? inet_aton((src),(const ip_addr_t *)(dst)) : 0)) +#else /* LWIP_IPV6 */ +#define inet_ntop(af,src,dst,size) \ + (((af) == AF_INET) ? ipaddr_ntoa_r((src),(dst),(size)) : NULL) +#define inet_pton(af,src,dst) \ + (((af) == AF_INET) ? inet_aton((src),(dst)) : 0) +#endif /* LWIP_IPV6 */ + +#endif /* LWIP_COMPAT_SOCKETS */ + +#ifdef __cplusplus +} +#endif + +#include "multi-threads/sockets_mt.h" + +#endif /* LWIP_SOCKET */ + +#endif /* __LWIP_SOCKETS_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/stats.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/stats.h new file mode 100644 index 0000000..07df9f6 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/stats.h @@ -0,0 +1,347 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS 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 +#if IP6_STATS + struct stats_proto ip6; +#endif +#if ICMP6_STATS + struct stats_proto icmp6; +#endif +#if IP6_FRAG_STATS + struct stats_proto ip6_frag; +#endif +#if MLD6_STATS + struct stats_igmp mld6; +#endif +#if ND6_STATS + struct stats_proto nd6; +#endif +}; + +extern struct stats_ lwip_stats; + +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) +#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_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 + +#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 + +/* 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_STATS_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/sys.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/sys.h new file mode 100644 index 0000000..d831f4c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/sys.h @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS 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" + +#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_set_invalid(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_set_invalid(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 (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 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 + * @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); + +#ifndef sys_jiffies +/** Ticks/jiffies since power up. */ +u32_t sys_jiffies(void); +#endif + +/** 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 + +/** 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); +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_SYS_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/tcp.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/tcp.h new file mode 100644 index 0000000..e6d3240 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/tcp.h @@ -0,0 +1,397 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS 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/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); + +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 */ \ + void *callback_arg; \ + /* the accept callback for listen- and normal pcbs, if LWIP_CALLBACK_API */ \ + DEF_ACCEPT_CALLBACK \ + enum tcp_state state; /* TCP state */ \ + u8_t prio; \ + /* 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 */ + + /* Timers */ + u8_t polltmr, pollinterval; + u8_t last_timer; + u32_t tmr; + + /* 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 */ + + /* 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 */ + u16_t cwnd; + u16_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. */ + u16_t snd_wnd; /* sender window */ + u16_t snd_wnd_max; /* the maximum sender window announced by the remote host */ + + u16_t acked; + + u16_t snd_buf; /* Available buffer space for sending (in bytes). */ +#define TCP_SNDQUEUELEN_OVERFLOW (0xffffU-3) + u16_t snd_queuelen; /* Available buffer space for sending (in pbufs). */ + +#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 */ + u8_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_IPV6 + u8_t accept_any_ip_version; +#endif /* LWIP_IPV6 */ +}; + +#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); + +void tcp_arg (struct tcp_pcb *pcb, void *arg); +void tcp_accept (struct tcp_pcb *pcb, tcp_accept_fn accept); +void tcp_recv (struct tcp_pcb *pcb, tcp_recv_fn recv); +void tcp_sent (struct tcp_pcb *pcb, tcp_sent_fn sent); +void tcp_poll (struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval); +void tcp_err (struct tcp_pcb *pcb, tcp_err_fn err); + +#define tcp_mss(pcb) (((pcb)->flags & TF_TIMESTAMP) ? ((pcb)->mss - 12) : (pcb)->mss) +#define tcp_sndbuf(pcb) ((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); +err_t tcp_bind (struct tcp_pcb *pcb, ip_addr_t *ipaddr, + u16_t port); +err_t tcp_connect (struct tcp_pcb *pcb, ip_addr_t *ipaddr, + u16_t port, tcp_connected_fn connected); + +struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog); +#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); + +#if LWIP_IPV6 +struct tcp_pcb * tcp_new_ip6 (void); +#define tcp_bind_ip6(pcb, ip6addr, port) \ + tcp_bind(pcb, ip6_2_ip(ip6addr), port) +#define tcp_connect_ip6(pcb, ip6addr, port, connected) \ + tcp_connect(pcb, ip6_2_ip(ip6addr), port, connected) +struct tcp_pcb * tcp_listen_dual_with_backlog(struct tcp_pcb *pcb, u8_t backlog); +#define tcp_listen_dual(pcb) tcp_listen_dual_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG) +#else /* LWIP_IPV6 */ +#define tcp_listen_dual_with_backlog(pcb, backlog) tcp_listen_with_backlog(pcb, backlog) +#define tcp_listen_dual(pcb) tcp_listen(pcb) +#endif /* LWIP_IPV6 */ + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_TCP */ + +#endif /* __LWIP_TCP_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/tcp_impl.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/tcp_impl.h new file mode 100644 index 0000000..eb14efc --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/tcp_impl.h @@ -0,0 +1,508 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS 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/mem.h" +#include "lwip/pbuf.h" +#include "lwip/ip.h" +#include "lwip/icmp.h" +#include "lwip/err.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Functions for interfacing with TCP: */ + +/* Lower layer interface to TCP: */ +void tcp_init (void); /* Initialize this module. */ +void tcp_tmr (void); /* Must be called every + TCP_TMR_INTERVAL + ms. (Typically 250 ms). */ +/* It is also possible to call these two functions at the right + intervals (instead of calling tcp_tmr()). */ +void tcp_slowtmr (void); +void tcp_fasttmr (void); + + +/* Only used by IP to pass a TCP segment to TCP: */ +void tcp_input (struct pbuf *p, struct netif *inp); +/* Used within the TCP code only: */ +struct tcp_pcb * tcp_alloc (u8_t prio); +void tcp_abandon (struct tcp_pcb *pcb, int reset); +err_t tcp_send_empty_ack(struct tcp_pcb *pcb); +void tcp_rexmit (struct tcp_pcb *pcb); +void tcp_rexmit_rto (struct tcp_pcb *pcb); +void tcp_rexmit_fast (struct tcp_pcb *pcb); +u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb); +err_t tcp_process_refused_data(struct tcp_pcb *pcb); + +/** + * This is the Nagle algorithm: try to combine user data to send as few TCP + * segments as possible. Only send if + * - no previously transmitted data on the connection remains unacknowledged or + * - the TF_NODELAY flag is set (nagle algorithm turned off for this pcb) or + * - the only unsent segment is at least pcb->mss bytes long (or there is more + * than one unsent segment - with lwIP, this can happen although unsent->len < mss) + * - or if we are in fast-retransmit (TF_INFR) + */ +#define tcp_do_output_nagle(tpcb) ((((tpcb)->unacked == NULL) || \ + ((tpcb)->flags & (TF_NODELAY | TF_INFR)) || \ + (((tpcb)->unsent != NULL) && (((tpcb)->unsent->next != NULL) || \ + ((tpcb)->unsent->len >= (tpcb)->mss))) || \ + ((tcp_sndbuf(tpcb) == 0) || (tcp_sndqueuelen(tpcb) >= TCP_SND_QUEUELEN)) \ + ) ? 1 : 0) +#define tcp_output_nagle(tpcb) (tcp_do_output_nagle(tpcb) ? tcp_output(tpcb) : ERR_OK) + + +#define TCP_SEQ_LT(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) < 0) +#define TCP_SEQ_LEQ(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) <= 0) +#define TCP_SEQ_GT(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) > 0) +#define TCP_SEQ_GEQ(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) >= 0) +/* is b<=a<=c? */ +#if 0 /* see bug #10548 */ +#define TCP_SEQ_BETWEEN(a,b,c) ((c)-(b) >= (a)-(b)) +#endif +#define TCP_SEQ_BETWEEN(a,b,c) (TCP_SEQ_GEQ(a,b) && TCP_SEQ_LEQ(a,c)) +#define TCP_FIN 0x01U +#define TCP_SYN 0x02U +#define TCP_RST 0x04U +#define TCP_PSH 0x08U +#define TCP_ACK 0x10U +#define TCP_URG 0x20U +#define TCP_ECE 0x40U +#define TCP_CWR 0x80U + +#define TCP_FLAGS 0x3fU + +/* Length of the TCP header, excluding options. */ +#define TCP_HLEN 20 + +#ifndef TCP_TMR_INTERVAL +#define TCP_TMR_INTERVAL 250 /* The TCP timer interval in milliseconds. */ +#endif /* TCP_TMR_INTERVAL */ + +#ifndef TCP_FAST_INTERVAL +#define TCP_FAST_INTERVAL TCP_TMR_INTERVAL /* the fine grained timeout in milliseconds */ +#endif /* TCP_FAST_INTERVAL */ + +#ifndef TCP_SLOW_INTERVAL +#define TCP_SLOW_INTERVAL (2*TCP_TMR_INTERVAL) /* the coarse grained timeout in milliseconds */ +#endif /* TCP_SLOW_INTERVAL */ + +#define TCP_FIN_WAIT_TIMEOUT 20000 /* milliseconds */ +#define TCP_SYN_RCVD_TIMEOUT 20000 /* milliseconds */ + +#define TCP_OOSEQ_TIMEOUT 6U /* x RTO */ + +#ifndef TCP_MSL +#define TCP_MSL 60000UL /* The maximum segment lifetime in milliseconds */ +#endif + +/* Keepalive values, compliant with RFC 1122. Don't change this unless you know what you're doing */ +#ifndef TCP_KEEPIDLE_DEFAULT +#define TCP_KEEPIDLE_DEFAULT 7200000UL /* Default KEEPALIVE timer in milliseconds */ +#endif + +#ifndef TCP_KEEPINTVL_DEFAULT +#define TCP_KEEPINTVL_DEFAULT 75000UL /* Default Time between KEEPALIVE probes in milliseconds */ +#endif + +#ifndef TCP_KEEPCNT_DEFAULT +#define TCP_KEEPCNT_DEFAULT 9U /* Default Counter for KEEPALIVE probes */ +#endif + +#define TCP_MAXIDLE TCP_KEEPCNT_DEFAULT * TCP_KEEPINTVL_DEFAULT /* Maximum KEEPALIVE probe time */ + +/* Fields are (of course) in network byte order. + * Some fields are converted to host byte order in tcp_input(). + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct tcp_hdr { + PACK_STRUCT_FIELD(u16_t src); + PACK_STRUCT_FIELD(u16_t dest); + PACK_STRUCT_FIELD(u32_t seqno); + PACK_STRUCT_FIELD(u32_t ackno); + PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags); + PACK_STRUCT_FIELD(u16_t wnd); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u16_t urgp); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define TCPH_HDRLEN(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 12) +#define TCPH_FLAGS(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) & TCP_FLAGS) + +#define TCPH_HDRLEN_SET(phdr, len) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | TCPH_FLAGS(phdr)) +#define TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = (((phdr)->_hdrlen_rsvd_flags & PP_HTONS((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 */ + 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(mss) htonl(0x02040000 | ((mss) & 0xFFFF)) + +/* 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. */ + +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_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_impl(u32_t seqno, u32_t ackno, + ipX_addr_t *local_ip, ipX_addr_t *remote_ip, + u16_t local_port, u16_t remote_port +#if LWIP_IPV6 + , u8_t isipv6 +#endif /* LWIP_IPV6 */ + ); +#if LWIP_IPV6 +#define tcp_rst(seqno, ackno, local_ip, remote_ip, local_port, remote_port, isipv6) \ + tcp_rst_impl(seqno, ackno, local_ip, remote_ip, local_port, remote_port, isipv6) +#else /* LWIP_IPV6 */ +#define tcp_rst(seqno, ackno, local_ip, remote_ip, local_port, remote_port, isipv6) \ + tcp_rst_impl(seqno, ackno, local_ip, remote_ip, local_port, remote_port) +#endif /* LWIP_IPV6 */ + +u32_t tcp_next_iss(void); + +void tcp_keepalive(struct tcp_pcb *pcb); +void tcp_zero_window_probe(struct tcp_pcb *pcb); + +#if TCP_CALCULATE_EFF_SEND_MSS +u16_t tcp_eff_send_mss_impl(u16_t sendmss, ipX_addr_t *dest +#if LWIP_IPV6 + , ipX_addr_t *src, u8_t isipv6 +#endif /* LWIP_IPV6 */ + ); +#if LWIP_IPV6 +#define tcp_eff_send_mss(sendmss, src, dest, isipv6) tcp_eff_send_mss_impl(sendmss, dest, src, isipv6) +#else /* LWIP_IPV6 */ +#define tcp_eff_send_mss(sendmss, src, dest, isipv6) tcp_eff_send_mss_impl(sendmss, dest) +#endif /* LWIP_IPV6 */ +#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); + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_TCP */ + +#endif /* __LWIP_TCP_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/tcpip.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/tcpip.h new file mode 100644 index 0000000..55632c6 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/tcpip.h @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS 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) +#ifdef LWIP_DEBUG +#define TCIP_APIMSG_SET_ERR(m, e) (m)->msg.err = e /* catch functions that don't set err */ +#else +#define TCIP_APIMSG_SET_ERR(m, e) +#endif +#define TCPIP_APIMSG_NOERR(m,f) do { \ + TCIP_APIMSG_SET_ERR(m, ERR_VAL); \ + LOCK_TCPIP_CORE(); \ + f(&((m)->msg)); \ + UNLOCK_TCPIP_CORE(); \ +} while(0) +#define TCPIP_APIMSG(m,f,e) do { \ + TCPIP_APIMSG_NOERR(m,f); \ + (e) = (m)->msg.err; \ +} while(0) +#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_NOERR(m,f) do { (m)->function = f; tcpip_apimsg(m); } while(0) +#define TCPIP_APIMSG(m,f,e) do { (m)->function = f; (e) = tcpip_apimsg(m); } while(0) +#define TCPIP_APIMSG_ACK(m) sys_sem_signal(&m->conn->op_completed) +#define TCPIP_APIMSG_ACK_SND(m) sys_sem_signal(&m->conn->snd_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); + +/* Forward declarations */ +struct tcpip_callback_msg; + +void tcpip_init(tcpip_init_done_fn tcpip_init_done, void *arg); + +#if LWIP_NETCONN +err_t tcpip_apimsg(struct api_msg *apimsg); +#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) + +struct tcpip_callback_msg* tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx); +void tcpip_callbackmsg_delete(struct tcpip_callback_msg* msg); +err_t tcpip_trycallback(struct tcpip_callback_msg* msg); + +/* free pbufs or heap memory from another context without blocking */ +err_t pbuf_free_callback(struct pbuf *p); +err_t mem_free_callback(void *m); + +#if LWIP_TCPIP_TIMEOUT +err_t tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg); +err_t tcpip_untimeout(sys_timeout_handler h, void *arg); +#endif /* LWIP_TCPIP_TIMEOUT */ + +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, + TCPIP_MSG_CALLBACK_STATIC +}; + +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/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/timers.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/timers.h new file mode 100644 index 0000000..03612f9 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/timers.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF 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" +#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 timeout callback function. Register such a function + * using sys_timeout(). + * + * @param arg Additional argument to pass to the function - set up by sys_timeout() + */ +typedef void (* sys_timeout_handler)(void *arg); + +struct sys_timeo { + struct sys_timeo *next; + u32_t time; + sys_timeout_handler h; + void *arg; +#if LWIP_DEBUG_TIMERNAMES + const char* handler_name; +#endif /* LWIP_DEBUG_TIMERNAMES */ +}; + +void sys_timeouts_init(void); + +#if LWIP_DEBUG_TIMERNAMES +void sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name); +#define sys_timeout(msecs, handler, arg) sys_timeout_debug(msecs, handler, arg, #handler) +#else /* LWIP_DEBUG_TIMERNAMES */ +void sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg); +#endif /* LWIP_DEBUG_TIMERNAMES */ + +void sys_untimeout(sys_timeout_handler handler, void *arg); +#if NO_SYS +void sys_check_timeouts(void); +void sys_restart_timeouts(void); +#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/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/udp.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/udp.h new file mode 100644 index 0000000..85e0fef --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwip/udp.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_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" +#include "lwip/ip6_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UDP_HLEN 8 + +/* Fields are (of course) in network byte order. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct udp_hdr { + PACK_STRUCT_FIELD(u16_t src); + PACK_STRUCT_FIELD(u16_t dest); /* src/dest UDP ports */ + PACK_STRUCT_FIELD(u16_t len); + PACK_STRUCT_FIELD(u16_t chksum); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define UDP_FLAGS_NOCHKSUM 0x01U +#define UDP_FLAGS_UDPLITE 0x02U +#define UDP_FLAGS_CONNECTED 0x04U +#define UDP_FLAGS_MULTICAST_LOOP 0x08U + +struct udp_pcb; + +/** Function prototype for udp pcb receive callback functions + * addr and port are in same byte order as in the pcb + * The callback is responsible for freeing the pbuf + * if it's not used any more. + * + * ATTENTION: Be aware that 'addr' 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); + +#if LWIP_IPV6 +/** Function prototype for udp pcb IPv6 receive callback functions + * The callback is responsible for freeing the pbuf + * if it's not used any more. + * + * @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 IPv6 address from which the packet was received + * @param port the remote port from which the packet was received + */ +typedef void (*udp_recv_ip6_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p, + ip6_addr_t *addr, u16_t port); +#endif /* LWIP_IPV6 */ + +#if LWIP_IPV6 +#define UDP_PCB_RECV_IP6 udp_recv_ip6_fn ip6; +#else +#define UDP_PCB_RECV_IP6 +#endif /* LWIP_IPV6 */ + +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 */ + union { + udp_recv_fn ip4; + UDP_PCB_RECV_IP6 + }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); +void udp_remove (struct udp_pcb *pcb); +err_t udp_bind (struct udp_pcb *pcb, ip_addr_t *ipaddr, + u16_t port); +err_t udp_connect (struct udp_pcb *pcb, 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, + ip_addr_t *dst_ip, u16_t dst_port, + struct netif *netif); +err_t udp_sendto (struct udp_pcb *pcb, struct pbuf *p, + 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, + 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, + 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); +#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); + +#if LWIP_IPV6 +struct udp_pcb * udp_new_ip6(void); +#define udp_bind_ip6(pcb, ip6addr, port) \ + udp_bind(pcb, ip6_2_ip(ip6addr), port) +#define udp_connect_ip6(pcb, ip6addr, port) \ + udp_connect(pcb, ip6_2_ip(ip6addr), port) +#define udp_recv_ip6(pcb, recv_ip6_fn, recv_arg) \ + udp_recv(pcb, (udp_recv_fn)recv_ip6_fn, recv_arg) +#define udp_sendto_ip6(pcb, pbuf, ip6addr, port) \ + udp_sendto(pcb, pbuf, ip6_2_ip(ip6addr), port) +#define udp_sendto_if_ip6(pcb, pbuf, ip6addr, port, netif) \ + udp_sendto_if(pcb, pbuf, ip6_2_ip(ip6addr), port, netif) +#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP +#define udp_sendto_chksum_ip6(pcb, pbuf, ip6addr, port, have_chk, chksum) \ + udp_sendto_chksum(pcb, pbuf, ip6_2_ip(ip6addr), port, have_chk, chksum) +#define udp_sendto_if_chksum_ip6(pcb, pbuf, ip6addr, port, netif, have_chk, chksum) \ + udp_sendto_if_chksum(pcb, pbuf, ip6_2_ip(ip6addr), port, netif, have_chk, chksum) +#endif /*LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ +#endif /* LWIP_IPV6 */ + +#if UDP_DEBUG +void udp_debug_print(struct udp_hdr *udphdr); +#else +#define udp_debug_print(udphdr) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_UDP */ + +#endif /* __LWIP_UDP_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwipopts.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwipopts.h new file mode 100644 index 0000000..cdea31f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/lwipopts.h @@ -0,0 +1,502 @@ +/* + * 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 __LWIPOPTS_H__ +#define __LWIPOPTS_H__ + +#define LWIP_ESP8266 + +#define SOCKETS_MT + +//#define SOCKETS_TCP_TRACE +/* + ----------------------------------------------- + ---------- Platform specific locking ---------- + ----------------------------------------------- +*/ +/** + * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain + * critical regions during buffer allocation, deallocation and memory + * allocation and deallocation. + */ +#define SYS_LIGHTWEIGHT_PROT 1 + +/** + * MEMCPY: override this if you have a faster implementation at hand than the + * one included in your C library + */ +#define MEMCPY(dst,src,len) memcpy(dst,src,len) + +/** + * 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. + */ +#define SMEMCPY(dst,src,len) memcpy(dst,src,len) + +#define LWIP_RAND os_random +/* + ------------------------------------ + ---------- 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. + */ +#define MEM_LIBC_MALLOC 1 + +/** +* 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! +*/ +#define MEMP_MEM_MALLOC 1 + +/** + * MEM_ALIGNMENT: should be set to the alignment of the CPU + * 4 byte alignment -> #define MEM_ALIGNMENT 4 + * 2 byte alignment -> #define MEM_ALIGNMENT 2 + */ +#define MEM_ALIGNMENT 4 + +/* + ------------------------------------------------ + ---------- Internal Memory Pool Sizes ---------- + ------------------------------------------------ +*/ +/** + * MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. + * (requires the LWIP_TCP option) + */ +#define MEMP_NUM_TCP_PCB 5 //(*(volatile uint32*)0x600011FC) + +/** + * MEMP_NUM_NETCONN: the number of struct netconns. + * (only needed if you use the sequential API, like api_lib.c) + */ +#define MEMP_NUM_NETCONN 10 + +/* + -------------------------------- + ---------- ARP options ------- + -------------------------------- +*/ +/** + * 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. + */ +#define ARP_QUEUEING 1 + +#if ARP_QUEUEING +#ifdef LWIP_ESP8266 +/** + * Only queue ARP_ENTRY_QUEUE_SIZE pending outgoing packets for ARP entry. + * This limit will be helpful to avoid system running out of memory instantly. + * (eg. within 350ms) + */ +#define ARP_ENTRY_QUEUE_SIZE 3 +#endif /* LWIP_ESP8266 */ +#endif /* ARP_QUEUEING */ +/* + -------------------------------- + ---------- IP options ---------- + -------------------------------- +*/ +/** + * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that + * this option does not affect outgoing packet sizes, which can be controlled + * via IP_FRAG. + */ +#define IP_REASSEMBLY 0 + +/** + * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note + * that this option does not affect incoming packet sizes, which can be + * controlled via IP_REASSEMBLY. + */ +#define IP_FRAG 0 + +/** + * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally) + * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived + * in this time, the whole packet is discarded. + */ +#define IP_REASS_MAXAGE 3 + +/** + * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled. + * Since the received pbufs are enqueued, be sure to configure + * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive + * packets even if the maximum amount of fragments is enqueued for reassembly! + */ +#define IP_REASS_MAX_PBUFS 10 + +/* + ---------------------------------- + ---------- ICMP options ---------- + ---------------------------------- +*/ + +/* + --------------------------------- + ---------- RAW options ---------- + --------------------------------- +*/ + +/* + ---------------------------------- + ---------- DHCP options ---------- + ---------------------------------- +*/ +/** + * LWIP_DHCP==1: Enable DHCP module. + */ +#define LWIP_DHCP 1 + +#define LWIP_DHCP_BOOTP_FILE 0 + +/** + * DHCP_MAXRTX: Maximum number of retries of current request. + */ +#define DHCP_MAXRTX (*(volatile uint32*)0x600011E0) + +/* + ------------------------------------ + ---------- AUTOIP options ---------- + ------------------------------------ +*/ +/* + ---------------------------------- + ---------- SNMP options ---------- + ---------------------------------- +*/ +/* + ---------------------------------- + ---------- IGMP options ---------- + ---------------------------------- +*/ +/** + * LWIP_IGMP==1: Turn on IGMP module. + */ +#define LWIP_IGMP 1 + +/* + ---------------------------------- + ---------- DNS options ----------- + ---------------------------------- +*/ +/** + * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS + * transport. + */ +#define LWIP_DNS 1 + +/* + --------------------------------- + ---------- UDP options ---------- + --------------------------------- +*/ +/* + --------------------------------- + ---------- TCP options ---------- + --------------------------------- +*/ +/** + * TCP_WND: The size of a TCP window. This must be at least + * (2 * TCP_MSS) for things to work well + */ +//#define TCP_WND (*(volatile uint32*)0x600011F0) + +/** + * TCP_QUEUE_OOSEQ==1: TCP will queue segments that arrive out of order. + * Define to 0 if your device is low on memory. + */ +#define TCP_QUEUE_OOSEQ 0 + +/* + * 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. +*/ +#define TCP_MSS 1460 + +/** + * TCP_MAXRTX: Maximum number of retransmissions of data segments. + */ +#define TCP_MAXRTX 12 //(*(volatile uint32*)0x600011E8) + +/** + * TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments. + */ +#define TCP_SYNMAXRTX 6 //(*(volatile uint32*)0x600011E4) + +/** + * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb. + */ +#define TCP_LISTEN_BACKLOG 1 + +/* + ---------------------------------- + ---------- Pbuf options ---------- + ---------------------------------- +*/ + +/* + ------------------------------------------------ + ---------- Network Interfaces options ---------- + ------------------------------------------------ +*/ + +/** + * LWIP_NETIF_HOSTNAME==1: use DHCP_OPTION_HOSTNAME with netif's hostname + * field. + */ +#define LWIP_NETIF_HOSTNAME 1 + +/** + * 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: + */ +#define LWIP_NETIF_TX_SINGLE_PBUF 1 + +/* + ------------------------------------ + ---------- LOOPIF options ---------- + ------------------------------------ +*/ + +/* + ------------------------------------ + ---------- SLIPIF options ---------- + ------------------------------------ +*/ + +/* + ------------------------------------ + ---------- Thread options ---------- + ------------------------------------ +*/ +/** + * TCPIP_THREAD_NAME: The name assigned to the main tcpip thread. + */ +#define TCPIP_THREAD_NAME "tiT" + +/** + * 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. + */ +#define TCPIP_THREAD_STACKSIZE 512 //not ok:384 + +/** + * 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. + */ +#define TCPIP_THREAD_PRIO (configMAX_PRIORITIES-5) + +/** + * 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. + */ +#define TCPIP_MBOX_SIZE 16 + +/** + * 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. + */ +#define DEFAULT_UDP_RECVMBOX_SIZE 6 + +/** + * 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. + */ +#define DEFAULT_TCP_RECVMBOX_SIZE 6 + +/** + * 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. + */ +#define DEFAULT_ACCEPTMBOX_SIZE 6 + +/* + ---------------------------------------------- + ---------- Sequential layer options ---------- + ---------------------------------------------- +*/ +/** + * LWIP_TCPIP_CORE_LOCKING: (EXPERIMENTAL!) + * Don't use it if you're not an active lwIP project member + */ +#define LWIP_TCPIP_CORE_LOCKING 0 + +/* + ------------------------------------ + ---------- Socket options ---------- + ------------------------------------ +*/ +/** + * LWIP_SO_SNDTIMEO==1: Enable send timeout for sockets/netconns and + * SO_SNDTIMEO processing. + */ +#define LWIP_SO_SNDTIMEO 1 + +/** + * LWIP_SO_RCVTIMEO==1: Enable receive timeout for sockets/netconns and + * SO_RCVTIMEO processing. + */ +#define LWIP_SO_RCVTIMEO 1 + +/** + * 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) + */ +#define LWIP_TCP_KEEPALIVE 1 + +/** + * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing. + */ +#define LWIP_SO_RCVBUF 0 + +/** + * SO_REUSE==1: Enable SO_REUSEADDR option. + */ +#define SO_REUSE 0 + +/* + ---------------------------------------- + ---------- Statistics options ---------- + ---------------------------------------- +*/ +/** + * LWIP_STATS==1: Enable statistics collection in lwip_stats. + */ +#define LWIP_STATS 0 + +/* + --------------------------------- + ---------- PPP options ---------- + --------------------------------- +*/ + +/* + -------------------------------------- + ---------- Checksum options ---------- + -------------------------------------- +*/ + +/* + --------------------------------------- + ---------- IPv6 options --------------- + --------------------------------------- +*/ +/** + * LWIP_IPV6==1: Enable IPv6 + */ +#define LWIP_IPV6 1 + +/* + --------------------------------------- + ---------- Hook options --------------- + --------------------------------------- +*/ + +/* + --------------------------------------- + ---------- Debugging options ---------- + --------------------------------------- +*/ +/** + * ETHARP_DEBUG: Enable debugging in etharp.c. + */ +#define ETHARP_DEBUG LWIP_DBG_OFF + +/** + * PBUF_DEBUG: Enable debugging in pbuf.c. + */ +#define PBUF_DEBUG LWIP_DBG_OFF + +/** + * API_LIB_DEBUG: Enable debugging in api_lib.c. + */ +#define API_LIB_DEBUG LWIP_DBG_OFF + +/** + * SOCKETS_DEBUG: Enable debugging in sockets.c. + */ +#define SOCKETS_DEBUG LWIP_DBG_OFF + +/** + * IP_DEBUG: Enable debugging for IP. + */ +#define IP_DEBUG LWIP_DBG_OFF + +/** + * MEMP_DEBUG: Enable debugging in memp.c. + */ +#define MEMP_DEBUG LWIP_DBG_OFF + +/** + * TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug. + */ +#define TCP_INPUT_DEBUG LWIP_DBG_OFF + +/** + * TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions. + */ +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF + +/** + * TCPIP_DEBUG: Enable debugging in tcpip.c. + */ +#define TCPIP_DEBUG LWIP_DBG_OFF + +/** + * DHCP_DEBUG: Enable debugging in dhcp.c. + */ +#define DHCP_DEBUG LWIP_DBG_OFF + +#endif /* __LWIPOPTS_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/netif/etharp.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/netif/etharp.h new file mode 100644 index 0000000..aca2288 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/netif/etharp.h @@ -0,0 +1,224 @@ +/* + * 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 prio_vid); + PACK_STRUCT_FIELD(u16_t tpid); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define SIZEOF_VLAN_HDR 4 +#define VLAN_ID(vlan_hdr) (htons((vlan_hdr)->prio_vid) & 0xFFF) + +#endif /* ETHARP_SUPPORT_VLAN */ + +#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_PACKET (SIZEOF_ETH_HDR + SIZEOF_ETHARP_HDR) + +/** 5 seconds period */ +#define ARP_TMR_INTERVAL 5000 + +#define ETHTYPE_ARP 0x0806U +#define ETHTYPE_IP 0x0800U +#define ETHTYPE_VLAN 0x8100U +#define ETHTYPE_IPV6 0x86DDU +#define ETHTYPE_PPPOEDISC 0x8863U /* PPP Over Ethernet Discovery Stage */ +#define ETHTYPE_PPPOE 0x8864U /* 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); +s8_t etharp_find_addr(struct netif *netif, ip_addr_t *ipaddr, + struct eth_addr **eth_ret, ip_addr_t **ip_ret); +err_t etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr); +err_t etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q); +err_t etharp_request(struct netif *netif, ip_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)->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); +err_t etharp_remove_static_entry(ip_addr_t *ipaddr); +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ + +#if LWIP_AUTOIP +err_t etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr, + const struct eth_addr *ethdst_addr, + const struct eth_addr *hwsrc_addr, const ip_addr_t *ipsrc_addr, + const struct eth_addr *hwdst_addr, const ip_addr_t *ipdst_addr, + const u16_t opcode); +#endif /* LWIP_AUTOIP */ + +#endif /* LWIP_ARP */ + +err_t ethernet_input(struct pbuf *p, struct netif *netif); + +#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 */ + +#ifdef __cplusplus +} +#endif + +#endif /* __NETIF_ARP_H__ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/netif/if_llc.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/netif/if_llc.h new file mode 100644 index 0000000..ca09b38 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/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/Distrib/ESPressif/RTOS/1.5.0/include/lwip/netif/ppp_oe.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/netif/ppp_oe.h new file mode 100644 index 0000000..67d8fe0 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/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/Distrib/ESPressif/RTOS/1.5.0/include/lwip/netif/slipif.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/netif/slipif.h new file mode 100644 index 0000000..9689c3f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/netif/slipif.h @@ -0,0 +1,81 @@ +/* + * 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 __NETIF_SLIPIF_H__ +#define __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 serila 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 + diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/lwip/netif/wlan_lwip_if.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/netif/wlan_lwip_if.h new file mode 100644 index 0000000..eee411e --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/netif/wlan_lwip_if.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2010-2011 Espressif System + * +*/ + +#ifndef _WLAN_LWIP_IF_H_ +#define _WLAN_LWIP_IF_H_ + +#include "lwip/err.h" + +err_t ethernetif_init(struct netif *netif); +void ethernetif_input(struct netif *netif, struct pbuf *p); + +#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/Distrib/ESPressif/RTOS/1.5.0/include/lwip/posix/netdb.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/posix/netdb.h new file mode 100644 index 0000000..8fc2596 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/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/Distrib/ESPressif/RTOS/1.5.0/include/lwip/posix/sys/socket.h b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/posix/sys/socket.h new file mode 100644 index 0000000..5d2ab84 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/lwip/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/aes.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/aes.h new file mode 100644 index 0000000..a36e825 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/aesni.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/aesni.h new file mode 100644 index 0000000..b1b7f1c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/arc4.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/arc4.h new file mode 100644 index 0000000..5fc5395 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/asn1.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/asn1.h new file mode 100644 index 0000000..082832c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/asn1write.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/asn1write.h new file mode 100644 index 0000000..73ff32b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/base64.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/base64.h new file mode 100644 index 0000000..352c652 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/bignum.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/bignum.h new file mode 100644 index 0000000..aa51556 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/blowfish.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/blowfish.h new file mode 100644 index 0000000..34626ee --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/bn_mul.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/bn_mul.h new file mode 100644 index 0000000..5408d41 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/camellia.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/camellia.h new file mode 100644 index 0000000..0424d62 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ccm.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ccm.h new file mode 100644 index 0000000..ef75839 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/certs.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/certs.h new file mode 100644 index 0000000..6b7e40b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/check_config.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/check_config.h new file mode 100644 index 0000000..b6448ec --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/cipher.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/cipher.h new file mode 100644 index 0000000..70000f5 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/cipher_internal.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/cipher_internal.h new file mode 100644 index 0000000..6c58bcc --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/compat-1.3.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/compat-1.3.h new file mode 100644 index 0000000..27abbd9 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/config.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/config.h new file mode 100644 index 0000000..d1db0d8 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/config_esp.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/config_esp.h new file mode 100644 index 0000000..ac393c0 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ctr_drbg.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ctr_drbg.h new file mode 100644 index 0000000..059d3c5 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/debug.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/debug.h new file mode 100644 index 0000000..d859dd5 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/des.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/des.h new file mode 100644 index 0000000..5ca2ecf --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/dhm.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/dhm.h new file mode 100644 index 0000000..cd056d1 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ecdh.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ecdh.h new file mode 100644 index 0000000..625a281 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ecdsa.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ecdsa.h new file mode 100644 index 0000000..52827d8 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ecjpake.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ecjpake.h new file mode 100644 index 0000000..b7b6160 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ecp.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ecp.h new file mode 100644 index 0000000..5246c78 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/entropy.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/entropy.h new file mode 100644 index 0000000..00de9a6 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/entropy_poll.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/entropy_poll.h new file mode 100644 index 0000000..dc11911 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/error.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/error.h new file mode 100644 index 0000000..5e549f6 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/gcm.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/gcm.h new file mode 100644 index 0000000..6743ac9 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/havege.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/havege.h new file mode 100644 index 0000000..dac5d31 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/hmac_drbg.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/hmac_drbg.h new file mode 100644 index 0000000..e010558 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/md.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/md.h new file mode 100644 index 0000000..703e781 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/md2.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/md2.h new file mode 100644 index 0000000..0f93fbf --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/md4.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/md4.h new file mode 100644 index 0000000..45214d4 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/md5.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/md5.h new file mode 100644 index 0000000..5a64061 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/md_internal.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/md_internal.h new file mode 100644 index 0000000..e2441bb --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/memory_buffer_alloc.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/memory_buffer_alloc.h new file mode 100644 index 0000000..661bc08 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/net.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/net.h new file mode 100644 index 0000000..8c6534c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/oid.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/oid.h new file mode 100644 index 0000000..fcecdaf --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/padlock.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/padlock.h new file mode 100644 index 0000000..2045a5a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/pem.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/pem.h new file mode 100644 index 0000000..54dc02d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/pk.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/pk.h new file mode 100644 index 0000000..458bb51 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/pk_internal.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/pk_internal.h new file mode 100644 index 0000000..01d0f21 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/pkcs11.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/pkcs11.h new file mode 100644 index 0000000..2e88928 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/pkcs12.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/pkcs12.h new file mode 100644 index 0000000..9b2d904 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/pkcs5.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/pkcs5.h new file mode 100644 index 0000000..ec5cb9e --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/platform.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/platform.h new file mode 100644 index 0000000..8d5199e --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/platform.h @@ -0,0 +1,214 @@ +/** + * \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. + * \{ + */ + +#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 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 calloc /**< Default allocator to use */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_FREE) +#define MBEDTLS_PLATFORM_STD_FREE free /**< 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 free +#define mbedtls_calloc calloc +#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 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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ripemd160.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ripemd160.h new file mode 100644 index 0000000..7083fc8 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/rsa.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/rsa.h new file mode 100644 index 0000000..9c8645d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/sha1.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/sha1.h new file mode 100644 index 0000000..7a67c6c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/sha256.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/sha256.h new file mode 100644 index 0000000..f8041ad --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/sha512.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/sha512.h new file mode 100644 index 0000000..627694f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ssl.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ssl.h new file mode 100644 index 0000000..ff5f389 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ssl_cache.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ssl_cache.h new file mode 100644 index 0000000..1155924 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ssl_ciphersuites.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ssl_ciphersuites.h new file mode 100644 index 0000000..deaaa37 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ssl_cookie.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ssl_cookie.h new file mode 100644 index 0000000..037e1c3 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ssl_internal.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ssl_internal.h new file mode 100644 index 0000000..fdcb8de --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ssl_internal.h @@ -0,0 +1,499 @@ +/** + * \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 */ + +#if defined(ESP8266_PLATFORM) + +int mbedtls_ssl_finished_hanshake(mbedtls_ssl_context *ssl); + +#endif +/** + * \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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ssl_ticket.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/ssl_ticket.h new file mode 100644 index 0000000..7c6bc61 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/threading.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/threading.h new file mode 100644 index 0000000..c39cbf2 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/timing.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/timing.h new file mode 100644 index 0000000..ae7a713 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/version.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/version.h new file mode 100644 index 0000000..ea2966e --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/x509.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/x509.h new file mode 100644 index 0000000..54dac16 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/x509_crl.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/x509_crl.h new file mode 100644 index 0000000..7988439 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/x509_crt.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/x509_crt.h new file mode 100644 index 0000000..fe821d1 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/x509_csr.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/x509_csr.h new file mode 100644 index 0000000..34998a3 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/xtea.h b/Distrib/ESPressif/RTOS/1.5.0/include/mbedtls/xtea.h new file mode 100644 index 0000000..b073f84 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll.h b/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll.h new file mode 100644 index 0000000..c483e4b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll.h @@ -0,0 +1,135 @@ +/* + * LibNoPoll: A websocket library + * Copyright (C) 2013 Advanced Software Production Line, S.L. + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * You may find a copy of the license under this software is released + * at COPYING file. This is LGPL software: you are welcome to develop + * proprietary applications using this library without any royalty or + * fee but returning back any change, improvement or addition in the + * form of source code, project image, documentation patches, etc. + * + * For commercial support on build Websocket enabled solutions + * contact us: + * + * Postal address: + * Advanced Software Production Line, S.L. + * Edificio Alius A, Oficina 102, + * C/ Antonio Suarez Nº 10, + * Alcalá de Henares 28802 Madrid + * Spain + * + * Email address: + * info@aspl.es - http://www.aspl.es/nopoll + */ +#ifndef __NOPOLL_H__ +#define __NOPOLL_H__ + +#include +#include + +BEGIN_C_DECLS + +#if defined(NOPOLL_OS_WIN32) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * \addtogroup nopoll_module + * @{ + */ + +nopoll_bool nopoll_cmp (const char * string1, const char * string2); + +nopoll_bool nopoll_ncmp (const char * string1, const char * string2, int bytes); + +char * nopoll_strdup_printf (const char * chunk, ...); + +char * nopoll_strdup_printfv (const char * chunk, va_list args); + +void nopoll_trim (char * chunk, int * trimmed); + +void nopoll_sleep (long microseconds); + +void nopoll_thread_handlers (noPollMutexCreate mutex_create, + noPollMutexDestroy mutex_destroy, + noPollMutexLock mutex_lock, + noPollMutexUnlock mutex_unlock); + +noPollPtr nopoll_mutex_create (void); + +void nopoll_mutex_lock (noPollPtr mutex); + +void nopoll_mutex_unlock (noPollPtr mutex); + +void nopoll_mutex_destroy (noPollPtr mutex); + +nopoll_bool nopoll_base64_encode (const char * content, + int length, + char * output, + int * output_size); + +nopoll_bool nopoll_base64_decode (const char * content, + int length, + char * output, + int * output_size); + +int nopoll_timeval_substract (struct timeval * a, + struct timeval * b, + struct timeval * result); + +char * nopoll_strdup (const char * buffer); + +nopoll_bool nopoll_nonce (char * buffer, int nonce_size); + +void nopoll_cleanup_library (void); + +int nopoll_get_bit (char byte, int position); + +void nopoll_set_bit (char * buffer, int position); + +void nopoll_show_byte (noPollCtx * ctx, char byte, const char * label); + +char * nopoll_int2bin (int a, char *buffer, int buf_size); + +void nopoll_int2bin_print (noPollCtx * ctx, int value); + +int nopoll_get_8bit (const char * buffer); + +int nopoll_get_16bit (const char * buffer); + +void nopoll_set_16bit (int value, char * buffer); + +void nopoll_set_32bit (int value, char * buffer); + +int nopoll_get_32bit (const char * buffer); + +/* @} */ + +END_C_DECLS + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_config.h b/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_config.h new file mode 100644 index 0000000..d8f2116 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_config.h @@ -0,0 +1,67 @@ +/* + * Nopoll Library nopoll_config.h + * Platform dependant definitions. + * + * This is a generated file. Please modify 'configure.in' + */ + +#ifndef __NOPOLL_CONFIG_H__ +#define __NOPOLL_CONFIG_H__ + +/** + * \addtogroup nopoll_decl_module + * @{ + */ + +/** + * @brief Allows to convert integer value (including constant values) + * into a pointer representation. + * + * Use the oposite function to restore the value from a pointer to a + * integer: \ref PTR_TO_INT. + * + * @param integer The integer value to cast to pointer. + * + * @return A \ref noPollPtr reference. + */ +#ifndef INT_TO_PTR +#define INT_TO_PTR(integer) ((noPollPtr) (long) ((int)integer)) +#endif + +/** + * @brief Allows to convert a pointer reference (\ref noPollPtr), + * which stores an integer that was stored using \ref INT_TO_PTR. + * + * Use the oposite function to restore the pointer value stored in the + * integer value. + * + * @param ptr The pointer to cast to a integer value. + * + * @return A int value. + */ +#ifndef PTR_TO_INT +#define PTR_TO_INT(ptr) ((int) (long) (ptr)) +#endif + +/** + * @brief Allows to get current platform configuration. This is used + * by Nopoll library but could be used by applications built on top of + * Nopoll to change its configuration based on the platform information. + */ +#define NOPOLL_OS_UNIX (0) + +/** + * @internal Allows to now if the platform support vasprintf + * function. Do not use this macro as it is supposed to be for + * internal use. + */ +//#define NOPOLL_HAVE_VASPRINTF (1) + +/** + * @brief Indicates that this platform have support for 64bits. + */ +//#define NOPOLL_64BIT_PLATFORM (0) + +/* @} */ + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_conn.h b/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_conn.h new file mode 100644 index 0000000..aff440f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_conn.h @@ -0,0 +1,198 @@ +/* + * LibNoPoll: A websocket library + * Copyright (C) 2013 Advanced Software Production Line, S.L. + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * You may find a copy of the license under this software is released + * at COPYING file. This is LGPL software: you are welcome to develop + * proprietary applications using this library without any royalty or + * fee but returning back any change, improvement or addition in the + * form of source code, project image, documentation patches, etc. + * + * For commercial support on build Websocket enabled solutions + * contact us: + * + * Postal address: + * Advanced Software Production Line, S.L. + * Edificio Alius A, Oficina 102, + * C/ Antonio Suarez Nº 10, + * Alcalá de Henares 28802 Madrid + * Spain + * + * Email address: + * info@aspl.es - http://www.aspl.es/nopoll + */ +#ifndef __NOPOLL_CONN_H__ +#define __NOPOLL_CONN_H__ + +#include + +BEGIN_C_DECLS + +noPollConn * nopoll_conn_new (noPollCtx * ctx, + const char * host_ip, + const char * host_port, + const char * host_name, + const char * get_url, + const char * protocols, + const char * origin); + +noPollConn * nopoll_conn_new_opts (noPollCtx * ctx, + noPollConnOpts * opts, + const char * host_ip, + const char * host_port, + const char * host_name, + const char * get_url, + const char * protocols, + const char * origin); + +noPollConn * nopoll_conn_tls_new (noPollCtx * ctx, + noPollConnOpts * options, + const char * host_ip, + const char * host_port, + const char * host_name, + const char * get_url, + const char * protocols, + const char * origin); + +noPollConn * nopoll_conn_accept (noPollCtx * ctx, noPollConn * listener); + +noPollConn * nopoll_conn_accept_socket (noPollCtx * ctx, noPollConn * listener, NOPOLL_SOCKET session); + +nopoll_bool nopoll_conn_accept_complete (noPollCtx * ctx, + noPollConn * listener, + noPollConn * conn, + NOPOLL_SOCKET session, + nopoll_bool tls_on); + +nopoll_bool nopoll_conn_ref (noPollConn * conn); + +int nopoll_conn_ref_count (noPollConn * conn); + +void nopoll_conn_unref (noPollConn * conn); + +nopoll_bool nopoll_conn_is_ok (noPollConn * conn); + +nopoll_bool nopoll_conn_is_ready (noPollConn * conn); + +nopoll_bool nopoll_conn_is_tls_on (noPollConn * conn); + +NOPOLL_SOCKET nopoll_conn_socket (noPollConn * conn); + +void nopoll_conn_set_socket (noPollConn * conn, NOPOLL_SOCKET _socket); + +int nopoll_conn_get_id (noPollConn * conn); + +noPollCtx * nopoll_conn_ctx (noPollConn * conn); + +noPollRole nopoll_conn_role (noPollConn * conn); + +const char * nopoll_conn_host (noPollConn * conn); + +const char * nopoll_conn_port (noPollConn * conn); + +const char * nopoll_conn_get_origin (noPollConn * conn); + +const char * nopoll_conn_get_host_header (noPollConn * conn); + +const char * nopoll_conn_get_cookie (noPollConn * conn); + +const char * nopoll_conn_get_accepted_protocol (noPollConn * conn); + +const char * nopoll_conn_get_requested_protocol (noPollConn * conn); + +void nopoll_conn_set_accepted_protocol (noPollConn * conn, const char * protocol); + +int nopoll_conn_get_close_status (noPollConn * conn); + +const char * nopoll_conn_get_close_reason (noPollConn * conn); + +void nopoll_conn_shutdown (noPollConn * conn); + +void nopoll_conn_close (noPollConn * conn); + +void nopoll_conn_close_ext (noPollConn * conn, int status, const char * reason, int reason_size); + +void nopoll_conn_set_hook (noPollConn * conn, noPollPtr ptr); + +noPollPtr nopoll_conn_get_hook (noPollConn * conn); + +nopoll_bool nopoll_conn_set_sock_block (NOPOLL_SOCKET socket, + nopoll_bool enable); + +noPollMsg * nopoll_conn_get_msg (noPollConn * conn); + +int nopoll_conn_send_text (noPollConn * conn, const char * content, long length); + +int nopoll_conn_send_text_fragment (noPollConn * conn, const char * content, long length); + +int nopoll_conn_send_binary (noPollConn * conn, const char * content, long length); + +int nopoll_conn_send_binary_fragment (noPollConn * conn, const char * content, long length); + +int nopoll_conn_complete_pending_write (noPollConn * conn); + +int nopoll_conn_pending_write_bytes (noPollConn * conn); + +int nopoll_conn_flush_writes (noPollConn * conn, long timeout, int previous_result); + +int nopoll_conn_read (noPollConn * conn, char * buffer, int bytes, nopoll_bool block, long int timeout); + +noPollConn * nopoll_conn_get_listener (noPollConn * conn); + +nopoll_bool nopoll_conn_send_ping (noPollConn * conn); + +nopoll_bool nopoll_conn_send_pong (noPollConn * conn); + +void nopoll_conn_set_on_msg (noPollConn * conn, + noPollOnMessageHandler on_msg, + noPollPtr user_data); + +void nopoll_conn_set_on_ready (noPollConn * conn, + noPollActionHandler on_ready, + noPollPtr user_data); + +void nopoll_conn_set_on_close (noPollConn * conn, + noPollOnCloseHandler on_close, + noPollPtr user_data); + +int nopoll_conn_send_frame (noPollConn * conn, nopoll_bool fin, nopoll_bool masked, + noPollOpCode op_code, long length, noPollPtr content, + long sleep_in_header); + +int __nopoll_conn_send_common (noPollConn * conn, + const char * content, + long length, + nopoll_bool has_fin, + long sleep_in_header, + noPollOpCode frame_type); + +nopoll_bool nopoll_conn_wait_until_connection_ready (noPollConn * conn, + int timeout); + +/** internal api **/ +void nopoll_conn_complete_handshake (noPollConn * conn); + +int nopoll_conn_default_receive (noPollConn * conn, char * buffer, int buffer_size); + +int nopoll_conn_default_send (noPollConn * conn, char * buffer, int buffer_size); + +void nopoll_conn_mask_content (noPollCtx * ctx, char * payload, int payload_size, char * mask, int desp); + +END_C_DECLS + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_conn_opts.h b/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_conn_opts.h new file mode 100644 index 0000000..5aeb571 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_conn_opts.h @@ -0,0 +1,73 @@ +/* + * LibNoPoll: A websocket library + * Copyright (C) 2013 Advanced Software Production Line, S.L. + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * You may find a copy of the license under this software is released + * at COPYING file. This is LGPL software: you are welcome to develop + * proprietary applications using this library without any royalty or + * fee but returning back any change, improvement or addition in the + * form of source code, project image, documentation patches, etc. + * + * For commercial support on build Websocket enabled solutions + * contact us: + * + * Postal address: + * Advanced Software Production Line, S.L. + * Edificio Alius A, Oficina 102, + * C/ Antonio Suarez Nº 10, + * Alcalá de Henares 28802 Madrid + * Spain + * + * Email address: + * info@aspl.es - http://www.aspl.es/nopoll + */ +#ifndef __NOPOLL_CONN_OPTS_H__ +#define __NOPOLL_CONN_OPTS_H__ + +#include + +BEGIN_C_DECLS + +noPollConnOpts * nopoll_conn_opts_new (void); + +void nopoll_conn_opts_set_ssl_protocol (noPollConnOpts * opts, noPollSslProtocol ssl_protocol); + +nopoll_bool nopoll_conn_opts_set_ssl_certs (noPollConnOpts * opts, + const char * client_certificate, + const char * private_key, + const char * chain_certificate, + const char * ca_certificate); + +void nopoll_conn_opts_ssl_peer_verify (noPollConnOpts * opts, nopoll_bool verify); + +void nopoll_conn_opts_set_cookie (noPollConnOpts * opts, const char * cookie_content); + +nopoll_bool nopoll_conn_opts_ref (noPollConnOpts * opts); + +void nopoll_conn_opts_unref (noPollConnOpts * opts); + +void nopoll_conn_opts_set_reuse (noPollConnOpts * opts, nopoll_bool reuse); + +void nopoll_conn_opts_free (noPollConnOpts * opts); + +/** internal API **/ +void __nopoll_conn_opts_release_if_needed (noPollConnOpts * options); + +END_C_DECLS + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_ctx.h b/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_ctx.h new file mode 100644 index 0000000..a9e4154 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_ctx.h @@ -0,0 +1,106 @@ +/* + * LibNoPoll: A websocket library + * Copyright (C) 2013 Advanced Software Production Line, S.L. + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * You may find a copy of the license under this software is released + * at COPYING file. This is LGPL software: you are welcome to develop + * proprietary applications using this library without any royalty or + * fee but returning back any change, improvement or addition in the + * form of source code, project image, documentation patches, etc. + * + * For commercial support on build Websocket enabled solutions + * contact us: + * + * Postal address: + * Advanced Software Production Line, S.L. + * Edificio Alius A, Oficina 102, + * C/ Antonio Suarez Nº 10, + * Alcalá de Henares 28802 Madrid + * Spain + * + * Email address: + * info@aspl.es - http://www.aspl.es/nopoll + */ +#ifndef __NOPOLL_CTX_H__ +#define __NOPOLL_CTX_H__ + +#include + +BEGIN_C_DECLS + +noPollCtx * nopoll_ctx_new (void); + +nopoll_bool nopoll_ctx_ref (noPollCtx * ctx); + +void nopoll_ctx_unref (noPollCtx * ctx); + +int nopoll_ctx_ref_count (noPollCtx * ctx); + +nopoll_bool nopoll_ctx_register_conn (noPollCtx * ctx, + noPollConn * conn); + +void nopoll_ctx_unregister_conn (noPollCtx * ctx, + noPollConn * conn); + +int nopoll_ctx_conns (noPollCtx * ctx); + +nopoll_bool nopoll_ctx_set_certificate (noPollCtx * ctx, + const char * serverName, + const char * certificateFile, + const char * privateKey, + const char * optionalChainFile); + +nopoll_bool nopoll_ctx_find_certificate (noPollCtx * ctx, + const char * serverName, + const char ** certificateFile, + const char ** privateKey, + const char ** optionalChainFile); + +void nopoll_ctx_set_on_accept (noPollCtx * ctx, + noPollActionHandler on_accept, + noPollPtr user_data); + +void nopoll_ctx_set_on_open (noPollCtx * ctx, + noPollActionHandler on_open, + noPollPtr user_data); + +void nopoll_ctx_set_on_ready (noPollCtx * ctx, + noPollActionHandler on_ready, + noPollPtr user_data); + +void nopoll_ctx_set_on_msg (noPollCtx * ctx, + noPollOnMessageHandler on_msg, + noPollPtr user_data); + +void nopoll_ctx_set_ssl_context_creator (noPollCtx * ctx, + noPollSslContextCreator context_creator, + noPollPtr user_data); + +void nopoll_ctx_set_post_ssl_check (noPollCtx * ctx, + noPollSslPostCheck post_ssl_check, + noPollPtr user_data); + +noPollConn * nopoll_ctx_foreach_conn (noPollCtx * ctx, noPollForeachConn foreach, noPollPtr user_data); + +void nopoll_ctx_set_protocol_version (noPollCtx * ctx, int version); + +void nopoll_ctx_free (noPollCtx * ctx); + +END_C_DECLS + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_decl.h b/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_decl.h new file mode 100644 index 0000000..3505366 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_decl.h @@ -0,0 +1,469 @@ +/* + * LibNoPoll: A websocket library + * Copyright (C) 2013 Advanced Software Production Line, S.L. + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * You may find a copy of the license under this software is released + * at COPYING file. This is LGPL software: you are welcome to develop + * proprietary applications using this library without any royalty or + * fee but returning back any change, improvement or addition in the + * form of source code, project image, documentation patches, etc. + * + * For commercial support on build Websocket enabled solutions + * contact us: + * + * Postal address: + * Advanced Software Production Line, S.L. + * Edificio Alius A, Oficina 102, + * C/ Antonio Suarez Nº 10, + * Alcalá de Henares 28802 Madrid + * Spain + * + * Email address: + * info@aspl.es - http://www.aspl.es/nopoll + */ +#ifndef __NOPOLL_DECL_H__ +#define __NOPOLL_DECL_H__ + +/** + * \defgroup nopoll_decl_module Nopoll Declarations: Common Nopoll declarations, Types, macros, and support functions. + */ + +/** + * \addtogroup nopoll_decl_module + * @{ + */ + +/* include platform specific configuration */ +#include + +/* include this at this place to load GNU extensions */ +#if defined(__GNUC__) +# ifndef _GNU_SOURCE +# define _GNU_SOURCE +# endif +# define __NOPOLL_PRETTY_FUNCTION__ __PRETTY_FUNCTION__ +# define __NOPOLL_LINE__ __LINE__ +# define __NOPOLL_FILE__ __FILE__ +#elif defined(_MSC_VER) +# define __NOPOLL_PRETTY_FUNCTION__ __FUNCDNAME__ +# define __NOPOLL_LINE__ __LINE__ +# define __NOPOLL_FILE__ __FILE__ +#else +/* unknown compiler */ +#define __NOPOLL_PRETTY_FUNCTION__ "" +#define __NOPOLL_LINE__ 0 +#define __NOPOLL_FILE__ "" +#endif + +#include +#include +#include +#include + +/* only include unistd.h if unix platform is found or gnu gcc compiler + * is found */ +#if defined(__GNUC__) || defined(NOPOLL_OS_UNIX) +# include +#endif + +//#include +//#include +//#include +//#include +#include "lwip/netdb.h" +#include "lwip/sockets.h" + +/* Direct portable mapping definitions */ +#if defined(NOPOLL_OS_UNIX) + +/* Portable definitions while using noPoll Library */ +#define NOPOLL_EINTR EINTR +/** + * @brief Portable definition for EWOULDBLOCK errno code. + */ +#define NOPOLL_EWOULDBLOCK EWOULDBLOCK +#define NOPOLL_EINPROGRESS EINPROGRESS +#define NOPOLL_ENOTCONN ENOTCONN +#define NOPOLL_EAGAIN EAGAIN +#define NOPOLL_SOCKET int +#define NOPOLL_INVALID_SOCKET -1 +#define NOPOLL_SOCKET_ERROR -1 +#define nopoll_close_socket(s) do {if ( s >= 0) {close (s);}} while (0) +#define nopoll_is_disconnected (errno == EPIPE) + +#endif /* end defined(AXL_OS_UNIX) */ + +#if defined(NOPOLL_OS_WIN32) + +/* additional includes for the windows platform */ + +/* _WIN32_WINNT note: If the application including the header defines + * the _WIN32_WINNT, it must include the bit defined by the value + * 0x400. */ +#ifndef _WIN32_WINNT +# define _WIN32_WINNT 0x400 +#endif +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_FULL_VER +#define strcasecmp(string1, string2) _stricmp(string1, string2) +#endif + +#define NOPOLL_EINTR WSAEINTR +#define NOPOLL_EWOULDBLOCK WSAEWOULDBLOCK +#define NOPOLL_EINPROGRESS WSAEINPROGRESS +#define NOPOLL_ENOTCONN WSAENOTCONN +#define NOPOLL_EAGAIN WSAEWOULDBLOCK +#define SHUT_RDWR SD_BOTH +#define SHUT_WR SD_SEND +#define NOPOLL_SOCKET SOCKET +#define NOPOLL_INVALID_SOCKET INVALID_SOCKET +#define NOPOLL_SOCKET_ERROR SOCKET_ERROR +#define nopoll_close_socket(s) do {if ( s >= 0) {closesocket (s);}} while (0) +#define uint16_t u_short +#define nopoll_is_disconnected ((errno == WSAESHUTDOWN) || (errno == WSAECONNABORTED) || (errno == WSAECONNRESET)) + +/* a definition to avoid warnings */ +#define strlen (int) strlen + +/* no link support windows */ +#define S_ISLNK(m) (0) + +#endif /* end defined(AXL_OS_WINDOWS) */ + +#if defined(NOPOLL_OS_UNIX) +//#include +//#include +//#include "c_types.h" +//#include +//#include +//#include "lwip/sockets.h" +//#include +//#include +//#include +//#include +//#include +//#include +#endif + +/* additional headers for poll support */ +#if defined(NOPOLL_HAVE_POLL) +#include +#endif + +/* additional headers for linux epoll support */ +#if defined(NOPOLL_HAVE_EPOLL) +#include +#endif + +//#include + +#if defined(NOPOLL_OS_WIN32) +/* errno redefinition for windows platform. this declaration must + * follow the previous include. */ +#ifdef errno +#undef errno +#endif +#define errno (WSAGetLastError()) +#endif + +/** + * @brief Common definition to have false (\ref nopoll_false) value (which is defined to 0 integer value). + */ +#define nopoll_false ((int)0) +/** + * @brief Common definition to have true (\ref nopoll_true) value (which is defined to 1 integer value). + */ +#define nopoll_true ((int)1) + +/** + * @brief Bool definition for the Nopoll toolkit. This type built on + * top of int is used along with \ref nopoll_false and \ref + * nopoll_true to model those API functions and attributes that + * returns or receive a boolean state. + */ +typedef int nopoll_bool; + +/** + * @brief Pointer to any structure definition. It should be required + * to use this definition, however, some platforms doesn't support the + * void * making it necessary to use the char * + * definition as a general way to represent references. + */ +typedef void * noPollPtr; + +/** + * @brief Execution context object used by the API to provide default + * settings. + */ +typedef struct _noPollCtx noPollCtx; + +/** + * @brief Abstraction that represents a connection that maybe be a listener created by \ref nopoll_listener_new or because the connection was received as a consequence of that call, or because it is a client connection created by \ref nopoll_conn_new + * + * See noPoll API because there are other methods to create connections (not only previous mentioned functions). + */ +typedef struct _noPollConn noPollConn; + +/** + * @brief Optional connection options to change default behaviour. + */ +typedef struct _noPollConnOpts noPollConnOpts; + +/** + * @brief Abstraction that represents a selected IO wait mechanism. + */ +typedef struct _noPollIoEngine noPollIoEngine; + +/** + * @brief Abstraction that represents a single websocket message + * received. + */ +typedef struct _noPollMsg noPollMsg; + +/** + * @brief Abstraction that represents the status and data exchanged + * during the handshake. + */ +typedef struct _noPollHandshake noPollHandShake; + +/** + * @brief Nopoll debug levels. + * + * While reporting log to the console, these levels are used to report + * the severity for such log. + */ +typedef enum { + /** + * @brief Debug level. Only used to report common + * circumstances that represent the proper functionality. + */ + NOPOLL_LEVEL_DEBUG, + /** + * @brief Warning level. Only used to report that an internal + * issue have happend that could be interesting while + * reporting error, but it could also mean common situations. + */ + NOPOLL_LEVEL_WARNING, + /** + * @brief Critical level. Only used to report critical + * situations where some that have happened shouldn't. + * + * This level should only be used while reporting critical + * situations. + */ + NOPOLL_LEVEL_CRITICAL} +noPollDebugLevel; + +/** + * @brief Describes the connection role (how it was initiated). + */ +typedef enum { + /** + * @brief Unknown role, returned/used when the connection isn't defined. + */ + NOPOLL_ROLE_UNKNOWN, + /** + * @brief When the connection was created connecting to a web + * socket server (see \ref nopoll_conn_new). + */ + NOPOLL_ROLE_CLIENT, + /** + * @brief When the connection was accepted being a listener + * process. + */ + NOPOLL_ROLE_LISTENER, + /** + * @brief When the connection was created by \ref + * nopoll_listener_new to accept incoming connections. + */ + NOPOLL_ROLE_MAIN_LISTENER +} noPollRole; + +/** + * @brief List of supported IO waiting mechanism available. + */ +typedef enum { + /** + * @brief Selects the default (best) IO mechanism found on the + * system. + */ + NOPOLL_IO_ENGINE_DEFAULT, + /** + * @brief Selects the select(2) based IO wait mechanism. + */ + NOPOLL_IO_ENGINE_SELECT, + /** + * @brief Selects the poll(2) based IO wait mechanism. + */ + NOPOLL_IO_ENGINE_POLL, + /** + * @brief Selects the epoll(2) based IO wait mechanism. + */ + NOPOLL_IO_ENGINE_EPOLL +} noPollIoEngineType; + +/** + * @brief Support macro to allocate memory using nopoll_calloc function, + * making a casting and using the sizeof keyword. + * + * @param type The type to allocate + * @param count How many items to allocate. + * + * @return A newly allocated pointer. + */ +#define nopoll_new(type, count) (type *) nopoll_calloc (count, sizeof (type)) + +/** + * @brief Allows to check a condition and return if it is not meet. + * + * @param ctx The context where the operation will take place. + * @param expr The expresion to check. + */ +#define nopoll_return_if_fail(ctx, expr) \ + if (!(expr)) {__nopoll_log (ctx, __function_name__, __file__, __line__, NOPOLL_LEVEL_CRITICAL, "Expresion '%s' have failed at %s (%s:%d)", #expr, __NOPOLL_PRETTY_FUNCTION__, __NOPOLL_FILE__, __NOPOLL_LINE__); return;} + +/** + * @brief Allows to check a condition and return the given value if it + * is not meet. + * + * @param ctx The context where the operation will take place. + * + * @param expr The expresion to check. + * + * @param val The value to return if the expression is not meet. + */ +#define nopoll_return_val_if_fail(ctx, expr, val) \ + if (!(expr)) { __nopoll_log (ctx, __function_name__, __file__, __line__, NOPOLL_LEVEL_CRITICAL, "Expresion '%s' have failed, returning: %s at %s (%s:%d)", #expr, #val, __NOPOLL_PRETTY_FUNCTION__, __NOPOLL_FILE__, __NOPOLL_LINE__); return val;} + + +/** + * @internal + * + * C++ support declarations borrowed from the libtool webpage. Thanks + * you guys for this information. + * + * BEGIN_C_DECLS should be used at the beginning of your declarations, + * so that C++ compilers don't mangle their names. Use END_C_DECLS at + * the end of C declarations. + */ +#undef BEGIN_C_DECLS +#undef END_C_DECLS +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else +# define BEGIN_C_DECLS /* empty */ +# define END_C_DECLS /* empty */ +#endif + + +/** + * @brief Type of frames and opcodes supported by noPoll. + */ +typedef enum { + /** + * @brief Support to model unknown op code. + */ + NOPOLL_UNKNOWN_OP_CODE = -1, + /** + * @brief Denotes a continuation frame. + */ + NOPOLL_CONTINUATION_FRAME = 0, + /** + * @brief Denotes a text frame (utf-8 content) and the first + * frame of the message. + */ + NOPOLL_TEXT_FRAME = 1, + /** + * @brief Denotes a binary frame and the first frame of the + * message. + */ + NOPOLL_BINARY_FRAME = 2, + /** + * @brief Denotes a close frame request. + */ + NOPOLL_CLOSE_FRAME = 8, + /** + * @brief Denotes a ping frame (used to ring test the circuit + * and to keep alive the connection). + */ + NOPOLL_PING_FRAME = 9, + /** + * @brief Denotes a pong frame (reply to ping request). + */ + NOPOLL_PONG_FRAME = 10 +} noPollOpCode; + +/** + * @brief SSL/TLS protocol type to use for the client or listener + * connection. + */ +typedef enum { + /** + * @brief Allows to define SSLv23 as SSL protocol used by the + * client or server connection. A TLS/SSL connection + * established with these methods may understand SSLv3, TLSv1, + * TLSv1.1 and TLSv1.2 protocols (\ref NOPOLL_METHOD_SSLV3, \ref NOPOLL_METHOD_TLSV1, ...) + */ + NOPOLL_METHOD_SSLV23 = 2, + /** + * @brief Allows to define SSLv3 as SSL protocol used by the + * client or server connection. A connection/listener + * established with this method will only understand this + * method. + */ + NOPOLL_METHOD_SSLV3 = 3, + /** + * @brief Allows to define TLSv1 as SSL protocol used by the + * client or server connection. A connection/listener + * established with this method will only understand this + * method. + */ + NOPOLL_METHOD_TLSV1 = 4, +//#if defined(TLSv1_1_client_method) + /** + * @brief Allows to define TLSv1.1 as SSL protocol used by the + * client or server connection. A connection/listener + * established with this method will only understand this + * method. + */ + NOPOLL_METHOD_TLSV1_1 = 5 +//#endif +} noPollSslProtocol ; + +BEGIN_C_DECLS + +#include "esp_libc.h" + +noPollPtr nopoll_calloc (size_t count, size_t size); + +noPollPtr nopoll_realloc (noPollPtr ref, size_t size); + +void nopoll_free (noPollPtr ref); + +END_C_DECLS + +#endif + +/* @} */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_handlers.h b/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_handlers.h new file mode 100644 index 0000000..e3a385c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_handlers.h @@ -0,0 +1,329 @@ +/* + * LibNoPoll: A websocket library + * Copyright (C) 2013 Advanced Software Production Line, S.L. + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * You may find a copy of the license under this software is released + * at COPYING file. This is LGPL software: you are welcome to develop + * proprietary applications using this library without any royalty or + * fee but returning back any change, improvement or addition in the + * form of source code, project image, documentation patches, etc. + * + * For commercial support on build Websocket enabled solutions + * contact us: + * + * Postal address: + * Advanced Software Production Line, S.L. + * Edificio Alius A, Oficina 102, + * C/ Antonio Suarez Nº 10, + * Alcalá de Henares 28802 Madrid + * Spain + * + * Email address: + * info@aspl.es - http://www.aspl.es/nopoll + */ +#ifndef __NOPOLL_HANDLERS_H__ +#define __NOPOLL_HANDLERS_H__ + +/** + * \defgroup nopoll_handlers noPoll Handlers: Handler definitions used by the library to du async notifications + */ + +/** + * \addtogroup nopoll_handlers + * @{ + */ + +/** + * @brief General async handler definition used to notify generic + * events associated to a connection. + * + * Currently this handler is used by: + * - \ref nopoll_ctx_set_on_accept + * - \ref nopoll_ctx_set_on_open + * + * @param ctx The context where the wait is happening. + * + * @param conn The connection where the data or something meaningful + * was detected. + * + * @param user_data Optional user data pointer passed in into the handler. + * + * @return The function returns a boolean value which is interpreted + * in an especific form according to the event. + */ +typedef nopoll_bool (*noPollActionHandler) (noPollCtx * ctx, noPollConn * conn, noPollPtr user_data); + +/** + * @brief Handler used to define the create function for an IO mechanism. + * + * @param ctx The context where the io mechanism will be created. + */ +typedef noPollPtr (*noPollIoMechCreate) (noPollCtx * ctx); + +/** + * @brief Handler used to define the IO wait set destroy function for + * an IO mechanism. + * + * @param ctx The context where the io mechanism will be destroyed. + * + * @param io_object The io object to be destroyed as created by \ref + * noPollIoMechCreate handler. + */ +typedef void (*noPollIoMechDestroy) (noPollCtx * ctx, noPollPtr io_object); + +/** + * @brief Handler used to define the IO wait set clear function for an + * IO mechanism. + * + * @param ctx The context where the io mechanism will be cleared. + * + * @param io_object The io object to be created as created by \ref + * noPollIoMechCreate handler. + */ +typedef void (*noPollIoMechClear) (noPollCtx * ctx, noPollPtr io_object); + + +/** + * @brief Handler used to define the IO wait function for an IO + * mechanism. + * + * @param ctx The context where the io mechanism was created. + * + * @param io_object The io object to be created as created by \ref + * noPollIoMechCreate handler where the wait will be implemented. + */ +typedef int (*noPollIoMechWait) (noPollCtx * ctx, noPollPtr io_object); + + +/** + * @brief Handler used to define the IO add to set function for an IO + * mechanism. + * + * @param ctx The context where the io mechanism was created. + * + * @param conn The noPollConn to be added to the working set. + * + * @param io_object The io object to be created as created by \ref + * noPollIoMechCreate handler where the wait will be implemented. + */ +typedef nopoll_bool (*noPollIoMechAddTo) (int fds, + noPollCtx * ctx, + noPollConn * conn, + noPollPtr io_object); + + +/** + * @brief Handler used to define the IO is set function for an IO + * mechanism. + * + * @param ctx The context where the io mechanism was created. + * + * @param conn The noPollConn to be added to the working set. + * + * @param io_object The io object to be created as created by \ref + * noPollIoMechCreate handler where the wait will be implemented. + */ +typedef nopoll_bool (*noPollIoMechIsSet) (noPollCtx * ctx, + int fds, + noPollPtr io_object); + +/** + * @brief Handler used to define the foreach function that is used by + * \ref nopoll_ctx_foreach_conn + * + * @param ctx The context where the foreach operation is taking place. + * + * @param conn The connection notified + * + * @param user_data Optional user defined pointer received at \ref + * nopoll_ctx_foreach_conn. + * + * @return nopoll_true to stop the foreach process, otherwise + * nopoll_false to keep checking the next connection until all + * connections are notified. + */ +typedef nopoll_bool (*noPollForeachConn) (noPollCtx * ctx, + noPollConn * conn, + noPollPtr user_data); + +/** + * @brief Handler definition used to describe read functions used by \ref noPollConn. + * + * @param conn The connection where the readOperation will take place. + * + * @param buffer The buffer where data read from socket will be placed. + * + * @param buffer_size The buffer size that is receiving the function. + */ +typedef int (*noPollRead) (noPollConn * conn, + char * buffer, + int buffer_size); + +/** + * @brief Handler definition used to notify websocket messages + * received. + * + * This handler will be called when a websocket message is + * received. Keep in mind the reference received on this handler will + * be finished when the handler ends. If you need to have a reference + * to the message after handler execution, acquire a reference via + * \ref nopoll_msg_ref. + * + * @param ctx The context where the messagewas received. + * + * @param conn The connection where the message was received. + * + * @param msg The websocket message was received. + * + * @param user_data An optional user defined pointer. + */ +typedef void (*noPollOnMessageHandler) (noPollCtx * ctx, + noPollConn * conn, + noPollMsg * msg, + noPollPtr user_data); + +/** + * @brief Handler definition used by \ref nopoll_conn_set_on_close. + * + * Handler definition for the function that is called when the + * connection is closed but just before shutting down the socket + * associated to the connection. + * + * @param ctx The context where the operation will take place. + * + * @param conn The connection where the operation will take place. + * + * @param user_data The reference that was configured to be passed in + * into the handler. + */ +typedef void (*noPollOnCloseHandler) (noPollCtx * ctx, + noPollConn * conn, + noPollPtr user_data); + +/** + * @brief Mutex creation handler used by the library. + * + * @return A reference to the mutex created (already initialized). + */ +typedef noPollPtr (*noPollMutexCreate) (void); + +/** + * @brief Mutex destroy handler used by the library. + * + * @param The mutex to destroy. + */ +typedef void (*noPollMutexDestroy) (noPollPtr mutex); + +/** + * @brief Mutex lock handler used by the library. + * + * @param The mutex where to implement the lock operation. + */ +typedef void (*noPollMutexLock) (noPollPtr mutex); + +/** + * @brief Mutex unlock handler used by the library. + * + * @param The mutex where to implement the unlock operation. + */ +typedef void (*noPollMutexUnlock) (noPollPtr mutex); + +/** + * @brief Handler used by nopoll_log_set_handler to receive all log + * notifications produced by the library on this function. + * + * @param ctx The context where the operation is happening. + * + * @param level The log level + * + * @param log_msg The actual log message reported. + * + * @param user_data A reference to user defined pointer passed in into the function. + */ +typedef void (*noPollLogHandler) (noPollCtx * ctx, noPollDebugLevel level, const char * log_msg, noPollPtr user_data); + +/** + * @brief An optional handler that allows user land code to define how + * is SSL_CTX (SSL context) created and which are the settings it + * should have before taking place SSL/TLS handshake. + * + * NOTE: that the function should return one context for every + * connection created. Do not reuse unless you know what you are + * doing. + * + * A very bare implementation for this context creation will be: + * + * \code + * SSL_CTX * my_ssl_ctx_creator (noPollCtx * ctx, noPollConn * conn, noPollConnOpts * opts, nopoll_bool is_client, noPollPtr user_data) + * { + * // very basic context creation using default settings provided by OpenSSL + * return SSL_CTX_new (is_client ? TLSv1_client_method () : TLSv1_server_method ()); + * } + * \endcode + * + * @param ctx The context where the operation is taking place. + * + * @param conn The connection that is being requested for a new context (SSL_CTX). Use is_client to know if this is a connecting client or a listener connection. + * + * @param opts Optional reference to the connection object created for this connection. + * + * @param is_client nopoll_true to signal that this is a request for a context for a client connection. Otherwise, it is for a listener connection. + * + * @param user_data User defined pointer that received on this function as defined at \ref nopoll_ctx_set_ssl_context_creator. + * + * @return The function must return a valid SSL_CTX object (see OpenSSL documentation to know more about this) or NULL if it fails. + */ +typedef noPollPtr (*noPollSslContextCreator) (noPollCtx * ctx, + noPollConn * conn, + noPollConnOpts * opts, + nopoll_bool is_client, + noPollPtr user_data); + +/** + * @brief Optional user defined handler that allows to execute SSL + * post checks code before proceed. + * + * This handler is configured at \ref nopoll_ctx_set_post_ssl_check + * and allows to implement custom actions while additional + * verifications about certificate received, validation based on + * certain attributes, etc. + * + * Note that when this handler is called, the SSL handshake has + * finished without error. In case of SSL handshake failure, this + * handler is not executed. + * + * @param ctx The context where the operation happens. + * + * @param conn The connection where the operation takes place and for which the post SSL check is being done. + * + * @param SSL_CTX The OpenSSL SSL_CTX object created for this connection. + * + * @param SSL The OpenSSL SSL object created for this connection. + * + * @param user_data User defined data that is received on this handler as configured at \ref nopoll_ctx_set_post_ssl_check + */ +typedef nopoll_bool (*noPollSslPostCheck) (noPollCtx * ctx, + noPollConn * conn, + noPollPtr SSL_CTX, + noPollPtr SSL, + noPollPtr user_data); + + +#endif + +/* @} */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_io.h b/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_io.h new file mode 100644 index 0000000..8e8f2a2 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_io.h @@ -0,0 +1,52 @@ +/* + * LibNoPoll: A websocket library + * Copyright (C) 2013 Advanced Software Production Line, S.L. + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * You may find a copy of the license under this software is released + * at COPYING file. This is LGPL software: you are welcome to develop + * proprietary applications using this library without any royalty or + * fee but returning back any change, improvement or addition in the + * form of source code, project image, documentation patches, etc. + * + * For commercial support on build Websocket enabled solutions + * contact us: + * + * Postal address: + * Advanced Software Production Line, S.L. + * Edificio Alius A, Oficina 102, + * C/ Antonio Suarez Nº 10, + * Alcalá de Henares 28802 Madrid + * Spain + * + * Email address: + * info@aspl.es - http://www.aspl.es/nopoll + */ +#ifndef __NOPOLL_IO_H__ +#define __NOPOLL_IO_H__ + +#include + +BEGIN_C_DECLS + +noPollIoEngine * nopoll_io_get_engine (noPollCtx * ctx, noPollIoEngineType engine_type); + +void nopoll_io_release_engine (noPollIoEngine * engine); + +END_C_DECLS + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_listener.h b/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_listener.h new file mode 100644 index 0000000..4900236 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_listener.h @@ -0,0 +1,80 @@ +/* + * LibNoPoll: A websocket library + * Copyright (C) 2013 Advanced Software Production Line, S.L. + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * You may find a copy of the license under this software is released + * at COPYING file. This is LGPL software: you are welcome to develop + * proprietary applications using this library without any royalty or + * fee but returning back any change, improvement or addition in the + * form of source code, project image, documentation patches, etc. + * + * For commercial support on build Websocket enabled solutions + * contact us: + * + * Postal address: + * Advanced Software Production Line, S.L. + * Edificio Alius A, Oficina 102, + * C/ Antonio Suarez Nº 10, + * Alcalá de Henares 28802 Madrid + * Spain + * + * Email address: + * info@aspl.es - http://www.aspl.es/nopoll + */ +#ifndef __NOPOLL_LISTENER_H__ +#define __NOPOLL_LISTENER_H__ + +#include + +BEGIN_C_DECLS + +NOPOLL_SOCKET nopoll_listener_sock_listen (noPollCtx * ctx, + const char * host, + const char * port); + +noPollConn * nopoll_listener_new (noPollCtx * ctx, + const char * host, + const char * port); + +noPollConn * nopoll_listener_new_opts (noPollCtx * ctx, + noPollConnOpts * opts, + const char * host, + const char * port); + +noPollConn * nopoll_listener_tls_new (noPollCtx * ctx, + const char * host, + const char * port); + +noPollConn * nopoll_listener_tls_new_opts (noPollCtx * ctx, + noPollConnOpts * opts, + const char * host, + const char * port); + +nopoll_bool nopoll_listener_set_certificate (noPollConn * listener, + const char * certificate, + const char * private_key, + const char * chain_file); + +noPollConn * nopoll_listener_from_socket (noPollCtx * ctx, + NOPOLL_SOCKET session); + +NOPOLL_SOCKET nopoll_listener_accept (NOPOLL_SOCKET server_socket); + +END_C_DECLS + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_log.h b/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_log.h new file mode 100644 index 0000000..c8f2c9a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_log.h @@ -0,0 +1,113 @@ +/* + * LibNoPoll: A websocket library + * Copyright (C) 2013 Advanced Software Production Line, S.L. + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * You may find a copy of the license under this software is released + * at COPYING file. This is LGPL software: you are welcome to develop + * proprietary applications using this library without any royalty or + * fee but returning back any change, improvement or addition in the + * form of source code, project image, documentation patches, etc. + * + * For commercial support on build Websocket enabled solutions + * contact us: + * + * Postal address: + * Advanced Software Production Line, S.L. + * Edificio Alius A, Oficina 102, + * C/ Antonio Suarez Nº 10, + * Alcalá de Henares 28802 Madrid + * Spain + * + * Email address: + * info@aspl.es - http://www.aspl.es/nopoll + */ +#ifndef __NOPOLL_LOG_H__ +#define __NOPOLL_LOG_H__ + +#include +#include + +BEGIN_C_DECLS + +/** + * \addtogroup nopoll_log_module + * @{ + */ + +nopoll_bool nopoll_log_is_enabled (noPollCtx * ctx); + +nopoll_bool nopoll_log_color_is_enabled (noPollCtx * ctx); + +void nopoll_log_enable (noPollCtx * ctx, nopoll_bool value); + +void nopoll_log_color_enable (noPollCtx * ctx, nopoll_bool value); + +void nopoll_log_set_handler (noPollCtx * ctx, noPollLogHandler handler, noPollPtr user_data); + +/* include this at this place to load GNU extensions */ +#if defined(__GNUC__) +# ifndef _GNU_SOURCE +# define _GNU_SOURCE +# endif +# define __function_name__ __PRETTY_FUNCTION__ +# define __line__ __LINE__ +# define __file__ __FILE__ +#elif defined(_MSC_VER) +# define __function_name__ __FUNCDNAME__ +# define __line__ __LINE__ +# define __file__ __FILE__ +#else +/* unknown compiler */ +#define __function_name__ "" +#define __line__ 0 +#define __file__ "" +#endif + + +#if defined(SHOW_DEBUG_LOG) +# define nopoll_log(ctx,level,message, ...) do{__nopoll_log(ctx, __function_name__, __file__, __line__, level, message, ##__VA_ARGS__);}while(0) +#else +# if defined(NOPOLL_OS_WIN32) && !( defined (__GNUC__) || _MSC_VER >= 1400) +/* default case where '...' is not supported but log is still + * disabled */ +# define nopoll_log __nopoll_log +# else +# define nopoll_log(ctx, level, message, ...) /* nothing */ +# endif +#endif + +/** + * @internal The following definition allows to find printf like wrong + * argument passing to nopoll_log function. To activate the depuration + * just add the following to local nopoll_config.h file: + * + * #define SHOW_FORMAT_BUGS (1) + */ +#if defined(SHOW_FORMAT_BUGS) +# undef nopoll_log +# define nopoll_log(ctx,level,message, ...) do{printf (message, ##__VA_ARGS__);}while(0) +#endif + +void __nopoll_log (noPollCtx * ctx, const char * function_name, const char * file, int line, noPollDebugLevel level, const char * message, ...); + +/* @} */ + +END_C_DECLS + +#endif + diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_loop.h b/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_loop.h new file mode 100644 index 0000000..245d973 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_loop.h @@ -0,0 +1,52 @@ +/* + * LibNoPoll: A websocket library + * Copyright (C) 2013 Advanced Software Production Line, S.L. + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * You may find a copy of the license under this software is released + * at COPYING file. This is LGPL software: you are welcome to develop + * proprietary applications using this library without any royalty or + * fee but returning back any change, improvement or addition in the + * form of source code, project image, documentation patches, etc. + * + * For commercial support on build Websocket enabled solutions + * contact us: + * + * Postal address: + * Advanced Software Production Line, S.L. + * Edificio Alius A, Oficina 102, + * C/ Antonio Suarez Nº 10, + * Alcalá de Henares 28802 Madrid + * Spain + * + * Email address: + * info@aspl.es - http://www.aspl.es/nopoll + */ +#ifndef __NOPOLL_LOOP_H__ +#define __NOPOLL_LOOP_H__ + +#include + +BEGIN_C_DECLS + +int nopoll_loop_wait (noPollCtx * ctx, long timeout); + +void nopoll_loop_stop (noPollCtx * ctx); + +END_C_DECLS + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_msg.h b/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_msg.h new file mode 100644 index 0000000..74242b5 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_msg.h @@ -0,0 +1,68 @@ +/* + * LibNoPoll: A websocket library + * Copyright (C) 2013 Advanced Software Production Line, S.L. + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * You may find a copy of the license under this software is released + * at COPYING file. This is LGPL software: you are welcome to develop + * proprietary applications using this library without any royalty or + * fee but returning back any change, improvement or addition in the + * form of source code, project image, documentation patches, etc. + * + * For commercial support on build Websocket enabled solutions + * contact us: + * + * Postal address: + * Advanced Software Production Line, S.L. + * Edificio Alius A, Oficina 102, + * C/ Antonio Suarez Nº 10, + * Alcalá de Henares 28802 Madrid + * Spain + * + * Email address: + * info@aspl.es - http://www.aspl.es/nopoll + */ +#ifndef __NOPOLL_MSG_H__ +#define __NOPOLL_MSG_H__ + +#include + +BEGIN_C_DECLS + +const unsigned char * nopoll_msg_get_payload (noPollMsg * msg); + +int nopoll_msg_get_payload_size (noPollMsg * msg); + +noPollMsg * nopoll_msg_new (void); + +nopoll_bool nopoll_msg_ref (noPollMsg * msg); + +int nopoll_msg_ref_count (noPollMsg * msg); + +nopoll_bool nopoll_msg_is_final (noPollMsg * msg); + +nopoll_bool nopoll_msg_is_fragment (noPollMsg * msg); + +noPollOpCode nopoll_msg_opcode (noPollMsg * msg); + +noPollMsg * nopoll_msg_join (noPollMsg * msg, noPollMsg * msg2); + +void nopoll_msg_unref (noPollMsg * msg); + +END_C_DECLS + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_private.h b/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_private.h new file mode 100644 index 0000000..306fb16 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_private.h @@ -0,0 +1,386 @@ +/* + * LibNoPoll: A websocket library + * Copyright (C) 2013 Advanced Software Production Line, S.L. + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * You may find a copy of the license under this software is released + * at COPYING file. This is LGPL software: you are welcome to develop + * proprietary applications using this library without any royalty or + * fee but returning back any change, improvement or addition in the + * form of source code, project image, documentation patches, etc. + * + * For commercial support on build Websocket enabled solutions + * contact us: + * + * Postal address: + * Advanced Software Production Line, S.L. + * Edificio Alius A, Oficina 102, + * C/ Antonio Suarez Nº 10, + * Alcalá de Henares 28802 Madrid + * Spain + * + * Email address: + * info@aspl.es - http://www.aspl.es/nopoll + */ +#ifndef __NOPOLL_PRIVATE_H__ +#define __NOPOLL_PRIVATE_H__ + +#include "ssl/ssl_compat-1.0.h" +#include + +typedef struct _noPollCertificate { + + char * serverName; + char * certificateFile; + char * privateKey; + char * optionalChainFile; + +} noPollCertificate; + +struct _noPollCtx { + /** + * @internal Controls logs output.. + */ + /* context reference counting */ + int refs; + + /* console log */ + nopoll_bool not_executed; + nopoll_bool debug_enabled; + + /* colored log */ + nopoll_bool not_executed_color; + nopoll_bool debug_color_enabled; + + nopoll_bool keep_looping; + + /** + * @internal noPollConn connection timeout. + */ + long conn_connect_std_timeout; + + /** + * @internal Default listener connection backlog + */ + int backlog; + + /** + * @internal Currently selected io engine on this context. + */ + noPollIoEngine * io_engine; + + /** + * @internal Connection array list and its length. + */ + int conn_id; + noPollConn ** conn_list; + int conn_length; + /** + * @internal Number of connections registered on this context. + */ + int conn_num; + + /** + * @internal Reference to defined on accept handling. + */ + noPollActionHandler on_accept; + noPollPtr on_accept_data; + + /** + * @internal Reference to defined on ready handling. + */ + noPollActionHandler on_ready; + noPollPtr on_ready_data; + + /** + * @internal Reference to defined on open handling. + */ + noPollActionHandler on_open; + noPollPtr on_open_data; + + /** + * @internal Reference to the defined on message handling. + */ + noPollOnMessageHandler on_msg; + noPollPtr on_msg_data; + + /** + * @internal Basic fake support for protocol version, by + * default: 13, due to RFC6455 standard + */ + int protocol_version; + + /** + * @internal Certificates added.. + */ + noPollCertificate * certificates; + int certificates_length; + + /* mutex */ + noPollPtr ref_mutex; + + /* log handling */ + noPollLogHandler log_handler; + noPollPtr log_user_data; + + /* context creator */ + noPollSslContextCreator context_creator; + noPollPtr context_creator_data; + + /* SSL postcheck */ + noPollSslPostCheck post_ssl_check; + noPollPtr post_ssl_check_data; +}; + +struct _noPollConn { + /** + * @internal Connection id. + */ + int id; + + /** + * @internal The context associated to this connection. + */ + noPollCtx * ctx; + + /** + * @internal This is the actual socket handler associated to + * the noPollConn object. + */ + NOPOLL_SOCKET session; + /** + * @internal Flag to signal this connection has finished its + * handshake. + */ + nopoll_bool handshake_ok; + + /** + * @internal Current connection receive function. + */ + noPollRead receive; + + /** + * @internal Current connection receive function. + */ + noPollRead sends; + + /** + * @internal The connection role. + */ + noPollRole role; + + /** + * @internal Conection host ip location (connecting or listening). + */ + char * host; + + /** + * @internal Connection port location (connecting or + * listening). + */ + char * port; + + /** + * @internal Host name requested on the connection. + */ + char * host_name; + /** + * @internal Origin requested on the connection. + */ + char * origin; + + /** + * @internal reference to the get url. + */ + char * get_url; + + /** + * @internal Reference to protocols requested to be opened on + * this connection. + */ + char * protocols; + /* @internal reference to the protocol that was replied by the server */ + char * accepted_protocol; + + /* close status and reason */ + int peer_close_status; + char * peer_close_reason; + + /** + * @internal Reference to the defined on message handling. + */ + noPollOnMessageHandler on_msg; + noPollPtr on_msg_data; + + /** + * @internal Reference to defined on ready handling. + */ + noPollActionHandler on_ready; + noPollPtr on_ready_data; + + /** + * @internal Reference to the defined on close handling. + */ + noPollOnCloseHandler on_close; + noPollPtr on_close_data; + + /* reference to the handshake */ + noPollHandShake * handshake; + + /* reference to a buffer with pending content */ + char * pending_line; + + /** + * @internal connection reference counting. + */ + int refs; + + /** + * @internal References to pending content to be read + */ + noPollMsg * pending_msg; + long int pending_diff; + long int pending_desp; + + /** + * @internal Flag to handle TLS support upon connection + * reception. + */ + nopoll_bool tls_on; + /** + * @internal Flag that indicates that the provided session + * must call to accept the TLS session before proceeding. + */ + nopoll_bool pending_ssl_accept; + + /* SSL support */ + SSL_CTX * ssl_ctx; + SSL * ssl; + + /* certificates */ + char * certificate; + char * private_key; + char * chain_certificate; + + /* pending buffer */ + char pending_buf[100]; + int pending_buf_bytes; + + /** + * @internal Support for an user defined pointer. + */ + noPollPtr hook; + + /** + * @internal Mutex + */ + noPollPtr ref_mutex; + + /** + * @internal Variable to track pending bytes from previous + * read that must be completed. + */ + noPollMsg * previous_msg; + /* allows to track if previous message was a fragment to flag + * next message, even having FIN enabled as a fragment. */ + nopoll_bool previous_was_fragment; + + char * pending_write; + int pending_write_bytes; + + /** + * @internal Internal reference to the connection options. + */ + noPollConnOpts * opts; + + /** + * @internal Reference to the listener in the case this is a + * connection that was created due to a listener running. + */ + noPollConn * listener; +}; + +struct _noPollIoEngine { + noPollPtr io_object; + noPollCtx * ctx; + noPollIoMechCreate create; + noPollIoMechDestroy destroy; + noPollIoMechClear clear; + noPollIoMechWait wait; + noPollIoMechAddTo addto; + noPollIoMechIsSet isset; +}; + +struct _noPollMsg { + nopoll_bool has_fin; + short op_code; + nopoll_bool is_masked; + + noPollPtr payload; + long int payload_size; + + int refs; + noPollPtr ref_mutex; + + char mask[4]; + int remain_bytes; + + nopoll_bool is_fragment; + int unmask_desp; +}; + +struct _noPollHandshake { + /** + * @internal Reference to the to the GET url HTTP/1.1 header + * part. + */ + nopoll_bool upgrade_websocket; + nopoll_bool connection_upgrade; + nopoll_bool received_101; + char * websocket_key; + char * websocket_version; + char * websocket_accept; + char * expected_accept; + + /* reference to cookie header */ + char * cookie; +}; + +struct _noPollConnOpts { + /* If the connection options object should be reused across calls */ + nopoll_bool reuse; + + /* mutex */ + noPollPtr mutex; + int refs; + + /* What ssl protocol should be used */ + noPollSslProtocol ssl_protocol; + + /* SSL options */ + char * certificate; + char * private_key; + char * chain_certificate; + char * ca_certificate; + + nopoll_bool disable_ssl_verify; + + /* cookie support */ + char * cookie; +}; + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_win32.h b/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_win32.h new file mode 100644 index 0000000..5b1d589 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/nopoll/nopoll_win32.h @@ -0,0 +1,66 @@ +/* + * LibNoPoll: A websocket library + * Copyright (C) 2013 Advanced Software Production Line, S.L. + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * You may find a copy of the license under this software is released + * at COPYING file. This is LGPL software: you are welcome to develop + * proprietary applications using this library without any royalty or + * fee but returning back any change, improvement or addition in the + * form of source code, project image, documentation patches, etc. + * + * For commercial support on build Websocket enabled solutions + * contact us: + * + * Postal address: + * Advanced Software Production Line, S.L. + * Edificio Alius A, Oficina 102, + * C/ Antonio Suarez Nº 10, + * Alcalá de Henares 28802 Madrid + * Spain + * + * Email address: + * info@aspl.es - http://www.aspl.es/nopoll + */ + +#ifndef __NOPOLL_WIN32_H__ +#define __NOPOLL_WIN32_H__ + +#include + +BEGIN_C_DECLS + +int nopoll_win32_init (noPollCtx * ctx); + +int nopoll_win32_nonblocking_enable (NOPOLL_SOCKET socket); + +int nopoll_win32_blocking_enable (NOPOLL_SOCKET socket); + +/* gettimeofday support on windows */ +int nopoll_win32_gettimeofday (struct timeval *tv, noPollPtr notUsed); + +BOOL APIENTRY DllMain (HINSTANCE hInst, + DWORD reason, + LPVOID reserved); + +#if !defined(EINPROGRESS) +#define EINPROGRESS (WSAEINPROGRESS) +#endif + +END_C_DECLS + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl3.h b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl3.h new file mode 100644 index 0000000..007b392 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl3.h @@ -0,0 +1,44 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#ifndef _SSL3_H_ +#define _SSL3_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +# define SSL3_AD_CLOSE_NOTIFY 0 +# define SSL3_AD_UNEXPECTED_MESSAGE 10/* fatal */ +# define SSL3_AD_BAD_RECORD_MAC 20/* fatal */ +# define SSL3_AD_DECOMPRESSION_FAILURE 30/* fatal */ +# define SSL3_AD_HANDSHAKE_FAILURE 40/* fatal */ +# define SSL3_AD_NO_CERTIFICATE 41 +# define SSL3_AD_BAD_CERTIFICATE 42 +# define SSL3_AD_UNSUPPORTED_CERTIFICATE 43 +# define SSL3_AD_CERTIFICATE_REVOKED 44 +# define SSL3_AD_CERTIFICATE_EXPIRED 45 +# define SSL3_AD_CERTIFICATE_UNKNOWN 46 +# define SSL3_AD_ILLEGAL_PARAMETER 47/* fatal */ + +# define SSL3_AL_WARNING 1 +# define SSL3_AL_FATAL 2 + +#define SSL3_VERSION 0x0300 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_cert.h b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_cert.h new file mode 100644 index 0000000..86cf31a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_cert.h @@ -0,0 +1,55 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#ifndef _SSL_CERT_H_ +#define _SSL_CERT_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "ssl_types.h" + +/** + * @brief create a certification object include private key object according to input certification + * + * @param ic - input certification point + * + * @return certification object point + */ +CERT *__ssl_cert_new(CERT *ic); + +/** + * @brief create a certification object include private key object + * + * @param none + * + * @return certification object point + */ +CERT* ssl_cert_new(void); + +/** + * @brief free a certification object + * + * @param cert - certification object point + * + * @return none + */ +void ssl_cert_free(CERT *cert); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_code.h b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_code.h new file mode 100644 index 0000000..80fdbb2 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_code.h @@ -0,0 +1,124 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#ifndef _SSL_CODE_H_ +#define _SSL_CODE_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "ssl3.h" +#include "tls1.h" +#include "x509_vfy.h" + +/* Used in SSL_set_shutdown()/SSL_get_shutdown(); */ +# define SSL_SENT_SHUTDOWN 1 +# define SSL_RECEIVED_SHUTDOWN 2 + +# define SSL_VERIFY_NONE 0x00 +# define SSL_VERIFY_PEER 0x01 +# define SSL_VERIFY_FAIL_IF_NO_PEER_CERT 0x02 +# define SSL_VERIFY_CLIENT_ONCE 0x04 + +/* + * The following 3 states are kept in ssl->rlayer.rstate when reads fail, you + * should not need these + */ +# define SSL_ST_READ_HEADER 0xF0 +# define SSL_ST_READ_BODY 0xF1 +# define SSL_ST_READ_DONE 0xF2 + +# define SSL_NOTHING 1 +# define SSL_WRITING 2 +# define SSL_READING 3 +# define SSL_X509_LOOKUP 4 +# define SSL_ASYNC_PAUSED 5 +# define SSL_ASYNC_NO_JOBS 6 + + +# define SSL_ERROR_NONE 0 +# define SSL_ERROR_SSL 1 +# define SSL_ERROR_WANT_READ 2 +# define SSL_ERROR_WANT_WRITE 3 +# define SSL_ERROR_WANT_X509_LOOKUP 4 +# define SSL_ERROR_SYSCALL 5/* look at error stack/return value/errno */ +# define SSL_ERROR_ZERO_RETURN 6 +# define SSL_ERROR_WANT_CONNECT 7 +# define SSL_ERROR_WANT_ACCEPT 8 +# define SSL_ERROR_WANT_ASYNC 9 +# define SSL_ERROR_WANT_ASYNC_JOB 10 + +/* Message flow states */ +typedef enum { + /* No handshake in progress */ + MSG_FLOW_UNINITED, + /* A permanent error with this connection */ + MSG_FLOW_ERROR, + /* We are about to renegotiate */ + MSG_FLOW_RENEGOTIATE, + /* We are reading messages */ + MSG_FLOW_READING, + /* We are writing messages */ + MSG_FLOW_WRITING, + /* Handshake has finished */ + MSG_FLOW_FINISHED +} MSG_FLOW_STATE; + +/* SSL subsystem states */ +typedef enum { + TLS_ST_BEFORE, + TLS_ST_OK, + DTLS_ST_CR_HELLO_VERIFY_REQUEST, + TLS_ST_CR_SRVR_HELLO, + TLS_ST_CR_CERT, + TLS_ST_CR_CERT_STATUS, + TLS_ST_CR_KEY_EXCH, + TLS_ST_CR_CERT_REQ, + TLS_ST_CR_SRVR_DONE, + TLS_ST_CR_SESSION_TICKET, + TLS_ST_CR_CHANGE, + TLS_ST_CR_FINISHED, + TLS_ST_CW_CLNT_HELLO, + TLS_ST_CW_CERT, + TLS_ST_CW_KEY_EXCH, + TLS_ST_CW_CERT_VRFY, + TLS_ST_CW_CHANGE, + TLS_ST_CW_NEXT_PROTO, + TLS_ST_CW_FINISHED, + TLS_ST_SW_HELLO_REQ, + TLS_ST_SR_CLNT_HELLO, + DTLS_ST_SW_HELLO_VERIFY_REQUEST, + TLS_ST_SW_SRVR_HELLO, + TLS_ST_SW_CERT, + TLS_ST_SW_KEY_EXCH, + TLS_ST_SW_CERT_REQ, + TLS_ST_SW_SRVR_DONE, + TLS_ST_SR_CERT, + TLS_ST_SR_KEY_EXCH, + TLS_ST_SR_CERT_VRFY, + TLS_ST_SR_NEXT_PROTO, + TLS_ST_SR_CHANGE, + TLS_ST_SR_FINISHED, + TLS_ST_SW_SESSION_TICKET, + TLS_ST_SW_CERT_STATUS, + TLS_ST_SW_CHANGE, + TLS_ST_SW_FINISHED +} OSSL_HANDSHAKE_STATE; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_dbg.h b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_dbg.h new file mode 100644 index 0000000..12ba25f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_dbg.h @@ -0,0 +1,191 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#ifndef _SSL_DEBUG_H_ +#define _SSL_DEBUG_H_ + +#include "platform/ssl_opt.h" +#include "platform/ssl_port.h" + +#ifdef __cplusplus + extern "C" { +#endif + +#ifdef CONFIG_OPENSSL_DEBUG_LEVEL + #define SSL_DEBUG_LEVEL CONFIG_OPENSSL_DEBUG_LEVEL +#else + #define SSL_DEBUG_LEVEL 0 +#endif + +#define SSL_DEBUG_ON (SSL_DEBUG_LEVEL + 1) +#define SSL_DEBUG_OFF (SSL_DEBUG_LEVEL - 1) + +#ifdef CONFIG_OPENSSL_DEBUG + #ifndef SSL_DEBUG_LOG + #error "SSL_DEBUG_LOG is not defined" + #endif + + #ifndef SSL_DEBUG_FL + #define SSL_DEBUG_FL "\n" + #endif + + #define SSL_SHOW_LOCATION() \ + SSL_DEBUG_LOG("SSL assert : %s %d\n", \ + __FILE__, __LINE__) + + #define SSL_DEBUG(level, fmt, ...) \ + { \ + if (level > SSL_DEBUG_LEVEL) { \ + SSL_DEBUG_LOG(fmt SSL_DEBUG_FL, ##__VA_ARGS__); \ + } \ + } +#else /* CONFIG_OPENSSL_DEBUG */ + #define SSL_SHOW_LOCATION() + + #define SSL_DEBUG(level, fmt, ...) +#endif /* CONFIG_OPENSSL_DEBUG */ + +/** + * OpenSSL assert function + * + * if select "CONFIG_OPENSSL_ASSERT_DEBUG", SSL_ASSERT* will show error file name and line + * if select "CONFIG_OPENSSL_ASSERT_EXIT", SSL_ASSERT* will just return error code. + * if select "CONFIG_OPENSSL_ASSERT_DEBUG_EXIT" SSL_ASSERT* will show error file name and line, + * then return error code. + * if select "CONFIG_OPENSSL_ASSERT_DEBUG_BLOCK", SSL_ASSERT* will show error file name and line, + * then block here with "while (1)" + * + * SSL_ASSERT1 may will return "-1", so function's return argument is integer. + * SSL_ASSERT2 may will return "NULL", so function's return argument is a point. + * SSL_ASSERT2 may will return nothing, so function's return argument is "void". + */ +#if defined(CONFIG_OPENSSL_ASSERT_DEBUG) + #define SSL_ASSERT1(s) \ + { \ + if (!(s)) { \ + SSL_SHOW_LOCATION(); \ + } \ + } + + #define SSL_ASSERT2(s) \ + { \ + if (!(s)) { \ + SSL_SHOW_LOCATION(); \ + } \ + } + + #define SSL_ASSERT3(s) \ + { \ + if (!(s)) { \ + SSL_SHOW_LOCATION(); \ + } \ + } +#elif defined(CONFIG_OPENSSL_ASSERT_EXIT) + #define SSL_ASSERT1(s) \ + { \ + if (!(s)) { \ + return -1; \ + } \ + } + + #define SSL_ASSERT2(s) \ + { \ + if (!(s)) { \ + return NULL; \ + } \ + } + + #define SSL_ASSERT3(s) \ + { \ + if (!(s)) { \ + return ; \ + } \ + } +#elif defined(CONFIG_OPENSSL_ASSERT_DEBUG_EXIT) + #define SSL_ASSERT1(s) \ + { \ + if (!(s)) { \ + SSL_SHOW_LOCATION(); \ + return -1; \ + } \ + } + + #define SSL_ASSERT2(s) \ + { \ + if (!(s)) { \ + SSL_SHOW_LOCATION(); \ + return NULL; \ + } \ + } + + #define SSL_ASSERT3(s) \ + { \ + if (!(s)) { \ + SSL_SHOW_LOCATION(); \ + return ; \ + } \ + } +#elif defined(CONFIG_OPENSSL_ASSERT_DEBUG_BLOCK) + #define SSL_ASSERT1(s) \ + { \ + if (!(s)) { \ + SSL_SHOW_LOCATION(); \ + while (1); \ + } \ + } + + #define SSL_ASSERT2(s) \ + { \ + if (!(s)) { \ + SSL_SHOW_LOCATION(); \ + while (1); \ + } \ + } + + #define SSL_ASSERT3(s) \ + { \ + if (!(s)) { \ + SSL_SHOW_LOCATION(); \ + while (1); \ + } \ + } +#else + #define SSL_ASSERT1(s) + #define SSL_ASSERT2(s) + #define SSL_ASSERT3(s) +#endif + +#define SSL_PLATFORM_DEBUG_LEVEL SSL_DEBUG_OFF +#define SSL_PLATFORM_ERROR_LEVEL SSL_DEBUG_ON + +#define SSL_CERT_DEBUG_LEVEL SSL_DEBUG_OFF +#define SSL_CERT_ERROR_LEVEL SSL_DEBUG_ON + +#define SSL_PKEY_DEBUG_LEVEL SSL_DEBUG_OFF +#define SSL_PKEY_ERROR_LEVEL SSL_DEBUG_ON + +#define SSL_X509_DEBUG_LEVEL SSL_DEBUG_OFF +#define SSL_X509_ERROR_LEVEL SSL_DEBUG_ON + +#define SSL_LIB_DEBUG_LEVEL SSL_DEBUG_OFF +#define SSL_LIB_ERROR_LEVEL SSL_DEBUG_ON + +#define SSL_STACK_DEBUG_LEVEL SSL_DEBUG_OFF +#define SSL_STACK_ERROR_LEVEL SSL_DEBUG_ON + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_lib.h b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_lib.h new file mode 100644 index 0000000..bf7de22 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_lib.h @@ -0,0 +1,28 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#ifndef _SSL_LIB_H_ +#define _SSL_LIB_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "ssl_types.h" + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_methods.h b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_methods.h new file mode 100644 index 0000000..cd2f8c0 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_methods.h @@ -0,0 +1,121 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#ifndef _SSL_METHODS_H_ +#define _SSL_METHODS_H_ + +#include "ssl_types.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/** + * TLS method function implement + */ +#define IMPLEMENT_TLS_METHOD_FUNC(func_name, \ + new, free, \ + handshake, shutdown, clear, \ + read, send, pending, \ + set_fd, get_fd, \ + set_bufflen, \ + get_verify_result, \ + get_state) \ + static const SSL_METHOD_FUNC func_name LOCAL_ATRR = { \ + new, \ + free, \ + handshake, \ + shutdown, \ + clear, \ + read, \ + send, \ + pending, \ + set_fd, \ + get_fd, \ + set_bufflen, \ + get_verify_result, \ + get_state \ + }; + +#define IMPLEMENT_TLS_METHOD(ver, mode, fun, func_name) \ + const SSL_METHOD* func_name(void) { \ + static const SSL_METHOD func_name##_data LOCAL_ATRR = { \ + ver, \ + mode, \ + &(fun), \ + }; \ + return &func_name##_data; \ + } + +#define IMPLEMENT_SSL_METHOD(ver, mode, fun, func_name) \ + const SSL_METHOD* func_name(void) { \ + static const SSL_METHOD func_name##_data LOCAL_ATRR = { \ + ver, \ + mode, \ + &(fun), \ + }; \ + return &func_name##_data; \ + } + +#define IMPLEMENT_X509_METHOD(func_name, \ + new, \ + free, \ + load, \ + show_info) \ + const X509_METHOD* func_name(void) { \ + static const X509_METHOD func_name##_data LOCAL_ATRR = { \ + new, \ + free, \ + load, \ + show_info \ + }; \ + return &func_name##_data; \ + } + +#define IMPLEMENT_PKEY_METHOD(func_name, \ + new, \ + free, \ + load) \ + const PKEY_METHOD* func_name(void) { \ + static const PKEY_METHOD func_name##_data LOCAL_ATRR = { \ + new, \ + free, \ + load \ + }; \ + return &func_name##_data; \ + } + +/** + * @brief get X509 object method + * + * @param none + * + * @return X509 object method point + */ +const X509_METHOD* X509_method(void); + +/** + * @brief get private key object method + * + * @param none + * + * @return private key object method point + */ +const PKEY_METHOD* EVP_PKEY_method(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_pkey.h b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_pkey.h new file mode 100644 index 0000000..e790fcc --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_pkey.h @@ -0,0 +1,86 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#ifndef _SSL_PKEY_H_ +#define _SSL_PKEY_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "ssl_types.h" + +/** + * @brief create a private key object according to input private key + * + * @param ipk - input private key point + * + * @return new private key object point + */ +EVP_PKEY* __EVP_PKEY_new(EVP_PKEY *ipk); + +/** + * @brief create a private key object + * + * @param none + * + * @return private key object point + */ +EVP_PKEY* EVP_PKEY_new(void); + +/** + * @brief load a character key context into system context. If '*a' is pointed to the + * private key, then load key into it. Or create a new private key object + * + * @param type - private key type + * @param a - a point pointed to a private key point + * @param pp - a point pointed to the key context memory point + * @param length - key bytes + * + * @return private key object point + */ +EVP_PKEY* d2i_PrivateKey(int type, + EVP_PKEY **a, + const unsigned char **pp, + long length); + +/** + * @brief free a private key object + * + * @param pkey - private key object point + * + * @return none + */ +void EVP_PKEY_free(EVP_PKEY *x); + +/** + * @brief load private key into the SSL + * + * @param type - private key type + * @param ssl - SSL point + * @param len - data bytes + * @param d - data point + * + * @return result + * 0 : failed + * 1 : OK + */ + int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, const unsigned char *d, long len); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_stack.h b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_stack.h new file mode 100644 index 0000000..7a7051a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_stack.h @@ -0,0 +1,52 @@ +#ifndef _SSL_STACK_H_ +#define _SSL_STACK_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "ssl_types.h" + +#define STACK_OF(type) struct stack_st_##type + +#define SKM_DEFINE_STACK_OF(t1, t2, t3) \ + STACK_OF(t1); \ + static ossl_inline STACK_OF(t1) *sk_##t1##_new_null(void) \ + { \ + return (STACK_OF(t1) *)OPENSSL_sk_new_null(); \ + } \ + +#define DEFINE_STACK_OF(t) SKM_DEFINE_STACK_OF(t, t, t) + +/** + * @brief create a openssl stack object + * + * @param c - stack function + * + * @return openssl stack object point + */ +OPENSSL_STACK* OPENSSL_sk_new(OPENSSL_sk_compfunc c); + +/** + * @brief create a NULL function openssl stack object + * + * @param none + * + * @return openssl stack object point + */ +OPENSSL_STACK *OPENSSL_sk_new_null(void); + +/** + * @brief free openssl stack object + * + * @param openssl stack object point + * + * @return none + */ +void OPENSSL_sk_free(OPENSSL_STACK *stack); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_types.h b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_types.h new file mode 100644 index 0000000..5aaee94 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_types.h @@ -0,0 +1,288 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#ifndef _SSL_TYPES_H_ +#define _SSL_TYPES_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "ssl_code.h" + +typedef void SSL_CIPHER; + +typedef void X509_STORE_CTX; +typedef void X509_STORE; + +typedef void RSA; + +typedef void STACK; +typedef void BIO; + +#define ossl_inline inline + +#define SSL_METHOD_CALL(f, s, ...) s->method->func->ssl_##f(s, ##__VA_ARGS__) +#define X509_METHOD_CALL(f, x, ...) x->method->x509_##f(x, ##__VA_ARGS__) +#define EVP_PKEY_METHOD_CALL(f, k, ...) k->method->pkey_##f(k, ##__VA_ARGS__) + +typedef int (*OPENSSL_sk_compfunc)(const void *, const void *); + +struct stack_st; +typedef struct stack_st OPENSSL_STACK; + +struct ssl_method_st; +typedef struct ssl_method_st SSL_METHOD; + +struct ssl_method_func_st; +typedef struct ssl_method_func_st SSL_METHOD_FUNC; + +struct record_layer_st; +typedef struct record_layer_st RECORD_LAYER; + +struct ossl_statem_st; +typedef struct ossl_statem_st OSSL_STATEM; + +struct ssl_session_st; +typedef struct ssl_session_st SSL_SESSION; + +struct ssl_ctx_st; +typedef struct ssl_ctx_st SSL_CTX; + +struct ssl_st; +typedef struct ssl_st SSL; + +struct cert_st; +typedef struct cert_st CERT; + +struct x509_st; +typedef struct x509_st X509; + +struct X509_VERIFY_PARAM_st; +typedef struct X509_VERIFY_PARAM_st X509_VERIFY_PARAM; + +struct evp_pkey_st; +typedef struct evp_pkey_st EVP_PKEY; + +struct x509_method_st; +typedef struct x509_method_st X509_METHOD; + +struct pkey_method_st; +typedef struct pkey_method_st PKEY_METHOD; + +struct stack_st { + + char **data; + + int num_alloc; + + OPENSSL_sk_compfunc c; +}; + +struct evp_pkey_st { + + void *pkey_pm; + + const PKEY_METHOD *method; +}; + +struct x509_st { + + /* X509 certification platform private point */ + void *x509_pm; + + const X509_METHOD *method; +}; + +struct cert_st { + + int sec_level; + + X509 *x509; + + EVP_PKEY *pkey; + +}; + +struct ossl_statem_st { + + MSG_FLOW_STATE state; + + int hand_state; +}; + +struct record_layer_st { + + int rstate; + + int read_ahead; +}; + +struct ssl_session_st { + + long timeout; + + long time; + + X509 *peer; +}; + +struct X509_VERIFY_PARAM_st { + + int depth; + +}; + +struct ssl_ctx_st +{ + int version; + + int references; + + unsigned long options; + + #if 0 + struct alpn_protocols alpn_protocol; + #endif + + const SSL_METHOD *method; + + CERT *cert; + + X509 *client_CA; + + int verify_mode; + + int (*default_verify_callback) (int ok, X509_STORE_CTX *ctx); + + long session_timeout; + + int read_ahead; + + int read_buffer_len; + + X509_VERIFY_PARAM param; +}; + +struct ssl_st +{ + /* protocol version(one of SSL3.0, TLS1.0, etc.) */ + int version; + + unsigned long options; + + /* shut things down(0x01 : sent, 0x02 : received) */ + int shutdown; + + CERT *cert; + + X509 *client_CA; + + SSL_CTX *ctx; + + const SSL_METHOD *method; + + RECORD_LAYER rlayer; + + /* where we are */ + OSSL_STATEM statem; + + SSL_SESSION *session; + + int verify_mode; + + int (*verify_callback) (int ok, X509_STORE_CTX *ctx); + + int rwstate; + + long verify_result; + + X509_VERIFY_PARAM param; + + int err; + + void (*info_callback) (const SSL *ssl, int type, int val); + + /* SSL low-level system arch point */ + void *ssl_pm; +}; + +struct ssl_method_st { + /* protocol version(one of SSL3.0, TLS1.0, etc.) */ + int version; + + /* SSL mode(client(0) , server(1), not known(-1)) */ + int endpoint; + + const SSL_METHOD_FUNC *func; +}; + +struct ssl_method_func_st { + + int (*ssl_new)(SSL *ssl); + + void (*ssl_free)(SSL *ssl); + + int (*ssl_handshake)(SSL *ssl); + + int (*ssl_shutdown)(SSL *ssl); + + int (*ssl_clear)(SSL *ssl); + + int (*ssl_read)(SSL *ssl, void *buffer, int len); + + int (*ssl_send)(SSL *ssl, const void *buffer, int len); + + int (*ssl_pending)(const SSL *ssl); + + void (*ssl_set_fd)(SSL *ssl, int fd, int mode); + + int (*ssl_get_fd)(const SSL *ssl, int mode); + + void (*ssl_set_bufflen)(SSL *ssl, int len); + + long (*ssl_get_verify_result)(const SSL *ssl); + + OSSL_HANDSHAKE_STATE (*ssl_get_state)(const SSL *ssl); +}; + +struct x509_method_st { + + int (*x509_new)(X509 *x, X509 *m_x); + + void (*x509_free)(X509 *x); + + int (*x509_load)(X509 *x, const unsigned char *buf, int len); + + int (*x509_show_info)(X509 *x); +}; + +struct pkey_method_st { + + int (*pkey_new)(EVP_PKEY *pkey, EVP_PKEY *m_pkey); + + void (*pkey_free)(EVP_PKEY *pkey); + + int (*pkey_load)(EVP_PKEY *pkey, const unsigned char *buf, int len); +}; + +typedef int (*next_proto_cb)(SSL *ssl, unsigned char **out, + unsigned char *outlen, const unsigned char *in, + unsigned int inlen, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_x509.h b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_x509.h new file mode 100644 index 0000000..840fbf1 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/ssl_x509.h @@ -0,0 +1,108 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#ifndef _SSL_X509_H_ +#define _SSL_X509_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "ssl_types.h" +#include "ssl_stack.h" + +DEFINE_STACK_OF(X509_NAME) + +/** + * @brief create a X509 certification object according to input X509 certification + * + * @param ix - input X509 certification point + * + * @return new X509 certification object point + */ +X509* __X509_new(X509 *ix); + +/** + * @brief create a X509 certification object + * + * @param none + * + * @return X509 certification object point + */ +X509* X509_new(void); + +/** + * @brief load a character certification context into system context. If '*cert' is pointed to the + * certification, then load certification into it. Or create a new X509 certification object + * + * @param cert - a point pointed to X509 certification + * @param buffer - a point pointed to the certification context memory point + * @param length - certification bytes + * + * @return X509 certification object point + */ +X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len); + +/** + * @brief free a X509 certification object + * + * @param x - X509 certification object point + * + * @return none + */ +void X509_free(X509 *x); + +/** + * @brief set SSL context client CA certification + * + * @param ctx - SSL context point + * @param x - X509 certification point + * + * @return result + * 0 : failed + * 1 : OK + */ +int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x); + +/** + * @brief add CA client certification into the SSL + * + * @param ssl - SSL point + * @param x - X509 certification point + * + * @return result + * 0 : failed + * 1 : OK + */ +int SSL_add_client_CA(SSL *ssl, X509 *x); + +/** + * @brief load certification into the SSL + * + * @param ssl - SSL point + * @param len - data bytes + * @param d - data point + * + * @return result + * 0 : failed + * 1 : OK + * + */ +int SSL_use_certificate_ASN1(SSL *ssl, int len, const unsigned char *d); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/tls1.h b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/tls1.h new file mode 100644 index 0000000..a9da53e --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/tls1.h @@ -0,0 +1,55 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#ifndef _TLS1_H_ +#define _TLS1_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +# define TLS1_AD_DECRYPTION_FAILED 21 +# define TLS1_AD_RECORD_OVERFLOW 22 +# define TLS1_AD_UNKNOWN_CA 48/* fatal */ +# define TLS1_AD_ACCESS_DENIED 49/* fatal */ +# define TLS1_AD_DECODE_ERROR 50/* fatal */ +# define TLS1_AD_DECRYPT_ERROR 51 +# define TLS1_AD_EXPORT_RESTRICTION 60/* fatal */ +# define TLS1_AD_PROTOCOL_VERSION 70/* fatal */ +# define TLS1_AD_INSUFFICIENT_SECURITY 71/* fatal */ +# define TLS1_AD_INTERNAL_ERROR 80/* fatal */ +# define TLS1_AD_INAPPROPRIATE_FALLBACK 86/* fatal */ +# define TLS1_AD_USER_CANCELLED 90 +# define TLS1_AD_NO_RENEGOTIATION 100 +/* codes 110-114 are from RFC3546 */ +# define TLS1_AD_UNSUPPORTED_EXTENSION 110 +# define TLS1_AD_CERTIFICATE_UNOBTAINABLE 111 +# define TLS1_AD_UNRECOGNIZED_NAME 112 +# define TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE 113 +# define TLS1_AD_BAD_CERTIFICATE_HASH_VALUE 114 +# define TLS1_AD_UNKNOWN_PSK_IDENTITY 115/* fatal */ +# define TLS1_AD_NO_APPLICATION_PROTOCOL 120 /* fatal */ + +/* Special value for method supporting multiple versions */ +#define TLS_ANY_VERSION 0x10000 + +#define TLS1_VERSION 0x0301 +#define TLS1_1_VERSION 0x0302 +#define TLS1_2_VERSION 0x0303 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/x509_vfy.h b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/x509_vfy.h new file mode 100644 index 0000000..d5b0d1a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/internal/x509_vfy.h @@ -0,0 +1,111 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#ifndef _X509_VFY_H_ +#define _X509_VFY_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#define X509_V_OK 0 +#define X509_V_ERR_UNSPECIFIED 1 +#define X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT 2 +#define X509_V_ERR_UNABLE_TO_GET_CRL 3 +#define X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE 4 +#define X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE 5 +#define X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY 6 +#define X509_V_ERR_CERT_SIGNATURE_FAILURE 7 +#define X509_V_ERR_CRL_SIGNATURE_FAILURE 8 +#define X509_V_ERR_CERT_NOT_YET_VALID 9 +#define X509_V_ERR_CERT_HAS_EXPIRED 10 +#define X509_V_ERR_CRL_NOT_YET_VALID 11 +#define X509_V_ERR_CRL_HAS_EXPIRED 12 +#define X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD 13 +#define X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD 14 +#define X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD 15 +#define X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD 16 +#define X509_V_ERR_OUT_OF_MEM 17 +#define X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT 18 +#define X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN 19 +#define X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY 20 +#define X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE 21 +#define X509_V_ERR_CERT_CHAIN_TOO_LONG 22 +#define X509_V_ERR_CERT_REVOKED 23 +#define X509_V_ERR_INVALID_CA 24 +#define X509_V_ERR_PATH_LENGTH_EXCEEDED 25 +#define X509_V_ERR_INVALID_PURPOSE 26 +#define X509_V_ERR_CERT_UNTRUSTED 27 +#define X509_V_ERR_CERT_REJECTED 28 +/* These are 'informational' when looking for issuer cert */ +#define X509_V_ERR_SUBJECT_ISSUER_MISMATCH 29 +#define X509_V_ERR_AKID_SKID_MISMATCH 30 +#define X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH 31 +#define X509_V_ERR_KEYUSAGE_NO_CERTSIGN 32 +#define X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER 33 +#define X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION 34 +#define X509_V_ERR_KEYUSAGE_NO_CRL_SIGN 35 +#define X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION 36 +#define X509_V_ERR_INVALID_NON_CA 37 +#define X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED 38 +#define X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE 39 +#define X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED 40 +#define X509_V_ERR_INVALID_EXTENSION 41 +#define X509_V_ERR_INVALID_POLICY_EXTENSION 42 +#define X509_V_ERR_NO_EXPLICIT_POLICY 43 +#define X509_V_ERR_DIFFERENT_CRL_SCOPE 44 +#define X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE 45 +#define X509_V_ERR_UNNESTED_RESOURCE 46 +#define X509_V_ERR_PERMITTED_VIOLATION 47 +#define X509_V_ERR_EXCLUDED_VIOLATION 48 +#define X509_V_ERR_SUBTREE_MINMAX 49 +/* The application is not happy */ +#define X509_V_ERR_APPLICATION_VERIFICATION 50 +#define X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE 51 +#define X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX 52 +#define X509_V_ERR_UNSUPPORTED_NAME_SYNTAX 53 +#define X509_V_ERR_CRL_PATH_VALIDATION_ERROR 54 +/* Another issuer check debug option */ +#define X509_V_ERR_PATH_LOOP 55 +/* Suite B mode algorithm violation */ +#define X509_V_ERR_SUITE_B_INVALID_VERSION 56 +#define X509_V_ERR_SUITE_B_INVALID_ALGORITHM 57 +#define X509_V_ERR_SUITE_B_INVALID_CURVE 58 +#define X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM 59 +#define X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED 60 +#define X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256 61 +/* Host, email and IP check errors */ +#define X509_V_ERR_HOSTNAME_MISMATCH 62 +#define X509_V_ERR_EMAIL_MISMATCH 63 +#define X509_V_ERR_IP_ADDRESS_MISMATCH 64 +/* DANE TLSA errors */ +#define X509_V_ERR_DANE_NO_MATCH 65 +/* security level errors */ +#define X509_V_ERR_EE_KEY_TOO_SMALL 66 +#define X509_V_ERR_CA_KEY_TOO_SMALL 67 +#define X509_V_ERR_CA_MD_TOO_WEAK 68 +/* Caller error */ +#define X509_V_ERR_INVALID_CALL 69 +/* Issuer lookup error */ +#define X509_V_ERR_STORE_LOOKUP 70 +/* Certificate transparency */ +#define X509_V_ERR_NO_VALID_SCTS 71 + +#define X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION 72 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/openssl/openssl/ssl.h b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/openssl/ssl.h new file mode 100644 index 0000000..39d4bf7 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/openssl/ssl.h @@ -0,0 +1,1755 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#ifndef _SSL_H_ +#define _SSL_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "internal/ssl_x509.h" +#include "internal/ssl_pkey.h" + +/* +{ +*/ + +/** + * @brief create a SSL context + * + * @param method - the SSL context method point + * + * @return the context point + */ +SSL_CTX* SSL_CTX_new(const SSL_METHOD *method); + +/** + * @brief free a SSL context + * + * @param method - the SSL context point + * + * @return none + */ +void SSL_CTX_free(SSL_CTX *ctx); + +/** + * @brief create a SSL + * + * @param ctx - the SSL context point + * + * @return the SSL point + */ +SSL* SSL_new(SSL_CTX *ctx); + +/** + * @brief free the SSL + * + * @param ssl - the SSL point + * + * @return none + */ +void SSL_free(SSL *ssl); + +/** + * @brief connect to the remote SSL server + * + * @param ssl - the SSL point + * + * @return result + * 1 : OK + * -1 : failed + */ +int SSL_connect(SSL *ssl); + +/** + * @brief accept the remote connection + * + * @param ssl - the SSL point + * + * @return result + * 1 : OK + * -1 : failed + */ +int SSL_accept(SSL *ssl); + +/** + * @brief read data from to remote + * + * @param ssl - the SSL point which has been connected + * @param buffer - the received data buffer point + * @param len - the received data length + * + * @return result + * > 0 : OK, and return received data bytes + * = 0 : connection is closed + * < 0 : an error catch + */ +int SSL_read(SSL *ssl, void *buffer, int len); + +/** + * @brief send the data to remote + * + * @param ssl - the SSL point which has been connected + * @param buffer - the send data buffer point + * @param len - the send data length + * + * @return result + * > 0 : OK, and return sent data bytes + * = 0 : connection is closed + * < 0 : an error catch + */ +int SSL_write(SSL *ssl, const void *buffer, int len); + +/** + * @brief get the verifying result of the SSL certification + * + * @param ssl - the SSL point + * + * @return the result of verifying + */ +long SSL_get_verify_result(const SSL *ssl); + +/** + * @brief shutdown the connection + * + * @param ssl - the SSL point + * + * @return result + * 1 : OK + * 0 : shutdown is not finished + * -1 : an error catch + */ +int SSL_shutdown(SSL *ssl); + +/** + * @brief bind the socket file description into the SSL + * + * @param ssl - the SSL point + * @param fd - socket handle + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_set_fd(SSL *ssl, int fd); + +/** + * @brief These functions load the private key into the SSL_CTX or SSL object + * + * @param ctx - the SSL context point + * @param pkey - private key object point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey); + +/** + * @brief These functions load the certification into the SSL_CTX or SSL object + * + * @param ctx - the SSL context point + * @param pkey - certification object point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x); + +/** + * @brief create the target SSL context client method + * + * @param none + * + * @return the SSLV2.3 version SSL context client method + */ +const SSL_METHOD* SSLv23_client_method(void); + +/** + * @brief create the target SSL context client method + * + * @param none + * + * @return the TLSV1.0 version SSL context client method + */ +const SSL_METHOD* TLSv1_client_method(void); + +/** + * @brief create the target SSL context client method + * + * @param none + * + * @return the SSLV1.0 version SSL context client method + */ +const SSL_METHOD* SSLv3_client_method(void); + +/** + * @brief create the target SSL context client method + * + * @param none + * + * @return the TLSV1.1 version SSL context client method + */ +const SSL_METHOD* TLSv1_1_client_method(void); + +/** + * @brief create the target SSL context client method + * + * @param none + * + * @return the TLSV1.2 version SSL context client method + */ +const SSL_METHOD* TLSv1_2_client_method(void); + +/** + * @brief create the target SSL context server method + * + * @param none + * + * @return the TLS any version SSL context client method + */ +const SSL_METHOD* TLS_client_method(void); + +/** + * @brief create the target SSL context server method + * + * @param none + * + * @return the SSLV2.3 version SSL context server method + */ +const SSL_METHOD* SSLv23_server_method(void); + +/** + * @brief create the target SSL context server method + * + * @param none + * + * @return the TLSV1.1 version SSL context server method + */ +const SSL_METHOD* TLSv1_1_server_method(void); + +/** + * @brief create the target SSL context server method + * + * @param none + * + * @return the TLSV1.2 version SSL context server method + */ +const SSL_METHOD* TLSv1_2_server_method(void); + +/** + * @brief create the target SSL context server method + * + * @param none + * + * @return the TLSV1.0 version SSL context server method + */ +const SSL_METHOD* TLSv1_server_method(void); + +/** + * @brief create the target SSL context server method + * + * @param none + * + * @return the SSLV3.0 version SSL context server method + */ +const SSL_METHOD* SSLv3_server_method(void); + +/** + * @brief create the target SSL context server method + * + * @param none + * + * @return the TLS any version SSL context server method + */ +const SSL_METHOD* TLS_server_method(void); + + +/** + * @brief set the SSL context ALPN select callback function + * + * @param ctx - SSL context point + * @param cb - ALPN select callback function + * @param arg - ALPN select callback function entry private data point + * + * @return none + */ +void SSL_CTX_set_alpn_select_cb(SSL_CTX *ctx, + int (*cb) (SSL *ssl, + const unsigned char **out, + unsigned char *outlen, + const unsigned char *in, + unsigned int inlen, + void *arg), + void *arg); + + +/** + * @brief set the SSL context ALPN select protocol + * + * @param ctx - SSL context point + * @param protos - ALPN protocol name + * @param protos_len - ALPN protocol name bytes + * + * @return result + * 0 : OK + * 1 : failed + */ +int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const unsigned char *protos, unsigned int protos_len); + +/** + * @brief set the SSL context next ALPN select callback function + * + * @param ctx - SSL context point + * @param cb - ALPN select callback function + * @param arg - ALPN select callback function entry private data point + * + * @return none + */ +void SSL_CTX_set_next_proto_select_cb(SSL_CTX *ctx, + int (*cb) (SSL *ssl, + unsigned char **out, + unsigned char *outlen, + const unsigned char *in, + unsigned int inlen, + void *arg), + void *arg); + +/** + * @brief get SSL error code + * + * @param ssl - SSL point + * @param ret_code - SSL return code + * + * @return SSL error number + */ +int SSL_get_error(const SSL *ssl, int ret_code); + +/** + * @brief clear the SSL error code + * + * @param none + * + * @return none + */ +void ERR_clear_error(void); + +/** + * @brief get the current SSL error code + * + * @param none + * + * @return current SSL error number + */ +int ERR_get_error(void); + +/** + * @brief register the SSL error strings + * + * @param none + * + * @return none + */ +void ERR_load_SSL_strings(void); + +/** + * @brief initialize the SSL library + * + * @param none + * + * @return none + */ +void SSL_library_init(void); + +/** + * @brief generates a human-readable string representing the error code e + * and store it into the "ret" point memory + * + * @param e - error code + * @param ret - memory point to store the string + * + * @return the result string point + */ +char *ERR_error_string(unsigned long e, char *ret); + +/** + * @brief add the SSL context option + * + * @param ctx - SSL context point + * @param opt - new SSL context option + * + * @return the SSL context option + */ +unsigned long SSL_CTX_set_options(SSL_CTX *ctx, unsigned long opt); + +/** + * @brief add the SSL context mode + * + * @param ctx - SSL context point + * @param mod - new SSL context mod + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_set_mode(SSL_CTX *ctx, int mod); + +/* +} +*/ + +/** + * @brief perform the SSL handshake + * + * @param ssl - SSL point + * + * @return result + * 1 : OK + * 0 : failed + * -1 : a error catch + */ +int SSL_do_handshake(SSL *ssl); + +/** + * @brief get the SSL current version + * + * @param ssl - SSL point + * + * @return the version string + */ +const char *SSL_get_version(const SSL *ssl); + +/** + * @brief set the SSL context version + * + * @param ctx - SSL context point + * @param meth - SSL method point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth); + +/** + * @brief get the bytes numbers which are to be read + * + * @param ssl - SSL point + * + * @return bytes number + */ +int SSL_pending(const SSL *ssl); + +/** + * @brief check if SSL want nothing + * + * @param ssl - SSL point + * + * @return result + * 0 : false + * 1 : true + */ +int SSL_want_nothing(const SSL *ssl); + +/** + * @brief check if SSL want to read + * + * @param ssl - SSL point + * + * @return result + * 0 : false + * 1 : true + */ +int SSL_want_read(const SSL *ssl); + +/** + * @brief check if SSL want to write + * + * @param ssl - SSL point + * + * @return result + * 0 : false + * 1 : true + */ +int SSL_want_write(const SSL *ssl); + +/** + * @brief get the SSL context current method + * + * @param ctx - SSL context point + * + * @return the SSL context current method + */ +const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *ctx); + +/** + * @brief get the SSL current method + * + * @param ssl - SSL point + * + * @return the SSL current method + */ +const SSL_METHOD *SSL_get_ssl_method(SSL *ssl); + +/** + * @brief set the SSL method + * + * @param ssl - SSL point + * @param meth - SSL method point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_set_ssl_method(SSL *ssl, const SSL_METHOD *method); + +/** + * @brief add CA client certification into the SSL + * + * @param ssl - SSL point + * @param x - CA certification point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_add_client_CA(SSL *ssl, X509 *x); + +/** + * @brief add CA client certification into the SSL context + * + * @param ctx - SSL context point + * @param x - CA certification point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x); + +/** + * @brief set the SSL CA certification list + * + * @param ssl - SSL point + * @param name_list - CA certification list + * + * @return none + */ +void SSL_set_client_CA_list(SSL *ssl, STACK_OF(X509_NAME) *name_list); + +/** + * @brief set the SSL context CA certification list + * + * @param ctx - SSL context point + * @param name_list - CA certification list + * + * @return none + */ +void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list); + +/** + * @briefget the SSL CA certification list + * + * @param ssl - SSL point + * + * @return CA certification list + */ +STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *ssl); + +/** + * @brief get the SSL context CA certification list + * + * @param ctx - SSL context point + * + * @return CA certification list + */ +STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *ctx); + +/** + * @brief get the SSL certification point + * + * @param ssl - SSL point + * + * @return SSL certification point + */ +X509 *SSL_get_certificate(const SSL *ssl); + +/** + * @brief get the SSL private key point + * + * @param ssl - SSL point + * + * @return SSL private key point + */ +EVP_PKEY *SSL_get_privatekey(const SSL *ssl); + +/** + * @brief set the SSL information callback function + * + * @param ssl - SSL point + * @param cb - information callback function + * + * @return none + */ +void SSL_set_info_callback(SSL *ssl, void (*cb) (const SSL *ssl, int type, int val)); + +/** + * @brief get the SSL state + * + * @param ssl - SSL point + * + * @return SSL state + */ +OSSL_HANDSHAKE_STATE SSL_get_state(const SSL *ssl); + +/** + * @brief set the SSL context read buffer length + * + * @param ctx - SSL context point + * @param len - read buffer length + * + * @return none + */ +void SSL_CTX_set_default_read_buffer_len(SSL_CTX *ctx, size_t len); + +/** + * @brief set the SSL read buffer length + * + * @param ssl - SSL point + * @param len - read buffer length + * + * @return none + */ +void SSL_set_default_read_buffer_len(SSL *ssl, size_t len); + +/** + * @brief set the SSL security level + * + * @param ssl - SSL point + * @param level - security level + * + * @return none + */ +void SSL_set_security_level(SSL *ssl, int level); + +/** + * @brief get the SSL security level + * + * @param ssl - SSL point + * + * @return security level + */ +int SSL_get_security_level(const SSL *ssl); + +/** + * @brief get the SSL verifying mode of the SSL context + * + * @param ctx - SSL context point + * + * @return verifying mode + */ +int SSL_CTX_get_verify_mode(const SSL_CTX *ctx); + +/** + * @brief get the SSL verifying depth of the SSL context + * + * @param ctx - SSL context point + * + * @return verifying depth + */ +int SSL_CTX_get_verify_depth(const SSL_CTX *ctx); + +/** + * @brief set the SSL context verifying of the SSL context + * + * @param ctx - SSL context point + * @param mode - verifying mode + * @param verify_callback - verifying callback function + * + * @return none + */ +void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, int (*verify_callback)(int, X509_STORE_CTX *)); + +/** + * @brief set the SSL verifying of the SSL context + * + * @param ctx - SSL point + * @param mode - verifying mode + * @param verify_callback - verifying callback function + * + * @return none + */ +void SSL_set_verify(SSL *s, int mode, int (*verify_callback)(int, X509_STORE_CTX *)); + +/** + * @brief set the SSL verify depth of the SSL context + * + * @param ctx - SSL context point + * @param depth - verifying depth + * + * @return none + */ +void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth); + +/** + * @brief certification verifying callback function + * + * @param preverify_ok - verifying result + * @param x509_ctx - X509 certification point + * + * @return verifying result + */ +int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx); + +/** + * @brief set the session timeout time + * + * @param ctx - SSL context point + * @param t - new session timeout time + * + * @return old session timeout time + */ +long SSL_CTX_set_timeout(SSL_CTX *ctx, long t); + +/** + * @brief get the session timeout time + * + * @param ctx - SSL context point + * + * @return current session timeout time + */ +long SSL_CTX_get_timeout(const SSL_CTX *ctx); + +/** + * @brief set the SSL context cipher through the list string + * + * @param ctx - SSL context point + * @param str - cipher controller list string + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str); + +/** + * @brief set the SSL cipher through the list string + * + * @param ssl - SSL point + * @param str - cipher controller list string + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_set_cipher_list(SSL *ssl, const char *str); + +/** + * @brief get the SSL cipher list string + * + * @param ssl - SSL point + * + * @return cipher controller list string + */ +const char *SSL_get_cipher_list(const SSL *ssl, int n); + +/** + * @brief get the SSL cipher + * + * @param ssl - SSL point + * + * @return current cipher + */ +const SSL_CIPHER *SSL_get_current_cipher(const SSL *ssl); + +/** + * @brief get the SSL cipher string + * + * @param ssl - SSL point + * + * @return cipher string + */ +const char *SSL_get_cipher(const SSL *ssl); + +/** + * @brief get the SSL context object X509 certification storage + * + * @param ctx - SSL context point + * + * @return x509 certification storage + */ +X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx); + +/** + * @brief set the SSL context object X509 certification store + * + * @param ctx - SSL context point + * @param store - X509 certification store + * + * @return none + */ +void SSL_CTX_set_cert_store(SSL_CTX *ctx, X509_STORE *store); + +/** + * @brief get the SSL specifical statement + * + * @param ssl - SSL point + * + * @return specifical statement + */ +int SSL_want(const SSL *ssl); + +/** + * @brief check if the SSL is SSL_X509_LOOKUP state + * + * @param ssl - SSL point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_want_x509_lookup(const SSL *ssl); + +/** + * @brief reset the SSL + * + * @param ssl - SSL point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_clear(SSL *ssl); + +/** + * @brief get the socket handle of the SSL + * + * @param ssl - SSL point + * + * @return result + * >= 0 : yes, and return socket handle + * < 0 : a error catch + */ +int SSL_get_fd(const SSL *ssl); + +/** + * @brief get the read only socket handle of the SSL + * + * @param ssl - SSL point + * + * @return result + * >= 0 : yes, and return socket handle + * < 0 : a error catch + */ +int SSL_get_rfd(const SSL *ssl); + +/** + * @brief get the write only socket handle of the SSL + * + * @param ssl - SSL point + * + * @return result + * >= 0 : yes, and return socket handle + * < 0 : a error catch + */ +int SSL_get_wfd(const SSL *ssl); + +/** + * @brief set the SSL if we can read as many as data + * + * @param ssl - SSL point + * @param yes - enable the function + * + * @return none + */ +void SSL_set_read_ahead(SSL *s, int yes); + +/** + * @brief set the SSL context if we can read as many as data + * + * @param ctx - SSL context point + * @param yes - enbale the function + * + * @return none + */ +void SSL_CTX_set_read_ahead(SSL_CTX *ctx, int yes); + +/** + * @brief get the SSL ahead signal if we can read as many as data + * + * @param ssl - SSL point + * + * @return SSL context ahead signal + */ +int SSL_get_read_ahead(const SSL *ssl); + +/** + * @brief get the SSL context ahead signal if we can read as many as data + * + * @param ctx - SSL context point + * + * @return SSL context ahead signal + */ +long SSL_CTX_get_read_ahead(SSL_CTX *ctx); + +/** + * @brief check if some data can be read + * + * @param ssl - SSL point + * + * @return + * 1 : there are bytes to be read + * 0 : no data + */ +int SSL_has_pending(const SSL *ssl); + +/** + * @brief load the X509 certification into SSL context + * + * @param ctx - SSL context point + * @param x - X509 certification point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x);//loads the certificate x into ctx + +/** + * @brief load the ASN1 certification into SSL context + * + * @param ctx - SSL context point + * @param len - certification length + * @param d - data point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, const unsigned char *d); + +/** + * @brief load the certification file into SSL context + * + * @param ctx - SSL context point + * @param file - certification file name + * @param type - certification encoding type + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type); + +/** + * @brief load the certification chain file into SSL context + * + * @param ctx - SSL context point + * @param file - certification chain file name + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file); + + +/** + * @brief load the ASN1 private key into SSL context + * + * @param ctx - SSL context point + * @param d - data point + * @param len - private key length + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_PrivateKey_ASN1(int pk, SSL_CTX *ctx, const unsigned char *d, long len);//adds the private key of type pk stored at memory location d (length len) to ctx + +/** + * @brief load the private key file into SSL context + * + * @param ctx - SSL context point + * @param file - private key file name + * @param type - private key encoding type + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type); + +/** + * @brief load the RSA private key into SSL context + * + * @param ctx - SSL context point + * @param x - RSA private key point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa); + +/** + * @brief load the RSA ASN1 private key into SSL context + * + * @param ctx - SSL context point + * @param d - data point + * @param len - RSA private key length + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d, long len); + +/** + * @brief load the RSA private key file into SSL context + * + * @param ctx - SSL context point + * @param file - RSA private key file name + * @param type - private key encoding type + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file, int type); + + +/** + * @brief check if the private key and certification is matched + * + * @param ctx - SSL context point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_check_private_key(const SSL_CTX *ctx); + +/** + * @brief set the SSL context server information + * + * @param ctx - SSL context point + * @param serverinfo - server information string + * @param serverinfo_length - server information length + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_serverinfo(SSL_CTX *ctx, const unsigned char *serverinfo, size_t serverinfo_length); + +/** + * @brief load the SSL context server infomation file into SSL context + * + * @param ctx - SSL context point + * @param file - server information file + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_serverinfo_file(SSL_CTX *ctx, const char *file); + +/** + * @brief SSL select next function + * + * @param out - point of output data point + * @param outlen - output data length + * @param in - input data + * @param inlen - input data length + * @param client - client data point + * @param client_len -client data length + * + * @return NPN state + * OPENSSL_NPN_UNSUPPORTED : not support + * OPENSSL_NPN_NEGOTIATED : negotiated + * OPENSSL_NPN_NO_OVERLAP : no overlap + */ +int SSL_select_next_proto(unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen, + const unsigned char *client, unsigned int client_len); + +/** + * @brief load the extra certification chain into the SSL context + * + * @param ctx - SSL context point + * @param x509 - X509 certification + * + * @return result + * 1 : OK + * 0 : failed + */ +long SSL_CTX_add_extra_chain_cert(SSL_CTX *ctx, X509 *); + +/** + * @brief control the SSL context + * + * @param ctx - SSL context point + * @param cmd - command + * @param larg - parameter length + * @param parg - parameter point + * + * @return result + * 1 : OK + * 0 : failed + */ +long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, char *parg); + +/** + * @brief get the SSL context cipher + * + * @param ctx - SSL context point + * + * @return SSL context cipher + */ +STACK *SSL_CTX_get_ciphers(const SSL_CTX *ctx); + +/** + * @brief check if the SSL context can read as many as data + * + * @param ctx - SSL context point + * + * @return result + * 1 : OK + * 0 : failed + */ +long SSL_CTX_get_default_read_ahead(SSL_CTX *ctx); + +/** + * @brief get the SSL context extra data + * + * @param ctx - SSL context point + * @param idx - index + * + * @return data point + */ +char *SSL_CTX_get_ex_data(const SSL_CTX *ctx, int idx); + +/** + * @brief get the SSL context quiet shutdown option + * + * @param ctx - SSL context point + * + * @return quiet shutdown option + */ +int SSL_CTX_get_quiet_shutdown(const SSL_CTX *ctx); + +/** + * @brief load the SSL context CA file + * + * @param ctx - SSL context point + * @param CAfile - CA certification file + * @param CApath - CA certification file path + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, const char *CApath); + +/** + * @brief add SSL context reference count by '1' + * + * @param ctx - SSL context point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_up_ref(SSL_CTX *ctx); + +/** + * @brief set SSL context application private data + * + * @param ctx - SSL context point + * @param arg - private data + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_set_app_data(SSL_CTX *ctx, void *arg); + +/** + * @brief set SSL context client certification callback function + * + * @param ctx - SSL context point + * @param cb - callback function + * + * @return none + */ +void SSL_CTX_set_client_cert_cb(SSL_CTX *ctx, int (*cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey)); + +/** + * @brief set the SSL context if we can read as many as data + * + * @param ctx - SSL context point + * @param m - enable the fuction + * + * @return none + */ +void SSL_CTX_set_default_read_ahead(SSL_CTX *ctx, int m); + +/** + * @brief set SSL context default verifying path + * + * @param ctx - SSL context point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx); + +/** + * @brief set SSL context default verifying directory + * + * @param ctx - SSL context point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_set_default_verify_dir(SSL_CTX *ctx); + +/** + * @brief set SSL context default verifying file + * + * @param ctx - SSL context point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_set_default_verify_file(SSL_CTX *ctx); + +/** + * @brief set SSL context extra data + * + * @param ctx - SSL context point + * @param idx - data index + * @param arg - data point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_set_ex_data(SSL_CTX *s, int idx, char *arg); + +/** + * @brief clear the SSL context option bit of "op" + * + * @param ctx - SSL context point + * @param op - option + * + * @return SSL context option + */ +unsigned long SSL_CTX_clear_options(SSL_CTX *ctx, unsigned long op); + +/** + * @brief get the SSL context option + * + * @param ctx - SSL context point + * @param op - option + * + * @return SSL context option + */ +unsigned long SSL_CTX_get_options(SSL_CTX *ctx); + +/** + * @brief set the SSL context quiet shutdown mode + * + * @param ctx - SSL context point + * @param mode - mode + * + * @return none + */ +void SSL_CTX_set_quiet_shutdown(SSL_CTX *ctx, int mode); + +/** + * @brief get the SSL context X509 certification + * + * @param ctx - SSL context point + * + * @return X509 certification + */ +X509 *SSL_CTX_get0_certificate(const SSL_CTX *ctx); + +/** + * @brief get the SSL context private key + * + * @param ctx - SSL context point + * + * @return private key + */ +EVP_PKEY *SSL_CTX_get0_privatekey(const SSL_CTX *ctx); + +/** + * @brief set SSL context PSK identity hint + * + * @param ctx - SSL context point + * @param hint - PSK identity hint + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *hint); + +/** + * @brief set SSL context PSK server callback function + * + * @param ctx - SSL context point + * @param callback - callback function + * + * @return none + */ +void SSL_CTX_set_psk_server_callback(SSL_CTX *ctx, + unsigned int (*callback)(SSL *ssl, + const char *identity, + unsigned char *psk, + int max_psk_len)); +/** + * @brief get alert description string + * + * @param value - alert value + * + * @return alert description string + */ +const char *SSL_alert_desc_string(int value); + +/** + * @brief get alert description long string + * + * @param value - alert value + * + * @return alert description long string + */ +const char *SSL_alert_desc_string_long(int value); + +/** + * @brief get alert type string + * + * @param value - alert value + * + * @return alert type string + */ +const char *SSL_alert_type_string(int value); + +/** + * @brief get alert type long string + * + * @param value - alert value + * + * @return alert type long string + */ +const char *SSL_alert_type_string_long(int value); + +/** + * @brief get SSL context of the SSL + * + * @param ssl - SSL point + * + * @return SSL context + */ +SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl); + +/** + * @brief get SSL application data + * + * @param ssl - SSL point + * + * @return application data + */ +char *SSL_get_app_data(SSL *ssl); + +/** + * @brief get SSL cipher bits + * + * @param ssl - SSL point + * @param alg_bits - algorithm bits + * + * @return strength bits + */ +int SSL_get_cipher_bits(const SSL *ssl, int *alg_bits); + +/** + * @brief get SSL cipher name + * + * @param ssl - SSL point + * + * @return SSL cipher name + */ +char *SSL_get_cipher_name(const SSL *ssl); + +/** + * @brief get SSL cipher version + * + * @param ssl - SSL point + * + * @return SSL cipher version + */ +char *SSL_get_cipher_version(const SSL *ssl); + +/** + * @brief get SSL extra data + * + * @param ssl - SSL point + * @param idx - data index + * + * @return extra data + */ +char *SSL_get_ex_data(const SSL *ssl, int idx); + +/** + * @brief get index of the SSL extra data X509 storage context + * + * @param none + * + * @return data index + */ +int SSL_get_ex_data_X509_STORE_CTX_idx(void); + +/** + * @brief get peer certification chain + * + * @param ssl - SSL point + * + * @return certification chain + */ +STACK *SSL_get_peer_cert_chain(const SSL *ssl); + +/** + * @brief get peer certification + * + * @param ssl - SSL point + * + * @return certification + */ +X509 *SSL_get_peer_certificate(const SSL *ssl); + +/** + * @brief get SSL quiet shutdown mode + * + * @param ssl - SSL point + * + * @return quiet shutdown mode + */ +int SSL_get_quiet_shutdown(const SSL *ssl); + +/** + * @brief get SSL read only IO handle + * + * @param ssl - SSL point + * + * @return IO handle + */ +BIO *SSL_get_rbio(const SSL *ssl); + +/** + * @brief get SSL shared ciphers + * + * @param ssl - SSL point + * @param buf - buffer to store the ciphers + * @param len - buffer len + * + * @return shared ciphers + */ +char *SSL_get_shared_ciphers(const SSL *ssl, char *buf, int len); + +/** + * @brief get SSL shutdown mode + * + * @param ssl - SSL point + * + * @return shutdown mode + */ +int SSL_get_shutdown(const SSL *ssl); + +/** + * @brief get SSL session time + * + * @param ssl - SSL point + * + * @return session time + */ +long SSL_get_time(const SSL *ssl); + +/** + * @brief get SSL session timeout time + * + * @param ssl - SSL point + * + * @return session timeout time + */ +long SSL_get_timeout(const SSL *ssl); + +/** + * @brief get SSL verifying mode + * + * @param ssl - SSL point + * + * @return verifying mode + */ +int SSL_get_verify_mode(const SSL *ssl); + +/** + * @brief get SSL write only IO handle + * + * @param ssl - SSL point + * + * @return IO handle + */ +BIO *SSL_get_wbio(const SSL *ssl); + +/** + * @brief load SSL client CA certification file + * + * @param file - file name + * + * @return certification loading object + */ +STACK *SSL_load_client_CA_file(const char *file); + +/** + * @brief add SSL reference by '1' + * + * @param ssl - SSL point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_up_ref(SSL *ssl); + +/** + * @brief read and put data into buf, but not clear the SSL low-level storage + * + * @param ssl - SSL point + * @param buf - storage buffer point + * @param num - data bytes + * + * @return result + * > 0 : OK, and return read bytes + * = 0 : connect is closed + * < 0 : a error catch + */ +int SSL_peek(SSL *ssl, void *buf, int num); + +/** + * @brief make SSL renegotiate + * + * @param ssl - SSL point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_renegotiate(SSL *ssl); + +/** + * @brief get the state string where SSL is reading + * + * @param ssl - SSL point + * + * @return state string + */ +const char *SSL_rstate_string(SSL *ssl); + +/** + * @brief get the statement long string where SSL is reading + * + * @param ssl - SSL point + * + * @return statement long string + */ +const char *SSL_rstate_string_long(SSL *ssl); + +/** + * @brief set SSL accept statement + * + * @param ssl - SSL point + * + * @return none + */ +void SSL_set_accept_state(SSL *ssl); + +/** + * @brief set SSL application data + * + * @param ssl - SSL point + * @param arg - SSL application data point + * + * @return none + */ +void SSL_set_app_data(SSL *ssl, char *arg); + +/** + * @brief set SSL BIO + * + * @param ssl - SSL point + * @param rbio - read only IO + * @param wbio - write only IO + * + * @return none + */ +void SSL_set_bio(SSL *ssl, BIO *rbio, BIO *wbio); + +/** + * @brief clear SSL option + * + * @param ssl - SSL point + * @param op - clear option + * + * @return SSL option + */ +unsigned long SSL_clear_options(SSL *ssl, unsigned long op); + +/** + * @brief get SSL option + * + * @param ssl - SSL point + * + * @return SSL option + */ +unsigned long SSL_get_options(SSL *ssl); + +/** + * @brief clear SSL option + * + * @param ssl - SSL point + * @param op - setting option + * + * @return SSL option + */ +unsigned long SSL_set_options(SSL *ssl, unsigned long op); + +/** + * @brief set SSL quiet shutdown mode + * + * @param ssl - SSL point + * @param mode - quiet shutdown mode + * + * @return none + */ +void SSL_set_quiet_shutdown(SSL *ssl, int mode); + +/** + * @brief set SSL shutdown mode + * + * @param ssl - SSL point + * @param mode - shutdown mode + * + * @return none + */ +void SSL_set_shutdown(SSL *ssl, int mode); + +/** + * @brief set SSL session time + * + * @param ssl - SSL point + * @param t - session time + * + * @return session time + */ +void SSL_set_time(SSL *ssl, long t); + +/** + * @brief set SSL session timeout time + * + * @param ssl - SSL point + * @param t - session timeout time + * + * @return session timeout time + */ +void SSL_set_timeout(SSL *ssl, long t); + +/** + * @brief get SSL statement string + * + * @param ssl - SSL point + * + * @return SSL statement string + */ +char *SSL_state_string(const SSL *ssl); + +/** + * @brief get SSL statement long string + * + * @param ssl - SSL point + * + * @return SSL statement long string + */ +char *SSL_state_string_long(const SSL *ssl); + +/** + * @brief get SSL renegotiation count + * + * @param ssl - SSL point + * + * @return renegotiation count + */ +long SSL_total_renegotiations(SSL *ssl); + +/** + * @brief get SSL version + * + * @param ssl - SSL point + * + * @return SSL version + */ +int SSL_version(const SSL *ssl); + +/** + * @brief set SSL PSK identity hint + * + * @param ssl - SSL point + * @param hint - identity hint + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_use_psk_identity_hint(SSL *ssl, const char *hint); + +/** + * @brief get SSL PSK identity hint + * + * @param ssl - SSL point + * + * @return identity hint + */ +const char *SSL_get_psk_identity_hint(SSL *ssl); + +/** + * @brief get SSL PSK identity + * + * @param ssl - SSL point + * + * @return identity + */ +const char *SSL_get_psk_identity(SSL *ssl); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/openssl/platform/ssl_opt.h b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/platform/ssl_opt.h new file mode 100644 index 0000000..65cd423 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/platform/ssl_opt.h @@ -0,0 +1,89 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#ifndef _SSL_OPT_H_ +#define _SSL_OPT_H_ + +/* + * Enable OpenSSL debugging function. + * + * If the option is enabled, "SSL_DEBUG" works. + */ +//#define CONFIG_OPENSSL_DEBUG + +#ifdef CONFIG_OPENSSL_DEBUG + +/* + * OpenSSL debugging level. + * + * Only function whose debugging level is higher than "OPENSSL_DEBUG_LEVEL" works. + * + * For example: + * If OPENSSL_DEBUG_LEVEL = 2, you use function "SSL_DEBUG(1, "malloc failed")". + * Because 1 < 2, it will not print. + */ +//#define CONFIG_OPENSSL_DEBUG_LEVEL + +/* + * If the option is enabled, low-level module debugging function of OpenSSL is enabled, + * e.g. mbedtls internal debugging function. + */ +//#define CONFIG_OPENSSL_LOWLEVEL_DEBUG + +#endif /* CONFIG_OPENSSL_DEBUG */ + +/* + * OpenSSL function needs "assert" function to check if input parameters are valid. + * + * If you want to use assert debugging function, "OPENSSL_DEBUG" should be enabled. + * + * You must only select one of following: + * 1. CONFIG_OPENSSL_ASSERT_DO_NOTHING + * 2. CONFIG_OPENSSL_ASSERT_EXIT + * 3. CONFIG_OPENSSL_ASSERT_DEBUG (depend on "CONFIG_OPENSSL_DEBUG") + * 4. CONFIG_OPENSSL_ASSERT_DEBUG_EXIT (depend on "CONFIG_OPENSSL_DEBUG") + * 5. CONFIG_OPENSSL_ASSERT_DEBUG_BLOCK (depend on "CONFIG_OPENSSL_DEBUG") + */ + +/* + * Do nothing and "SSL_ASSERT" does not work. + */ +//#define CONFIG_OPENSSL_ASSERT_DO_NOTHING + +/* + * Enable assert exiting, it will check and return error code. + */ +#define CONFIG_OPENSSL_ASSERT_EXIT + +#ifdef CONFIG_OPENSSL_DEBUG + +/* + * Enable assert debugging, it will check and show debugging message. + */ +//#define CONFIG_OPENSSL_ASSERT_DEBUG + +/* + * Enable assert debugging and exiting, it will check, show debugging message and return error code. + */ +//#define CONFIG_OPENSSL_ASSERT_DEBUG_EXIT + +/* + * Enable assert debugging and blocking, it will check, show debugging message and block by "while (1);". + */ +//#define CONFIG_OPENSSL_ASSERT_DEBUG_BLOCK + +#endif /* CONFIG_OPENSSL_DEBUG */ + +#endif + diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/openssl/platform/ssl_pm.h b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/platform/ssl_pm.h new file mode 100644 index 0000000..e6ce49b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/platform/ssl_pm.h @@ -0,0 +1,59 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#ifndef _SSL_PM_H_ +#define _SSL_PM_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include +#include "ssl_types.h" +#include "ssl_port.h" + +int ssl_pm_new(SSL *ssl); +void ssl_pm_free(SSL *ssl); + +int ssl_pm_handshake(SSL *ssl); +int ssl_pm_shutdown(SSL *ssl); +int ssl_pm_clear(SSL *ssl); + +int ssl_pm_read(SSL *ssl, void *buffer, int len); +int ssl_pm_send(SSL *ssl, const void *buffer, int len); +int ssl_pm_pending(const SSL *ssl); + +void ssl_pm_set_fd(SSL *ssl, int fd, int mode); +int ssl_pm_get_fd(const SSL *ssl, int mode); + +OSSL_HANDSHAKE_STATE ssl_pm_get_state(const SSL *ssl); + +void ssl_pm_set_bufflen(SSL *ssl, int len); + +int x509_pm_show_info(X509 *x); +int x509_pm_new(X509 *x, X509 *m_x); +void x509_pm_free(X509 *x); +int x509_pm_load(X509 *x, const unsigned char *buffer, int len); + +int pkey_pm_new(EVP_PKEY *pk, EVP_PKEY *m_pk); +void pkey_pm_free(EVP_PKEY *pk); +int pkey_pm_load(EVP_PKEY *pk, const unsigned char *buffer, int len); + +long ssl_pm_get_verify_result(const SSL *ssl); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/openssl/platform/ssl_port.h b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/platform/ssl_port.h new file mode 100644 index 0000000..cae74fa --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/openssl/platform/ssl_port.h @@ -0,0 +1,81 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#ifndef _SSL_PORT_H_ +#define _SSL_PORT_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "c_types.h" +#include "esp_system.h" +#include "string.h" + +#ifdef MEMLEAK_DEBUG + +extern void *pvPortMalloc( size_t xWantedSize, const char * file, unsigned line); +extern void *pvPortZalloc( size_t xWantedSize, const char * file, unsigned line); +extern void vPortFree(void *pv, const char * file, unsigned line); + +#define ssl_mem_malloc(s) \ + ({ \ + static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; \ + pvPortMalloc(s, mem_debug_file, __LINE__); \ + }) + +#define ssl_mem_zalloc(s) \ + ({ \ + static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; \ + pvPortZalloc(s, mem_debug_file, __LINE__); \ + }) + +#define ssl_mem_free(s) \ +do{\ + static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; \ + vPortFree(s, mem_debug_file, __LINE__);\ +}while(0) + + +#else + +extern void *pvPortMalloc( size_t xWantedSize ); +extern void *pvPortZalloc( size_t xWantedSize ); +extern void vPortFree(void *pv); + +#define ssl_mem_zalloc(s) pvPortZalloc(s) +#define ssl_mem_malloc(s) pvPortMalloc(s) +#define ssl_mem_free(p) vPortFree(p) + +#endif + +#define ssl_memcpy memcpy +#define ssl_strlen strlen + +#define ssl_speed_up_enter() system_update_cpu_freq(SYS_CPU_160MHZ) +#define ssl_speed_up_exit() system_update_cpu_freq(SYS_CPU_80MHZ) + +#ifndef os_printf +#define os_printf(fmt, ...) do { \ + static const char flash_str[] ICACHE_RODATA_ATTR STORE_ATTR = fmt; \ + printf(flash_str, ##__VA_ARGS__); \ + } while(0) +#endif + +#define SSL_DEBUG_LOG os_printf + +#define LOCAL_ATRR ICACHE_RODATA_ATTR STORE_ATTR + +#endif + diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/spiffs/spiffs.h b/Distrib/ESPressif/RTOS/1.5.0/include/spiffs/spiffs.h new file mode 100644 index 0000000..2bf0a6e --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/spiffs/spiffs.h @@ -0,0 +1,560 @@ +/* + * spiffs.h + * + * Created on: May 26, 2013 + * Author: petera + */ + + + +#ifndef SPIFFS_H_ +#define SPIFFS_H_ +#if defined(__cplusplus) +extern "C" { +#endif + +#include "spiffs_config.h" + +#define SPIFFS_OK 0 +#define SPIFFS_ERR_NOT_MOUNTED -10000 +#define SPIFFS_ERR_FULL -10001 +#define SPIFFS_ERR_NOT_FOUND -10002 +#define SPIFFS_ERR_END_OF_OBJECT -10003 +#define SPIFFS_ERR_DELETED -10004 +#define SPIFFS_ERR_NOT_FINALIZED -10005 +#define SPIFFS_ERR_NOT_INDEX -10006 +#define SPIFFS_ERR_OUT_OF_FILE_DESCS -10007 +#define SPIFFS_ERR_FILE_CLOSED -10008 +#define SPIFFS_ERR_FILE_DELETED -10009 +#define SPIFFS_ERR_BAD_DESCRIPTOR -10010 +#define SPIFFS_ERR_IS_INDEX -10011 +#define SPIFFS_ERR_IS_FREE -10012 +#define SPIFFS_ERR_INDEX_SPAN_MISMATCH -10013 +#define SPIFFS_ERR_DATA_SPAN_MISMATCH -10014 +#define SPIFFS_ERR_INDEX_REF_FREE -10015 +#define SPIFFS_ERR_INDEX_REF_LU -10016 +#define SPIFFS_ERR_INDEX_REF_INVALID -10017 +#define SPIFFS_ERR_INDEX_FREE -10018 +#define SPIFFS_ERR_INDEX_LU -10019 +#define SPIFFS_ERR_INDEX_INVALID -10020 +#define SPIFFS_ERR_NOT_WRITABLE -10021 +#define SPIFFS_ERR_NOT_READABLE -10022 +#define SPIFFS_ERR_CONFLICTING_NAME -10023 +#define SPIFFS_ERR_NOT_CONFIGURED -10024 + +#define SPIFFS_ERR_NOT_A_FS -10025 +#define SPIFFS_ERR_MOUNTED -10026 +#define SPIFFS_ERR_ERASE_FAIL -10027 +#define SPIFFS_ERR_MAGIC_NOT_POSSIBLE -10028 + +#define SPIFFS_ERR_NO_DELETED_BLOCKS -10029 + +#define SPIFFS_ERR_INTERNAL -10050 + +#define SPIFFS_ERR_TEST -10100 + + +// spiffs file descriptor index type. must be signed +typedef s16_t spiffs_file; +// spiffs file descriptor flags +typedef u16_t spiffs_flags; +// spiffs file mode +typedef u16_t spiffs_mode; +// object type +typedef u8_t spiffs_obj_type; + +/* spi read call function type */ +typedef s32_t (*spiffs_read)(u32_t addr, u32_t size, u8_t *dst); +/* spi write call function type */ +typedef s32_t (*spiffs_write)(u32_t addr, u32_t size, u8_t *src); +/* spi erase call function type */ +typedef s32_t (*spiffs_erase)(u32_t addr, u32_t size); + +/* file system check callback report operation */ +typedef enum { + SPIFFS_CHECK_LOOKUP = 0, + SPIFFS_CHECK_INDEX, + SPIFFS_CHECK_PAGE +} spiffs_check_type; + +/* file system check callback report type */ +typedef enum { + SPIFFS_CHECK_PROGRESS = 0, + SPIFFS_CHECK_ERROR, + SPIFFS_CHECK_FIX_INDEX, + SPIFFS_CHECK_FIX_LOOKUP, + SPIFFS_CHECK_DELETE_ORPHANED_INDEX, + SPIFFS_CHECK_DELETE_PAGE, + SPIFFS_CHECK_DELETE_BAD_FILE, +} spiffs_check_report; + +/* file system check callback function */ +typedef void (*spiffs_check_callback)(spiffs_check_type type, spiffs_check_report report, + u32_t arg1, u32_t arg2); + +#ifndef SPIFFS_DBG +#define SPIFFS_DBG(...) \ + print(__VA_ARGS__) +#endif +#ifndef SPIFFS_GC_DBG +#define SPIFFS_GC_DBG(...) printf(__VA_ARGS__) +#endif +#ifndef SPIFFS_CACHE_DBG +#define SPIFFS_CACHE_DBG(...) printf(__VA_ARGS__) +#endif +#ifndef SPIFFS_CHECK_DBG +#define SPIFFS_CHECK_DBG(...) printf(__VA_ARGS__) +#endif + +/* Any write to the filehandle is appended to end of the file */ +#define SPIFFS_APPEND (1<<0) +/* If the opened file exists, it will be truncated to zero length before opened */ +#define SPIFFS_TRUNC (1<<1) +/* If the opened file does not exist, it will be created before opened */ +#define SPIFFS_CREAT (1<<2) +/* The opened file may only be read */ +#define SPIFFS_RDONLY (1<<3) +/* The opened file may only be writted */ +#define SPIFFS_WRONLY (1<<4) +/* The opened file may be both read and writted */ +#define SPIFFS_RDWR (SPIFFS_RDONLY | SPIFFS_WRONLY) +/* Any writes to the filehandle will never be cached */ +#define SPIFFS_DIRECT (1<<5) + +#define SPIFFS_SEEK_SET (0) +#define SPIFFS_SEEK_CUR (1) +#define SPIFFS_SEEK_END (2) + +#define SPIFFS_TYPE_FILE (1) +#define SPIFFS_TYPE_DIR (2) +#define SPIFFS_TYPE_HARD_LINK (3) +#define SPIFFS_TYPE_SOFT_LINK (4) + +#ifndef SPIFFS_LOCK +#define SPIFFS_LOCK(fs) +#endif + +#ifndef SPIFFS_UNLOCK +#define SPIFFS_UNLOCK(fs) +#endif + +// phys structs + +// spiffs spi configuration struct +typedef struct { + // physical read function + spiffs_read hal_read_f; + // physical write function + spiffs_write hal_write_f; + // physical erase function + spiffs_erase hal_erase_f; +#if SPIFFS_SINGLETON == 0 + // physical size of the spi flash + u32_t phys_size; + // physical offset in spi flash used for spiffs, + // must be on block boundary + u32_t phys_addr; + // physical size when erasing a block + u32_t phys_erase_block; + + // logical size of a block, must be on physical + // block size boundary and must never be less than + // a physical block + u32_t log_block_size; + // logical size of a page, must be at least + // log_block_size / 8 + u32_t log_page_size; +#endif +} spiffs_config; + +typedef struct { + // file system configuration + spiffs_config cfg; + // number of logical blocks + u32_t block_count; + + // cursor for free blocks, block index + spiffs_block_ix free_cursor_block_ix; + // cursor for free blocks, entry index + int free_cursor_obj_lu_entry; + // cursor when searching, block index + spiffs_block_ix cursor_block_ix; + // cursor when searching, entry index + int cursor_obj_lu_entry; + + // primary work buffer, size of a logical page + u8_t *lu_work; + // secondary work buffer, size of a logical page + u8_t *work; + // file descriptor memory area + u8_t *fd_space; + // available file descriptors + u32_t fd_count; + + // last error + s32_t err_code; + + // current number of free blocks + u32_t free_blocks; + // current number of busy pages + u32_t stats_p_allocated; + // current number of deleted pages + u32_t stats_p_deleted; + // flag indicating that garbage collector is cleaning + u8_t cleaning; + // max erase count amongst all blocks + spiffs_obj_id max_erase_count; + +#if SPIFFS_GC_STATS + u32_t stats_gc_runs; +#endif + +#if SPIFFS_CACHE + // cache memory + void *cache; + // cache size + u32_t cache_size; +#if SPIFFS_CACHE_STATS + u32_t cache_hits; + u32_t cache_misses; +#endif +#endif + + // check callback function + spiffs_check_callback check_cb_f; + + // mounted flag + u8_t mounted; + // config magic + u32_t config_magic; +} spiffs; + +/* spiffs file status struct */ +typedef struct { + spiffs_obj_id obj_id; + u32_t size; + spiffs_obj_type type; + u8_t name[SPIFFS_OBJ_NAME_LEN]; +} spiffs_stat; + +struct spiffs_dirent { + spiffs_obj_id obj_id; + u8_t name[SPIFFS_OBJ_NAME_LEN]; + spiffs_obj_type type; + u32_t size; + spiffs_page_ix pix; +}; + +typedef struct { + spiffs *fs; + spiffs_block_ix block; + int entry; +} spiffs_DIR; + +// functions + +/** + * Initializes the file system dynamic parameters and mounts the filesystem. + * If SPIFFS_USE_MAGIC is enabled the mounting may fail with SPIFFS_ERR_NOT_A_FS + * if the flash does not contain a recognizable file system. + * In this case, SPIFFS_format must be called prior to remounting. + * @param fs the file system struct + * @param config the physical and logical configuration of the file system + * @param work a memory work buffer comprising 2*config->log_page_size + * bytes used throughout all file system operations + * @param fd_space memory for file descriptors + * @param fd_space_size memory size of file descriptors + * @param cache memory for cache, may be null + * @param cache_size memory size of cache + * @param check_cb_f callback function for reporting during consistency checks + */ +s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work, + u8_t *fd_space, u32_t fd_space_size, + void *cache, u32_t cache_size, + spiffs_check_callback check_cb_f); + +/** + * Unmounts the file system. All file handles will be flushed of any + * cached writes and closed. + * @param fs the file system struct + */ +void SPIFFS_unmount(spiffs *fs); + +/** + * Creates a new file. + * @param fs the file system struct + * @param path the path of the new file + * @param mode ignored, for posix compliance + */ +s32_t SPIFFS_creat(spiffs *fs, char *path, spiffs_mode mode); + +/** + * Opens/creates a file. + * @param fs the file system struct + * @param path the path of the new file + * @param flags the flags for the open command, can be combinations of + * SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY, + * SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT + * @param mode ignored, for posix compliance + */ +spiffs_file SPIFFS_open(spiffs *fs, char *path, spiffs_flags flags, spiffs_mode mode); + + +/** + * Opens a file by given dir entry. + * Optimization purposes, when traversing a file system with SPIFFS_readdir + * a normal SPIFFS_open would need to traverse the filesystem again to find + * the file, whilst SPIFFS_open_by_dirent already knows where the file resides. + * @param fs the file system struct + * @param path the dir entry to the file + * @param flags the flags for the open command, can be combinations of + * SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY, + * SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT. + * SPIFFS_CREAT will have no effect in this case. + * @param mode ignored, for posix compliance + */ +spiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_flags flags, spiffs_mode mode); + +/** + * Reads from given filehandle. + * @param fs the file system struct + * @param fh the filehandle + * @param buf where to put read data + * @param len how much to read + * @returns number of bytes read, or -1 if error + */ +s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len); + +/** + * Writes to given filehandle. + * @param fs the file system struct + * @param fh the filehandle + * @param buf the data to write + * @param len how much to write + * @returns number of bytes written, or -1 if error + */ +s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len); + +/** + * Moves the read/write file offset + * @param fs the file system struct + * @param fh the filehandle + * @param offs how much/where to move the offset + * @param whence if SPIFFS_SEEK_SET, the file offset shall be set to offset bytes + * if SPIFFS_SEEK_CUR, the file offset shall be set to its current location plus offset + * if SPIFFS_SEEK_END, the file offset shall be set to the size of the file plus offset + */ +s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence); + +/** + * Removes a file by path + * @param fs the file system struct + * @param path the path of the file to remove + */ +s32_t SPIFFS_remove(spiffs *fs, char *path); + +/** + * Removes a file by filehandle + * @param fs the file system struct + * @param fh the filehandle of the file to remove + */ +s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh); + +/** + * Gets file status by path + * @param fs the file system struct + * @param path the path of the file to stat + * @param s the stat struct to populate + */ +s32_t SPIFFS_stat(spiffs *fs, char *path, spiffs_stat *s); + +/** + * Gets file status by filehandle + * @param fs the file system struct + * @param fh the filehandle of the file to stat + * @param s the stat struct to populate + */ +s32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s); + +/** + * Flushes all pending write operations from cache for given file + * @param fs the file system struct + * @param fh the filehandle of the file to flush + */ +s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh); + +/** + * Closes a filehandle. If there are pending write operations, these are finalized before closing. + * @param fs the file system struct + * @param fh the filehandle of the file to close + */ +void SPIFFS_close(spiffs *fs, spiffs_file fh); + +/** + * Renames a file + * @param fs the file system struct + * @param old path of file to rename + * @param newPath new path of file + */ +s32_t SPIFFS_rename(spiffs *fs, char *old, char *newPath); + +/** + * Returns last error of last file operation. + * @param fs the file system struct + */ +s32_t SPIFFS_errno(spiffs *fs); + +/** + * Clears last error. + * @param fs the file system struct + */ +void SPIFFS_clearerr(spiffs *fs); + +/** + * Opens a directory stream corresponding to the given name. + * The stream is positioned at the first entry in the directory. + * On hydrogen builds the name argument is ignored as hydrogen builds always correspond + * to a flat file structure - no directories. + * @param fs the file system struct + * @param name the name of the directory + * @param d pointer the directory stream to be populated + */ +spiffs_DIR *SPIFFS_opendir(spiffs *fs, char *name, spiffs_DIR *d); + +/** + * Closes a directory stream + * @param d the directory stream to close + */ +s32_t SPIFFS_closedir(spiffs_DIR *d); + +/** + * Reads a directory into given spifs_dirent struct. + * @param d pointer to the directory stream + * @param e the dirent struct to be populated + * @returns null if error or end of stream, else given dirent is returned + */ +struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e); + +/** + * Runs a consistency check on given filesystem. + * @param fs the file system struct + */ +s32_t SPIFFS_check(spiffs *fs); + +/** + * Searches for a block with only deleted entries. If found, it is erased. + * @param fs the file system struct + */ +s32_t SPIFFS_erase_deleted_block(spiffs *fs); + + +/** + * Returns number of total bytes available and number of used bytes. + * This is an estimation, and depends on if there a many files with little + * data or few files with much data. + * NB: If used number of bytes exceeds total bytes, a SPIFFS_check should + * run. This indicates a power loss in midst of things. In worst case + * (repeated powerlosses in mending or gc) you might have to delete some files. + * + * @param fs the file system struct + * @param total total number of bytes in filesystem + * @param used used number of bytes in filesystem + */ +s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used); + +/** + * Formats the entire file system. All data will be lost. + * The filesystem must not be mounted when calling this. + * + * NB: formatting is awkward. Due to backwards compatibility, SPIFFS_mount + * MUST be called prior to formatting in order to configure the filesystem. + * If SPIFFS_mount succeeds, SPIFFS_unmount must be called before calling + * SPIFFS_format. + * If SPIFFS_mount fails, SPIFFS_format can be called directly without calling + * SPIFFS_unmount first. + * + * @param fs the file system struct + */ +s32_t SPIFFS_format(spiffs *fs); + +/** + * Returns nonzero if spiffs is mounted, or zero if unmounted. + * @param fs the file system struct + */ +u8_t SPIFFS_mounted(spiffs *fs); + +/** + * Tries to find a block where most or all pages are deleted, and erase that + * block if found. Does not care for wear levelling. Will not move pages + * around. + * If parameter max_free_pages are set to 0, only blocks with only deleted + * pages will be selected. + * + * NB: the garbage collector is automatically called when spiffs needs free + * pages. The reason for this function is to give possibility to do background + * tidying when user knows the system is idle. + * + * Use with care. + * + * Setting max_free_pages to anything larger than zero will eventually wear + * flash more as a block containing free pages can be erased. + * + * Will set err_no to SPIFFS_OK if a block was found and erased, + * SPIFFS_ERR_NO_DELETED_BLOCK if no matching block was found, + * or other error. + * + * @param fs the file system struct + * @param max_free_pages maximum number allowed free pages in block + */ +s32_t SPIFFS_gc_quick(spiffs *fs, u16_t max_free_pages); + +/** + * Will try to make room for given amount of bytes in the filesystem by moving + * pages and erasing blocks. + * If it is physically impossible, err_no will be set to SPIFFS_ERR_FULL. If + * there already is this amount (or more) of free space, SPIFFS_gc will + * silently return. It is recommended to call SPIFFS_info before invoking + * this method in order to determine what amount of bytes to give. + * + * NB: the garbage collector is automatically called when spiffs needs free + * pages. The reason for this function is to give possibility to do background + * tidying when user knows the system is idle. + * + * Use with care. + * + * @param fs the file system struct + * @param size amount of bytes that should be freed + */ +s32_t SPIFFS_gc(spiffs *fs, u32_t size); + +#if SPIFFS_TEST_VISUALISATION +/** + * Prints out a visualization of the filesystem. + * @param fs the file system struct + */ +s32_t SPIFFS_vis(spiffs *fs); +#endif + +#if SPIFFS_BUFFER_HELP +/** + * Returns number of bytes needed for the filedescriptor buffer given + * amount of file descriptors. + */ +u32_t SPIFFS_buffer_bytes_for_filedescs(spiffs *fs, u32_t num_descs); + +#if SPIFFS_CACHE +/** + * Returns number of bytes needed for the cache buffer given + * amount of cache pages. + */ +u32_t SPIFFS_buffer_bytes_for_cache(spiffs *fs, u32_t num_pages); +#endif +#endif + +#if SPIFFS_CACHE +#endif +#if defined(__cplusplus) +} +#endif + +#endif /* SPIFFS_H_ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/spiffs/spiffs_config.h b/Distrib/ESPressif/RTOS/1.5.0/include/spiffs/spiffs_config.h new file mode 100644 index 0000000..ac19c17 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/spiffs/spiffs_config.h @@ -0,0 +1,218 @@ +/* + * spiffs_config.h + * + * Created on: Jul 3, 2013 + * Author: petera + */ + +#ifndef SPIFFS_CONFIG_H_ +#define SPIFFS_CONFIG_H_ + +// ----------- 8< ------------ +// Following includes are for the linux test build of spiffs +// These may/should/must be removed/altered/replaced in your target +#include +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +// ----------- >8 ------------ + +// compile time switches + +// Set generic spiffs debug output call. +#ifndef SPIFFS_DBG +#define SPIFFS_DBG(...) //printf(__VA_ARGS__) +#endif +// Set spiffs debug output call for garbage collecting. +#ifndef SPIFFS_GC_DBG +#define SPIFFS_GC_DBG(...) //printf(__VA_ARGS__) +#endif +// Set spiffs debug output call for caching. +#ifndef SPIFFS_CACHE_DBG +#define SPIFFS_CACHE_DBG(...) //printf(__VA_ARGS__) +#endif +// Set spiffs debug output call for system consistency checks. +#ifndef SPIFFS_CHECK_DBG +#define SPIFFS_CHECK_DBG(...) //printf(__VA_ARGS__) +#endif + +// Enable/disable API functions to determine exact number of bytes +// for filedescriptor and cache buffers. Once decided for a configuration, +// this can be disabled to reduce flash. +#ifndef SPIFFS_BUFFER_HELP +#define SPIFFS_BUFFER_HELP 0 +#endif + +// Enables/disable memory read caching of nucleus file system operations. +// If enabled, memory area must be provided for cache in SPIFFS_mount. +#ifndef SPIFFS_CACHE +#define SPIFFS_CACHE 1 +#endif + +#if SPIFFS_CACHE +// Enables memory write caching for file descriptors in hydrogen +#ifndef SPIFFS_CACHE_WR +#define SPIFFS_CACHE_WR 1 +#endif + +// Enable/disable statistics on caching. Debug/test purpose only. +#ifndef SPIFFS_CACHE_STATS +#define SPIFFS_CACHE_STATS 1 +#endif +#endif + +// Always check header of each accessed page to ensure consistent state. +// If enabled it will increase number of reads, will increase flash. +#ifndef SPIFFS_PAGE_CHECK +#define SPIFFS_PAGE_CHECK 1 +#endif + +// Define maximum number of gc runs to perform to reach desired free pages. +#ifndef SPIFFS_GC_MAX_RUNS +#define SPIFFS_GC_MAX_RUNS 5 +#endif + +// Enable/disable statistics on gc. Debug/test purpose only. +#ifndef SPIFFS_GC_STATS +#define SPIFFS_GC_STATS 1 +#endif + +// Garbage collecting examines all pages in a block which and sums up +// to a block score. Deleted pages normally gives positive score and +// used pages normally gives a negative score (as these must be moved). +// To have a fair wear-leveling, the erase age is also included in score, +// whose factor normally is the most positive. +// The larger the score, the more likely it is that the block will +// picked for garbage collection. + +// Garbage collecting heuristics - weight used for deleted pages. +#ifndef SPIFFS_GC_HEUR_W_DELET +#define SPIFFS_GC_HEUR_W_DELET (5) +#endif +// Garbage collecting heuristics - weight used for used pages. +#ifndef SPIFFS_GC_HEUR_W_USED +#define SPIFFS_GC_HEUR_W_USED (-1) +#endif +// Garbage collecting heuristics - weight used for time between +// last erased and erase of this block. +#ifndef SPIFFS_GC_HEUR_W_ERASE_AGE +#define SPIFFS_GC_HEUR_W_ERASE_AGE (50) +#endif + +// Object name maximum length. +#ifndef SPIFFS_OBJ_NAME_LEN +#define SPIFFS_OBJ_NAME_LEN (32) +#endif + +// Size of buffer allocated on stack used when copying data. +// Lower value generates more read/writes. No meaning having it bigger +// than logical page size. +#ifndef SPIFFS_COPY_BUFFER_STACK +#define SPIFFS_COPY_BUFFER_STACK (64) +#endif + +// Enable this to have an identifiable spiffs filesystem. This will look for +// a magic in all sectors to determine if this is a valid spiffs system or +// not on mount point. If not, SPIFFS_format must be called prior to mounting +// again. +#ifndef SPIFFS_USE_MAGIC +#define SPIFFS_USE_MAGIC (0) +#endif + +// SPIFFS_LOCK and SPIFFS_UNLOCK protects spiffs from reentrancy on api level +// These should be defined on a multithreaded system + +// define this to enter a mutex if you're running on a multithreaded system +#ifndef SPIFFS_LOCK +#define SPIFFS_LOCK(fs) +#endif +// define this to exit a mutex if you're running on a multithreaded system +#ifndef SPIFFS_UNLOCK +#define SPIFFS_UNLOCK(fs) +#endif + + +// Enable if only one spiffs instance with constant configuration will exist +// on the target. This will reduce calculations, flash and memory accesses. +// Parts of configuration must be defined below instead of at time of mount. +#ifndef SPIFFS_SINGLETON +#define SPIFFS_SINGLETON 0 +#endif + +#if SPIFFS_SINGLETON +// Instead of giving parameters in config struct, singleton build must +// give parameters in defines below. +#ifndef SPIFFS_CFG_PHYS_SZ +#define SPIFFS_CFG_PHYS_SZ(ignore) (1024*1024*2) +#endif +#ifndef SPIFFS_CFG_PHYS_ERASE_SZ +#define SPIFFS_CFG_PHYS_ERASE_SZ(ignore) (65536) +#endif +#ifndef SPIFFS_CFG_PHYS_ADDR +#define SPIFFS_CFG_PHYS_ADDR(ignore) (0) +#endif +#ifndef SPIFFS_CFG_LOG_PAGE_SZ +#define SPIFFS_CFG_LOG_PAGE_SZ(ignore) (256) +#endif +#ifndef SPIFFS_CFG_LOG_BLOCK_SZ +#define SPIFFS_CFG_LOG_BLOCK_SZ(ignore) (65536) +#endif +#endif + +// Enable this if your target needs aligned data for index tables +#ifndef SPIFFS_ALIGNED_OBJECT_INDEX_TABLES +#define SPIFFS_ALIGNED_OBJECT_INDEX_TABLES 1 +#endif + +// Set SPIFFS_TEST_VISUALISATION to non-zero to enable SPIFFS_vis function +// in the api. This function will visualize all filesystem using given printf +// function. +#ifndef SPIFFS_TEST_VISUALISATION +#define SPIFFS_TEST_VISUALISATION 0 +#endif +#if SPIFFS_TEST_VISUALISATION +#ifndef spiffs_printf +#define spiffs_printf(...) printf(__VA_ARGS__) +#endif +// spiffs_printf argument for a free page +#ifndef SPIFFS_TEST_VIS_FREE_STR +#define SPIFFS_TEST_VIS_FREE_STR "_" +#endif +// spiffs_printf argument for a deleted page +#ifndef SPIFFS_TEST_VIS_DELE_STR +#define SPIFFS_TEST_VIS_DELE_STR "/" +#endif +// spiffs_printf argument for an index page for given object id +#ifndef SPIFFS_TEST_VIS_INDX_STR +#define SPIFFS_TEST_VIS_INDX_STR(id) "i" +#endif +// spiffs_printf argument for a data page for given object id +#ifndef SPIFFS_TEST_VIS_DATA_STR +#define SPIFFS_TEST_VIS_DATA_STR(id) "d" +#endif +#endif + +// Types depending on configuration such as the amount of flash bytes +// given to spiffs file system in total (spiffs_file_system_size), +// the logical block size (log_block_size), and the logical page size +// (log_page_size) + +// Block index type. Make sure the size of this type can hold +// the highest number of all blocks - i.e. spiffs_file_system_size / log_block_size +typedef u16_t spiffs_block_ix; +// Page index type. Make sure the size of this type can hold +// the highest page number of all pages - i.e. spiffs_file_system_size / log_page_size +typedef u16_t spiffs_page_ix; +// Object id type - most significant bit is reserved for index flag. Make sure the +// size of this type can hold the highest object id on a full system, +// i.e. 2 + (spiffs_file_system_size / (2*log_page_size))*2 +typedef u16_t spiffs_obj_id; +// Object span index type. Make sure the size of this type can +// hold the largest possible span index on the system - +// i.e. (spiffs_file_system_size / log_page_size) - 1 +typedef u16_t spiffs_span_ix; + +#endif /* SPIFFS_CONFIG_H_ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/spiffs/spiffs_nucleus.h b/Distrib/ESPressif/RTOS/1.5.0/include/spiffs/spiffs_nucleus.h new file mode 100644 index 0000000..80cc1cf --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/spiffs/spiffs_nucleus.h @@ -0,0 +1,718 @@ +/* + * spiffs_nucleus.h + * + * Created on: Jun 15, 2013 + * Author: petera + */ + +/* SPIFFS layout + * + * spiffs is designed for following spi flash characteristics: + * - only big areas of data (blocks) can be erased + * - erasing resets all bits in a block to ones + * - writing pulls ones to zeroes + * - zeroes cannot be pulled to ones, without erase + * - wear leveling + * + * spiffs is also meant to be run on embedded, memory constraint devices. + * + * Entire area is divided in blocks. Entire area is also divided in pages. + * Each block contains same number of pages. A page cannot be erased, but a + * block can be erased. + * + * Entire area must be block_size * x + * page_size must be block_size / (2^y) where y > 2 + * + * ex: area = 1024*1024 bytes, block size = 65536 bytes, page size = 256 bytes + * + * BLOCK 0 PAGE 0 object lookup 1 + * PAGE 1 object lookup 2 + * ... + * PAGE n-1 object lookup n + * PAGE n object data 1 + * PAGE n+1 object data 2 + * ... + * PAGE n+m-1 object data m + * + * BLOCK 1 PAGE n+m object lookup 1 + * PAGE n+m+1 object lookup 2 + * ... + * PAGE 2n+m-1 object lookup n + * PAGE 2n+m object data 1 + * PAGE 2n+m object data 2 + * ... + * PAGE 2n+2m-1 object data m + * ... + * + * n is number of object lookup pages, which is number of pages needed to index all pages + * in a block by object id + * : block_size / page_size * sizeof(obj_id) / page_size + * m is number data pages, which is number of pages in block minus number of lookup pages + * : block_size / page_size - block_size / page_size * sizeof(obj_id) / page_size + * thus, n+m is total number of pages in a block + * : block_size / page_size + * + * ex: n = 65536/256*2/256 = 2, m = 65536/256 - 2 = 254 => n+m = 65536/256 = 256 + * + * Object lookup pages contain object id entries. Each entry represent the corresponding + * data page. + * Assuming a 16 bit object id, an object id being 0xffff represents a free page. + * An object id being 0x0000 represents a deleted page. + * + * ex: page 0 : lookup : 0008 0001 0aaa ffff ffff ffff ffff ffff .. + * page 1 : lookup : ffff ffff ffff ffff ffff ffff ffff ffff .. + * page 2 : data : data for object id 0008 + * page 3 : data : data for object id 0001 + * page 4 : data : data for object id 0aaa + * ... + * + * + * Object data pages can be either object index pages or object content. + * All object data pages contains a data page header, containing object id and span index. + * The span index denotes the object page ordering amongst data pages with same object id. + * This applies to both object index pages (when index spans more than one page of entries), + * and object data pages. + * An object index page contains page entries pointing to object content page. The entry index + * in a object index page correlates to the span index in the actual object data page. + * The first object index page (span index 0) is called object index header page, and also + * contains object flags (directory/file), size, object name etc. + * + * ex: + * BLOCK 1 + * PAGE 256: objectl lookup page 1 + * [*123] [ 123] [ 123] [ 123] + * [ 123] [*123] [ 123] [ 123] + * [free] [free] [free] [free] ... + * PAGE 257: objectl lookup page 2 + * [free] [free] [free] [free] ... + * PAGE 258: object index page (header) + * obj.id:0123 span.ix:0000 flags:INDEX + * size:1600 name:ex.txt type:file + * [259] [260] [261] [262] + * PAGE 259: object data page + * obj.id:0123 span.ix:0000 flags:DATA + * PAGE 260: object data page + * obj.id:0123 span.ix:0001 flags:DATA + * PAGE 261: object data page + * obj.id:0123 span.ix:0002 flags:DATA + * PAGE 262: object data page + * obj.id:0123 span.ix:0003 flags:DATA + * PAGE 263: object index page + * obj.id:0123 span.ix:0001 flags:INDEX + * [264] [265] [fre] [fre] + * [fre] [fre] [fre] [fre] + * PAGE 264: object data page + * obj.id:0123 span.ix:0004 flags:DATA + * PAGE 265: object data page + * obj.id:0123 span.ix:0005 flags:DATA + * + */ +#ifndef SPIFFS_NUCLEUS_H_ +#define SPIFFS_NUCLEUS_H_ + +#define _SPIFFS_ERR_CHECK_FIRST (SPIFFS_ERR_INTERNAL - 1) +#define SPIFFS_ERR_CHECK_OBJ_ID_MISM (SPIFFS_ERR_INTERNAL - 1) +#define SPIFFS_ERR_CHECK_SPIX_MISM (SPIFFS_ERR_INTERNAL - 2) +#define SPIFFS_ERR_CHECK_FLAGS_BAD (SPIFFS_ERR_INTERNAL - 3) +#define _SPIFFS_ERR_CHECK_LAST (SPIFFS_ERR_INTERNAL - 4) + +#define SPIFFS_VIS_COUNTINUE (SPIFFS_ERR_INTERNAL - 20) +#define SPIFFS_VIS_COUNTINUE_RELOAD (SPIFFS_ERR_INTERNAL - 21) +#define SPIFFS_VIS_END (SPIFFS_ERR_INTERNAL - 22) + +#define SPIFFS_EV_IX_UPD 0 +#define SPIFFS_EV_IX_NEW 1 +#define SPIFFS_EV_IX_DEL 2 + +#define SPIFFS_OBJ_ID_IX_FLAG ((spiffs_obj_id)(1<<(8*sizeof(spiffs_obj_id)-1))) + +#define SPIFFS_UNDEFINED_LEN (u32_t)(-1) + +#define SPIFFS_OBJ_ID_DELETED ((spiffs_obj_id)0) +#define SPIFFS_OBJ_ID_FREE ((spiffs_obj_id)-1) + +#define SPIFFS_MAGIC(fs) ((spiffs_obj_id)(0x20140529 ^ SPIFFS_CFG_LOG_PAGE_SZ(fs))) + +#define SPIFFS_CONFIG_MAGIC (0x20090315) + +#if SPIFFS_SINGLETON == 0 +#define SPIFFS_CFG_LOG_PAGE_SZ(fs) \ + ((fs)->cfg.log_page_size) +#define SPIFFS_CFG_LOG_BLOCK_SZ(fs) \ + ((fs)->cfg.log_block_size) +#define SPIFFS_CFG_PHYS_SZ(fs) \ + ((fs)->cfg.phys_size) +#define SPIFFS_CFG_PHYS_ERASE_SZ(fs) \ + ((fs)->cfg.phys_erase_block) +#define SPIFFS_CFG_PHYS_ADDR(fs) \ + ((fs)->cfg.phys_addr) +#endif + +// total number of pages +#define SPIFFS_MAX_PAGES(fs) \ + ( SPIFFS_CFG_PHYS_SZ(fs)/SPIFFS_CFG_LOG_PAGE_SZ(fs) ) +// total number of pages per block, including object lookup pages +#define SPIFFS_PAGES_PER_BLOCK(fs) \ + ( SPIFFS_CFG_LOG_BLOCK_SZ(fs)/SPIFFS_CFG_LOG_PAGE_SZ(fs) ) +// number of object lookup pages per block +#define SPIFFS_OBJ_LOOKUP_PAGES(fs) \ + (MAX(1, (SPIFFS_PAGES_PER_BLOCK(fs) * sizeof(spiffs_obj_id)) / SPIFFS_CFG_LOG_PAGE_SZ(fs)) ) +// checks if page index belongs to object lookup +#define SPIFFS_IS_LOOKUP_PAGE(fs,pix) \ + (((pix) % SPIFFS_PAGES_PER_BLOCK(fs)) < SPIFFS_OBJ_LOOKUP_PAGES(fs)) +// number of object lookup entries in all object lookup pages +#define SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) \ + (SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs)) +// converts a block to physical address +#define SPIFFS_BLOCK_TO_PADDR(fs, block) \ + ( SPIFFS_CFG_PHYS_ADDR(fs) + (block)* SPIFFS_CFG_LOG_BLOCK_SZ(fs) ) +// converts a object lookup entry to page index +#define SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, block, entry) \ + ((block)*SPIFFS_PAGES_PER_BLOCK(fs) + (SPIFFS_OBJ_LOOKUP_PAGES(fs) + entry)) +// converts a object lookup entry to physical address of corresponding page +#define SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, block, entry) \ + (SPIFFS_BLOCK_TO_PADDR(fs, block) + (SPIFFS_OBJ_LOOKUP_PAGES(fs) + entry) * SPIFFS_CFG_LOG_PAGE_SZ(fs) ) +// converts a page to physical address +#define SPIFFS_PAGE_TO_PADDR(fs, page) \ + ( SPIFFS_CFG_PHYS_ADDR(fs) + (page) * SPIFFS_CFG_LOG_PAGE_SZ(fs) ) +// converts a physical address to page +#define SPIFFS_PADDR_TO_PAGE(fs, addr) \ + ( ((addr) - SPIFFS_CFG_PHYS_ADDR(fs)) / SPIFFS_CFG_LOG_PAGE_SZ(fs) ) +// gives index in page for a physical address +#define SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr) \ + ( ((addr) - SPIFFS_CFG_PHYS_ADDR(fs)) % SPIFFS_CFG_LOG_PAGE_SZ(fs) ) +// returns containing block for given page +#define SPIFFS_BLOCK_FOR_PAGE(fs, page) \ + ( (page) / SPIFFS_PAGES_PER_BLOCK(fs) ) +// returns starting page for block +#define SPIFFS_PAGE_FOR_BLOCK(fs, block) \ + ( (block) * SPIFFS_PAGES_PER_BLOCK(fs) ) +// converts page to entry in object lookup page +#define SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, page) \ + ( (page) % SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs) ) +// returns data size in a data page +#define SPIFFS_DATA_PAGE_SIZE(fs) \ + ( SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header) ) +// returns physical address for block's erase count, +// always in the physical last entry of the last object lookup page +#define SPIFFS_ERASE_COUNT_PADDR(fs, bix) \ + ( SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_OBJ_LOOKUP_PAGES(fs) * SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_obj_id) ) +// returns physical address for block's magic, +// always in the physical second last entry of the last object lookup page +#define SPIFFS_MAGIC_PADDR(fs, bix) \ + ( SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_OBJ_LOOKUP_PAGES(fs) * SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_obj_id)*2 ) +// checks if there is any room for magic in the object luts +#define SPIFFS_CHECK_MAGIC_POSSIBLE(fs) \ + ( (SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) % (SPIFFS_CFG_LOG_PAGE_SZ(fs)/sizeof(spiffs_obj_id))) * sizeof(spiffs_obj_id) \ + <= (SPIFFS_CFG_LOG_PAGE_SZ(fs)-sizeof(spiffs_obj_id)*2) ) + +// define helpers object + +// entries in an object header page index +#define SPIFFS_OBJ_HDR_IX_LEN(fs) \ + ((SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix_header))/sizeof(spiffs_page_ix)) +// entries in an object page index +#define SPIFFS_OBJ_IX_LEN(fs) \ + ((SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix))/sizeof(spiffs_page_ix)) +// object index entry for given data span index +#define SPIFFS_OBJ_IX_ENTRY(fs, spix) \ + ((spix) < SPIFFS_OBJ_HDR_IX_LEN(fs) ? (spix) : (((spix)-SPIFFS_OBJ_HDR_IX_LEN(fs))%SPIFFS_OBJ_IX_LEN(fs))) +// object index span index number for given data span index or entry +#define SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, spix) \ + ((spix) < SPIFFS_OBJ_HDR_IX_LEN(fs) ? 0 : (1+((spix)-SPIFFS_OBJ_HDR_IX_LEN(fs))/SPIFFS_OBJ_IX_LEN(fs))) + + +#define SPIFFS_OP_T_OBJ_LU (0<<0) +#define SPIFFS_OP_T_OBJ_LU2 (1<<0) +#define SPIFFS_OP_T_OBJ_IX (2<<0) +#define SPIFFS_OP_T_OBJ_DA (3<<0) +#define SPIFFS_OP_C_DELE (0<<2) +#define SPIFFS_OP_C_UPDT (1<<2) +#define SPIFFS_OP_C_MOVS (2<<2) +#define SPIFFS_OP_C_MOVD (3<<2) +#define SPIFFS_OP_C_FLSH (4<<2) +#define SPIFFS_OP_C_READ (5<<2) +#define SPIFFS_OP_C_WRTHRU (6<<2) + +#define SPIFFS_OP_TYPE_MASK (3<<0) +#define SPIFFS_OP_COM_MASK (7<<2) + + +// if 0, this page is written to, else clean +#define SPIFFS_PH_FLAG_USED (1<<0) +// if 0, writing is finalized, else under modification +#define SPIFFS_PH_FLAG_FINAL (1<<1) +// if 0, this is an index page, else a data page +#define SPIFFS_PH_FLAG_INDEX (1<<2) +// if 0, page is deleted, else valid +#define SPIFFS_PH_FLAG_DELET (1<<7) +// if 0, this index header is being deleted +#define SPIFFS_PH_FLAG_IXDELE (1<<6) + + +#define SPIFFS_CHECK_MOUNT(fs) \ + ((fs)->mounted != 0) + +#define SPIFFS_CHECK_CFG(fs) \ + ((fs)->config_magic == SPIFFS_CONFIG_MAGIC) + +#define SPIFFS_CHECK_RES(res) \ + do { \ + if ((res) < SPIFFS_OK) return (res); \ + } while (0); + +#define SPIFFS_API_CHECK_MOUNT(fs) \ + if (!SPIFFS_CHECK_MOUNT((fs))) { \ + (fs)->err_code = SPIFFS_ERR_NOT_MOUNTED; \ + return -1; \ + } + +#define SPIFFS_API_CHECK_CFG(fs) \ + if (!SPIFFS_CHECK_CFG((fs))) { \ + (fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED; \ + return -1; \ + } + +#define SPIFFS_API_CHECK_RES(fs, res) \ + if ((res) < SPIFFS_OK) { \ + (fs)->err_code = (res); \ + return -1; \ + } + +#define SPIFFS_API_CHECK_RES_UNLOCK(fs, res) \ + if ((res) < SPIFFS_OK) { \ + (fs)->err_code = (res); \ + SPIFFS_UNLOCK(fs); \ + return -1; \ + } + +#define SPIFFS_VALIDATE_OBJIX(ph, objid, spix) \ + if (((ph).flags & SPIFFS_PH_FLAG_USED) != 0) return SPIFFS_ERR_IS_FREE; \ + if (((ph).flags & SPIFFS_PH_FLAG_DELET) == 0) return SPIFFS_ERR_DELETED; \ + if (((ph).flags & SPIFFS_PH_FLAG_FINAL) != 0) return SPIFFS_ERR_NOT_FINALIZED; \ + if (((ph).flags & SPIFFS_PH_FLAG_INDEX) != 0) return SPIFFS_ERR_NOT_INDEX; \ + if (((objid) & SPIFFS_OBJ_ID_IX_FLAG) == 0) return SPIFFS_ERR_NOT_INDEX; \ + if ((ph).span_ix != (spix)) return SPIFFS_ERR_INDEX_SPAN_MISMATCH; + //if ((spix) == 0 && ((ph).flags & SPIFFS_PH_FLAG_IXDELE) == 0) return SPIFFS_ERR_DELETED; + +#define SPIFFS_VALIDATE_DATA(ph, objid, spix) \ + if (((ph).flags & SPIFFS_PH_FLAG_USED) != 0) return SPIFFS_ERR_IS_FREE; \ + if (((ph).flags & SPIFFS_PH_FLAG_DELET) == 0) return SPIFFS_ERR_DELETED; \ + if (((ph).flags & SPIFFS_PH_FLAG_FINAL) != 0) return SPIFFS_ERR_NOT_FINALIZED; \ + if (((ph).flags & SPIFFS_PH_FLAG_INDEX) == 0) return SPIFFS_ERR_IS_INDEX; \ + if ((objid) & SPIFFS_OBJ_ID_IX_FLAG) return SPIFFS_ERR_IS_INDEX; \ + if ((ph).span_ix != (spix)) return SPIFFS_ERR_DATA_SPAN_MISMATCH; + + +// check id +#define SPIFFS_VIS_CHECK_ID (1<<0) +// report argument object id to visitor - else object lookup id is reported +#define SPIFFS_VIS_CHECK_PH (1<<1) +// stop searching at end of all look up pages +#define SPIFFS_VIS_NO_WRAP (1<<2) + +#if SPIFFS_CACHE + +#define SPIFFS_CACHE_FLAG_DIRTY (1<<0) +#define SPIFFS_CACHE_FLAG_WRTHRU (1<<1) +#define SPIFFS_CACHE_FLAG_OBJLU (1<<2) +#define SPIFFS_CACHE_FLAG_OBJIX (1<<3) +#define SPIFFS_CACHE_FLAG_DATA (1<<4) +#define SPIFFS_CACHE_FLAG_TYPE_WR (1<<7) + +#define SPIFFS_CACHE_PAGE_SIZE(fs) \ + (sizeof(spiffs_cache_page) + SPIFFS_CFG_LOG_PAGE_SZ(fs)) + +#define spiffs_get_cache(fs) \ + ((spiffs_cache *)((fs)->cache)) + +#define spiffs_get_cache_page_hdr(fs, c, ix) \ + ((spiffs_cache_page *)(&((c)->cpages[(ix) * SPIFFS_CACHE_PAGE_SIZE(fs)]))) + +#define spiffs_get_cache_page(fs, c, ix) \ + ((u8_t *)(&((c)->cpages[(ix) * SPIFFS_CACHE_PAGE_SIZE(fs)])) + sizeof(spiffs_cache_page)) + +// cache page struct +typedef struct { + // cache flags + u8_t flags; + // cache page index + u8_t ix; + // last access of this cache page + u32_t last_access; + union { + // type read cache + struct { + // read cache page index + spiffs_page_ix pix; + }; +#if SPIFFS_CACHE_WR + // type write cache + struct { + // write cache + spiffs_obj_id obj_id; + // offset in cache page + u32_t offset; + // size of cache page + u16_t size; + }; +#endif + }; +} spiffs_cache_page; + +// cache struct +typedef struct { + u8_t cpage_count; + u32_t last_access; + u32_t cpage_use_map; + u32_t cpage_use_mask; + u8_t *cpages; +} spiffs_cache; + +#endif + + +// spiffs nucleus file descriptor +typedef struct { + // the filesystem of this descriptor + spiffs *fs; + // number of file descriptor - if 0, the file descriptor is closed + spiffs_file file_nbr; + // object id - if SPIFFS_OBJ_ID_ERASED, the file was deleted + spiffs_obj_id obj_id; + // size of the file + u32_t size; + // cached object index header page index + spiffs_page_ix objix_hdr_pix; + // cached offset object index page index + spiffs_page_ix cursor_objix_pix; + // cached offset object index span index + spiffs_span_ix cursor_objix_spix; + // current absolute offset + u32_t offset; + // current file descriptor offset + u32_t fdoffset; + // fd flags + spiffs_flags flags; +#if SPIFFS_CACHE_WR + spiffs_cache_page *cache_page; +#endif +} spiffs_fd; + + +// object structs + +// page header, part of each page except object lookup pages +// NB: this is always aligned when the data page is an object index, +// as in this case struct spiffs_page_object_ix is used +typedef struct __attribute(( packed )) { + // object id + spiffs_obj_id obj_id; + // object span index + spiffs_span_ix span_ix; + // flags + u8_t flags; +} spiffs_page_header; + +// object index header page header +typedef struct __attribute(( packed )) +#if SPIFFS_ALIGNED_OBJECT_INDEX_TABLES + __attribute(( aligned(sizeof(spiffs_page_ix)) )) +#endif +{ + // common page header + spiffs_page_header p_hdr; + // alignment + u8_t _align[4 - (sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3)]; + // size of object + u32_t size; + // type of object + spiffs_obj_type type; + // name of object + u8_t name[SPIFFS_OBJ_NAME_LEN]; +} spiffs_page_object_ix_header; + +// object index page header +typedef struct __attribute(( packed )) { + spiffs_page_header p_hdr; + u8_t _align[4 - (sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3)]; +} spiffs_page_object_ix; + +// callback func for object lookup visitor +typedef s32_t (*spiffs_visitor_f)(spiffs *fs, spiffs_obj_id id, spiffs_block_ix bix, int ix_entry, + u32_t user_data, void *user_p); + + +#if SPIFFS_CACHE +#define _spiffs_rd(fs, op, fh, addr, len, dst) \ + spiffs_phys_rd((fs), (op), (fh), (addr), (len), (dst)) +#define _spiffs_wr(fs, op, fh, addr, len, src) \ + spiffs_phys_wr((fs), (op), (fh), (addr), (len), (src)) +#else +#define _spiffs_rd(fs, op, fh, addr, len, dst) \ + spiffs_phys_rd((fs), (addr), (len), (dst)) +#define _spiffs_wr(fs, op, fh, addr, len, src) \ + spiffs_phys_wr((fs), (addr), (len), (src)) +#endif + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +// --------------- + +s32_t spiffs_phys_rd( + spiffs *fs, +#if SPIFFS_CACHE + u8_t op, + spiffs_file fh, +#endif + u32_t addr, + u32_t len, + u8_t *dst); + +s32_t spiffs_phys_wr( + spiffs *fs, +#if SPIFFS_CACHE + u8_t op, + spiffs_file fh, +#endif + u32_t addr, + u32_t len, + u8_t *src); + +s32_t spiffs_phys_cpy( + spiffs *fs, + spiffs_file fh, + u32_t dst, + u32_t src, + u32_t len); + +s32_t spiffs_phys_count_free_blocks( + spiffs *fs); + +s32_t spiffs_obj_lu_find_entry_visitor( + spiffs *fs, + spiffs_block_ix starting_block, + int starting_lu_entry, + u8_t flags, + spiffs_obj_id obj_id, + spiffs_visitor_f v, + u32_t user_data, + void *user_p, + spiffs_block_ix *block_ix, + int *lu_entry); + +s32_t spiffs_erase_block( + spiffs *fs, + spiffs_block_ix bix); + +// --------------- + +s32_t spiffs_obj_lu_scan( + spiffs *fs); + +s32_t spiffs_obj_lu_find_free_obj_id( + spiffs *fs, + spiffs_obj_id *obj_id, + u8_t *conflicting_name); + +s32_t spiffs_obj_lu_find_free( + spiffs *fs, + spiffs_block_ix starting_block, + int starting_lu_entry, + spiffs_block_ix *block_ix, + int *lu_entry); + +s32_t spiffs_obj_lu_find_id( + spiffs *fs, + spiffs_block_ix starting_block, + int starting_lu_entry, + spiffs_obj_id obj_id, + spiffs_block_ix *block_ix, + int *lu_entry); + +s32_t spiffs_obj_lu_find_id_and_span( + spiffs *fs, + spiffs_obj_id obj_id, + spiffs_span_ix spix, + spiffs_page_ix exclusion_pix, + spiffs_page_ix *pix); + +s32_t spiffs_obj_lu_find_id_and_span_by_phdr( + spiffs *fs, + spiffs_obj_id obj_id, + spiffs_span_ix spix, + spiffs_page_ix exclusion_pix, + spiffs_page_ix *pix); + +// --------------- + +s32_t spiffs_page_allocate_data( + spiffs *fs, + spiffs_obj_id obj_id, + spiffs_page_header *ph, + u8_t *data, + u32_t len, + u32_t page_offs, + u8_t finalize, + spiffs_page_ix *pix); + +s32_t spiffs_page_move( + spiffs *fs, + spiffs_file fh, + u8_t *page_data, + spiffs_obj_id obj_id, + spiffs_page_header *page_hdr, + spiffs_page_ix src_pix, + spiffs_page_ix *dst_pix); + +s32_t spiffs_page_delete( + spiffs *fs, + spiffs_page_ix pix); + +// --------------- + +s32_t spiffs_object_create( + spiffs *fs, + spiffs_obj_id obj_id, + u8_t name[SPIFFS_OBJ_NAME_LEN], + spiffs_obj_type type, + spiffs_page_ix *objix_hdr_pix); + +s32_t spiffs_object_update_index_hdr( + spiffs *fs, + spiffs_fd *fd, + spiffs_obj_id obj_id, + spiffs_page_ix objix_hdr_pix, + u8_t *new_objix_hdr_data, + u8_t name[SPIFFS_OBJ_NAME_LEN], + u32_t size, + spiffs_page_ix *new_pix); + +void spiffs_cb_object_event( + spiffs *fs, + spiffs_fd *fd, + int ev, + spiffs_obj_id obj_id, + spiffs_span_ix spix, + spiffs_page_ix new_pix, + u32_t new_size); + +s32_t spiffs_object_open_by_id( + spiffs *fs, + spiffs_obj_id obj_id, + spiffs_fd *f, + spiffs_flags flags, + spiffs_mode mode); + +s32_t spiffs_object_open_by_page( + spiffs *fs, + spiffs_page_ix pix, + spiffs_fd *f, + spiffs_flags flags, + spiffs_mode mode); + +s32_t spiffs_object_append( + spiffs_fd *fd, + u32_t offset, + u8_t *data, + u32_t len); + +s32_t spiffs_object_modify( + spiffs_fd *fd, + u32_t offset, + u8_t *data, + u32_t len); + +s32_t spiffs_object_read( + spiffs_fd *fd, + u32_t offset, + u32_t len, + u8_t *dst); + +s32_t spiffs_object_truncate( + spiffs_fd *fd, + u32_t new_len, + u8_t remove_object); + +s32_t spiffs_object_find_object_index_header_by_name( + spiffs *fs, + u8_t name[SPIFFS_OBJ_NAME_LEN], + spiffs_page_ix *pix); + +// --------------- + +s32_t spiffs_gc_check( + spiffs *fs, + u32_t len); + +s32_t spiffs_gc_erase_page_stats( + spiffs *fs, + spiffs_block_ix bix); + +s32_t spiffs_gc_find_candidate( + spiffs *fs, + spiffs_block_ix **block_candidate, + int *candidate_count, + char fs_crammed); + +s32_t spiffs_gc_clean( + spiffs *fs, + spiffs_block_ix bix); + +s32_t spiffs_gc_quick( + spiffs *fs, u16_t max_free_pages); + +// --------------- + +s32_t spiffs_fd_find_new( + spiffs *fs, + spiffs_fd **fd); + +s32_t spiffs_fd_return( + spiffs *fs, + spiffs_file f); + +s32_t spiffs_fd_get( + spiffs *fs, + spiffs_file f, + spiffs_fd **fd); + +#if SPIFFS_CACHE +void spiffs_cache_init( + spiffs *fs); + +void spiffs_cache_drop_page( + spiffs *fs, + spiffs_page_ix pix); + +#if SPIFFS_CACHE_WR +spiffs_cache_page *spiffs_cache_page_allocate_by_fd( + spiffs *fs, + spiffs_fd *fd); + +void spiffs_cache_fd_release( + spiffs *fs, + spiffs_cache_page *cp); + +spiffs_cache_page *spiffs_cache_page_get_by_fd( + spiffs *fs, + spiffs_fd *fd); +#endif +#endif + +s32_t spiffs_lookup_consistency_check( + spiffs *fs, + u8_t check_all_objects); + +s32_t spiffs_page_consistency_check( + spiffs *fs); + +s32_t spiffs_object_index_consistency_check( + spiffs *fs); + +#endif /* SPIFFS_NUCLEUS_H_ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_bigint.h b/Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_bigint.h new file mode 100644 index 0000000..99f5415 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_bigint_impl.h b/Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_bigint_impl.h new file mode 100644 index 0000000..fef6e03 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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 int64_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/Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_compat-1.0.h b/Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_compat-1.0.h new file mode 100644 index 0000000..d0438a2 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_compat-1.0.h @@ -0,0 +1,100 @@ +/* + * ssl_compat-1.0.h + * + * Created on: Sep 7, 2015 + * Author: liuhan + */ + +#ifndef SSL_COMPAT_1_0_H_ +#define SSL_COMPAT_1_0_H_ + +#include "ssl/ssl_platform.h" + +/*encapsulation the function based on the espressif platform*/ + +#define SSL_library_init(a) esp_ssl_library_init(a) +#define SSL_new(a) esp_ssl_new(a) +#define SSL_set_fd(a,b) esp_ssl_set_fd(a,b) +#define SSL_free(a) esp_ssl_free(a) +#define SSL_connect(a) esp_ssl_connect(a) +#define SSL_accept(a) esp_ssl_accept(a) +#define SSL_read(a,b,c) esp_ssl_read(a,b,c) +#define SSL_write(a,b,c) esp_ssl_write(a,b,c) +#define SSL_get_peer_certificate(a) esp_ssl_get_peer_certificate(a) +#define SSL_get_verify_result(a) esp_ssl_get_verify_result(a) +#define SSL_get_error(a,b) esp_ssl_get_error(a,b) +#define SSL_pending(a) esp_ssl_pending(a) +#define SSL_fragment_length_negotiation(a,b) esp_ssl_fragment_length_negotiation(a,b) + +#define SSL_CTX_new(a) esp_ssl_CTX_new(a) +#define SSL_CTX_set_option(a,b) esp_ssl_CTX_set_option(a,b) +#define SSL_CTX_free(a) esp_ssl_CTX_free(a) +#define SSL_CTX_load_verify_locations(a,b,c) esp_ssl_CTX_load_verify_locations(a,b,c) +#define SSL_CTX_set_default_verify_paths(a) esp_ssl_CTX_set_default_verify_paths(a) +#define SSL_CTX_use_certificate_chain_file(a,b) esp_ssl_CTX_use_certificate_chain_file(a,b) +#define SSL_CTX_use_PrivateKey_file(a,b,c) esp_ssl_CTX_use_PrivateKey_file(a,b,c) +#define SSL_CTX_check_private_key(a) esp_ssl_CTX_check_private_key(a) +#define SSL_CTX_set_verify(a,b,c) esp_ssl_CTX_set_verify(a) +#define SSL_CTX_set_verify_depth(a,b) esp_ssl_CTX_set_verify_depth(a) +#define SSL_CTX_set_client_cert_cb esp_ssl_CTX_set_client_cert_cb +#define SSL_CTX_set_mode(a) esp_ssl_CTX_set_mode(a) + +#define X509_free(a) esp_X509_free(a) +#define X509_STORE_CTX_get_current_cert(a) esp_X509_store_ctx_get_current_cert(a) +#define X509_NAME_oneline(a,b,c) esp_X509_NAME_oneline(a,b,c) +#define X509_get_issuer_name(a) esp_X509_get_issuer_name(a) +#define X509_get_subject_name(a) esp_X509_get_subject_name(a) +#define X509_STORE_CTX_get_error_depth(a) esp_X509_STORE_CTX_get_error_depth(a) +#define X509_STORE_CTX_get_error(a) esp_X509_STORE_CTX_get_error(a) +#define X509_verify_cert_error_string(a) esp_X509_verify_cert_error_string(a) + +#define EVP_sha1(a) esp_EVP_sha1(a) +#define EVP_DigestInit(a,b) esp_EVP_DigestInit(a,b) +#define EVP_DigestUpdate(a,b,c) esp_EVP_DigestUpdate(a,b,c) +#define EVP_DigestFinal(a,b,c) esp_EVP_DigestFinal(a,b,c) +#define EVP_cleanup(a) esp_EVP_cleanup(a) + +#define ERR_get_error(a) esp_ERR_get_error(a) +#define ERR_error_string_n(a,b,c) esp_ERR_error_string_n(a,b,c) +#define ERR_error_string(a,b) esp_ERR_error_string(a,b) +#define ERR_free_strings(a) esp_ERR_free_strings(a) +#define strerror(a) esp_ERR_strerror(a) + +#define CRYPTO_cleanup_all_ex_data(a) esp_CRYPTO_cleanup_all_ex_data(a) + +#define base64_encode(a,b,c,d,e) esp_base64_encode(a,b,c,d,e) + +#define TLSv1_client_method(a) esp_TLSv1_client_method(a) +//#if TLSv1_1__method +#define TLSv1_1_client_method(a) esp_TLSv1_1_client_method(a) +//#endif +#define SSLv3_client_method(a) esp_SSLv3_client_method(a) +#define SSLv23_client_method(a) esp_SSLv23_client_method(a) + +#define TLSv1_server_method(a) esp_TLSv1_server_method(a) +//#if TLSv1_1__method +#define TLSv1_1_server_method(a) esp_TLSv1_1_server_method(a) +//#endif +#define SSLv3_server_method(a) esp_SSLv3_server_method(a) +#define SSLv23_server_method(a) esp_SSLv23_server_method(a) + +/*encapsulation the protocol based on the espressif platform*/ +#define SSL_ERROR_NONE ESP_SSL_ERROR_NONE +#define SSL_ERROR_WANT_WRITE ESP_SSL_ERROR_WANT_WRITE +#define SSL_ERROR_WANT_READ ESP_SSL_ERROR_WANT_READ +#define SSL_ERROR_WANT_X509_LOOKUP ESP_SSL_ERROR_WANT_X509_LOOKUP +#define SSL_ERROR_SYSCALL ESP_SSL_ERROR_SYSCALL +#define SSL_ERROR_ZERO_RETURN ESP_SSL_ERROR_ZERO_RETURN +#define SSL_ERROR_SSL ESP_SSL_ERROR_SSL +#define SSL_FILETYPE_PEM ESP_SSL_FILETYPE_PEM +#define SSL_VERIFY_PEER ESP_SSL_VERIFY_PEER +#define EVP_MAX_MD_SIZE ESP_EVP_MAX_MD_SIZE +#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT ESP_SSL_VERIFY_FAIL_IF_NO_PEER_CERT +#define SSL_MODE_ENABLE_PARTIAL_WRITE ESP_SSL_MODE_ENABLE_PARTIAL_WRITE +#define SSL_VERIFY_NONE ESP_SSL_VERIFY_NONE +#define SSL_ERROR_WANT_CONNECT ESP_SSL_ERROR_WANT_CONNECT +#define SSL_ERROR_WANT_ACCEPT ESP_SSL_ERROR_WANT_ACCEPT + +/*encapsulation the protocol based on the different platform*/ + +#endif /* SSL_COMPAT_1_0_H_ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_config.h b/Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_config.h new file mode 100644 index 0000000..8481dbe --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_config.h @@ -0,0 +1,147 @@ +/* + * 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 +#define CONFIG_SSL_CTX_MUTEXING 1 +#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 0 + +/* Mutexing definitions */ + +#if defined(CONFIG_SSL_CTX_MUTEXING) +#include "lwip/sys.h" +#include "arch/sys_arch.h" +#define SSL_CTX_MUTEX_TYPE sys_mutex_t +#define SSL_CTX_MUTEX_INIT(A) sys_mutex_new(&A) +#define SSL_CTX_MUTEX_DESTROY(A) sys_mutex_free(&A) +#define SSL_CTX_LOCK(A) sys_mutex_lock(&A) +#define SSL_CTX_UNLOCK(A) sys_mutex_unlock(&A) +#else /* no mutexing */ +#define SSL_CTX_MUTEX_INIT(A) +#define SSL_CTX_MUTEX_DESTROY(A) +#define SSL_CTX_LOCK(A) +#define SSL_CTX_UNLOCK(A) +#endif + +/* + * 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/Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_crypto.h b/Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_crypto.h new file mode 100644 index 0000000..5d90227 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_crypto_misc.h b/Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_crypto_misc.h new file mode 100644 index 0000000..1c45db1 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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 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/Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_os_port.h b/Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_os_port.h new file mode 100644 index 0000000..7b5ebf8 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_os_port.h @@ -0,0 +1,146 @@ +/* + * 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 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 "esp_common.h" +#include "lwip/apps/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 { +// long tv_sec; /* seconds */ +// 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 + +#ifdef MEMLEAK_DEBUG +#define SSL_MALLOC(size) ax_malloc(size, mem_debug_file, __LINE__) +#define SSL_REALLOC(mem_ref,size) ax_realloc(mem_ref, size, mem_debug_file, __LINE__) +#define SSL_CALLOC(element, size) ax_calloc(element, size, mem_debug_file, __LINE__) +#define SSL_ZALLOC(size) ax_zalloc(size, mem_debug_file, __LINE__) +#define SSL_FREE(mem_ref) ax_free(mem_ref, mem_debug_file, __LINE__) +#else +#define SSL_MALLOC(size) malloc(size) +#define SSL_REALLOC(mem_ref,size) realloc(mem_ref, size) +#define SSL_CALLOC(element, size) calloc(element, size) +#define SSL_ZALLOC(size) zalloc(size) +#define SSL_FREE(mem_ref) free(mem_ref) +#endif + +#if 0 +#define FILE_NAME_LENGTH 25 +//#define OUTPUT_FILE "leak_info.txt" //¡ä?¡¤??¨²¡ä?D1??¦Ì?D??¡é +//#define SSL_MALLOC(size) xmalloc (size, __FILE__, __LINE__) //??D?¨º¦Ì??malloc?¡écalloco¨ªfree +//#define CALLOC(elements, size) xcalloc (elements, size, __FILE__, __LINE__) +//#define FREE(mem_ref) xfree(mem_ref) + +struct _MEM_INFO +{ + void *address; + unsigned int size; + char file_name[FILE_NAME_LENGTH]; + unsigned int line; +}; + +typedef struct _MEM_INFO MEM_INFO; + +struct _MEM_LEAK { + MEM_INFO mem_info; + struct _MEM_LEAK * next; +}; + +typedef struct _MEM_LEAK MEM_LEAK; + +void add(MEM_INFO alloc_info); +void erase(unsigned pos); +void clear(void); + +void * xmalloc(unsigned int size, const char * file, unsigned int line); +void * xcalloc(unsigned int elements, unsigned int size, const char * file, unsigned int line); +void xfree(void * mem_ref); + +void add_mem_info (void * mem_ref, unsigned int size, const char * file, unsigned int line); +void remove_mem_info (void * mem_ref); +void report_mem_leak(void); +#endif +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_platform.h b/Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_platform.h new file mode 100644 index 0000000..5735322 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_platform.h @@ -0,0 +1,53 @@ +/* + * ssl_platom.h + * + * Created on: Sep 7, 2015 + * Author: liuhan + */ + +#ifndef SSL_PLATOM_H_ +#define SSL_PLATOM_H_ + +#include "ssl/ssl_os_port.h" +#include "ssl/ssl_ssl.h" +#include "ssl/ssl_tls1.h" + +typedef void * (*ssl_func_type_t)(void); +typedef void * (*bio_func_type_t)(void); + +typedef struct +{ + ssl_func_type_t ssl_func_type; +} PLATOM_CTX; + +#define PLATOM_CTX_ATTR ((PLATOM_CTX *)ssl_ctx->bonus_attr) + +/*encapsulation the structure based on the espressif platform*/ +struct _MD_CTX +{ + unsigned char cksum[16]; /* checksum of the data block */ + unsigned char state[48]; /* intermediate digest state */ + unsigned char buffer[16]; /* data block being processed */ + int left; /* amount of data in buffer */ +}; + +typedef struct _MD_CTX EVP_MD_CTX; +typedef unsigned char EVP_MD; +typedef struct _x509_ctx X509; +typedef struct _x509_ctx X509_STORE_CTX; +//typedef struct _SSL SSL; +//typedef struct _SSL_CTX SSL_CTX; + +#define ESP_SSL_ERROR_NONE 0 +#define ESP_SSL_ERROR_WANT_WRITE 1 +#define ESP_SSL_ERROR_WANT_READ 2 +#define ESP_SSL_ERROR_WANT_X509_LOOKUP 3 +#define ESP_SSL_ERROR_SYSCALL 4 +#define ESP_SSL_ERROR_ZERO_RETURN 5 +#define ESP_SSL_ERROR_SSL 6 +#define ESP_SSL_FILETYPE_PEM 10 +#define ESP_SSL_VERIFY_PEER 11 +#define ESP_EVP_MAX_MD_SIZE 6 +#define ESP_SSL_VERIFY_FAIL_IF_NO_PEER_CERT 4 + +#endif /* SSL_PLATOM_H_ */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_ssl.h b/Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_ssl.h new file mode 100644 index 0000000..4564533 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_ssl.h @@ -0,0 +1,500 @@ +/* + * 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 +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); + +/** + * @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); + +/** + * @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/Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_tls1.h b/Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_tls1.h new file mode 100644 index 0000000..48e90b8 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_tls1.h @@ -0,0 +1,313 @@ +/* + * 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 "ssl/ssl_crypto.h" +#include "ssl/ssl_crypto_misc.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 1460 +#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; } + +/*Max Fragment Length Negotiation*/ +enum { + SSL_MAX_FRAG_LEN_NONE, + SSL_MAX_FRAG_LEN_512, + SSL_MAX_FRAG_LEN_1024, + SSL_MAX_FRAG_LEN_2048, + SSL_MAX_FRAG_LEN_4096, + SSL_MAX_FRAG_LEN_8192, + SSL_MAX_FRAG_LEN_INVALID +}; + +/* 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; + int16_t next_state; + int16_t hs_status; + DISPOSABLE_CTX *dc; /* temporary data which we'll get rid of soon */ + int client_fd; + const cipher_info_t *cipher_info; + void *encrypt_ctx; + void *decrypt_ctx; + uint8_t *bm_all_data; + uint32_t max_fragme_length; + 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); +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); + +/*Max Fragment Length Negotiation*/ +bool ssl_fragment_length_negotiation(SSL* ssl, int fragmet_level); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_version.h b/Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_version.h new file mode 100644 index 0000000..85c1640 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/include/ssl/ssl_version.h @@ -0,0 +1 @@ +#define AXTLS_VERSION "1.5.3" diff --git a/Distrib/ESPressif/RTOS/1.5.0/ld/eagle.app.v6.common.ld b/Distrib/ESPressif/RTOS/1.5.0/ld/eagle.app.v6.common.ld new file mode 100644 index 0000000..3af39d7 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/ld/eagle.app.v6.common.ld @@ -0,0 +1,219 @@ +/* This linker script generated from xt-genldscripts.tpp for LSP . */ +/* Linker Script for ld -N */ + +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 + + .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) + *libfreertos.a:(.literal .text .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 + + .irom0.text : ALIGN(4) + { + _irom0_text_start = ABSOLUTE(.); + *libuser.a:(.rodata.* .rodata) + *libcirom.a:(.rodata.* .rodata) + *libmbedtls.a:(.rodata.* .rodata) + *libssl.a:(.rodata.* .rodata) + *libopenssl.a:(.rodata.* .rodata) + *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text) + *(.literal.* .text.*) + _irom0_text_end = ABSOLUTE(.); + } >irom0_0_seg :irom0_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(.); + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + *(.rodata1) + __XT_EXCEPTION_TABLE__ = ABSOLUTE(.); + *(.xt_except_table) + *(.gcc_except_table) + *(.gnu.linkonce.e.*) + *(.gnu.version_r) + *(.eh_frame) + . = (. + 3) & ~ 3; + /* C++ constructor and destructor tables, properly ordered: */ + __init_array_start = ABSOLUTE(.); + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + __init_array_end = ABSOLUTE(.); + 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 + + .UserExceptionVector.literal : AT(LOADADDR(.rodata) + (ADDR(.UserExceptionVector.literal) - ADDR(.rodata))) ALIGN(4) + { + _UserExceptionVector_literal_start = ABSOLUTE(.); + *(.UserExceptionVector.literal) + _UserExceptionVector_literal_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; */ + + .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/Distrib/ESPressif/RTOS/1.5.0/ld/eagle.app.v6.ld b/Distrib/ESPressif/RTOS/1.5.0/ld/eagle.app.v6.ld new file mode 100644 index 0000000..6bc53f8 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/ld/eagle.app.v6.ld @@ -0,0 +1,32 @@ +/* eagle.flash.bin @ 0x00000 */ +/* eagle.irom0text.bin @ 0x20000 */ + +/* Flash Map, support 512KB/1MB/2MB/4MB SPI Flash */ +/* |......|..............................|..........................|.....|....| */ +/* ^ ^ ^ ^ ^ */ +/* |_flash.bin start(0x0000) |_irom0text.bin start(0x20000) | */ +/* |_flash.bin end |_irom0text.bin end */ +/* |_system param area(0x7b000) */ + +/* NOTICE: */ +/* 1. You can change irom0 org, but MUST make sure irom0text.bin start not overlap flash.bin end. */ +/* 2. You can change irom0 len, but MUST make sure irom0text.bin end not overlap system param area. */ +/* 3. Space between flash.bin end and irom0text.bin start can be used as user param area. */ +/* 4. Space between irom0text.bin end and system param area can be used as user param area. */ +/* 5. Make sure irom0text.bin end < 0x100000 */ +/* 6. system param area: */ +/* 1>. 512KB--->0x07b000 */ +/* 2>. 1MB----->0x0fb000 */ +/* 3>. 2MB----->0x1fb000 */ +/* 4>. 4MB----->0x3fb000 */ +/* 7. Don't change any other seg. */ + +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x18000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40220000, len = 0x5C000 +} + +INCLUDE "../ld/eagle.app.v6.common.ld" \ No newline at end of file diff --git a/Distrib/ESPressif/RTOS/1.5.0/ld/eagle.app.v6.new.1024.app1.ld b/Distrib/ESPressif/RTOS/1.5.0/ld/eagle.app.v6.new.1024.app1.ld new file mode 100644 index 0000000..c1604bf --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/ld/eagle.app.v6.new.1024.app1.ld @@ -0,0 +1,23 @@ +/* user1.bin @ 0x1000 */ + +/* Flash Map (512KB + 512KB), support 1MB/2MB/4MB SPI Flash */ +/* |..|........................|.....|.....|..|........................|.....|....| */ +/* ^ ^ ^ ^ ^ ^ ^ ^ */ +/* |_boot start(0x0000) | | |_pad start(0x80000) | | */ +/* |_user1 start(0x1000) |_user1 end |_user2 start(0x81000) |_user2 end */ +/* |_system param symmetric area(0x7b000) |_system param area(0xfb000) */ + +/* NOTICE: */ +/* 1. You can change irom0 len, but MUST make sure user1 end not overlap system param symmetric area. */ +/* 2. Space between user1 end and pad start can be used as user param area. */ +/* 3. Don't change any other seg. */ + +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x18000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40201010, len = 0x6B000 +} + +INCLUDE "../ld/eagle.app.v6.common.ld" diff --git a/Distrib/ESPressif/RTOS/1.5.0/ld/eagle.app.v6.new.1024.app2.ld b/Distrib/ESPressif/RTOS/1.5.0/ld/eagle.app.v6.new.1024.app2.ld new file mode 100644 index 0000000..7da7160 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/ld/eagle.app.v6.new.1024.app2.ld @@ -0,0 +1,23 @@ +/* user2.bin @ 0x81000 */ + +/* Flash Map (512KB + 512KB), support 1MB/2MB/4MB SPI Flash */ +/* |..|........................|.....|.....|..|........................|.....|....| */ +/* ^ ^ ^ ^ ^ ^ ^ ^ */ +/* |_boot start(0x0000) | | |_pad start(0x80000) | | */ +/* |_user1 start(0x1000) |_user1 end |_user2 start(0x81000) |_user2 end */ +/* |_system param symmetric area(0x7b000) |_system param area(0xfb000) */ + +/* NOTICE: */ +/* 1. You can change irom0 len, but MUST make sure user2 end not overlap system param area. */ +/* 2. Space between user2 end and system param area can be used as user param area. */ +/* 3. Don't change any other seg. */ + +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x18000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40281010, len = 0x6B000 +} + +INCLUDE "../ld/eagle.app.v6.common.ld" diff --git a/Distrib/ESPressif/RTOS/1.5.0/ld/eagle.app.v6.new.2048.ld b/Distrib/ESPressif/RTOS/1.5.0/ld/eagle.app.v6.new.2048.ld new file mode 100644 index 0000000..958d19f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/ld/eagle.app.v6.new.2048.ld @@ -0,0 +1,25 @@ +/* user1.bin @ 0x1000, user2.bin @ 0x10000 */ + +/* Flash Map (1024KB + 1024KB), support 2MB/4MB SPI Flash */ +/* |..|........................|.....|.....|..|........................|.....|....| */ +/* ^ ^ ^ ^ ^ ^ ^ ^ */ +/* |_boot start(0x0000) | | |_pad start(0x100000) | | */ +/* |_user1 start(0x1000) |_user1 end |_user2 start(0x101000) |_user2 end */ +/* |_system param symmetric area(0xfb000) |_system param area(0x1fb000) */ + +/* NOTICE: */ +/* 1. You can change irom0 len, but MUST make sure user1 end not overlap system param symmetric area. */ +/* 2. Space between user1 end and pad start can be used as user param area. */ +/* 3. Space between user2 end and system param area can be used as user param area. */ +/* 4. Don't change any other seg. */ +/* 5. user1.bin and user2.bin are same in this mode, so upgrade only need one of them. */ + +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x18000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40201010, len = 0xE0000 +} + +INCLUDE "../ld/eagle.app.v6.common.ld" diff --git a/Distrib/ESPressif/RTOS/1.5.0/ld/eagle.app.v6.new.512.app1.ld b/Distrib/ESPressif/RTOS/1.5.0/ld/eagle.app.v6.new.512.app1.ld new file mode 100644 index 0000000..a08db22 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/ld/eagle.app.v6.new.512.app1.ld @@ -0,0 +1,23 @@ +/* user1.bin @ 0x1000 */ + +/* Flash Map (256KB + 256KB), support 512KB SPI Flash */ +/* |..|........................|.....|.....|..|........................|.....|....| */ +/* ^ ^ ^ ^ ^ ^ ^ ^ */ +/* |_boot start(0x0000) | | |_pad start(0x40000) | | */ +/* |_user1 start(0x1000) |_user1 end |_user2 start(0x41000) |_user2 end */ +/* |_system param symmetric area(0x3b000) |_system param area(0x7b000) */ + +/* NOTICE: */ +/* 1. You can change irom0 len, but MUST make sure user1 end not overlap system param symmetric area. */ +/* 2. Space between user1 end and pad start can be used as user param area. */ +/* 3. Don't change any other seg. */ + +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x18000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40201010, len = 0x2B000 +} + +INCLUDE "../ld/eagle.app.v6.common.ld" diff --git a/Distrib/ESPressif/RTOS/1.5.0/ld/eagle.app.v6.new.512.app2.ld b/Distrib/ESPressif/RTOS/1.5.0/ld/eagle.app.v6.new.512.app2.ld new file mode 100644 index 0000000..1cd0d2b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/ld/eagle.app.v6.new.512.app2.ld @@ -0,0 +1,23 @@ +/* user2.bin @ 0x41000 */ + +/* Flash Map (256KB + 256KB), support 512KB SPI Flash */ +/* |..|........................|.....|.....|..|........................|.....|....| */ +/* ^ ^ ^ ^ ^ ^ ^ ^ */ +/* |_boot start(0x0000) | | |_pad start(0x40000) | | */ +/* |_user1 start(0x1000) |_user1 end |_user2 start(0x41000) |_user2 end */ +/* |_system param symmetric area(0x3b000) |_system param area(0x7b000) */ + +/* NOTICE: */ +/* 1. You can change irom0 len, but MUST make sure user2 end not overlap system param area. */ +/* 2. Space between user2 end and system param area can be used as user param area. */ +/* 3. Don't change any other seg. */ + +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x18000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40241010, len = 0x2B000 +} + +INCLUDE "../ld/eagle.app.v6.common.ld" diff --git a/Distrib/ESPressif/RTOS/1.5.0/ld/eagle.rom.addr.v6.ld b/Distrib/ESPressif/RTOS/1.5.0/ld/eagle.rom.addr.v6.ld new file mode 100644 index 0000000..5a66e5d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/ld/eagle.rom.addr.v6.ld @@ -0,0 +1,58 @@ +PROVIDE ( SPI_sector_erase = 0x400040c0 ); +PROVIDE ( SPI_page_program = 0x40004174 ); +PROVIDE ( SPI_read_data = 0x400042ac ); +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 ( Disable_QMode = 0x40004508 ); + +PROVIDE ( Cache_Read_Enable = 0x40004678 ); +PROVIDE ( Cache_Read_Disable = 0x400047f0 ); + +PROVIDE ( lldesc_build_chain = 0x40004f40 ); +PROVIDE ( lldesc_num2link = 0x40005050 ); +PROVIDE ( lldesc_set_owner = 0x4000507c ); + +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 ( bzero = 0x40002ae8 ); +PROVIDE ( memcmp = 0x400018d4 ); +PROVIDE ( memcpy = 0x400018b4 ); +PROVIDE ( memmove = 0x400018c4 ); +PROVIDE ( memset = 0x400018a4 ); + +PROVIDE ( strcmp = 0x40002aa8 ); +PROVIDE ( strcpy = 0x40002a88 ); +PROVIDE ( strlen = 0x40002ac8 ); +PROVIDE ( strncmp = 0x40002ab8 ); +PROVIDE ( strncpy = 0x40002a98 ); +PROVIDE ( strstr = 0x40002ad8 ); + +PROVIDE ( gpio_input_get = 0x40004cf0 ); +PROVIDE ( gpio_pin_wakeup_disable = 0x40004ed4 ); +PROVIDE ( gpio_pin_wakeup_enable = 0x40004e90 ); \ No newline at end of file diff --git a/Distrib/ESPressif/RTOS/1.5.0/lib/libairkiss.a b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/lib/libcirom.a b/Distrib/ESPressif/RTOS/1.5.0/lib/libcirom.a new file mode 100644 index 0000000000000000000000000000000000000000..a93892963cb61dc9b22a32a30acb296c606f8849 GIT binary patch literal 5159208 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 H5&fwZj_^NdQ(XTLPeCLbc&*MsE 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
    Ur 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

    hd*_g^O(8eV2_a%8sTw`Fgp05 zpCF9cJF-Ic4Xx|?rbp=TS%>%e{OTvlm0?v3b7D#`Izl2@<+=T--8x51L;NU11?wC! ztV>m&tR%$qo=oa7`K79L!$6FYbk9T1%H4pK&Q>diB!6y~%Y=L~73i5r=iEF&hkb-2jNTxx}^6*)UA0rQy(L=q1nJ(vjbUkaL%MljkU5~J+c;{s)B{5Zn%LPYR46t)M z1|Fh3g4$UCha=-_+JwH>qXQ)Y=)7nqEaa$=wIRoiw3;v5ifu zb$EoTS#v0rvQrMdhOr~YdLP_VD4Wc#@p88^q{AS8+PeCx@7q86Y6Pu4HGUE$+4*E;u zH%AzL_+ggBR&pl{bDS=oa&L6YL}PIT`+P?CP0HU&(UU*MN|wKR;gFw`OA9;hbMpbI=4FGQ}UGf8OGqcsrzE2L)<#}1UR|{Jl z!3YINRRC`+>`J*qe)o&tSoy(EFyY70!{P`=pAo;Ufrr8E3Jdu?B_@oE;m6q1@^`Z^ zaR|eVSHN6jA~%rhHg6lDe}uz&nJ9kH!H@rnRxjQ6jQ&OZ`m$$qk;W#qN{sg! z9`GBgi?(R*kYKb)g%|4S#`9qsmfz&sBw)7Q>-)8=^$E^SU(9pDKb^K9Y&kI>hCJn1qfmN`k6;Z*@X zE5LlujOM%mUl3r<_cWR<0e&}F-yF<)by=N!M%exVxNnMoaNh|0?*RL_zXtm}3nqMc z9>$Yk!+K2<9M=E1z<*+Zd8aMzya3amng59aJ|)2JIdYSsjai;)8y5F`y_n{|L6~_t z<}Dr*{SuG)USVG9d_C6hTi?*WZnK-1_qK;;dTrm&|DMRlT8($Q%VB9=es)?j^GRh# zX9rAGDR$`NJawPjhYos*vb@+C-@Gpwy+_Q=DgUL4nbO5G)jj2&dAoDOgA$40*9~jTg2fDfW@_}w{ zzCvFVH#e^wpJU%JYPT|bEQ#ivZb(aacR&2vFCiUaO9a5=S zX%%)rX}&%%n6Kw;zFv8V@---AzIZtEb?J*IS!ZY(ny+KI*C1Mj<(_hv(<}jwptoz*led^kGD4cY8UY73F!WKs`x>@|H0Nz;Gm2!vmvP^^7vGRkT8#Ty= z?{&H?j$nk=?yCb2gWDAr@>?%{i{uACI#tV`8;8qn&#GPlON@#9fn43^_FvE#u15Z5 zjP5RZ@Epy2Pjs|ZGsgO1c^D?FqP%Z&``c6w>Vb0XYHmM7{H#pyx3s#??e7&o=-{Uz zQBp4q=&a2PM#qZZ?*QHyKWsgM#9XNfNnhsnx2X`MXU6!M+w9Q)^*FcZ9ment>q*Wl z8MDMg02^AkI5xj$j%f3H@ZOr=tEs;x=l3njx6QLV1H37~Zwv4{!M@R7C2aHEPvP(9 z^j`|_Enq5MW^c^(na5ckc#jQF3^4Dw`5zhJHwJiKfR79CX#wURiScO&@R|VYQ_<@= zLoIr-tqv~~wtoW`c}!bkA3OfM16O!VHD2j4-zdz>{AbXqGn^aN>aRg>{|t_pI;+oX z`3uOjKA`r`V3fYr``rHEeV@8G{XnL2pUTXRd2f4i%l}<4;N~A+J?F9YSC#!Wd;c-Z ze*U)G23Mxb)rbH3(Feaj_o)*vn^bYaqN6j5Q_WL14|`|zj`C*|Q(DLZY zPap8RpHx0D=$>O9y!+|DPs-$OzV}m)T>ZqB=Puai_S!*Dxqc%24>7^jR(xxh70U?J zX6OsAOlPRh_hjCiy)<=InLF<@?msiB(W>v1^5hH=F=?K1`XSm_S*C&=_hspd-{4A> z|IJys&tj#sXDcj|$+8Ssmdkz*&s@b;tW0)?vntv}lFf(@>d(qjIo_D^HSjzE9}MZH zwsCq<#raK}qttvm$SC(ILY$M#;w&isfUn{_>15rf%NY&Ku%?o)!~_0=$e_C^XciPZ z|KbP*4NL$*qn%7i79kt|?Q1_eJgc*(pF0#vE!O;|jEo#hc?f)yb_*FPCFoK&p1%dnN z8WpiD;Z@;cl&3v4WOiyoFjLVM=u*PECkEnlRQpL9%DK8y(K)(1!?O>v+9+o#;%n#3 zRNYV2m5Rn3S&ul~qX3>cvMW{FvVa}J}jzhXc}cf>DJWf?Dy!QY&;Q|SNJ0sPHL z`@6Pf3+HuD;iG@7sj^PuJ5=VV${deDUXW)?Xm4Ft z*U|UCNo^W3)<^YqolV`e!n+?!9Zj7ZTGp5TEH$?^Hf@TXiMU6@hK`OVecU&!TSp;x zE&PEvODQ4xggqz@;%mWG^eZ3=fsnKXCZFFs8CP!5xoN;`L<1_>WRo%IBZ)G4Tnj)Wx&Ft>Kw7pYgU?gkh%XqRxAxn=KlP zBN$z)3qLcKC&t}|32RaQ&XrC6Xfu|-lY~QlkI7BhZ@C*MXogufy zfyZ<;zUu(qSXisvh6zH`&ho&+;97-+>E1Y0|5QXvx&wU}^?b1|iz67JW3CF|jfHKJ zJLGrUKJmXF_`!!T?5lNI9KmRb0?<}w#^9Cm2>CrGeox5{eyXB`-^YcC!`uinSq*HH zF_9a{b-lNZ?z5^~-b*t^ce6age?Rxi!9c`}vA#ndhFzE%8FgUB!oDGoupAF+mp1b9h+PY>|90bUc}wg7Jo@LL1?wg6uRR(Uae zN9-TQXNB#b&F8^B|NkENe=YF8Gw^rwK~Mj~!2gke{^x=JuLA$41OGn<{xmDg5C8iu zKTNRAe?;JaP~bl%@Sha;i+xgF-ZCpYSvSo4Z`gfbd|kbq|4FoM<9SMeY1`)Cm;Xsj z+>M?-#qibuUlHK<2KWO3rq8pup9}C!0p`zx(cB&2ZwHuv14i?c0RJMuPX_q80KX96 zGCd>XQxRbPE|~xR0j>`4xB&C}!RYx1Vffep&kwMB-?_=~6}0zags{b}6TSKKug?C@ zb$HCzm%b8zc)Zo)QNqYt;(vhfyFBLm_dbsg5&n?JeBZWtJXQG99y7+f-ebNWU-WpU z@GTxM6#kmWd^_*-c)9R*Jw8?VA&+Ty=+Y!_d}Dv=@wvhnD=$5VVaj88Y=CP6?8blo zeOVOvGxoH&=LWbX#Le}^x=Hou(CL%h(ySwA)>b*w`?=(|@FJ_5r7k1&OtzoMIsI*) z+aDWn!F_cJP-L2_&Pn|UA^K&cr zy*Ra_GWv7Py*0x!xeM;Cd*qaTZm-f`$9Sw3{&%eMX<_jli2plQdHJU+)B4>QeO3*M zZXa}}W^2Zh=P$wBdz)E=ep!txC0 zD&_(g3ziM-gj*)dFUHKVN~vrjK3OD%rH`10Se_|6?k3q4ABXv(w*wCaF2*;?(QtR@ z8o;eg%qm8RGx~_1kVpPNm@Xv6C_fH-!qtMAD036(FS!TDV@kd3LTU~7 zk*)t8u?(Kex)Nf~ob(YtBkw#J$j+E6?ooaP+>Zoj@<-u66P(Lm3-?*z%KRi1Cwmll zXnr90jo=aaT4-j2N9Es-|Iy&l`SbBV23!>lU7QlTRQ7l#B>4yA$SwlL1Fh_0@TJ3? zD$yn6SwB#n%G;B0WKvP?Z}M9pB3F=uqoFgD5c-HOgP*IiGk{V4Npf)JT)|BKN2GH$ znuv3GGLSuof?uJ^fmQA!x^a1)Lo%O`W1m6W#6kLq@024yoml4q^}AQM?D=!yEDkh^ zL0=cC^btQJYjAO0l)b@G4wh1d?B^Zf;Nr$8dm}KHUk9%*94=g$Um=d!FMkpLuSAFCe>(FzKjxn{c_>4`AIyt|GYtXLjLW# zXTNc$?h^+WH`GVj+u>O&teky|oXr$g*6x7+Z0$}H{oP20&&i)n+`8&wl!@L$}<)6m?5#lyR z!?7SA;cgUa#0g4m1pcZ`&RpMjsBTUlF(HNH<&r*PM^LyVCC8HVRCQ&U!c-W?j$Gl% zQb=XtagsmL#Ti=ousG|i^5HopQ*hd2m${JI!tWtFCH)p9Gre#OjukFsW`XmtrH^>B z;><35kaSK<^D53MunSfCh{?`^!Y36|XO$DOsIZJUXQrns&eFmx$j)(O%L?>-(nm~j zRu5)ZvyeIu%jB(ZjVpSKf<_T*NQP%V{LS*dp({CF z_FS%nhNv{F5=+ItNgnRYNTYFYP&#)1+T6dGjGb&(?Y9Pa;Mwjq779zo$Cv6MdIMGB7!Yl*YkJ*Z59?}hXcLzOFB2-(^+a?E23 z|EIgoDkr0h3ip%I^U{numKCTc=_5W;DVdxSEhw=U7+xtGuL-n2=3{ z#e}q{uTnaf7A_*ub?J}GaYbPp*}1@_v%T<5676ttt}Xl?2A$4vW8t%etapxE3ST5- zgLB+g_)i=cI>()bOUTYf$L;!H>)5FJqNQQUqz=e2I{qk7iypPg7NAsu?aOtI^4DZ8a~zxEQ&)8r_QF8@!fQ9V!h(VZ=yr)<)-i>99pYT zRSwx2k|F2g$LhINRBx95kjzoKPZ+7%%I(J|m~4!2-(pHN0xr=T-l~KuawmwWw2FDa zZf&FXOP$gdtV$l4%IBpzIPaD(2PF%X%0em?FGmijmW=fj%}@sp4`}lx+L;Qgj2A}- z4NsK~E-{qmTod|+Xo#(N4s~Q%OLthnOXb>U-)OwXo5M>hq9fuJ(S4I>S+ZO3(OxZT zkF~s;qev2I*IcE#>uPU}Nw|~qF@cQxSOrA!R`qc)%?IWw`XN5L3U};&h`Nt2@ryks zbX|y^?N*@QFgZGQzgV)K=e(o+8kHN@x3{-+vg>=wnudlcJFV+ZpFDH&v?(SG zzeiUojcF85boGtY>W7Y~)*7vzP?5DdcF7AT+voLx>S)rkV(hKMsOvfe^_Uf}u0>ER zk}dV_>H97915#z>Zk;zijy>zvVlQ?pyk%}ZH{*|EAE-6lOB^m6z^ZN>>SAeqS1qR4 z*x6oOTi4du(jQN;W8ZHqqZ*-^1WS(!dFDmJw? zb*yP>YuFrDXH<0SeA4o(v$b36rMazcy)wM9q0_lLy~m5}CeXlswJTe?yQAt_D$)!u3;Br z70cwfeS_jFi%L1JtYo`}X^M&xYtTcBPn+gUIEp8fP}B(}`7ux3$)_s1Q-H zWybWnxGC$!E3V!^owvE?7c+^YHg`5s0j}8Vn_HXW7!57$ovPjrzI<_8vp0I(5kAdU z(u|IuKmVwz2@M_Xot^Y_lTJFmYU<=^(s%NPD%Z8S6~QVE4b*c)r#VeB#l>x_+oM%0 z78d8uTXFKzRVx=3mo8qpaQWP&D~_%mICtLSqo=Z;{W9yV`V19j(EVr>{0`B zT{XIf=^`yg&OBY^vl%-Dy(j4F9n08Q@{#J%*5m@xMt!!dlt; z>moj3JQL!F{1(V<&p|NZF(ttGKPG-Hvf-y8Ny2ZAF#Pbtd@#0>J7E|GtUTx5=$47b z;s{0`(G~x<$5qPTk^tks^g#Val1=`YG+TM=g+qS#%Y6gWKyNJUY`Mew+b(|htJ2{I zx$$%Btv)W+g?cZ>YrJO0_-&DgVZuJH%5O5FAnYRHFx{51v780z^1LkFtAjX#QCce$ zRRC`+tt;gY`HdK-S+)G&H`s^4_c~n`M=+`pzhinR$99E<{AP;ZHu=Gic4+y#Sr~q_ zIn233v{sdkF?YhaZu7R$4c6uzz6EBC?k;)o9L>~(It9|M%vjj}$Rp(UnD|-yLypAiWtgzFd3f9@e!l~F zWBjm#>W@a~g+5oFyw~u6AN5UJ4Ee3sdpTQvW{jV?%?|x{mPrXY!asO$Vo;WRePV9C z%b;l55SZPUL7|r@nX)cVg#2h0ADA+yiKFCE=ALNi9@#}ohI$NBzKgETWxp&5U zxq3g$9I~NLW^ko}Uohl}hk`ah=stiUdWwfC!*jL$NwnM42z=wVnWACJ@ZKT=!#A`V zOv9BqL>Cwyvxs#UHb$Wo+~r?VDVUZ#MikN%@yS zpW$RJp0e9n^b^3Ip1#U3YvhKH4)BryFAwnP0X`?d%>lkJz;6lgfy_$pAkSU{;>3EQ13)JirGBct(Kd1^A=@v#-c_vX{v4H38lp;2Q&cYk-k4u(%Hf z_|X7A5#av~a9YpS;<9pNc>e&?r<(u5051>lIRQQ|z!wI1dw_2Y@T~#@fNu@(odJF@z>fy_i2(1XkAd+=KbPU@0iGLR z7RQX{%mB0KWB#l>8@?>SEGC&ht1^aJPBi=<0lp)^4+i)r0seJ>pA9g&VvOfL0j>)0 z4f3+Vj4_6JToC3Mbo?nRLPy|g;V~W`Cj17E4;P-| z@f_hJJf1I%cmQ!JE9Rx{XRRf!_+S_t8(tLPDbuGPSrwSx_PkE7?fafr-X{%G6L~ZC zyl%==X3I5KyuM6g4QHHJUmmUb$f(xrvVYs5(jKt-ymzZ{pZBh9&6nk(50Co&0joBC z@S(M3mFY81J-zG=8A+49v+Ue8JDRm)wuk+!Hf~d@PB-VXvT2*Tr+%q>ips?-i7iQ1 z#k){b>dCQp4PU zXl1@RN)0DI???VT4U=&+>Qa(z?tVFrowt^jwvd*Ulw4Y?)EhJn1@0oLV*<80giKGasx;GAG0wsY?rYSaWp6D}JEGx)gv#{p`FHs1KNC zh_#=@o~0`lt(qgtRc5qGC^1IK_hz!LRCMYbSqo#RyEB?N`Wa{3R`9e20&Y(-+UuXwpdD&Z7Tq6u0?RG3L8|IeSQf^u8LZ=eTZIkrsu`1n`NPVK% z64|zCZXf@Q|5NRBjG`(PoSG@ug_*9)Y6Z7_v-rPZ82?e~3>V2}Tta-p=pQF~x4LC# zF7dWm&|;?PqSkw(bK?pkcyp=jDvz-&PkiVN+GwaRUnpqXmY@9{KP7PeM6O!r>>FMdjX zq|4HfrF*fk#Sx6|7QZThHx{-@?vUTDgX90y@Z)(IzpI5Uj$rgl@k3hOjKM4A5%POf z{H~WD`~(wz)B$lABVtZeq?3(_+(0hkhIHHXuy`}g7#-sw>fOvYMAy@Q>N`Y095aY+ zQU_)%>>Kh3%du6H3Fs&Xe?6^U_<~p)6^z>SqTCPg#`s~Y$`bPe4@;gSWid~IAM*os zab5VmpidDa1T)6Z+-8UVJO5V>L*XCh7~je0$=(j-_5rqlPY>9HrquDs5|jj}Lb7V*km)hj{-vvJdl^-hnv8<=caKssCX4 zUhauKjO5Mc#e5SDyOF2b24;>f^FKboCk2>+snMJj;D!L77vPNnen)`cAK-0Z->A0> z+kE!l@%I&Y57_7P(ZK)701GB@d3MH!Xog?Ox%??Xy40KHp)tT~1H3N4%(#r6>6Bsm zIm51PaFgMkw>lglY&2=TvgThY%zPZfh8e@7J*KLeq~T8+X3qq8f-sXuFl~O0$Fy-K zj`;H*V5!G%6khJ}9O2VEo+o^c$F#3{kLd$3Nj?KSD!^j{Oxi|2JHU$qyfVP&2Dl}} z@jkUTH+8i4X`kBEnbT&*zZrVpr#6buqb|le)Z$Pn;^Ez(ZR(!lxhDFjv1i8V1;-=p)DSoU#By?Y{FF0aef;AP8%g~EM3h^m!lBrh^Y zOLEg~`eajLHawf;q_sNc(wV&SY14KeA^`9{Ro|NJdh8eF5Y@?0% zeIg__MmI@LzG1!5F^0D|aDZPMz#9vrpA6rLMrHIC`3?5|gfX_Augl^HMxWL-7T}GA zohr9sg6`JE_sxuj(Qkz5j;e^$AzeWiM!HS9ERJCGQ(b(w%~;q4@&NPA#5}KyUxQ|V zTo-xU=-3uoV?;g-y0_~hA7++{Zl*b88*4^m_AChADmwaoGe(E4pu~Jc!^RzQ(N|MW z>SCy_?qk~1^gQr0WBkl*cIe;xm^RD_`43BgJA5*@m5IRY{utK}YCI1&=CzNX{NQf? z{i%zTFEDj$m_HOYP8uEfj|uRh0iGIQ_s7EXJTCA*F~BPWd}e^_1Kb>7muEdgj07yT z4_tz$l76Iv?d`w()FWrj=xhJ_D33~yC;lEx(0G1`YkQ1Q;-{2JoiCg`|Mc0o($q!P zJyzebcIzj@y&-Hqu^-KRTSn-LTS(V-u-W-{>b_HNxre()Co>=U8g>6U_jCvBq+*i< zij5muTQ?VD_sjqBw->uYRX)avuDruCC|OGTL9QS{RK$gqVP?%qd+-)$<- z-j(isBy{wLW{j?TA9<}_e#YQ@uSt`ur#_N#Fz=xmKQ12K$iFng!}e6wS}UiVj~|BQEV_=Q64G;@8N z_uMP}X(_>%J%R1-LU%{YW-K$y_lS246OR{T%-z0K<2|0-N2qW4Ej$Ya92^`Y-mJ<|`EF@EMY zJM@1o_MtYjP5RK%H?Z3WclYPHFR>qGrzYKK@AJ_9esq^&CGp!}lo@2h?wU9CUdSG{ksPD@mN2TLM>iuo?PP; ziXkFK^yn!p%lIRJw0_Hyt5#l@i>=mg+niOgL_}J#WxtnJZ0}Xf>>NTW_)DFgB3L$b zgX5R26HV4B)trb=`Fj*qT02R(LRvfjO?D1_ZDotz0o)h37~g2XY~8-4YalnLwev3u z%}Z5a}8gpl7fh#MAt1#K4z(Xsa5})iF!P+4S&1~?f%1zK54IW+jM*NQf zS4BhTD>2jAS;@{gud~xlBur=LSILFx?7RRX)7d#-qS&C*&=o{FJK11nIy>Vki*KG0gQ;BA%m>i?>x_Hk=3T6^tnwf?_v_N;SO0z#;GAC>w2 z_TJyjtXcD(JOPdfW(Ue36yn$~f1LA_wReGCTQ6%j{&N z0-2pOM`{|Go&Sl{Ov~&v;z-B1hQMD*zeQ$e5gCij&Yz}j;{LPX0GXY1lk0N~lakr_ z5)-P{*p&M}C7H^kFGCOC|ACcL~;+vM)$&;CBnVmh!JSDU9GV(~t>^zUU!)12zxT2NW$#@v) zeI~U{LL03~$DD9`nVp<0_&PicqyQRn8WmV_BeRn@Ewhs}@QkBz(=JkGr>Q}1p#Pod z(Zt@yXj++_IPH;^*=ZU%k=e<54Vj(vChXr#Cr6aonGgGv%+B{nCNeuWGjl~|=i}5= zhAski-08#*MMT;Vo|2N;`3I8KyS-rV_}i!vnVn4xj>zmBgHWerb{=HvFEE)~<9~-C zxZ0f#_qG0&BompPKcLM*m$hKNpQOzqqgmp=10%@nq)oHmoi-w~a~?evnVmmjaF!Z> zHv3q`JboFGNXCOzn?bCjb^9+Fg4d2&69pTgR{bL+v9W+nVlv< zx(9m7>@@n!KuqxxcIGndBD1s8lL$Ozb{aRQI-PpKd&=yz`W`8novh&^ zvvUwxSeczBRFutWTpUAYr!AUknVp?jOAQeVQSk4edyDI>`; zQ%kapr6o$DN{J-P&LYXu(~>OXX<7=Y{Kpny+2$zO>FVrQH{@Dc5~T>QOi7!eQ8fZ4p)rcZ0p$k@<-jWGl~UUamafA|)sK8BWkJJ$%dr3wMNKF3l61WA56!^Lt>U~LBnC)r3diAcAdeu5@p#kZ$k~7sXbTq3 z>6lDN6e>u;3k2+aJS0FKQ}p9Wk&lUf^Ai0oZVH~ciyQh~y?oJ&c?d%qu!Jq6 z1VYxZl*q?GTH*&vdz88vNGzn-N6IlgDebX?(jJeuaX8kJ!h(hYk|R8fb8K0X$00hh z?qem_(e@q9IyHI%DP=atK_{IEez||N1dntgjN7AZpfh)F2Aj(lLW*i5gx3a33di1X zKDRNs2z$uYt)0i%f{x1EhCH?4p;&ZmUwUfQ17Wr-k9#*Bx^+k=rYA;hMsbgTq%{qs zOUAwJf@wYG2t!AHRd~pcW>nn2 zqZRF_#^7PNk40At8gT>YEWxAK;3baZU@n++I}xy%_%eLxY^1_B3t02JANogC0*W1X z>S}&PNYI5ybn@eNW!f>mi}8pXKqm>y?<)g=YueHEz~F@4Yf(bC3I^KWmf~P92K}Xf z;_pUaaRcaF2!06ytHf?S^qSv3@GFHG`DI%>^1Tm_xB+zLfnOif%cCxBw;5RTdmH?k zVMc!3uP5Q#0Ze}7c&IjDgTp5=-V{YUK0EDK=(2Grm2H72p?eAj%tuk>pws1mbW|_m z5lsDj(5dWA**ysQC>?1p2^Cl<*V1e6{)Edpk5o@>dxL z2FHKq0EJ1Z<3Cr+nXRvChUW;NnB6*D(h<83X7F#_(w0CsBKuKm4 z2Ok}Vvr917iB6op(7=2{t94e^KYR!9;ywBW;3yEx3?)wI&sVYoM4g)=9YiK z{0|Cd|4gv?XYmEaf3$>++c<>gS8S8*f9eo0Wd%_Er^WmyziTmPzB6G@8vdp!OO}|t z`F|$n|C(}TiA#VJ7MB8ZX_Mw>0#ls`d4u-+g_*U*w$Wqm8y$L1`Osiz%(3MIJi~-S zM}T8MEG#2#{Hq757*W~vN=b<`BIG7BkwC4EbB3EWG_NdlX3wF;!%Bt@999xrn!hWN zb%<%D_qi~QMD+!rEL0~u5oQrt4OU&zX=T3S9qe!U77VFKOohEH+s!9-DT0T+EKTNP z_Ohg95peqpcD8(ll(Ecl_=HE3E^`E7FwqO&=YP7w%h!Nzl0>A_v9z6hzy)CQ;-siz9GB^nLdE_!A@aY+v z4-I_ki;iLB9OAgg^Qw_y#JRy8q~{VBc;BJh;lzdB^`sd=T;#n$^Ye%kPA&&!+}l!) z=z5pH`$!F;+(%2iI&UUjjC&Wx=sf3;Xd*SdkM=M4R)NSw1bbVu;Su+?e3JZ3l3h;d zcxK}0Dn^|5(UMi{PQ3V7o;l%rpvlj=39PZVr4<_Qak{#i zQ0}8OoWX&GB5Ny1vA5+AKEZvohBCO1)({4JTL@!bjG_4^d)#sFJaCMBi&*xyd;uo8 z-Yl3zwv)cl`xWuSjChe}ma!kD)Zv83mD|W;Yk^BW?g@$fU@LH$mx*`epIh;k`)J8i z?xSVM4+3B51$$fQ7JFOxA$fs$F;WHGHc&uwq-FuEy8ac8&E6K; z_!Th1eYA$a??%7Jx&6?LgnhfWg_@XuUD_t@n~hBqjGNTnmK?M>1^#Ert=8C-`#)zW zC%G%&O{MQsGsV~p^?ysvH1|xn8SbxULQi*D6|4L&)1S)>*(kp^Tw-qvZEE~;>E;Tz z9B#(@`~hHZ3qxJ&Q<4q#wlF$VgDnPY-8b;Nncj`X7kgV+WN{zuRdlq@t-=TQ(f*7< zz1gh>Kio&lnE^CbZ-EEyqvhBHds`;J?)SWpc07!+-;Z06WzCZQQImC#0O6Z(2s z71C8s_%gh^TnmO<+mh2r@}-3|bjo6tW(n8ZU|?EC78+B7a35_MC|?&nLP~Mu*xN#h zZQXYwjJ%JwH?qw)HMX0V;)=^iqf3vU?joG^KI=L`V%w#+93mx)wi zu)Vr?kkLf_1+=LQ4F)ytqvfX=4r~a`-jfKSWcYJdl_gs@vVZVvNndg!! z=Kq;w^If)~rT%A_p9@Up*7y%IpjW$-;l9?-MgXz5We|Lt?mteOh3-Mv%nx?3EHauU z{w*-V-WJ+4`#&b@2KQ$8v)Z?NTRsm>i+?R`mKuLH`!)2m(YU$SXWn3M3mI(lhtOu3 z(LCgzMVsYDv(q0&&9z4Jq<=Mov%+x0eYDJbdT9~__t8>MUyUC3(Nh0_=q}#yO$kLRP{q)t_O-du5jbm!8I$R%Ec{>qSBToi;IO`RD=#HHru^Bs=`~ zLcOxPco`=zfQ3LobssEpqA(Dw+&y(At+_Pz6ub4uXnNQ^Lq=1Sc8;RM%V#+YcN(0> z(l^?kuJ^%=?b2pDO(HFYLoR?-f|^qoz#^yh^{>`ZYNt)Fwmt;cx*8!KoXEv)n_l>s zvUT*!S4kp@)AFwKTa==Yc7F}8iaYLIFh^Zs{RiD%!yPq75Xy1wtx=b=GNtW3t%Sjb z8@Z(w4F_5fkIjj>=oGCj?s_z(hWkZ$ zd!@Zm5N36_Qt-e3=2Hf#DG1Trg~@pc!w1}f`eAm!;3CD@*YG~d4}baT3Ej`Ycw;+5 zP&!jWy7i=v&>_XN5 zfn71CO8igWdCIOHmFe;Y(7a`D4EqFZ@A+j1xde}N0F2v{dt;CyhpPmP&?`Fby)o-g zLH`o&@GDVQ)HMO_IxuD6RK9aa0iF?WK_v?qbJ@r#i2 zOgbJn!c&Hu@i^Mvm`&ivIwDH^ZNE2W1Nf1S{EoIa<^cG0WN%CvmMyB_*|GM+*k%RHy*i-&t-n9ibDuCX^J=w#|!+U;Lfx>Y1Q(w-Qax7ibe zg2uAP`X_r|IH$t(H~tT)PUJoqG+Q0t`+_h~ag|Kg7f%J2{Vpt9vfg=?!W9aiqws|a zPgHoC!j~&tuW+NnD->R<@LdXTQTT@n?@{=G!oO1ZkizdN+!+-`;>!ga!95hNP?%>k zh2|oKn-#uM;SCCJQuuy_A5yqg;XMkQqey78sdz$B!tkcTe^aytng?ay+m{%)2 zQQ^xKo~v-9!kZMnU*U%oep=zT6=tVE!a(`%f_X?+aJj<66|PZus=_xayg}jn6@EzJ zR)zN{d_duY3U@_?maz3yxLn~83SXq~r3%kcc&WmlRQMK!?^gIeg}G)a;rXG$dlde; z!mlg*M}@g@PWW&QKyZ=5XDU2Y;fodiwZeZ?m<^Ng%u@Iig)0@VR(PVqS17zz;oB5u z|4saQK;iEx{Di{$6n&+>RDtchs2f3dyJ+wwFDiavl~TuZPX_l^iV}XJm#;QIeB7;V z8D1R{>U9jL=if4|j{nSx4l()J0fc2~&akAKLOX`E|6TKMvx8`+t;pNvI9mSwMasOV z!rVJ5^aB+(XC^GqG0NPWnXu-Z(-XH>C_GEy1qw5`A@nz??EjU+^$y)bRXMQZ_hj73 zLWu0CG(NT6X9~G$ZZZRT+lsK5cWmGX$xmaNiQ*VM%q)leG=5gYaSNUx*TW&sIfc%I z0Tqd<@b6v^BkY-)L!BE*Q0Hbo2wi$#DZ4ZHcjJvuCMyhfkltiInO_e+cjFV>Qw?61 zLK9huSH|MY@QyB9gx=8UW{(L+>25LiHaVHAiA#vXnHz|E62~%`<8CQ&JhLZpFXG%x zj)dJahzl|=rg?AT!c5b(C?hV)+(+|1#0e+%b80FU<4wglhc=A{lTK#-VIUz@XBN*| zXwJpsg(heGF*MnU=fjXYOA)Pc_+)(oFnc#%Ze>06d~ytjaCjZ9I0xhoq-RX|9KPUm z9X?sK@9f>Wv+>bw1aW4YM#pTRFlatgQg%nMZp-e63Q8NHB#{uMige;=uHALlZ91UICc_yk zx<;Y`KXZ~R9r#hV#QA``)j+g@MCJ}PXjW2_;wq+1^|Q&Q9*h3uiuKXdO>5B4Z&=(3z~3+c#tX|{<@p=ZE`1cD8R4|kc?wGLBtF$&7QZo zeon%q(notofE_@8;0h|M9;>5NK|_CX)s%Iqok~E@wmWLg`Hz;=rI9peZ0`lre0o;L z*GwfB=uUXFUo%|-ejM*}O^9`#bo^0O;bHhpJAg0e#=KxXA`PFX@Gu`m4F=tj#zrrKKzU>C#n$yh?4Admjz<{+&u}wc*zczu^#}2Y8$jn; z_$zUuUhLYhnO1@y>Bx_BY{HM@3n}w}&Q|bygTN}`$1jRVO1+JKOce}SugQb_;KgC` z1S(NZi(xKG_=#S=+Whdbn+_qvYX=?H@$rw%jxZLJfZ&^9N@Cg|!^BMM+1pL46CqE) z4#CVHhijxL#wo>g)omd4sa{XeM@e@8q}O6yhip)pKO#o}S)5ukCH5>0%a_OwAeQx0 zz!SP=%G{*C9g-Jd3mxMx^UtT!tsP#M65H%NOW_KI&r$e7g(oVk*GxG=5}vaazFOfG z3bTzA`r8%$lENJL3C;Hueq3R;(?atLgK zx=84UD?CZjFH{&_rFgO|34gK{%rYz35*>sydE_KDU%}aq$j|UPe7=GuSmrBUBDV7t zEU7YI@kwGkU%^@=^A&f|D?4BD4Vv5eibsg;e8o`G$b7{*TAZ^OZz{$)v}rL2I(?Qf zMo87^mv}*ocQKyMm|h8)IR2)OyS40>CTn>2-i$?L%Uh!=vq)lAHfh@@3WW5rwv&w?O} zjyhNJ5ls%5aC3?T5-s^LQ!8fX1RL!?ig_5E##_E{S$aAq)vq!;`#*4MW`0BCvP8St zn)F;oYEH)X&A{u!FK!wyIWLr+J-M!)vtE$pcEJV15@oX+8=9JyH8d>jH}S&6!2T8G z{mc6#D*F%ZUttCk2~-|b7-#yj`o&Gjy0MGrHaOF!jIOI5IpyN<)25ED8$WjH=*iXN zr;I4?Ts?B^h=I1lC4(1!>0Xprb1I~#&UE|I`-G;Uh^9cy<`Jmir)Z*X9viZ6F8r#1$&Y4KR|TKcn|4%V z@G#uRqN@dsxB+x#;?ZMfiSIa=3kGyXA$&9O<=FLTb0>Gh{)fr~f$ir`?ghVRU`c-b z_egyChZZ-0&ZQ{FFB4cLc59#)Osh&ne1fInN9;_mL76YapRgHv`pf(he>Vb)8$f3b z_$3Ie61(-#>vTB?ex)!YKSU|Tul?K!FHxB%Oh6}avvq@yQ8Dy}YJkX(KWz!$4q&<| z$3w-nt*;3a=n47kv|pk7HVU>be?s>Z==9vle$eT1AgtTZop8op*AJn49{hB=)FK{C zU&iBTb0^$KCSe6>DqY&oom>fiq$9th&7D+(Uq|LnHXv|S2>h|;PWGXm_hG=SlK6^V zzS{ibICo-)x2CLd?nL^ZOrKmlr%OUvz3LO0*%SPa^?yG7m$vSXG>1YzW#2im%%RY4 znL{D|DCbbvj&m%H>UeTK#TJ6ckrp!F@tnfHQ22F)Pw0G#4Z}cGNSSBhtym%C5!F=+ zQ}T?2^B#psC-Wn0(*%>XU_H-Ltjv2U+*e_?UE+3#!sjZCCis~9K1ZtXj|Z0dn#mTk zO`mQt|Er8IX&Cld7Rx-Q?Bj%0YEFl3wxm^|!u-dHxy<9Bqg&UJdvGfT4KDBKJkFI& zaQrJ}9;d*}Y{M*IfOi>HN|ypHxos8h)U(Q(R~r>Nf(i&m8s#2A(LRA7{Ew=6@ICm! zhRyz<&~zId_acB$zccZsfG?z8n1wBTHVr~Cb_k-x>>XvAE>g&en2QP>_aT^tuwpGv z!|bl6Cq;7cr*+dZG|ul%DH<8F-6I@KK}1R&&pQtSPvDQ->yv5j^fG4PWLEy=s zY9$`mX~O%Xoi0ev0}V)s`V##o;>wG0;- z1Sr_m@X-!0kwT6cN*-m%sKxXLV)T>Cl1~3wO-+!C-(ap>ISvW^f7j;Mlra7!jSWi} z=8h`%`B)6t-cki^O@R5P9TnSeVpFT|C7mwCf_t|!--He_+fmM!v+R?O`U*UHjHdhB zuuA#M{{#KCzbw-)4@saD-6(|topV5Q4S`kST6E|cML&UEquuAMWYfa4Njq1~& z+Z90brX8P~?N{i=AOlMbMeq{3+o9$EQq+9V={zAF)xCHGQ@jE5+(<6NnZZ(kK( z_7^0bF_cM_De~9`e%~apO8D_BWq?+z7+4sxPb*{1TwtapSftb{gt%%f425%b@+NPOMY5qm{4oI?YLQ^!{y6kAg0ve>%%#YogFjjoQIT? zGReA=$MB^a(>BevG_7PGVn#ukzL+f>%xhWeWZntpxK{S+a$G9rXAm=kpje*7+|(}{ z$Z5(vNv!>qhKc4jV+T|Y9h~ax037SiYWop-mAGbe_8y=DBnL)j8QX588Qv zeW{&eHPfN-Sm1mR#zWJvBX?>%G!>sISiIu?Tr6sZ@CV2ur);`M_{cwpFE^_g2HEDd zgop$IRk}OIU9zT2W_w(yQ5osZS2(zuF(TcwXji8}+NfJs*H}MqK@+Zz zs$+7ZA7~vmET;ZMuJD-f1UZ!+K76#@a4D_)qKQZ;S><6FX1SKKY<{pu>9T)puiQ!? zk(hw;Tm7JZeET(?yYYkLKhFHy@nuF(PxqQ1|M8Lufc77E1ero`%wGig@wYDgs({JQ z{_34efwhv%9|J>X^0DYlKSMF#zllFoQBttR!9XzWb|QRJ@n!hf^^x$Q&1zEsTcD@t zT2TULz(DiMMKgXSEXj|3RN=Q6Slj@b^`e~wR*Bsj=mpd26DaLBS{i=DZWXZhcOkkB z2Vh2jnP1}XMqqIR=)4bp2?DFcZawsx-zfZIN?}HR?2!n+`+&s_pmRDh=DP$|iQQ)C zHNW}bR|7Nh%e8h4Cx1kABYE{x@cXndv3Arltu!6wK$pNw6z%vtg@^elidUqwtcoHH z)r)upQ~x07Ok+X~l-NBFtmCmA@nEc z85F^&<|*te%z7_0eHCV#Am&39)@vstl{x>DLeGDnV5Y5Lrmf(43NKc;QDIYN_=3vC zBXKVP7Csx4`8~k0HnZ7c*6^(sGYy#Lq+xmAZgC;LRDbW<%z(4Yk87S_(Aj5K1oH~V zo+r4MO&Xdx_J15FJx_o+f)Q@qJ+Aoy)4sFG#QXs3}i}yOPa=lp?nNO`EvAWxM|yscOC_s&MZU-atEcq+p)SHgSQ!hN866T zGt(PCV`>E6W(+?ZgMAF#Q#(JIsu*_j!@`D9H9scZ+YGylU>a29Anl<|B{=becw8fg z;J^;14HZO>bB{!f5=X z8ZV3INT?6JmX$tciijl_E=-N7oBp?qcv*N^RHZ#I|EQBAUZlujDghI;PRBjwor52B z9PaoprhB#t)E{ZgE7<^R+io8|=3N4Q{HKv0n|t9`1x)@lqq;cwq~5fn;=i2Pd@Q;4A#r18aUmF?KJ78Ts*_ zEBx*Q7B_&n#|N@`39J&k&CqLpSAw5}FW1^JoICK)jpWr{@Vi8qSUYNWwxgpA!V;K? zA`PFX@bH%>YBcCNGUmM=bf!764kZZBL$Bj;FXF*)GhL20=KVArNu0=1__ZJNZU;Zo zkss?5{UZN7JW}QXo$tcp4Fao#AHQr8MTN1x)R8f7CCcfM!Y6#>EB;XbaUApJ+Js=< zaLmiGuP9^3L9Y4>x9bxe_9vxV8S`=}P{zE(AJv$b<;aX*Y{g*tlJOeLnP8S@8P}jQ znHtxeN^=GfsuYjVpQUhx!XGsLov3Jzcg$;c3ZcwWHRF*mm^}fu0<49(jK%(mG`2$D zLu_eGdt>>)I7QETCvIsin0;o!A2e1qY0DQB%Y^u)$A-5n^G(1qHvEdk99rFPF|+Ag z7BktuW3iOQzkh5f@)Uy+-?7$^2My`?*l;-GkAilDv0-^hYbS2UY()#(A-PbdU1g!g z*pTV68jjiiGmr2NeGc!?zZ*@^2oqv7c#HYO%%ISXyh@#$$-*LoLOXm+$%Wzs0>*~( z%_p-4-e6?dhq_Q~GCtuXv5^QBIRKc^?-9JIOjX%LUG!4CLcN#M6e@ZpUV*lldN&qc z%5O&phFXMDL=O+;YOA|Onp?0qKvY7K=tWS+oyp7zlZ0)Cc_hHU20tRRx+(mzf zliT~B`f%XN!Rig>9qJSeUm+9eNGrRkVJFvZQ=0TLXv&E8AFx7MNu^+y`BN;bgS{!b1cv%U*{g|KIzoWCLAR|QP|G^3gj zd{S@PQH{aFY(5rUEoj6IV28)7>@#+B%-TxER*7Hj$E;lc;;DYd_h@6*D$vXnX7~!f zH44*uGb~0DSS56;pilo>K!^X)OqkJM=9i@NMqqIR=)49^g1{=VTMxbF$AM}o%*gL( zV^$aSalSACt-#H|nqMiH)WD4V*!Pm~nLZ@+<#?!gKkFo60zDxg_F4E9y2rqv1bR_I z*M7|UGU$d15x%6OdJ&Ic>bs(IWSSFdpv3NZU>y&xhckT{50-z4$3b9m1L&LzeiByd z#jgFBwHf?KM}8a^3BNpGDf58N1n}#~m~|66xg8m^?m@jQCS$84e4>}HHvc$|S((?O zask+uQ8Dj1hSlAby1Kaw8NBdp8)DMJTkt# z2UzIuCAO9O0cFnB7%_iLnFFTyus#Y;23N2i%d#Gcc`t?gD$F`AG$vp8f?}DH@ar+I zK4-^;HW}kiv6%ULnZ;yPXECEm@gbx~(_+-$KgO**uJzA>a&2aeG>z`M$u|p)< zk8y2~o%~&`mn~heX643NyK*P*O2nV;^yY%R%R-Gw7m;g4Tm5DrYzTC>y2Xw&HW`qY zxq*WT8S$G&!~#bvi`%+ko&KP`*1cgT@`;!?tKpQRIjS-|gYbww=W=NOD1P)TCwPbA zh*M}k4Eq}c$GO6OF{bVhV~mD>4-&{OioprS)Q=;h(qrlypu>7=f|Rk${bczIl4n*E zJ_wkR%jp}8w0Yt(%D-%Rex%BcA?;d;WcG{r66c(vl` z#1~E@gfkbyapzdZ1;2rT_eC-tO&=ZaKH`fu0*0M1FQ~~F_cS#l$?jtIe&X08j-OMc ztH(fxGrtO(tSNXEM*7yn$a@X0BK--S?7C~5$N+K&+rQm$<+iPMYDwgz#G8u z*ASW=+D>FF@#?%k(e*fn89#u};1iihO*rJl{syyAATkj--O1gI0Bi_FE?Wz;AjvK# zbi4)RaYZ#?*c$?q$cz@eV;%z#xrz~QLE?~A>~6gHSe`lIFF})^RRj*P$bu)K@v7+R zYC^|jJ&0UmID-QVMb^0>ogaDNZ3HG8Qh_61H~V%{C@_Nd1o;p5hLQj7XF*@(Euh<{ ze}VS}*>wxy_F1|e<$azsdr3du`#SM+^MPx|3NC_g1vE!$7Q(9Q2E59`kx?#f{HMukjB5z|+e6Tda|fdB z4*Pd7F#=7@AD7m|eO~btnPA-H`aQupGSTf4gExL5BUo!}%KgP8o8)p+Vx`Y(sv=X2 z%}}3rK}Dvy{o!V~{|;GCcUcvy{3X;}X2?eQ50TsD#-_&KM+R58m2flO{{qRbGGw*> zR~YI#6P>C4Ur4sreG^lx)4Q?wMn3Jb$kv3q{fv&*xuftIAL>>|<~O^e!S5xvTO)aV z*8NWyzT$SPrS3L&66}8OBHe0Xj5hK)1Uo0pVrUYY5mO0mwADdEuYpw|UFC#l;N9gq z7_;~&avDj#tS1efvRI{Q;Ced@Ov}hZV``8a=zk}AgtQNnGcWWkBG!Ej%;S-+p|g;O zzG>vT8SMCvG5UoedK31!x)$jkVot~44da~?CeQBqu+NSR3@s#s&ylRcV8?%nnn6Yr z_5VgqWoQ_v<4%m9Rd8TKc*?%WZ1;L(fqy1gM(W)f*gO7j=w`0TsIdP#24|k3iur3v zHs56%TIydxn*}CwYy9zabG3U3+}HZN%OY}(I|M#W_j&19WTE>T*v$90(q@s-Eb%F( zF|ycbn*C|CX>e~vXjc3GkF1xtUxcQ`_h_@!__Nu6f^Hg(n|u8?!86iiG~4{|&}Ny@ zJml}7&2ppJ>9Q27?`cJVUtJeH9kXPK<2}q2Y0=6Jw&XoLha5Ly@GZhDEI5k!F_}Qq({eYh3yj z_}UYN+PElmPGto&#SNKH^PDhi;i;o(Tnz^>7-x)!;T>b~NCFtwt`nvNooLxYm}ETx zt9YjKMPSbXi%f@YkK>(!SAfIb7eSNhkZsHfe-)qTEOI+-IoQM&nQ{q3r#GI^rrzki zoQ^ZsPNt+!1fE^ zR%*^_O)WJWyrz^|0fbJkr|JD)$+ip+{}rK4x6yZcXZjnnVHS8dn%><8ZQ$Kl<=sW( z0Pi?$llBh&n4@8ibH;Unf1tSe z3N$29j+{x$HDnQ9?m$7fd5Ra3EHT}9YX4rZlqcR{o}6LjE+AOvcjw-|-YH@eA{rUR6>04A-?J4IP_PPC(7-BG4&^O*#L*n7BrmLm52|s-qdVF0rp$iJg|Ilzxsu92h3W& zVBs8!5NsNN(}M%%&7M8rFd8FKP()6CByr)K(UL~2*~|@=xFD%8|Bt9%m5wPoHLqZv0vof}dQZIpn^)brC%rIvm zW1TRf%81y_pTV|In%rP0R~Z^{MYo?Y=3>ITM+~1}wXJSWQ$yYSlMmNjnI(4&>O$Y_a&7CQAbxkmASZp?r)*;)QoVg8+i;@Wb?1qMG z7Lc}S-ooYe>Fu(ZflPu7ccz#Fp9swy+{RKjYvDCPfM;L3%=pwWcWzTX_$->m7$e>i z1;l7!{bH*-@r?r(6;nmOZth|eCwviNCWpfb)Y;eI8W{$>zOm7%8@XT}6RU1sa?v6r zE{K3ouIiI>_@;DI%qcL<(kr^g0rFt}EW@W^ITP&KWr$ahP;J(EvEhitb@76RS=gI< zxZqQJ^tU_+VRB)eNk5UPW;9mFY8}0FR={^e;6pF*)-ffRAjr=Ol&Ho9ETJqL_HG#~ zcBf8K6l3(dx_OJ2&t@qM3OP>hE<*{TBTAgLQGr3zoCPQsIMrK+g23dyR&fys&(ZJ% zoW@^#!MM7~qc4~?dCJ&JM%PVEC$?D-uR~39>gLxW%N94NMd={ClyVC{O|zR)+ZNZ zZlG>avU$ZElqu70BID}oL5@1JoFxg#!zx2lr0;@7OO`hpnL~)~l7=RRC5S~3F_U(z zLW?Lz*9NF*87j>+bqkYhN#-sNPKDPc=g^mF;~N&Eotsy`3{6Zud8I=-8z%D_8j%{y z7cXzBpJSRwBfT_?{C7@-(VsL5{=h`LFX&{}&9tzXE1{2$*_;N@| z_oSmcy4U=wpqESlOz|6_FwGZ&-*9}%551WbzbatzqZ!o~f=}vAJ1X{nnaRhZs|Ag? z0dzLup_wR&?>HC;rrrGrA8CUjbUJ*qV5a%~9{L|(yedlUI18@%jXKS75}5%%l1ut6 z1{OEu@c`Cp(Vt2wv0DQZ!L50XEnehs>g>;X6(n^H|(L@H z+>8g;fhAoSH*o{#^aj5g0;|OC-=Np&ayR&qj{J_c2cQA`IM)$PZ^#;coZOKx zXDi%A;nNi!tnf&MCn`)~V8XLS;X4)HtnfC4A5r*8h4(4^lES}H_)iMEC@&I*Y=uuz zxVOTi6`ri{RSI(*Qg~jg@MeX#Dg21SKUVn93Uhye@GMfeOyNp}s}vru@N|V+6uwj8 zZ3;i4@RJI2Jx{{(lES}HxH}pTq3Nw~rNY$;PgM8{h36~0T;a6}-=^>;g&$D(dkR0H z@IHmPw@#OCSPGpG^fn_E6lZjp`W5K<)n!DI|}pmDlyMf_%wxwDm+?Y zo-Po#bqcRj_zs0PEBsA`zpwDq3jb8$R~7z)!hcmbhPGD1(^cUTg$F1+T;Z__U!w4A zg_kJ&u)MhkH!2BOk?WH*$s()4Z z6=E!sQ2kDs$I!_aK4rv~rb3wy2A2QbMKrhkFIM!IDf1P?Har^?%_fBz4hb`gdlMCD;X4%Ozf$;o zN#Xkxen4Rq?PJP-=l&T<=f45VKD#i|fEZ1r)7fJ7J8~^%myG9iNyC0tk;Mt%5{t`# z%PeLet-r-gW9|>4TlR^DSv(B5%Hk^EF&2*m9&hm|;K>#`&@FfC=bDT?i2D@k@kRO;?B3ySHY1Hk=-}g+m8n9;&x4=zt2l z-?I5}GoRuo6g^-*v9ZQ5auz};Tm4e!<|=3xj$COznP-CpToTlUVwd6*j=87Zg>QtT zIXA)lccP8;iyXI@IP7HpkQOD&@s1%s9JiL_R18*VQ>VqtaYNu`#vu$k_ktIJmi6Al zy8jG1n2rY)vKoGjwQ#+P9Z@UKXnLa1s`ctjy=)#c>#oK&y-15wc$f!iyAIsB?K-fh zmVh}zrYgXLg;ah<8h8~yChrbAtQXKu;fHHwA!i0ZLYrPl5u#jn@ zY!@>B6)TNSCv14ZdSe*xkXe}wRw;v1e?2;NhHEz*ih>XenGjW+J`+fD+y%(>N@WUO zSkvr;U*u8m0$jSh!5#-}vv8DN&1++v(wOxF^D>lNlseJtX-Fq5s4?B}#>&MJmap_G zgZVm+`rDUOi^^ApuUn#Fzacx~CogvvjZdu^%D%0GQ%2Kw+BK zg5OMh$q(Iu6u&B9@}n8mr-D!FO*^VFco^{2qb+mv}^p-3%CLeqnST`ofa@(9KWrTMR620G%&D^ECpi#BL4rf@w7p zmEsSUh99w81+4uoN9C9gOZvWgq)PmnAVFDfk zH@D-r6Z{^68N&yd3f~T3x+%v)bteLGo-l!)kk3y06}smmL0bT0qlAu~Hs+(Kw?W6Y zLzJ+75e9;3*B2E<*AKC4zizN3uVd>5mEgy6B}(|E`=5c$D)5u?ceHhb7VvvRnBgn@ z_(c&(sRQV}Rl$(;8mvt^Grd_Br49i)g(&x&Ulk?%L@!@${&8G4&}E6~$VU`0dz(}j z;<4)l{Fm2ZOUJcM3kCr!YM4U+y&=Ra#EgMreUtfr_B#uZk@BCD`G5ZNGb|<_>V+rZ311^Xk?h#qzAd0kD;fK1(6 zPgHoC!dEIhTj38noA^mZ^ErjL5!>)@2bS>fqPcA_b}RaQ%KT-80aI?7@4|=C7R?_PRQ_TA+T(0mCh0j%Zq{3qqo~|&{O8C!H_!@;-c!lOVh1V(k8HMjs_#TC~D*SbY zzo+o`6=vFszt1ZCg2KO0I0_u%3ySqq@~!|_`20U*{##(qw^02D9%AOnpDbpc{MBN! zPK5@MG;FIgEoQmSx0rRYyTxY!bB%`deSrH|%rZW}V%AYk7?7qC_*{zz1D|iP{J&20 z{7()1ko2*0L3WL^VZgEGf^bgMP6i$OoahoJ7JfdAU;DWrn*3inC;B7&NLhdJ4t)=K z7V3|PF|(+y2tJ%O;(8orf4Dq@bE085!Hm*EIFQLB2v&j)=S0g$8O!`R+=hQl^2};N z9(qWf6I~0MFvTUeVC`tiB5n=S?|GG&WZj%+8%yR^hO%nbE2<BFY=mbF6TsN zfNAQS=+EiH5zdLeN!M~t)Eo``z;mKsLjY3eL`{;}bE5U+aRoyV_Fknw_M9jK(6Mu( zJhLe0L~H2Eo)cyJ*Y2F?5Ri8Goaim&WzUJ$As>!(PV^A{*j|lyq1Q-ydrp*n5IHBx z6V7r@lxu}@PV`o$_i>yPOnK~zW5B-*Nq9e#y&WUnm+-lNXd~xDx6mIsC(70J)HzWel1!Zw-9-j+PLzx7sdJ*{WUZVN z{ZEp~IZ+nh^f}QR=qPng^a?UhofEx|@k^Z(olf21=R}`Hu>Uun6Ya(1wC6-eB3h|) zqNc{mInjDXU(Si1PA5k^CwdCr_2LpO3x^iGn=IngP!k#nM7p^cmq&13e-Inhb9k#nLv%$_tw~&pT6RlwgkN=z~ zYq*>fy@o74nscJOHOHP4{ULmjbD}Y%mz)zVK?=z^(a(b>bx!mfu(0PuUk004!v~%d z9n$8UsQGyo!*POw8bU+bo)aCe4sM#?qdh134fKUR;GF1boP&x@Hr|&34#E@K^kq0O z2SsbDp`VQ>@UN!rLDBKbzX_xaP3~n5w@zfBAA>>9sd%NmSLa5*%}lcAMsH^lJbCim zDEc}7;O9o$E-n6}9~B*j!as%8!kLV>QAK#85r#tfw@OAM)N(6<>#*znkuNWvJU!Zx zmD1E^Vq^(Vi3Mw=C;af}u#O!b%`k^YGt6S^_2xLKSys)s&Mdb^xx|V^SH4%8x0oE| z@aUW%hCFh2@(`&#o67TH|0fTTo;>EcxS`+G%NH%_w=9W+j7^Dtb75ePZu4AWM~`{7 zJ=%GqcM>dU7+@8g; z1SKAfo45gVhJs%WfmLGHeh2hYH=1v!e-=ds(_7 ze+eJ4R@(gIxCeym!Bog5v&RG3kWwtix(rg^ACF9W1$#nLqdnD$!pYIVm|Zg^!or$@ z2g||9bE83BlYJnp6N1fpyv-c0!OL1UigjwOznJE>&%rzqxBN#5W*rbbLg8@=bEZXT zE>rj_g%>D%t-_yBc%8!cC~VqP8&mp9L-~aU$w-x&A(ikuT}Ua zV%xXgtmwBXOm4EbjeQ2eWG$Hc*aY*RD7crxeHCUOTWCfq%(0l5Pf&Q0!m|~gr!dDq z;#+K$1UerJPi1Ji>rXS zU4w2%0#o8R@hIR)7BjCdwYUa&hQ$+slNNI!mFh(AEwuXy1KE){UwW+lgy#&bD8~_0 zsAKOZ+*g1ABjGt8!CIxymX2^oZr+~1>(E7m4!>g&{F3a(JwXk}{TUatM~piph9bg|uG|)j^RKNS%K8Id*c+IHk#`Mnq(7m(L&C(x zGh2%W5XZdTWMFXITS{_+?Hv;H;F5Ppuv;5@7xXItOwi%cwV=k{z(X+dc%MXMa1d^@ zi)l#U)2C=YH1Mf62qWhZ$34oyhzujn_5Ma*&m}JKen*<&#D!je(u^Q3@^~IRavpI4 z^B8czy@BO0^jzB15IP=jD2|LJUY$3Q=HnPm)ev4S{kl^J5x!xCG64_4rLT@l>9%jUgJlaMcrIe0@X9UqdM&b6QUKL~e1Ino{ z^UQw3e{KbqJ0$2z?vP-}m=_~eFb2LA z&>X2*0IRNlz{~6nq>Xs+umkZy8) zvm11xn}cpdfxnfBS!-;{eX}!dlDh)lRQhb%us4uyhWgKwY?^x}+zj`}klS>ZRk6x{ zie#4=vQhpn+FWjIYW&>{&J}Js+>G~mxD0y($*tBugJg9sqchd-g*WyFzLAM^>c--W zy@4#UxI@C+3A4_vf(~~`JV?8n-D>c|9TJqbgS~-o!8PuXc!i<3&7A-{bB6?F`J;`z z2*J(?vlyC$X2euN8?8ylobdIqDx|BN@MU;+;Q)MVTXGsnzO;~rPFbwdEa7?^47l3h zu+W$qggYdte_iwpDWj4X+Ko7L9|+97fxVH3zG>vT8SMBiq$)JOfUr+V6WANboaP-8 zjCW3$JiD_o=H9^hWRPIeRv7H~C3G{$Xrlhzw5benwgPuZ@Y4(jHiW0}4vCe>0{<%J zbiF$Y_Kx3$ZswYd3j4Y640{7f74vf$w)rmG&{F?mx>;Z{x5nQ?H&?ry@u>C99^z}< zLGWq1e>#k?H}D`n^ZifJ%_5^&;(v{978^~o-mbjmXrp5mvJzZ-2 z+3ep<293tey?!<|O-8fLA40NaM)Qzw?%!E%G&_TZ~x_aEAo*o?e;+ z!5tFR(^sR%9TL<(AbNX;#9rwAEo5_pOYHbRpx3M2m!ZKO5^P%t4G-KQF$yFs=T_f? zcSx`r7O{q7Zy+kc(&0S)k>B82KKZ(0*E(9`;6VE%RJts<)9Vo))tmh(tfpJ8Tf?0drERmcBwj z#F3|NN-%QL14$l6kbO$XeM;H}g|-{%{pNlEO85}5^zAP&km~@f^mt@ca$#CJcuFEV z_x2be?Sbg=!!89d^1~sQ#YobJ4D)76j!)m@Aj0*nSn|VU#arR}BK18GuijQddP>Z? zl5s8q(9`>hf=e5CU4Xf0m7>hm?l>boJuQ{RB%WL`pw`Ih0ul7VzNW=E4l0-xU)cuY)MBa z<(~1f1t~3s-$YjA@1v{-8QJFQ2qc!itl|i=VuA|{Qg=%Pw^5ku5dvBG?e1V`Bf~zB z)Gw0kMZkSKVe|HG1cpRO^cOk)vs2RX?d=sN@@?Xsmhmsu+Li!{?U$<}MEXB-)!da( zXOoK=(?)cEa4~?~iDBr2y9%rj|KN&%)b$Q_3*3hmqZ4fSN?&Bq_O=jxiHZ@<&+^db zJ_HmO?i`eKGqoBQ8ra(o+TCdq+$<7oq-}F+h1|Hns~emPFSuY>qHK0!LsJv)$LTlm z!otAuV9^xEH1CFyi#`ij3BfyE73d=LB*1XhXNdgwL3W#Cr|GsYv^+L7;l zc*G5$^8)zsh`1=R+YAHE?{4tpoFVz;T08RFfroBbMyTTO>`V-9MA429(_hmK#%Kd9 zQ%dNbf(i3c)O65wWWUx1(CPX?epJun(eW7HGpG-Y$IYrkJ>I{1-} z{EoI?>lN^OLzv+!{Pv9IhAhhUaV4Lv_n*9;SpS+@Hq-!s4&+rg?^gC zmn&SaaHGQLC#Br3RroH2w8WtJ!Xp&ENMWVantanrek7Dtv{)YZbmt z;Y|uZpz!w;enR1W3csxI?-YJV;V@^uY(C~Ge44^%DLho+(F#vixK81P3O}fDtHSRn zoPi&RglDG0^AujJaFfE<6QfR2tpS#Q!JRb6L-lz@^Ic*a_a7?rCxGSO^qew3py&@O zOuph5ieUINL+pe%>6c0|86n0Y$s`sqUpS2F@ojD-XZ?}WbY9F z|FU<8%QLcfi2q;NJ4DLc3Qv#cQ*2#!D2 z-k!4uR}860P#t@3&p~deMtjIU3Kq>FqmsSsv|^t)3lH|}+~7EeZpi6P%$(Hf(D~@; z{Vg#0^ZCgO8fJg(rsvOp@R^ynlznFR`F~yc<=QTz{slBz(G68;mH9YD__n?q-~yVh z4)81O+y$m5-~W9n0C{mgdUb;P%mrm5JH7ey{lDGyUpu~-5%2u;SKM`@9B292#=Iq>tv59B=>LX~XAnyy<@-8}H_;`{Ub*P_!yi?aK5 z-aIVvNMzi!?VI1;_w}{gxBuzuU)lHA+RceSeShsE(aoFR-oE|qVdnyUwRL;>pH^>w zd;5c}o683ddu)68K-fBu+}UWyhn_-MeG84M z__bu>t>o!_su%2UOy-SUbJ@nni+gSQ<*jZ>NnX65PZuY@$|>E_r)R%d5bl=hxLYzm zw`}7JZYZ8VbYq`*F-93BxqUY7#wf?_6aVu@7#ym|?S01pfVIV?L)Y|)0qyzfKoGv4 zi}#_PpITdd#-766MH!Rbj9V(s9a&rXsdb&5XVx6pSdD#*Xx8E*vO*@yURnzl@%%n9 zxFDCpbvYSeaZYSqRz_L%g!qiCMWJy^1KK`I4~@ES)10JXF>_JwYuiHo;dMAS{=7)bz-B_rOJ7K%b}9Qm<*@n8-EzO z=9Q9G#=Ym3fOj>r^$)`;?!Ym4)? z7LL97&6|_!A|^02K@jt=Yq|N&9xXQ~dzTIF7aJ3IR=pFC-Ms(tWbVp0S0;-})@8u` zs&~L4(8ptIlX>f0C*FI1J5ZeCudVowyY5BD-+6Y~nxPw;CzT}qie$H~-5OEWmLw|6OSUih zY4LB|Kj+8$UbyJgY7B~t{mG@BDvG;}ERF5kR~hi@v*w(Q@!?6w*&TB-7xk!#PCg^l zFZiCIYw_>d2?ihK0f^M?Cg#=iZ=8L@llcJ^x%Aj`;7ufY z3(8GC%1twhS^j}!zxZp#vA2r3bq~Hy$ezK$El|KFz`Go0k^AfumwYiCn36RT;_)N} zrGge|F(W=9%G5|1Y|VGq%?wS5Cea3feCCzqfz@4)PaCtyVSAEWjG8#YFU(F{fOLVT zhL?4;={=FzO(8ztuL0iW2#X|Vim=ms!h@cyaT+*y*?wz z4FsZ5r3b>zTsFML<(Fp9=}+B&c?OLLLHau-4u`ZaWM=VpDu44 z?=%({_So}Y#)?f>wCo6i!LqmSnbiUB2`*X}Bzd4iK8(2x&B%1N=7{Z)XkHlU4$tuV zj&z+N1#Wb6Xs^5bukTl@$TBL?pS>THU6!S?&|QyrMJ4~`im$rsraEBVl1%j8&U)pQ zCCU;nxEW{#Ubx?FPG0i4!2zogIdVM^LlcDKK=Qq;7ap(N{US=l{58!RpV`qbIwF%f zqSG^=ec85v>HI>PAd5|W;VPi&v8QDRO}xGpd&`@X6(gP1eOp)Detp02h)6(T@@!%P zHC6ioMqu}P{`o-wQuX+fS(j$Mac1<&P|J>+^211(Og5l9daM|pv2s#Hjk6ndx3M^X zs zp1I=ZY}VshWyxoDy)e>A>}id=ExVexoY`{bin8i>mz#I3w7+dzV#@ z$eCb&^zXSfOQ{c1`we#}bOHYD(&ksos`p*kI&|rtJ9lG{;FMJlU0U;MVA}_D@h$;g zTioSkcWYr5_+(A69hR5fcxKD~m9M^DR#LWR#qFmSW07IwkhNX$9pdINd_7jI+|{Ec z-i<#xaERw`ij_^+SF*WmWWcp=22!qh%XKA*#Helg&<$$cI;CsNuA(Pk&ZN0{*O_}( zZef->XIzlqFM~`=9xpm`#hEQDVTDNV+S)Czq&QqroVnye+W?g$Gh4Q7EzCj8MkH3( zSksqXwAwqLE?X-7A5@8!NsO=862CVdxp`6$rsg-1hJBW4h~uD;Y(jBTe@UOLbZc|IV$HE z#1H?^Fsw%=yMq&$2hK+pcW>Db$Ezz7J*8Llc)w3Ae1dBo^NNU+=S=#tSrCyW@FEDs>-ph5w`bO8 z4!^y3*8*_uv3v3uXEy@oY%TEN-#>L4etVDIC1ad1=Qw-a9@Eyn^S;yL+LkRVlc3w1 zdDC6)m=ec$gd$)QV(ADJ9TtgSe>qiy-f*K)X{+CJky6V+~$;&zf5jG1JFIcwHnV6gyEOBz4MxPNXgI*MyrZAhL z>?(5xXuTUI`RWiao4YMy)?-OK3UsGn;vzUNv>_DcgwJ|6Mb`yug`B6tJ9H59H=#LX z3Uw7%a-p!>_XhCD7)1P2^A2b7WEjp4t>GsW<+u)e<|)@1=ZYxEH5`s`S5d}GbUDm8 zibY;C+%m7nC&MFA<|Tx`gNKpa^|TB}YUzOY+eP})B=RzSNQTHE8jg(l5x$wv!z@z6 z19+J{eHIx@Qzuq~*U#~E;>#Q=x&oX#$08Smz|?ySK1N27wTl$36a^qQi)Dy>Z0n5*K*8=yo`9p*Mq}96?;##6bO8&9 zIS3TJn$YnQctx)X zR0F9tFimA6tGLKMUPWF|(S ziTT{CYc+BIQF=eYxXJZLf^&4D+ZU771^!*+R%>j^{U=B^$)%L&O8?&&%qhlZsQ)jt zndb7q!f^jtvYzg;DpvVtQgfLh8|9B%V?d6 z&Q$;ZGxsLoSyku$_I}^w4S_^vBPwc$D5yZfpdv+O5>att5L6^&0wNhO2?!PmTC`5J z;yj?Bsj-9_ptWb$Dnp$wwp}P-h<{_a8Z^ftCxzdCD6s$v*hTdBHp7ZxHLOgih8MN z3O26H_E3y^sferBg0E)J*0JzXQN46EK=PcaM?TFk6f_xg1s%Lr&^PN)KSK4$U#j0e z*Qk(wyt6u@STFyE4nb*FohB9frxJvbkwz1GkX|a9BF#Ld)P|cJ&*lnxW&Ws)?fJO$ ziVJqnOw#d^Fv#r@I4L=g?DxwMO@2ueLH5j0)4WtfzI)_jbI&n4-o0RW<{}Kdh1!U~ zNy!;9T`)3u3QAVs*=fP?>lDCJxYyGKHQDR+B&g&r)atT~|4GSwJo7_E<(GVeDp*~F2CEWKc1$&nms z44%a$k4w3rDR`EZ{Ert4eOg^y2J&@?27KDM!u;@vJZTE>+$V!fYtnihL zpO=aXR%G9lzvM?W+4jIm$!|#Es_e%)pqGjmTfksLFBMU!v~%;MkAX8uj=zX5l^Om%OR3My zz|eK1#hFoN?IU_%GoV^xfNj8Z^PDPASyPf3On{Br_ur^&We(ze<0XzQH_uQR+P_R? zkvW+Ew{hCb&N0t&Jj+|ncLToaWl83cClnhOrt;O9msh0ATI0bbsV^RU8t-{YW+<`i zGo{k3Pcp-ZuP?sy6h-jyLgK(DrL?J6k{pnko;xQgnAHD(%(U#v1`3|C>5)&k1Iv}< zuCFmVPm-6Dzs%ZJg&GjnGT*|`ey*$ysH{ygTL#GFtMUyxltS1-neeXFpkmS!ytm0a z_%>O}Y{5!)O)~iHpqu*g4{BMe+-zAMjujqU&aoZX$y@XO%ChPa=HsD!S@ogj`+>9$ zsa81Ce0OD8ZT$lC4px1ZsTjhs@5;0PJ_?+A_fY}w|AI;_^{&CITfFA|njUlR&x5=4 z=?BV9?rVN%XGS8{OQ(?XfRAT$zijhB%jgRr()8QSV^Ww5b_UU8r&oN9Xj>QT3VNIbTIwR;zTpL3`OvlNrn8d6PD_BzRPI!PlU9 zi9=7K3G~lCpfO|Udum&m-(}lW_(Qjm-Ct+t!js`yc?YV*hW-kj3EAH%>%&^=+LFx4 zdGDyuhaQ1^pS%}UJ41hg&2f28NM3%CviYcT_EQ~D56EA$s=Xj7=Lz*olD-|JvuJ$> zWKPRl^RAqzGfnL%Px;J~nNH~yDye-X-8V?5XNGqkdP#?l(4leR(2VT)^u27m3;dQe zPM1b)s*%6uiuQtCbv~313BE9mz;rB86(wq=#8F-*ARTvpJ{^ad&d*{jThmxbPqed4 zI?J*1bHP^yA4TQ$L3!tB%U?0AeN+VpWM<^Ax$$!*%Ri6~1I`gaXL`uKqEi-=@?urv zU5ceD9GjV`kde$7Wqp@;4m7dX7T87WCl%R zdN3PX)O%83j>wr7)RG!Xh%0iEdafO_W)qI}*0GNj51=_nLx z>CVSO(RNc?;@DU_=KFqMJ2u;nxoi!ruw#mA=alGgnnAlqKBFfOrjyGQe0VZ~B~-iI zoVi}Ue(m}haiETMxh3=UC>Z%I1YgMzoFw&Shz~!>sKFZ9x?GrH08B3c!gNoNLtX>?BGb*{`Y0_8~pvxs8GgMt){=AZrdm+6%greeIs5C)sH3W$X~5Fq1j157Mp!lH>Z6Yy9Ze$LSVz>WgYYks_I5|q&-L3q_4=2^1@VfXotwXN`DyR$>AMG z%mO_^n_5w#SL|`d2b_U3S$kfxvSA(YL@LMOrdN;yTyW*@^h&-ok|9BRIu4dH$>})9 zYcEK`waYp5+;kY_s*d zTze*&&Pn|bQ+z?ri`uhE#X8(S1@UP(?`zK`t;x6p*MY-=xiI?37Zmjf0&{rTh@nxt z%8wW}q=-XgIbC~?J766VVu}cbVVk7i@FGDn4ToH360UT^wm`pa+B3-+JLJ5sy^C_v z?X%DJT8Af17%v}$jjWTBOfnaT{C7)MQr7*KBxURHle%KbJ zeWc&43}!-Y1QEqrr(MazxmkNQS+Zh>-1oGrIpgq;} z^K?VUIxo+>7Dx~u`7)1G!Ohzp}|2QrFT28~cS!V#Ux}hCduRW8@#0qg|=QsY_G2 zv3;T7?2yW{aE?l2-PnGHhI_8YmE?`>jRG#ygU1!x#*V1o=cwACx(QC3_Pk_8#X4Yl zD#v*^%7LGyp5g0&C$uXt)x$-72>hzx_2_v=@KN;4R106BT_G-&b3=-;1`pKb{uj83 zkj%gt7jQ04xV4bXz`0O+ezNkO!gbK;p=jo^Hek3dk<6yC9j9GgaK4=HXr~-sm%F=8 znBXx58cejqxQ*HiHJYqh+g{Lr9loz??;8B2D>P=}-L#VuK5k}`xkjx6s15> zE=&5ag9m8u41{l>c5j+i)TUi+<&t(_sdh>Tca?T!b&H&|YfM|M26uUA-P3Tc4mcg> zI_(8XVQGt^hSR<=4d)x$^(Tvy_Kaz-sr|jHy<4(0Eq)abH)f8}UQ9{~LZ$4VT{lIN zx!TpjGV6dE?K&rDle0QS9GX>7p}7yx?g}Qhvlg|5J43q|u?}}*;F0U@mitrfAw2M; zc16+Ic1Eo0r#7^&_Mig{)Gi&K=`4$KfJNloDGTE$tu!y``q?_yTniONI#^2HIataw zSV#B-Zm1C8oM3Sl4#p+l)DB#cdM;@P9@MTA4jkqOP=UBKE{PwOL;DFfX*%4Xlbj~A zdpb~D(tePDVI(L4bF^#Ji=zoPzar7?sThZ94C>SyH6?YNv^G?Yaqw~HLev83*(oi- z6C(em;Y}Th3kG5oXQ{HN0-Z+TjMAP>Myt8oc47wI{4D@d>Zey zb_+daMu7&-Lhb5%IF|fNLh|1agR07w+aULZGN1O6oE<5~eEeC7;yb!3d7NVHnmUv0 zw+^Qf3LxU}gPFpBR+ve(aV6V_NXW{%b$^qJ~qKnNp1pd8b1!*Hx zW&~Ve>pv5R<{Q$qP(a&K9$XW9pq;-+E85keXdh7#h7bVvrxhIzZ86AQqkN#9bF(S& zNGx_*HxDWm5{IS{LIRY$x=Jt5fhe6KzSY%hxZ|>-79B}7q zn|^s-yjzse3V}Ca5!=KI75@@uAJBUs13Gf67(W#>^=7;6-v;0-lDmT6)o38@^1r%gc) zd>j%v7pG6!TCQjZ_S7yrINwoc5Bk8p+9k*7p+*(tKp*Xr<8bB_rrQ~@yAd-v zr~V}Ftj5k;JpSD3Pij;AR}qZHbES3|HyvT7#SsQEL)s4QvW)Xez-c(?Kv#*wMoQH$LG@P^y=isEJHFuZN;?!Hl;u*N=i*i|< z77-3-+fu-xl$5m2!s@t7^q&z^0T zS-TcbT6rB~_;1vMZqV>jkj%Lz|Ez2BIahmJdqFbyn*7RZ@;S}te>wVDrk6n>`Z+tM za-*MAa8eQdvGwx4)E~4ff1k=JRn8xh@hCx}`A%{BwLT(0dA3#av zRzPuRIkRxm-Zuw_>xB>_zy)5na7C!=Z(S4O=YlU@!X#-=%KtFL15@3ta2}R@Zin zn*C)$jYON;gl%z>Hr@ex_L)tlOXdHU>)b923;zvmST?-ku%UGg^UL{)aV-l5wwANL z>4KV?^3Umn^#jXo72N-wrF9#tY8KWv)&1`nZ`BmB|Ix)@V^Jh3xvF7d1zoM^SX(z= zi{h&0D@9dH8rnL(=dOXwR@hae>5z)Uf{*D+x{Zrl>S}}!t;AGkG~JAd$&CC;TQ|3&lMHr_1T)h3~h=rFB_mH`6tz-*j=_D96Hz zuEqMz4`FlI(Y(M+UYD+YjWS*HJ4j!B4@cX(%3`4KZTLXhj<9(w^c!U7V>M9t!hE2W zUAvkrq$S9_m1uc+*CNyF6;d9S239(i_Yfw{LzaBXpVi{SBQ<(QJQ>gqaZIpdErJOe+)YVDEt@};b zD-Sh%DkZO@$m2rF-$)(#+H^%ODxoMl;x#4kStF}({=!*EhsO|eK;CQFHnd((0Lsp3OYh$yPgo@ z_4e93^rGdER#lVC2s5EnGF`ieQt_pp)*CgJ>AJ_~j#3XuBDWykKd6!_JdnlRqkkeG2=E8-d z_*GJjd}&M03n`1`NUn0$N-66!m7%?LZsvyc(-lY`g`_7u0fx=!10yK4`AdH8H-x7m=QFrLc}BTDFbV&ZQPl5`>Y)K1!- z(~{2X+W&L0r#Vh@MtP+F4{5JS>ml29kmOm-0_vze)Ds#_LEe&({$BbdHRC1Ly2SrA zH%6vQ+H*9vO!{vgqk(G?DYjF3q1C2&y0ATTvDInGXF?vjhEg~;wlB=q&2^ORLtr6&y8 zg1mD>E%tG>?&D2!k@nNHEzJ*k>~H;oc%n{PXP-|kl9kqmI(6oRkvFZ^fuXFj;a@fL zxluALxAY?gvCPx_VJ)@^+OaEPr79iSsp&M9*t60!bk;a}Q~jtT@gK!VmkV_hM;XHS|CY2z#&Y3kHk4r6 zlG2=~V{2MZspOx9>a?8p<205`=t;4ZIiHB-==0Ob={Zd-!A^O4wh`J;%&j6U$ou8W zuB9@1SK7CpJ3kEBhlN7?M;t@alwm8DeL8BTxlL=hv(I(0mX%8A6){w5hcmVAAy?;y z(J|ltF&HsItBL8ua6=w&mk$wH$_2=nx0F~jIu#!vm1PPx=h#who-|k4isjz;SF^EJ&elqa|YEUrSsbw`ryUAItr$8!emMQV}orU-TkjA>kn#IeL_~nTSRSmi< zm-VG>)k}yz{U}RqUCrW<&(`p@jncuV}=SaUV((&yW%4+AYh3F+6HI?*>BjhxE+eLZN zhdI*n-}%EE;WHriA(wyl>5%lRFcoQXK25l7`QrcK zJ4xwXm~y+_Q)wT4A?n6vRjqwcr+P`_;*hk;*4lb~;Dc}Mq@N;cZmLU5EPnQ;^NTp2 z`_@i9ubS0VwX~?+Pe4!ilXRO&@5y)6XZkT0KKoG_zZl~_H{`y8623%apUVl|sj9YC zbv608smFADdWTUZeo3U`Ydj1yA)BbVFTHer@?_UioIfS2Cz@!nI%=qqQ%rtto!of+xqs=K|^sW%=zdPvP5q0E;k2X0E zlGv~hSIEVFFAQiy4wuVCKF-PEgG^rUPj%Ure&mc|fek7eW4*m<>6scXfiCsU>X4VQx!flW8V;S0ga<0@%=j zW7tA_WP%(foyuOAKP)HcGlM{nsDhorVm*5b%p@*0!op0+C*F->J%tO*#8EbM;Qi#H z!^1*eM}}V$$Nau7KE&jGlo8TGSSFq76~3U)T)~(IW{90=a%SU4IQl%4WW#~UGIHiW#kR)-ST-DZgj{rZP|1cI?k5-d zSSN?|6fek+cXBw^3loLdumkTS7duPEd`Si7we*;N9_f!XIrCu;HD=mFjH^%ul9e2r z%;uwNu+vkF4DKf`HRdt+5M!p*>}h;)5(KkGa{f3CA>Vb#gfNLFO>Bp%2HhddbP*Sl4fhV|sWT9{(43ftDbo ze~<8pJhjQZ3v44Vb#k7c$9m)eda3D57LzaZnNk$nPkaWBt>l053vbO_-VW2L-0)$; zS(u=qYFKSu^%9*;wNy3M?Ifvhn%|t*(W>g|mb#@o9p+lk8>rGr?t;43on#F>gf

    L@E6l+C?I&73XMqb;X*McaokIEE1>4vFOt%*VzpKgZY~ zH#h1noSBX$5{E77JtrR{cib+M-stF&iyqsn+9TtCSbAX;!lNx7`-9l$W8<@Fzabxt zVlf|obzy|b&t#7YT5*f^-jTrD+ai1DVUM$#Xpb_AeM6YMdRF>|C(IV@;kss&G}K6- zfQ;aMwPTO!(Fw~=_8R7^Jx3!t=1{)Q&CCC9z6%$NfGeczPAMQgT|(QUy{4P5IgZEB z>CwEsmL$2c|k}Vf!y!4>MqD+n_zeWt6s!+B16vOg6y` ztlBnfk2+gm(|G`9u++9ydxq0^ZQHcRu-jql$dAF?BGC4P_ROGw$!FKUnS9gbgtE#B9i{4Lnh|E`n24_o>_gsmJtfh}!RLbRC=m+GK4+JDq%LD87^ zp0LHm^4d{{J7m#Le@`13G|6s>M9EbH0tei(7x41^bmj1D@I#XaP ztEsTXdy3;3@PIVGv*FT|=fIYRd9bCS7B)KzVM|W~Z0T7HTYB1HYoE(t3%kO}SHXkR zcvr(*%4xd<)_EG+6|lAWtDMfYu!X(R$=AY%q+!>?bU1Ar9B+iJPi=zj4`#FDEsh^> z`deYMxed0qy&WEw#`T!fc>=b$o`%a)o#&kV1=#ZVB5d||IGtBuOXus3-*Wt}eF+$tf#zXet>U zgL{fKNgy!A(jC^$Rrg?%mr8z!afSFu)8VbB`Nq7$bUrMbqol(zc(nLZwZ#AAF-eF9>Sj;x&Yp~8`;n|Y2jwX5GZO1Pf^WGcZ&P2}L z;h#AEl`#tj{MDGd!#VBf^ZFSpQNYMqA{ibpcL{9qUS>Q;Y1ruaTd?$>k^74Akeu$w znht5^9bxPcwkIt8gXE4e`8>&wG_Dn&WxP;4&$vN+9;~oe$i2|`GPxUI*bjHb@V9eV^yl;k_JD$9k2=i{xUB=w0{GRd8<^I%|bpF=yo5nkERR`FiE_jbR zGN+F)rx5(L!xb7w$HFQ%Hn@lZT-#Lb=F|{CJH|X& z{Gl=b+fNzuU;PVX{v-Yj%jUJR0~gtO&IhK$lSuwgNhkj^1;&Kk8&=pG6&5Z!kkqIS zOlO?jUmK=_DSkRexw@400JG@qioVtaJ`U|wNJ_7Qs#zl5s`T=t7JbC@tbhb$c zj%g_5|43oCOAZ&=^#zMQ5|;nC!%XKf>A*#H{yElkc!FDL%oE&2#yqvaLY0OjDZy56g_ip1St+-U z5@_RPNOWrC&NJreBYxyCODVvw%l)!3|F>&l*?d}d;G$A2rcZ0p=SeLer9kI7$>CV1 z{5PY+liin0=LPA&(GDwTpu>||md?Nq{Sl6Kc)E)YPj*=i2Av(!fuj!p>*%06(wL{Y zdE}uF&rIh->Ad}-cxcomPxhA`$`T+ zJ6aVv*k_D|V>Yn0E@SHShp_TB zP+{R%N53)oV9DVq|HR}&B!{ECk8ELw|1vn11KuhhtoqnS6@ma4fg0kjoC`bF=Y! zxwjhgl<`}zY)(~JIF`e9(_xmtyFjv5rQYe4gZRtfL7guaz8*X*kW~3nhnR zd7gt@X<+8WGSg|04jk+5N|P^^9FBE&GjfIHJoZl0X_F2d&jB`>4(C*N8Kckl3kb_B zkXMYEDe?)dvRWoPa7=%1&Rr#6AvqlF?~7b^us_I{85l#1naMH2nAsjIx`aM6Ihu?) zPiAEn?5~o2xM*-%N4J{}GdaHL_%35sJ$uxcbLl6Inbq->F*842fMtKR?88L|rS@Mn z`6ZIWMF*$yznJ_A$>E{{QhA>2l7422uw(No>A=xuf0JJ;IUMuC5(|W7Hc5r)+$bG5 zhGnflbeLtriVKlXaD1xcdShmyw7^QwTG@n)4oTCz+H{zS!g_GnWQGbm%=N`qV`im1 z2FuQR*@26Oq;{S)9cHV%WI7w914o@VOov%4e>RSt6PAV= zn#RR~XHlorbT&%|E;5}8(_t3Np^jOinXvS0zCwZhEeZ?AuqT=P0m5*?3uevXPb23cuvJiAB5d5Ib1X>&F{}m{+Q%&wD}Hl zrHAcP(|JNVa7=S?acc8v$>E~%RKGuRg=N;xfu{4Ebl@2F1e3oYIUL)06>^1THcy@7 zdShncG#R(a{h~3me7LqGEHis9H)aOURgUj~RSqvIUO48LHF1#dkQ|Qbd=R;8vc}~P zjDIHgM~+z)4IR=(d@!?rer^1!+>eYullzG=*RWbLJjDBo;)P>7*#o)kFk6V{W2EhM z>A+EkW60l<9FFqQCVy9QILc2%E}LwuodGkWh&43eg>qSl6PxcVEF8mLZSoH#hhw?j zX7W!Yhhw>Y9l30BUH?sEuFW?&`4(elBRy-(jHQ1!=9>Mlu+qalS~#{7mh#6woTF2aPiRt8?d}Qv$MCLjz@*9pnaGX`yMIAnO8kzg}k-5hbd5GiDj!$-c zrsD;UuXB96<8M3up5vc5<~~eJ!|xow;h6g{QHOet%zggI+U$ni+W+>41ia~&^o z%srW?^CidJlZkTf=STjD<6k&_#c?lnj;Ozn<3k;fcg#JGs2|n`Gw=(Iex?O2aYou7-HBFj>kDZ(eW9M7dUQne1YRD9pB=Zdml00?>c_i@l%dp zbo_?nzd6p+b$7JM^N7g%I6lPj5sr^_%sq-2mU|JAxpxq`r{jGbAME&W$EP};>zEY) zqs?WG*E#0;I_iAS@gt6(b-csz+m1hW+(m<7&rTBge2@ z7e~I-@zai3t}N;>TR(ECF9hW+tgPr_v$HzFH?zr0VV#n={`4(7=_h!c%9e*3PJU$ECc=9_Z|ARRG z7yk{pKHSNVc6_4aGac7E zZi3DJGABRZ$$5qq)58bDB0uPKwmbPR9KYoFEysK(EXMl}C-0_{uxNiz$6OOd`6$QZ z9iQxY25k8{6Snp_&&d}!d4rR;I{7juZ+CL8qoRGTp`!g89ItgcUvu(}PJWk@Z*k1E zQ?$u7QsjJ{Z$=L5cUr#2J9(YsFFC%#G1nc@&f|`sbNsR6eN~oGe~ja5$Co(1+wqf* z|Li!YYmR7hKgZ)7&vCrW@y(7mJATCR8;)~5JL4Mac)H^`jxTh4o8w0uzu`Ei3x=4N z0gjJ!e7fVyVU-2jTF2jZ{Fvk4JLa49G3X+_{WYPcl?y&mmI(B_zlNzJLdUQjF;z3krQ3x zM9z22v+^kK;h5{VDBssHZ|+9ujBh2GiNO7{LC@el~Mjn$IK;*a;`BW|HJWTj(OG}b-Fp; z%kjRBD;$qA2eQe8+r`Ii_d1<5iAVJHEp4RgQ0R%vZvr%?*w>I^OJf zi{l?Se#kL%38KyC9RJqw?;XG6_%DvN6i|nqoMXN=9qspXyr1L!9UtPj+%a9nE88A|3b$XJN}B}HIA9j5X0W)c%$P@j=$^pdyaqX z_)*8qbBOkzbNs5~Hyty_BIdzxeJQABx_<2uJpj+vVg^;bAv<@i#^UvYe!<2xLG!|}Hr-{<&2$J-r0=J*$m zf9aSx9x=@?JLYrdQT}(wpE}O!o<`Iua@@mliQ~N-@9%h!<6(|RIR1j;qa8C>B&Okb z$I~6pay-{@wc|yOn;kE8%>2?A*OwfB+3}T*uXcQk<8_WVI^N`%IjAwNhaCUZ@sp09 zbNqtiKREt($8R})*YQV=|HE;C?)k*@baULt@g9!(#(mTu;&`NE?rTMzagHZBKEW{` zyoma<9nW!G=eXYSV#jTc&v$%*G%f6w>ZAT@tuzOAX-c__uL|HbG+U0wJ>1^_j0_u<9!@+uP=r@$nj9e-1mz* zM>{^r@ifQt9M?KtZTw zGiN5o^@(F%T!`{w$2}eI>$uGE2*-yxKHBj_$0s;G*)eltVj9kHT;;gVaf9Q!wH-sqS)HZjf2Igh-}vA;L_ypuCGJ?j6_@tcm{ar}W}=BUT8 z%u$bA;CLU$%vX;(2RR<<_)y2pX^;9798Y$9qT^E?GruQ>J_t;}Oe9iIK9dnO8>TGfR1IG_J{+VO$x5u!*cl<}kZ#jO~@kfsT!!dK5 zqRnoOxhEgxdpKskQzGgT#jxi%UgCI# z<5iBiw;#h^?)YlQ*E?S4_-l^ucFZ$^XmhLMZH^yx{J7(195YWV+WEcXKRV`_Le$}l zI+6eGnCA;o&hv%H-5u}lnCA{rXMe|o9FKI&dp%MAD8~~VpXzv~<2jCbHWBSGk1KMc z<2J`Un}|BRLlpTU$5%LJepl4F$?>g@?{xf4$9w=ShP~hMHpk5GiaL)w<~^n;f59>H zz@nV@n*O{H_svucRa@NQI3ywe1hX? zj!$!3>6m$CF|G#3yu%gc7dXDiG0$|O&Q*?Ya(t`f4URWDzT5G49skhr!;X1o6ytr$ z@e7V$bj)0}sQ-pzo-su^bJ8Lg=-EhQ=Bq{S?YP7-&!?hJnd1?T4|9B!;|Y#WaD1}k zS&q+iT_s*zS8kJ$6s^2$?;~#_dEW+@k@^1 zcKn{>j~##Nm}h*kUbG;42lsYd;&@-jWsVPWJk;@Fj>kAY&hd$kXF5LJakb<5jvF1H zYW~YcXbNsI3_Z|Pk@n?<;^-Mq3QL*Db zj`wg}>Uf~zLmZbo9_@InVsAtb=}i(U&nhp z-p}!Yjt_P`-0`7~k90iV@f62X9nWz*&+$UX4UXF!FLS)g@oLAHJN~NU8yw%__zuT+ zI{vofyB$B^c&p>>jvsUUl;dX||JL#E9lz@MO~>y!{=o4kj(NEv_VF%`S$84Idpj<1 zypQ7njt4s);&`Ov!yO;xc!J~O9G~cThU3|eD;?K3KHG7V zcf7&zw;bQ)_&&!EI)2FUPaHqt_-V(#a{ODze{}qs<98hY#qr0EKXtsDUSf%DpqJx) z91n0j)bVh~M>-zw_(aF2IzG#BmE$FjmpfkNc(vop#c@r%tDO8=$G13M=Xj&zO^)w% ze81yuj<-90-0@S6UvT`Q<3Bon&G9>q|Kj)`jz4o;ph0;{T-J&9_08C z$0Hmc=J-g*;~gLG_$0?O9iQ&F+VOnHjgHT8yv*?m$6s>%Wye=KzS{9kj&F6m!SP1N zcR9Y-@m9y%96#;&Ima(Me%0~&jz4t#nd3aI*V0kfj=MYF!|~pZ%N!r*c&Ovyjz>El z>v*E$V;!I5c$(wW9iQd6!SQ0p=Q{qPe#eXxd6Y~Nk zd0!yxX51`ho*VMz;(d*o4?Ea+rFew#m&L4;gZ^dW$;MZRPci zyUCb2x%U{~Eq=h5Ik`VH=3UR98nf2p)5hDx&l^7>=G{Hg!#nlNRfAcx>viM5i{CN+ zRQ$d%YjAyR9KIN&c};}fUweV^U~#cA>pu229wzQ*JY39LMucUqF6$h@hiO09_y{p; zBq9F-$Bf5`#~V);Pc@z@KFyf*zUCP>h|e}|61N$jBVK9DyQh~JvkoQm&4_oE_O-^0 zd3PE!&v&!&#bVYxME?ry+l_f|_2+)5KGa&l0oV5jw05##}PETFg6@@B(qIG3$n%ZQLYgE*UyY#7m8tx4Xi4x%fh3 z))`|RNc6ufW-b|gnfO{`#=@J8uN1F0Wz1)b63jeb){}&96|+7P ze218MWiV@+{mhs-zfT+AEoNRBIzJG^%yhO~}PlR15{-H7NOtZcd z@{7bjGiI$g-jhXsnfQ6*o5U{~uNAZI6FQ9LtosCiNBoZQ-QxF+9~HCi6FQ9FIn9rP zpA<8n4Sq)4+n9OB{frs2ncIfWo8p1SZ;4qC3i*3t)_{WZHLftv4elZyYs~xEtowwV zHRYxlGiIM;++RGynDM*PnDKkQG3(N?HWYRkzgZ6oX8c}h%$#E07e;=j_%h?O#8(;D zh?&oZPMvtIalQBs;|4MF+0bEr@pp``5N|PNoPN;wUNLjq(EqOZ5o6Y(d%~EpoH=jk zJS~2~_*deWj9H8B72`L>%y~nfar!;u9^wy;8B;$s9xLYkW%OBxwwp0?a(fyt6qgt` ziu)Tki_46edpp>e_tb|Oe^ETjm^ry)j9F)HoH64lbKyt>W8qX|#=>dFjCr$-8S~~E z|6E*ayhF@fIPAPC=3Qy{O)+a@!Hjb&j9GJ!xp2sLQ+vO}cyBRl%pxBpzSj6~G4EC* zKSI3Tn0c>v8cz~$GM+5H$M^*C1IDZo$GkY~TqFLeF>CoUFAh0l#`DIkNB5#JYx=%y z%sBD3@x$WxjhV;#u`%nvF&7S-&xs3+87G(vhn#oong0g=NzA+3@Vnw6#@*CjnCFJP zyLgQ8USj6CA@46{4PJP(c&hOn@igOkV&=J_Lm!=MTrXyx8}dcsvyJJyi;dgFUo^f@ ze4#OOOD{2I?X@e7>1WJs!{(2~Hyb}BUT^$kG4GP2^AqtV<448!82?nvx?bqeFCR8$ z{WsS2Le6@~%yWbPB7V-8xuU-@W?jA=#;gJGC*yK4Yk3itzLMyo7G|9{=DESF4Nz=+ zytub9eT8?=(K$)Hukk5j=D8tfErElLnNP}kU&t4V4>N8Mk2P)*Gye@8=95k_ZWEtm zOn+jHFLaiPSvL?qPdv|gAG5(qO31im7 zWBwaD&xl_z-XZ2adgSkjUorkr{H8JelKF4wd?Nmv@u%WXj9KR>t9euCyUp1a9zRs9=vTKbOi|;UIEkWkOVP~oM zJI3dUS$hrn3h{%+7l^kRv&Q=)#;kMrgfZ(8K4Z*S!n`=_Y!JU>{7vyI#>|<0)A)Yz zyT;!W|IPR@@h8TN4Oz{z!sct@LSy5I1-(-$`wv+m$GjUN^>FOIlaOXEIc=Av#jeop+b@vp?pi$niK@z0H! zm-?LXt77KGp+jHXVf?=MRpXDuZyB?O;a`k6m#?{1@L+K_;|g&v z;|bz^#>a@6BZvMJ@j&C5;)9J(7Y{d{D;{l3A3DmoO+3kXwfJ~r)>=Hp_(t(*#ld~evpykntqWWQu9ATM%`lj)L z;&+WJ#D6npo+)$W(5F9T^*{nXT+AFfc#OEa@lj&t$RVF7?r%(=V~!m1DPp#a?8Ys! znpVei4Zn`!Kqs$o%=3fz9At{)8II>UZg9NJ@oL9cIbQ2{qvI`(w>f^o@e7V$ar~}h z?zzYG7wTSZRfcR~y+LE{p~tYNIOe{2lrMDL=6IE3?srH18y#7R9z0N4-o@V5}j!PX6aXi{F-<61A zPjNiQ@j}OKj#oLp!tsrcH#pwxc&p>b96#rHhhy&R#dLn?nEQHB&b_?I+_Q^3*zqXG z;~eumCF;+1Twb@WV<=hgVcoxZlIjJYv+LI>I)uTl+CnCucJH zld&z6%uPCdI!9yDgT|jx;rL*!)odRLlE3#uJHC<~d_jHYpaBDPw%_a4yl>|pnH!uv zvGA;}jor@A>&iprZ8`@!r}smpyS}3dZ3^UWwvZ#{!h=Bj zY+;UtqOyfurt4UKPq@noI-bw@QeMxc7|qW;DtZ2&^piIPNsfU(zbZ3WT#%nP`ChqQ z4%biKluJPVTl0=XniR6m^N+Q6h{YG;Y6i~FCgWHfl2quMMz1+9{Ib=EzHx;O6?)(iioKq19PKzQeKotM2Ds6 z<}@mIcp6hN^3iZ%(L?&p9RU{?9Yw5T;GRVv5$hM=zD3y2jfMLa?TgNlaQ`Ask#a}D zrAbfDF$y!eV-J^GbUjC=fJqUH+T@OdSM_=s`3a;s$@KabQJjP)Kck>>X#yc5`z1a9 zES;+|xzjJgUMR9Nz@+GE?43!h`9+Jdch=>S7Z#C#+*~q#i3$f(g}3O3-E8*Azg?c* zyPc%4g}M4i&#S!Xi$obKjn%-{PWYvHKmkd-uxf`AP1sJ0$5@gw@<;^!pXDRCMlsGTy(4 zDG9mnouTMTi@t`=_b(L>EUF;4KlrwIaM54M?GGOn59waHq&mqxgv|=EQuZ(@8!cAS zevJLGMV}D%5f+gdSJaKLkN!?Pv3q5M!v2h~lZt+g{7Lku7PS!X&ll~_Essle3aY)~j+3Fq7i*-`q}$S-+KLCjNFGMbV}j}(`%qEha}5T<9z-%&d$TcT05 zZ^=!xrc=U^iV`N3}G(=;g_&ByI_kN(LG6?h7CXyThV0BJ*+;SEF3i5K!GHE1G~e7s zS(@yW%pOk@=;G|L@=eX`!StWprCFY2zL?!(6*jKSvM$e#>>lS4?yFgzX171dWA_N0l$4>>FGDo>CEvueXNHiY&JvXcd-xQ-^a4vy5>AOI{*OeW=_iC9JfS zJ3D*26iz958MQ@Oo|w)q;omgZko}XKg(XXAQH{Z~xa0=HGzHJHk^@m|&R(U|tSV{8 zvpBn6o=Zv&CqL(ec-EI(j)9gCW<$yKq@Xo;HkJH>Fm1uJrQ~f)FA1KlC6{w#Y4B_> zVVY3x++gjAq>#EN%1|JCrhZ}#{w}GX6P@7SBiZZS+=?tGH6_e`%C!ehN@kJ5RoPc` zU|CYg*aC(y`y_=FD(&3-d%v5j3f-_jJv_H8ONI1jCQa^wEODi=9;ikgLi9`ap#z5I zrpia&BcEQl4}BswO`h&+7}jqg&7)QjLT8hG2P!?8q7x-$qX}fz7U;xdzgme01fd2} zmIurf(dq_kFa1M@cLrW2iDrrjwF>XQ1(SHcE$@CUOY3yBSY9S74#2>^@|0y}<^44? zvn+F(oEc@=a|-j;Bn5Kw<)0-tk$W2HCfXkPBys=SD9aIf42%Q+O+N*%Ax=9Ri47S} ze~7)vUw zyOavkcv0$s60!CSYPlG1FK0_R@4b66NL{GU?wLV*rb+0VQxfzC(Ge_1!b&WdGJwqgxat z)2_*%eoa11D=yF{nm@=6VD4?lwwEZA%)l8G@C+QZ^Aokfopk#Lg_$_1?sTs^b0^(> zgYIcKC}op#f*TE=wv%#cP@aX8DzB;amS^pxJXBiQWKDvLIZVfmq^YNAQ%A53owzZT zGaEk4n#ue_%}bX#>OCreBvZbyxv{SN+_M*yPpezpTwd3@cxdzDx~8G6wTsGYTAEv1 z+nSpjhMsh6`LOCG^$oSO?Brs)K?E3F|1-(g?Y*)s3~u4tCgGlkJ_wns%cnK zTUXw?y!HRs@UphLrq-&V4a*^Ll6UGF@{?Ca=9~k$y8>3j%iwoQ)DzsLNz3D_d*pYwMfp+mg!p4OI(TMWc;(Wnh9$VI zD77wZZfPs!!m_fZu60R6o36poBR|1HYaJ$9Wv;b;K~q&jYWm!o)|R&B#_HA>Ye-O1 zd2UO6NJDc?RYO~SV_m9US<}3P7%JNuD;sO8mM4`9LJ|~SR%9z$X&E(I@wC-8FOjx# zvy8mfHP*E(sB5ZGu$rZ9%4t&B6!JIqc!2i)Ll(ObF1oMKBhulDiN)9N-L>Z*sRN&B~8>zU2SR2!YcAd3#Bfr zYL&CPWo=YkTWy+mHH2!_Zl`)@Ryxd(r=2{N3u8f6wx-qA+*C=;RHpfEtPXW(Rfu(K zR6AQy)rCr{X>MLruPjwpg^blV)Fo-k7gRMiR)t0;N-CE$EorT*t!$}kvW%#4)wU*$ z&9w@w-2cyZ@N@tycir0(Km(wOTK3LW@lX%SwCi#;OIljg&ns(GqYIi_)KKeND{Gcj zrFFe?IjBnOs+x3-sz$DE+tI*ewW+p#L4BK=(geBmm&U4P;tNhbj}HWrWm*c1d0|n5l_d;i-vNp&W)xtcC$5nq3kaPufeWT5H_c(wcU5{kQ3s z$;63cN(cMDztZ8uM(E$}pftnb{#|MM51Pyle=?QFHO+5MW==n*a{PqpCr_O@PhI>$e^~4CMipW*jG7DX z!bmN34OPSHTbdgyhBau^Y^iEUhB=u=zqVvp7>R~ex3=1`+Pdl`8n{}j8tZnF)RT*0 z>Cvj{>Xy2tI~`_xOO2a~TFrvGosBlsH_2vtTxm>()igIYs#zz)(!bhaX&fPm%i2h@ znUrU7OY>s#{NLS5rAQg-$|!8yn~mj*Af68KdG^T2XGp;F;`B5yJ;ps*!h3sT<@YC2 z(FU@}!lXg=2Fk^r{;tC@?2XfoJ!EW)Qm5lL*8gNlNcX?eJ4HG%3`QEXbH6rjF-<2( z5Se3FDScd@kv^RSbfm9Z?Cq_UpLvdPi^tBAz}tI8_IP%IJ=8fyew(z%Fv8?b9sHFO zM7&@Zy@zxq@-YEyi+U^M_wjBnOTztd;w8Qq?;3FoBTT-pgQb9N@z@pedwUfFJL`>U z2GQQXiDMW{{8sjM3#VH6I*+XvdwVlvZ=PhNucsX&op)=;UaYIv65M_7nST7dOy)lJ;seS2}VbcTy)rer9CqKTIu=z5sy8iV?G~Sln>HPK6vcGG5oJ+ zk70yKgY3n$;*ZCEFZTAf$sT&x(^X!Fy%DOjsu?EO zAg-R;X^Y<85Gim;6}MlEZATJXeedWPhD#HWjAx8;Sejdlw1LXCR=9y_Iga%5~|W1Q

    eyJTDe^XYDQXbfA|mtb{+L;Iyq} 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 z za6rDmgm6IeRk(xTfGnh%a6tZ@2809hZ8k@I2iHEF->yKct#)KpHAr z@g2OGIpRB*!Hp@tgN8R!I3Qo8Y2koOXBpvue2itpckly_Y4IJri#g&ucsp~%cd&&C z@g01RW9`fP4qi$#!U0*%79KhWB=>Of9b7^aUkwN3IcRDypDuYRzd|jMBFO_PM9}QUF;8E3!Nlq7$hMlK)-zdNY7xT{QTlg$Z$#euSGgoRS7eleh+E#HB@Kd z49K&A&uLr&$M$=v>nECh9A`%y>^M>6L6BN}o_PkC-7JQrhk!MJyQNnQ;3 z+o0#V6Ha#B3E@>3cU8Orir~P6N*33v)0-%e`~x;99}A~ko(=aR*LW=+%@$Nc=C(JN+IQcr(>e5M)wKbF0GucaML%OGHYHRRE zc1R`HVH#$z-XoNfba}*Z%j#xmDBHzJE)5N3drOOH5*;j`rb%Qc2rBV>lXRB6Yu`z` z9FA%Ixs;Mw*d&@r66r7G**K){$VnG#*CK))D(WzMW_F|;&XrnNRk*hmd>n1AZ^$Cu)2pGXO(4quhhkBj2JgC|8 zA$UhU2*_jl@N-OkC7yr(Yy6Ij7Q-!T&KGlJtXw=7K8rYH52;#GTi4X9ww_KPjv@GR z{Th{vBaUunWcWIIe15~!xH1_&i@qZ6X*en^Sykhs$5 zNGX;*(^wEm5E5hOfbNPFODn;)GWS1D(THZ$)zbOtu=p*`S>|q1`VYaeYFRZLtSX!6 ze1&=%n?ORhth%XTVO3lV_qE2FYVdp3&yATs`sp>+&aJPR9dn)1mKbWi{~%|h8AjyI z!z$I))JxOn)MEsKhi^_j{@7wb(v(sYgAgQpPQ~!rxyJ8sZso#-Sbr!1k-D!Eu562I z8sUhBuR+i?E5SKv3ZR?jRT(=COJMH++>M9-=mmzn_`X?DZ+Hz|;={PdplK#H?ef~D zLU;Wu>nhBqs%!+$=E52`;jScB5i8{UJN+dSo{|-F>z7n>{JG=&usBZQ3B21scnBZw zl7n@kT&fEH2dN{!j7Q~vgEQqpdOUJu)X!f2`5uqv_{H&4(Nu}Y3@3~jF*ufAy||&V zk#7U^ns7p_Z||bQ-i1A4#{J*8OT^r{g)_COroOSVVho83r%W1EF>Lsxlg3S%JgQ>c zn8~BchmD&wwD725!^aHmYgxf~Tb6+_=O+@x|B+KNp3E3C(4Udhq<&Z^mnlyO_=rCv zJ7J#?Lz*3n>lzby?_D~b0+~JX`H5i4r{YF;7sR~8WO?SX9LsBaB}mIg0F2w{qcG(w zVQ&ax+QU31Zm$HG_9$ccfg8pDna98hF*ovo^va+kWdMzjB4rX}9mhf-n0e%U+<@4< zq)xQ23Nmf)4WwVe^`QjGn+buoHyO@Hu_V_X)usRV>`2Pc#&5AB{7DG}uG&ZMc69!I zEMSA^twdVa+td~HB9rUE?IrcD2bMB`P8}Yq#RzPWymd%xdzW=fjDu90N4wW!kureJ zI@numrkzYB@-_l%d-uTJi;%H>X*Q4cc;|=qc#*{L2_E!4jcZH^%;U1f#-jHW`~~ww z$>ve-AuQv#Ag$M91CB^+H`n9y{22$rUa7Uk zNbEfatnF=rJ?haOACobU_S3P*mw*PG)&=A zi;qUk^Onc%$lM0vv%&pBF!w*f^a&9A7}{}vgIvn(q=WT|KF?Ev2PiyLVV)~Qr(EG_ z3eQrwR^g=zpQ-Q~g|ATfdW9cQc!$Ef6n;(Nw-x5y9%=It|3h>PLOI5o^vMzbL$^FO%((2`u__ToSqX98zES6gmGEK1I$ugin!EvRw2N{rWi1>TYoiShyAQ zf%{oG=V*g0W*-aBBIiV-tb8yqspV+11Xy?$hXV`G;z(fOS>!emp2bq&T3eR$yM-1{ z24*zJh%R_AiVv9N1Sd#12KrbMD9);{Lb^O&0z#wr+l+GW~_h zv}e5~FRlJ{ZVyi+Gm->3F@f0~{xOs~$tU3NF)T;% z51%FQCmj#V;gEmCI}k*s(C8@E=tStN;y;mx1Ha?tjK)9qNhG`^B=?^*pYVRD1lmN| zWPcKOn3N#?;I6m`qR7?E?M-MuSxvkCND0M#h(nQoAk)Q>h;bY-a_g?R6q)>FH5p`+ z!}wc+#WWlh@lXJFMIL1$UGWzf;I{e_S|8}vG@0^Zx29j?QYkQqI1(Y}WMD9HTI3kw zV~H~(r%-1IaaQC}%7+qXM=qiKIO3R-Rt=+cS7fh7USJKSgyz126Bt9>oNhjZI+ksQ zvxD)Jo4|zM<0KD+jGmolMexaLa-7p$@dDa2T{fN2iR5xkPGznB$m^_U=B1E_B5Xil z7FV2~tfr~tYw^d$+HB>&0f~&1Ct(`yioZc3GJ&P$6FQNO_zNsBmSKTIB84t!a97-e z$o*us(R4pqZ4}*4RuhII#^vr79tQv_B+L%5~fJ z6!c3X=ioo^@JslYPgb++$cW)tdyM+yBKJ}M@g=}zk$dqU*x3=aPmW|@?E_Ca$ekMb zkoalt6f+`O#LuuS+!Yy7J=6Sgr81|WwoJ;=o1Kx>rWAk1U6DD_HAul-(I`Z(W!+=F zLvZ%=M@OS+HW7+`lE{ffvsq@mDU%j0f@QcXb_$`IsQEx{naL@PcB9%vFW*t_A3crD zoMdu}qx3L_yW${}84}&XdZv20E0#n%GcnDmjf`$XNw_OAr!=~l22S-Jk22$;r&4W} zQ7eny$+lH^xjK`hcTjD$_aodunA(=Z7w(E2viM~66)d#IdlDjivib}fKhIkRd-!Da z*|c#Xytf^Gvf4P^UgVvDJoCwFy1e0-cmbN-%FkhFI+`n{I@%;{NAnxhSuEAcKM(({ z&qXKwWN&qfWV_G>)|lk5N|;3H`yepKMGhLX2YKD}JCepB_Rn0+bk9>*v38Y^(_L`@ z)+B27*tP~c(KEUFSsu2~AN?bXwDWLF^OMzF?^b@=Y}XU{{ABeq8aRm?s>om``U58V znMBb25_Esh6lh1BWJc$rfNf!WezJNkHi7#s>KZSP{!aAAG%&|(D1Y=eHfOHU3PrC( z&2U%bF|Jvgw%nNY zCb2xah&c`3%h8(VD33#MSKNfe+UTP+aJs2yWAsUuS!~K&7v)?5?us;hbMyfwnoQ!Z zXbVJeS7gqX=x>-}AnBWe4|>Rm`jOKIjT zFR>Gy%eFUr-#}uylgwiap|R1?NoJ>VoZEBYKCYaO{y$k065h)3Z+nZtw5iKevI@y5{9U_VMz=!_gn%G!Y3 zNLS#bc7#rZA5%|i-xbggSm<6-36^bpkPRDe z88e|fMH`!P6*D9-$K#yLXsv-W7>Tiy>rUMpjlv{GuI^N=o9G7W-fVOyGjerL(YlFlpzf_kcM2m{ z_hhY`=#gwF;AntgkElR$=}74{$n-jY!I9_d=x6#V!b-YN{^v<8zmRL|!LntVyD`-m z!gLRvT{8#%q1ZWVR; zyOzaUmG*@`)AeGdSE@^~`59E2?&pGWKCi$@yqaGQru&>>8>BlUzM(q%>+m)4!$GlW zSJFAmUl%_Fs!g^4ZjrTQGi;p8?=#08U*SPoNuSc%#)|6YmB#;*goRag3(WSQAE4|YDJ^nMMz6@0Do2SC^ciud`~;>L-{pxE5+_$x9nH^ z<#AR7=VA^CPOIbn;rf(f;A3(P%F3_rhsY1rn{CT@aHje!Y`RE!#?=c`lx1co`b*`C&YLVA62@saEin@h9wWn3@lwN zZbsb3VooC&=*P-wSZ6FOD^n_7SRL_WWhd+tVo0;|aTmh`J{OV=LxIdrJ19(fEav(Y z@^KQ&Q;%2uEU)d2Ls~WhVB8-4gTyxFWwC?fvgy)xuV87lH7 z6bF?AY13E;1T*iwSfYKr%OmSs1+4AOMq(DP=53I?nMiAU8*?3JGYql+a0ei6uO3*+ z06O>M`g<@(vJH~A3TeU2;VHbZ&#aIszNS-g8K6dy8O?dbHQp=CNP+++4;ypwpqj;Ar803A3`Y> z>hrien;1H*pEzvWP)9j*nh`H2h639~9JXz{opKxpBphz8&%Q8BUl#5YTsPV;LCi&X zKSvTnhk@%weQr121{XZp;vXUAdG>Jo-Eu664-?0c;1LR+sPIIErz%{b@EnB~D6IW% z&sOra3SX-5j}^W{;T;M;tMF?I|4U&H4luG_5rx|++)3e{3J+6wyu##55u4{Ke5t}$ zDSVT{cPq?iS7PTk3ja~zR}|*A{zRX%RKY0N*NZ}_Geoo;x6nmmUHNXl-subO6mVr$)8d37nFRr z!tW5EEUBHiaKmc&EZoDg1)MFDv|! z!o1j$w(baO{YoTa#bSk$cpDPo^8WML7^z7WiPUoh8SaH+zR6+TU2@e6OPuB@K}$M6IC zg%=j}9S~zUuwVE*-c-PRsXroK(HXyRgWW%H$R08`?7{NRvfn<7LzdSw!XeucnEMUK z9|POk9gF01{4-y3$eQ^qCyu?5$#AM0kwcb_*5Huk2Z_NUdyR>bPR9mJaLD#X3LLUA zYFZB2Ch8>(gBd?3uyGFAv!LVuDb5j=LzW(w`*O(MO5>&9LfNEa3CHm8>4XaK*McRP ze?C0AP0EMmIEU}+g@ z198YUP~URM^4KmMvTfPN_WSeKacwP!?4|7QL*S4dP5YKZb^*)oheP&<)Ol zL@4?}A}10(m1XwJA={oSC>*lJm3^Z3Ovw62jeoRo$S$D)`Tjg_h{wM_&ogTL`}04g zHQ|sooW8;#dm`0@L-xmPn{dcp#_kXfSq@(~Wz#PcPT6EbPjJZ6dl^pIbT@@l_A=Ut zbI8tM>eC#u&Nmot8tk6sr~IkTrX(aLCT*>I;XgVdOn9hpeI077p1zu^Qo! zVi?DyFm;gB_ND+q_|QOpqz*%2%w9I{u?nsCTYV2*IeZeosb z$dbi0&LL}FW)Tiqy649^WK&p1IAnLQjBv=l$^A|^WbbCqfjMNq&$0I9Ib=&{MmS_A zu!V=tAAESD>aPJ=qdoU%D;n$(C@+ZCg^HTGC5e!l`Yd zC7+_N?Q$cxpXHDp>_J=ZpcTa-%Sw)L$nvQTzMSYwg%>hOV{rx7RwXgq{wFwOF*vbH zl`}fpz^RPPCBdiYWO*S9XJ$sO?qsc-aOmZ@o@8{(8S!#pZ|~rQ!X&M*KMQ+t$R_-N zd3}Oi*jP3Z{^YWQX?SMHa0$hH0c zKg9RCk3a6AIpTgL4ybb2tEd<~X51*_3QneFy6aao?j>^l_wD!Y7gi|>9)fO|IK1>6)wSYAWlOEP~z2<;Jbm968~UUSk|p-4_PPic0@=NsejG7b#UPQ~1s zCh%0(&}^d7)sW0>SiAyzxpAcZw|e9L*U`sv3Wn34nTl~nL$_PGV4z%PJDj;4al2(F z>>FYbU;?<8-!1QhOTcxI2_5h+n1V9g1n+{F&lXvpc`V1?*Y-+~maPC7x6wyo%9~)1 z&mm|JbDOxm5@6b+jNu1v6#r))!)Pqr$_LUbgN~E|JZS#d&1l~S=(Bxzj2>@a6|lDV z2GR$^A3F{g2z>TWd$^R0+pFKl-r?qtt?P<<(O}lg?Iqi7{XX^9r9cld39^psAkgDr zUAM$I;4?e1cRjF_p^bI0$443xByS@G+TLc^dl53WkIzxW9-n=&Od%GAkMXekx46EP zz&tKnY%F>^;A5C4N;Z#r4`JbUl<*exiY0-VIt=^z-S)(Tb#pXvv*UXE`rTgE-R)nl z2i+WHJ-BXSn_mTt!qp1TRrss+ z88!0<{vmKqCjFTSEbaV+=NH=#A;k0rWZ?OQ*vzdg<|gC0hH~1ASxo=MZWhxYufSsV zagoK@!15h?K0A`{*vEk7JNDgx>2^W;+$QoJd(MmGJNDcr@*Vq8z*ScN1Yr4&J?D3I zRz4Y+L3{@_=JlbhJKHU|i^3caA|Ik~pW?p9z~L_*4&)=)uc&{~!E(o*!wDEJQn=o5 zq;Wc$(P|RLhm`$&IK$fE!|%^5tjV3}Klewc6c&ywS-Y`h&c^NihWgi}Im?3u$%Wr< zaeO6<7OfvUXQn?GbT$Q@b|ub@S1&pvwj!`RIChHUo;%<#V~<%8STyO<(P;nF;Mh6S zd}I5~^qo84t&&kKCBt*a4Bze_Qx107h`$mOT(2{@Y5K{FM>!ovo>&f6(vx5M1bMj_ z0$X=y`;z;9>*GC0WM3Pw@wYzO6Y86>H7#X##@3C4D!r9$->Pgq#xw2o+KDTM-Cr4f zqO#2km6<(qF{oS6bKV|(T~yq+M|#iB;k-ON4g_J?s=QW(+cPk%Ag49w#&v*X}%Tt6Rg=+vn|EyLHz!yPhddA3WuP07{KU>sTn(xtXOh_Cz8NXQh@s((?TF zbhv-bOnEFd(h2!9d;>EAMH?3lyrd#8;3>FsU`A5GZwF?i20iF;ba#iY5&t%{Ec58D zx0{_a`~1Pj7Wtg;+0D&O=ML_<4J~jA`)zFQcX5Zj)n2FQf!*hSdv(YOUw-k$P2aos z#lq&(N{TNXydCZ76)3Ij;a_)Q#2cwTt@GL29(HzgZ3*WMWnCTm#d33BUj1%;C5BN>rUVP4C^R=0$DR8GBp4R*WmPx8V}>8cYl0&^Z66bw80l|4^=`k1$L zx7@J)j>@BS-)vfc&($|q1^>C{ykI0$wawqWDF!3xr}@Inb0e=`N?$KDo?Ce%QL?2x6Irzyk)4rSL*OediG%KM1rO3=VtT` zcZnU7ySv}UNVKRkMrDb!=IVi=4ln2VBi*+7ouUUn>6JQWy<4JmeRTCFkpZ+aW_|6> zZ#}xFbp46j`5p?bJ$+64*vBpTxkFROw~~>xdwa{@yy%vBJ4-$JT^_zBnxFgpaWUJn zi4kuPU*5)Rx1A2hvi!{M1>Vs;otFDso-UY?-@jX4|87Nt=42fE^oHV>du0`SN>9&k z-NPTr=rN&3tNe+tdGj__t-)!hS88~uYwzSsJ`Vbv;$hL&A7lHJ4mkJuPp*$nTt zld(C*?OOVy%(m`oxY-N6rR!0M>k%#Kn!7u1W4`x!!C2I)AnWW=)q2YE0jxmIepDQv?G#HGQ4GY zr9XdI^sUHy6Y?IxPVcuhX%_nRIn*N?O_3m##^5iYE-btxd1gNb84g*;DN4usy$X zBXOR! zShT-3(-Im1B;5qe`&>N7GF*&>=P*OM4L)t&3u(soqm1D$ERR6w`g5P=Z-;cV=c2$m zFB!TW=Zti@HwPAFq&;V|6v9f*1`y!Wy&U%7(@m~t_;mADh1Z*OIS%^1j!D3SN}&cK zZc+rnH~MXyjp5$Smo(ts&G$-ut5DLHL^a>8rCG(hHtuH6^=zkDfc5gD_BqmQFs7zdlMSY?O-3X z%3+)v9T$hf7ed{|k?ZgdRicCc_UN|JM%Z`OwRn$2n~rs=5YA1K)+*q?8age&nE z9N@M)Kq~{?nl7fim^c*XD{Dd1>5;G>-5DHAd0KcaIv{u~ac1~=mK{Qz6+Vis97>!W zCJAxyIO3R-b`^|%;Xf2+1A?=-;^f?>snAvU<6>>L z@?VccMoK0ugo3rdMk0JZOU);A!rkx}TwpB2LOxO{{h&H8cmtWH$+;c8(P)x$J9v{( zB09|a$y{)4kolwS*?Ddv6upkNgEB*+Bwr6s^>SA%iN3^orWv)7(MIG4r<OB^+anYVEGs~!zMZGLjVOD2y^iNbIJZMI zex7$6BDi<|glm4G_hS?Q=k^s$UF4mLJj1z77hxPO9T;up=P)!K%@tD}ZIY#KN3TUz z7E87A&&Gf2RS9~O-bYUn#=A?Hy>GO z_d41b3AXVRK^8R!xwZy7QNEEA%<`~>{%8jlY3JdVCaW>myOp0d+l@eeYOt@Tkp}Lj zT9Ls{v^zI$Ka&VXPi3ONX8^P#PKeRj(6udWzav=fJqH@myQo&eFVdl{nU=v}OIk@q?z)<#cf&grI}jnP6@y4aMtF4~_4 z8cpKnXclvtOyaKS8>lU~#3Z&vKV)L5Njw;R7o8VeW~^;@LfrPO(sW2WH_cj2I>}A5 zZ%mq;+rgFIXONE41wMF|!A^8HB*A9ytB966As$-@O_`2Ph@HxDZqprh2P@5Pn9V&r zxZKMPl0A?ev&zf5+**4=U`l{(NxZrJ#ggBTiX-jVx+3{AR~w(<|de~80l9)KzB zb$kUd8F-Sd@P_adr%}F~@z_TGoMDg$au%`gbMl~`l!Mu=6UsRanrS%=z_FZa=oIEGMKvu> z&TA-!X;N%-*%&7?G>C6hhkuXaA#*Nu!Y4yHWX`4j@b6(HWX`3b@Du2nkU5t|!dr>W zxirnmrJ>OAY$}>Oj9*F0nT0x>oW-We&*0yivjvuXPRh%W7bmydcoZtd^_G*|VIne| za5EZ^oK5Tx<2ubr?noR8k3dHxcOs62qfkuFAx;a2s1qa341X8vm7GhQ6~2yk@`$s; z8&Pp`XX04+eCl^0?h@vE^2uE}@bbfd#eZ@);vV5j+V4)>Gn~rdl23ee_$9WX2XR68 zOxo#5+$(%5?H^6tJG_l;C?M_==8GfAy@(6LquHL`#C^lxrp-RYMd4|b7ZUdicgBBm zU*i7Z%P21*KE}!8%Ws~eJ-g6Zok8+?G{<%4MgjDc@*G`?Mt7-oJcS0#x4`MT5DoPl zk4%SCXwQc6xLMh)3L*kedG`f?EW(h#-0_T<1oR*Q zL-IkqK9VLjA%UTPX^8*K?ZM3}vvtpg@4<4o$a|oL+6P_MQPUyZ3DP80C9kiM(k5k6`KJndB+y<0%iA5>D^yZQhGE??jV_1h&8} zHjiaoxqDlwFRv;*vrKOs58T;bvb@N5{BhIdH+kG->jv#Kih|2}8Vff?rTjt5ZG;YFPkh8IymQBhDqP>~k}Ul?YF z;YDEv84xrSH1(oszNBS^L0-F=X=&NjN)7Veu&ZWiWj8Y`E4`^%T3P;o-?i6s&NGOC zH@*M5m-U%F>$}!^*0a`Ld+oi~-sjnC1yz@ziqGKoYFi>P66g$j&0C_Qb;%?Jml14U zN$T+mZXno5=tPAcRcPM|HECMHpA@WBy{@9@aoX>Zygkf(^i+vnreJN`uo(J52*tpj zszYs?svHD=pwLKep_!|xbsy2l0TNGx2Pjy(aH%HD52=d?s+WYo7YXQihXAWojO2=u z26t04)XFR`4GmXlfsL;rBC7k&CPSKUu4t+EYDgzfTd|^pJ|&|1GN0 zIdidgbN|7L$PCDA5+6XP`moaGDNkln=8`VDF7;7AI8ymXbrviUj5dkE{S|YeVg~Om zxD^;FcuG)rx3pZW!*GgJsN?0Xym57hr0xmD-k{heA$D5!+(I(!8O1%KIQ7Nsxn)`D zcv`jisZuty)A5{Q-&E|sTkOr!d>|uRPN}*&?M`<+!~QHJPtRR>!|D!Fox4(Esz_FY z;yNClkjZqV*!D6>9ba`)_1+=Xs(!O#$+O?q@*GG{9H!K|UTVf81yj?^+M}e7*P+DC zb8$Rda0xrx#jR9agXGqwMPyfR*(P;YOM+ue#@BDNn?-b5^svl%I(${9jwi zRiiZORw=C2=9Q>U2 zwNq~%Q0^rqJgEet@2ixD6?@2`UsWACo}Zx$rJ2JO>fozXP}P_}D3;9zFx;UJeiXg^ zQNp3_#ZDv#|4jco4WwZ9EkvgOLSbW=NT%c3FfgVedvQ)DWA4`FpyL%80vys_6x|CQ z$=H`k`f%8MY3Om#KON?<>W494&rC&SIljMIG_F0N{$G~~ zpMYr*iJFj0Ba?FKpz^vDnxmsEnyz#aSDVuB_I;Ee=Rr7j%{}|9`!@8~P8uw^s^{hPA85MR&c}7=fsI+EZRi%>d z64O@S0tcFgUIlXvk;*FL{HsRg-(aJx2^$mJC== z#Bgn$UF5*rdZG^T(aVzoiYDstEu$;f6E%Iy=-hguW@;-H*ro!Bn4_&!pdzKYQBl;t zB&!0~D;yj1q!?E9#;2n5Ha>k9TgQWhI zg{L9BG8=^NTn!+ccB!{ZPdC-s^sWmYjoQLiwuWikT~Va1lK zID;xuAywS!B>}4U{WKQu588AtW!3|{8&c!p?WV0FS-N^Xz?@EsA0=;Wig?WElvUTo zpOi-9HN|MFG6Q_#RE=}xtw|AYZNQWHVd4uZJ}d8!0ZZMVO1`FzCdE(d!s#9ytxF@4 zj6X!1791)!!wKc`Pl$O!uewQnA)5?ek3U^~LO(CB$LGZg@%VRX)3Kgj>L8rf!5yPY zPSr-S_~{N#+f~X&YExs4mUl>sct>cfNS3W$&)RytxYo4{Z*OfC$*R@sfx&4!9`q&%Mgv?P<&qe5kO)7C-PHLf3UQJZQ#P+nb%c(hwLU24L0=7V;@w7pD z^y~4s99Jag_FBJ2knUjp1|j`i6?jcvhtL(K;`P-Qq=ED_n2N`#5aNM@wP}CxxU7fx z^7XxRuFxO884mWa_4sKYIHlYNhJ`-B%R}`^>PZ(B(o56McZxL`=NVROOgNVczZxa7$(3Vm0H9m;SVad%EAj$E zofwasokYju(;}{KBbm0A#uAqO8by9an<|d?S#7!rrST^EQ3ccM<8(Yq=#;EZ zMhrSvC3mAJHa_c#j9fUO%{g`mg4bQ+#yX*UgR6Xe*n{qoFf@?$TNRGdgfm zmSo=RZ(}vjUhxsf=#3Sd64qo>FRM7WO3SOoHPF&^(y}3@qKdWJ&JF+F3TYKtO}@~66}3!N zr;>(DmHM!LSR!XZvH6hS)?A~c9QlL9>X0ujC)II$6|1tP^|F=Qq)%m1LOLZxHrATj zWn&%Do7UQD$`lfrD*k^j2^H4QItp|QySBQDW#7`}<}!hO1=Af&cifaxt+X&NX;n-c zF#Vq^?Hu8bq2lL;-AZ#-gc_u}DyoW-$%JL^vNW7nHH(dt?o?XS?lJZZa)6&1T@s2h1w>GUY2|Ca~J>QGXq%8o}{2zPa* z+5V%&_K;&@<)` zOgwtTq%D(bx8p$Gw1-rL{Yy_YJBiXo(BPchmv9M4d{ws3rNp||A1=~or^ zCcQ+Yy*bT8?d|-cq;tdBkRGi}6*aS#pl7B>w?33TFzn~aLH}N{&CrmRo9<68Xh{1? z+G?NnSGta&T4^UrlPg@;EW}-;i)X^l*x^f?T!&xr>{2#V;^A=FQxvtZ|I|8D)iVgO z#}%<9I0Me9>Kan*QkbvmTavK7rl|JCriJUjdWA*`^>f==>lbJN%08$#;vlchDF4Ei)ZoSHB)2B{9?x^~SE%R7dg=N#;wti(4IktIzvZTJLt)BZ! z^IT0gQOeuAa>2r+UXx8Uyz4vj-<*X>cQ}nvhHi0_T-4Osq6Pj|G-(Em#f`R_525$1Y#o*sOPY3tE@AssHF0 zG;2B(nk8lh>ov_uOR~7NrGEa>*5yky1kubT3~iYEM29-eQ*!vi`Qb3lZ&M9iMtSwekWIZ}L1QRGd%jSs398VLApNb&mn91t&TO8$ zPzA?TH%m2ndrz@$-*Bv|xlnB^bCUY0t;<{H)}P(Hv^81UwqW5r)x2e4YhzooMT508 z&u>_^@XY444ch)Y(*$Xh78bcocUL>BT}u`>FK$|LmYsRWo!PupEx6)6n>?tz&uN2m zbdu)9tg9MUTODB~Pt+_l4Nc2jo3u33`L|s8GftAj87pH?b%2HCR#_4nC+!uSlFVVF z-PA~!BNPru?A_&-*U$N9FJ(1XX2F?fwK=wRsSb70dgeS`-8e5&se{sfmYxV|g|ouSn)PjA-OSKS-nuLGx3sdTlFDxGm0#CEeM*^Ei`i{eSRwW*WTzx*|< zUL9cBz9YEUgo%{2O6an*m;bF9m6%0IJ+l4OO5u1nGZ&PfV<}#7(hE-7g~~g!q-jC3 z&ZW}iQB7N&hpBD3R@`pU)J)ctx=^;LYwCivo$IBB?nVQqi>6Wy-&NwVn%cZQ51 zA%BoI;hF8P;#dv#dA}ys19xEFBjS*Uv+|MQ2N&LM!MtPME%Gm%JZw6dh98F>SXNR& z*Q+ib?x%Qkc2Pn43-Y{{wByA)NgR4$Eb0bmo8aPM8P0@we#XEd5AP#?fVOkQ6iqy@ zhfRL1xI>iTT`>+Bc!>M~+IVq{BOWF%QT%#f$KqM>bj1zO#&0Lq4*YelZ9xHc@xOa@7CN@31ySHP?%X=JpU^^BUh^;=n z+_&?Q_qoQr(8ZA#9w(oA@aER~d|#BvAp@IEUb)*o%Icz2H{QP2NS1v}f3-=O7t1*G zzyy(*EwKJ??|G4VPp6A(<=LxFV}s#!!;`wD&5Ii9<~BDj*G*t)!{X+4F$-JfwaUOQ zq&74*E^R)uU9v`e?ZORu9-OadJ+E{T?{=dKm6_BvwJr`%nsw=W*1EKeP>q$#>K19( zm1b99$tLmGIbHV*r?{>>oaC6~!Z9-4l+S)pAKMRZW9T)vLHf?^ZlQA8B1M^QQY(*5k|%Xf zLLaB5={ra4_3fr>5Wj_)vozY@n6$N0^m`OVXK5c+*q8gv$w~6Eu8EY(Ez!!|AhtZh z?%Uf^I-;_Wv6$O<$$On zv|u@^BHRFdm>y7e6*_`@D;TusU-#tIxAs+-b9#_A=AAoCKIahMI}<)yY>u{?X#x3! zxvrTbJl_KH3Ab($R(C2n($6o2QhBZ$=19NF0`dtbTfAJ1Z*|faWP|kHqHP(stU<#{ z?-5FnzEG$yJt3w)vBg&%@$HR0u9x1=)!UO&eSLh~tuH;qrY{2GE1p=-44qnzere?(X7cnAs{^9FbiU7#uS;iO`V{iS zH_Ja0j;8|sgZK;OUlHSJ%j+W3mY2+FOD*8 z@;A8ne~s}s%Et-=ojex(EHaNgFGR-P>$j1yPh&Iv)yhZSqPBe_W1x0KWDGV~XAqea zwVfULS@|E1%p=L2k$IeX2#))*zb;SY<#FSb$ZO>+d7S4XICR!XCu}-D zM!f3Ak$HT+Dl&0=c28ceRj}>jzegGRJR5p=gntc| zJl8Y0I$qN-)k20x=`OHjhDipl=Ag*+i87oQb&fGIcrCpl%G@OXbCG#`z9lk`_N%PYk}^O zxjyU+OP>1!Y-Np%GQ2K0JhDW>bp$;;VxJo0c||ZMGOq~u!Wfx_^5;e7nnRfQR{4uu z{IbZrQn<*)e>^g;5ikuSFRvPIip(p8J7CqHdm3#0d2@`PqIkGE-s8R>SM0K-l^`UmK%`R~)#Wx(TY7a6f~& z*0E*8I4*4&$>TUBZ0@=mSTcj;vzdG?9OXIRkY6UB^9uQq^4UzDesA*hZ{)9#f0*M5 zkv}G%c0|u~`D~_#{WLwNAR|4u%WrVJAo3mZ^@y8fxS7at@6U7z7)H&;T)s^wmuA~{ zPSH#peusUJdG{ec@(9PH9UtO&s^eLX=QwV5yu|T2j?Z^|nd8qmzS;33j-PV;GsiDG z{;d_JFhM#irpL6^b$Bd~=&$k^v<(RRS z$uPb$e$%lGM@sQKIqvVc&hcc&vm7@&W=?u5E4)^Y`}H{&{}spIbo_*4%*;(swXUVc z104@_e30X#98Yu1t7Ox2x#Lec{)*#oI{vofryK`M?YNJO2~B^EE-=P*jt_D?!SM{o zjgGlqo1RsUxn5iR#~lBwW8OQM3?D}uKjQc)$6V7*Cd_gX_v^1NzFOB%li_-8tPc!J zyr1K7j!$y@s^h;puGU4$boOz)hvP#XPj)=ZF;n@Np35A6((&gU-|l#meK} z|K4#{FQ=^Bu8#XT{(xg9yfOK4j(PWL@uxaI&G8Dy_c;ExkHl?0BZ*xsI8w!OB|Yc&+2B9e>90j~)LE);$3CORM7SJ{peY9xJ9?#(Pb~D-Z4r$7>v4?)W;#*Tb=_n_c|Z9N*()9&+*D zclh#9QE`1*6NvuV|-T^znkNI9FKB*FdXw9<>F^JKFP_l}a0@pm2n*0F4!OLZ9Nc#Pw-VAUIUAsnw2m$>-PI{vof=N$jVaS#14 zWIBgCKFV>UW6I`O<8-)7%ptdU?N*7me5Ny*K~ARD@kqx!x0?K+j>kDZ(ecTS8y(Mc zyu$GZ9e>2}RgORF`16kMa=g*;cOCQGXZ3%<@r#b%a$KQjC6i|kF5?==P-ziKF6Ve)QaLinK7XJmuUvkWE942#@<3}Ao?)YiP&p7_M z<6k*uwkgy9SI118Wbyj=qr^QN7ai9)9^`n4W8O2HPNrBh=DFVZSjSTx&vJaKW8Obo z-UW_Z9k)3?+wr-MFLQjQ<4-u|_aiHd_tnNXI{uPl-Z_}e*B$d-+T!nb{IFw8+)U=j zj(_8r_Yx-a2giSMT&bIf$rK#-bllr96WWgMzB((T`jt4oebIVIHz}#7GLSOo8w-N zcX7PC<2@ZS5w_`M!hT~W%QnV_(|D}oqa06i%q-d_e}dyv9XB{;VoH-=F|!<- zp1(Ne9lOO>I_~axC&x^WZ1Q_M9^qIsT9#y(4%y_7c6_|!8IDhN+~An^^QLE+W9C%0 z_=_E1;h6XKCUc!*-r-yPt&VSZ{0+z7bj-}nmiI@FpL6^R$GQ#b>wo=|(`&QRJ33yy znVvR1pW6FFY@vE+!(HI`lE@@o5n02j|P+!&eizZe-yi8PKPzsIe2e(>$hV8ni2Rs%MPzIh&x!oB_(PGO z5o1q@{^!J(M}A&>P2^vQu>nBlCGlq>zbwYajQCf@*qFhui+N^;v3vYl9)+*ka&$h(OD7#aJ@w<7ayGOy=5 z%EFeiIx^TgOKz`ScbEb?h$p4o}V4)gfP zZQ>InpDX5>9T{veu}_0PDaIxZ-XP{V9sW1*S&?}MxjHg7oEJvMW|QZ1nfk#`gSCh|VwS0eLn^7Y80#D9rAMqHtb6FLvk#&bG6L0iwr%<{Nv zTYr^9o#u_hWkPaDta@Ir0JL_S?SE%IV9&*{jtYO9aD zRNNey_n@aoK2v-~WZsFch|IP5yvS?C{}LHH*vlecBmQV)Y`H%XnOPZmPNxpo5Pdc> zQx|?AGB&igMgF$xc5e&m(n z#gRWKW+5i>ay>pPGIqaOG$F)uJ?2>+nXAPgj{He6&+^1$1N`yG*!o@oe-$~{|3}W~ z9OXG3{T;=Bj*J~LzyA~8Rm^ib++Ex`axZbu$h<@C8+ovJ_s9o`_lV3p)O{i!A?8^g zokxieh=6&jMk(pw3Mr5wXtdfO%tGFRDHpcTK^RATVdSosZ zFN@6e`0U6Z5wD5-QSn8Qu^+xP@+ZYtMgEMKXMA*iR{ZJ6H;Q@2C;k@kO_A>w-x~Rw zVxIAl;W~X+WS0Hl8K3xP#1BX2z3G2M=DN%CJ~G%Kvt%O7HJImpnD3f@8JTM>&-=vp z75^?WcEvpJ6TgS}t;pCdS7{(gJlEQ;k+ECeDKghlp7D{HE$$zAj(D%gjp8AZ=Zg1@ zJWtGOS>#Jjd}O$15FQ;FvL@jmg(JzR@vb zJCoVyc(Y^1b|&+@W5#M0&p6DOag{M+DPzV-#$h=cwIPn*YAt@eV}6sh_){D+9B-jQcsRbv)AXSjWNcS7F>t z7tgrCbS`nc$}#tKleyY4zi(PR>)aUM>G(d!k2!wE@e7V$bDZdUZ8{5%`#2utc$nic zj`^O&^h|d=$MGV^+zU@W4UgwzK1Wo>S#~U4QcKo#C=N-T7_)W+Bu4nqW-x$|8 z=6+-Gqa2TS%(rYNbBberceD6qj`@Af;xBc~?`Rf(gX5v2_C27+xoxd)KYZB!BZmd~ zIh|G?G5N@J*5I^{G6k|ugOWR?hfr-YGQ`yCn+~jCQdhWe>=7Hamh<4sv1>QZ?4jXl zpRq~vXXebWNpfSSOu2Glc2?qZ^@mLyE}K} z?uj1M_ug+rMRGz#esINJ`yROBrUk#ap#LxL+HFYT;4WHPe)z@xKhf~{?q54B|A)8k zJnY8q*EX!}zjFA3;|mu&_{~F}+x+I&y4=!H3$W)p6q3OoJ)lSS$UTyonSIt?oPVH7 zE87>&-(|&7*H=CG&7R+qXra)nwlHki$c+QK4;xW4y0FXI0hO5(zWjQzcZXkG(EXQp zbxF(oM8grkee2qW1;;=5&3;3=PAE(oFydQpPOO-;`N6wiDO8Nsg4lcA{l){j$*ddQ z_`sX1UcKUqIZ4&nnk%lX?Qq3a-9FKww(~QMuU}WG6~R06$e%p%=$l9W>8--y7l{i~ zD_?o&r%ylr!lpNF>#=F9S~C6qw>zGTrM+La+zO+K%(^yQqbDbe5;_vP|s6@){Z_&30gb)9)&7O3r62gWM%#@!RxpQ zFP9%pJ}oA#Q0^$icUp>yT*sU7GL<~v<#X&|hqH*O%sm&YcSd+%N#wWu=yc3!%)k&I^U;*iBp4(~``71Tr(#GV=x9 zc!`xcj5s@#nRPd+LY-NS?=XnrM(3~^-(kE>BUk5@T1D?LisKzp_ogIsB+=g_pqZXS zptn-Ht5!!Mh8a_LY865l4s~DI978;=cGqf+N3Buz4=d1vPL!EIop|KyzF@9O3&9%o zvhLcU5D2fFXwx*v8Gc`GG!=8D0y~9e(tZpQP_FdAW6&+vV+ioT77AWfCn=v`3eo)fHW~wjx(~5w4tHoGZ`bSrdDz z|LmFIb@Yo)RobFcRqYp@>ePM#E-mb7t3s(4lox7hx5!iHd`XBUn7X*2#+F^(!cq!$ zE3JYQmP~4=sJj!Dq8{Znn9$p^ygE}aTRn<(oOW`{N);_ZO=>HR_35uh>>G9EC-yv4 z>oKWm>yktJh9$Ma0!GW-pWj?BG8dGUDN#hN{KPZ$7s;ADDHz!3!26vABpRdgp8-XdHI$5rTMdAuZR$@0R zQ42YhOMYZaaU#B>t$H_34DLkzpQ}v^SKzUeTFwUVs{v2J+Zb>*-YWr5 z`JKFC*pE|&%i|Q&k`C-$xFeM3Pnsvew<(={M=ASkwCowOPsQ6?TUZD!T-a>NoR`K*ad4EI*2)Q<8WR(%RaSMQb{n)+sA<=46l}HtK)Werb!b3#K8UgV zf3$%7;L1vetv97w;%cK3(^fl?Y=uzI6U(*d2n4tF{3m@`i5s=GQ*}~V)k$SlCj~wF zw{=z1Y4(lUSP2FHyV`WV;XS1-tfT|{IE}}9UK?wx;HP^ry>cGj)9pj%pKnu>jy-dio83BS`h!z+}DRS?2t z-hs+1BZMj9W1J@QE>q0iu}ZnMasrw@7&r-Yji=Mxr!gtp1oNdy*rg$5G^BM&7Z%v9 zN(&QI%ng&J+XUt5%{r+v4z9nfqwq1<#uht)wo zOy?f<-vDAvHofKosIZ%UD zp~h)D&JHa&Ft!Vmr)&I^$&{vAO(&bSnWDFxu6K(WR43QR8EBbhSp7t^1I-At-nO51 zIOZx%*xYVD;W&M9X`b>h0o_YKAOkFPb!Od0Wkp`87k1lgBo%rFF<@%NH*h zvaCTfo5zU8S&T?x9n|`{~WXyRS8s+URQ>sgx;Xa1LT+F3ur^|WKRBr9WAB)mF z=jn9J?PjX>*)&mp&==dADS2&n_%N4tR9~Jj`Td<8S8qgv!*`eI#Ae6stavV3_&l@> z(8dT4r;&1aPU$a3hVee5b!50P;LrZA zwz8VUBoWU*#_DhPJL2EdnLPiuOx;DU>pwyp|L`!Jak|hp7JmvNyh6bNq=$q z*EFr5F!{Yc9+K@K2unJKIwt-UDZ4=#cNXh`HOQfFtTyx!hr5k{a~3>OanyTTa#JK@ zc~HX(lnFp|wvUq(HV#Ru*aZUW*Da=8+{YDQX?n76SMKe*>H?r0pj^tca<3Fy9$`|iv$Y0@ z&eASb*cFq!I4FJRg+5MR)Aw1i|O4!L)YaLT7zmn6xV5B_KM}hwqvz zxvQx8c@)Wc-9sDtXm9$W*H_SaxwUqYSUYFs5c&7a$H@(C+w*Ty%d)G`W4?E9pMR5{ zS#}j+PkopcC_4tP-c^L#UO8sl^KbSJ*G9`hyY|;MSR3zznO}2nOO#LgmJc!Q#;ai^ zl=8q;!#BmG(^`@>6RXcL%=98gPyO0@afg;$s;!p}K970~04)CQ82^g=??mQ-e2D6Z zJU3+C2*O;0PImEgBJ;*z&zP6uj);7W{G(t+QZKkV*6kePrSoz5=SSWs|H8=BXKmzL ziD~kf8dzwx#|D8Fro*tUJtZ%k&8<1na>GGko)bjK&bu`h9M z*l|3A_;^XZ#PMg~sPhYO%=;y=^((%gw!C~NZTzfbY!NN~PmViEpT&oHykZ>&x_EwP zFd4pkw)!0E;*WKFvg0{Uo}Zsg54L}{FWB`NU*&is9QPf2XJZ|fQoC{9S{rg27;7j| zVjk2iet_c-I3D77jN`G6IbTfAB*)VnpXhkLe@#i`IsN;`2<~nTh z*E{B%vUslD#@}>&uj5A?a}P54XByH2IIID*R)33L^CGPCFyW<+i*fCk&!H#(@ zw)g`aALRIO#~5yyJhs8c$2*?s_!P(dSZ?yIj`=>r;;{`jKHu?0j+yJ%WUg}j3CGtt z{x`?i30vOV95V;7#oz51+hB`-$T9X-7LRSP@l%ff)A4hTUv!L3mgNoB13KQg3f=H5 zzLVoFj*E_Wb{xi;9aB9#@7O(;v99S%bltFc#@pD3;<`CzoK1XQ@imbdzB2YEzO#5_ zWS*4|iCiOQERM_o@v)Hyi5Vji&pnxII6PQ9Co*Gao^yyFDP9!$5b@H;W5p{Yj}xC8 z`3Ug^k-3L6zCzD2;wvH_FaB6$?&0eqpCrCMa=rM*$cw~ZjJ!n5J1lf^Z|9m1GcMj3 zd5!pi$QO#a<|DIK%$N;ky!>=z?%V$vnQ`&+k-sedb!5iHFGt=e{zK%4#BWCCex8+X z^gk}HjQl-um&o>fh78YVT=U@{i)$i3C*C{q^J2z?$nZS7e`N0eVV~(rEGnO;%<(O-N#SeBo%JF!|Qygmz zqeCX4hoscewG|=wHm|k#y;nQ&(0xGYBM? zRjkP*C+RtlJo=w`O^KNognNVt2}WP$ij7LE$mOE3W2VEI+H09Fep$^Zd&utuuj5S; zk_F@f(keSXq}=%pq;#wU`E0VH8y7>_MSepvc|OLg7)(qDzJtm&WGJ~~uHr~8ZrbHl zfV8BK5I+j8EL@28(Qu*Ark%+j2zM(S2Ok9YDs)0-4BV%Hop=6VxL@H2;tzpql5W>Y zX=NsV)JRpJz*R0k0SqsllKez?O?SRt%uk}uNv8X^sm8Gcaxxelthn(K3OllU(ruLr zx+0UGb-v=#COZjC3PaIxGNtAU+)eVQuGRm_0u{*5X2;j6aZputt^Tn^on3RER-i{` z#zmF+h4(2?SWB+cKsA8=Ko@J`7fiSoB1->1McUj7btyk7yE-2B&0 zREyRWu zQ#c>}4?H6Iv4sQ3``{1te_WUPMaugKdB+!ih|HtNPcHlh{?2LQDTV9xKmT|Sl|H?& zANBd(?-et%ARCV){}d<1DFw#s`KQS{H|dFoc(3q}o$7V8O6x_uTC`7TZ6U-I);U@+vi#!3wK%vOzX!&D8o^D0PfB9pxEJ4t#_zO~| zgp^^$kpzy8xcD{%WNw%d((aM7iQ_Q6EeN|Dl~sl zcD%gFnchQCesT5)>3b&I`zz@9NcInkd^X$rT0)m+k5}4@S+&~~MeCY)wW{4UM>h-& z&5pT-4#C*ae7M?&TwQZvo~l)9B)X3iC(4e?rAi7a=~iVK<-S!B;krnt31?6?4gcE0 zy2SpL-Rz!uL_5~Em*NZgoih9A7#71tu6N+1_^<4KpA0q36@NvRz8Q{mrHWy{yXMf@ zw};ZZpmc{pnd`BdGbruhg(Tz>K=`XLH$5RC8^G7nB*sWo<(zwsGyE}eNqt}uOvBb zm)b^lvLYPT^u$EF$}=ncUAAh6kG;K4v$8pU-kalhhyhuktF+#k>gofl530t1y|Qd` zuLd`>^-ld|wLeq}t9v@xLRof{(mKm}ze`zD7o}FBc4ALbyV@53-GW%&3heHb=wS5N zDcP&9u0=a#_Ub#aCpFUbgj()Y%9ba#7_(^)(B9hxrKL~$l|kQ9jY6KCW936&m$=s< z(65|by^pdfW4F@h0W!;<*t6Z|0lT{o3pD1hai0h18LhvW{-b7q`zBzZC8!UTw7>o1 zgFPgs=h)%Oz2}x63+(0djR_U4Ek%Wj@<~B(o#`jZRJ?-&o`T1@focEL^@5TkPbQg$ zX9Cko0(9~zL0~H0g#k~&yHs0yW&ISRvm?X@PydiIw_1tWWOsd{HCU%Z<7h8nL}f- z@4CpgrAW0Mt#Wj_bCgDN2NylDRl1-<}np(%Fe%V<|n%h#AN$K3? zd176MoRzhr7q%)^*Q~J8rcf$$9Sg_4;zzRbO{zKuyWf&&aIg~AwXCYUWMzG=H^~?R z3$r4b6pJc4$Ua$-6&;C?toljCxxq#_8}ywUY^1Z;3!4rVfYwgsn6lQ+?X*g#x?TO; zw$}Ou4J~sQH7E5LohJ2KS9|WrQAvIC;^w9En_HUBde^P}wu2WAaC(@BgeHHRM0#-2 z;}P0Z=E`jgTeLuTJu8SO^(&f|E^A%fSl_m+VVNqqqNy!}+hRo7Otzintp@hxHpn#wiv^{ijExW28q$(aCSkLwL@_1v<2UQ*xK(5Br&d_k+8 zShV+wY;CD;Ub%2teZ$iEZApDoYwPI?5o(*iXnAw05^eSK7B!H*u&usnrJ9QB$=thf z(dp>{Z8~#VD57=VytZbEFK(pm)Ph!J?ZKkv77NX5NsF7;BAwKf0(3sqE2~sDFIDXh zUpPOMJilS_;)Wn3QrBs2n9KjR<%^c-L7v@7+8+-cxCM>jL<`DVmrJSYr{dH7X)ir* zA>FcNVQXVswAF5(uCAcw(F(X!vtdzv*v*EvrezBkH>ZKLE~<&jO;)JR+Ka#2*1MkO zh|NACIdbCUBh(?6E~H;_0MBY}SgJ#Ob~Bd_4wp`&WqLram&N=t9aUr&x2jpw>LW3C zp$-|HUB`%ao~O&pqJ?du$;XYGR6q5IaWke)n|Q(z_0!Ak84SRsb460Wpk7C%#oM!| z6`9*`7TQCzghs5dPiw0#z5$6Zc0tv|DYeoL%cZ{gx4%a=CSGbXK{x1_a= zx}UpXjJSB_?MmTTOk znE9n*R-gW^Li;4)WwbdI9a0+_8<#ep*)EwQohpwax(&{6Zm)FF!WQXF(^bc$uBmnLVx0&{U3x#O zOUnpVT)B)oN0kb&RyS?2U9Lt_93VY31~*dwX*_cpX#}^Wje6~_=||c;zL6iff;RGd zeG?S6gCGoY_}IspZo+e=Z?k;#Y0Oj7H&%>3;&4x69cj^!Dg1?L38zNxDgmuammuER9E9U+zPDgdaRYxg0Mm_e!zlLCHWpztjNHSsKUE z>s!009;y__esqax=>4oV%Ogz2NguE8%vst7MR9er;KK{RBqi%ZeE7~0y!tR6$>3X1W z?jOM>-TK7gsuwosw52(?j|Jot90DxpL>>oMbLW<0 zACVs>U)?vz(9huNSndhLOQuo&Nsdo}r4zNV>0A(HxXHJ|5@0`I(}2{ou8qw3z&@a7q<2jB` zcg!)cvd(e5*6}*WpL5Lh*Ya}hH2zP=zj6Er#~EF0Oumcbo{o2SyuV}K@mt3FQ;$&RrbG(Bq_U+ws2$9Fou&+%i9pK<(x zX|GVRR9rI11$^Y2# zuN^ZNrOD)UO)~D`xW;jv<1vn>IcA<()APDx>`W}ayW`y)k8*s3zItJRn_Rg8b?_`e)8_o~TM>RM~Olj8x7hdLhPc%oz0JTW~@j+Z#T!|{EN z|LnM9Wm!+7zK7Btla$_ALSTbR)2Nj5~JGUHLNc&5BC<&xYu~F<8WV&`*?th zKgconILmvy3!)5T{;=ALi1n&*je{`(!{FrHB!Tpw-LCW9QaKNio}$#{a} zFeZt5=D7Gpj;WL7y}+^F|3{m{`sG+1Zp-Fy^ypEeusGZvo5Lk^PTgM^3o`23(&lhN zPnii;kFOd&vFG=%<|%Qb-ce{j$~J|=gB{?(+1egR4yYO~^TSt@{z)=mz~7LkUEj%W zuvTf@53mc&$y=jh=}S1$Xzv^y(5I^tBCG$IKdF8htSERGz|kRavZTYF*V_yBlbCE{ zxFyS8@X6qHyj4Q77i3Ik_JY{rM|(k*Rw&sEepNDgCWwyqg1=MNE$s!dA&mBd3&D4^ z7p#}&lD*(Ultz2OGhnk9e3SB1d%@jNm)Z+*lP%c`u2FnvPAjt)47Mw8w-=mFrf4t7 znQHce-PQUjZ;!nobMKqIV4n7f_JZrt9_7d%TlWA=hG;Ak&cL?+q` z@;!pt3m#9r*$Xl?X~|x&K>fF3FSvVsII|b5BiB3I3wBgt+ifp+54xhg;8oP@i{sSM-`QS}M_RKNJPP@*ov0SA zDX`|K*$W1Xl4vg&ER)`ayT>Td@}mc7f4ekU8efUhpvL z`EKk5nb5avFUXYbd9xRMl(NlUa0!i(1}clS&;AoCT$zJdlbd>A`43*$ZOg zTCx{hikR684kX3w1y_(__JXg|CCy%t^-xOof}2ro_JTi0f!PcGl|yd!f-j)J>;?G{ zdpqm}S@Y*Tuoqm48nYMNle)iqdqK`{vlpC*iucD}aH6Uj?FFw@yLPy`WG~2=B(v_W zO0yT7(9T|P0tp97q=xZzrN$}!Gt(+G2V?)tRC!Z5$r>cG+ka?3IvgIfqA`pr*S(2W z%nqlcW*KV6w^O7116W8Xng9-5KsCL^ANf?j9TtCGWHtDYV)0kDMY{03}kt~c-< zZ1Z^OEZaOh9!gRhI*7}e67c9l?Tzac5oW28rJm0@Z9O^rYf}QAHdQLFGOQ#Vvc1C`hu~g4#nDnIRMh-X}}J(D!6)_0Mj)hY8?zS?vX*tmQ4Tt2rGz zs~u*1JIwgDVaA8~Ub|lN&t=S)+I7DFR(!l{#NlgrQF3O*han2LDSXl^wJ|2@rfq;W zhCetg_u$>NAipN31L0a1czOZF%fe# ziX0?A9q6WMzQi z%-fQiA{omg4El&OXZtuw5yqswtop5!PyKl1O&axU)aLcQpl}U8#6)LlTiWYgDuavL z)#&I8zuU-1-;9QN)^lebs>su#%&nu30;WW1T-6kf_Fm1S= z`eE;Cy<{*)8rxmbH@VO0VSj)L#WdvZ*T!))_pszfSwKEAxTmxk6VAwhCR|Pk$XOaT zCw@QH?3o@<_5+(6+Yk25@(2^nsviuDVVtFHX|H#w^sQ7n`nWurzV2e{^TOmj>3a!? z&h+8C=1(4zBIeWBmc3q$`aQNj=1iZ3&G+&D7wz?;xm36I-9Uoj=R2C{=~IAokec=fv%Qnbl1(0c)$H@s#e;2JfBE!vY~AQb<752s z^7-AEUsn3a=X^FhJlJgJ_KPwTt5Xq?YjCM zIL1FAw);`AlT#S?8z=J@n47SiUbmK*FnMv@vyBlo_O@==c3Zr+?H=UfYaJixnESZp zJ;L!s$I~32=yGmbU=s~vyH@gC5Lc(r(D0m4QN_bbQ0jZ6|Y*2pj>`Ez8RB|0dMc%J9FMP}TzOJv4W{Ui4mV|$G} z$6-k1y~X=R9xP^VTx1xx92%LimN?ad#g19L%<2sz#(s|Ypu(a>g&)R{0 zV$8V9c#LDpu=weY=Qv*Exnw`Lpkb*D=(cG;H)6zg+s}>VAxjTJBjwSeTiVYZoE?P) zUACb@2W+FB;Zk!ser{9rsBG2nAr+%A_;+cv%{$q~g=a7hx@_Ng{#v7~dQ=LIb`0-J z=y%RG?zPJF+|~cgWjZ#Q59v&{2LlcyPHPGGk}lc8VPYd&xKo4Iahx(#l-3gFSx%O5 z9gwW-xKa6XLy_xv7`U6TqFWo?$QoU^)nse1Zma_a%xU%|giKkqsehcvszZKg!t)G|9 zr5CEMf;dm3ZCv$Vq$|Ha8k6cev>X8Es`=J3KMJm_{*X@Y{AjpPtslW;8wYo*enGX) z9|ZTR4pt^(;6By!kvSOdSA8gX4}oivZU<$gF3zP_eX9b|HZEM_Z7w}lJ}=qEEkwv{ z<0}6uHRDxi*b&X8SFM7~HZEKv72CvI&Ch! zGo&Hf##J+)YP5~3<~+!s9yH5Ff=gxZCnsc=h6c!s~gdE3mv>rja_m6i*P&J zxN6?B{8pf>YtJ~olCE}k`_yC~_w94(Rj)+mQRF9AUkra|fp|*wC-pzhrC0qO>hrzdDQ0H%wY2_IoEE24KS})4 z}3N>0Elmt2M)1dOug@vTfV|cJ0V)5GbCJQNV2Dg2|)V#%(UA6pCM? z_+vtzE#}gD7Hv~P%CO?Sh?#9%PXg0I%BUi9P?v1uRbbLqkNwUd#eTNM$mjLfAM&LB<1 z%1OZ#X7O^9KbPH%wsBg%x@;R4E^=lYhhe>J<0vLqTuGL#+Q#)zddW8KMZ|0_y#qM7 zW*dj0vTWlR$rX}HJf?1oHQc#0mtHWIY|e81Pm1HnW43XpQysI7J6g3a*~am;nQY^z z=!D{DsKIGjEd8gXGv=9X91o4MjpHm>P+Wq7#UZey_*+HEHjb2)#a&6Ux%3#Ylx*Y9 zq&jDWayAsNr_iM#&keZG8m_ol~8^^?mCEK{l`;^37dLhrQNhOWSTzWCQ zOKC1W&TzAhI{+2YHZIhPIrBn}ZOo-d^Q!}v=hCaB%QaZ;Y?6CM^@+A|bClHKn$Wk% z#&{*O?sJme{Z-W^Gu3S4Y8VxNU-2a~xB;_t6gu2TX*QC{tb0Tf1L@_6CWE?gpwh|i z_Gm!-qoJf%l$f4Skm^e1wq^5Hp5CtgYV&@2yAFPOyN>1A=D4?J(kbSuYxRbomEb~Cptz2=JrrxHq3s%!wBsk#R!e3w)e&g?Ypud%Le;1HxZm{ z$}}BZMTaUDzcw4SiopDLHfoZTQQA9Nk?pV^bE_l&U!0_EyDh!`$>(SLzd0*goT2Ug zo|}!IVRgmZjyc-iC%en^a$B0R?*G>WaIqcuA^IKWg8N4_A7dPWnV5}W8Ee@1f-&h1 zb1)j=?XE^qdb$d~k(0{%RNnuXv(eg?_F#h)F-Sr?Ya>5$VG9 zCrBUfn$f4{m6E=(V)PM*YfHV-f6{PAYU4O>OKyr}ERQgJ*+ZN;+uuowFedE+)o-1A z>Zb?3QvDjmUf+ERzY#i|K+e*5BkJ{GXLF+-*U|U4?7{9*B2&qmGdxcb#-x2o4?F!$ z$fd0k`*I%|klIyHF2{>BeBR`GeUC|BjpEE%+NFx{`reSfL5f2kzkQg#&x$RNFnL+} zKEO#CouzG1*z4;zu-wi(shYmq#N-*K4cAwNU8YA~bEL7|6@8QYx1LF&Dwdqd-LDvq zqq&D9H_8I?k;Czx(l|u)O8Z%0m$s!n*qz!B+LdHjcosY~bkYSYF2$$ppL-|@kY zCpn(#c$VYYju$#U)A0u#U*!0cj>GjdcCve2{9}%var`UCuQ|@>M790eG547oMsBM5 zl(or@xzExz*)jK7+73JBK1tn?0T7bLJ$$Z(x|GU`kN1I&y zx1Ib`j?slYjxnGymvUp?m>Y-t8vo=NCs=(ntSia>z%y824V=9St3|-{>0W zwrxi=a#$+9?X^G0{1ey_{a*cvuI{q#@qAF?FPCKH(68#^y zBYKs#k9I^KXK$k&5#}QQT{|M?KK<|75&eYvL^~qpk2O1@Fh$k7u_HQLnag%Wx1s7? z+7TT~o~_yuW!XWqBbter*%6JR%bFb#^Vyc{h%RQwwrWRo4ccsut#0JmwjI$gDaY)H z=)Pq;qWKh5vLgzU54}4(qB~WEe?&VX>^9AgXqeipG{;srW6h2zOkZYpL=(ueZ9Ag# z5HmZX2MCxQ(F+8&ZATO=Va$%`3G$d7(JGFH*%2+`NZTA+?d*txDU{g}osXE=5pCw+ znjO)v8~w=g*7=RwzDH*q+7Bh+U@gX9T&1Pq-6M*S;xS503$k&DCIxy%98(d zD@yLLBGQtP=?abi+)F@)_rV&Ay=xnyF?vE6q9O)Yq_32Thq;ISk z{lww^f7uYNQ~lPdeD-%+Hbj5qF(^9fj@#0PXjDJx({Ban`&%|dcPsHJQzBWz^BfD4 ztM#Kqe;_)OTct3^#@v$ww$Fy>tI}6vndFsMRa5Mi)%gPzOHp^xpZ=nsntH*BX3(F5CQL-be4xx-s(mo06Gu=&{@ z8=?-|X+!jw^i9w{(O>?S4bidNX+yMbJ8g(wRDs9Ew#2jJ=Ar`n`2UMGM4e-Um<>^X z*Ff}RZ-+(r5N-CN#oG{-r3dud~n6TYn7~2{nYW!|(ihiWQm(}MNV(fWv zwgw?VTZ51?--t5U6tSoc@?oqkA7)=VIkx$c_)(}B6qFse>i;SA%zhe)}%>~ zW;c&m_3DwkB_HTKV8faZbm=eCfb6B`k9uzNxKvk(t#?>2Np3!|s;o$tN;b--?GG-26+5gh(KhSwr zm$P48GGpUKzkBP!-Pabf1CC2J4&7LJ+e4pu`pOs1d*h5An}&6MIXt`g`IKr)dz~ad z5{HSDx(o|z4PI99kz9_!)tbzu*~{}ug*q1fO#d@qS6|4ms*`mFGUKv6`1d5wX%)GS zyGtyW%cpZDRb)Esqe@p~Dp{SYBAfqo@H#e1sG>5zD`}M-pCW%VDIG_H%pj5LwkGJy zGbK!xwR>}eiOC+RN5$MIDn#?yjN>_|FdF?wpfo8Q1|R)-VJ^wC!dPw+pMhkblVI++)4;H_-%cD3DPoGK z&U_rC8I?YWvU8;%Uk4^#>Q9%I6MA!nK|}|xEQDX=0~ZQmE}Xz|My2zVvzLB+Wih#` zqW&@QMyR+7!un4$DsfU5n6WCqe_HESv>%X`L|4m)CaNs_2fuiaCcaPzCL;&J-3mKt z$MOfky$a!1@iB0p!i~fq4EHOXN!~-?nxxxQDP=|_ra&wF2PI4ZL-$JZ6X7-8ucQ`} zsI#V@Sc}lH1ag_A>Hx)^B%!b)no)^)wy=a^Mx?aKP6B0XfsT_YHCNz$N&Zx8p#p`2$#oj22GGC!=|QtJ&?P!QE>T%R zbyAsK>X#(>n}TE)J*DNp5Cqd1mB7jZ2PS{Zu|d@gY0Q5Swi%Vas+ewt|58l;R^ z<{*CuJKnEAz4KpNtQM^)bfJyEu}(awFp<5zd!x9va4qe94-?!B?xGLKll&%h4il?p z-=b!t#H!l8=pR!!0R0a}A3W&I!5rGAm}K0@B{g^wfiDDsmFH^SdpE}l~0 zElmFLT9rP%5T;uBUbRwZ7JfqAp5ml9rI3N2Ca-2x!b7}Q_{UE5VzQH7#H%%#(Q7B{ z%7P^nDa9s*WC;}nidRtfr0h|8QI;$2OJk&g%3_#nDh(8hTy10tMV@ZO{`#-g20u`# zVu~z_ElVg;h7~zpvV^))aU+W?O(shyQbrYn>CTMoc;y*W{4C|n%yKG@EpqSEj7o@& zFK$BHNg-uI@njU7oIP53CKnGvY<3WvQrtkT>$B|6^dhrw$r6h7o@e%^`^plEE;}L9 zdpVgd%AO=|a;EoelwX`ZS%S}GdoMu8N3sR&`Lo&H#}K+aJ6~xpX4P)WInE>KIH0}Yt#Rp|DxE9?Zt_*<8nPRWTjh`RVugcVCi*{P7}_c zY#Qbba=hGh_$IsAJ@c$~tnXOKVF`7Z(u?6D*E?`hJel3^lcAVgIw@A)3`e?B#jxL6 z!czbH_EkDFDxHsleK~|90w=|l1ojPq4#iIr7@3(N=|WP4ca<{48ipB_KH5+)#X7rD;YbRNq_-6VojVf!m9BkfM&Hl)H)#5YW@80{0cKp*kyqw#`Wu z$DSfXgY-?qlp4Yv)9}3(jx#F#QsLro)U3|JNpW`qYqGB^urjIQ+5!e0yCzlPmZ~lq z!(m1xPQ!kj;j)C{fb?r&_s`2xR$A(4%b^*SH~~X<)4?acYmT#USI!CRn#@wvH8(~7 ztLPpp1fjfa^8eU-6F9kwa{d2wPxoX(cQV;%5|WUf$u=RG>_7rRLe>dc2$M;eunm)B zCK;F|nMp|SvV=v1YuHgyqXaH0D2gBo$YR*l3kWEJ3W~A_R}d8SiX!3Zs|x87P$ojT{d=dC1H-_lzz(SNe13ff}|4Et;bzL0Og{{ zRNBgm5PQ%_#mphd850MORIp-wM^}_^m(9-+T)i$zxCpMkbae%eIb8)F$<8e>f|PXJJtw`n|w;j-|F_gDOAjD?Xj)R>M)s@)U(D zPo1eI8GSf?Gr5HMxoW*K?OA@0B&hktGUf_#?{Oy6HhBzi^EYXueXrDC*~MfS_t#i9 z2JbP;oy`MiC{^SgwomkSqGaAk6PPz9)m!I(Z0adpG%r+-UqWvL3OdzoO^MbX=xvPPtW<`_?tN1BZnM}-ItqTO}J zs>Vl$3@UMktVR!7(0_*J@G%A3Q_g19j6ulT*AipW*aFF`oiUW;c)%_TRd~E>Nkqru zxm%HL#;Qb&xPjJ|ig-VC@Ho7{Til{iM7Q60BC4wv+)qa`y0{L%Mu*6FKlWsNWF(^v zb@B?1q={&GQNji%DVDIjC}D$>>F)|1*XdA61F4u``9-2#6360QrlTahPW^snvJ}p zy@KPWGa3CkAwh}1^zNnqgs`MWi4R`GC3?Riw`^=`?`o`W-7;z7{?$#b%@bB_YH9s{ zui`hM>*TKYU6-!T)f3vAHn+B{s-8T4;`oU^FhPXX6QoGfx@k>Q#5QVcnp#`hVoPJ% zvTsdO^Z0e@qKK_dgw$UR8&6)})D>fA4Jd|&s&p+KqN>l8tg%&4J=)aS*$!1A#Grg* z4qdDyUZeAXL`hlCj8qG^$hMg7Ih;MRGJVdHh?1#9X}lMvHuZIu%ThfxSmJ#!L#$Rw z#A@qI(TR;Y14YrYYZh;;>7*%>(vlRm%wjnuJzb7HdX_ti@+}FwYRUo{xs;sbxN};I zbc<7ZD2blhXtSh;lM*XT+W(lI@|r^4CX+PJn$rX9K(R&QyHP)clRj~Z6Bo=AnGhSeu+ zWR2L+(cIkCq;6?j)z!JNWAo}RaW-xgL))s()~5ClYHn}rL|k*b{<@?oD##f`k4m&M zj~ZsRtaUlBZES06bWB3(@TSH!{C90?-KfV#C}u?k^*WcJVe{&BtDKzow4vs^n_27j zB04T_V{3z}Z)4Z$jV*0WaUd>~ilhQWn^hK7Xa17q`PuoY;6kM%tKmp?TE)lcRYH7R`+sHg~qrrl>)l+=Lad z_BILaSRK(BOf;f2ZP}>)cy~?7hN6z)qQhr*-%PWCckph)D>m`_)L@J?5&x$4Vl15D z5)TtjXIFMcj2STh3so84@746byaKsP#)Qxty8QgNEUy)2r`G+aHo7spx}%*_u4QdQ z^QLx5ZFi%3Q~Rc_CY@!Bo|djPU1D(;s=`p$mC~R0tsPxWk^elH!BI#>(i%5;FavxAQQimpWt zvu4$eqQhZ*2S1qGeE3)D;1vOwd)7eTAWT`{@6^G2C3sjZ;-G_B5GHl7GG(O=&s{oj z@PK)B13fGmq5so%9F6dHmluh4*Ao)wrs_Y84+voaKG5 z!2%{~hX&N~@+lu{Ou$8w)fgXDA6l zDIp*i;?6J_`ZsiG+$kPLyg1pZQhctrG9g*HA5VrDOmOP$$A+L{*qnx~PK;A?hxcmC)hMdX9 zJK{KQ_kQ5}oCY&Led~QA=AQ$2u6Sno(sR2&8 zsmGo^j_`9jLK;Cm*Or|R2jagF_j3iUyay!@KIHA?iLTm7}}~ zZw!yHtLwq;JHZt`5xaTpXWz`uA%5~mHZI~kMfxH264d# z9yp_?hPVTCAcu7bZ3ZU)*v74ZhUi&l!B9!FL$Uxf*1?Xz=e1=0RiN$r`+u!6OVF zWAJ_kFEY5^VAc;o{v`(Uk|@x>Wbii)zT05;VYSu{xStsM3kIVL7G$FT6>vu5CE$Su zV6{hgMVQ#nh+uF-Ud%L_(KL`aw+hy zFnE>0?FOT66!^bn@ZAPKZ17JEe!*b3d5iChw+wxPPVOKd!x{k}X7G^)uQ7Oo!Msfm zX+LK0y#Nek5{ttuy)8Lfm+91EL!TT6I z*5GLd&o#K#;0A+R4L;dmv;{-H4;lOugZt_t8F+>oyv5+N48FkNPl0t#;yx=Ju0e0J zy{9Wy`>cBUpACH%*r#=Su6mx{TEGVSK(MEeHh4dS4>bI9 z41EFE*Q?gxR)aSg{I3Ro1?`q2ijGPv2`HiI`9{9%JnGx%c$UuZDvmXPmN z248FNR}4n|CGg*8FwX=6{Yis0#p;Ee{^VFEhjW&7a^Ua5n!%sTedPze_`N*l+#2d} zKjGmXv%VhhG3)F7JRT*Cq91aqgb($Y`;5&FHtyFC7`Fa{{0bH3s}Xd9(9$dr5>?H=&)2GhQQzQy3P4Zg@=+9>c}WAIG| z?=+aY1^y=ue$HUM1aD}p)@^-L`$^i8`CY$zn7-fCsd?w#{kw;C-1MoPr^;h=@4hE9 z)MJws>WI5ut4b~|IXK;usc5I}wEgbPQFL$||BT`jJ()a+)%OJXcle%w^C~#*D^q3q z)BekNTa`4#=M^5TBaY9fIOT~SscR?KN&P402_#NZ;c;BtaLH7Uv(=}vqWW#TL}{b* z$_{YEG}pIaTD2_wNlDb+%+lA4Qq0K79&;3*+83riT-vlZ^N&PNWyMi44oZ4IWhk4f z6~gSze4YFr+-aB8oB>3uw`2j-sBC}z-L9i2e{OGPh7&eb>E4W^&LzhvGgE&hhw;Qj zdo#10a>>Gb2nBc@(xrRqz9Mv*e*!s+oq|0RK|OXfAm z6ToGeZy>0U*qr-QTc4#)?B`?&q6(+7bEWX>n;4Di6r(3J4O;31iRhyEdOKI(Io zgz_Z;H=vo%6H^0>GFOvg0eEX)zHCY_q|DMjJcbG{A&^Q$Wq+1GQ%tTR`jUVPIA0Q= zw-`6sQNSqUzD78jTvM6Tk#{WPs4PPP(#KJ8z9c|Y*=73U@G{F&pH`q>FP?AcOM;yW zWPYi?^a;Qy^9Ch7(MgsB21T!|ZhQ140eusHN#Ho+F9{rD{3QXfEW=!z{>s7n&&GRO ze-#|QBw)txli~W4{u=xPGwA20Z>HiyGIPPVE>m{-%opIf4J(c#GTe)%@A!gnRfcC! z={t7{hc5|`8NMW-WZ_E!fYH}SE^yuV7rCF3q6FAPXEzLbf*&32mr!MD=c%GSjMR#!Zdog_VB>_WLUlQ*#B-{m29l~gg|>44lSKVOcXmjjU(SVxqztQ~NTo(Y-pz~*8g~Y1Z)Q%4 z7eZJiokCUmChk}920g4ez9it*Kj$X7y&R5mBjFmDARB#2KwwaUp5{ve>Rp~f=Ab>* z=zK}Qvw&Q=0{W5w9OYPXDlY=1xsMVvHBm)&ZeOx!i|D?D?n?r0v~x)YL=%@h0;Fkn z9hJ)MBCs|IS6S{Wiq@9|%%LN4takJz!5qDLXuVA(%kc~otT`Woa%G^3A84k zleaGCEK#?)!1~-LNYm~DTXK2WI+EuppRKtw39L_kN`Z58hf<#nE}tE_85FeBrMWuy zHA>Ls0@vk!NScipK>RL0x_bTYIzGmXkP_hI)X0jJ>*&TxH6 zK!*%*A0wQRB(FHvVd8Kp^d$i&pc`)LeCXQVSUC>moCrg6z9a9i|1yThu>vl2GTNs` zB1@Og6BWn$B(eP~iXX=9RHBCS0XOXDE=bHc1@lY=y|gf?NYs_Qo>*3qSSC;XTb`or z_8BMc(q%}^E6A!Qu{|O7Sn6`5vMi}|QtL^Qy!iM$D>5%Mxj~}6%;DTUNpYX)a0DyI z(iKRKPce7GQY@~6iIKhgXG(haP4p}6vzKHR)$W4^z8L?xowIb~o#ocO{RadtFxY>2 z-~vPZ*92+4UKpy0$my`}Q&3oc`)16;q;&rtwsZFC^C;gB)NSbQ+Vn+BtX_4VewAYs zN~0Q&)w?vi@ffYCx2eSQj$SJ9crkCC$!> z*NmX89h2X#f&D$F#Ehc!>0V9QDmuq>{)1XGc3}5#D$ylQDf?8Hs>J=DisH5uu48_2 z_SCE{MdyaDH7!!Dl`3&i`RuL;S^xjjFEr zE>!xu)^&7lj5T=+sneGO|}S>C1$?6zuE%RBvCsRwVNx=n3Oook!gS1XyciKY7)v=QH~mKv+<#?J** z!&oUc)>w8Ls}hL2xY&(VIf;K8@ikqp3(}On3&|ZDn z7^G^56C>Ry-qyG!)XwX2cWqRQp4iaZh}vyeQxn?m(u$rsE$;7=-HFw( ze34YiUA&aT3ySBQcpdE@fYP}$&{|Zw-n^PwAWQ;lx;h%xsYvQUr`PMIjJT9ucN=wO zoxhzd82i)oxM=;x;**<9Pb&rcd9{6`$GCHjbkCvu7WeuUg&N(bcuFqocKY z$^87J@sstX&X`!c-YK!19hBxupUGA9~6aIV(6;imKsE`d2?PqOIqk*5#Sb}^?jOSJs%tK~ zMmI9fvC0q44neDW=V;P^AuJMMqWryeke;}#4$@nBa}*BUAXtzw!C>g8NM4P6X(kVY_iLy=DyLV#!N#>ZaEXOqCYz;}wm zHs5i>V^cEZOZh{-7Ym0pg0ia-MR|aCA#R((R$gj^Zu>+-9*g=Q@AJYTjbOA<@@8>P zdKcn$C~W0bN!Wv;A+L{*Q_{ET-+oh>4dRZ&JLGZP?){0L{(apdReFpU`0f*?AA|d? z_@;$`{7}9p3?_QafOwpNae?nKVOx*is~(h_dT@tB9O375gfxQDB*|mk2N&XgE`pWE z%}_W$bn{%0*H<`+eNyiEu$$P3}%Tl)V+ z{ab&rcPFRythJqh;<3 zm~j(yY8i6@)Bosz;y5S3q@z4w(t(3+>v&Hm2{_ONKTzFJ$}rK(^L-jnxtGWP_(0Jk#JM1}``G zD1(~}?lf3SszP388vF@^uQd4E20v)meryH?jE+UXhZ?-ZU|yXD zo@RqP4c>0>H3r{g@B;?_-e4x~Ab+62BMjzSnZUyX^nhy&#^PL{pKb6(247?FO$P5Y zm@U+ToF@%_&S2hM1fJmrPc-;{yDn+(bg_;@4Bpq^X$E6SDYVJ241V2UCZ@piw{%IZ z{wQXu0{`FACB+g|;JMJ?eT$-cN+TL!r|KVkl}d(tOMutO8qtEKcIV=Nv-iid93~@X+oKG zdKEAt0=?W|)*OM(x-;N$2D|I5&-VaBKgi%&2G29N-r!>lUTyGNgWC<}8W+l=q57^m zbMBh~U(V+>xA*fHdwXDl%=uuQX3>9oOjG~WW7cFPiid|ajGpQ`+*`QZW7a!+dQAJF z-vWPLxWeN~;n5zC6h^NEo+{xf9@ECtJ!Y-MHwo~tmcf0{x?&TiP2WFn+`H{(J!#UE zX%ij)yX#;*IZy@GoFA9{oprFNlkCoZ_ew0!zOmuyWX~J^TJnk%T%w(7xG4Hg^3>$E zMaPz7g0vc?43V?R(t*+7<(27Z^4<4r>%XFM*Nh*%wtVN>OJ<+*$6e9l^ugsT6D<`d z_l>#h6YDCr^nH2OwCqt+DodiZmkh4zF+GugaOcjuE2?{a7p)-4oR%0o{2aCO!UwCe zE3W#>yytf9Zb6oEK7%5dhDp!@i^s#?vMc*})h(rRN3tu+c-of4vh0QF6er=_y2&f#eSvGcv*Y2gQ~odvK+f#o5OQCCWbM zi0LE6B73wv|CPnrD^+J%oc)>Nk|V%94o4985~)5PcGA))swP?Wq{cx>e?elU-$7ob zGBbO#e5W3ks@VqocQ_Y7jmi$y-vc^&^5@LVa@Ou4GqdQ#WbW2qYA!j(>S3wFE{75& z`KBbb@L>g#XCm(KHG{344$fwdBi94LeKLc<2Z0ANiQLwv!@KT8x#~=MWh~9qA==V=ONEE z*-^kK!$&mfqscXuIZsUKV^P5^%TR#yaa0`jFhrGIp+62Uvpj`m(SE&_Dy`JR7y+4O zq&fi@Wya}5NuTH>OTwWd^7qyKDXC33$C z4(efFP#!@&4E}+ch49==#fN101S@?jCP?#{>yUHX`NAVIOR4Q0Hwaf{m{!ww{=0Bc z4?|{952Iv3Jq-CXGNZ(qzW-7E&&=#YOFi%l;h-Ky+Bun5pg#ovqRhXL@53GXUz#}! z`lF13y38Hm$NwyPedYr26R!#f^)S*(Jq!=_0q&1V4LCx%4S=rJ9Hyu}OGR+%VZ`L- zAZlLHG2~vQo(q%Hbcsym{-Pv4P?o!gTE{Wj+*e>*?9%kfWe~6=xwodO0lC{~%%v`7 zV(yQy9g#%CuAm-9KGSl)hi!RsKc$(GTLD{rl2dVJZXKDfbOPq&eoV|!E~X~uROOCN z9;7sjau`OIdKl7{=4KOkhxgo<=>4dY7k=IcR@1I_hCv2;ja->S5q0 zcMoZ%xIk&{8e*m

    GOw7~WZ8@+EZYVP~rga$U4*QM^gUU+29bIgVRCh0sfQ81DTKXx*pmw9Zs$ZhJqeC- z>nY*Z<0F<1`$?87}oOI%EiU;W9K!UU9Cdgt-(_590)M z!%dwJy*$NPIFxfD49!|cK2-l@3=eKE6JmN5n4 zhBb;Wv5eD$5)XUY1z}`GpXZ%^qMlKiSY9FfvMZ|;bGCvNQqVYxR97ib$&<3LE9NB? zV7RQlo+=u56ZeYtS3^5aw8us3t7Euq#OjUB2&BR1)2W(dSDvEi`*4e0S_iyFL>5$u z?U#r-uEkbr@lz4wT5P2}Zz?#_)#7aANIPxBjq+)l;fXqFrzu|)-;`af_%`Y~8f5-w zC3WCc`jdHj{g19uqQop<)vpD6WGQ3Z9aRsh+j{h(A~9jiqbf()aPk}ACK~rwp`c{E zO}FiD*_SOEmQ7p3vZdCrY>%R`SmhWD%k~V0W%sa#Wiv%y49jL?`?deT_GRB)w@q4W z!Jw?}V=7E=FOAq>ES6{D!;KZ$5g|e&%j>;)HMmj5poUB_aL6Fc$yQmdyV!E<+bqnw zF`|*jNQr9kwmWz%-sg36S7#H!^DcvThmJ(lfERd+YH}ia-a2^sQZW%7hZlJ3u28_a zCHmj2Lv~rW$#YMXBktp!+fV=Vbx3>f1bJsUxQr9`Tpgv6>^KikTmdGrF`#;lf;Yq@ zJnnJ2*Qdy^%rX=!F+@ppe!7It(_gq%BFy(;NoQT?f2982|4=o%|CY+&e`)Q`+FRAT zs)o*3gRh{gr*1;gYW#m?Z&l0%4L-^6{F+*&i_y})R%wNG!F1!HMgRKss}!alGB`GUrLI638?@M)PK@gPYt$GQ3?#W zp!`?z;hu3G&ho00oPko3>Df>JL1hsBpfV`c!w*(vP>m$b6lv}3t}%#a4k}Ck0~7}v z7!9$G-3OyX`2SLQuw#|9+TzOmT@(hLwp9bx7yo|xZSK^3@0yA0>A-lD{ZmI#3UNU} zuBfBvMtHo}{ePjb_z$g9s0q4#b(_>Bu^IaRQ@1eIVL+Moe}Ij-IChaK$cA2W2;RpbNz1v-!iW}${7 z3@+CJA1gc@T94Pr=gtXwSUSP~PqU*m!fr0FFrC3O72H%EVGs~@D-ijE4Tk>vePSJy zy@g2+Usea{t-KnALnjCpp|hrvk?dWFJ44}siR#jsHq;OTJVkLf-7ZSdhAe~l{Z!Lg6&z}M~3oow}d>N zvf!F@hVxZpaKv%k?)|`bLoS{;cIUfK1o|83Ad$T!ujn4B0L74m?&yXCn^#6-GkMwPDjN34WavuCGokz=mKnTbu{UJK8 z(Lw(jok+KsEi6!rijcB5TDa}7>$Ac_rLfA7Jls3!M>4JxzTniSo6S*AA0&Fvn;Zew zprY)PJ?5f(n8%uG+yfJMpkHd}dgN5lvjhiy%DmyxR8Y{%1P42vEEteEOFr!c4v%cW z7l>95U6r67;9xg&4RrBrliz0WX<#wa_TZ4$MV@Dg{OiH}^ygiF%|D!@qyf`J96?`m zAXs_fc&-z4J}L~Rji7T5QwOl7{8+zJGG_{N1etTd;=$GEfd3l#EUE&o^Z3j1xvqZ@ zI-r%vp(%|b1{+_{482qfk zuNllc#!!CNA_4Dd@ZJWGGMKksfq#L)%MIoQYT&uh;LjNRMT5U?F!ne?T5PZc{Di^J z8vLrkZyKz}K!vpE`UE)@24iO{&=(nu-K;=wGI)c*ry7i1tHA$tgE9US=%{!Eyvtx- zfd=|;gC`h#kiqi}<^_I8%UjZbFEscw27le)ZyWsY20vl&vj)Fva9)!^$ZNd82N{eW zNZ?s+@G65l3_iu+^9=rk!T)A3MofbII}HAw!A}_coWZ{}_$`Aonumf+zB37Uw88rs zJlo)-494t7Nc)z-8BJ1wKG5Ki1|MSZB7;{N+-&gq27lV%FB*K4!FL(_u)#ky_(g;N zU~p0k$x!}sgNGPA#^C)8o^9|_gO4@%1cNsle5b+xZg8@!Sf1Vnw;0?7*7=4*2b60E z?o7k84Xguqv7vv)(03U6mkj-0gC8~cM_`|q)%$$Q(EI6zDDX@G`|HSbLqAwJT<>ZO zkFyUdS-2w&y%Fr`&4#`a?8|ehpqf{halfwJq@+tevsp4XzUAz8*|J2R&NWfKxr4K0naoS;8|to+CWZHBy)XShV7EnR}UoVXPBk+yFxDQ%CxCWV$k7I2d@bLz>8ob3| z>KynlGI+be)HCqhWbjUd8N-1`Fa2Vhk*zK5O)?t!Zu-j8Cr*ylmGkeeuRMf@4O){- zmB%OxHX~&s^4L`N>SQBYXgl=`!&`{Vip%Q$4k4L$d&!UWdHbYvd2u!#M`_MWx%gD# zHMMDih2S`o0GQ+^DfvUjwX|JPFPGk~*W69$)w#%tvb$Bvl4Sa4&g)StCTaDu)RtE7 z_euYGVtPymUM868v(?E7KPligs&)##>y$}G3cgGeS=L>txd@H2XM+#BR!|DQr34l-^&}q?W9sk| zfIk&Ay=MibPxY9hY#d&~KJ{FJ3k)dV2r3)L$Ue1LB+xg6^8AEQ>Z^dOGxMc8jW< zJ`mg|>r_t<0uRVKvvzJn?15R#Sf<@}*h8{>-II2EVdtYheCmdJ?_uQ3{Ykn8=x({C z-V5H^_dAqgA!XJh2R?{PFCn1Eu05IF_^ixTMC!d~C?nK++4MbbvZH`e_7G$o9oOUm zL>!Aocv+SLq>rQGsP`hO=U4T|;boSmZc?CMFRcDcz4s>yWcMT02|zV~{?aEp$&$ca z+6$d)srT+7FIMk$oUwYZV~o{%fo0hZ$odNNZZV;)i{`U)Xye;z=q|BU!&W)CIp1Fz{nsP~d~PWGelJOuxu?B(ExHwiDzGQQJ~R;k`~S+~Lb<6IZ( zv*?_qpWvi8CVK$oe3Gw+3!B1o2efCi{+xO*F}Y78YF?6rQU@jP zg~|E4;-+$Z72pG9xt|tevbh6Ev)HBSldDidsrQa4Q#QHRh*|1lCg$c4I3jtmvYDDY zk76!!G1GEJzFQJNXKpOQ~~l2dVJE+VkfvCYYyrIb?dC8j3F-Jz^M9;P&la${jT z&ao}c@$IJ6d#O%c?h)9|O!g34{ay@TsrNEurQX{`uID6=Qb_8(2O#{syORi)%19!1eB*3hOVKhm}zJibnRH4`lO-;lBzt_rT_jP zRU_@}&JHQ`%T@4@lwnmAsnqw2(36vZLF3M#WE|!xlAmr$cTvs0iDy)?LHmdg^;sT|) z9}$?EST62t)D!O#CGaJ5>b;ltkbtC$BlTWp|0uTP*z7tgm3x>jT$_ZeEXOUW)O(pj zN92A@>$kYht;toA&k4!ZO20I>9<~#ci~xy-V(Fadx_bS zt0tx+`ESZ+Ywm6`U7zHuy>oNVB4C5dXGiV^GVOF}uFk!RfG!ufF1Lf2jV^Fgj~y>!SBr|y16lDy(vr-u|$@8tw^ z!%dwJy*$OaHk5NB49!MIUaJ3|3=i&0U4F?Zd8I^_-g=4tlZU9FJ*L30&vC$CC1Av{ zU`cHMqe8>bP)$q#;_}k!o$#gt6$F~4*gGMqh0H94D*EWJOo7V8aw*8xRVL~Z2Uf;9 zvz0+-wmiiNU!EE%-trXp$ir_Y>la+s1IT6o;$1}sAezgaH}W{RXy);6slvvps_CLe zY^l|V?O`=y%ZggAYNntOyGPK7%~*}tY>^j@*nePE*!1W@3;JVCbLPNL&T=LocQ^AW ztB*kyR>P#CsNz~_G+&1oG+3QLlv9NoQrhT`A6AjzF-(JHg;Lic#~o)Lf1~)Y9KhG5rr=UlF=Uaz!XYdcv>N@V#v^U; zc9$24Ce$5-b37{z%?lym-E|%x)QcLP81cS_^zacTy_Gjj;m{3&1$h$;hW?}k4U~^O z-Axqa%@jr+G~D5_SNJCmH%|xM{BC?p#S_v9IvbDfCYgX-sP969p}(er)yb!PEL=l< zR|#8rTNU2d-SY^@g}7sdgKX$?)S%a>(UAvxkk>98(g;RhQY1Qx!3B7R2muqe*WlK6D=%9B~}Cdq41fMlYQtvfu*WeWK8h!QCM~#%gfz z;hxYDFyTLl&rK%; zAP=3mFy;lL>H+Uf=kXNX&P`NioY%-eULPHdMJw+*WtbN&xKO?j4!))TU(|Wj>EaxH zgN`D79vtn8dB(8T!|1tNPnk{9VM*|+NNx`uL9Y;;@pR%oXgxdT{r993=PSrlfbi~a zDCP0zbOm$@D>q6<&{LRV@N9z*Gx!LD>kV!&xY^(n4L-@>vkX4h;7bkuoWVC5e22lj zR}bZX(cs@3jP8Bl;Z0M(dl@{!;4udC)+O*SGMG0afxgDzOAKb;%E0p_gTHC;-3C8w zu(O@z`|$-s|DD0sMq);N8}b@xF#D zf9|&(x5GnPPz8Oo$H1C9a6Ppc3G)fzaIImj5-`(Qz&u3`xWZuGR0R4sgIP}n`YeOz z860%UMT)pi1%9qm0Uu+qyPonV$8|r{Ma!}R|8vZ@zK*{UM&AebdyiSx@o>lay;`SCo&KKf1Wui)f@u*sRi0jX%f>ZN^1C~A^V?jY zh4rVF#!i?21o`N=U-q^X?~gF?h>C0~KV?U$GT2hGE_rgYrDX7&g_V=v zYG9EEi#%8sluVmdfiXzO*YB>cjoGjuQM2Lh#(vp;50zv~W==lqvBtj1#{R!-?DNKN zS59g<8TPd!#OblQdkuG(v7 z<&LW4w%;iejhdY*>Cgu|2Tz$k^psumN)r#x&h{I#c+Ak6#C7*hPDvTB_MRVP2P_?N z*5rF0&*wL8o3g!jULwklTv@TLGP~!>imJrm$}x#^bdssGvApcaY)O9ES;TGcoSf8q z?v;nmxN7vJeXA1LJ>gz?XlWvnzcvgto9UfFkL-*}zZ~f3|N9-KA<4?(zS5}wLeQ{U)mAT|w4<7!~(9*|t(b(1Han>tt zOznJl$F#oH+4OU}>g5gI?<3Fds?KKnr=Q(5c*%mHrT6dJIetfda@rBq>6KUB_pBs6 z)k(z4UgtEc<906DQI(opkxu_|SMIUj)K6ORk?54y|5}pmea_sdYUpppK;s=;o@KSB zwmZ0d`{eo~av%R|)le5RD;ZVp7(4p1?^Z2t?ssq1(Ci3Dj+q~voUN>EOF7nQ$*RTs z4xjOZIOdh4BR+LnRWc?_8@g`s&M7-yEIEGF&V7F)mBn@9KfZluzIo@CNvHfFTRv~F z$|Kn|qOZJi-w}&TTW&a+7xOAq{gtaKGMyDYSIkOPp{*&>x*O`R+;Z{g+`Lig@m1Bi z$Mn`Snl|b3p*xrNtx6uXdgrHhs1<9n^*z^>c8-oJD@)>JrD8j_eDJQ$2l`AN9j*BK zpC(_w>#ykp_S~a>(#{Ee^CP!Tu1x&s@SatP-0#YY)tWN7MBN)pXj9EroRpeYz5NF& ztum=sfv1)1ySye_IlQDcP4C5=8l8)G-o2wHtFgHFz^Rh);A)MQp^V2FyWTjslm&im zX=29J*^>Dm&(@YEv%_oeyI+HI>ZKC>;^M00;NSemFDpxBZTt=TZRa(?9rYPWvrU(ifdy;bU}$t`FjxW=vOJ*s?|+GJPXKmWl+)%XEfuaQ6F z^`*nlDosbTN|i>j#bmCmRYU6!rJggcpYgk;zdLIl*B>`%rY|1T>y?suZk}r{?>}v5 z6+>cLiI_EXH2FMON!w(5ztpR~qH6J*dp7r*P~Z2u$LkxX_1$^jj=@W+vkMX*`MS=7 znnZPW=6+l6yK&bvp}9Bis&5>;U#ZTpsJUN{X+sB3`HyE`8ak?c@A@;grQb;VdQ?sL z(;?f=d?T4Hr#1hi?Xde-m)~8{@3D%$zpUuti|T>)wx?`@XQ7oWw`I`^(vHt7Q6l<<+$rMi|&M(=Tzyz+Y^0BMZ;$@Ct;N@B_ z-cotzOC40+)rUZQJw?TkLfd~Tq4a%um?I0n zzZ8@7ecOpE>%r56roHznVbloBOhzT)qR>g72) zT)~ymc}giIUyK}PkI-LG@_ilYUdflOB!ZG}i$+~g@;zEr4obdgTc^E}?KFcSB>D$oU9Fe_6|LHrvq5rCEp7y?z0Unfmkr|YHDOqf8crHpyW&1Iaxmc3`)Md77R+hkI)v64pk@AW!d^7{dgqK`s@-( zNI$_zaZL7G(5;d$>;v520b&@iT)aVJZ@8lN{EP@r$(NYiuMicKd|#v-3zIWc%vA0w z3K9p(a!ZSWY_5YeLCN25`D67YJRLJVtR&$@gdp z)tvYndF3gFq0`8vVy2;8aJpJUJlhmCkW}TVb^3QozTfE1{!u!|v!fI2L^7<3B9;0! z5uB1QgT|dfUdi_lA*>gpQ-!7E`?xAL=t|W9C0|bRoSWqKayZKUh&BsKzT-(UC_zu7 z`&df8;3(Hu|5EZLP@3Zl&+baT9~H%y&?)(zt1ifW1h$~$ zJAy#7>!?(23cay530GN;=S))aWey#YJD!3DC0~r)7LaD5C12QXkF8vvy0Dad3EvXJUdi_< zg<}Q!)05yRcLOEdntWLSDfu$D0G$l4s;&PFrEZ_U~Xl0bAvUiHoqYaj_-da#bJ-VQ0l_`F&RmyolkMm3PL@hg5=WUM* zV-aJ)7sVp>K%B#6*%_))jI-IY0#Bc49}G@w^;0Q9!;X^BXxKQhCWalYf0df(LteE72@O@lIl;_Kx#1&zso7ny{r5X7&!ma=&YL&sa z)Oz_YO8Dh9N;6VNV!LcYMiq|n%P@W)X`}QUB}$y1I6!fuU6syv@QY-6KADcbt^g(Y zVDSxf#eaZed=rkas7`GEaWCbNAX^u~)26tczKPIL2?hBOC-F_@K;H9I>?@YU&7><= z4JyWombjU|XR#1h{bur5OVE}57Rr8!f>rxaf^X4(tlFw3=r3^_Rs9peUs3GaNy~+! z>QM5%gW#tLzDe3UVZN2%JpzeuQ?EZ0L}@;;6XsKutjc|jeiy-?D>!_$dh>30$Lgs1 zGQ9T?c|Ji_?1_5`vKSacn}17{ViBKs>jm9!>^oK@xc1Ep^ie7I-BWX@4&T8r- zzHy0Vsf%wqy>y%mQJyN}_A;1T84B=}k5{@9(L)i&zNDDu=0idi)zz3Ag--?GyT_D6ah+l8t;?Q;7WMRP;xX;+n9gxyej+Epd5Zl2_Z z($5mi;fLy|=BqJAif_>3D5>MC9VQbQxmOR!t7Xv0U#_A3gi6ulI?5BCfF!ne^_6_r zw9mQnw3DAJ&vULk7ZP?&`M+v)8^1N%>-w}4@eZiHtzlvF%->tkV z&kBueilx~^-aD81NR{~ynkRbPK$*i+nZ)+dnit|SzwF99Q+dQ?e%Y0|k+3WC%dX64 z65dxL60f*2{~KXf=2u*q?+IVioLKi`|}Xc^-r|h%<3*QHZHmzC zJFp6U_~qye`X@CVRd)XlYY4w?vj#-;$PI9Fg8$Ls$D&x$DXw@M?I^3kLO)TF_sa?BFP+ZhkL`@Zi@73PE z7sMoABDFq+nC#0$P!*WsEAC^bni4B^zan$IwZs0!_(KMf{($Z|$GbgD8>Mq#x?*GJ zru3*5FR$b6U(LBwCR&CU7`lHoN77_8@rocqU(ku-oUSQ;w}%y;;$(2f>PtO5&eQIB z=0zE&BM~jbo2UbZWmkYE#}RlTWw9`8ME!_ksKq-^M|aWNMEP{gfOo%xb$G+m)ZyYq z_!>pR8y1P|9I2dkUbGDFw>q>V1>PTZ#AO3#i7q?{ z$GN4N<~vxaXRx|I(#Q5((Tnd2~=rsIz32q0W0!KpFRHG%2s=-*yvMz zH2%kQsNeB;v7JVxGC(Gq}93{LVhI~-{Tnt~5 zm(pkwFCJ@)WOS>=2<=x!}H~RDTcNPluG+$?79MQtIK#f&ufReESBSKbFhIj zu+Nwp;Rtzr&@M<0&In%A&|95C$L!WhRZ8b_036_CExS%0Rv|RQP>H;gwX9g$Wt0}% zHDa)(tr0WriGP?&UyIk_;0j8(GlqCPCW9G&jFYv39KI97aQf}mCA1caD8O|dpt zcvQyDBgN=tA-bEyVtj3gH^RBQb(>X3wRkIBpB{_HEhJN6ZK1&MVnRh7g%=o#mxLli zonp;gBY1C2!h6BNWAV5->|QZ=A9W1N z@B%}zVnv2J%TTOXkzu)IC|0b*!vdBEvGvP%KZ8q0TZC z%Tr`nZW-RG3@a={v2~F!*cI|fJea7FWj?Yn#<=sH;+Sjk&@|{?qawpH%TTOQk)h5q z6l+vuSZ*1LH7YW!unff-!7#xU@<=?GsF7tZ)@X=McU^|$G^cqN6etMt`1KAQck8%U z2UFQoI)WQsM*7z@um0UFKS)vbpQaz2L4)ea<0p=vIKf&suseUDNc{dSKNxcl`YH+; zZl^DO6>rS7}M9 z+XbvQbnXA;M3&+rLsXmx>5qdO0EBRKe65adr-o6;VE-G zy`6+kC%LyPUBKkk>GG0NjBsza>shC-fox)^-mYeQ#AWMKq`0~!o#bTCUall5{kt8~ zd@V|l79=RLRPC|1qm+n4BGt~Y3n^5LpwSyd2JNg#)KhD*$ z&i%(c)ea|Jy;3f>q^FQJfn=A*sg5Jvb5B<)@^Gcse{bQ7Pj^icx}v8@zlmJk)4m1R zr7i8+u*{|S>gldPaUtUW$6XgIPwfmBYU}#E#O0dk*;g{+TBdsLC48#OH0<}rpovFE zsC{g|1j{9HtDoe0JLBqC;+33;bV9>O8{jyL zHHd4L=m|aL&pw?Is(oDcxK8}Xb&7dnX>l8bvzxw*TkdbQN7zM>_Ha8Ah7qGvit~sZ zUyHl$qIg6rL~|BHaY2fezA&7vG+f+1C9Y*cz2Y;1WZ{ekm%5gTOP+GO8peAgp5jLY znYvj}Z4ze|w?^E0>~@&$Nh`fuDta|;+qifB|D+1NUp!}GN~swMr@K)W*XupRs>QW5 zXfSqxbZLn%Dp9OH%T{F{mPwP1oorr)Wg9r0i4*Of_z)^!NfHX!8n^$*k>}Xph(;+el5_LA6)YRGK7*1+vYL%sh+5aNNqfCDbcxu} z-q5tAWh3?M@?y2&UPs4?E%0`&ZQa!5dMPe-b8Dm68d|y@R6a835;e?fQClgzwy~|P(b?`1id32~w&Lv)3tMnf*{FNF zt6|rv$0f02lO(M^X(Rh>ze5K#x3tE?bX{lE-q@zrXm4RJN;ej|)^&7l%+=~g9x$od0XQ~g*K}l z)H3szEYHu*PaQvP{N#Lf8!W3ETU)#G)ob(Bhs)z=Ztti*VN=`s>Wz&W(4N3~vQaj1 z)a?ziL7aGtP1nJbqj?J!6$Y7dYU)%uHMTojH1ORBI=QK_Q>Q@V8d6-#*X&? ziCpm-7=B%x@tfB*b*dR@E`=P4Gm4>)@i8|kX!QFbpf;9qo@P&N+7iZjp-JP++t`0K zZdu0Ynig5XYEfr)G&eI^nzf~8YfG2VqQhq|Y|zI7%WIb{STVPu?tRZM?`BL&vj^6s zR5h)^3&SBk`Ltk<8rC($mWbj3;|4D$;K>;4@mt6?xM3BxSZ!P7rWfkb(B-<}?`TZv z9c?Hv1aykGt>4tygtAfHO-`R zY*M7Z$r^TTI&C^uYg*oaYNIBr^3UJcmelf1=##PS8T zb3L=mqK&cSPR+u(7|owO`#^mI)2XZ2#*U8G>Lv5@lg3ZhZRD7EvT(ZddEM6QRz9lV z*wo(D*s!3zxg%P>Y;MD$vz8scNLQJLMGNZY)*iZO*})U{ICR#6gD2_zJnrn+b3W;V z3ud77+SNT}z$ac04P1T$%f&&#W*X>Q;Bgpc-R0BZ^Lk;1?x$aqwgm_@VK|+ z3L|HR{E<44)2IUneU1D;=ZzT-IxjW$*8%_CI&kC#?xUkp$74E%dCc?ZPzK)2;NS=2 z!~d3!eLNoG8-_TrUX(f>tYZ@eofkP1Je}v+IOyPz7tgl&cmVll2*U;sFJDG^`Zb1r zt#FXZ^KTsdU~JAH=XK$vr?ZcQ^qw4@7eOIk^n-O{?dW}BmO~D>T7IRD4+#gED~0JB z=)9c4!4D2~ztYgb&5Ezo(Zjt~i22Ke_w;n$k1&Sd;r&L9$Ec(6Bnvw4PqgNA_)=ks zb@}qTVqZ`HwlGaWd3bj*#?xOC#z6;%zU!d@7Wm7A7bu>*cr$~8AFMapj=oN~pT{2- z4rSnlNNC%C6(&2<^7hW;#w89@*b4Z$&kLWJTAjQ-l@VN4I)NqV&oNba3Ss@5dtP| zqAqOxm|VRJaUWCI=KErk&UH<0)I%Chg?x7ihctrGEKRm~fOjG8GYVUI6SwGN0@08s z9nXTin}kCe!D!XrkaxXL0}rlF@@nKGPt8-1_kggKcc$cxrX#!yad#_h%eP(f)~H>O zN4F41zx_Z5X;_QkuGPRfgA0#$#Bu!0`+;xY1LL{ZvpF94ex<`Cj~0ne z0TVu3e5M+OxZf+z)`P_v<)$73eH`IZ3A6IHN#5lqVTelz7_v5?iTRMXw~%9XoiOQ@Fg2 zq)LF#LD>jv_!Q3Lgl5Sp3K!R$CDBZU*XS6j1AgmD)YD5u*rtQ;x!)dddzAWz(!^3q zy3Jt3b0!vDi93^Qm|iKm5;u}3L)^AXF0Nb_;V=FS-&pqHK6?r@TQQa`aXE zXxeZtgj*FV#;2pMZt>~p!#<41I5=mw@cFxiFWW85JQE!0uL=SAgs25E6NYd?T zO85IYe=}Nm5~DOcMUls&LwVd}%hRvhox6X^s^sp`OnmkFcL{{X|YfNo*`^h<4lOK=j&(f?ABg2jX!^HPEZy&Qd&fKhIMj*yl) zETn}sq|JkU+7V!%whHV|qj3gL1T%@rP1O;2n0o`}ybgG#!E+3*0W*2YEz*(TMp165 zjzF&i=k+I7uOpGypWHDz5)}?c$Ac?lyat@tpWHeffzG*;7!FmMY&t^PjbKmTV(=*j zZ#9@UAD~H?wxo^&XkfY7I>0pDVIISKgvay`<%fsv>b@l;_xr-Fz3(K@i_ zS?lpM@m%D2sN?M(qd)h8$Ee4pbRY+{xE$Eaai6{m({Ix}eWvgd&)+P6g{RLE9qSdy zA+L{mjLc^|epx;r_XZwLMKFDx_jo_~qYdU72oH5<-3+ELZt<8lzr*9Z<$u@X$K*fa zF+4vqnDr8Jpg#*%9cw(!`19-6o`+{G9Pqy-pUajjkNiD7=2;82Km$GRF&eZ}z>>d6 zNx>O^&d%{XJa;+VW5!jh$DQ&!JmwjRvyvg7XDTOqI?qu)<#Ar}Kj$&eX|D8`@%UA+ z%CJ;C;7~_C7^KX|ztdx}L=PDJu))uIoEHxU4no?$8oCx5j!xUMXA3+$zZnKr8R|p_ zXAmNXX$^RIt~1tSo&z0Z@JxdjfhC8z0UYG;aUybfCe#cT&oSZwXDY}^+mt}p!SkWb zVDTI;Iyh4ahpxY#zQ*Gq|8D3yxX*dO^Q;pOIHdi7=iwO=HUi-1*%F(tfjLj#0xREE zr3Gh(3&{0T96VR*Kr_*=UEiSVZc1QIsq*Hjp7G~ ze9!belx@4m*U4v&AT7_R?(>*^!N21%&y)V*ahY&$9q{w~slUhTq@O;Yfphy~coXraHBj*=} z=Ox3VSN@J4`9lrn8+hbE$Mw&~*VaBBt9j$Kjp(?6Iuhc?4bj1M2$$DE+7a?O5}u#y zW#AtNkNETQCxXQ@RX#`Hp9c0asSo`4Gr{7YBcCJiGyewuMevA!jeO=T`0M0z1b)u{ zz<&%p;@>8}(O}L`=oiZG@c7g6PXSBjR{0!3=GkEJnp z{AYxb&;7*n2EXj_&7!mZf#+MofA)B%FxNQb^K6qN$S(tX`B`{`xj*S^@Ia4uiJk{b z&ItJ&K~5Fe%VDjB9PVo-89dEnzGs{XmYg~AIf9%Tu$Qw49%1f>FccMVy~krk*Dp%& za9mE}B0fID_0fqP!7B~^ zsKJ*Se1*Z7!wPxbZ16n>f8XGr8vHARc@GujMC#9gdl`%cn?T1JLco&^#*9;-A8T-n z!P>&Iz;lMdUpDw=gYPkz^+S-4>4$*19|(A~!59GwbT*0%nB9#7KGI-}$pt#^umZlq zV7^QW^m`2czQI2=_*VwMZZOyVAjer#@nfEAeV{Kgc%{MIV+0=dmJN8T!K?=Y9W#9a zf6?HZ48F_YhYkLz!K@X69IpETCpE7HTy8Li*L%`Dwo^SAR2LI9Eq$a75w%p($ z29Gg#w!upcKGxt948GXl&l&t>gKshTK7$`K_~!<{Z15WfV^A;DrN6;>gR2cb(BSz7 zvwLKa(`azJ!T)0L-3EW(;L@_9oPGwk8N9{dvkkt;;Oz$AX7B?B|G?m%8~kg7|I=Wn z-|o+gK6)S>>YFooh{3}R9&hkeu;vcjG~sZ~nr(O%gLx4mcZ|U;25&L=Y_Koe1z<1# z5@F=$CFiq-=Zj!3|2jkerlH?%=y!v?%=?9r$yyP66CvN{4gR&^f7SD^5&xeJ4~9TP z8TJ7C^5+b$FnFB7vkhJh_GLRln6hnCUdI@oX0WgCiH5$(&_8VGXB+x?hJLA`UvB7E z8TuCu{RTt-rlIdN^!p6``-c8QL;snfKWpf(82axF{Y^tp=)F~F+YH#ZLmxxm+t7y@ z`WQnWZ|K-i2y*5bywLD0H}sVr8~muj zzc%<)Fbhe!U0~l1Wm;$k+}Ge7*vp@6FjfNs{RD&m1*~?*onh#g82aUg{&j=zH9U_P z`tt_=+2H#5?I1(n$I!cEnPTWRQP486tBHyZlMhJLo8p9l8k+-Z2e zXXpl2|u-3J)@AVVKv=wl3hs-aH@`|@uz zJf|7@nZlHxd-?MX&*flW{?8ivHHQ8bL%+q)?=bZ582Uqo{-mKlZRjr=`YT{x{;Gb( zHkk_6eFAQ}q0cq=2(W)Ixx&y_f&DwmwT9jW_U|jV82Z`ZA#q;k8T!8&e2c+9Gx$#i z_tIDn;~8nRIgV-stV>w|)AWH}Vem+U#~D1);8_OGGkA%?wFWmD++^@ZgSQxby1{1| z{BeUnW$+GzuQvFr2H$9Kct$6Zd*2k=;roW?2L}JdVBR+c{?`oty}^Gmc$dNG&V;mk z7~Id`oWZYT#kb7w}yM-)Hbc20v;r@7qG!rwo41VBUoV zo>vX#SyQ0@#o%2AW7IY9;0L_7!TT7@`?A2p`?7$s1{?59gXbH((BNeTA8GJfgHJTL z)8LZ~KF#1W4Zg(SPZ<0;gRe69MuWd;@SO(p4ldO3dj>yj@Dm2}-YxJyYw)iO#u9Ge zdDCFttp_^q@B;2*@Bo7c8$8Tlp3#N0V-4ncU7%w_C*b)8^Xx9rml@1+yg+X-m}h!{ z-fA%K{{nrB!KWDf5rfY&7+b(0?dJ^sg27)h7-PYK{| zFwa^;+WQQC(BMZ5{<*==8jS8pki$FKfZ1Io;J+BmbJ{>JHJI-d0==)n0}UQxFwb%W z{{({%F!&&YG4>ny=NY`%VBQf2o_d3iF?fx^>kQ_-U`X3#@P`dP&0tJ!2mXr<<{fmP zf7am78+@(7w-|i8!Pqwna=v5mBL@G_;HM0J#^4tXe%atR4dw-2$P2UJ0Xv;Y&D}Vx zga@a@G66w4c=_<|Ht0jz*$w*`~Ul#IcMe!=Kuo? zM^Mz^fQkw-z{rE5G71QSihzcXBaea(5Aq;b+ypbzu9c=&txHKaE9}K}=yw_geGv66du=Jnz=6apI_j|4NUEj6#+7D;#y}o;`cR9Y$ z@x_iAR@(CYh~v$UuXoJ*d6WM)#|%ep;k>Ii-s<=v#|&3(GCy_voa0|RW&~@KuXEhP zac{@{9q;Lw5vfg2v*R(24|RN`L4XB{(Aw#nb=_+H1~a?Ie_CjX@4pE>@8;};zN&T(FS2d1aqaf9PV$9p*5+cCpw zo1TLmk9R!5F~e<}JTqDtpYC|BV}|248OB^Uez)Tb9Wz|F$z1FBI>(=M%n05l{}snu z9N**kKOBGCF=KO^o*y}W#_@BG8N1u$YhoV+_n&T#dpKrnZ<8PF_&~?Q9W(Z~$xm`T z-SG^^a~#vBV`&-V+jynp^BprqhsiJoxbc;aKkE47ju|7|!JJN|-W#yK~c`yJBqs(sw~o`R#Ok}UMzP5dXRIb$m32u~S=|v;MvuvRJ=mSvyEtq{d&f2aTjK$d(YJ48 zz2;7uBcuC}$a*!FOo~iC*q5S*S8y{UV;(#wa+7$z5mkFOLzCJQGP&_XaK2v;4 zI_3YaKgeAu`wf&5@ao4;v(8HfrG+ z8NOJ{mdKZi?~RO&I?u?+d{hgz$}snXZIM4A{(fYx^`|0#Q~dMD-xc$`Oxnk^{4O%r z^vjWdEarI`nV)Fk85!=TbD?i!?9K*6?klcD##WvFROGRH#}*bIBE}XLZWbRBnQL)E zwwczxva z#TQ2Y2k|A5FA{$+@+IP{B4ZnWU1aR)KOOlx@r{wOng3#B?B=kkrEJ*kV^a%r9p4-I zKg3%ja~(4Y4Kk05w?*c?*Y_j;Q2bP6Z1R5|nd|uZ$XvVFlA(upU_3j+iH4X;7Wuv6)se9Wd}m~?-3^gHEan*;Jy(e@ zi_Cj3rllqPW8!Ng^WF;^Il{T7KO6Z*@hy?RAigc~SHxeB{8cf}X7+&G0*1kqvB^HKQ4YDGT$h?6!~fKE0MX@nR=PDzY%wf%zLti$bS%* zBiHI284$T3u0-a0har*qp6j5j-o0mLk)ij@={S*u(dW z%oxslMdmw_O5_$XE<A%78t&X=i-s*UpZAT@%@e;ar~s?XC1%fIH$6k{szZ9XIc0V$1RR0IOf^PUK;>!)@k2BYNjfgYK>a;tyFVYkBl@$P z#{QNx-ZFBlgl%D zV>VZ}n7BedJe3vdPLMCxO~uUC9VY1M2<;u0({H|w9X|t z8n!jl?#A;X86SVLu$0S{w8QznbqbOyo^-lDAjy9Dp>q{fWKO*NL7*n1KPSl#5BpMl zl;FUH;zv;sxKu1w!y9_EtxNLFn3*(c2D%>F7PvpJ6@;QIqXtP2&bRQ{eUbM>`O#^) z4~NI3In}B}`LS@J_*Jd*-}8E=o35tfJkG z{_#bgm-F}XVMr7ioLsA6%gIjN$^qzr!1k z*~QPnkN!&GbBcVMpa0%d;?ppDPx9MHyCCVq2JyzQVy7A>E4N0%Rh#TbUmgO648p{(n zn`VTV<}yzw`4h5hl}$^T0_10fn6c&C5j!z^fYOXF^Wr8yC(ETcq0F_LKRJj^EMp#! zKPALWDf2EWe`>Z_X{MJsU-M@Ku^Hw2DO+3Eo!Mm`FY*^=pVJ*~&TgE(`S)fyWv66z z`xY85&Q6eTdSc`8Q!e+|E6S1dCl9XV^|JX>~4XR@&KgzWhh~;OiL}_Kf{qOC>!>> zXAYhHv1RFzACciXxBMapYGmM~Op7i*DtKzk?bLHiW;EF)1vcxHAeM0Vhw}5Ybbgj! zqFxtfCn`QEV?L8#6b@9b{1gh#3Q~pg^@`3f&TM;c8}iv)9*KgLAZd0+_;*Woe?GrH`+)pqrb*9V5I8BHKnXWwpHRfQq`qee#xF(fZ=r0!6&?@ z{;Kr^$2DQ6=FuT|wAKYq4|-Zd>TI&tUMf$f$ejj92ANHJ^EjXxXhUdqVpiq`ZBWxC zJ2)v84=>iJ52Pld^ySKK7SDY2Xo^fV8RE>OVgAm#I5TOHm_jBqwGZaQ^#e7(>2Tcy zyTvI@gKV)wmhX8=J(aKiNUD>d2B97jDlmCzI&o@GgwWj(#PYo&L111*_n22L$ z?ou7NY_e4AH+QBZ4OOmIVf*R6QR^C>Wd^s3=utn>Nvhi@kn zhMynq=OhYybvc>t zpM)FZJq}Q>@v${}nN5~Z9kttrfDa?)SLax0Yddc)^BBYd*WFm`)tLgS1Ja{m)j|!U z7G_8ABlLHj*`X~?h7d=^?=r-9b!c@B0v<-_*5KR}LF2oJc^+(jh%g9vbvgnY)Lyem ztUPPsviTYnJUOMEf`^fejy@4$017Y#O_EAtSVFPbh-M`e(j@bQtrF@y#9|uRTPX2%z=DrB}!ps$22HIzD)9XkxCd}2)@#!Q2)mbCb zDIfgA7#+J)RmFaF@>GZJ*O|~U3r1&=PLpTo(E1rXb~HtVj%64o-saaxXXFSoO{8-M zbe`Cv^APswu=#5jsNPj2HokqAk>caL5R}DTAKML=Z!>tjp*Nmz444kVF8?+i%Y}27 z=}~~wo>@~kzBY-+(z)wwXWGJa5;|b2z;oK#=Q3pes)Y-6C~amIPJ%dT!im#$GKP4a zY3T)=o*PUH@mEiXkxo9Ko0-n;Why}Dd05=UHf@Z_AExj~OBtuph*P3ijfcAeL;Z*Q zytHW#t5eA6foYAVU`ek7KLLnNxpe9W=8$-E2lKbTKeoDESDg*G&7UIoWczbe3q?H; ztIl7l*+jI}5ewVJMqw=KC7Q{lnc=7xuGG9C>5$ZE*lNx1p>eXAPv@X{t2z&W{klih z-q9%9|Njk{oiwQ?s4_JygX6uFRVM+)*sK^6{Wn}F!7Ow;5yChA3%Z@jkb zFZ)9r<(sF)>pN5a3&Qy&kh8ec#a>^t6g8{T(Wgd2Ro^m~Mwt9Sx;|h^T--*-$YB@O z1Vm>^*30knJyQlpgB3=;l;8FPn;T0bOfHkY9py_OiPv|L(}x|D>HCBjea%{M{goNh zK$|0u<;J)*x!rmtNyUU>9CFz2`16SGKF4;E!+W0=6v$86x8u#s(hA`Z%(uW-S`f9OyQS$0JDoj4BfG2?HEHAcM3)J@7 zauUYB(sN3%gF|0~7S0_z=Y`4bI!^}y(V0H;+t!EwC1XvS9=41P?VaYi^j^j5NzJ+K z$Aad}>2Nh+&%EE4mi(y24p$RquJC@2V27*G5#ZRGquw|!I7)6~9asPIeUq@GVHV^w zB#y4p?N%Q>N7^xg8zsY%5#z|u`YZ;B&Hj-4ZYEYAWwh}P*h6E^A4|*ex3qf_9;#{MKjrw>j$d(%otfoZc09;& ztK;JwpW=9tm~ZP$<`~ECaJ;}V zFUw6Hdq3lUbbPJjPdVldy2;<^c&p>b9RJiY_BWO`(S5}j+Zy8mjt_8*-Hgc`@Azkq zf8&@2p~-i5j2)MSW6xpS>i9UveCuQ~7drls<4umSi8A>wJHFd7-yfOG6OMoG`1g*n zUo!b#j`wnWpyRQQCppH}$n>;1Zg>1e$6Fl#-f@i@B&O#K$BSWId$@M7-RJq{#pJbH zNrsgie?=zGe~rn%llw{3!#xfA9NZ<2@iW$vIpgpj6y^PY)?nnVY)j^~%^jv^I_)6edH?tjwO{lHU+o_s5N5BiQfgnm@#MeHee8s1TK_Pj{@g!h zpR0MG<~w?N$!lQd(tUf4EoCdylVLq-ONq97Y#q{lO7F3a#ZluLzk7Ewtmk1l)xZ{s zXEpx#9)tGJRcew&AHL__U;kM)y@hk{pS$gZr(0hd(fb=s>WNR1!?FX(@cALx?A#h% z8wJHQ?4XaHx-qvzkW=}S9!(4xmRy$oK+OkpAIfh~&iwD=+O@EoIUU!eM?+4k6XHkd zzg(BNTrLytyBig_PY95qf845nzfr;JyZVB%QU5;Hp6cJnn7^ZcpT7e2@7E$(sM~_d z&B)cYf*%srG^`S;f1gnoa_?2XHA4x>Kc}SXG?*f$fBzP3>-fUGX3Bd(KIpHRN@!9T zs?`=P^{hhw{>joz|NheoD9%UeByvoO=fKBYAyohV@5q1JeR%dn-SIpfseeCo#q=$z zKPW}+M zp?ExeDBM`gA~PQDSLFXGe;7QVco^Y_!%a!Up&6-D|9*=KP~_h~KLt#i%=xMChF(~I z=BH6+_3tmyCVw0roz8_<6gE*pVMo-zzg`*9zki{^(keRzOp3$NacZkDSLBY6Km8J| z3q=Z$KZ6~oe;-u^y8Kz9&YroC%hS92kEB}t`}fFG+?P~mgGrHlM*f_jSsFMgx?^Ia z{(U+d)BgP+nfC7o!L)xLEEMOV>!wlSQt@(W%-;-K|NeCfX()bAA^BU7?^m3P{B7*` zfFiao`LDb~HQH39jgkNA#p1!mRqXB8J|`YhBsTwbEG(^mADz~}Psyx*AN}KtP3XV( zTauqp&$F z1hE8t*IPFeNuW3;6H{fXMBf1mmO)W1JT`qaN4 zdQv}_{hb2Uzdss{AIhGfxX`~pL&3U7UZrC9%yAlqie|@LMF%ehm&`^*^&?f!-052P zd8a}@*IAq(J1&L$v`uE8uSH?kI4S=No>9S5 zTfPTROXd(stAC%(dL@V@4E_6j&|JpiTmAb}6rYrD#*a#sKT zyHxLkQ(KZH;owdwb0VvM|0JcKQRe#!_3w{SPIJn864Rc2S}}{u^NCp+JS)n-Qjq%h ziCI_PgP7&n4=A4v<$K9=MfPLzTvGlH3eFArY%ag7tku6yn(NC?qF`0<+*tkvF{^{; z*79az)&$QT<$uF-Uhv#gW(*Pa?^C_%-{;tqWvCGK@8c)e;8*`X{+rAn`}e;ie;LzC z_3y(;xi@9sko}=N>fh(y0tOxG-=|VJ&!a!|?{gUr;0jm&J_lsL!Km1nC9gEsL6Qh5 z)W6RK7*01Ge8PL?xYqWZL@+y|fN3H45UmTG9(+9=QfHIgQ7UTfC_?x8x{6kNP39Oe zj&@6C6JIdzy+V^TW~Or#aeMQ6KQkRUPU0qYh|VCRIe1njnG=ZFD9^x2TJ=>ErjnVN zW%#T?SChpziEo#e7EfkVy#!K~XAyCm0tfPrlJ;&TGppt|8QFylKA-9sSwk82nMavx z!cl5g;`CaBw5#l!{t+|#^yniKggtt^ZIzJh=8P0n!Tt6PmJI!?b`rsoVfScR5j=ZD zlZ@aQ(2-oH6&4W~Ozd?~CR!!rF_EB}C-l4K$Pl-8zG`!k)iG|8nL;$dz&r5L3o|-E zBc!DAewmwQ`(1IQo+}1b6&ANsIJm2!!#-8vko)+Mtq#0yeH{K|CYuET+t@78lG6;q zGp`d=T`D_^%{(nK%w=P;v#PQP3=9G@_t)m26i?9RloYkDI;RxjOmdo~sY%vnt|Rdo zX}BffQaCpR&1CbgfV0@VM@#2o^T42MD1?WNR!EsUQ<2%^-!sZM^GDgf$naRKQY4u- zv{RJ+z~!&o4&$wC;PHl5kGC3G^%q!-gzA+YiSBl~?S%tg^B@-M^*W?Ad40N*sma8( z?80m6>se>(^IHD{YdtPyYR-$4tyRL^Ltu@lUat$Jqb{V&YF$^~TkA|cd_mBZ3F`|& zNXlUy?N)quaoWpk{n;G`9*;KPVHPvNzJ@wT zWIiNY84Mz%IN0f!VMG@rkkqE7YN-^AKRTPCqy{eNS-u7Xn)6mOvty|D&Vs?xgguar zOt9D4k&#N(L@9kHKmM3KgeJR(w6Q95(}2-q|nsZW*pXG^R%5cRkgZOa~#Ys zs&+umY%CN6yC`W7)sh-NwWXzXwk~GJQMIVz`j3_(oh;Zo3{JXQjyM~dXfP9PNm2uu zs-0OhaZ{+wVtg;0*;S>cVd;*ATH;DcEwxh9qE6;FiCA$=bLLeQ;JOqwlp2g<%Xn0`-VRxwm90` zFt45~T4?Ry2#5F9LiiLdIKttcS_prK7V;sSCx~8J2w$QFhhe-uEM(=k)(-M-6^k7X zeQFN0VBx$qXSMxJEqIz#FI1==9D{4o+72oKp-rJ}SNoluI*$h{e0MFRM~-x)_xdKt zZwEnG)i>NR;X|ZvleXxq(PH{0h|xzF?(TF`T@#0!tc8QTGr1X(u{6Tu9xa?m=ExT} zO^Y%9dtCW=u(tBe6MKDpQZc5U6sfbg)8+O0u%qD{eD)V{)3;1)X@tovbprg}1sHDZ zB6o}`|HmYV&g6JD_W2IoCkcH8gQ9f=GR=&@RNz<$a_j%nBHt6}(9C0jn#I4DV zknsaI2y-U)O$Bfq&CQbBSo3I$9PWEsjPd`Y+EL@lIk*LJGo8If0OTdSp$Jyq=E z<{Gg+ZjQb&`)2y}7f~%6<+MI`%4zca?-`GFe3)bYdrU@eGpl^E5k_(zQplWj&F2)yW@KtKjipv$4@)%uN#Jy znK9Xn=|wbdbxcpag`es;jL#73YK;rO(D8>HZ*u%u$6t1Qx8sK#KjHZ2jv3F$%7#IP zG5tBlO^z9>$il}vp5^!#j(_hsr<;_e?d5nc$73B&ay-*lJSQM^_-D1-IGpO^*Mc<2&J~=OH+r!~f;NZ5&|!vwq{!zT{*W zG=~-o>Eu05yW7-MEv@?x|I&OA6#_^$!k90iQG3^G^d79(-j?Z#T zJH+HyI^O8`y^b$)e7WOm9RIW9>mA?V_%_F1b$plOdmTUE_&bhun(O7cR&otm>{!z_ zwEg-n|26R(_@UTr?S2+nk4?#Qk!e;jhYK>aJN^)PfS5U42&er<7XUn1%zQ5J{$l>K zVA_F$BTo?@7@79kh{znPF_CF29u}GN@TkZfpQ(}06(1j&b`#3|=KL|4O^%0;8#S`Yxt-ZA zjvhB6%J1BE@k}mE{Xe#7qcf1 zU-^lXyAQp8{9~nSQptayLY<+U* z=CRq6zW7S5bPg-stGnFE+4V2nTbq<>=S@n+E#l$`hwX^J&0r6LN;~7*yQqG51YE#B*@k6Azv=XH6r_>uLRFV zt@DJ`@@YZ#WF7`^6gIQz1yNmSBOeUn>LzNH8U2#hv+$mdV2Hg_-okwKF=fI)LcvyX zMUolEwK_sl^-l>J1u6q!x!fyS=fQ3dYL%S>GD?V^;MLZl(X2R+RtF~Q!RyL zeKKrm1+ z6n{1wEB@^3OyBne6gHbQU&j_rGC9yXxC6BQCoP%eL^hkW)Ff*%*8zwtyd&=u$t^tH zB`2~;>y5K9xB*(HxA63;B9H=^!)`Yl-dMirrU&ZseN$`?l7!bWYvwIqu{!OvSKp)Z zQb)Y@P5nqqmYtPy`j4#29G$7j)fd%ozMgLNnp%3y>3gTgU7hr`ijBSTgh)h@S&^)b zYikO0%BTJAq*33yk^~BU@iB~^{fyTVg=%Yx^xH=%*#*Ru*86_}Y0{Lk4B(9zdAvK6 zHbVh|KObX)jX*)_DRy=y?v){hj1rBeMrA>+3OzwWM@6#*b(?cU(GZ0D~44lQ0VGky>kB2 z6-j!UXuybM2ffYS9N@3+I_~J9)p@yO`LY!qXK6>5ap)&q@h0~T^7o2k>#qF7`UdS5 z!4`)c+(S!63%4U2;V=u~H0#*1aA(9J1JnE^ocmX|$lU(OADPWsYPBHqX)ReTgx{cr zW+&mdYQYf>57a{VqgwQ&82E8*amc{>(+c6g(bn>MQA|sKw105n+(XHi@Rzli3^!C9 zI^o{hBE#JkM>x!Wk)As)j&PVq1;Xt%OZeM;o>W2?*Cao6$BBSz(Gn^v_-G8IF0|Al zvl-GWeID6eOnT%vX-Mz&jhEjJg0QNuYoF%?>3dQM(MN;J^i2?>FEqlmWj+P(%sW|u zlzV4#GbCea(6d+`%52W|mnN?MEqqNxV??-O{qO-V-@*5MiTs!^`F2HcT;{1NR*eKg?=_Fr{m+i+DVoM`T zo>fE>5S_(cCcoFWURV2Ig`tm|mFfGG*wP4Th$aKMBBQgo&GLJFo2Bm&MWU}E#!=4C zYavau7Tho$gaxKVevsvkxHUQ6Lsb-J&g8zS0FI-%FG_B#d9*dvG!u=9{)Oc9t2&E& zSRsBtR@3-a82iyT#^HZTi=`2U_gEWTfZ-1m=k;xnKIG8H4VF0c>9VPw^TK46?ugF; z(V0HBuKJTLdf7EWfn3+g2*h;c5Y<$3qRp!YkO8?8VvXerv{fsMjk)m+{-VH ze1o=^JN|Iw&DydcPlF0Mn0ot4WXg7L%*GlIu_2;S#IL<43H@l}eqk9W(uoipAexT!#j>kDZ+VOFYPjq~m}o&4zanMF~b{W#c?BCfZoHbu!;CL*{2|9zI{t)X+6k8SM#r}}zSHsDj=$yjLC4!1b1j+vA3Oe;<6k@e ztz+(4mX<$lV_qa0mmTlrxZ;?1jV6Dv7SbRfd?j<)z-YmX7@(tpb?}YTa+c7dr!X@&i@^Ae-O_9HST{~9}{(L=jW}C zw>aMFm}}qU!@XMjj`Qa;b!svN)r)bX<0i+9RbVn>9doW)_zcIVIp+D&WH>*KhmSjW zM3Zwn>pL4ca@YILo~+RhYH4A|)pyogCgaLFd>_aEj#?p^y|vE#D0p;!Wopk9st;x} zn{1xDxcYP2wdv^3k%#`ANm8Z$oJ;ZL@;8S~-EHZnJDW`532ky)w94#uu-0i0N=IMG zYm9Z>wM!%1Thc?AmR#zB3ndJebZ_oE^Yq&aTI+mnuzZm|BUqWf;qE*-?Dp?r|N6I= z`YLGQf~N2ebw_VX7cXDAx~cjOc>4l$eihsC7Pk7W%z`ybm!8j(Ec$&(@cSI``#r~RS3{cH z&d1a2X2lBIosX~CJ=6ojBzE%UWQ?@CncD}mUk2znI)Gkf3(|Fd;)hYmg(dpt+9v5sel>~wC2nFAW*XVS)F`hyO-Rwqc1j)XQVeav6`9_bI_^Gp@D&~Y9kR(7?be&y zI;AP~=Gb$*p-sOys6&{6B-||DNh2z4Mzag4X^2e+qAOdcL#W=GlFj>}+GXC4)gfh= zIfM^_-x=l!=-kk43oY6pw*%{l9WVx{TmeZ>}AMm_k zbuLV<)gL4OjocAQPaJ;IdwpZ&w__lz>KN{r@avsEZUUxnf*5__#-J^J7IRi6+BzI# zliOedaf=Sz3@yg^H)v_nV$SqUQ-CpXx2SyMwPk;4f)L04&eP)cZI+*RK;{fjSAf^| ztP*cfB>HFqn!eE1vc%fHESXO`zv*Pr-cg^@4iw|xIe zY-xnaUDEds7hrgKOoI&Wa;J~>f$95%m^95=aD3zRc~c@k$Z})cn%uW^vQ!ji&g5t? zQSauSl^o}mIa7U~0*r|ptP|T``xbYX;wY=RTUB`KgL;v9Ms+_P5nCEzGF19F56oHI zw-w;^ZIM1ZU;4&4^mly@V=lobOqsT(kF5?t)y+}!rAdMP6@m`(YS7a4Ic%LWX;Qd3 z(`SC$`ta?a!|WQMczBPfkJ>S6A{|@)jF|^|WqnpK^^EjvM-R}V8pLhJSS~&k;htv4G1PxNRk@ZdEyvE% z^5kOS)+eRtWTwLDTQT=n^{vFqP4=|uc;IVyZ9MR?V-DWs=jLnKDdp1=3f%Ecjm7~# zJzF|zSf7R=^kIn5XNWUd%%5jJ` zNX-kn>2ghIo%x9BDf5a}LqkB4kN}tM&FYb6t!r|1b&|;C^6A{#HJREyq^2fQ_>4+j zlg-~9Hg$YkRa40GrA$qsj=O#KpNOgB1kYY1%r$HX`toN=Cc9dN$PFc=_QOi58FR_4 zE|;79HEj!*k>?a%q7|^d$W0|QspkrLKub4PdhL{}<9py@A$Qbo6;L_@rIW}pDJ_DJ z`M5BbWPd^a(;ks0OUGdDcrKUh?GnlNrMFm$_{gj~C!-dt%a z!NcJ~=^jOB%1oHp`<+=Zb};X zPKV*Rk5IzWZR9Wo4Cj%i+lDvv`W%|3QD(hIp$78D;ZZ^BdC$zT4m+aZxX)Ea49EQe z^o1%r1x!kV(Qzud=1O;>;`A#OUMNw3{2A;x!*Qdk{*zjZ{h}9D)HH1 z{$|*Q#G?f@gKL6D##Dh!A*xRptNj#)9 znfm_vx3#w6xY23DaZ@rIjvM{sOZ%bo-bW=rp|lri@B4|?HXJu;CzdWi<^klVmoA4N zTqB-Q`h?c`?=bH0>=LiG^N%Kqol|;6HIe@w7sY9%Ckfw1S`Ej|2JyzQVy7BURBnxg zt2PHIs_zL}h2gk~DX*7L!*K_J@;dUKmL0EKbgsMyic?Ra{GS~$rSjgSIX0weC=Zlo z4adEg?mUg<2Z)&wVw%hQ<2fPAh~_Qj^C|MI5Hq%X1TiOO$0^PD@OcV?HrgxH1Im-PoTXE#n? z4adzXtKqokk?7*=@!DuOZcUP#XgKZ}(x>6LdBLdZwrM+PIPSyneJFdH;=*v;r%G1$ z#P_J!J#(Cfp`zI_SJA;6EBZ1;^&?f!++wZ!yib+%rOx66*>SlB8Ip2Zb*NP8uPPwi z7ddId6_ic=zcs&Zu}`s^y)ut#$NK+KWn?(+(b|)8xMFt;oRp`q`~5OxlPiCpB>giS zX@=uwzkBA;*}uQy8IF4`3g&R2Mg~sGSKt{HJhkO7;%Ujycqt|IY~H5?v4mkb?n`tC z%0EDCVV1jpQvMj8Md3i@%4;dkSy`kC0uk)aNJym1GvI995)AKz+hBt%#v4{D?@OH6dI133ox8+I{1Y5%yF&l$u(i8=1C!V zlGgQ{9t?CHQfHIw(<)ExC_?u-3LGEKE#(th8gV%8Mf&{na0ceaH7%5Irj=7Ld&QXp z8?}8@QI*VzjGSG`%+8F^DB778#^63zkv((dH)x#pr}kU>D4;Ri(gKB5s<`?|s2f7t zzpbw6nB_Z{PQ0D(nC!dO&+lF5=l3qe!KA|+-1RoUcQ>2gyXfclE_KNA%KQJ|#NMxK z2yOeCR?lF&HiR}`&IZRbt3H5b!wUg@^vPylEju4v8Yy!%IwRk@gG=vt1mV{;$@d%j zBHDKsycvo^hwa+5`$6BSrW23r2rWWPG>Rp1EKNx7U_6=OO3v)2Dz$P?8k$d}_~`CcKmG{WSa z($@q;XK|Ow@Aa*gzQGDZpW0hheV-Cr8e#HL>ElJSIg8t@0I%;_={r+l=xc~^l=Jgi zNMpz96S9S44nuRqvD^{2Cbyd&9x5gjX~pDQ_cc&l*_ zE6(r7O9MNukG?UE{dh`?*LS}3Sy>fTjr)Pv>&s~;kfUC9i*e|q&&tkuVe(n&dk%=s z@?z_%KY2+PTeAYWuF*kW4O%!Cy}lvJP%5j=^i=~Q`0&4^U(@T`x&5e4Cg)!NeC+gp zbhtNi{AKQS^lR$$tUBry6D*odY?8ET5#lqkC|o<%w+RN1n zx`BkpzEJkt`UXciKFaYij!$qr$8nqEMUKyLe4gX?IKIU3m5x8-_zR97a{PqjXB_h; z(e^8&liaxExWD7Q93SAg)$y^8Pj-xryXn8u@pX>>)iK>WCeOEV#@}{KkC%o2%<*p= zb7L@>?vDFA-pBDs$1@zC?s$pgHI6qr{#VDhIlkNRcO7dwsA@TTI^NImD91-Qp62)+ zj^{hR((!eUZ*xp{sMXcC9sjrEpE>@GW4g>N?MTOThFJJ?$0s|cyVGQt8`gM(V7(~f`ZIII6&%d4m3JsltDc%0*-9W%eC>0wGxG)yCKXCl4<3BjARYSw}rH|t#$BeCFGKV-m z+VO11a~&^p{4U3LIsUfeS~XxSuilQAIu2tD$NT?#2-kIpd!N|u|Nl(57Tjhy%HIq} z`R}@LLpe}AuUJy(bBj|{e0{%hUf9%4SAvf3H#E*)qVG3)B3Y>0qI9__$knxi z!-Um&;pa&vH&8jndEq~#q+REQzZB(D-mA2AW$;z!g~xQMIxlJ zf7*Q%Wvg z^TJbrU7HvF{nB9b!Vf3atIrGnS&8oQyzu9sE6xj#;mywGg~ztd=7oO|j`PAlPue&y z{2tU;oEQFh>ic!f3%@@)b~!f1cWp z^TPj_@NJ~s#d+beV(FL{zL{N{oF#oyekXa`yzmUxTAdgE(T`C+o(;k@u0(KaJ! zYc4YbM0H;H3Lcvm{#iUWFZ@RGv3cPc4Wc?P{Bo+==7r~*(CWPKG>ohB!oQz1HZOdz zNHKbzb=UDQb0I_*2kPofrNHeA~|pKSoL3iu1x>!*0fT;r~r#tj-G` zu2`EFeiFNH^TJ<2lAX^BpQn;+Uie9PY+m@Y@a%kE_$v{!dEtYBgv|@Tn&Q~J@Dn)F zHZS~7sC}CkKG=8IyznO>X7j>-lU=ZR;pY-#^TNNRbGbS%{MRXg%?rPnOl@9xtR<`S z!t;n%ofn>G(dxYLA0=kz^TIEsIDh@T@ZC^j^TL0L62AU<;e(x8oELr=74zoI3;zpM zW}FxPNmW?g``@cIj^;{c(^u69O{aw)%#`f7y)jD}OvFI>nrQO;51ufE`>cVPndwaK z=@jjIVa!u^0ZOfnli7rL(9(>SBhk`?fEqj1mY37>fRY* zLO{n*9nOZO!)(PYSd>-HTejrA@k*^XUUA=G@=u(Z+K0Kh>dknin>Su5b~auqr8YAE zhizE49|FGXH1Hksz7KTszE`>q_fDO5nGC*a$-;AmELpwrY77ahH-)r+`l7o(eoS-_;hW&xu)p69OYVhpn{!=`JL^|-EQuyh~tcQOq+ zFV^QX2lZQhKJ@>^hA?kI8<=Hbx@xW`CUe(3^dpm$@Sh75rHgSiJbExm)^ylH!_*+hbt~OzCZ1v|-b!HAjBbbH)TO5;= zTRWC;YcvEsZ=1=4I_kP=QUG-uUpt5Qt5)yG#>a~7<|!Yl4tCxb^ZuIj$nmhz68)xc zy!>_?gjIcA?PMlOU$f%Tr)EM`-vlxG3B%1#H`TSB7n2o2xpyWvLo${IB@46=X3q9^ zngWc8TdneK(w6eoX|esCC-(Yom49D75}C8Ou68mFYUSRlND#OTuWz07%~lxYYlv}_^YdCr)2szIRvjAe*3+vw;#ls8Ta){;ZVuYzsx!H7 zDum-`Zky!BnnzpYa9!bnU_cZ8qpK~lYTGRRBaRIiWaZ4hhI1~XV~*pVYqmD9+1hZ<*m&`9G0F?y z@Nwa}?y&1=(Uye|y>MJx)^9mpOn)ZDXm!l_O*rQ_<E z%G1MfAIEz;9_^Sx7`FFdV>`*hQ^Yvk`?zVNjL?XT_&xOa)oM&@$DwctMP_>*vyzYFFC zwcJ)0{*c)Io1P+E3+@>w^G7(Q?W;e2W8|z1{4X0LYV7TR2Dk96Ua z9Uto$`%}v+{D-oVqm5zv&i}5-{D^yO)Ngh}$eY~|$<1zv|6#KmLI*Y&*bUL9C`4`& zg?5Qj%c&ws9?>R%=xlGiD@U|*zPEPyK!(nsFa*MxP#LT zHb;!4Dx0I3HQHqJ%fhCPkJ&qHj(B$>nkQwQku=tpH$Uma}m2sfLfL#4E8b94(iOlgsh(9fp9Z{Q8R z&Y@zag$J}uuP|23tJ)m(Rz_8uqflkh<_ODQvpJ&WW;RC@VApJpE|dndIog+0uWobn z35o8q%@I~_W^*)}`n!3QD!>N6xlSPsMV{63x3p^AuQ(O?+g=e5DEo1-RlMw_FUXJYvRs>^JShNA7%Y>WORc(&K z6>By}tA#&dzO)ULlRy90g-XvpEXm(3s6pFeWma zBcAfAHb-Be1ZHy-1_?8pqpuNTHb>`jG|lGdS2}yDHb?stV>U;@?96PAf`Qz*;auBX z{ueS`nSEMGuP;A|f>ptDWBCeVc5ZXDkmCIHHbL@ZWnEc zWLl)T+eS#)pg6|83VcL=?1lz+);>O{-KT4y&JbL9$Cu1x6Pmz@hETdL#AwB-r887c zCrNbH?!`M&k=f({UEOb62QB!UkGm7!Yh&H>`VEA3WEJ#KFapxSt+_x=Y7Bx{yU}qJ zf}v1deK)PMJe}9PJIJJ?>AYLkV}!E~l7A;=L~mOUF^J7sbC+s-q%i(TImGatohKAr7PB~T-df^^~$u1 zPRB|XSu2*W(!qJNY>M726QJ}q+%|vB%9RUscFmu=df{2iSDtTnL1E;uq;2hjRp|+` zmJx5-&T3!7Ilfd=`7M_TQTynYxoyEXO&3(#qBYADmKv+AS+-`?LPi$SxwT}~f>pY5 zlwxjsn2;o-nBTs9m2|Ca8T+?1E8APB2Ey4n=2 zlfEg6N1vWGs`@5~(N7re{B%=Y6Nj6ug@e2^xfznNG{P`e!m|t zRXUCv$BQ_&S7@;`!sG$zYXYLPxXa}C`i2bJHJhU6q>p!j=1kva1$cearSDdSQ7@c_ zR=&@RNy9mZ8zh^e59)!+9C0jn#I4DFUQamM<*GBeZz{yw6#b{uOV!3{LBn{phR3_TwqBr4c55q>uC7oW*suDJn^yT_3MyQ*^5I?TSs&4Z35Vsm!>p zd3d9I)Hmm%T|>g8Ac4by=&XF^x2+HVd$cLy8Zt*cVsDA#j|m$h9loj~p4Tk81ytk5 zRAbZQP;J2IS**>qYnbFLJZsSitv2Z_&{{dEvJ3}Sj`P)+|&c!zaT7BUi-x zMW!vp2sFs-D;^PbZfj@$LIjvk@HRe3F;jl3Jf+%0NTMN1^wO|NEaM4Q}fjd;Y_prpsBVa|D>b>?W*SLQ*ja0ufxdGzNb zr`e_%wnbJ&HxZaAoTtLcs_4Vom^o1)PY;dkh-PV%I~{?#iQpuJ8kQ58%fCPf<}x)y z3CT}ThO#3XD6Y-bOukXuxnrV0A!4{$B_>+aDT<)JFljXDa*r6wvI5;0?Xrho)(iSq=OwLdW6JBwB_4(UwCN zc0`kCjZ{Y15xpCIp~_AHlOm%7=1(QpT=5iCoQ^q2p-2JpXRzZ;qJ^r$Ra&t`ojr3O zm8W<2PfLUBh_=X6ypvRCgXyOW`E!D1Y2c*j&L}0aBYIw&9&Ia<{O5vXI*C>gOefI- z3&lU8>n5!HOT{NC+0C%o5&g6BXecttTK*Q~`xSo#-^Pv)D1HF>ugucXXewSU$^2I@ z6b~*kXiffWpB4`(9>B5s`WCHi5-oJvBwCcrCecFw_~KX4fA77LpHO7%!Tf#S)!HV} zBJIRtFYZyBvV>!&vHY3C|mtUfkCuG+uo0jq+cxHu|vE_n_ps|Y%P@3`O zk?g=6&9kQ(Dl>Yh?1(7N#PUR?lpPTQJfFH!2|9898af6_ic=KQ+Hf`bBoLSLR;rSbt`%!j5P^9m8_CVs{Iilz&P! z^~;b=u6z?o`e!)OOrphp_spTQKkuHHM2mT5%LAoNc0_PeUWR8>@YI$s$J3G-qKHy> zfgT10k0lI~Xq~S^P`(?nh1r1;)6iIW7KH6tlQInwX`*v!Z;7f@DWT%)0U~$#i-4 zQsuLu%)qc3yXYhGT$0Y|b#BOKb2$vUwlbu-zI;9kRt3+E z6Rtsnw6lA1P1vb#UX)-L03elK;f4zAn#Nkta#Q08?5Cn_{4 zenus(tH3!vH%;mW!G$7cYTaPCRD4c3*6jl~6fx$i+ZS#uGHz_$esI4cW9-%qfd>>B zi@k1txGC9txr$IXYIoj0%F(LHY{J*H3OuYSMhv9AHAWuI&Sk?REe<=zm%RPhsX@V@ za%2rR&cVA=jzdt?h>FHEgX¥9elleQNgYQI0TJ(rNJqSt!ZCsZcD+D5}WY#=SdR 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 z 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�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 PH5i$52CDLyFv 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%0DpDi3e=- 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

    gZQp7^CGS{ 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 =b?s1%1^AgOcE4!;_BlQ?7$!3xM*4+ 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%0DlQqI@X{tWF8D|;$3 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 z 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�f3X4hbPV&G-<>xH;Y_4{e2ekTQ2 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�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

    0iRTWoHltwkF~BwDk*YO5F(Vcc|UG$hQR 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 z zGZNk>F-Nb(DA)la@VxNv@WYb0-^K2O^4o)fG_lj!?;+RC`EE<-pS}2Yv!S z&zlo}NKKdAX&PAu-X2HoDw*T~QF~mNs0}z$RnN!qX`%7*vqMhh%SYEliT-H{=BGWcMmnM^*mA&_F38PY|resn}MO8d_xrfHxjpo8Al1OJ3$gV5ZqVo2OqC_S$ zM=3i})&V`md#wBq=r3>_;5dN^fU^Zo25c6fYDWEU5^55dh2#$kB>HB^Yd*y>;8r<0 z3HJ-k!{ZAAPE?t46A%r^DO;L_1~Q2lDZN^vRNv_el+E-I(ZD-nw=Mf|dm(oF%zoS^ zsp%o}+xv05F?Rb|!7Un4r&>?S23#TF>eVeVW#EhIso^De4fA!)zw-MQ-Gk1*=J zH?2LRyQx3X0*sx~d%w;$U6i?wVYdFAdO-gVNy|INUmcu}L0uMA|4za9gmfaBje#q| z3-9E?@KeW7hw+Sq3owkgj%{M6n6tSvPmwlw{OT$dZMjWDzgGqK*|?vjJ~a`|$6z70 zcen-KI(XfjHLAyGl1@eIliLBSr4!LSjEjs8_@=XHW&~KGhAk$HPe?0HcdQ58;^`Q? z+3V;4H;P8{FovgNI$)Hv4S?upjcY+G5Q)Ekn?nmp+*M` z^K^`fMhDFFbd2+i4&dE#$;V(8=)whjz|%3hYV2`zfI36?F_`B$x|{HM`e+%<@Ejem z+|x0b(m6Wd5l_d^Q!-Bn^pKW(jE@-|@M%xS=%t42Q~CyEJ0^m2{D( zY=2UiDy<;^W1y=^=VJJpD$#&5JspFJC~l0tu3nsr;p>;U0gt%yKNsUi4%TD*QM!;O zY=4t3^4Y%~%-NYlRG*STbrHlk%)xUpj*@moS|xCtr(>|X3I;J|;*>O%0+V9afL18q z+04f&SU4~#RdE!Gb2hVb$`KAs3Q-(|(woiPoMM9mlQI)Wp|ECOtsJE^;J_r~m8e3V z*R!x7o8Z8Fo?M7#lLJ|oru+!b_-7TJNk09zlFaO$E?bcG_8&cD1x?2+DoY*OWT))$ z^}LpR@b$Nr1p9hfOUitGtG!9k9TAOcF&KSR3$3NzsFuZmO7xA!kj#h+4U@>K2l&c* zV!YBU#Q6h?mUAI~l&G_Way}Nz!6Ymt0^>}1Rz4!I-9yBE%R`J^(#hz=?U>*9WDGy9 z%^_z7x!kE|l)BEB3e|s}tK0PpWUx$87<8{6_mCcSrmOMwbe63i(m(cg`CCsiZugLS zONu1H(lbaArvQ}(47##pv}KYxle5oC7bzE{wu8$QXW6wXj<$pQdb@K6^X$sp!Ho4m z=^!#@abCcq9LpT+s6UIv`#Rebd~N!wxYE&NF6#;Wep1#?dlJTb{9NG9^_v84HVfc3>0~r|J7zqSxO2Tl_)GG7 zrhLsx6ssn`>iY!mSTn1WHuxnM(!t#q*HpGp^3penZCn9$Iuc82fog znvL;g>8?@x`s3T9>XEA0<-ND#=>gAy@l)xZ(Yk&`qX!(Xf8#QFv@SyHq7kYs8ZfBK zxFfb>zfHO%();Go08y|JT*zg?_mR&q0$v8O;Bji`13OX5M(YL?Szs2&{t!Dy)643j zMo#k&GHJN1V;rdt;{<79+wNkE?PO^ej!1)wl>|$0yByX@2g2w?wn+Ob0NUyp>M%OI zgBl~~v)%#YYk3FIUETrXI}XmqctkoCsS5l|;J+O`zt&?b>{{s_iua_`t18R3KD%fA zh>|^rZ-+`?Dz-jFdpkkCX}_MJeqsNfAQMO0u*G#hvWYv-aDy)5{j!pVpvJyQU2L=O zW-UwUfcrU8Ee6*G1w9XgtRGlwnPK>WHJ=LuBt(y9q|_J2%Ju=VPE_d0$i1?XcurRe zC8R{ACx2DnN9Qf~Q6oo=!hDrp&;O_2)bg@!ojH{2Y+iB(9Z+bP^%OyTJAtlJ6I=T$r!BwysN8RJj|@>dXuTQyJjIOz5okM+#Z z)yUKjlH4+ri4v(x+<&q(?JzgdBujOtjP{l7^ALjC%hV%3i0LBTOEW-R-Ac7fm+H>< zBVrk8ceBl%>*3UOHigS>{C6q*6*fu7WPx(oO~Q#txd^Ott|=F#za>k{u%a9i334mqO`mI?RFia zlP2}b19IXL$JyOc%G~`tsnQz~_{upR_&txyGtr5|I{aGxDO-zDr7jLH)mN9;7iqC< zBgBJ+ za|?%(3_psp&PmP0oVfbZOUE^ewEF63c}xvVmiErmtt6@3PO_ywU*w6>KF*DrkpD0# zu~ZVtA7478H{tSpz01!ou1zIeT~9flbuNEWt_E6qlp7XaKI0RmN5pyJxLoeI*b`>l zkcE`BgsysP6697C*K;3}OI+#umf~~GeL^+9Z_3BY*90FQ|DhRQf)+#HrhMusyQHfR zVX0i`%Aku&S0e5z3gu*Sp!9W|WpU0(rp27f6;UYkMTF&hq%NgBg}b=Y$~f$EyU5kU zMCnku`gY_~=Q|tU3%XJ_`95#y^M=G(>#pna&c0kMEXq0zE93I8rz=O_hxoirx_+jc zOK*68*Lv6O6_*|EoGn`QT$)61P5|!*TIa(wrsm{j~B$C@q?=80xWI zuEM39D@yf`YdbZuD86-!FnwNLx6J3XZ%3Cn znLekjWl@MpH%KJoI6(1v)9&cq<2vH&)c)&;=l40}haBId7wy##ky78I`2NYaaf=m_ zy@X4gFN?FUaY^-lCpiD~1=c#~!4j@!`ZVl43LtS^+?!ESuGLU|l#58|;_@RM*Gtk} z9Jd5w>f5{@hkU8~da%~j=`6XTcxt-Xu;jeex;;v_MY$Wj7VD;})w-j~E^4c9zepEh zX;z>sqjY7{viJi_?h3EHZtv3cLbpom+Nq1`9k;;B2F(?l7S}WL(2Z$2cv8PaS6Q{U zb-LCpyc=u@p6WT{;x1Tv_2;mX+2F*K;^! zg>I~ZNB3K~>>{15tD73Rfot_*mwg=P(&b&N$Vw+pg!biyE7G{atFfuEnRylITkHhy zo00DRIKo`BVu}3k??N*LzGCIl7I&i{!THPH<~e~%pZoN)g45k$ulS=@t9)8qF1dTJ z6t+v9f^F8_c9arRLzil<8}rxi=~A?&mNkv7K6^>7s{~3EJk3k$TUvEHT;#Ku#OCXg zyNa!~QCD&4cDBOBfl5|;%jzaoFkP{izo^RzbyL>HsG)gPv`chlk(%RhM3daTO zZ+VMLE^1q|N?#4rO?7K@ADX);?PP!bSDmWs%$CL602bd#s0jMBD{PM#AT7c<*eS|_5K`i0Uc=-`|*bWYKrpo9BLL;tKa3OZOzBuD>(Op|{{K>w;R3Vtvrl901g8dWm1 za3(P+JNwTl=sYdAwD7bQg&Z&@a@Zq6VF$B4kDTekBV@wEJ~9d(@ToGP-zj`@jQ0q` z1`h&y$8_GfHaa)OXfSYoj}=D24>o?@Fh)TKSIDfC<_$d*bg=QiJ)nb)|7u~J;NL26 zyv$1J?*#N+!lV~EH$tP}2U~e@a0Ue(%t5e9>0{gjYEK7SxTgu@1^$`BCZ{3b2M>wm zurq^#A3RVd^4Xd|K?fT@`!p!%VB>!(po6RAjvRJvQ1F9||5#y*CmSABa)+Ni92ETE zqhvyF5w>z%9vRa=Eo||;RhT-DoO^^(@PqYC&B@sn(7{;YXQu{CSe!gS;TL?0Oz20r zNBW-5mX1#BIlp{T02%O)5U!F5KYJ1==wR|0`T}8VBktypn1}rfD~k?cOXK&1E$!?w zOo-)lEf$bMK6sc+)}(U$8v@eLA3ndFzXKZ~_B`0fwKjDupec>>w~MVCMt|3IlBY z)%1W4wsC|L7$^*|@pI|DrKMTe+7Wl#A1z+u@KIrlLx-@H;}3;V7+|aCe-Ji)HvBBC zlp2nO#Yql}8>cr=$N?Mw(0~rMzHVYb2j}FEcrFO&U`xw#VT%tt>O*3FwjEJ~3qDpR zd|wavzaczSH01wU_=p(OxU4R*X@Nox*xDnz^eE_H`gY{c7Pfq-6UH6-{D8hd*z*6f zfX*fcae#k&KxfB*xV#^m;=nv*{Y!Zf`2S*arjT+V`F++nTBlqa{A;-nb@xh z=xizL=ja^*CWo!rF)^Keb`)~J)^<37fPxNImb&=R08I}22gI3hdj@p&dueOX+4r^l z=VS{CnP6*=CktC2!r=w{RZ346ri{S034z~N^=8)=F2o+GdFSYnqoa|nd27wc8d)2g z8b&T@T(nvjYPYhy3@J=lqu8}!(W2JI3-)qmofon<=&Iypjct3;npWr&!m$WNAsV^3 zrMX#4;%KCwe~LzcJF!G_HK1;O;6mF<# z($s>3@trOn{M1OJkQWc0&W;=UoY*wJJH&U7x$kMw(IFwhSCjVZwa8u^?4iQ3m8hIT>ue{AmXty zH@034iz{==du2Z)uqeMOg{s;D-Ls z*fhRdPKbLv(NV_tE8%!@;OO5G-*|`oAAG34NE^nUJki%%Fv{F^3kT7O(%1X;MLKjS zJf9BU(ltLKM_nZE4k}cv% zoX6fyiz=v;8@oa~HNT)zF6E(}npaSJ-wI23VQR56S1PEK8}C9pHK3qUDnZK86!|__ z`T=Q1bncBEA=4D@%mPheKgldIv7ajayfp6#{XZ7as;DU^QUknV|L{M0UZJgo;@_F&sR2acc0DlJ2$6Y-!t92{5K>HsrV z8xMVr;RylHqySG1@bm!B3~*h5=LL9vfENaMNr0Qc{q!eAeY87-a{;abGkuduU#jb{^>4oGUVwDD{W@bzHcQ2AI6O5FF1x=sUn^neU2miOl!MxJ>4?;Mng6V|ovn z+ha^r=|hmyPv)n=;{U2l$`Sl^ne-!u2P>Xn4#$s(F)I;XV}s7o-RA>(57D6ifA-D> z&Z?^1|NERd2L@(%5pYCBJ&dTR2*Znr3JM4aiiW(2DGmb+f(`>RgP>uGqNx{6N>dAi zl8g)u`>SbDq2g<3YL;4d#nP@Cnx>YO>Hqg#dp&0!@P)x^_jb$mIs2^ddiJxQz4qJM zdp&!twb9wf@ga^+bX@QF^N#Ox{H)_YIo?}0Ra+PR@QqJ)d_iQ|c7HwcsoIGTM1EHB z@0`4~=3$3+-1|gE|Cq?M-mZ&G4Q^p%dSRdM_;Sa$MlMrX_EcnA)cy_Dv8dAi&gE0? zC)OL?kOw?+ci@9rgs{mI4@IW2AYLtW z*bhI8JXri<)HzmpFVRKDdTIa4gg!cDky&<+sDpm5D4!&GpC~^+=Sy@<+rV)fJ48A5_lk`D z-ce_Y7Cj`&IcGi{nd4O(d4l50A|I=Lcza};xwqEDdK(oNB4d9{WRB?xk?9pq+VXa8 zl#{pRk!cRPI_hv7zZd1S|NKSdXB9JHXS{SW+GgAK<6+5XN`7wS>0JQ&5==QcI5J+EF0zHZhvG_D`9TKT`2YJMm(EDV zhr-e+L^hp?$fd(Q;e^OHDLy$e+gRh|q|xU-GTX_y#~^3fMUlBzoEMpU!9|Y$BQkcr z=;X^Cf8Fuw$ml-s_)kKR>m^W6fBXdt?++*atIjV@vx7-=`7&&h-NW;8s>>8PSc(=%Fl;<9i`zY=e znR2vWWbX5fhm0NG4lt+@%y|DpBjdp)jhr`e#9*<4-18JByq}N5}?drE8GXlVx$lR;H8<~-UZjH=aOVZf+k)|I+=56Dh zk$G;~5Sh2AKaKoz#g9eC4r%N>r|DObpH=*yk$F@0Uy)x{{8D7z;Jg}{XR+5Ka}K;6 zS#9l-cO&yQgf#2gS8-|Nwu9+u_p zYLCc$6!(hE+f~x&j8;4#@?nY(jm%q^A(45O92S|kA)ksoLGjqgy!DtAndi+DBlE^# zJ{;W_ys>7zbR+$b$lN>VWQd&kcfe7fH`d7ML;BOm=+os8IrIMtM}6K{Bc}st`^f0i z0TDU#2f5hm#^S=g1eR}gD=N|Xt$h>iWFfwnMAAwb_E>tlEm&JP1 zZ=#(03|z*IPvQ4ber{yb{}Xbpi)Y?=jxTwq<`Gb>B0kC5KI)`UW<6JAYv0(TWd?Y&`|h;Vt~MD6dmYA3fwt6@NbRTE#0J-x`@W z?+-@iZRRVHd6WK{ALZ09NF(R%HXZ!1^N93ev-3#Q;jQCE0CGTVC?tUNreWns(1#HhpD@M%$JlXPG^_v)hjImuyLFCF|? zFK@=_H3#!H{M(MH3nAyt_+ybde_n!>pBH2kwz8!()?X;k87>Q*&C-F(3IYYX$svC= za#`0P4*lhjzo8_3=gKNm`O#7TEhS;w_T!@bZOP%XJyU)B>DWp13=5n7yeP-72HSq1 z9*cgdz=r2i+F1bnxfFro(sM(Ba(JFEaI%zLBXL5<2P{$|-Iixszh1jO2vQnliFO=%R_% zf`qP`jJrqHW5E{Rdg~wMtZE=En}ZcInf+mKv^i3Y&HEJ}<9K}JpC~>t@31ntg8nwolkU znKt@U=&s51dpTzRn0%1qqaBZRe1hXCj%yuLzc!m^IsTmEs~msbF?DiVc7tQeHIqN> z_yxyrIOe)C{osp^`!M*NBX@H;y&cbWyvXszj<0aM((xL{w>zeeZ28&b_$|jdofoD< zebtycsd0D5{TvT=JlZk!L|b;cF zpA?~^lke{2)Kg6V5IEYTeqz@nBb=I@6P$h+qbk~;<>ZY{|4caAyvga@?&OT{Vb`Yr zCf(1S{w6rC>v<=C)ydyGyT|hdKEXPEP&BY}Pv+2F@}& z_~cFJGAI9{lYiC8uXFMn;JDwuFIR(!g0NW91jt*Ui>geA&<+}!tuDA3ddzX1M3-)u++(~b@J<+{1(Tzi&+x~RjL{AnkD7LIv%)A75GOJo=Oq4liT?CbfmK`#51x~&Qj``<(gz+_wuXFrOG24Ql=Lg7R{_k`;_e33hO0*2N?Rv`T|EH6` z=;W_B`CpuzdX43+oz`vKQA~dDYjr^$w{agh=8bxd>GzKM_%sf2`oo?6QBHrn<4I!H zh3~5dd0f{bIIe54lT#Nm`7$S8?&M#CQ1&^-tU-w297g+ z7LGPwa{RjEw;kv8EMxlZ9P^CBdU=-Yg535k9JjZJ)5nKpb`EoVq+{Lzna-yjpW&D> zqD`lJE*#Gkl7jUc#`89$F+{@9P>PE zb{OB^_-w~Z9AD&knd2)RFL%uIv)TNX;~O2{;+W@Z)4$X4J&rdze#G%pj(_d=Ima(J z=G~L6>rKbJe=>QZ>(W?#nTyQ(CX-VSHty`WtK+>K_i$Y0_+ZDpS2LT#9FKH-oMYY} znf^(Rr#PPFc(&t4#|s@Vc6@>3rH(Ime2rt?2U&hrIbQAfX2-k(GW~Uq*E@c|@k5Ru zcl@N|XB|K9c(dbI9rNzW^6+=Z8l9jh=lzc9@E*r_N5@?p^B%`^ct2!(fa89Sd3R$v zyst4H?wEHxCLiONdXvc~JEjh0@|liLcg#B-(^=&BT*ntXzSQv*j<0t7HOIW`HT!EE zuXW6OBGdVy;|-4Qcl@Yh>T$O0(~harnfyh^FFSt2@mr2Fx*6ND)bEVT9aGmcIo~li z-pw)Zs!ZP9ac{>5Iv(hFu;WpVX|H8A$2*?nxW+Ny-{P41r0Lx0_#Vd_9rHfU^l5u$%zHcI&5mDn%(vQ2hqh|Q z)Mt(LY0V<@ZqDRg9Cvfv-7$kqnm%=2MDp6GbGU<=Nx~@@s}O* zH7>J*@5T5w$KQ8+x8wU9KjQdt$G>*`tm8jA{*&W(9B1W+vHWPPu_Dv%*W{fXcXrH| z$xLTY$NM?%>A1gR+6mjTLmczI-{idOHy-2oc*lJ2$8@GTp5b`5U=Ro6i$Jo5|mF z{I=8KeW~ftR>8O&ADXUz0zNvE({{nQi__`q-gu6pK`p(@pFz} zcKn*-zdC-$G3^Cyy{#SdVL6lU;dpPy`#J9Im=BrRvI89tc6_8`+H9CUAFwk%*>SDo zS&rvAZgl(^$LBcagLr2D3y!aGOnVN~S><@OUf>w^^Wg%ywNcq;Inl-6# zFFU3$fa$;GIIG4ACZ`>UaT~`wINsGUeI!hOZ^yJ7F*$8VjQNy>G3`r?k8;dM08KvG zF`xf4`CP{f9Dl|!p9eJk%N$?n_!`G+9Iti!J;y(A96mQFUlQRzo%|KYe{@W@W6KYp z|26L9xU=Ivj{7?v;rJ-WCpxZn{8`86Ipzb1mWL}HFL%7sF=H*5{&yYosYH|i)G^;e zH2H5FZ+85u<3Bt8o8!FR?U)^n&{^d6jypNt-EpPkeH|a*xS!(zj)yoN?wD^nT7D)u zu6I1o@x_iWb$p%UZ#w>wtbM)!UKZN}{VT_>^GS)lxy{5)}on19;3z^e8qmqpgCD2)Dw zT$>mAEWo@&`$p8+Sxo-~XmFN$}K{Cja_ zg^_8CvNSU9m%b2rg&3bR`d<@&HS#L) zs>rn4x*;-sq3}7Qf3x_u$b7zMU1a)|+!cATVtmf%pRf4g$QLMnJn}_~e;N6UifKE9 z{#O)lj!b`uKSstEj-MHwdlbJD`98%t`5}=%AZ{IbqZmIk@+ZW*Mt(+2KVIbYpTM^a zf`z$LPVk5=Y)mG4qfgsCf6t^z*>CjGX>-`$e9mxL@Sc6dxA(Y{jD@)5m#C zWc;=Gjj^*v@kx>K(N2v_+bDd<=+OV8J~AIZYK**2F+OB;?oxbiWZFz!82P7)mqw=j z)E6StXXNV0FDU+My`uJb*6~pue`BUU^;dhHS!UnzcL z^lw(YcVv8}JtEUbq)+5K6c37gzhZpFEQ_ynY-IeP_=l1IK{5Ven0_I%BfqJ*F>)K# zjqwAcgD(?5FkB^G8kv3{Ux++Je0Ai};;%+NPP{5I{>vL8^P#7;k!dHz_F$iWBI_dK z%cRc>@>ycG4XzW@P7IzSemwF#F@0f>)4ya>WPF^zi;ORmeSyx`#cV&!C$ip(jL(wx zW60@~lG6m!cfNJxA1iJjnKo7xkvAyr68S#Gm60D*+&wb>%bt-pE5;{`eSDLLM}A%L zh{!GE(_){ZLqGemk?C*9zC%u1Dn`A8>0>)RGW`cnja(z18yUag8Ii9PFN%DX_`Jy1 zi17nslYaJ>MW%1dHIc6u1X>=sLEIto zGBG}0boiLp?veR)7yBLg*TnlpzD`^fnf^EZBY#^wF!B$@LnHrKd`x6~WB7Hk`IwmF z1mpLri%cJ!hR7x2vm%#@&y7rf%nKvq$66YhwvM!s!zSO{x;k=C@mC}F7O#rjSBzg5 zecGw5jf@`)zb^74#p@!E65kb>c9IW8rhgBEXyf6+a&NQSmP$(to9d-4~g?0rjLKy$b88zFg$^ zkOoG!en}bCIV~7VEwOr~@0Zlg$!S+K}Tgt<<> z$T7YPTkjQ)S2|wf_;$w|96#dtX~!=(e#3F1x}vSO+;L~e-5ggr9_VyQ(B)heDsL)%eCqKIHM89^e9jayxZrV*e^)B zt4}&_2lO0y=c}!HKhSk@w!Fo?NwWWhU1!YOG1>U%!aeKP-`REju=TS`Hg{{G`|6Qj z`b~?!zAJxAiL9>II|E%~dv|J4IUy+vD{0$4r=mMKH?uU0{~gwUhVh#-6ZN-m5Tu>g z!EB}l{l>GI(kFH{`mNC7w{GU&7?6BNINw82%`I z;|DP9`+oi#mH)$^?u%#0d%qOfl;Psn6UjM8Kp$L;2V$!)D~4|%Hf`igeF(6y#nRJR z_P_nv$fgfBZtu?e&`+VKyP{XqIkrXCi{GM5jy&RsLkiue&70GpFB{IOJK)$O3%z^x zsp?s^Z=qk$0s4>(_w<4$oukR5#@hOZn(9$}J!ZnV;nhQij{DT;3FC)Xj~+FC_}C$% z#|^4#J!I&pLHKbA>AgLTS>A$urI0d?l7*O1stMLTA*s}~k0zEwPWhxqks$A>nB|aD zV97-n(uXQGeTq4J;VtNx#@a)Ps$$tMC_^RP_$Ps zwq=B2+}MYK7;N5RrHz@z7@}7>f#D*}^Xr|i=ZuxoWxX6P<`FN`WXlMXd74oGVz7Bj zmG<^>dcN)^8TPog&E7Y}wu~_Of@b{D2@F?ip10Rs_VD#$PrImSk4Ju%v15f#;z2VK z=aF2umEN&BDJmtifDY3=nmCRYsP}TNS}@a3NMOvo)zafUvtaWclfZ9Bl^SrdU)c_A zQgJ(;6WcPv@ZM`R5QEKoMrm(vpzNWCJsuO8hy5Ki**Px^?|@zgVlaEeI_$-;S_g}^ zQe4;Az#jXXbJ5#-Qr9`_v|#ouZLybslyBvj9pd+X8;4vqg_3Yb@M-o$Qz$9kaZ=f~ zzlGy-&-$&pV#{}GGA?@Ww{dnV=4h(s^Q{_hf&FSvA^H@IJ&(l46K3k1;Q3#HdtE0T zD3aYGbI$J{nPbm+iq7$hIk({MiYp_JR7@H<*JK|!?jpD>u8VspI+UH1cQ7(SN7c3M zoPgN_Oc^mjRlg)7eL@#a*7mWhWAcEU^NIU`^@SiSHdYJgo-x~E%rk=7r~cyY+xT?Y zH+}9W#{C@+a?CcG&REAMIG*D86vy?B=Q}>j@db{TIsOV9_Z1aS+m>69m+DX9ZcWCI zIi?&i`DVv|ar_R1u*_k4JlbQ>e|+wl&G3)+JFx$NLI~UTk58fO(+#JeBJP5nb%$It zy=>UzlI2VGpD^{FclNKGT9M4V>z%2`Crd|^4ZH9!?^&OtIyzkrX@??nSx7IPqu}b;6CyO)p3%dq^Dg-f>ubX?EywrP3 zMZWH@hN$IGMNPi$)d-8e?r*U`F3&Y8CpV{=qN`FX{gm>)?)8YHubYdsWc-V zEPq@7sjqt^NGJ`y?vYt(XU4UZ;~>e5WFgA%R`PTogW_Tm@^l}I+7%?^>HZXIn>48% zI7hv8j(blT_&@Eqc7AM~>o~5RTf4P+sLN6hHTg>)M?%BZWIrWw7LQ#4_0S|=Fwv0W z3_&q)kmZvlqKGO<8Z#>ZGc(?q8Sl+(>2r?j(SpT*6}i5NS_hm!#En?K=g+PHSV<gZPQN7f)HQo>S+~s+->HLmhFm z>ZjGspI#fE?^T>N%ia4Exm{c6wuBou(?Z|+l<&1gNv;*{*pgNq^lyyIwjKvBnk5~B z3pdxQOs-m;93SAS{XgZRomn%lx^cU`{vUcwymK@hk)m@nIDNP2`3)7cxo3Wy&fj7V z%%k3T=3JdL|4{cVSG2ie_YiZ{6YByGE{uX=okR&`1qB6xyC;k;a*7wK1@J+dOy5cj z^qc8gZLD3WZ-nzr^Q7n0hAqD~{?G6U^X>a;c|qIFj-<3E@VsF=g|ro}_*aaP_fwxx z%3`^5!t%^3*OV6L6!mGKj_CvIBJ|M|A8|tZgY*V!t}TNi&u9f82Fnu%)tFfqDSs?W z{_>hEe>|Iddsi#n)(H%$*LiyzWREtN*yEYp?0s5n%LtR}mADp&!RF0Y+L&2K=**

    i%p>5flxJjd~3#}_!h!ZG(DTh|K5*Ezny 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%0AetE#M%W}xL3m^?(3MF#s=%6z3GeIUZQ@=Hdruw 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 Imwdwi4|M-2I{*Lx literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/lib/libcrypto.a b/Distrib/ESPressif/RTOS/1.5.0/lib/libcrypto.a new file mode 100644 index 0000000000000000000000000000000000000000..b04d57b29030968ed25590592ab84e65aeffdbca GIT binary patch literal 119932 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 ^ELGZNUK)Y%t3Jon`CvyB0)J!Ls(qI+XSdttK0 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 z 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 literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/lib/libespnow.a b/Distrib/ESPressif/RTOS/1.5.0/lib/libespnow.a new file mode 100644 index 0000000000000000000000000000000000000000..401ff1aa9115b35f85617def4cd2168446231bc5 GIT binary patch literal 45608 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

    ZqNw_sYEJsGYMH1GZvsb#t<* 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 T;Dz^-3orv37SbF(4J-T)TtX*w literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/lib/libgcc.a b/Distrib/ESPressif/RTOS/1.5.0/lib/libgcc.a new file mode 100644 index 0000000000000000000000000000000000000000..050268e658b2360f06a7611a192c429f3fe5ac89 GIT binary patch literal 600904 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

    GDZ4A zuS-B=aSJ1^4_v+1LvlZ~$QVbEHAMI(cash@P+=qDa37YdFsA%(Np6%2BLjU}&M@KE zB*%FeS=?$dI47g^?tFE7D4s9pZ*>LP3SESo0g+4}zD}`7x2Vv#ZrDbquUeQfkk_|b z4A#~enLZ1f@A+@MJwweZ(YEVxsR1S0slA9LahC4ieHGY>BCbs)V(e+ddx0rv5$)LcLmfWMVdgzdW{kt9I(&x1=Q%vX;rBUwk;97} zzRqFlpdI%nFcn4Q$KZs+$J*r=?-ub}4PA|SN7f%+uLnG$uAlKd%0X2zL;s~m4fdUe zs(e$DG>j}HxrV~Tl@li}I_J#EWy!UNo-=Otw|-fd?{fWQjnuv-m$tQh=KaE%ef76r zMt>p%pwbwUZbIK<_yk_2vRClRZ z`-NOL{=%sAXF7;Jr>rc!l;L4&ca-|^XvckvYFFDGlNR5qST=aC6Z?{~VL;qtSl<3y z=nPilx7XQLSZSl#ZZ?|T!;fZ4_s8#uM^Q-zZ@# zdcmTOLmY;`PKirBXh|RWLBEX;&qml0anMn6T-vVW#!1G~2quhM3V=v!F z94(*oWz22od#140w?tv4c#JG=k{Dj!%hESdk?3PsX8M|iEsbEpl+R}Xku2_Fg$)zc zU-ynnqYR$KwFvv;j?<04O+1dv^|Iq$C2VN~laEPX0T9XJS{3&C*lRdQJoGV!FnymE zwlsptze(SB0Ff+iwZdK>-*lKK9{R8iOy8}-q^XyK*bDi;rbJ;NZbS48}j&(Qt`Lwq0{c$(E?=y^mO+C1L>MiM@}Wa_ye3ksq#T ziE`RSRkYp2rrvVhp&B{flUN*4v3JtX)4L#JAjrPG%=NPOAEM9pRwDCudWJPj`LX9# zhdaEzXILjXnb3d6!aLXT=Qupy;Y%F;pu<->e67PP9Ht+&=O$}~?HSM);m1b3(cvFD z{0une^H&ZF7WL3xO(&v;)pU!P`e6Kn9IkVCxWn{GCQth}e4N9Sr}3vce4fKI9j0te zp8ND0v3~PL>ERicx}W5hh$+%9MBHEg-4PFv{~r-kukVd`Kl#ub@s7k|8;ct$yPOvo zK5A4UP}lPU9oK%^ynsHmP*uJ%NxnP$r!^DGU-(wEh!e%&MWNuGIvWWR>w(VI40 zS*>7w%gTw<3aw|YV)Ec@CJ)A)Gkf+U57(97KYU9~_yB{-fnLqOQ)yocC(;D@_Kin+ z$K{!iWnY6A;`5oiEHKaF4PJ1%<3|{%?<>kKuUNR=c zmwlT+`gkh;VOX~N@|z(dcN@IQ{7ORAxy1^Vg}I*-azlh6a!{I6I3Y(hgqTw}F-X-C z3Udl+cskLQr|It(a&b;UyGg^G!VfsoPR=Rl9BocPm9qVFuD5DVVVq9EmSBP@j?R`~ za&KX30YCJh$rQX}NSTzm@F#kNJ0PM_Mn=`$8ZV?FHm+|_dU`+F>C?FC=mO_6M(A#JN^;~S;e zfpXTexclv%XrK_Ff*d8tcmvwmd4{KS6XZU~IDzzB3Bp5T*z{5QR`P=JKA0qjI1K*< zC1(7AKCBYc*KwZVD#dxStACW3Tv@YdwkJ1EGL{BC*T|VoN|@t9^yY>M^OD0U^2r}o zkmWColNC0)Tj0+YkZ;GDB<%H_Cw)6J&%nKYXXY6u>qf%!Nh3RMix~d6>vhX*6OZ%Y zdf9nUUY15MJOeENB3WFk!d~Az4Wb8$hdxFurmy2X!wbsaj}>oZ`c{kK^{tS;E5$<} z_L}LtRhTq(t-h@by)*L+tdFAg8=(W&ah~D(lB2E~S^gdn!!U8>s@S0iiGmilNnw8; z{gioYAM{3c9$SPh4Jvv{ANGTh#dVx#C`cc2l*^9h8BUVEt)@)A>BHA0DAID>jCW?9 z;U1ktZ823zpJN4R$04wLo*}(Xlm&g?&dxJ1Oo42kK~=Ii&p>~~JOgzJdcE@uHKdId zf$IvU&s4Q}TfNU|BKg5s7fq8hJk#O14*#vpKd2cO%fFw)b}hsT@B6cB#Qo1O{gYwp zgW+QxKE+|m&}61NJj3DlJ3QavP#^dck!PEq@p)eA_#YK!o&j1R2c}+KA2EIAnuzHa zKO1px`FBQ4-M%N{cgx=tF=p20h&k_vA|5LrdSm7#nikAmbXi=j(DgSO4n4enr}w1h zDMu9s*OK0JAB}XbSLH3#|E6$YePPrX{zvjZT+G7AB->D5xT8>D#R6sJ=Nbqb9Vl>{ zTzcQhX9f$0O{(9E5(q%0^$OggwO-*Eb=O+2Kw)dm>tsUNvU&3IY~<{?Na0h6<@2)< ztIU0YP-T7;q3YZ<3YG1nzswoMMG71?vxWruck4`*dcZ^fKXHHTt`l{CIPhxZsVg+UhuaZj+)By1S_n36R)?)_GpfXWubW7 zR$;I26$J|78Cl#1#PIsYYd&C*c<2)>>RT;rX#|r2x~N|PM6$T+6!!Y~zT-Uc(AO)* zQ4iM1k)~b_`hoQE2*C)5`+W3GZncyTG@%%W++A|ahZucXa@18LQ@u$H!^Hhca-mm< zf)=+?VSgT5bROiJ^XM1j2xA{x8o}hZN@RH@Y;oTg_WGWZKIG8XKgOYtaj4aK!Q@~W zUylMJnLd2lmC@0ABuPO`>~eH)tZF&ka@*-UPn86_-N^J=*nH35){gc^M!!EZ!dQ$Y z+V=UqFLC6Rc}Lqmzo#aaXxn!tamFRu_IW*{uM&0r{JwwjdHsP()+ej;wH1%y`FwHk z5r%j644xyrUVE56sNH&P8ncKqGn*5;#4z>7Y@z*x&AzIEAB!{ewNcOEE-iM9=^5wn z$qr9+IP_sr&rHXEzr*xZrt>m~TOGd2;T7Omjp$n}|F^(*)x-GIFvDcUFnx+)+L2+} zf#HK3=6+^;+MnT(4u@;OpNKYO`J~;Od{;InX|I>V{zTQ9h-u?DM@+4}Jz}mc77g+k z2X{t{bpX9y+j4qKsH?@-1$XtF`_LngJpA=O=PuflG9!1wq}-uRd9coTv^pWKyZ$pH z^q=9IKwAPs9b@$Myn3VHHqWakNLJ6Q2Psb91ZpIdEn6WkzaG}IA^Oi_YQ}E@h425^ zJA@UNz&v?_lrj z-;Lo-zoY&-j0xoJlHF~ENjmGIxW5^Ozox2Wr*Hv?6Kfm0`@Q0MB2Um^a$GEWPH1~_ z9qsN$$rj{{EKeQn?%S1_qb0=nwOr2fH%Zv?Aegkujd2Wvr-*O51rwhC&ru}$$hYb1 zXm@Xv%uh)W$@H}-Y?!DURcL2K89a+)tm}_^if*8b#pAe)NA0++!j?ubd0zSofJheC z(eA!a`UXh`eONoDkFl|(5lnjN!h8b|$>KWN-MpjM^0y86!ii zLm!yJ@NaT=Ddg?$|B>9N4srxH$+^QM@6yE&okEngxQzj6wqtjP$I}ew-mZ3ct@38J@Zk>cjNLui$)DwLv%?oSe7VEHCZ#hHEtj)A zV22pK(czmMzRlq_ho5u!Rfl)xUB`#3U36v3S4*ea)ZV_P42?g;;X@rh!r`$FAMdc5 zagyOr#IgQTTb@3`YA|4>0J`x%3{dY%PBOiMGcK!TI=PsN* zLa%WuKwa7OBab+Ir`NA9r$g6?jtn`peeJE>@{81GTC>u}*p{+g8ZG zI=tIOf6Nu0TeXQ*xk+1+JeD1ueSB!4VqQfWelFX#am?r*bv@2}^pB%^{^Z{i6+;>` zI$L>BUGDy-Et8%e^UCl(8w;I0bEX~`%@9b}w-@sC;mflh&*!r4+dPwAr3~qrG#@R}GwIv#vSs1rOvRTkjTbY#Y$>~9j#TKG^qq)R z=B5WP&&Ln+O!`Q9Wq0c@^NVuEBM^s8pGlW^Sho{#aw#6$0>1|hLGOe>9mr17KkzH}|XshDl)umiKMv~gzjz{B^ z0NzOfPR2VYxr6P#1!GU0hoU={SwjXjgR7cV{f zWW4iIuKokUi69pUExZOTMb)OdBvS4*F17J6|5x&SzLVpGM`%b=2;94~RxXZ{-U4 zH~kU*TRTh8!PMW*%!NsH_Cl`Hj}Py(Dm|5NH*3&t0>r;FD^L&>4~e78!G4ZjZ@ePUa+Wx=Otd>V(D8U9v3bbJIg~_YY$UbTLavpoi*?DXcwlv6|EPaiDNEXLDgxA*~eU0Lw4}0JA(YaZj z7fe1ceOm#MOdq~3X_20lJ=Y*6?HV2Eqr9n$Uf&S4%faFqnLZ1f@A=z4*Y_IHuZ!Yn z+voWH${Z3 zV(aCpcZNCRjOql$sMY2yI1cORsmmugej#G?fxC0jMU1FTo;HIXjsrFs`a)z1^2bHY zjg`SR^5g~FJ?2O7b+1>bA#JRvwGmT$hDS`z;M|bGHdb|iTdi-PTx?F{Y=?u{p*9C$ zjhV~>hc9!u)#1=L$FwWp$MT`?w6eMde(ad;bhypo?>j75OiP_GJsid`;qM z;mUdwh`FA>jF>*- zHxZAM&rOfx(kC&;2d1q+uXnDBd|0_1?eKVqr#Kw!mzldTw{_Ugzq7H0i=mEcq&#LW z?A;97`AJa}sn5oTzI)S8S3a}s)r-2_(ePs9bNLIhAIv?NeJoe;{D_TuFKdz<&$Uz$ zwIvC06SC8CbycH#RLt))H?yEAlg2FWJx5=Cek}LGi(@8~PphaaA6;?g+CNOFn%3hd ze`5Aa{bedh^2$5v@}tY{ziG?Lr?u*(`n)_NrD9n8!`C&Pw?VUNO zXW#C*p8NFtOJ54PvvXgyI;<@+0n@z7lQUQ4&svoqAxtx|@I>Jj7ZxlMX*0LB=P)01VUz1@UW)@5Jty$?nAhqN z=Bb$13SZXJ{8gWT^%_vkUong2=db#zFgng(Aydx$7%?5@uc|eFrRPjLoWB~E&ab@b z^G-I$^S82fKB?dt4W7b{rO`78DRZ}R+Azt}SH)oB&U=C2MGM|Z!lh6TS;js}dQ zOQj()lmcVstI`E*jSl(U^H&sts31onm&-xif9(PgPVZHzoog8WC=HUh=P~vnJ#pL< zhsLn!8?UexykJq^Ar8ameFt~RM<4cz=_5brhX*~Bdc}X@prhotuwBWGlZ>Si4Eh*@ z8F5^QL5E?&)jfCa{SK8<{s;*o*|8XVdwnydZ)fJO9+d*d;YOy9ifx#QX(>DHZj7TG-MECVT6`yaC{Odq~3X^|f4p6t~8RkhmX;9{zhKF12sjzeJg{8jrtlzMFQSM-IQ&0o#5`KuH# ze--Yu)U|eVR;mXOI&JMncB$bm|&Z~ zI?Bn6jWQe#Y%=FY8PYXJOdo}nKz_(C_|2T-Qq}*Pn9FJ;pK5>5`ErKmIsA5*%i@~Z zTuMKO3l0x*xZdHB4v%;E6o*fD_$-H+>$Brhmkcj*c(KDDcKBL{w>JkB>Ir`$&e7&T z{5dXl{ErGV-vX_W1FKss&K;q{=8l->yE)3x7H*Fiqx1_A)1K~*c(nX`Bc3RKbHtR* z!x7WA9*ekH{?ifDrk{ufV$Qm07Gmuv`Lc@18+tO2jG>|d2AS6RUTMe`-hk!XRC{^jNW1Ft&A zW?(<7vHef4g|V`#gDA~ifco1@E*ngbOy;$ovaCg7$?0e2XNM&Q>^ewUe(^wO-{UHN zb?Xf_@wT%hqPVajY(R-d^IL7C@9L@kWjjhrCBapB6BlgkVDrU}zF+WWe6Y;wZdX2S zhRPhf(AZ8(sfdGWOfn zGqO0wOW^t#K@Y-5f{cJTW_a;U?oM?`0~IzhIqqrX!{`yojk17zi|UzAud!5X)I6X3@5+7Vh{=e2e7b@FyfReW{kxzvpjjQ}|f&>vKZbp8;WiWe6)1 zj<)?ySjT7P%;cA-(`V?Vz34%^t#9U<+c&%@Tf^9ehPhv4XapkKgYkzte3--Gc}>jX zv5wDe(b7(Gc&fvp{>8Mj9sdG{DINE%u1n`G+I_F@r!q-vS^K)Q`(D4WP(Z7W&V}>q7A|U<@&3A&1@jlpnz3m90x>U{yKrvvTC+ZRDm@tOYHz#<5Aqd)S4u%-_*M-8K#2q-%-?Oo5y zc6f@XWk>gVVOU{u6U&69YwF7WSB$DF8_m9%H28@lMpv1}(OF|JzgMec;&G;~T>tRs zo^?IXUYW)^sfX)&j*dBy<|l?#m2WzTt20J+RL>J9$*b#mV$=9ZXRmCVSv|gKW0Ex9 z_fOksc?s<)cT|(~3}m6r_(?TM^7vELg+r?!f3i^5V{{KY{?wJr?+vjHqpN=?1LxsY zwVAV5mU30qf6c(!%=k%F{R<5-}iR8^8pX!>hAb4@@?-QWhF> zpV(BJdFZ(6vnMIXQ=1AS3JpK*P!P-StQ?)qcWJ9si7cL1QTDbe&N@Jx~jIL z3okX%=j-BGDI8tBQKfM2s?xRSe?{-9q4*A~-m0i4R&5%iMfHbQ*Y;LL(6Q6>b}*Ia z6Sci9G`Xf*{{Fa-Qui7ys zg=aq8Gn`?Xz2y(91ZtH1()m69o|yGw+;!>fGx`RHKPn zz^bqG0HZR0%v!x0omDGI*-GK!V;gudTWV{gv({dUqSLa+W6zBV8CF%_s0%(xv5ohx zDxdJ@PyuT6Sot{W>)Av!JiKbthyR?d>08%pblJT%eIBmq{X|XmD=+rhII)wxl(n>} zNPT5yr0d8g22VRFdn>9n!-BHw%EJ2e=C zC83I@Vz9f+vWn)S@F;?M@lq-~gOHZ2r6E3OsBaZ5Ofn~joc=`N$}4o}%XMc8Msa3Z z1)2VpB6Mz^6DAW`0C_MDYqbn)Z9*{X@vauXDf29kdqQ95V6VS@Pz} zrTI(ou|em1kC#_P)oK5ZlbWD@3f>s$(Y95*adIJ_`GeMif1O6XCU4)O`qpDO)R{s3 zw6o>Cn8H`(aUzxpu(n{LTSqBUjZh{z18=1CWRr`6k4`NI#Otj@u<@z&x#Xe^#nH>b zN=K{K1;axom#n;NsT01dC_I9Lq{4Vn_--$JcTt!*poUZ!FACq|h3_c}kC((LsW2YG z*<@vd$lj*DSlUGSoN>|9E?(&5!{7dCB$(f&)_wOnEp*%&y%yBgCeM4HD@w zSe;6#7@XHJ#eAlFuG{C6kKA(>;ce&fd~#_%_wOv9%3PGUvo5ZR<=k|L zn0HBqoaj=O$F;QWB>y3mOv^Y(9+FDdh9i{HX8e^2+S+kc2prK}y}&8cYFo-rhl%Br z){f?GLtVM*OmlmL`jVD+`p)-#*tyK>D)V{8$CW&~D?P|-$8P@!c30;cyI3h(Iwm3q3`rQ;A;XR9oQS_CELGvS+{8@gNyq1g z1|KO(!vI|;75Lu5q$jRQ zE6_;m1}DWd@&dgeeUB&-eOO$k zuUXjAAo!>X@*{vq7I(42hKZV`Oii+rcX2Jk{ygqGNQSxc$Z@$|cHFC68o}htvSA8< zNOr7Ng}uJjvY`iwhdyj<)5p>xOCy;4MEd?r1C3;Hs}=V8?v_5xG4%1=-1OZlOd5N> z|KlF|R-P$|aRfJXko%k-#19nD2pQa0<+zSUn-smtNn^eyG954l$CAPDNI#6r!5$nJ`0=g`P;5j@Hr&Es(_AmeH}t~ml}Q4aR!=FAjaI7=^H(^~*$U6lH9SQ_rR zwuZVO-G&D_TgAZNfkJ=WFU7Q%OvLn|Cg0%rUH#2oiM5p&#ePUdXKpYHff=5bucuKUQLlVkDD z8ZdeWMa(%K;be|-G7V1VBquY$$(-(FraPHt$DiZmS4KQQ$Gyj4CY;DK<7CFxmggTt zOrC!nF?s&4hy}ysC~2`lC~Hgmv`hOdm-g2#Epv{f#n#wYx=4$Uv%M6xkzbGxHvY)S zA0!`a{D#O!7Hs@eB7cZ{uXEbGethw^#4BcDKoI?&(fx(pLWdtKlGocc(Cd36J@9~ zL!wNhWWc6}$1do>o;@kb%#;k+WTr$J`j!PzhHC{jnGZ+)Jn_Mn|LY>3>j^gb&%oDl zv6t6IO#ksYu+C+XtK9!Iyq)=PeP_SN*r+Gh@%OT9p=T zI&(?`|4Q+}rc)DsK_`7!uPAekWWZMD?}{?CwUJR~xn#hm=cp)yy?<(ySs@v)$xMkd z^lzL4=K@{?R^C=i9&CAD68SfX4>mnl!k1&-;GkOY%B+(N*!15L z`LqeJ>0b|Dj=2cd0HgnQ$$(A&*Wk;c|Gp@*UNT_Qzd7e&bQF^wZA3 zrvEAUa_E0H%G@m(u<3s}@@bb~)Bgwfa`eeLIrO(l25kDf!;dn3qs)Dh0h^w^q73sb z!=lXnk^!5{VNr&8nDG%a4|8tB;rfD=hs{d6NZ9(-*2sTIe6aDajr>Q%2iy6sj{Gg+ zgH3*2#7m9Z)4ShqltqZU^uMRkNk0tf3m}q9X{LPMu%rP zOh0J)Kj`q44qxjq{esDV1{}|2t+1WT7vWdxPqb0aFk?c)k2(CT!>>8Khx$O1-^<~_ z4j<<5aSopZj(Iy(n7myf-KWEkW%ynvf4<{OtavVYhe>AV*vny=(nUV@xyc;t@IN@r zH8q)|93JEFaSos2@I;5ta`;?_n;o9*@B)V~ahP(k{9NtuCmm)!$7I$ye2c@Mclh5O z{<_28ba<1)j6F>MPaOU)hqpTXbBAAc_!Wo$>~K!k*Ys1b46_i+Fm{LG{T)8Y;X@pz z?wLIA(>C1TFyk2GpX~5y4xj5Vc8$ri{KGI~8^f15{6UAWa`+<-uW)#^!)qK~=P>I` z>{wrNm<2M%Z*%y&4nOEH;~SHI!r^Bee$L_FI{bTwS=nNG7~2@`@9^FZAL#I4hglM1 zX^(dJSch34Vlt;We7eIk96sOS3msnI@MR8v(BUf`zQ*C}9A4${jSl~d!z|~qJm2B) z-45U5@V6ZPj>9YiGClw0Fsp!!|B}PMcbIp*noODQzlQbp?jo*sxSzw=%O-z-!v{Oe zIL2f~IDELn?{Rpn!{zD+Y#&lJSb2r|$(c@UH{*X)xKEVfeh21uc74Qq$Y;z7pSjqZ zBi>j3?GX=@|AmML$!Cm+{K4|S7BO>vZ4uYYr$0nygnY(Z;G^X~9PxPhjGy37k^f}G zjq-mP@k05(iTDcne~9=t`Q>U;q{RlTju=~#eh)sn2SrT3J2c||5oR6+nXSTOBc=~# z(Hs2#73SUweo1&*#Mpy#BF64p7%|(6FOQgSakNHEe|dGpljX0B7@Lp&3jJrwzb)c( z{*C;XBYs6bwiw67FOv_(=Bkc( zU-|Su@Q26^ig>vEVG)m%e|W_7J!2xq<{BUIS@N;D(1VS|ToZVnTw}!8P4ABw8)rep z*dz2U$YXcVw}5F|^e1525b43pKiw2DN0s;mr}R z5q>ygmPc)gnE8aCMa&%1QxQKV{L6@$LwX@%=8AqB@o$CcXUH=)5%gB=?{DN-IxaL% z&hTP~!#Fw0&{voY{exlp1jF znD%CPqQkT$IBKks0lY=rtkx!t{13GTW5rnmZTA)R*>(sjK=Q()*9Oxf{zRUG=WZHjc{F z4xgrX&icHhil$|W8_~4qz@~m<*JYa5B@<_^8e7wEa?PI2O_*Z3coVYqr+1R?IvBu^Q%YqnAYPXy&HcQW!H>tuBoa?uS*ZRE;Wzk(z-Y;w!;25?^i7Uswnkb_QBlM zEz0|M0skNqU)l6FW28zqaO~(FNC?^dFc>ugg!SB`G*$o9nWsPZT*X zif~aDZ(Vc54VLz7ORKgv=ZF0dHvV+us}0fX(wC*#8sD3DH>W*yb5r#K>pz=osu$Gs z=8Sn|b1FL~^b0BeSeD-WpOtcSkMx>FebSCb`odk&M^By>(WYu@at)1RxSoCaYMN$X z)0RK2WWfLFjS`Z`r^>A+>#UnXJ18HmjX(#C?)Hgwt#y_3`}fxD|8UKIPt@%DQq4X$ z_U>Xo&=1P>jF@p?&(=&{IQ_U95ARwtYzShkl2=IonP%b4vx27tMv{;i%2tLwJEi?V zSY)OBK+MbPyX@ama_t8?5wEiB-NCE)4srQBW}h|y{Y)M!g7k{%gMiH1Wj}ch|JAwE zm7=UdSo?mMT7}4g-w(u;98}(n6rno_X%|l#I!Zdy{XoR!G|-IufkJTQiluQsP#U~p zY1|K#2G=Q8nobIOb1QFOS{e2O5&0=;sto&q2>pOi+z&)ff2VM_M+JUdmhNdu;(nk# z!wCGZvL9%GvZ!r9?t|;yY8tYKJLF0!l(8c9 z7AjAstjeFUDr|AvM|rSqJ>aaWb$RmMRe8N?o6iceOUKR-{3+$f;y)epW?^!c=0qi+ zZ9UzAaatObuc1{mNTO;(IZtC5~kjjaIa!Sj*EAf$QXg=CfDjc~uavQnm2= zgwbSSOLwCH)9K~OIji#LuFB6W%B5kGv-DNuT>9I`(wx(?u3w8kRp+HWSR0mdEjXnR zuybS2Q0c7dL(zXy#|=Vuz%<^z$>ej3|HL|WTfq}?*wO_Fl>uZX*J(l^ET6X!!gLlzme+pvq}AWcE) zxcikj^DS40)r^_z1S`s+at8S{YVu>y}gTi zwfn{LsDq*HT_uioio!4$XdIzJue6=Z~1OBQz+?uBMR@)C+j5* z>2@DIO*fXbT*j3cHb1%F01nc7Z=RJ^%EI z1dbq*juZBY@fQDLsa2<`948b@rrVw+86BitJIExXBaYX<)gS6ubGI`Be}MkGb?X)| zdD|P@O*=4(JCMRQBTcO&@go79ZAIGt4y1AE{-s^r=<}DoM6lhCqtd3Jc5K@dl%CG6 z=I?KCBhp*314)%HCHV$n*bbzEnDpNG6Xg$-YZ0!9INfH-jZZgt@%N7WPY9nA@w39Z zD}=O+piIwLDdwJlPR0yJMcgXPQ*`*(3M)y_&n>wz@}CuMj`-AY2T5fn3UkL9C^t`- z89?wlVao%<4C6D?YTMwN)R$&c6T9TcWwB)cSlhOP(h9w8VfC*bA}O#D-P`=XPEFJRnry~D=h|b;;Q6$ z-q%i_0#@>hD(dLCH|i-}rt|dB5q+x2MSawC^udF2;qs-Jf8rooA5mS&jgyR}5lr}I z`O$z#c8df7BT#JjQdAfC1P+~u9qG6Dq%|_n5w>zRyp)3I?%ghO8(d# z0EpWVeUp2(Pug>YL@^GzugY;9je2T&Wt0Wvo9YJ~Ci-~E`6_5~n-u5IV~8p)`Q|+6 z5s4!lo_onRI#v33Zfa!uek6w1H%j`DLmv|}rVoqS6>D;Z4z^W1Bh!cP4wKv`McfH# z*XTeWE|P~H!20%88;H&<`4J0ITglh|ZHUnMQDwnF)?EbDYdPC)46&7CHW6hnG0q3Xb`|(($ix zc)62V;rOc^{|3ij1CIGz=lHicd^!Qq!3eg&*P4Elqd>EszY>$jPPVPwtv>T1P* zAmY4mYs7-d@`(Eh+x~?C!i>I2TPgf}#0rMBEAaOfK2*mr8P=bGkzoxAxFCE?#Djz{ za`KCu{N+xbbta@mo^@+>F5JVwj6NByBg1)}9kN5IeDIwkpEicts>$f z!c!doEXQXek#omF2-b$uavfWu4CQcf#FWDaA}$DjC}PTi`EQO3T@$g2HMtfn{aB3D z6=cxQ1f!Mn4H1+4Um`9D-xM+Wnfx{Ve6t*k{x5)~A8T-+!tm?mgKb~H(UCt=KG^uD zM*b-IVBKIQ?(7#ABVAE3vUyd1yBO_+!;#{!g7fT*&@)txIW-Bg@xK;iwV976$ zJlN##kNj5g!FFChiu^0Z2b=uQ;ma`t@=V0^qYOIHe~lp65kPO()Wm=SBCTLNVxl1x&)BmB!zgv8;>0bd~`mr}Z z6J_WFz^4D-q73@)i!yDJ0h|8sNB(`{gH8YA@TH#_tN)8K_bUiC{eO%y=`X85mu=VG^jQpp>2OIxSk^i*# zU@MV{}vxxNwCIIJm{z*lohMnsJL%OU>O_Pd==o|$$Q zT_|UGp~D|?_*#eQLrwlO;8<2`g{|Da2)|N)qK$HfSxaX4F^321o@D&P9PVoW8f}3^ zC6=G}y0qszzQl@oqaIj3s~x637{B1~AcyN69_jE{hmUu7io;VKp6&4a9A5135{IvG zc)7zjIK0N;J01SA!}mJ8$>E0`{)xj+IQ$ETUvl`j4rf*7R)(y7G~CDG{tgdx_+W=w z z<6rDBcCqo7Im}`!y? z8ix;Zm@%Zu_`O%}cKl-;X5EL$Grly;Jb>Y|94=Rz%J3(mkFq}2_fbn7AA5@ZAQ1gC zn5SUZN6gd>{R8}c<=-6fK>4>vTr2+z5f7DrSH$#rUyGPNuPx%EA!7PP`WEyok^hH?IY0Ut_?#b0L%}x+_lx+O z!UshBs4#sCGT3_c5o4Fp&%npN8y7M57kvwS+WHw0V~4R96+U(r`>DX#Q;Q=0o%|0) z{HpwGBL0(n^dis1y6xMdO>+$R1LRnD2i`~S?ucoxEWCt|UH1Km=L^%Hz{lo#BH}BA z*~bN+g|_zAa+xwL2p2 zDa?LP@`KItt%$KNz85jJz>gzl%>QV_%y0c~#Eiq)?};Afv0jas@phtP!~bXD?h!NI z?h`TdQUfApyuE+Kyuuy(l(hYY*@p&Z0bG5=%n7iU6F&1sM@P*3(AbEX?>RnV><(!6 zUa&Z~ta5`YRp*QSr^ECG#vkJFD2M42OlG3Pf5~338=M}V>6-ox4&UQ2V+oUCKF9Fm z4$~hQ{}qSxDg)!w#trZ5aIM4aQ(L?%`_y)SzgMN5P~w^>ntwsdyjhD29hRW&{(kT7 zZ~AEk(VT^g7A$INPKNIOesAcOX)%F@>)$X8#+VBLkt}YA!n$=A=_%ds+7#+32On1@ zH(Jip2qw459Sn$MaT66bOcdkS0f0yrce29%xVyjKo7yBD*M4l#^@vkSp#-h`tUS&4 z{B75M_*jNlx;Z)8{r%pssZDF3(?Y>^GCbYk*$!Xeur5(?&XarnqTToUFb|y8GT+Me zJ`0sqHoT2LlX>m`vv)3VUKMr!KflY~U|Dtn@rLzVM8O1HE+U%ff{37~$ej{lxe2)f za#1udE19BFLi!{YPl}b9S(%zqS*<>%R$8b$X{Gk{(j#D6)b(K z=h=Dv&TroHo$q|loH@6dbLPy{=z9q{iZA@y@Ad8T_l_7dY(NJc5&f5*d1|<`+a13B zUe7(;JG-j4-|N$7JXSXGg3>;JuL`97UY{NnJSVk#`U#Hzp?m$D1*gBQ`FjT(+|W?K z?Rfl|^|fK=g?f9E*!VLohqETFf*EHaUad9{rO#nQsbE-U)x{4AFtxx@D zvzlAh;_BMQy_UVOd!pG*t5b0>9ofcR*suQ0lgo5*wZpWUw#ExD6f}H`%@N#vWnayA z8uQWp=KXa)*wn9(rkLEbOhL=Ve)W@k=4F^C{o0PzH<#wdojiWu`tVx0@K~*2Xx%1F zeH$|zwzIe)qdu9GOqi+lUHa5jcN>-+6N~1?Cq^Yn*uc0hQ|#WQbI^Cp4S8Lx;~l4BWh>

    |ky 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 literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/lib/liblwip.a b/Distrib/ESPressif/RTOS/1.5.0/lib/liblwip.a new file mode 100644 index 0000000000000000000000000000000000000000..db26bb85cd750d05e31a33af7ee20df700a57ae7 GIT binary patch literal 516372 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

    bu{)MGsUCF71wB_kn%klJQU01e~Ue2H7)e zra9GbM6S7CF~b3;<`<`{s@k48A6qb7y>E9(*ORSwW`jMn#?C6UhlTCou6@qlk*$@! zhDxiZ(qC2?2v^48=(+H}-f>etzQ0x9T)R)K^EM1|pE!(9wefwew^amBSX(t31GwiI zD)m|RZX%2^%b8U8QXN&eAWc40KZz5@_^JA5`h_hkB#E|#nnC+27zT(BL=r0nF&km> zx58w?xG;~yT&*!*hO#bDo`Ch2@_Z>xoBV9x1lYXRr7(zmVz!6mk2ms9X~@3Cr^)G*@ZMoVR+^(&eIj=WWSE?1ldI_GzLMq$T|v2r)bi-yj(J(XHA}*g`Kr!8UQg7JYXBoBHyhk8;#!j$v3-C5-`n zjVRyu5@-^AwBZ${HYOUF?5+%k;l22rVOULlZAj;9z!MUE;_lB5s2u6>`TP6gW==7D zW)9HJQ1=kW0%kZFFB&!}{LUnZ@QvybSAG}7xJzT)6)|q#lEy_hENocXT05T~;j!y! z^ia*Es!JA3Q};dTixsjf8nMUx{F@rv~X^Q-W<9Y*?^ z_iN02JFPMO7(d#%Fy|SVDJJVj#%p=cnbIwj4gp9Q{7W+U$R1PS|f9o%(PF(&oPFz0q)PDcTQEo7P(EEp8 znp}M_&G%uMf6r`RC>!&{*rg?*#y9W2g7|Cdy-k?r)z57m;$mZzIcj5+ulW zA7VR~%g`6Ge#@T7+_H=V2PSkM&M2^_%s*Hk=WRWcbug~D6f@%1tCX4PpL-+~hc)9o z)R*bTF}+7pu-S<95?$!a%sp;bU_X?S!n%_qt^G>v!DQS)?aQ=31qXZ<*x@Jkd3$Ef zbq5#U7s@W2*A|{-*UU;OtXff6yrO1SYIs&!@l}eQUNbAhV~1xAshNcXfx~6^AU#my z_hUA{YP_?mv8w9Cq#wn7V|+O(0ZzU>fz6~azaK6OtUB(_N^(1V?ySM?tmJSY}e>bE=sMJefLT53?Sk4+pF)We_m&6;~Sq*g7+J) zg_j#+EpApf(?UcRrywe74?P^UsEMn*LGaB(MW>SMS?-+jQ;$7dL6FZ8({RR8p&`6n2&hxG@@6)Oqvk1`}azXj9n zB7ykK781Wlz>vJ5-vaaz_#sk-&0_i`c^?7<*1Kc1<^;h zd%?cn_o=!bmHGSo z#_Y)VP(bzOO*cmiJrqzeG~KDa@<8IvmhoPdCJE8jl2_4xEP*DvFBS)Ey7Baj65Z8N zm*>y=AVhzT#f0cyCJxwie;J0YCtJ-RO87?DLiA_(6`~v8d)2BPMvTU;-|x>BaZ8f< z3vXJ!VzD<>ZT8z0Ha6OFkx`&t?)z8m%ijW@&oUm7!w7J7}3dhcDxsP#G=#IeCnK|F?%2Ryp{<9 zxr*A42F8hBbIsl zbYKbp548+=#J$3g_>k0np+`u1hw5HhhPM>H%6H9I>8~-{S&^wQ@N5Iu8Mv8P-*=^f z*BY2D&_rV(dA7Av7Zn#5I*QIdjx1!v@myv8vs9j^YK(Gx>R)hI$Ktpn^_j=(haB~P z9I%5^?zH0$)(@?zPid&P{q@6k*JpXFjSle3xryEG??Vr&QNLT*BvDM0d zNN@k44S`JMpEb5#`48*ue@;VSxbi=D>@wv)qPPFZhCsIRA2oKh@;|S)e@;WdQU31O zP0D|?=?|Z=+iL>nHw1Fa0%P1j9zJNw$@S?-Yncn+n+ORcTU#9oS{c@GLPpB3GS+sy*qt> z6JZ?t!hi1fV~XM3U7Tb%_0-Y8hil@>KMyTs*>Tl>jMV=TJMK<-_++-XCJj>q!IW?s zUSzDD6wYuv*5v&#G-mYBF>e-?v#s&DPuzCFcso4lX@B_zeE*T^%{nBgj*W8vJHwxF zK4f!#6T!u-i^c8`ke~y&?II=kLU8L*v zX;Z#u{YpamWh?e0fOBD!|DwS^0L-SC{NYfLsWG<&BJo-h!^C^hrXG4p-4Rhe z?)sY*nTUlP=Cp`8V=__Cx7T8?U>vJ@L#(>CMT@apm3u5&u-F(g^gt~fw>Qo3hlXi zD)OaZ3`B1B0OeW+D0klg<=AH&Nci@iMNZdC-@j@(R(w)yx`^D%@MEPpo7`_96B|Bh zxZo9SFb^4+{Cqt3AHjvJpo6s^`?7r3V(P0yEtWb3J8=em zvt#rJVis z((o-2fhN%>?*8n)b8L)x5A|IO$~*T^K+QCoZicXj{_%5y(&~Em=)0CyJ&vOR==(k$ z;{}5Ps(aDH2&fWZy3g%Z1|;1@f^IX$bo2QjL^r$MLUi-FAVhbyIAGIV8{=LC_XHTe z0}rBPvNI?|`8&h`o9?g1xVON~GRSZR(c*lsmpfhUtJLEkjP66kj!uxVlQ~FZ8ZkN# zII*@B^M#FSU#jJe&5iThYL_ov(K^3TZIRWue7W+GiOJ=SD;6wOoSsQWrByAVHG4l? zOyKRXytp|Em8hD$^hA60Cp=b6C&FX)?m38{+3{igEh8g|nU-r|GLi1|e+o8nI_e_p zJTa-u;Is6}{1V#~%8*Aa^GmZepB-}6Hd&|oWz8p#I9V6fdo-V&|9dsQANEF#85X*E zFUmY%@EHe7&oA+rsKO5(vCKO?q4^vvFbOO+f}o#iK6%74zqHSgr>Lw)$gG$(sKY&8JS4?|9CUcEeDfJYp&5`!t{OstlY52Ixf?%9BT&tog5L zJ_mpfjFg8rG@m?TDG#~8Qufq7KF~=Xv7~2+GP>-I1E2RLk66lHK4o;HJyFY$M=bX$ zG-Ox~sE0gak%2Qh|H*z6*F}?v8778}By*%nh6M@qsWS1OF2lU!zGEcf{_e$cY$41f z%2+yVDj#(i9P;(ORJs|DS_w1Dt6+64;zeTIgwJ#lJjK8j2A*x;Is-Qo>u|0#@LB_J zH1IY9?=bLA19uv@%fKvea<8`xe9XY74cuoB0v%2VX&~vDZ(y|tflg<(FP2W{Dg$3< zV6_K-uyD|$>?V*d)?7ZXEgS-R3u-NB?NGE#eIYatC%t@t#`aYT8CS$JGpEAZB+!S=( z?8FVhydR!xk1U*e=VZ%UgI{cU3z*#N5^(~ew@f{#mZu${+y@~qUO{=M;b$~u&WQ1(gt?akp(eBL(eRQ!gN zQz;GOMsIlK8mk~R+?7<;;pM-hDI~>~nyn3JMJBZ^0iwaWsHNAN* zC~g%c#)~AjT6=gj5Dv!kT>zJ~9rk}5_u-xXgvq|WLCnLeLrn1!pa#p%aDF1z52`aF zulHA!W+6)aiK4X@ADT|LNOY+nQU0mkWbYKXP7)ob;C``asJ)N-oNb# z6~udAXOtuV-1wBH;9%P=o0I6yNGY3P;{}U)F%bJA0PzrFUh!EYgu3-^=}~_ufDuw_bTTVZ)b;Q#XvS zIB(LH+JZD36u> z+*r$t<)%STA(q?UU43d-@*Yz7gtqH~%v}HBT}{ zDlQ8pNo;nENaC-b^{RtUzQaFIwr53ck*9tubU}jB=U?4@1=GUvlc9C=Spi1IpiFqnqK#W1)`;X2q%EAm&ukVHRihMzXmg!|OH9LS85Z`_h^e2l#Cl8<)k%5kq&*IX zau>r$o=Tqce%HgW-$*@mFcRjaz$D6$92n}P&2mMZW?YDwf7H_oLw{b&vcxnc|8W@d zh%xl1sUx$E0FqC13U-FI%yF?}(fD@mT$pMzPdF&jMsF%chSx`os zVe`Yxh9OagxCn-N?t)?YA^sMOqw&vRbHbney)e9vnBgbUO`HHj{wpvf@`+h)$$tli zL_TRCVatLXue}k5<(POQ49fxW6EKW2bv_9r;pCv2L_TpM4CQyhkjN*_gdzVoFeLJc zDes4Q14eZIUh^pP4vfU>BVZEwB-&QUvsuQdhxtRBeoW&67~Z!Wh9uV#_c=k1Oi&;G zK;DjG(4trf~_q-~lZ}ZZnH{q1H8!!jil8YCBZMj7; z5{s5_x0UGYQgxTMrN$w2e0p$i{iUsKo}T3~;=D%_K8{j1iSfgi`>nC+^|^4pZh7NU zM1g^fxgO^g+}zlohdSl0-=pPJczHaWd9a#d_DL$^4e1#ZD@Mjkt{5f`p+&%Bm@!Ef z;~SG`F}^z4Vz@ftVz@@q#rT+s7vrUpPaPuH+^puOTal~Uz5LeYZH(a&gYuC@}4Kg1|Yzo*6ktTRn^k2FTd`t{Pu5y5KO9m*ndVq3U1}MkoZXogK z8lYVF0Od{$P|il+1`@vW2PpR>+RsnZM?caet&fj-QfxU8xv2nbcF!hvnbv2PE9nwa zzm%&o$O$I@Gz#Qt*yCZ+Vd%$hikh2(E&57u-4$>PiHl3e`xTsDXu&ImG1vv==-RWa`${(MR^ke${Hb&nH=<7Bv6n%$c^mRZV<(R*W zo9N@P1w}YYb8wTlajlT(qiwK#Yte^p$AxUqb782D?P~0LjX1Qse*s@e^ohGayT84+ zOu2w+A$vFh)xw!>wopA3P%VtNy{?ZsXpCv++uMr1qx;cFzME8v_wAmL3qCB?2W~wwR z_i(k=0Z-Ee0~Eq>kz67+}XY#z~=Sym3x%>zQzF_jtUe+`FtK&i27cH zVX5wd38K9IR=a5j5&J*E=KU^FZZrm1@4`LRYU`KaG&g=F=Y2YNrqASRm$tMS=hW5K zE?&A|`J(Z@rORtu>z6E8y4Z)YtDGd)a&r|%n)-A&HTqCPE^k!FahCEg=ZfCg1NTawtqbN^B&$v^$IbKp}Y#D{Y(gnvsx^T?~^PojzPC?$T zF)WpS7M^RQi(x3wG$oe3{>wD~L)f!4W?A5~kn+^Yye4LzFpn){2k99Y^2sAk)_mr# zm4`pjJ1~?Xk2qQLGl8uT{y@iIC_^4`vgWfN$angTKBqm1S?;lKd*zVT~ukR$(w23HgqaLE#!t-fM`)uvGg&KJ~Ls5>p4|EHnJNDWe?E zY$Lfa#0y|oYRv1HWaQVuzEESis=}9bUa-HT=eu2ge?;?#Ek7kWIZGE@K zhhTrpzz=KuIP7OMJ^=e)49qmObotq<`Q#Bx`C(cxUOQp`QDcVfsKyr423X?7z9Qwx zBbInYG@sY9oXLIp;*Ij;5zBptXg=lnT(m;?1C7>v@`$BvRApd-5>bCrKKZ=l8BwIm zVTdVPt?@qC`!!}7{+oeSd4oK4sCo^|G@PbosIOdO@~_pH>Bln4do6@rZ{S9aDU$>v z>8A1&^5hXqy0rmQ&t0%>7+J$}o92^8EOlg!=Dz}ay~aO-eXqtWBbyDZ$^g=l^bid1 zMIJHNXfa<@{$2n8+5tlu@`&X*qVjYs7@#L%C_^5xJV*9v{%qJPF1!(lah7)JQ}Z!d ziF^479L-1I-@>Z{hUe~3-{TrT5BtX&?}E*=pbYsm#0-ln=fJN6zp43ugssW|_?G~y zG64Jzuqp$<(K4Xc0{8d;{O0F=dzpQU;c2K6%7a25#1T%CFLx?UTxD z=-)^l4C^B4t1!GTdBl>B_iKI!?C)sIG`e0pe`8l$s?BM7t@`5 z<|#??k$I5Ggr!Xbd@<~7jhU`&I>{&goPn9I5|^;%lSeFZp)Ov_eh^9IRax?TJe9Tq z539IP3CMwwb!#DFJ`6#HFczM1B!V;-@NFa0DuWC>Pb z(0P<=@YQ`ae~Q6Z_tJc(ue6zU25vU+N&~MY)^Xox;B5xpVc?wx?j+V})n(w<4Ez>x zJpMq(U<98wuv&|#W!Rq;8OOl+2If4R$f&i5I$zXUM2*#auf}REqQ-5!R^xU9bN*KH zbgO~YT11`KoGTTX=M22pz%LuPn^>2P_Y8c}z?>@-8Lq__tmYr}wdy=1jVDlM5K|N7 z&A@6tQ1jJ!NE$CNWLgZo%E13m&qLC6M4gAEu{sY)V|5;q#_BvIji;c@O8u%Z@N5Iu z8MxWND-FEXz#9#`jTr3}X@`M#8o1NIT?T&5!0J3Ctw)`Qq_H{=Nn>>$lExf=$bB6H ztMibwj5-fV4{qY~iVWFn~`hbm9!Fy2c!z1HE zBQMXus^=&cr9h_ z^`|%d!1DkXto92tj-4z$cHB93>;yJOxwdxSFFTzN;Bi5h*hx>VI^OAG^P3ZUx4*Wj z*J5gr>x;+V9jj*z+?qa%%kLIoDVX^_KO%7v_0Z zG}Kjp>g?`5fw1Q+%t&m=bUUnL$2+3|J$B3s{)SO=@BL`Q6Hz`Rkeg9bQCd>wAX(d+ zGHzV3Z;u3A>@!4wrFmXFaQ3A^r=Q3C&R9E#u zUEK+&zjiKn1ySp!lk~13)WI^5IH(BMLZ;;_&TU`YG3d4jwhroe@`H|!6OTT&@yQcE zd358(4<3B*%3B^>-}K|(wpV@7-hSfR^`2cduiaaDZR%W@0IhZHC+g}x_-fPoMCfjB zK~UP;;jC-_pswY_S8r*l`=F(T;X>lxcmr1J_X?R;TN$>bK}9d*c%g%2`&Q?x-+gxQ zSHHJo@ROY%Jc+P9*U@=m-%mR_K6v!8E7w2z^`>WkyRq(rjT=wg_;qbBvW_ypjD@j? zwTd@(Z^eB-rthl%N-A>lfMv#L^p}yqJG-hFruGrGi7pM_{`w7d{%Jom3R>h$7aM2!;t#Z zc`o?WISPjDzvyIlhS&1BHACZNu=#8vpJN<$Pl(sS$h|s&N&VgHQt)}NX%qnUC&R7{ zWinwXPyJWJkouD^1)uT^BdI?bwp^4s2c`suILac=>e+3A4%{2TE7v5*vqj2jS7Mx(xawd zrng7sryVQNe<~U4{LYY0pC-{erD7#}r*IQU{1>^40oeMSO-{}H zK+X)`LMqZE`F1Jv38q(W&|5(^2AG3c`f;$kK!;ECZ3FLN7$MP78>6oo`es9j`Zx#{ zed}WMmB8Hze<9JgI!0e7^fg0>`Z$UbeQNdzZV4ZocX?8Q9gX8-G5Ye+%;&_;$lBPeoH7S2mjAd&CIeIflN8G5R=zltV?DL`PAKzL$;gu}zWi&5Y4k2YvGN zq)O3O5u@)U^htT)6It}BnL4;-1pYGgxm2WyX+g6X`pgmdhmb24AuU7a9XfpCH4Zl_ z5eIDQBHac#2`k-|nLb|~Z00Z1N5Z!uM&AKhFs`eJ7Yevp7w z6aDC;UW4shi%Q0sQqF9!cSwEgmBr2wY{3og1z$+QC+`02zAKvaw3ZeQs2bUGWkA&^ z)2&9KQAXb#c~~NQD4^CHm~NJc9{PvOSoEkvn~Fp>=x^U~NKe0N9cN!5cAjxJw&_lc zJ153HI$AE-mIu*7XTfG3v$q{YdXLraS;{?By=|j^sd5ifqYS#|DEB#Pl@Hxa*&xz; z6>PfMl?amCZ|BUI<Ey)rmw4zmYqXNHJ_t2UPGB2*k9C` zBQ~~wTy?V?HtRDnM_?q;&yg1SBx2FewwwHAuz5Z4O4utj=Dp}9e;sU+g)opN!f6;!a&$y-*38B=RmW`6ObIzX+Io-iOx^Ge248iLZxElK8T}B;jORC~xJ4 z6C-^{4veMa8zREbMm~}{VFY&>_%#E+W#D55K5bz2c2etPofDl7F$)Yx zy`9upy`9up^-*>DtGAOHtGAOHtGAOHw^66gqjm$Ux09Ox-+DXA0s?xOIyLS#uzEYG z%b|KZsj+%Hsj+%Hsj+%Hsj+%Hsj>NXl1o92&CZ>(&65{R8u+PM+Yoja!Yv4|M!Jj**7Z#k5Tf_2yBM$Wh5lS!|<_MO88a*oBI9>?pzol@w){KQ(rgq zQI7i99}#`%UPsdyP@Qmi7l9_xM_V`Z$|oBN3c+O0dN2(2rNc0+l4pRvN+j+L1e!#j zxcjsJr<`!_dquHS}8-HF?nM{VwGhmmXuq0v=@sp|<%N=%x5zEm)!zP!l(z#LkzRqi!iH7skNF zXC;X^StkPXT2>$A15<`PVmUdIWn5P4tNtBi$Rn0hEm^*0AbI!hc!eM?G&(D!DUrym!`L1=;k6pB0$T^h3 z{iLkEI9Rc6y5k+J_|m?JK3nnLhP0H{G`lPcbd@Ih(nidJ&iyfi%%<)Z)yF6!6hV>%~^F4Of=8wx!=yD#5RB%HhUq#&8 zTdaz>thk_^u;*x`!n)!@oQzrK=gF8k4@D4=ydk5@r=hhv1rqbwBmY-94zn zDzHlm>#U7*yJ>^QxTPP46UGD!xaroIhAeFNwfWM{e5d;o$68OB1T{ugCw<(d+#LM- zlzWYGJ!Sj*ET+t=#nXbE%>8rY7!l zJFn`ry1j^W*O$)pC!jtTpH~>(7#`vq;a)ub2KU$=v_dmy+68IZ(=Oj+y+YxNO>@gW zTDW@NdF$)jCuXdfkyQAOv%a)p#-Oc92M(5QEN%F2uEgh7mq@Mnd~{Gu#=8b*M)dICv+&vE>72 zN9l;B_0^kaq_@rphG+QQ8F3HIh;R6!53l+=_d6Rx3zNDguF1(N-|5 z%&;Gt!E=P3j!$Wrk#;cNekeY*{ihiX@o5Ks>i8bbc=A!Fy~*lma_TxxJb25aw_v%# zjW=98@q*ERIC8~R`<|Bt7_j&4mPI7)jKQeh?u_Jeb}~Z2b4ttn88!a&us?{(>-vZE zIT#gzswk}qWfde%P3w&JVfV!|Zjl(=)xCZ-a{q42PP#ke?i{Za3|i*xzL&HN*9Of! z5QE;SIR$ZtUV3-esi!8Fmet4m>(i=^wbgaEwH#>k#wNw371i4s##%V!$6lOzdy2Py z1-cUWcyK#T$L=xrnGR6+j3V)QMv^`ZpWP(sm#Sx3$a@y^S;qE1mjWQl5a+wIgA2i35ta(o6M&P{4+?}Nxs7vh}<;;l#@9E)(O&??z;wl zpLSpRk=DZyv%Mh2>Jz#9;Kwp~Ho2{kiM_A1-SATNh4%dhrn_W__w^9xkjy!Z$Kf{h zJp#A18-P)L-!m}zcBZ#Vo%;ApV1C#zoiL`p>kuKS)9{Mw`>BD+e;IX<&jRXWdn)?g z05a z7YAi#z8!}?-Go7^2g|01Y~x9kb3Lg3877+H_~Y|Ui0@O1#Q~c#qzeE9(_IO<5P>G~ z{Yya*g@pNXz_$if0j+g zq7Wv-cRW%8y9%ZWc^E{?z~{OU<*yb8Y`SY>+|4oWJ7U~-$GE>1JO6>~ja%Qg{=CYWF}7E@*73U(t;1 zIOLh$|AF0du(v$rjdO5%-jRFzinKQB9Y|yw$DaKtTkCJpy##gr!p8aq*d^1OkZf5Y zGm=C+_C|~9*~uuk_c=PTT?~EJ53J>lDpozc3`Eg$cxhxA#nWQt2GQc&9%&Q|G1D_g z(+QJ>(ptDInE%DrX42Nz!MD2aSCM^&KU;( zUX2;AhcxE6Y7yipzY;dU^3VtJSUq~`P5 z;V>2-KA<1N@LuE*%gHM#I_^v>p0-CBdB#|L(11p1KAptLnmO{))yNv$Bke&dr)n z9n&>u9PJYqQ+ z=)W|dWs2=8@5@KyDUCT+rki|@r{gu2F|lENNb&`5edB8hARd)oI1& zBjZaRv7}W6W%NU~Rm+e^oUHkkl;H#ih-(e0hdg4bUtIS`KHGt<8n+?6zpXLzpCoG| zZUW{yp}&B?RpTA7AJh10*q>+&%l91QDE~XyQ#GIC_!5md2M`A%@m1|75x{x;aEUDE0QtmczP zEaB!^s6HD5hP(4FHmgk*8D1{8wf`YIB!oQ4$! zCZGAJ(v1%{&?PYBlSeGORslxeeI*eiUr8#Ch%ae4jKvE<4vef@qTAB(P-&>KlGm8g z5E<4t!K@F0D-1l_z;y<0Ht{bN{E)$)VBiu1v)z;RTk{O8)?Vv!*kbV2E(w~y z-r#RBaEE~(H}JCte%`NKHHkDi5Ct0o%6~;xB>3PXB}G;7b_olA$$DeG|Z?o8T)XitqRkMku@FDxpZyYrJhe~tL^ z?i@tN{D>V)IcEEn-bf_k!w-|`Dv;{WJNZk!(!;AgywW@D-|hGPI_LJl$JW?Vd+X*W z{^PoPvLAH24&d!f-n0I73w=}k_7C#5owGZ|+L)jIK)sk-Lwv288Ii^ zbpT)0PAWe4vS$~VO+TyH_(uA{{XY+PeH$@b5z#E(A8N|>FkcT%HNFS zAIaM`BvhLBZGXae-{ol|egpQEk@Dvw?i2r!XQ%A$`b%eLo9%z*I{&%?U;2fej+-;W z9peu9eK;X{fO}`>4;4Fk-yyW;cYlhX)1b{ ze&d%HTMh7-c+>2T!1vl!;~ghA-5KqSP26MQ?XP-~ z=Cgxmda;N1dQ&aD##5gfS6KMic$qWd{(?Zze3^%Mh5RTXC>h@SUcC4{_5SUFvDVRm zowVP&@}-A5BAYwL)!05etsvfh`0~}aF1x$_>)XG->6%jO&&=t0r6ZO)Px9q4{TG$~ zbG7#x_@j^A-G%Nf-?P;fs~488T(-V`>-HU+-bhYvYQLoO=}I3ixIXDJ)=z$Txw1SIm+ zi~(%&x$i&2Ph4%t5c9!6{-r50rS4+!H`6T_`h|8P0Ivt-{3{d8(Npv zFPLA?14ZPkZ|Nu0VsdYB{qmb?Z?13Vd$=BdZ_nYjrAzuUu^Vw8=90Fh^|k%8&+@9V zzhIiL3$=etKurlFsD0TguzlDP+U$o3(&_<5b@(A<>T`nF(GpFJ1DRAUN4=bXH1%~sCI@^W(ZRW7 z!SqW)vz80nf#Ey={iyFE$l(_)r^ldAT0XF&ItpX-0sml^QlOE%pX1c1oG%LF!|IK5`E(C&km@X+2a#XF*n_;89ns(pK!q#^iV*}l9}$_ zq5i-B4wtFgLxJd5lOC_{i5x63JrqEWOAIaoJBakzL;(OF`s3pHtNL8|4nFZ%XK9$_8=ea@ZtZlL78s$|dgMJ(D7}W>@G8 zJ)qj!6$=*K%mWjE^w9~6T6%gIg4wOmSob9i7hkrq|*v-AmO zk5({Koj4bEzQ!CSv5sY;t}yOnG=}B7P-BiVm@kweF435y9i<0+wk=aNpSfIOk9HpptS-_tMmig>oLgouFyq1`w1Y*((jURx` zQ3Cml*Z*Pf?E|YSuJz%w_xVTyJ13t6BtiDseB?wEO-@jPf+mL$g9aNSgxHHE2@s-! zLI{Gb+88uMo3n^+_9BG?Ng zru<@w8(`n6@$b~|y&Aq>!w+ltF%64v)G|KXH9pH0qQcAU}Xzpzl(hGh}Ab(K$n4ffW)wB3|>4J z6b7ND?HjAMiKTwPzHd0eI7{S-sWlxmpIuZmB#h8Jsim4@%p@LCOT z*6>yhKda#`4fkkxzlPr>M)@Hfg;DsVhGTIbil3@sTf=xllS^)bMT%zp3F~4Ik0)XBrmYe`NZwZ>RK&?>~|s)c6xLT&UsC zegBbVPkjH8cq!#27Tb* ztMZTgQ&@cek$my}hYu4-eE*SMG3-2|KHu1+vwg$K3x(uIoU^YRJj_l7;xj>9HHi19 z41pqD_}<R4vK4gab^7%RLmXA0>-R>=46X)M_&&CaL zTa!1f-}oJ~dklug!!IYUeDF|#yKVIi?#q|YaF=`%aT#y$POyT{4(4r0HuCmHY-eq* z(-Ab=Lcwt57H?XQ2NC^2Fr%k7nBC(9C%@QP5T6m#GDJr4JVr4!8pZf%6n!F!=Z%u_ zdka^@)kO4;MFP)6f?}awjyt+OGP;wgO3%}XO$2!yLC3Djy-cL&3^Q;dvM29AVCjm) z%;B-+_VL;+kwxtZOFWjD5&OVLk%vEu@MBZ$!{7#5PDDC=yxwAPl6-HAWl z>|gWX(A_Dm8`f<0w6F)5?lim#C5d&Rw`x01S1-hB!IPP3v4MY!KpRvkC0ja9cXpf< zs)kEd32Pp-qN=>zHdH}Z`pT#(r=!;%mpFb`Y+zSZ&(+`b)V^$66LEV(Iy-vXW6K|p z%iQGKz9+G+XY}SRyUjV9efyJlr@T5UY0g9bO)2}+)_$*R?fBIt7=`r>U5O=m>8(&* zdDY1yhh&su+hb5BhHYxu_+aAJlua8pekblir^`vYU~IS9AC&`G`*F0r%rJC2hv{>yb`|UQoY9`}OPQIE zz7~2Zn3I47efTQ%Ylf{V+WAT(>^-l+J0j#A>3Gv|dHveBa8_H`JF3B(5%Qkj>>WM8 zztzZXweQ;;_68cfcF60rd&dm$f5^yv$bM*B*gLMlJ2vDUzr~w5!2d}j_euMS7aP2B zo!;26cSy)Pv}tA1_La6v#6m8iEo<<`cY3X`*B|mGoWXx?gEy(un;7;chrB6g@L$~E z9oFeh4SUl<-r=A3FEu9JG2Oa8+b(S6x5xB}>#q#|$hbOexeG5}jnAq*tHVDwu6FEa z*0uexr?uzC!0nL&BXi`}@>WHH2GUWiNi8s{iYgm?mb-=hmAvH}{aM#9^XT-ndOWA+VTkZb+>)+ZGxBt<%9`fve_N|eb=_^rPy|?iX zrGc6SkwvLb^;}-yM)@w7xyo3%&Onv-(g|y5_g^B*=0t*59gI1$D>&y!b8yj-aB$@j zvviHKC6bwHwk&m(J{~A1>|Wvu$7DMl0^j6HTRpPb>&tGQWI1zvp{MreBwSzAT;o2} z5j4tJ8cG7L?9R*)scS->w!_`ouIyczBQBeaAG0M3OH{+A(TwM&*cs*9_ioY!7hzE? z3f_C29v?eeISIYF)z=r@muFlibfGQ_jq(LYejR(FN^u_An1S4H3tvoaYtA9tNt-<=_`uuM6XD4sT9C7XB&dg1V zTO3y?!zWhhR%4kr*6JGmJ`EO;56vJ%_yj4581h2_7lIjHA%nJakc>-{InBDBpSk00 zW=qQOkk^MOq$Gq#L9dn4Tij)QN*ToZ6WUn6Y-MF5zp~1*=4LIe;N=F-ZXxdxd8d?zYyG5%Qd$Wx&(%j2`G85dL<^<76cX|1kso#|i(jAIhhPiE4j(duyyU10QTFDkYHPa9!0=sxv^N674h2$=1yYiCR?CMM9q9u}x%(Qe)q4W(8*zE|F1xU| zF}lKhiFu^9D#Mv(SQXAR({h|?ZVM~zy;d^TnH%C42fxH1f#YM%rFyR5@4uvDvZ)u49u56@@K%1 zsE0TWhWz<3B=U(VPn{h3P&&T`j7D0>-v>Kg;zwaqmSG=*VVvoH8fF*_^|O?zux|pZ zuzv$q>3<9uFH9orN!T1IVpudwi534mjZb_&{HbRmFjY~060pkCYk--g!fJu}mo)4RReq~j9_$5`v=M*rB^2C&-8SUwpw}Hn<{#1?6v$GU`5ip5*hy$>x zrxlny;E9Eeh%!fz@|U>)xi8RM*d1h07O2C zw@jV1uYzHiYsiD4Oc{)NPUixXMA&oMt>DtnZ&z^XyyXiQFPz^vZ~3h&8s;w)AH^0f zU#`y{x>Ri|&_DI)Qn`$8-iK1aEy&LYQakyz6c^NA)6zF#Hx0{r*{oK5Z($PB&@)f0eMUk|BE z!{o0=)5ey7EeBgvrZZce-^1woTH#PF8@&4T{Z_-|2hlC!x(Mo{9;J^%U%I{w+>ojP z;nk<_9~vgVDS-EA6bkBN%dYf^?-y{Z^0FUYDpiAl-KQ@B7iAblFJ|(+J*tm2jnc>3 z75{zuGLRUm_F`D2BRELkanxq3;LrH6CRO^T4$`+C&AqD8Al9evib47oXGQ16P#;@- zrLS7*%Vl8DQRrh0s|emA{x<@!cc~~DnNXk{uqj9Sn$#C{q4xthrJFn@cN>7Zck;I) zexwC^ONX8%MLGYQVg5g}FFWz54?z0f>12xPOJ20@hk8a^~%YwchhG1~=P#ONA;Sv##=maRtT@pQ*6^+=efxWYSR}_A}YlC!SzNWNO4x7Di^7(fDU5OXM-YxONu>T-2ukV2z$&8bj z_r-n%`OItPJu!8rQNL`sL|X;S@^+cVpCU2&g%ZzzE$T$bvuspL{&MJCEHTTf$UCY3 zE{*@NCjWDZE!amiz8AU}H>w>ru*E-Yun^I_kh z;Tt99z1%7>XdE%uSzDHt?R58y~oyL6S+%6k7%aEGqC7x5+8R`U|^Uj`tz)^`Q8^CqQ zXIT=XPr%f7rQ~yDh$Bvv;We+4I2Cw}#C$v-kaz>^EfUX$&F~D%YrQHluXR9Tj+&g5 z_+H4x!BD;nCQZW=B&IyqCsT&<^ECc_67PV0L}HH6{6mxBp7IRK5t>2`FVOJgh#zJ6 z?uOSUm)c8Zo8*&6toBk7;?Wu&FEP`2EOe?pDLC3gdGd(W9uSvl@_cur%)PMdB)${&%^F^+;T0MddvhQx zuiGs7HL&lOcnWN>pAKZ!18r17^-w;@w8Hx<=~Kxkk67)!!g*tq=g6f;VheVR#N_)WE`yz-@$)3+ z=w>$bs%wQMpFCo9E$$`AYjJe5L1K<*=4xTTF8SmUtFWw>4I4k8Z%G;Qh=Uvy^2sAsI-i$(K7&7(m?OTEwXnaEeDa7@*h0z#@B?~N$`ndGRPz5_@)@5$ zNz4)1KTFI}+xI25A#+S(j>7(3Vm{Z!(5vpnf}3eb9(H9J>`@cgCEdkQieQYwSUblxRss?DMKEy(o;p5vG@UfMaqyztoB%0BKa(< zD>OV8a>h7@_fsY7MNpNoP&)2=!#qb z)*qs8Lnf%rh{~{i8Vf`DeApLim}QiFj#68|Dot2c$S03jr3v$ce2!lKU1DDIKPAou z=C~4Nh}|#>^UIpTiI7qApxJ(tPo8MY&jSF7eX^(r*GkvIiuPUVAEWU_TQB(+BRuCj zvtQ3Wor&ke&XW8PF90%zNA1Z{hA!fvl3y(O)v%%3Wnip|R3Z7~5vx6MMEdx&J$Gc? zg(kmmZZ)w=Pe<}uhDm()Br%WK-jGCEp`4ROz^HkwHZkst6ogUpN$FO4M4n2WBCNz? zH5rxxCC|K8nD?TvcwS`KYK^~G!>crWkA~N3c(aDLYWP_VcWJms!}~S-u7;0l_@su} zzgO{RA77=Xtzq#sN2W9TeoBVn3VAL&JQAmCOVU7iw6{t%jS#eu$D^py8z&zC**U8fM>u?KG)F z!(wi=vWM0*jxKG!KKd9k;Slo5ODNIXlE zsn+mf4X@JhJsMuC;msP}s^Mof%(h&`r$@v4HT))HQcD-CJnb~c$0=7)$n!=zeo&2+O6R?HQcM=BO3lp!yeR&N>8GO zGc+93@B|GPYMAF$sXDew!wWRLRKs^@xK+dJHQYgrHiEQG!#gzmvWE9*n1gE^cTgA-I%;ikV)*4>78W)>w;;*#+<@uklb^J{o3Z(gr~cTT$=Uf{ zSLHn?TRw}p9^W{7^YY%?lD@h;X5r9HG3j-M)9vXoKGa~vNz-G}XFqqZ*^-AH2Mx>f z_{RC^&Yj*FvE9hurE5KHlhW&23|Cuz?w>mz@~5vHT3qLO@BZ1}^jIFB-_`!=zO}uL z?_KV-&d2dDu6=(`JocMk9zEJ<`JcPhdvZ((8rH7jq@I62^yNsj`+|qGbc}StYJPZmPoI^fAyA9 z*Hw?1zKgg;QpnZzO8RF}-o@VTe?(lTV(M zys>-YKR#YF(R^cf?i)~>ZMOVA(sk0_zI{S<^@Q|q?|Kd1izb@8Ud!cGgJ$;|5zFev zTdL2>NS{6aUbEyyBd(;l#C#hdpChUy z$`Pyd;Rqs$d}7+X9((*Gx`|bM=4pKTGw+RH)Xo5ASUAP%XI^(c41-Y50vPHce{ddw zC1jXis3?TYy|7hSK4sL+u&prc=@WOrkf^@{My3BVz$z?z-i#;ZyI@or?gJ(`Fxu717%yRUdxJ;9QQ^*>@sLdBN z6GpyZ2|vn^#NJ5fHa{u)5o^$vMwbe%+7C#ZZPdp<+k7HT?ST0|eG0fQ(wTjj^8)IAmui^&33ycbPR4IWtPv^468}vYUEg{*R4Im6pT1TN zlOK!6n(u_v$0thZdmLET*NY;rN<6&!^li~F`P=X)@?D<#Sc@us&jah}!m&a;P<_N} zk#@rn^9d7#gyhq$NTtg`FesNRJrW`3C?V-b|3AYpofL&2SD+lQ)pbA9FuiYr9BVU0 zO73GYR2=Ac7?B$boA;Xpqwd#>04faFu4d@tJDZ|DKLA~y1tpZDKGt4JA9ZWNU4O-c z!Z9mF3exUNJKz_Q358&?)?zwRA8qEfuJ0rY(M0eRDSgU)CfhwAWvP!^`^hazfbM2H z(@$Lyky)jTM<5QOjDi-qIykCU!M7K z0c;Y}IEm7Daq6#=m7{N$mi`J~%vp#^a#t3P)v*V0Eo_!+;xgE**NBh6o+a^Ruy2w0 zHrQ{sCfzu zdzIuc)i5r&y{!q?3*QK97MT-e)g0YhSzF={dI{M$8SmeEbNUEcffu^V(Jm) z4Pm>0eS|KQP0J@q1vV`DiIK z4z?pPW%!MNVK0T9FER6iq{eTUru@!BVjdVt0^&K3^2sAs=Qh(RQPF>=YDtMSDcx#Tx${3Z>zX;_SrOL_K( zR2;+@x#Yj7@x>Uq6aTa6bk}t-{B^G1k5{of%iNzSX z#A1wG;^VNDPIfvJwlplp$fdj(BbQi=kxP8eW8~gwS>l*wT|>>Ha~-oR$i3uJThQ6Z zEG>3r5dR6{QbEiC;dsWm5%vNzt?_U zh1;lgV+H{H-Euu|aT4~T$9i6fWMw$nrk&q~^{xAIc-(XJJm>e?<8tDy6ys2&3twd8 zjdy5&XafC_Xn#fv4!9nL_4PQVC1je%Om~w|3N?lKc20a##K?`<#&0S7fn)a`N63Gp z<6uJN4JY$^AmLHqaFbCA)h6)OD!B zh2hcyYm(XhX(V>p?wb8G4;Ouwm%P)~7Lf;Cs6)B2%g+Cd97y77)Pv@S?ounqma0+7RGX745IaXy@tY?)2qzwIeVx6r>$BL)h*ni{1 z(>OyOyKlsObkIChV@3C9A9PxLbOVhsD0s)S0)ayjYiNN}6%M<-4Ja4U9V!|*yjysc zy=qip;qj&UU7?rk%W#ar@kx1kZ$;`WcDoB|OPePZt!gi5Xx*}@^Jhsow!JgKdnmz! zGuCn5^_GN~-WP0_leFEjo1Qf6C+*hbkQ#Q# zOx zsou5NiePF?c&aNr)d){D!&BY0Q$6ideXSW*^3Odj7t82g&*(tg4&!+z^QotO-*c@R zu_eZPEXIR-KKi8n_;b@YK5v$6bZz!Dcw)AAeAuw0W2L?FIkTkQ)wHUyd8(^ns?oG` zMN{jFhN))rRCn5}xP7Y{8;Xs6RV(%_UGYY-tD)GeD0X*`c0Inq?7qi!EGDKo#@7@{ zYWlXl26~#HyV>IldwADP_t+gus zw33?+z!y4lXWLUeZNn-b`_G=*gJ#QBtVhG~Mnycf_BB-23HX z)Dq#ju}!l?wK2`6bE*ebNO-C@WF?2fScDr28~iatVf=bRVQ(nx3x#6>FP%okzAlc{ zwokOXL2Fe~R!rV6PKO^xHE(qDnmO^u&UYCv6WSMdIbU%Vj0$E)+oPO#Hb=jp*S1|~ zKYmVR#rtAifu~OAZ99GVQ2607IeudY`FqXEH(v8)Mk?R!E%|07_M@Em!CQ^=wc+#e zemQmOWp;3W!>!AgH{N>d;+$)*vhywqTY$-zHZvQqVRQJDw{oP+Pt#qv!+!Pm0dR_cSuoq`josO5C*ZKAgM|{HtKX0OPl@% zerVUhFm3qa!xsPtrUQok4&oockf?*0FYV<26^2AUaSROke0jDd9>&OnC_}7d_%cHx zpO`}#Cd`EzA5IZ}BN(+AH_C8WTj?1GOrjoQ>R}w%kzt>PxCn-WPsFoe6u$K#8^Exnz*CM_UHu)!k`7%bF?Zyv?GQ`=i z$*%$)FY#T#2qI*ffG?2zCxJ-}OUyK4*j>Qn5&sJKN{Qn<03iAiPlHXFYk^gs&IVTZ z!o^R#E@i5KXG{De;4e!Y;}v~Zp>qguvE*M1jDHdKIsy={OUwa!>b*td6Qe&R_>CH$ znD5Gr!@U|GPC??(d4+=#!1`}|KADGgN6VL^d%tkuJS2)RFZve)G86YW}S&Zo$DCh$Eti^ij8oDBsv{>ynGO?)#s2C1-><5+ z;nkNek7}6wcTop(%wZ%jufz0X^YmL7U0*dEHQ*^y>AVjNh3VHZ3~P2_Qy*JBrH^AB zy1tj;P}MTT`gCyoM%P!G7G2vzeTG~Dsni~A~>7d+Dr3|)`tCe!B_DSm?$0|(`b4Gd2eoXKCA*aH?>54}pEmnmQ zZsm9HAbnOwRF3-C?D1OE$0}P3?z$a`vQ8<1pMtbingfcnMvj8X=bzmM>Pv))gVFWP zh36XZ6e)emeJ0y2a=zc^f4=To4&q9cZqb3$^$(2I|Nb{9y`(UGm}33p79Atq%^dG1 zuDjM_$aH4+OcC7y<$z5$yD*CAzC<}-)6K31pD)(e$tVdkU@M~kY~_GWcQs5gOc9<{ zuCu-gSP}hKDhF)3*^N^~cl6|Tc^-Rok#FOTOBT*sxN82wg$ougi2Bc8yzrJNVk7Um zt^C%8#u6gF5=7f{HjQe5GR|OMI&b-nUtPGoU%<6ggqjgOB3_=-E>1I`}PunCY1;F}v&Pn;B*KIzX8Y*nIBP zdGKG8eDa8g%A#?%1U+k2h<8fJ>(G&m3&%iUGrKgLmsg@b9V$~P~Vci14BLJ z5v#MDQBCyec~#1gN38VNz)H`Xz|=z?vC_k|BmW1m-<9|i*heL1J3u#O_*yg;My-!v zVJDwFVzoYkX|3{3c*#bcPdC5okXToXZ#=MzBxbmA5>J4Ak%ljonErfCU|5D@Ub2lO zT@FJ&dBj}*8H9a}81+3VRpMOOyf^Y07x8@*m^#Hh%Infi8S;qL zbs3&~=3OF;TGuJcl@|;UudB+o(5X5=v?^fngF; zw^%bM<%=XAZ1L(vdB){A$>&`4UrSs9Jy~#5W*h9UNzB)Z$2C6vl%5wPrhbeN3;uN2 zVl5SHzIt#zHs$f}^1w~Zx!5$sjB~lfl;`~j8SpDLnVTi%tK~9@`O3z;Q_oi=FvF5Z zte%TQl7ATXe@M(mli$54&$%1SLt^szt&2DW`(lmHZ|US$!Je)0xfcuhcfh_~<9|oP zFKGB}4WE*juf`r2>e+>8h&lmoQi9}@N6a)}K8iYlKOk}5Ji^i`&YPF~@iHv)*M^^3 z-+Hm+lSi!9x85oFd<`Eb z%PH{*O(sc}E9NhCQJ!;!E|!>ju8_DGc9F)XoAP}9XZa@P(813n=Bxe767$u54E!mR z1v6e^zIwA9lh0TCYb53?KixtwFODqS}tTB%eHD)plf4Mpi^z`#?S95vw)7 zPf9+A4o*qTVFA`HsvaHzH^Y)gtm@$jlo^H}&=@I09;!;g!mWHb}yja7lG<=VS*J^mPhPM*qUP;fwDBPvt z9u4o;@Vgp5s^OCwX5FQ9vQ0K*TG<*F-|Qv7K;w&V_L48Y*-JcElc^_`Y2K*eCJl>k z_EKh(#uwl0C0~5Am-t0ZX19jl)Nrqc#W#By_A`yodQ!zLQNtM;4r+LUh6^<;*0o9f zVqKfW3pAOf8ooortr}jh;SLRpZ}w8B_+~Hh%bJY%W-s|~Ykby|>K>147%wS(d`rV4 zG(1+r;+wtHFTUAJEY`K*IV8=ZyzGZm6U)9gy7T%c`?H=ma_Oa)*ikzBH~W3OFs{Y= ziM3}OM}q!&9~J(KdEn7;IBh`jjC(GMXr9AQI%H5(&pNIZka9=@LD6)O4p`Jd%7kIP zcs4ne-z2CK;Jr^T>+4+(eaQBrC6+Wg!rd*5*@dEXnWjZf(s zI>q=zaP8wE>%4Ra)9c2M8CsW;7|MuG8{?YT8RN{2$FUY==jmsq^5}^QAK%5;HG)NKAN?*D32i zC+3FOB{9*nVkSRwsLVW6<~~&BIaKC7ROUNW7LyZyd(C|_jaL{?r_8j2IPb`RNti5zK2ph-^ykp z;O5`I`$H22<;1eMr%$<=5*f=g^UdzruHEN{I+`8JH8I%=b*!G)Zu&}HzH*E;eGtKs zTLt%IrkE|4xq|B}EBwJnD@}jFvw?SUwv$W7bomtir9X$VoRh1 zXD*KVd;6t9Oin(2Rmw$k+7oad(w5+ip4x&N0zXBh(?gcG*79I7T~2&;zCGQzKFN4i zWN1>Uu|K}@!~bkaa^?Lvg7c}KBKyT=1PF@&ocZ=c@_g*z=lvkUL$S7!F~!`R?3m}( zC0p1=VXSjqe0b`4&eRc@ZT2v|W1rsr@cst|6b~pENbFCj{K7o#6M3i1z^9P|GdVl^ zu(_w^pxf#AM|Zv}?Wy>xgr1)ijP6-paB)w5!If$2tSNrWQ@?uAgTq&iu3xukW8$id z>mOOPF>ckB_0KHYX!OB4?KWp?X$@Hce8}=d3cg>*gV$pkCH4`+Bb*P$M-yk6S5j`LRKg^ zC9NS2X%VUJQEM~7Dz}{K9>Ms2>Qp+` zh_p^uSGFDMxF?!!tS2@U7@V3bYKgqxW1{-2?ISo*-G?TRGu1sfzcV@+y#)jHou~8O z5cSBr(K9;n)o!Rri3Fs?EuSC-FzMHC^vDzle^zoLg6bvV^W}%-B|5)+Pk^VA?l!F) z>`dZvGU7MC!RQ}H*1R2ZER;&Wi1g~{{Pj1=&O@EE_>|W8h&FZpKXXU|kyVA85hp1( zJ9i{@SV&`|mdlp*2x%)hhBJcE@a!zG6Eq8k{_M!jg<&U%co7Uqh2^ywmUa#d!}6mj zYfj2s4Z{u?!~P45;!|gjG3=dvb@$f7^QPOF#8+S!wv`U zpO~FYL{Z>s*t~!8SHX~!e%ibj+WcNi{i;(<9^;q@!?4*Jo(xQ)42jpJ9@^wl593av zn>YYNJxnup<%mNtlqHUKnEG`x52=$j<3YJX7!q|B!l-$VbAVNvR0014hC1WP1W}&Y zhD|;<-&5&79hm;)&jcpXO-vpQHzhVDe+BRu$>$)hio;XDB!(r~Fh($HtN82bMw|*m z{b(oq@{Z+@A5zI*2BY%#>%b)HCms#MIPs-|L_V=9w@;7>BA;0CpCuDSKC$BSV=0Mz z;tOFIhYw)*J%gButmX`Jf&i~i`BY$00RwXa6^VReCC|Zi68Xd|^9+Bv#)mWdAukxU zRk}@}2Z&*bQ(+jNQW%yw;xZTn6SxsJiSop%{I>x!-6;P<7+#t(+hF(-MgDUzB=U)4 zV95VD42gVV6^GZ!1d&gy?yDD=M1C)fN{3^>B=U(_SC}yFLFqt$BN&zYqGyxO2IE!; zqn=ZiB@)9c60h{qakkfcwQ+~o6Mw1mT)yy@1%p|Qc+c-U zX-G&#gU(xo-TIem=M@RRfm`km3@1+r8W5eEZoTmqp=i)G7B8&1ZQ+?b#Qaljz@mRD z>KSiukazS32Q$Sj4q^_v$w9t@ZgY_D=Z-=WQPXa9ki34ggS^D;asn+>L{mI^e8T^U z3A89)s_9@=K$;M>`hNMSk_up0+Rr9;%{j__h)U$(ls$E<}vs2tkAML&<#%Use}qlRE{O!PiyYBVIt|?`Ik&zYBer&9G6MiTQq% zW0xQU%5;5{QC%RwK7HJ`LFp!c?npG5;87o|Tcs~=kUq}qT*UyAlnypO3e#&F3a*MD zt7E0FWRSjk)YFrtE?P=Q(I9=L87@~f{24!1-AdnrLHZtrK0QyAKJKNXFoL_bLf>N8 z)W_)xN?-FJefyzLbweQ5r-O5Mb$zMmU+~*3^|AY+^oeiMaI5FC6&|X22D?uO=hf=^ z)}l=-*6left8~BLqCgk9CUDw|9`f-H51a?sR?pR<6hI zMfBHL4yX^e-lvcAielkb<$eU(dOe)NEJyek%`_|*wWh-W{|#}(8oDuij+Ri zhtl=w&{?&k;*}KYf1RBX)%Q>GS&_G3WcqEne(&x6|(c za*LOxewG_0NY6*+J6}N*(ao;4BD&944%l?_)kG29mnsKry2FFqvj(|u9^}4#kb5=U zyvxNf$tW-19OS<2Jca)oU+gB0jIc#v|nV25vkVHSRuoNMd~1 z?kl4E&oDL&%YHJ-+b6(^=x>6LM?=ixPDc6Ts~F=`3X{wlZr;2V3vRq^`HlHNOKx32 zaO-j$=y}V6TL+y&B_@8<;ZW5vzHJOm8(el;wajs!XW4q0=Ov<&Swo znYpm9)%Y_tK49Nj0wv_5(wvMiRT^ermwb|lr!Al>9~SxK5f8QT1G*fBd=4{BmH2Ad zBK`pYkcbat$Ri#q`IW#7%Q*9SFdY1VK7}ElJYsdu1k0u|20tJ%KNvFP5f7Dov6cXQ z4uOq=p&sIZhEoy77)vd9wk4lDVs(ZD%fG?K2*k4|sfRpbbykE(AFXmRWYxxabKW`0 zfgxT1yG&w+yFlV<*cVI8e5Rp%0c?@BzziqSGZO$L(hYp_h}Ag$RlR@@}3xme7311rQZjfDw_$mvBVsP^J|#>O2ub* zg~w=EqzS@?z!PZ#%8yEwOsWMcI?(O_V+Pyt51$EaZ}m>?q(Pnu>le zX%Y;vg=^j+G0WQ5C8mxw5>xkgCGLRzn8ZJX{j|i-!G2NVov?o`G2NTu$<^+>>pBwJYrSGn12k*^kW!R-o#mk;FCwJ%G-D;&yMKl%8V>a2;x#@W;Adr z1wnZ*#J`8lbR^ynd$YtWGg~F@g8hudKZh-zeaMqf!?5^|mJ@*A0Uwn7W3WYACEy`Xd0BAQ1`Q#C+Hk9d3zDN&X zmDle|KFbfW%IhPN-w2ze+C->urN#+Xw9N$$!zuC_xDYrChBCw#X_$Ge?tP-`^t*XaYmIFZ2J_h*KnhTn>5^}VYY25 z?4!g!L>9DN!!K%hw}#);aIc1sX!tV?b9_nZ7wbLbwZwW4iN$&ki6?0Cg&G#?J)}&P z#$P}z%b{5BA+cERA+cERA@O=mzC*)ey@!<9q48hVuvqUQWyE?9iN$&kiH~dY7;xx| zn^^B5WyE?9iN$&kiN$&kiN$&kiN$&kiDzj#t2Mk>!(2P3(&QcuuhsBoV)@K+4yD4+ zYPd_oJsRGx;deEBRKq7V9E-BA^z)rSVOzuE93vT@0*x=uF_L_7j*-OT93zSAHTgyj zH)&X$V@EL-ze}Mz}t`^Q`M| z@^dHTU22ogKELx>zWgAaCy1vvh;}wCPzB~hosM7*m3z^HsjHIfQxC`sShiKHqXXPql{1%ut#84!2Y0%Dp6!v%ic`na3%^j8C6a7SlI% zY|va%Oe1y5hW5=S6TVicEZ)vtVFy=WHmOsV&^N(M_$G$Rl9Vsz$fmT-2u^9i4dlcN zZ%!|@#w&reT24Y6?j+o0#a!svg=4Lh!ilTxF@X!lV0vvh;V!3VWau|vzkcS8MYq=& zFETBwX4V&#+n!Z5X(4Y>C+9b2c>HYA4D*R5Hj|dM0=dgwYtl`A6ev0F8XdH1kF$y_-uQOs!VB*)5cwE5pO@7>1M}N!&Yp4BR z%xgVcejj-K{hcSCW)2^8V+QcuA4M<&_>{?+z|HHX7g@=eQtY{}#yHCBd}y}Tq*V-; z*>AQ~A@`l9)*#PChVuviC3Gx=#`&VACwI**v z1nHGq(1jef@Q}E3TUJkrWj4=XHY1ZaP!O5?AnpGmlU*8#ImO(rc2D4-*?TC-m+vaI zrY|qZC{3w&dBo;Vnmy;Wdq&iHMmDu3HF(l-G?%L`sj1FxT4_|Tv`g?J;H~)}a(l}* zZ@XvI7EeaA=X@OE)!-T3@sRCmO@cfmv6&?E^iJ>X8z>jp;<1}Oj*uI3X1T{UztZd( z*X|kH;2DoAS9mgc<&{a$gbgW|&bEJltvz;oFns-UMXyCFoDp4K)NjUXym4&r%i8S` zV>exx%=`N*?ELM!msid`7M-JbSREb4WMIEId1r6jvOP7N9D5=U6E&@MnfaGvTT^>? z9;(XTx08PLVeVhI2k$!NZflNKY?hgI*ROJpI@`JRq#X(eEcc}Fr1nYXBou*3p)+g} z%%+bfkMqWlGPw^V&2U>L_IpTsFp0DJ8^bRL>)QV+nRZuW-6b&<9;0ViceX3t5uSg} zooYKB+#`bCv!mX=aedxe*l9BCD9!VYj>sLKAbhRIRX0Aq7P@b%Po49e`v%`Zvp)vC zO*w`g%-b73-gNu$%3^tExXZ`cwJ)En_q{!yVbl7;UW%}LwXg@8vKjWEHQpRzyd;XF z)#AtFJ_Gxby6T4cu^n{Jy;Uihmw0l#g>TyZ?cg7yS7kUc_dbWU02)PYS}9U5N}_SC zT3tIPF7ISym3t1RCZmb13w4$`7s~S z#So-yzEcHZl$+&>qrIbPt(I5sh4c7JS!{c*MaSjRskIXYo*EWi}b`G8{dV#-eb!4fiYwfXY zVzctQ#wT5nW85$5iaR3(ZD^YVcSJJRnZ6%!!|{9R!MY%r_dCbs+iK>mh}h22T&E*! zjNp>dpQ2C z(62{2yHbr?C|vS@S?iB$@W+OuIZ>C?zm0FcQHY#quJy+^_^q(tA3{!i-oL%ppVZ(_ z4EvKq$cfMUZ$VBp_*29Fw2;V&!TLJ`g%P8Saj~l#o4Spz-Fd&uc9q<07EO)>E{pV@ zOe*#K>Ppn52c}M67xsHTH0QkQb=-Dcawf{!$4E~6((ks8y8ciHTKQcvt1hxXRMF%JbqX z-;M3`$8GV)V&m+N7wj$mA#y)(lyU3_{(`-=`SI`G-06?s;G`?2jnPtqRC+y9 zGR&-ujjudlRX%F%+G}6Fyd7bN2L92W#H-4(S4JnkIjZHX5N#hQReqKNf*oy z`|P^Zngb;${Z4o4g;%0%JWI7!xPF;05$|oCbjgs;^1RJ`AqRwcf>QO%f@N90;M}aV z;Nq8sUre_5-A{K-yV zt)}~LL)z8)Q$zkV2hUQp*3|s-mYjAL4-I!z<5UCV>x^s5Lk5bqC7%-C2BT)~>AV|H zTV`oVYvrc8t+zQdR#*vlx`Xb`ojbxm{oe2$=1-1>`&+uwLFBpT1hQqNLe&1b4U$l3b>tc7Of6(LOcummAGf!uGZt&l@tf9td z*i4vJH9Jq8s$b?`r_VHin zLRr0VGO9AX_c6T_sHSSBH71C?#_hc0rwZJY+L_G0f5Eu1<*l$hA>ro(R~fp1-Vf?e^;9v5^LBTD>-bXU}af(KATJw zTiIl`gsfrhR;pvARanE}zqZeRHrvAMH(;IU7HfoKjcm8l;os5c|BzunWIyy+$QspY zWjNOPTddLW-`?l{q=6$9o_H=NetIB!vk&DxQDnS%iUsUwV`%_yySUFyd0UHC)?SwP z!YOnncevs6_G@|DPeq%>(5}P-;pyh}$qzYCgiuhX#&)}1J5thKJC*K)UdpJe*xQom zLJ7%xId$d(OA%L^`R=+Ba}KhAu{)A{S*&rs;jYw(W< z`A0hbbmY-ekwH6eKZO=n)(vH0|ELCkM#z7@;~(88((gYv><={f?U3Jb{A14Gzc}n4 z*We!;@{f1?nS=a4y6F`1(ODeBwSHe`y2`4qVQhmxuDP%E7jHVQ=%E?;MzcR2moKV5 zg-XA{??+u)=xoPBg$JnrwWt_ktnzV34gTcm6~aGdp#Lys-cV(%Ezg>#z;$k^>`8q5j&JpLE%=17F&KlLYQ^ev^9POHAie-=C&{K2sQf=Ly^|H6U(Il@0X z?7t{f>k|SO>jLnd)DY-BX`DRSUp$)4yxx_Cd3F@u9P2MyzI3|SKE z>KR`0=Tj{sPveytRa;=s$@1A9`(`J7`B*5yu1ooC_s?)t!51%acKsKmj}w_AAjo$b zzUz>b9d-5p;=N|iJ39|Y)F6@-f9R3J$2zba)-`@Y#izwX#-}EZA3F{wabPY>aq0M3 z6~0k;t$!|L`cm*3i^GC?jt0$8Pj5G7s5m_*gJxSTy6C;^HwH5@uZZEfC9W2)tJmqu z%JBKY{J`lx8KK`_j&anfo8k5ud$TWW4zP>|dlq4VVQ=FUZ(6FS*7Q^trq-nv zRCs5$%?`UOj=X7&t=M&BtM|fLUC6QPp72)eI=a={HH-Mct&gm&v!D3E)@QEHf8r<2 zQ_E|^9%om^%J%Qi+!(Re?Dl@NA>zxzxf|sxo6VLnF54d4);!sCW|WuMF3j1n?v0s$ zJ4dY&vPKtNfp@3e(iK@3W3&=4WP$r4_Uc4b4j6_+i_D?Q33k(J122z-rFPT{{JZat zH1!Qtj+52;+B7l?Dux_yQ34oBCXx;#NQip$i#jFyW-0;%)Bp0-l>V$J&Dd< zyDPMget()PslBXa###eaxQ)X37ni+?2 z$oD!;l&-_0ou}^2n-+1dbyZwzR9tITTCnvHo0mt7JH$Dtnip%dEsb)%HZ!=t@5mq#!VYq3f%7Pot?*ni+!chQ8% z0V5}2iY10&8#*pCrqCa2!6ys3_!U^KJ7WcwiT~*67d(kYrz6WwM=;{EBnFLb`t0(i z#->fi+D&j9Bzo~TNI%`u}+wIMO#M&C`Mq* zJY(3l!)^JkrEAv3wx+cev~Vz@FWj&D!!2!WT4OY|@|p$44Kb^HZSVD@V6E}0t5&Y_ zLJVIn`hxuiZj9UXeawJL67Tnm##uP-L8Hb(#NGn$9F1^K0j|B?Yu1|>0(t#IzB%u6 zwx4nrm=iaQEX^oLp13}xG&|&&6W0$7WxLr)UT3yk&7z4PEPM zndZVWa!=5W1^g*JwZSnxPB4F4a{n0AyMfWt^LSHCz-M=qM$VtEjGh*9)oLS@#4UiR9+5wevfINWMwM2tEtJ7X(9DjWfR&sr9=;s5oy+!Uu+%u3}SL zyd7@~t;L(%d%YVs4QrhhOv&8jZ(R@^lesCTw9y&k&P=VjY0ke=NBxWjNVcZMnl?)TMFAcV_w<+cDjwQBRSk5c48&!~3YE&it?vbOu z7qQCy^K0CZ9D-CiqeI70-{>#KggG8;?`!1H@QFOD{X_R#ou)73%5isNh$3WKd^xz- zg*`KpBP|nLrRMbIdraefMkaK=XNF}t#(Q*N=Yhpmpf_^#O7Z%&yfSnOS^@_n?;MPL z_Qn){PD1#xDaJu@69jry|&w7$?vT$NZH$bKE{On>hJM z?2%HEgk<~(U2(+K=`h0`E~86C;gqr0Jo;Il?~MpQC5Ufad;OJvJKbI^)M=KoxmjWi4}hznIQ6s75}ef zg2*R+1cv$_fbwFAf2+m$-9d3?SvP{w`EdNy!#H0EL!wUNi(shpdKeP<#23JjzZyo} z%RRuElK(@E&u3<=df7_^pYnX(P|b_D zaeiu&#JnbnVTn~)EeBRIHNYgw5K}*OE`d=pcL9?qL!1mlnYA#fFb>S4Fsl4;PNzzr zUjWCzP=;kPUE*HY0f`L?gQ%a_1Do<*V0B-dr_6Um@+WEX#Jn%^d4@ZQdPqWFFlxuc zZNgBWD$mRx6*dG+Vi;l-2j&Thd}3Aq@cAH-Phx%>xE5{JU%XZ?42d$mFibbb^B4?? zd}0;12r$Eu&vf{nbblXs7cj$CQvgI6;$qn3KdSMGpO^fvxclp(7T|G`|3hE~p`ITB z^SPk=6<|IW4h-jW0G$*gBWfvAUAm4~gs%zMh$A}KMKtHf?-$xKkU5?d|g$U?|=45`bJJmo0f_a^fV1^Dk&ssDXF%ShEjsI zT1qKJ3vK#FE1?Z-(4tiXEm+5@m6s8njs`@h%yblxnPI#*6Du!eEZk0q8H+=miim)K z6|15Gxxeq)&vUYJ5@_yc#`~Z9|J>)3mGxcEe)hB1UTf{O*IsA84DPYnDz1_aU%SNP z%;sV7QsZhhHt#<#q~S^M56f-v`Tj@`~60ypX?1vqvXStM7w%c8%e-gF@bKGI`Ryqd>dU&5=^v{V|g>`=&*}&Lh z^J=7rX;v4sz7_ii6cFrT_wxu!32E5t?lF`S^f0@FpC2nA=wYwNUy6OZ^arL=YNve z+uKyJm+dSu!us$i1-7+7!Pi|S_I2CDUSA&;E30AMs}=jYet)5e>s94_P*lNk)GwX3Q2Vud*Agw zbPB9HU%~6QMU0?_Pgkf^*r9-+hnp49A5_36{96V0`LfvCQg@`s!1Y7KZqM@x-VR5j zl&~$>%i+zD9`>@GB4!cxQw1XxQv|cc#OQfILICjVedfGGF#s2{XFP}qV#Qnp4 zUTK9=(ntRWUo!A_OX*sC>FTxXRxVw)YVBofmapHibVbXGHTtI8y7moMX9};SDwy#V z*0t+e+SjgM_Xd`H-Sx`eYx6>>rR!SyQ%0}GVmra|%Br@O4eeF6z3sziV~?HFb*nx+ zfc?2_Rr}KQ>sr^YyL@TehE=QAZmL?be%;1)-q&4qM(^zwy^xDshWAayrMPib>#7y) zOZBd=_Eph`Xt8BW>+}iNrEAu=^;fc2UbX6~RZH7iR$RU+deNA#85j8#?N{~AnLenu zVol5PwaUrWOV_OBE3*B*^9yHhP|rOt(<&Ioo9)#mifpZ}dut1|-JiPGhj`guQH}Rr z=MCz-x8dv8dT+a9)O&B^K5r-^zoG7X+ZEM*?}h!sJ zh1S}#(Hmsdlqq#On9#BZ8(Nm?v%{-tsNtPySGBgUU4eDW%9R^d@u_6D3{}6fR|eEw ztlHGaqHtK+Vw$18X57A^W!=W5d?!-dGF@o0t*e6e|Hv1P)3H8%E$0`+`}Q=IjxpdS zg@M?$4$!V+fOaX!pPX?VcZ?9dkDWDVLc8vy*_y1yl?b7w<@9jnYnrHX;<9f#ZeW1wSJzCbJ;Np2&ROD}${B4pE z`8!d;{asn)kFlxG-3kl)*jnT-uYnxTo#KzNruz%eaw_fR$Fr9{uPSxH- zhWTSG=>EP^l)rsi;Paxfzb_T}+up2tFn?SVxWD^~{2d;oc_tj0V2Au&k-tt|FfEjx z{mm=5zn>QQYu1kY+@j11`+K;^-%d4?~H!zd|TK$Uphd$kI9a8v^zoAu5Sy4^XH4~R=$qi*UiqG z(i++6P%nu4yUXmTBV?WIDpL&q$rIt*vg2CcWryqLjtlU!#KiV{XLDSeV&A zS#yKYitdlt%MQEEItlKV-E6V9XW9kx1hK!lO?sD(JJGTTmFi#mep{Y1XpfYHGhm$N z4AvthVKyR8tI#7U$>gIH`HgFsbXC!Ede9yz2|Zw(rU&bhlF$RiX?l{%G>G%wVeeYU2_V=2i1|zrs z-@m7lS>hfk3BUZsX=W39q@-7mM*cY}dZZ-GqQz-u+j^uV%#g)t9UPIAgd?~|QKBP| z5~kF42u5XI>gL#q({YPr8Rs+?($hSlm^6Ka3uz5c3PO5*A(h%MFG{x+r9Y-L`Pr^O z{yt^P(T!63xkWKt71A$t?^cYY%cqCmB+-2&#~kE@%>7|$`j7lPR+N6aDE&*NmnhVz zGbz{c_Pe6x%&Btz`nE#3MiBgFOsl^jOS&dgM**9#y%|c^Dt@Qpa-GrV6)k^%QF=vD zn)z|IN6nVY({)NS&i!sk>kM3&4p_l_VkVxzNHsk#%>2-Ny#B?dtFj&VJs?c~yJcRqecflb3Nacd@i(-PM_NIxl@|rcI6bY{SY`t6MbLVbgSO z5>HYvJ(AA)q;Kf#d6Q2ujU;j!I>oZR~tlve{sRTxZvM7_%{yz#RdQ3g8vg!pSsmAyjKz% zj=eEnlF5@;$_BL6>l@%t@uu3 z%9(ogcKDR((ZRlt)T{SDFPRNG*!v%T&t|))N{9IVju(#^5>%mYg2`LG=^6i&DkSQ= z5Q+>Nba0vU>?4BDykgS4Ul2J<0sf8ROC$bh#Edntp}o9j%(!A2d6pj5?sh2k5HZ&&=qi2pod>W@6^ zQ2cks|DgDvj1MdRpAr9S#E(b(jPV1Ce`U=5Y@sf!z9>_+g$^#0Udaq&IP`B(JR;)q zh%1e`Kk!uJ>55rDG5_IMmI7Tkmd$_21D%`+#}tCym|+1mmP;91?gv0WP4SzIs}xgz z=;3k3w7VMP6BN%@@G(FmtnJeNXTVgrq(LD;AyE^|kRNRDlh`F#HOxW@+w*=P58J+w ze?J$OnvJ3$2|FY?q%h{V^nR^hMEpv`)Dt%Nc)%Fn|7^_h@gK(IbEw86*pCrc8PjFe z7*kH?8Rx~97<13q<;LvOr;ORxTO*q)9i#ZiW`;3kbCxmoyNvP4{fnM|=7C`JE7VUr zUv5m1e#{s@w;MmB`0pb9&y8s+>(mcykKZ>zTGG$7$E#zWj)?I1*nAW{D;tQ09_GHm00kG3H*u zu?qM>f08l&8;$Y*O=J9j*BJjV8FO#p?~StX}^bx&o({%#2jPRU1dx^vBsEj)_i;_M%I}g z9b6_o?cpP)?@-J=i{uTT{6+=S-&`N*7it|JxBr>x(ZN0rT#SuvccS$(=wRROG}F^p zO*dw{7aDUv_6Ll)AA6PY<%-uBW4|QI&&N%V4)*-qVEQj8zR8$%zi9jw#r%fh`@RgH zYLCcmre9`UCO!T3J*NM*;=ha5{YPW^SAKWEC-;OOHhx<1PmHfo1(3!Dem3IgBmPCi z{Py7XXGFX>;*UoBabxZ={*z&PB_Nxlf+_;h(x&qjkKEtusA3*xT4gd|kz# zHs+rBR@P;pBKeZ((ZSwk+LTT>=p?($1|7^fLs`h&V|wz_uC)7n)b!|J_qhohD~FHR z`3@cI&IdH!*&j@TLZ+6W7(DdkF zFVCNuo@WO-u($Gg&h+SDFP~RUPyWxgb1vuWbB%e{;627XU+{Hfo+j|gw;6L@u8nw_@eIY&BmFjQ z!|VFprbh>RU4P2-pHsZu82^76@pk-3hrClUc|!+#pFiL9j4LiR=DCIrW5yucjCm%a z%b0Eb)R?ixGsZlN@oVEhD1Ov$Xcis{k8-o|#B{u_$_%9yduEv&1uLs&*W(ZSx{zGHgwuv5#tj(%u* zbgi1Sn;sqP4yjZ@)c(D42&qn;G#!oB$nsG)pdyJn@{7=TL8^(e1xmUU$nI2}2iEUvs zN&zOnVf-d0ztyH^pWbK8eqU(J{{EveW%HnMUi`2z_xyzGGWlF7{*~z|2kMjUR*S2R zYs6uUB>g_we!}!0(s}b1W0{2U59{W|yssUu6@M$T`LXdzt@~`GpQ^O4J1^o7Ykl;O zDE^4?HpL$^{=DK2<2w|y4Ex6vf7Pk6@k=wP3(pb7eW{b?WMAv8;Ina+{b*qWaD4|5u_X_x*K(^n|2 zHRf5Ksm9DZGJk|m^mC1w&sb*s_lnm<+#WIC{bXHiwiq+#ye-n-XMCyRFb^qv=2XMn zvY58SoIZZI=j&(2=o{Jhv-M9B#_+OfG%hp!Y^A+?c+Dez(7|3lYfZmiG54flLz|>c z!;IfQY22=M^cmwD74L}j&1}o&^B*-mI@srp51O8L_y5TFDaEBqvn`%cnu{MBN1bYV zbg=iI^RYQo|0M4+8+5SG120rMp}|NlH5+uW&jT-3+WXJdW`hp){*z;pylo|)*oOut zfJdeAP(@?tSR^tHjP1LO|57n+4jcHkh{qdGQhciMEX9+Jrz%#L8rDTm(clMWiprU? zhQ}&iYP?GEWyV)4UTfT@_=-rsA>t0>1&Y65yi@U)jqg<4Y5XZ%Jz5{1JOlMXV|;$Xm}j6qYs@~e4EwzJZ;UB}-x<%A{U`-&&@VK` z5BH#=hp#r~_w6OJLr*`wBI3&A2_({e4Bj)~S?9qpFw3xc6QC@xA_?+3GgMHi>&f~IwMY>w-X-E>% z_(TW$Sdnr?&+~LswJe#9wfYm&ql3##{~^(c7n@q+ z&02SsF*b{ghbm^bv46MXbB#w!e}VDEiWeEbS^DtXne69F$8qbwC51jsdUUY=mNXI@ zI|qg1LN@4NKL?RN@-RpK>8IcpVuhqx|0G{gK#vYCGyN{pA5?s=G5bZ|;d%R>>CwTS zw+d{`&wjH(2fP1&Gd(_^H_nKU7{9DIui)pb4b15u#?MFv|Gg#$*Xo~SsDht&!nXQ3kGxGbV{jk|=U*|lp-qZg z#2-|^27eok+0JdoocF$OjH?FY#fs00m_r&r=;uWo+MfCXgk{*EgS{L=o0tB8be}XE z`s&X{d~?J*BR)~=ecd-qj}G>}?mMQ(KjQYG3@vZ$o451elY)}u6?~jY8}jjgEj&d3 zBn=AQe>TFy^iR^Pz#IWGUm+h&eaAp1$6BO~hRLxV|G|u6bO4OT@QF zd}qY>MZ7oS$09xq>-r9PKH`@nE>%6a&B%x=BIbJBZNhih%x7bypBpjfb+=y`aa+WU z;oN3h#Nj(^gVQ{BqBrKc-ud2$?~j=09^B@Mh@Xi#e22|^X4FR9J{R$c5%b%wADcX< z;mmI*&dm`ogomd2UluXfa<1PL@z#iUM9gm@ZqIMW&iwY_+!gV@i1}T?ZJvtwNW`y1 zJXG!7?YY0qIUjLN#Q&w=VYB{iJN}Ksci4>oXy0M8zO+9 zb0g+A7`Is&aa+WjBi{6ni}AMyT(pNROG zh>u2`Q6J-Z%SC)*#8na3Mm!_p=7<+Y%A_J}(o-X8HS5#Jv1oe|#` z@!p6Zi}-NF&qw@n#HDJpzAqyqu7GVUT^;e%h#MoG8}Z_ZS4P|x@#cuPMSN4loe}Sj z_}+-`k9dE?PelAo#784$V!-z?7x9S^S4CVK@r;O@BVHKsvWQzF-UQpV$<~N>M7%TN zT@l|CaaY9qB0d=LQxPAD_?3ulystKItaVf6yNw|Q>qu)5?A-Cep7;3a)G(Y~3e z?1Nq*1DdLeklq+H!^_}XLV^5i$@`o29nto!(= zVResWYxf`B*ObdXsI#)Z9MP11{Wh1KIecC=`88`#%8h;U)kziA<-K3ioGEO7`%BvX zf=rtEbo+g`sQIGr9^vzjd{y(2>b5&`6C*}4n*JmyCKJ(Jd zv*iaClpa_xXi|l~Q=!SR&R?e4==HhEj7zj%he~!H*!iu>%1lE^x`pao-LJbRRWx

    1zAgRYD-i`!SN+t{-7ymhPBXD+5 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 +jvAFOc>-^s;3pld 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 C-#J16 literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/lib/libmesh.a b/Distrib/ESPressif/RTOS/1.5.0/lib/libmesh.a new file mode 100644 index 0000000000000000000000000000000000000000..95c4f98d78f7491b83378899a0f4474e64a354bb GIT binary patch literal 179444 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%0DG$8P7fC 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 literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/lib/libmirom.a b/Distrib/ESPressif/RTOS/1.5.0/lib/libmirom.a new file mode 100644 index 0000000000000000000000000000000000000000..18e27afcd6d09f4a17c705f5da4ad14ee4e8526e GIT binary patch literal 2255754 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

    SwXhZ#DWd!^LFrzuf5jAFr;fge>`AO~!Kz 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%0A*Tl6CO+huh%ViJA95Va=QEXx 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 nt3m#MfG-xzXL_7q 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

    Dw%}G{U62^nK4Iw6Jd}%!!kq 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

    0NENm37;o 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⁣k2^1M8#KL9 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 r-f4KZ;cmk{hWiYkH0Dzb`z+toy$Kf=V8R literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/lib/libnopoll.a b/Distrib/ESPressif/RTOS/1.5.0/lib/libnopoll.a new file mode 100644 index 0000000000000000000000000000000000000000..20c8c5ec4b46a218c72748e8b0cb051282b45875 GIT binary patch literal 255842 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 QwtjzkWpg_^j&~*ee?P=*00000 literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/lib/libphy.a b/Distrib/ESPressif/RTOS/1.5.0/lib/libphy.a new file mode 100644 index 0000000000000000000000000000000000000000..4dfecedd1384c9d9405ae338f356375fc57508e1 GIT binary patch literal 200966 zcmeEv4SZD9o%X$x5C*t`Oo)hrb!OxvC}0wh1`F*>2ox-65`jWjJDGezG#|rckl_8s>ua~#omfkug>Im>f|VMmwqX4L)C!8u`#k6VPjV9M>hAB| zeRucQ^UKY7&U60ff4)ENnS1UHOpC@VmwtTU)&AZlfAW;Vf`Unfg#~_pp7JvP`~6cU zPo3h1C?9B9_LY|PkxT#m*My%~)_>)-{65S2_goKt&$9l1T`z95tpCExzOKgl+x6eO z3_P#7qy{-mlKq7`-3k?4|2SE9D5 zmzzndjn>uPULC2ZP!dguw5htGsam<1g!*V@qPE_3*ES%f@#V2dOqGML>r>W zM@?i&G*R2I1o0`BT9{fSE>aV(UZ%*(rM0ohHF;3q?b*ZMc1N<`zRqG+9pI9?O0t8-3UNeYE8>-jxQ>fVyt&qGG4UGhRE-8b z!w8pXu8hWdxqF35KuM&s@wV!CADP~&x}_rZOCt5IKDU0*Q=^H5(V$(8D3vAbma~>O zG@-qstQsoa1{AGmLPHQ8x&c>7kE^VVs&r^xI%Z#5b-hSMwDMM6p;eU;WJI^G>IRfo zRkhpL*gJcrl0;==9Aio23dy$`MCgiCRj35G$|903lX8=!n7Z1A>S!GGr$f0#QdxJa z*~8<_22sEC_JZ2#YPTqw5LgX&93mK24-;sWO{i0mf=69rV~pADX_0R0gJ7buLF5vR zF}Cq;BGF73kyN4q^;C&UJ~Lf|h>?n_#^pVQ)zDbmR9%B8rA@H%DO+EQVOLVBWH7#I zAvZaFLLxC37JC((YnC@uHdzUzgYw7+(i=&{k!P!^uDUuFVYin7HCi9( z9wGFop*dr;(vV_)IZI4sX=jx-) zk?LkuRVr+ck6V=qw9QC;b(AwywCc91s!5Y9H!~8Uw2^2Gg9SP&qSv)caI`P971mr7osOA| z)I>3^S1zqa`>cv4qHZnex^;Oq6KcvW6^>u%hxM`Ln2j5jV~9lCRr7AVx}kanyO0|e zC9%AY5!A+}MBK&@i=yC~grZt@qlg+H=`t(0su5!WecWUvnk$gXSXBk2I6F73U{^zx zsR^#Tdh4ohljQhkjQ_MFq$HZl{|bXhdPTLySrtinO6o z%@?W|V{t4KBF35_qKZY=7?rScl$Jzn1$#xslJ3PvH(lFMRo!fr zWfXaiRIH3eo0=kx@!BP|4H%*siQ71Y`0cEw^h&pIp+!|)JsLXIKMsheZ8S{kMz%f`^Xjnbt zU8K%!n4HIZd06hqSXH|Ok-~v7S}<~psaZyiXq>URJq;__?zs&@(t6z%j!FZiW?YpK zwbYEM+`H`!qbA1{H?b;o+--Bc6m{pXCkH65gqfkHs5>~agxn?}qdmtWwe&HlEClb#uAau5suEa>Nn9!h)xRURq0_S_uux`oR$}R(n_M@Ksj0G? z?H;66`(|l3#g@mZq&E?ZH@c$=qv#IA>QQo7GcdZECDw8-^wg|STZKuPy~dq?8ZijK zpTv?_Ejl+Gtky>KYz$u-qU&~JiZIzd-Lcnzf;%4>OM1~5bkPCyJrJ{xBr{soD%5C* z?5q18r68a40;kQstlMegD^b365$4N^BCSm;YSHrDrWmiTT8_1PF~^;B)D z>_%&F2f#VQ?M^j~u|zEv(p8+P-JZZq3hS)_D&8WVOdqOD_(rT>|Q4@g@V`T1d?A9n{R05iD z>)4x8V`&e?l&R&bo|{!t;}P73VinhuZndD2$yUw2SomZ5uB}rX zYB47na&yp~A$`l(UG(b4mC5DguEquncZs!28W3fKc6Vn$lx*lyzPdYrt-h_kd$?zj zyL&NuT2Ku_?apWh`XR*;QY~3}E#WxPVfMxy29kr`87VB7GR10YtVyhh#xcIZCtiIE z8l81x@thk>_tI#*O38@78(Vd}i9=zmKC-;2y0UFdPEtitZT%o+#Rmmh&jD9bM#jen!El)Gmckd zG{F`PYCz2!OlB3Pv<5ZhRW4n^6;7Wrg3OXeGXzymmOBY}HpaLDGm^)Q<4o_LYA$f)Pbw6yd?1^&Tf5h&Rkqv+ zPi(xpmzNsG+gi&zw8Uwrxur+xo24 z+`rK6IR3(kc@y*f*ZTe4NviboHW5Nqek@d$!f(P21^x+3CRq+NZbnp$&D9r~(@@iB z&Hi*`#tqlcn)Asy#d*{7nkx$mE32Y4(SZh^4?aJyu%Kc}&6I&f3+Bu%jx4x-PU(V~ zkvYZi%FD}hy~0Ivrsoe_aO2EKxah_k<}R2&GctG1{F!Cpxi?PFqr!zV%Wj-=!}ZgH za~Dlw(t{-D&ADECMCOIByP<4)!K6GT-pgms_3+780m6&^S^(2W0+h|1J2Q+VT_2t| zb9%6B#)N{rd=<6!=uVU>&EP=IyJ;yz?s_QEIpc;ht*{OyGbK21{+yYS8M9~3_|%OH z=0#ABy$KXxZ=#?tF^NR+ry?cc`Lm}7gZL%Vn%K0oDG|p?&YGCOHi|Wot3YdFMN^YC z5tUqzC8ss9S+$Ib*f4KYE#|}g8w4S?0<1fw}B^Vj4qhOZab2g!|u zjMhzs)HjPjjP@H1cYjU7z8%*t?Fpv0f87Thmk{fRn-eWsJ~8{%3e$J z!TmMHLNxkowlzdYZ#ik%9j9*g46yBYQcm__3sw>(WoLI}Wu6kL{8VaOnz$eh*>_W3 z%bNv3$D>6Dp7}%|l}h@pV6f!^*_I;PYlU+2d#g5dmG|~>BZmJz-vIkS8WPn~01bJ$ z`Ce|0N-|#E>H~cQhM^AdZF(cdu zkCto@e;X)e+~fGGMpixU{f`?cEqD0Ig`JLz!wT&Zv0*8gy-Dm{V(%CG zgxKjAN2rg6;cP@i`!ZauxHw$Vkb{?!rObF>4r7#=go}nUI(?KWgnKwH$}qh&l+kIY z%zU^xWK$-Bi-t1VFnu&kBjssxsHMCg7Y*h8xU|eD;9j%Izl+oqQxE_I9%lv`@FqF}CL77gtwagzW07ID* zxO7}E18W(NlnZ5a9a4`Myq5WhA%h8bWxbki^|aeF0oP*fm^ZNwzXHc`|2Q#TT^GG@ zQdX=h=}y@1J4?HPn-kO~n&7|&TMX&^&}IZAnf43`F}Y7j76?rM*N2h&)ceTk#zs9_ z-<1X?zXmOnjUWpb=VHn^xURv)c=h~z7qDsQNAodUtRO9?8xH+wbi6Zx&3sT!SDq;s zft*ZOdv-4eFkoGE%G`%-ft~Z2RR*vD(*&xmJ*23 zeoNps)Auq8Yb!XWkDXknZzZq}185C`N0&ipn2<1(p;?#d%26L+w?3}rbQuF$f9~gY zY+@R%kG4lK?!V9g%W471@H&0e4Z4@U$H!%SQan=O|npFz9AE6ywShHy#yK z?U$25Hd1gE?D4qRX6O#XF2prl-1A|xzi9nY;LW(Se%9wBhWk$7PQ%T9^s?c;2Urhi zOy9$BGY-}j{=}4> zE_gC*mJ9h3*sNol9R!ATL!KP*AmKS_=(tXR*Lc5ycNut-ffEJ}8F-q3{RRf?*3UMV zBb{}eU_b16f~kXJGi5@s?-0y5zayAw`H^6z@i&5*_S1ryr%dFLdh{Z~hMUHVOXDm9 zvwSq~Czf=wtToOvaG`-i2A*x;5(6(XaJhj2yW@2XY^I0(RHsd)LGq%?T(F8)@O(qQ z+`x4PZZ_~51Gf=No7_q)<*?Jhj~F;@axFky`$71MfBP(+0lUeJID2t%z{=H&eFMTrq9>Of^?Wbe zaXQEP`wu$a)s>iq?EJptSjy{o{2!gO0V(xvaE_0CVsiLss&jhVb(7lDthEEISvOj1 ztE^cSRz|tC=Voi|-&wO3TN$6W_RP1|mRYk(tc>feJ)g2V4yLT@+ln?>*5J^>;(m+r zr|lYc(Xg8yz3JJT{_s%yZO0$Hv*^M9bJNe9KdqSVSv$$vuqV~|)wXY~Yxi0idDb4k zwYI?8(`wE7ytVf4t&B-lMzgi2$=cIs&8o99mNEqyQER8~aA4=a&fmAUw{PhG(#Pya zQ-#=znSk_9z1c?kt&fD9oI+oj?TOoVg>AL0@L4s!SdG7Yfq!vkZkkoREfn;ROUv+D zn={+m-rN|*GO%S`xHW8hGc!C^Mc68MaCbr2_Jlph+EZTCZ{Y+gCYo}1HPD1id#Bo* z3LlP6a84}STbkXGmw764&`qxg+be=$yC7_>eJuq|o(G>_HL56VXS|#$gR8x9)i)}_ z_SzGvjxVRyKEnSQ52rf5lv=x+|1)-_I@YDu{(%289!Pb3F}3!e_&?*mRL9!X+MWEL z@%>cC7gB5Q;s1;ssg5C^ko8{|RyZO|x_%(SAgwdb)EGFX=^c<`xNKO{UJw&%9YdYI7j;EuUD$nc&A zQ;vmzppcWyjOhc*9{foe6upz$&VpD4zs&Sm-=k~f}M4DYZwL zq{P2vI6elBg!kp2EIokH@!%g)^ZK1!c5{X|v%bH_?~nVkl2~AQyvtBCk5AtATq?P> z?LMiQJ!Mu#y_Io`m9fOiP^~=UvsT96Ss9D0j0IK(d~dKa=30l^Z#llrJ1i@G_pi9W z`OsBcr$#US^F_h-CH5~;&J3^RBs~5x&P+s97;7}YyaPAx zKRfK)fbIKVANIEQ(Ec;4e(88Ruey`tN5R3}DaWyYM7`rMMU?&^75+gA9TV=GGv_(> zBSh~1Lc8?d)GMCw&Qz|?-bH?%b91KsAW_GTl>LAby*t&Fx5@HkB`4W|ZOrQN@jLym zX63!=w_auHj@Rux9NwFMqSPBuW2e(P>-VWu$1{$mR&Ct#yVUV*0}gFJmhnRX@1gdC zdmeJZ`L(+MJcqW8o%I6%`_Q%EsYsYBa-JL?`WnTNJ} zGVTU|!ijs@UGN#SOKRT!#aUYc`W@Q-NXEBR8w<8aouO*8xZ`|kfQ_+!4Ju^hMaZ1; z0#QX`fkCj!ZgM56oHR%jgD7iXsYG0cB4zD=52n`+GnL-zT+u7O93{F`1%@BgjRNDm zX%Lf@$WDV{j83&d%qQ^$gJ7!5+8;9*rs<|18pIlgVbfEILd2U$^fQPZN{Kt$x@mia zBFiDtCtsE}1FdomX`_#gvj^ncZ>6UCFh$M@td9lWOu?B%`%?dB+xD51Gc?z?D9{!3 zwJh)zgsl8mQzgazYlCdo6-oRr2qwSTsb&x4Wb`>12;6wsJyNaND3@UNFn= zPv{>nvMe!fo^0);t@1S$Gqn9?YEA$-Tbz%ay{>ci7p5owOv*l$LX3f2-_m?!4zn8a zhgl7ob1o_iS*0(ft_{M0{Pf8uviHrm{-Sbdzd&W)a8JhE_!rx?zLkM};UlFdqbT8X z=%iljXc}^QARPhbIny(pi`Lmo1NIxKW}nxxE)H2W+hXgIBi5l3t>GbS!8UM%7OZ*; zD7GN4q%3Q~V5Y8wHNH1|xb#HSn=jFNP_Hr;BYLleaTwbZ<-n?(?IVGGzMHK8GVaIE zI4?%uO!Yq=2Cf*h_2Qbsjx%b#a#>Q1XRk9uhqiIK74-PWJ44}o=E+lV7SMSGr7BSu zH5Jcocrmpam5ch$EoxiAf{HIK!vE4^siM&@I>YqX_u^hGGK}A9EHP{YKKuscwLJdZ zaazS>X@7liIb$$I=MC*j|&>R^xA}@neBQrs75XFAJXd?H4S7jlmP& zs7rUw1=*+Yjitx)pLXZI(Q zi81$IJi&1$q56@;krVvf+1_OxO>zdvR6eiL2Q5DTr4*W{>Th0qug}U1<$4YW{QeDo z|C*jM;lS0!_I40MWxhA_fQPlkQgMcQGsmHijdz0LO4g(&SEMIrr;qa`Z%lUz+86jv z75lnY_&RHR9{*Ly`*A?N{&d?i3fGSHgP^SRPgrOwZ zt?k!c;tEY%sL)k)KIH@@V9~ZU42cXpd6>I_yEclSn18Qej*MUG+{ic(6)@OqOw ze^;>nG*_nb1!*0UWu<1V@ zN@(wZT@G8DbmWVMes->F4+Pf=_h8ryVQGemxo!4qr#vj$JB`6`1a*8D97PptWv!4qr#HiIYD{3?Sd z)_kkM6Kj5*!4qr#9}J#Y^P3EwSo7a9cw)`B8$9t9QvN?Rcw$}GuK-^xGU;rPFswUb zG<#J?K7%Jlw^95^gD2MfSc50lb$X4#6Kna9!4vCv=NUY)*7J7;Pt5eP?Nu5)G5aF< zMuR8T@!oFm#5&$D8ay%EF!g-X;E8p5?lE{`t>+=q0FnD6k|JvY*HUFH!6KnoOgD2Mfs|HW3`L_(7 zSo5lakQbI4vE~P`;$X-VYd+iHi8VjM;E6TQd5wm8^c-jBVypplpDjfRY#|0uH= z{2`IKg$iJ3>A8_I>p*ZGq@EqX`LJ2L2WH!2T%QBx?l^Tm0gOL|@tXmD1avXyY8vX%^EUN#fo}vyJvR)*KN!mB zIh`_f;B~*a2l&(QXIz}`X(+Gfe#(2%@h5?!&W~{rfT4_D7f@z4c=jX8EH`BInt?Jc z;I9#x9|G%q{RDU@c&6c?5mv7=81@D5eCUe$FXsRS!!!`*!DiSS3|_BI7#~Tb8y{4f|IrtF5QBS)eL(Hftb3gD*kvVP1=(P}K&V#>NWUk_1 z2;;@2*GZHq1Rny&xS9(~DKOf*s zMcS|&F2lt#DThEd($8svw~}5&O}C6RVBK*WjGPr%Kk$_m(YAAqe5^*^m0u<3rWkNYg#dWpjDe73F}mER1WZa%N9 zmlbqRhMP->Hu3)?%K{CX-aO-K9?ziFAQ!d?^s24rG(#@aw^i)dsWVrRTNp~sSdWxjG z5^g;m(%l5Np8Dv%6K*}t(fv)hIi)?1ywQCh+}bd|kM(hP^l|^HkNdek?vs7oZ}xG& z*T=2SUiW^1UH6N;)Z3qU?EXW%%C0)WH^sWER0G~Q|89R}v@g_gO=z`T9YJa2b2=53QL3x;B1 z$kBuh%v(3jryJNZFmD01%pwCnhq*!Xy!F(0HZjIpnqp#^nnMQ9MTM46V9wI=F=CPD zEx6`+%dX{li?8w1$e+gh4g3_bjCVY!om|Kf^_eA@ z+oMATa|?BtU~aQsBA8pTBL#E2_Hx18(hUmcw(n@c+!|*37*`$A`)R=}8*X)z=k|29 zU~XYA70m7FTLp7lut6}l4wnh$_F_VCG2~YW=62-mg1KdRhu{!!i(qbja&BcBxIMa7 zFt<>@B$(T*-xkceeOmBY*qkRBmh&Us#B2+bkPgj<4Sa)vSx=N%1^ESnuY#N9MZN|6 z-x)m1l>8d-QG;i>lV1mZiNUjO$a8H}Z}6-?@@?Ro44!pNeiQhW2G4dto@=Vl8$8jQ8~RUz zzYYA7U~b=Y>|{Czz#c4^ZRQfeXMjf;e1Uh0z=s8Q0bdHel(`%>FX9)#PZWFtIA8F~z;gwk0xlK&25^nw zv%rml&jbIxU@Y~m?SdK4_YHi%fqy9YtC0VRfq!n`P6Hn?@NonG*}!iY_+10z2?v#5 z#x=yi!wnoTaDiaXz1szIPW~F^XqFr2>Te6?9DcuG&h0-D+zfjF=6%X@{;w6xb-{AM zTraEmTam+UHWiToa8I%(c=y!CXTv63n$#rC_eP?i9@J?|%@y3icVnT%(P|nvHP< zU{4f$82rtGxuz??+JrJ(>n#z?E$LeX&xgHA@FLh>5zKYsqk_49+$)&t$|Hi+dK2qX z>gPIis9>&7rwit~^?Jcv&qf4uox4^r*S{|b=DL{o%GAj%=1&POhMf@1b@V#HTwi}j zFxTCC1amz;9XH3+!|mgtxPK<*Ht`t2JAuQ3?+5;@;LpM4Rx#ywfv21J5#ZsnX5-@m z2XK++&;N%Ed`d9aL6dP&hCl6pOmI8KTkZ*v=lW>AV6KZc3w{RnBhX_bP8y%gFXV^^ z3I9XkIVavAV-&|^_D|~Pc=m0<{CP4Rm)5yocyh#A=UL(TljJ*s`Lm@hr;O-aC^F=TbzCDUBRb1Ph8(eu%TF26St~N+h;>|BWW3@}eXDTUm$+&BuJGiD z2MOOonM++6hGBh?BOWCDA>sKm;qL_V=fgF)Y;N$wyed37;z7bU$ympq1Lxz?>1h_8 z9I;N%BFad-48!!0Bi8BpXW{u%;!g$hC&rs_>Gb?kcyh!#J$K4D$#HbOftLd7Hn~-J za>Tk#?iQXuH~!4P56O7Qp8$U>m_H4s%NWR?_nw2>9_5x5pLS!u$Po_`zKb%WU767$ zLymZm@Qe3CNPxH9=7LymZm@J~@@iYxO` zks(JsNcc|(&#`JR95ZmUfm;l`&cJO3-fZA@1Mf8OE(1Si;G}`~8o1NIfZcma z7!tbkKHR_@N_3gz85lp`b@Q_gJm0|O2Cg%(Sq^Iq-pu<}gE#a0h`}cfyx+iw4g7+E zPZ{{UfxTRlVEm-XF|gmj;|*MB;9>)p7+9Ud7oFVa()tqyZZRX z25vU+8Uwc(c&mYT8u$?dCk@O!BAplR|7gs;9gR;J_`HF=={+(z2KF0xynzc1Tx{SH z1K(uer3OwIxW&Nh4ZPXFI}E(bz>gc4`ye`x-22eD%fQ^T&^-4hG*Pf zoiE40!wt-P94(V);AsY)ZQ%I^=DmgvTW8>A1Ftb~n}N3)c&C9MF>unr`we{9z%Lm1 zl!4D1*o(azoz5Hs`wcwaz=Z}bHgJi7Z!+*w11AjJV&L@#=5q`>Jv$7%%fOEtc&~w< zHgK1LUpDYr1E+g?;>t4cNCW2@c(Q>*2A*r+MFy@iu=+hq`jNVq6wK!|bbdD(xZS|q zL(?*k8Tcs!cN+LP1D`PP8wOUtyGa@x-s=e-Zs1V{&NJ{d1FPToB&@n86Z3fF#a1HWM4QwBb7U@z`HbsBOE>?g)NK{MXKg~S*` zX|68#sNXan_^zMHAC)&~fAG70cJkR@#P8mg<>D3q8)-1L3rl8)K3br#HP9+|0ro+s z`Rvzm!5t!Z3OJR5f^WDoUromwXO1jeyt_7>7kXnr>A3uT(Q_M4uAVz&?%aZ?O&mn+&!t|74l71`y`BXvu zuK@zTPX+6Lox9CGo`NoKU?Yx0;@ta$Upp6tZs=E1oJZl`rYb-T%B#sL|KXj(o=SgU zz}x3raE$(J{#)bh2ZrSC9$~e-O((VqAOG|80WaO(a-ZG4GynVJ?CAqr{$O{V$R9J( zo9qa*?6;G9^9Ka1U~*x>n;jh~ygbDjn7lgK614rf`Tp$>;|(uPTJrj2OR*iAogbR~ z@T}L6A-;j3<$5x6Y-G$m1?+efeS@NTepzU~O{nL@YWQ9r6wS>q3>Ve^`pgXL_ze60 zg6KV|4LflDex2R5!j7%ui#y83Y-wAN)w00Pqt9^GY}p$&b1xu(P;ym`OZ#j&0SQM>kNwGy(gb8 z2;}UGcFssRqa9C6TViAM(qQzGvS{|9?begqtvMZec?oOzT`P}GJ$*}YQ8er9!R>)d z9*T}U^>+J+`?g1iwzns?M=x`V3IdmT2alK=Dh-rHEY?c+4V5OBpQm_LiHZ*fhS|H> z^l;F4a6#Z=Z>Xpv3(jC*_}13I_fpfHd71Wo6bRg%Dh$sql~)E0_FB1N2D1tRmu|c} zHTH^OUUH?qIM1xn*3QzRz$NR#3pb?)133=`_$~?TTcId&Pw%>~)$)Ye+jsBEZT0(i z`}ZfU{k~)}zx`-37#R7$0PCo4L_ud~ejbZ%Wbny1em*Yu0cVfbdMGfW{l4~=-1g3( zuk${iHHb<~4QpRb9kAMe@i25KjnAN;WVR1{*y{8_-@^DS8w0+gz(tFWg%atZiX6P$ zp)7jo?KS10L{apj^^dd$E^C*6%|7h*A zANoi8M?SlX1#~DdeEl7Pn^JaExm2w=gU$r9J%OQvQvBsUddZn+_QD%p2nKxX!S)vKvMYUZjyh)bnCy=BbE~Iz%sEyT&02ZzJU)bQ0;?)w{vCUyFY73nQ^=$m`&Q1s$q4`n%-C%44|7Z>>QitMFjzJkRY z=Ikzr4vV#niZ$iLROP(+*GIqKZJym6m#$E& zg~7Mh?JfvpZ9W(b41IRXM+>|a0bgECk`6hKH>&WTj zsEKV(zcW$afP)p$q5F=_SvIb8YSeu@T6zcG1c2AOp};);(PsjxSkmymwQ8rv>%4-2 zVl)JyAFrHS<1BC%q8|H@crzPb5wP2kbT+x~h8x$>O+sRW$DgIL;AD3mx~uE>UB|;& zhr+(~|LS#u9a$d#%z_RdB9e4Dqfr}U_%b&&+^Kiotx+$FyLh9W)oT0NzME|MYO>{v zceQ=!!?s}C*2pub{CC-}q=tRYJNABig0tCbd6IMX#&KhZ4e{!fqsiQn ziB%oe7Mm@2ZM`}fD|S6MIWwIMc+DCpSz@zUm~0vaE*Tr8gm4IdJm zl<7_CbREve`{4AE`k!zAh?|C4FQjw=&^+A){4BNS_bI=>9Em;Pnc(bs0|VWMHl2{% zb%AvH1&k)XgSmXyxeZf0RvsHrdUEx?=#gayGLH6pB^~9Ei#3)%*l*#+5gVhv!VbPc zBX?X{5)06y>P;i^YMb9F$D}SbI@(9zk^vHB!WWX{s4pPsCXV+JU>LJ8j0I3!9LA<+ zLZy>gWS2No;x@*B+TECo*FQ1lvH>*{20G1O+QvFPw`H3%#BrQ~k8Qj6;D{gp==9?c zjJfQxnhEpNOQoDq_7f?zX-mCS@(u?Y*E*;zyi5vSkEPIrF@~XTl-Hhq;+11R)W-|& z8^e@)%;O*F+zlnKc!Ghf^$!K^^!Tql6yVsDo0-Im3^Vr()%kR;Y3^_` zn(?~1v3QXcBqULM2c~^{s=32!xt{9fmfEx0PNW>HXPYrTj*a)X5YAjdqL1pl-P$Ju zd(@ltWbJ>-g83GglxcixQI~nz<2z~D9m##$&K;a{dU14R>3|IW ztz!~BrG|gEW2W~W;Lq5h_5T?7CDv{3OEl_-GE@Ma86Vm6U{qaeAo~I~mw~VrJfAhzznO0u; z)MIP2ti5T;vtf4-ZW&?+)}*@5+y0b4a3}9p4o%$bKbmD7^`AP*xc6>5)Uf&N!Na>x zba*#pcZ4w7Uz41A?CdeG^W>8uv}4?h`Ja4v-)h`}xhj#_*{c^FLsD86aPff~C%ogV zq}abGKff+Dr(bSn9-I8yu9Vex>QM8>xl+y=NAh1uJBnFj{hDuN4{(MY@MLh3IKxSz z3zNi|)Ua1FE|?@f+g~>Y)Z`sQI7yt8Nn&F6B!RcuI8)$-2MCj~`EGz5EJQeQczq|r z&kX537o07X*Q@+|`*?RQSo>1Sxx8l{d)A#9+$D}1>w(nTW5&!d>$E#FU<9AKdrrsV zgSE%dgQCG`_PK2*Hyl~LZ<&+nILF>fow4UTK`bRbfovz+$_n8fbRK(=CyE<~H^!Zw z;1qOZ;r1%W4p!J% z&Lu51$#uudYwxNE<7PA28ptYHd{+UEqTF3Xh}d8YpaJ2O*pNWPPE z^N^N9h!857WKIA#51EjO8?X-M!AS?@t>93?cUK7Bp_tZQ1_C@a>{4S=aUrhhS4Mpiz zL7EkKITf0e#Ebb5vpZ9K_gLUW%6^%IY9G!fyiX8IMR#UWOD1orm%3R>26!95=97ykQ#LC@!(#XrkGD;WwU(4UT9-BI#tR_Imst>cXy zD!y-SeUdM$JCT1j%=bRYi-hrrp}Qx;U*TM%UMjWES9&gm&lsI!Z!Pd|4!@NunUs}R zxV&YOomZF-(&OJ8va&4CZ(1x43g3I!Q}ENS?o9 zqpSS01dR6=&xqV`F{o>ZV3IkHR#oKbfb9t>l&M&~# zBD(Q@^FywRsH#rzJD}>TryzQ%;Me-xVE7g(zAx6-A0Hc!+^V#6e>7FObo~78=CywH zQBd`z<-Xx76629-JU@bj(MII|zBeqH-}C$18F@k2bhL3#D%aa^Bdq{g8vM>L~vOejy4EB z2u#DU#4KxuebeBHb@}v1;j1boxIIOhZv(T`$)eJh5&AQg3Vem|e0-6H^2EAck_Jz#>+vwK4*L!;lSlo0 zjGV{Hi37l+1z#O+I&&S4T7%%b1VUsU4cw(LYZyWqp!AuXa2jNlu%G1SjT9APQ_!!cOtxnl~jZj*c*^-9Q4e=RWn6uzARhB}EkA5n&n zL(-7f^BCjW51!@UNQodaC&_k@{V+K!r4KB*>GI(OPCGwpHPt3kR{*=KJYkA(*&@lbPtUJo{R)>af zq9NA2zWqs`4bT7QZ>afCdoztYxG+yL@2JHPGpLQsgQ`OREjcNd3*Jpr2t}++ZFED) z13{c79_%!x(fT;ynDK_-){TzxI(@1EkPzdH!X^(!26i-6NwC>~XW=sSwW9%JFQ?mN z2`Uvi?eXN$_kZWiXCPqa?_!Lmy9|9A*7ec%bF?(w=oyEWTLP@}M7}T|XAEF7AF30< zW%uksxX?89Jq~@8qdw}PA8qvY?z#Z9uE5CBN+3qZMVp;ao05Q= zUzQu^GwLJeV5I97P|cnLv=TTCsJ!3r--X}jV@>v$3*R}@TkD12=QB%!=`#upYCrg$ zGfuB`>pbTn?AH-B-wDFWS{wT3;^LzEVH6tuIp}Ib{~}yTBx{|7pAR<|dl!p*CEQ%h zorBHrx5MTl=riK~Ww^NjxKZ3&;MRuvci_?!GQEbCUU) z_@9N%iD09+t=?}K;oWhfu_O=&)1O}aGu8hWdxe|N*0U3J zqwx*{bMd74@u+VdHkVl9dK~RSxb`4a^%M&GRNo<44fXbo$kE zxuT~FZC~@x8Thb))idgn_fCV~PmD{o2V&7V5`@O6qHc_&bz_FnGIN1*(1&SwBS6g2 z>Q=!FcZXo=V}GO!nvwNw!Cc7yi{Rm~FGhMO!?au~m>U9D34R{@G{M|_SS8pGyg_g- z@Fu~dfc3j6xM?sCx~abm*S7@!BkXO0SvG|zGs>{cW(sCm{z@=!>dy$?1^Z*jH049E zXA5RM+$xy$^L4?jx2FZOK3~T4z_6!bpA*bFUxqe7o^3&&4Qxk&-i?d=Kf&H5m~H2X zV74hfdr6r9+F%wgVz#?a3g$DLpApQqd9%UaA~+2Dn3jS4u3)zDftb{(lWl*vVD^bo zg4tK53T7Xw7t9;m4T9OvwhQKs>ivS*7oRZrp9^Mxr5xjBKYmp(`*#l7FM0O+0>K;) zW(ejDtUfo*F{4FzjwN3eybE}v;QN8^5quW*F9kmW{*Qtm10IY<&3GRN=2<~v#--0t z^M-eY@Er5r70j{lOT3ANd>(KX#!2FZumgf8gTGR6A@F*^(||V%{s`>7f;(aVMli?S z_XKl1z64`6^-q9(qhK3$R4~Kp^U)m3R~RyD1kZzgpJ0yt{V{h?C+7rwgh*k|6}+h< z&pAY&CFI;vDSQ_&KEt6hJ1tY`0KF0 zV&KOhuj}Y*!jmJ`b+lJ_Zk#?Xm>a5p5X_BJo&jMRxN)k^(MWxz%h*niSf?#Vcy7|3 z5zLL#FUfe$4bQI#=BDVwg1LeDs9mlXBFxf|>7n_)(slith;KMr8zJU2X_70eCK*9CLK^KHT0@bn@bOb<6R|3xr2 z9yTmavW4dyqRw24e6H~1h_(DA;kl`( z&R>iCRN=`HYxz3ixsiCcU~V>gWKQ9RAupz%8-_Icyau{YH-_47%r&c)@f$eTz-TxPtZ4Bm{38=*RFrheY9YrfpTbp~!W@EQZR8F;IKcN+K+ z11Al<-@u0r{DOf`8Th<`y&T(7FEpHsHTD~Lynzc1Tx{SH1K(uer3OwIxW&Nh4ZPXF zI}E(bz>gbvuYsR7u)2?ve5rX{u$s#Rr^D9y%`))c&JMfnVHDOVx_t5s{I|2iZu$J} z?66x7e>*$umcx9kEp>k>H*lSS|J$4$Mt`PJXNLu=v%`Y@SRd|_ zyi`qn==7nnU(Wk+R_Mo6{LqpwZ*PC^RI6{}gLcW6?*>ybc3)df7Cv`NykuYZGr)X~ z^MYqNPaO&1YrAJt`|!Eq1L@w*qiIRp8XOJa3${pf@U7{Y{xSTVG1zhVyfMhYYpG!H zEZNt{;werXb4ZRG34Fm9fm5mHQ}~gqJeB%>5O#CxfF1t|LOKE%<0DRr+YqE z>ZE_AEZF|}yainro{TQZFPZtURqPAp<^S;y_JlO|A#YVKD34_+Mp!hqD^$d1JIlr% zD=8z`KK6L~c7lh-{-O1!@9lbsxMJ*EmN!&hz8iSs*t5WGZNvcavFF;hw3gSj{&R8r zf@H~p)=+Wlw`yXs-77txDaQG-+F;#1B{#NN{X(J8?m5|RwaB?)JX1R$ysz|T&#K>c zyrYsc{^{~!X0@p9X(tHVGyZA6#e9z3xHvj>nWye)Jfe*<^e)SdI%)NGvZ=lN&NleR z$99dFgwu1e*dwu6dHfk~e34ai=ku+;^oM+D+kO2De4ZzL_C{aEwfpbe(zd1T7eC(a z>$kV`zIAOs?tG}sYFXFTwl3LPVtoA?Z4vDqs)NDB{!u^lUl9%-dJo%Let&*<+p=84 zI?l(pY_H1qTH}1)wh63e_0{I!2Fu&!OrrBIDQ6PA1KzIS2KpBUy!rk~$y^^kHhXQb zTd{4uol=|OtfO~R(RWk%?=lr-S3HmJ{_?xUz?ILhdVwjs;(7h4*ynYZ^PLX4h3|z@_cXw{8g8cFGN>A53*?V^WRuw0c;=r{BLhb znRy+FGu)^#9+f=mIgmEN&Oetz(?(|gGA+}|OIk@QD`aJE%kWsi{qI_yP^Yz<$Nln7 zg+@M^7nBpxf8^_1Cp#XzEqPFZl@_wB-Ei+J@?BbzEbw{5*G&rc!%;7MmA$)AEZ5*L z#Zx@*r@kJG{`+5hm*ujsuOHqSmc*@3ZBPALiXz3jDrNrhiZjht~^(Ec+E`JG?}K45=*?dvKcV@$)z zdOnkWGXGq7ap}rs1MJ#p#gp&ZYS4`PyR3{5`Xg$z)&B?JmX_TuZzbU@^B;$^q=a71 z0FVC|Twfl0)Z=)Yqf1LsEdyVS)#Q~}$pcpC#=IpL^*=E9=#W>ecRfy4^6}Qr2U`F6 zzI!*cx82$PVE(P4%Q*SB_lq7{$7$FA_r-jMgveD}Mw&C$-! zwkAK(+EQVcFU|kVq!BfXmO-LC8YmByLn=1w&Z3#tqSdqYc~*QQ+#qD~}!;IPJWDRT77K_n;y5KY-5> z^J#W`fq4@GFW0SZg2Qi|8{d*f?^&Eb2Pb$3gvZ%9Zj8@32XQb+9qixs1w=QSCwt>O z^FEX=oC4-|>%|p-tDxJJuU$<3-cp{XbszA@xb^Pm-%V}&frZ&Id_L8B*wfOo26>N< zTHJFYsA_Q(1JY>F1)~<>L{N!35mZpMNR{R(v}Ne=w0Nuy@22A0+Wjq~!tbPF>wE}M z0X^oZQMI@fCm@uf-deDUqUwXU?_J3IRC|uEHn1|EuXWTTr>&epW!w1C z@xbe;`|FqbX4~b}$@20&dpZ zMEMpUM!T-9l#Kgd^RLL-wZh-F!Y^l_%3llG{?$iQ_a6_%?XC)Yqn%r{A-gANG22Ih z|8&cwtk@*K5y@!|Vcq4MO1+bke6gLOfH4rAPmRgGW=ybVOhGA>l=)u`$-Mrm()pS@ zsTY*L24~QJS_bX%(`(Z>&{jachO=Hp`K$IzTvwcO567Z)<2&Si!?=a*?@@|T0VOPk zBeZX7^jztY{FC8*fmb|_pTVh=%y-#5z19TV+jdoc60J6;V1td>$+|p*!$5hH?<^>_ z-J>d3?pH?+<&6J#e~u9f?`FU!p-+S-INgVqut|636PDHTdH18`WmlYCc0N@S4aaJ- z;_c_%naY`>r>nCvUEQOnt9#sO<%4w~^JSH1og5az6$s8s3RX&Ro#(&VeM$f)B(sJN zyJY0$!BJz!ji31MJSl<)TWat%lZk&jCGx-Nln8!TQV+;^VUNc}d#-RhU~}_$xQ!q4 zU~`j_^3$-fNVzW9bn~Xrfwf5NO|a?zve-IqTB>0sg&mXmE7)G}h$`pey0@sR*A4OsQx8wRfFb(B(o1**+;4cN& zic5bSj54~tQN}?VWBF3%)4(*8(QT13Rp2Lrqs&G_Mz>SS@a2v(MCN&5G%c036TnD@ z!Y={SP`_^54EqLnwgc+FoDC0#GQ?wGZ^t#$;EBfy&%QxJdEHN_lRt15ful}-G=qjR zx(`t%X~=lcmuM)X`xj;W;I9NnJ^ay`hBCxDk2e}TF}HP?<{E=1=I>nOn+=|rPV#pc zyzbjf!+P*B_%jXXf&H*4KN9_&JTb=r8m3K;2MoIvyl%s<7&3aSpv)WKbwA>VKWM0j zcrVxk$KjT(c=8QA3aMUxKl?X!_;vj75;lo)pxm+{b# z@%|kyQ{Pi)Vw^6u(K^^gHKt!V#&-U0NPTRTT3-z?gL`n%bfJ*h)wR*M0fZ5abqaDE z(zMZjD?rHTqP)ULG=C%3M#C?G(3pPweD`53WcaNCHuJFtb6_z7G9P^WLFeNeMi@YA zAD#i>`)Re&apAVGm%hDMyK>a$6F-(Sv94P{Yc~Y`kwA>rM_ZR2y^_OGhKQF#IkKeU zVi|HoG4-`$U2^1o(g(4>YCia^1zSpwNmDg#x|y>c^TFTyHEWXTXO4PInuS6(Oq!~Z z9wH5;sLP3M)Q9x2oN3qwv(d5xu*q?mNjHbr$%dQbz#?4iNA$l1wq7>U-3&LEh_&MX z1=w8njS)B7MG|f<>nMLOY;8DgJfR)1>F&g(mt&Ma2De^%(ftP8TxMMlo9+zg=F*Aj zp!;ID^|FUsCW zzu(8rKoU`eN7+toIdWG`?wqXxbN)a{zf17 zeSO?d^l?Ai$IT_WHcT(yudWTi>s6Za#;q z4gDYJ<9@P_`$!-6t9{(IF(y)9wzw(g!wk&#r)$G;bu`??sN-(|vp-Dj<39^-wuwu{ ze{moGa=5v)=Rn2q%li1=4!2%9)Bhjf*2`qN?}l413+d*!^7ImrZaz25v~wiQ<_yq% zHVa>U#*1JYDy!AGrD#P{BvCErn$)+Q@ona++NNklU3H|gGOC0$U)}J&bW?RhQ+1>w zT6t?@O^pgrRT;risOqMKa#c6rI2T^@q8v+bcBhPQzze~+>|S(uC}2XiW7|y3FRK$s;s*; zQr(~=)cLPwgQ#D6dqHh=HA)N#;W;#w!ur}KR~*`E8*1I`F|7WycA`1bR2i*v3z{BC zd5pyrSrV;9R8U4%<%(a>X12)TB{{cr;HVk)UUbLy_3*IZ@wTbF7IowAnO^6ucbPo|$S1ezGZ)&@xqNwVIL^Ybu z`*<|hCf<*)X^dA^qaR3vRZ8MjDt!vOEyAs}{{bK7M$yEP7d9ibKb4JmO{}httaL+F zm^f=mwyCP#kYQfk+GeflGn`ZMdP<|`*yexIdCeZRfBod9suH#iX7)dFNV9uD#Am~e z53%UVSiL` z9&E1Z$(O+9JuUHk*j(Qe$6(hBo(ub@f*I#;1n-1>O7Q)#`BNdo?t(o5X(ndcuN6EJ z_H@C1*f$6s1^YI^Uxu9&%(e3kC>!eG7BJTl#9gp`u!&ht0l_RkK95VD<;wd8Vs7Iu z5quNuTLhQG{;uFnupbk=8FoL^7sIlyMheb_jrZ>%=Y^m!EDzVX!DfMgw2O&h}rgM2xg!7o?vckb_m`Io9i*kb1U<-;4at> z`V{#WfWv~>&lUg7*%@J)rOlHg9whwT!t*DP=MX>Bz@Hgj6wIF=PT{h- z5e4Iwc1VtRknn?r=g$oMb~p9#r-g~qmbjIlFPPi(lLf2x2(0t?G2wGy6YD%OJasbc zLc#pmU^p%vR(+ovGUSMLSl(-BnR;OAAxErbc#fGoe-aof?U_FbtbyC+AO~}`@Z^XG z3BS&eiHHn2VlDHI@cbFzCTXkOcIU--x$XWV!Q6HqB5jP@=-Gm~MShWBZlm8Tm|NbP zaOph$T6l8AI*)%8o^6@NmTezYQ}@|0L~ZHsl5!5Pxq$|gh0ErR9L#WBHuuOUcX0_UJK$nAcRT1}R-1i=i>rv4SeT`_?9mEZb;M&_93vj< z;skN7i<^nZxp)=vl`d`}#y&008eBFr4YTh5viJ7!Ra9rc_snGHjZ7c`1T0ba9zsYk zf$R-xuwZw#AqIsuiI4`An(TxC-a(TP1wFCuM2x7|hWG{+?M|eYS}G8!;#<3eG=w&` zfl>(;TA+Z?Dh-GVzRmglX4Zry?S1ZZ&L7X`d7jU`KAEiVT>F|eYu2n;v)*Q1*wicw zl~v>kHn)(`e@XWQHkAnjw+5T)wNP0{_SqaJPqKMEnTZFt0h`K>Z@7)v)T=GD-lHmC z+HhO3sZ3zFZP*-poNtoZIRzKNrgCfrZU;7Xs)b57d78~VP(yC$g^zL$?W`tOCo>AX4du8LYw(t#XemeHWkk)T@p5jM@j6KI9=jwiJA1yv3`kp zNsgSSceqsIGKm*STqE&vi9-^vl(oO7|> z>~OcldnG<3vGpCG2>+ZUcj4YT;aJ}R3LWb^K*8yf&SZ(LI*ibGVo`K;jb;pOu*H3g_B69^vpPiBl!Ez5~QQ-Bd|l zAn|O8+4gY4td@AW#499jk$9cN8zkN;aYW)CiTflzDzQ~p#6H~@lALu#C!WJ4WjaONPJFWw#S@s zEE}RCeXM$^;B-lcbz?{0FEQI@j=WUjN{KBSq9V)&Np96qh5QLg9+r5c#M>m^A+cpc z6xT*~fO2ef6R)|(ExZ5fTQA>L*IebZ4*0LX_1eKY6XHJEI#W8v8AYX(T?P0~$E3v$ z%eighfU@MQZ=JBOr#0f^gpoAzhl$7Mi!$)J&Mr@Ua$SJ}(>t*6_e!d|#8npJV)ezD zd*^bN_LsfxpC{W$0$|p^i=Tn0I}v$&6;Qnwv-j~eKm=EG_v*Jzs5E8n!@P1r^*;Qs%iLSD z{H|p&3E=k3z2OaGORhD~H*Tvvxq8GcgY?8RVe{}S_Hla~_P4C$S(>W%;(su6uRczE zYJ=~ahT7I-bfw`l{MdmX>o;$^>s1#6Mmk^t`x2iCyASxSZKRQTsHok{DKCz$&Ysp1 zHnQEJ^`j5MMp*xxh_U@2ZtZ2yT61$tQ_C8UJ3Z;?iRyjvUceqJ)@Q1Dla5sL_5={g zrT&7uZir$eaT^Ou$Cg}WZn>Z8?V0;FzsRd?uin>i5`I%=pL6+r*saU#b6e&}IF_qcsfHU{vlI)?Q?WD=slo z>WWmkVAW-rOZVaPrrxUL{yE9`N&@$rNqw^`Qtt}SN#49HnMM%raz!k_#B?YKstt8%o)E`V$j&sHAcmm2&OxDa*_+Y^I3wb zr|{u}=FZ7dA-BHU)ZAAC@l)W3w;(H~WhUr8rqXo9My^nOTX2V_!br0W&+k z@E`gow)7kQ#`epU{^b6CuX@}>2w27|kgR`{80GiVKAC^-%g5h>nG@T_;ww{A^rjbn zs5UggbWk2mH;um^A0Zjx%7|rmrr%=cH^|lu)zXzsL>OK^neoM~vhNzyl1cpoVW-$VC{cM<}yWbomvfa*5=)njFgps^QU zqu`zfgL{kc)hM#Nu}{1Pg8RJqjMuGb#=dNYI$Cg_5$;A-i7-n17|cbpvot7H<&=w# z{D>qU3H?kL0`S7<>=?Yf__XP%`dxUgVD$<4X)g{#2C*Jc=TZjpcF2mq^$s17@j80< zH=bM_U!JjLSMB+>&a>v1+Nv|Kyn}dV9&;-^hgN-T_diiS=s~A2K%Ad|om1G%`q0ji z|ADwU?>7{kMOHSo-fS#Ma}mp+|J!anp>{cEoAQF)EChNtubJ282**Nb-Sk*XXeAKd z8j1E>gPMA3V~?rVsXbP~OoS2$*G;s(U-CYUTYSv< zgy~pZd0*p+)n%E<=i0h!jXiPh%(K#aY*Hc&D`0b+!ze#?c{7sne)|OPH!Ts5nK`Z{ zULT5_4r^2~O3JX>7c*F7rd0hZJZF43q+gq3#IM8gE3W73zgl0URZV;PYwro` zJ&JGLRN90*nR`(C(AD{wIl>TDD|hJ8_(W35v-m_aWxYNf!u$(Q^hH8D%iF>^&>W}} zSzmbK@B!g~ChCuPEyU@|Q8gJ?(@-DbLxT|X;j+B`f*jX>LBD45fPS83G?WoOgreCA zW%327Wt#6$%~f{rsfeESscAlRVI&OZBYU%5c+cwkV1$u<i4i z>wf<)Zyt95wUb=TV#F4@9`6@F{5+g>yM5;WyZ@{gc;l0Ic~0iO6Mgu&x$2K;!{VyO z#2r3n;_*Fv)ZBg4EHjeFryeqr?N@yftY5iQ)YDKa`5XUdsNRES)?ir0!VaHd^$^Ls z-&FrX_)vr0P58!41r>k1U@SEp@Sa79FuiGO_1Rh~wcZ`j+AFmFNME)7$KkV1W2QD> zmQO5+Cap7)Mg3s9PKf5+p&DxxP^oF-4mme^D z=eOKG2d(Pnc%^y1(shT@T&?8auEZ=-x)vzS6-s`&5_6l z=ualhp1L{V`z7P_z@}F_Ha*ZDzWdg{-MatQowsh&kBpn9b(JgSI|o9~|DKW`P`b*L z=0}y7l}i2!hT9cVnj4hn`1NzeMR;j3Rj2;8{cLTIM#hPPs!r5xa2oL(h(y zHDuc0`RX2}X1j7{=wR}DFcf+=OGgpEdo$kIhhH+C`Y0>-tc)6}dlg>+S$ggUrh;$6 z8T+GQK9IgU&YUY6cq*s5rha3p;R{!FY+7BtIAv7brZ@Cs-+gOx(T~jDB`x!+!ZA!A ztm)T<|JN${*DB4^6qLoysY)0Aa+Lg3r8!&a%2t}AvGj4%rk=Or?u$!I_=Rg)?5sgr zt{S64?8{XXqXM}~jHWc@D#oTQMy{&mYWcr0JDbe>7x}+ygW1_==KqxcyMAJJhRpo+ z{NL4XcHVF1xAA}1kIl~SoB7Z2f7d#*^FA~GNBrNl*6eIB^VgVM^8Sj1UlocEg3 zVxNt=FDfzq7p|ChteyP7TN=%~OdqdcM|C9T_r#7|b!I50hp25@KXWwpo4ZY2K`;$_D(F=!*F@_fjTzea?skkRY3W7xOx~Jy*@F$$!;MOu)|6 z>wP$K>xC*RpP8r7Z_-@uJV=zFyzw7BbIMj)Rwb4qbOfRWl2}! zi{{77(#v66QuXi2&(2VTok>}V$awnu-gnJJExxlos&?61lUMIGdmn3gW@Q-p28NH3 zS8|p7Zz(a;lrH2avA55)Ur%_O=`oFOo9Yg8 zc~PA52-oOflLJ|uZ^x7!>aQ-UMmzG?r0xi-Vp*)d&LS(WGxwKf(aWZHt2yu1{yFSG zGR91IyLS{CZoA%XR7}rGoTk8pFVt=0SUHt!|d9S&> zZCuPB@&D%L-T43gm|pyUvHAD-|1Pr7_I9oLclbXc=C}Ai4_Rb;`$I81@qcUcZw78I zUW-_4C0^B{YsVya+QS$UN`uj zUw4(iZ`Pq%ILdq6EIMxbqSWFim514E&eBoKgqp5(9yU=W0~Y8{*ALYLSnA@KmBQA4 zgqNOczrY&)Ub~NlSL?XG@LE>kTNn1}qu>X}^@Xg3nTmSN;KIJ*=v%7BCT#h=+4*~_ zcT|VE%j1efl|yRJ$ydkgDc@Dwv|g#j!V#JkXs;b8YA1^KECTK=I&GGJ#OuLD;8Nmw z9c<`jwp?ofBkp>b3Pn8{*V0|fY#}N+?AeULlPKPA%2)sV7S^o#6zA6%2edc8!kdhk z&2~&dopD+)fG&`-{hTynnJKDj8%}8-v zNMOQe=vX4$@tGGj0p#nfJo_EU=3C}nak{Z25A9+je0u~R^8VS}a=>hb5!(06b@9+{ zpYWOTV$x=-mDGO6XL#k~QHH!DD^IZ(%UY7x_D6FyUis*hn{Xn$GD&o3-f^P#4`%rv zC@-FH{KEP|cN}kE+shcU&S~we(+zbO)6KG?4FAH)CE-TwdVl@3cvH)VNaGho8vSd? zX}EyQ=@$#;KtSb*@B=?Hy)Rk8jOn${i#t1AkI^4O0#x*(R*5pi>i1HAVwNheejIDH zn!2#skdl4j`9Wx7tkb~uH_kg8=bibWIE`WbV7Fceng@36)E17#5otUPg^buR>xhe* z39*uJppq*K2U;0+*cUY@Y~e!vdUWF8=E|*Yq!ljuDkm1>a3Wo^tFRXp49u%nV9hi* z6g(-9w#M9A`?(oft746umM0=_8oHMKe6sgbvnCkEy=+SB%r3=!j}*>xheGwCIc^Ax zt2)s^?5=;cb^q#9W?;sx_OcudQ&HSs>sxU~0i6DROGWzUJ%bEyJ)(LN7Q~5Cwd<9h zrk-jPJLubFHV}OVY~5jUnLZM!yo*ilBG|yK>qJ?C2O!hwps~8zeVG?J3D9|7wrFh0 z)n>zfUQOm+r)$|>C=9*wcIR>(mI$-z!_Z=%`n~K^AH;43Epx9DH?}0(MEAiStNhw! z!Zf#Qi8}hhvb$R9Mk=Ag`WtURXGqn9ALu1|toLoRIBY(O8F0D3Hr=Ub1FmYsxiBx{ zAM*gl48~*>=`LIrF9Gi?>jC~+|M)v`EKZBZk{Ioi$iqVC#)ay=$ET}i}JTvp-rtd_g#x2|LIiJf`*5Qxv7JFy#qo>ex-J!=A>tax1&eyK&d4Jsp zooKILb{bs}ADU;b$O=Axbm0|R?2j+i-=4a|(67-)3_N`EHMDK;`+r~&nX37Hcr9p2 zgOq~$EEm4`I;gy`RWo)RdLg3ii9{ME>3j7woTK{Yl&$kMJ8s6w0g< zUSHIF7%h+D3wv2bg5oZ7kMX$OWoWZ0V?3Bx;A2y`(0%q_Q`JsQ>$yPL&*wt!mt?)* zW2;`E_O#$3u$D=~`-ujlKSIxDwJ&U5(+aEbh+(2u^r6{hn)*`Dht^|Y>>U_nK`*AA z?`z-ZPeEg!)2X>H*XrZ<8Dh;qUvOW;KcLcX^oenpV4r>|GnRpI7(VVzL1wJ@A{wQZJla=5XQ+Z+;4%;rqc&e zcqzkoL)i`ggz&p#Y`t)-t;fm94386v>3;#AwX{lP;8OT2@L_ftd>T2K3V$PhWVm{= zqWIyvhT0P`m%}f_emW*z^7s|-bKuX!gv(U;>qp@?_;kDu6+86Pur* z#A_h?z&Mq~*Mk`c%I}wS9tCrrAmv@)(Si?yuNR!ET?jK9jCO^ke>a$p*W@@Cj>Dhj z$aG8_#+iN>wkB-9#YV?to%=zZ6WHhcMCy#i@!x~rj_m<3lELC1iEw$Wa}RlJ81hQU zc&tmqKRD`;d4H+n1}_0q=P^mgx%bpr2l;n|j%92F+>Y%V$QQgn+o02D{-?#}D2BrVjHi z9d(?1Or1Eq5XM19or&Pzz~_0-f}Q+>#)`uEr<7j}UM~10uyZfEz;q1Xc|I8aQOG@z zG5lyeFLcx)JLxuBl9M@?nfe)$oP0fGj6*eejNl)FS=XTaIZ5AnHW`PFkaKK=VZH_) zC-e_V`ee>QW;kC-aMLAFcpZY8t=&0|M z6Vzu1=0eD*|GA{&lp)m7QI0U3sgnxMfX^^zff*i|A0{~Iz;cIm)gu(O@_? zNpdnDVakgoIoXlVmE>e*b?R42a0WbQJY=OsCr z=|}m`B{><7j3s|nl9QeDZkOa_=e&QAK^1CHD z*^xI$aE_fO z)pQJ&LC&&~`DCA@Lq^rnO8*ZeIoU1btb5WiOs5{oFlR!}IugTNB%!zp*%Vs zOAf%N{4+3LVdN;(W$CEn)NdJn3gmMkYr=Myq~p|msnZSl_k~VAUbr8D8RnGX_y@-@ z$sfR{d@L^(j&i5&%y4obciwj;;7t5Z{U)#`n00JA9_!S%dF-2zb3vFUY?q>j@IePjy&6uL!Zp>sqdHMWJk{DgO1^o z9eEjraIOO3lQZz||7xAN|J4$6i}CII|3ji_?a9<$KJ zdQQ`l;X2{*HRCYlJ95z5hXYxfM2X*+MXtie@F=5`*Dc~cf1_iwms!QpJxFG}ggl9^|)67>0+1XFKaJW^SNAg+spbP#` zTu&bS6WCrB``?A{IHqeQwlD&tPyJ=^-MAr3#Qr1j*);u)*nbv2o4loBe=~e`#e5rK z@OYlraSZc>E<7?PpxHKNb7z z)_5Jd3~vVZ*~JhN`&=)M-2i3q`TG+1PBWkTTrbXXJl~3o_FFI7ce=TF4D~l$^!t{J z_MN4a9sRd2`n~s}{R0>6AHzPI`0Vmxd_TiJn+d#!+#f7GOpMPJ7wvm5+Rw#4tE$fZ zoQr){GhfBA4Da@f^!cry;}|}__j4TgpSx&(!$teAUbO$ai}w4l?^Hv1{{D-8cS+AY z&o>PFtderwJnE0ZKC6~9@f-KO*k^U|ZjnCU#6I7J0ZTthnZv*Hm&DojdPPtW|@mto4mFC4RVE)@>E_b=B61ufEMrn3{5gyHv4LOhlhoRKL8UyatOq z*{dP_o5j4iMv}B3R88IDJL;3UVqmeOBYvi533+mR!sub*TGgnW!2IuA9j}9 zRlU@ba*-qp$}1~vs9L-n2QRH!y4VS8>EfjfY3W@-YA_WTzppJKW+ltj+42txFS&B@ z!rPYC+*QXPzAmV#yVI6%St{qYIjQS}|DVZ~8aoabvX-)xE2r^vb;}3t>p(DA)vZDa z2E||(9}DiPu~#r-M9ZtVx|nr`7Tkd#?1h~Ev+(SranEimudhc2;E9m>3+ieV zD~P%(tPEu>)8$+dB-Uza)psrv%iA$UxHuWsdc$gXRvfUx9&^!cRpnT-tYXmuEGox3 zv;EjmgUeLea_dQQM0U2bn*h!??5TKW9b3z8GTW1IEEgO(_Z|JK!Nc)f(|rdU8Lu9z zo0E*!f>JBwd^7XiL^;F5@UO*a*(!d)C>E5b1iQh%6pSjHa!RljN0c=TCmnJQ&5$#} zbFh);!5<^^IUF=mFo%iweL8hG)RPT8XKj#$LQWYuffX>g1|jE=(MrJ_O6nBM;iEqb zW|)5w%%LZbh#TXWB{&uSW?ZO~h8xKuoi|8wHX9wCYLuVOIw6ZBu9Ub;;@N`n+ExlB zIh)T;I2%xgJK={VUPBh~d4kMJDBMbk*>&I?JDJQjCmg#Y9F8FU9Dag)ovpKiEW)JC zXX@O7pOPefoh;%&`_QV-J~kEaQAeIa7U!isYDZ_dq?07+u-nJc-;50C=(CH-3G)MV z8#-}2A@Na(50LQ=qoe(A=h(eu5g&FrI`WOETR8gb$>Q4Ak;OHxk#t%lUMcCbpG4)u z1;^nMCmas1ILx6Lhc}>(=J0xn!xA4t265utM;3A0D=~++oOoK_i3=U;J9oj^h?jG$ z^)0-RTi?`+?g5?gQT>_yD+G@FDOO^qQo#?we_8OK;d5OA>M$)6k>+Hkae-hr{CR>?;a3YzhtG9$ zsn7fKf?(b^t`$J}WcWRTd2dIe%|JPaPdQXd{s8=I!Tn%Cz$#D zpkNMZo)pYy;&VwJi{BVNpPO94e4g6zd{NHl%!6l;%;zspFrUj^f;s%SSMVbE`vh~C zk;9HWwi-V7$u;m#39g5);(4chIe3KN2JokXSsr{Lcolq8Fo!EI#|xInvi#uCB$>mK znSwdoH&HN$wtRv){B@OJ4w2;u<}lhf1#_tFI>8){%N5KayF9@h*1JJ4hyHF9%;CXV zf;og(D44^Hj349q1mfHvm}Mb{O)2M)+9QHFjQN;g4ym;W=CIG>f;lwwlwb}Ytrg6n zwsnFz-1K9?9Fl4m%wema2!7SrX2o8gz5pQ10 z2Jm%)`A*=FF6A7~ohf(~{O<_97k;r|4*ks$8~~RJ<`Ca4f9ugZ!8z=d(ol0m%O$$@#odeh6~fnIJQLxQ-o}X`3vV zX?umlSrUI!(k~Fq`~Drlyr(6Syj<|JkXH+4`1eZupv0|$o8X5f`3Av1g1=Rg|61Z6 ziP?X`>ta3VR>2G4FBZ(Y()R_k4)v&D)~z_S%40dKx>hiUPuB_NP~ndShr#WFIpp{g z!5o&{Aecj!KNrm5&6fmo2y}~J4wG&b%%Rj*1#`Idb-^5xeM>NhZFdVkggEaN%zEO7 zf?0ozh90kl^-8zkv*0m;`@v~~&w}3j5X?IJ{eoGSe_Al> z_`eh!fxlg_8~zc&Y!jRkoDToA;7s^wXge?t9FqN}V74uC1+#6DCz$PzIfB_PVILTe zI9Tkux!8-lliH8ipr=9}OQ!4dG)f~Ui0A0KtthVu)~gnzT( zZ1@d=+2&&(AobZ6JSLcJ#7_jTg8#YT7Wj9fqn-L}Q~pr!I`CS-YFD^i4^NUAdTtnAmbj;S?kUr zUUal~!tg00CkXj*A!k4O8f>bN)BXwdDI+`jmq122rHt_{a!HJM!O|>2&|5^!#pA6l#vsJdcFLjDAG z#@jlV3LVPG2|~VxI#=2{9-%`SIYG$RQ76;Z$r3u0krRYGOr0!S=Nh3y89717*HcHt z|64+bGO}}B8>n-o9nK9xhcdDgpN-TJ=e=3zP)2s*vza>Lyz_+)Wn?ElTd5=Bvq0!j zMt0(}jXGD_@%ay-LmAnL&uG+}d5_q3WF4B!skL(@E)$%Fy6)YA*}l9-Fx!={kwsaz zL&({N+bQuON#`pe=hR&Vn^QJ^lZ-g99hWBRew1^HQ$}{m%zG%GV5iSYp~HGI>x(=W>zJH0;5^HtM171hvhysvsFQ7nbA!;KjGQ3k zan$kJIq zKAAdK+d4dk$5KX45b{STpJ?mkfYobk{vqYir;MB+CyR{4@B)D36`%nosuF z$BqI!Ygt!Oj%%choG{JS!GcYeoOQ_^)W=5moRCvScJjjnQ4i!a!%1XuzXIf`_OUbZ ztngf%PI!-CPBZKkd;tC)i8q3s`}?ktQ$}{~?+8)H8w=kM%;|@ld8~-@4MI*C*@<(h zkaH?xrC?4`+{$Cc`**RBQ$}{)%PWPPQx|s$W_|Ndf;o+G259K53;o{DUBIqp?|f+(}WJEL*6XO%OzeUbT}RIe!-jqxlb_b z#XGP$dEn1NP8r$B1N}nIy79+kQ5PDFeJjrJzaf~@Ar}ee6v%GqJNM!aA*YP&+zY0* zin=Xb95!bx21V2WLY63nVU-xK!dYi5E#+Bk^*HLlUo)xJBYM z5{D(;An|62w@Dn47&wqtc-;-~D2Z96bJ8#o6 zrY`Y+uX%2#KgSoH^x-(7!`4`^xJUoJ=DD3#|F2o|T-+CH&2zyg&`;sqJAV4=F#ACq z)+HV#ajL}G5>J)5K;qdFmq}bL@p6e*NZcYZZ4x_i+aU2)i6atoEZNcTlbCZ^9eKaR zUq~E>{t-uKxWsOWGbPTEI8Wk2iEov7k;L^9ha_GlG3|{x@v-J|i2Jx%lC#gp(dm|W zuf*&Ra&$hB_?*P9xC=T-5~oN^TV+l-lO^^`JX7LQi7O?pk+?zPl@dQ8aaiJw5^s}u zhs3=SACUNj#AhYu^mOOCbcshvoGNj)#8V}v?JFmo*%FsY%=H}|o#hg*kl32rBkuJ& zNzQd4onyC39Fe$3;y#IwO5888HK$0ND~|mzf`?1&mN--59EtNJE|mCIi5E#+FL6j> z_Q5%EU>}*oR=<{$|0VgG5_e0ySK>nwe<1NWiCySxa?Zv6J%>{yPM3JH#D0lqN?a;& zrNlK7H%QER9?p3=H^Skt#GFIm$T^PgFvr3j?vC+~=Y(G^@p6e*NX$7Nj{Z7{IXAXd}6eb(&wG+Q?BVdlwj~x1c-$k4L`waLdClhnhU2SFT&> z{oHgf4_`Yu;#LYY{0mfsZZd9~w5;{RL+Qx_$2<`E=JL?;muu=gqnEAwY1`+f|LO3H zlV6;H13Jcp@c%XKrb#y$H$48~p>g(6ihHTcUG8!hVtuhg@!nmzx6i?%+U}t1-YR#r z%YC=&Ud3IHf45@-bN0=t*wOu;6mzj~cS}ldq0xdhx5i~-Uk@mS^;pqg_fOxvXgC&` zFL0IJv*Mm)f8mO4 z*$-pA)>2!>n4|W(gej?9-BgeL*_O43;}VUEqgcC?iv~tT&`D@5{%tR#&&9m;SP1o@ zdZ9ifXZM-%VcFW_@tvie0nf1SrfOY3RYugOC)AHvmfp1Es}YORTX%dp;^g@D9bb&N z_DZbRn$S_6snu1y;fXgiDFextds#Y(O`leYVH z)7J*mD6@3UeM!m!$g=d5ih?b8@HYPCK7Gj$EJue0Sa1KC+Nvf6+FbUMfoqeS)Z}7M zQfQ?bTIqe*W3RNo`)8I3k|fw3K+r?oS8-&bHZBX6JoGd7X~#FK_bG`{p?wVWnu%)SkQ5mD zIUa#D^r;%R8`=j7bJ}W@*}d+(u#xOmuzvrrY@=1T}cq?j@@B^oy~*Jt`tj}}gHgMF1pyUY7(Pc)ue%|%-a zv9fNsCbKzMp42=W2QHsEvaUR-tH?wyQ2x~o#iGX6dj02%;*;mL-LpEQc1EKSzCUz5 zZ=B!v{FL(J!?c(itksJ3A*F2zcOQ(tch1}`?TJc%btH6LJ#@kwdQlB;@cwkdb)hOX zeM{LQ@3>z~3fI*4{In?%xtAIEp){kfZL|`0*N;a;>IWUPk3}FC4u2^U- ze}6*%3PB;D=0Qr1=dpr%!SBH_YbUJ zZNIlz7Kbqo=Qz{+!m{6k{DwgtyU3n}(l&f@cYIq$?UeHUoyFxzySAJ^yuIxZmYEEc zCl`HS9*ixHcBSm=d2mhCl=7CA=#qOpx$m2YPncdTM(oDow8H8S4gR3GfzgBX?RS0y zakdwdPKB8o%QQd?L@4i8(9Bod;EYDg49YS|sK-LQ8bvh@yl^;HW)*gBVj&!HFewGY zv?!8CrtJ0o;)5d|6d=_Zrz5L#53LQaiI1(0ZV4YldbWg*hSOc)6|V5juJBW?N9Ked zbUm{&yw>%M5q=u~9x=k9)OiM8llt_xqVei{OWRyn|CXz8P75rU6&9ZT?qv0?=*^qY zDhYliv^w_0@{aOhD3`VJ;f1$szIIM=`OsIdzANnBYOinYdBNn8#y>Ij^>Iq+Y0dpj zt1Q+$!#g~~5YLpoi1x_V)$zvaxc1cv#j6K}!z&64SGe6PT3S}rtWB;lk_!!Yv1e#_ zt=m}eVC#ZrWwc*;s4b+pt->$zY^3Dj(}#axVwv66vG*Ed?}1kH$1p{f6ID zm!lZqLb>9`jk8}WxUD{8P=}{^B{DwOtYQ&PnEw}T9g4?3&|Ms2~ zxWbjzJ!y8`J}11u^+;9tVb>#h;fL_=_PlUe>byL^ANM3H`jgpemdl-8pB0;ZeM?zh zOYj#TU`^N?uA#K>tTJcw?Q;TSn~TRj=nt(ZEL(wUOyS%WxVX@qWCk1hV&yl(fF41HR3mdmzBkx?`yx71VMwItTsyR)Je73JiPPrGr_!VY!xq*;mT zpIDe=q!g%&k{8z^h_XAqi_5J8daYkpPiZVIFQ~O7upopn{HT?ya~j8|-#F16U7}~h?$;u^u?-!;%JbjFk*TyU{#!4%cOJCmqrP=h7Qr8xM0sSBI`6T zU{*+}iY)xqyZX?tn_j_UvY+z&tG_b6U-3juV*+By4o$^eo9lANvfV>)H4btDesb=$_dcu~o| za43RHwAQlKwSfhx(JUQsnSx{)MfSeS^2yG|-xl)U|As^TeAnvzZSjp*SNP`#Z2hwG9&4HW;oeSl{Q45G-daof9fB8Qau*0{+k1X-GTBXHB7~6T43-P!;_>wZo2a#{z*;O8ePK_ z{UPh7^ZTkH>FhA74$WSQ9FOeNH`do+H&o;tm5z5Y~%Xxm1KRY>jk^5roo_pCgjc7 zU2^ne&s|tJd8)UbwRWUG%U}QVbz^Y! ziW_e(j#fhc`kFbB;(Vp5^6!c4R`CY1z|P-j=_;~T5|ea+Y5)=e8?bdH)u z!!oCP&9uvg8t;5IqIgK)osUs(%l1b-z`U#U_qJ@GA5(Stm9WItaK1N`9I2^SM){k< zrn0O}S=rXIG8+$nahe&LlSCt#;3|{3d6Zt6^6}v}%%--S+BZxk(h|hl3_ZzqO*z>0 zS?~s!iol*8drvZI!*##UySG7ojh9fG>psi$X*mIHnxRcWyDT(G#mnXS136uZ2$*ES{cuyUs|63uGI6LaRaFgO3Tqm)lJ@_@!bVqS6Lb#qt$ zn**#@Yw2pW3kP&1C`RIq`n&c6vh!*Wj+>E;gV?qTMAAJe6?{s6%X?IstiFLmMjuQ# zwY)Q^Ou6@d+{)1=ZshnX+}V-|A2%tHR^?>cs4LShP1mFMYzi$&^lUQqn+rPk_y-sJ zC))SAJGZasMESW|_RgR!(yqLEM0w-DyjP}b%{M5X^>}2j)h`L{VOuxmpXSc%%1?*Q zJ<4mJ9o&(dY_&9aE(lto2k|6(AW=e&p-qa@>TFIe2aYVnt z($8&#)#X+^hvT&PeSyTePIOLbF9V>QV|P zA3D{d#HSXXYUw`}Idm#{TsTf2a!`wJ%*QM4ii1iEo(_75G+CAU-@W^*Q=*vA(bPncUvMRoLahtKb3Ne^oYFwgs?Rxr)DY?41Ox}-kwQJ9;4jm0Vh25Kyp@wd3a za*gHRS5+=!ald5R5X;bkIMrUBXP^bOyW2V6#O}rjUQ53*)2HdKz^uiAS&IVmCj@4# z$wsAM+B7vwe>4|G89om%zGu~(TJ_l*JfK&ONFhW%F@y8S2l$oc{$YRX?;m)>eE7@6*zZY>fDxPNx~dy z<=paqQy&YlFSWF6Qj*i9#TvhDhpXQ-wUDONT6JaLxYDM!@W{VSbho6ooj1{5#*x8s zbHi0hEmiJN6#EwPzm+#aj1V&5?E*lhX>JAo>IzCf%jN-c*A%Y71C>&3{D!D zr)|qBnK(V``-Q4vcaUJ0>^O4mIWyR^oM^;|;N$VA(HLXPPpjMKZ@*^Mb zCCp=p>irb&E3MJSOPkSe1e1f}HsyHB_nU#2s>iLrvv`D3_tM5so*X`K-(q9O;l9}y zsI5yG7rq_cB7?L*E&pTF9cZ~xk>V5cXOz0a;T{wqt$8od2K%+s4s>K+ z+jou`@ZEME!v160>JL~sj4#?%ezNiW>ixB6HY&T1!_wjQ@UCgDfG259e4MK_V}ueN zUE;nJNw65D_`|!Wbk5y^G4j@z8gPHw4wyOb^`q;=>Uf><9z=2PH5@^o0w|ulO)qU! z_nPhFOZ9};+FIvdR?s$jwo=*BRH796>u0o8<$VaH)$f=&uT5b;fRWLi!PfqnjNbFP z@VC9z@Il0~w)@&^Z9ABWn=-m#ABwQJyR*|o)vk^DnW2I<{fK{ZII!c((UbgR9=G3= z>Tg&MKmo%AeQg1E>BhgPzeFWWIoL95Nc!%a&QcCL9H8;7z_Td*ZfMtx`3f2?JD>ZD zy3y?1$Wx~GHvA2S%Rzl@8NH*w?C-7L-&Qs2AqdKUVy^T&{0eBfx2~!ierYZ&u~+rJ zc@#AQV^g0VzqU|k!QS5!s_A( zb43qW_T{WG%(MCkj0hUKf&Gm zH1twTQF#U!BHizOC;Fi4o?M(If;tRucY5N^)=#q(+agn(s?UbCRET{>Y4*2rVQ;eP z=3xzgf*@cxJqf|me3fYsG)ilanagAA#$Bqo>m#uWdn+U}u{^!y%qaBr;@J_q|JKtv zxOlQ?e{Q^ImsdTFy7R#(-SD0=k0>u+n-@BzUTa`lf1pS)G}C$;r;}j9WUy z7g=aGyRFWybdMLUTV$Xy>qb`i(5F33Wwy3jyq>?KUfXZCcVY7@PVt|PnR8SK|OPv#O^WIp#$t_a_eD@v+=?b;dsXV%i4w0yo_VUN~Qw+{OM&_DENo!ou? za7HbAZ99K$# zifl!34{ky}!_?z`cXCEK9s>8bBgdZ@X(?EBw$Ym6sN{cwA}6EVr@v+BheliK!| z{$>bviOmuB$7V$}+|hfgsn_Vto)qq%gfZ77jCD>MqW;3l>|A*IAv0%)-LWKEbYC^20W!ooucjZs`1pvV zxcFQ{KYT|2vmLK1Vy6x1b$4RORp|})A52zT8K&k*-iLNmfr9F;qW*v)`+o)=51e=v zC0}Y;iFQBJG_B7I=}J2~kUm86R+>3c>Vww7*8ek}VdJlhQ5E=l)Rfbn`R1OKT6Mnp z-e2OB@dwdnVWmTzXXehs5PEUA^1Ft5Fv^!wm+rdu)Sy#wTGn9vo^v{`Hjr{#f`VZ^ zzkf??rB<@(l0eFx7k2-6Ny(Q9_Tl>A?(##we>^`^ao-tfH)W>boQZ>E2c z_o#@3`QqAQV6#X!`^%mvEKZ74 zp%KEDQPzf3H@u6B*o#G2uZr+}Z%R0jtVGQ{BEIkzA*sJ{x)}OZv zwHFL6<}Qr=<5AtNs(c0Xs3EIQ7plkc4R@}mi?0o3s9*87dGPwdwFG||?71BMbtC*r zc3b4CmsxlQe|kZ?K^aMHi1nC2@Pl?J$1C6PE1|Z?!&GhxwxuNvuX4Ne2T>vSMZVO3 zK0hY=7OSIg>6A}QDhYBHwC|Sd$i!+SvA3ni6yJbq1X*F4Jzp{d|gp%xYVIW}sIf*-QlE_kh) zL;6i?!DqBjU$9@D=IqiOEY>xo|G45#_*TF9SHF%<7IfZlRc`E?oc9O!MXLH$6vE*{?dL+{0n~~x>}1QKoQ>^yY;;zC7Oo_)DYUxBEZT*(Qg3|j zuA=?r=NnJfp5A31-f8ZJv2k=*AVD)rMMJ%sBU?u1^}PlY+Ni!>?W96SX0P%_Qm<|8 zwz{_sqa|*oz513$^i$xWsh(H+Iw6=jTUbx5o{e2!TT5|f7ooaK-D-L|sIzCn8}5Ti zidEO&bH^K7Hd#SUI3jE+-f;w$cUyOzhGtV{v46mnZgp|_3uf(lDi>$oc)^rz^^M*( z3eykRO`MDa+K|^WPsElDhp;ZQ$Uo3EQC);~dFEm(;36sDqPk6ylo7jE+d&_Yf-|D$-51Om-hGV4XUZ`qT&#i4V%kf|^(%+Rr z{%-DlrWX$f(|R`MyrENwY^7R9IHXyr)=}N1-w1JQ<_=6AAXM*YtTk(Ed0a5_z=d(v z>H|ef%-kiE`!aW-A}iusz00%MR2Ng;ky#?ex1?=>xq1QRO__g`;`_(iaH zDZbsg^R2)q9C1?Oh-a?JS0X~rT6ZDjCF|PeP}rKeTXY*$?>2^P$Ah@L5L4aavaM0U z_Dz4tjQ7qm%V(J?-h_z7gdbdp#T`F@q-cg&m)Qy^u5Q&U;TxHci{ayHmR?%*PWrXEvZ){ZudCwl8*mAPv1pH$B6TkIXZ3>MpiZ;yc9n#86dueD~3i(Qm1W@&H+ zWL>xqO=MfJLcav(9>E!pBXLd?fL~KQVYj6N6V~XLh+eWg)_BdYc(s|0cK+%sKT&H` zH=b+kF5(2+Y^zUBv7J-aB4{IAseaA^+bKIu^NM~9ovJK*P&QqGBO>Ov4q;Z)6)2Y! zls`YmKhxauiP`pv=|$6pNql^>krcM`b;WT=TF1Pz*cFd8XDCIeWyK|gM~qME zh(S_hir^_|g3;p@ z*!vmxx=xuTq0cd8H_FoZiKT%#PL_t%pvgaO1(U5cyOp%U`(JV2-uM)6ebWLz1|r27 zoa3MV+VM|vFaKS$r0nB?IG|{k;$XF9y53S|~?jg4?@HaneZdpd|06$}{QEX@VqRv7Nee2K=@vIDi343-YqaJe>!)Bq9);P>? zH^No0&^<|Wr|QEIH8k>#3d8OzDmIQ4S74L~eMH9t6{!Fu(i}Zz>Q2LWALB+w#n?DJ zp;asgCgE81sOdS%DAoSW>=^gH+s+3I-)}oiVe7c#;(=Ruyzw9s=Y{tpv)FAQ(Bg_? z0k;+VisOcxu{SE-he2(BgHx7RVO9-|Mw!=aEvV%D!1JSC8ir=ooP>wznOTHW( zOx8Z0-TzI8o-kH>JSWZ0_j&yR<7xc&8BgJVQUNS_>-Ct}k%l>nx?wzxR5ilo5qqU4 zYqp$A|C$|pj6~yC@4IGJ)J>Bx4vn48y=KAGg=dp>O|?dnYImE9rlN0Y@l;%6lm6AJ zMY;xxL4#l@{F%{uEatXfst?NDWqNj+P5Ldq?ZYvvHZWZMnYuO^lWUv0udrv?h8DeC zR#tCMYH8J7s}}1)yMF@VVCJ<|=jw3d^~>4;9;l`I?4nmOkgvyfl&x!f+5DN+U1W_V zJrx6Hc0n9o@uosEt6tPC3+r;njqvOi0WPYztaeTM3L z`%QbI6Qaqd}~=d3y7j5S0eS{Td|3haMd8~HzR%vYWa702^pj0a~VH~bBx z84qS#z4==3!CN)E=S&|e8k#E`rqrIaABx_Vsw8{3sZ|ON}T?Mu)3eeiB9DoA@0uR zTn6Kvte!_5!KXY~tSs)S(1!>7Pj>0(lnDBt9C_?Y7&rfzfuJL|PI;U_+*hY5dF#Xi8o8ciOxCfdaozQ|AxL_PTrp zf$^`5uIfn8I;KaBp0n)9{`rGyF_ITkedYN4(Q`&u`CQ4q>B#}t@Q&#tZ=B?tK784e z$Dne;)DzH>*1i!axYehP_7%(zXemDJGQWRzC@&e6MPKPe1W*-lT^^Y34ozm)@$m|6 zStZWnX2{E)Jd9xW;Y{}VjgIN5&iVgH>D4%QRJw2acuT6!snfFS3UY&*H(0PVp!os? z^*(Kqui&l@ZE{D!-R;^{?FGx~w5#h1mIt+Kf(7>kFh!=|UZ3Xo75tA5Ew`hfp^IyUrMd0e zj5@6VljB3n)SBg9Op$j&2n4kog9Xh2?WQHse*fe^!OBl6)g`WA!OC{+rttdI_JT+1 zw3}*{x#|j51+|%FWs`#i4=ub(ogY(N@DK%+slkGW1KLdg4X!}Jqdsj`cJ^dn!4EpL zS(~@wx*luSzTIB%!#eFdbpsP;F)%9UVFih>a<&03!bejSQpgh2MeAHXx|GI z{Me`6<|_zyXk{G*ZS7ildqI1h7OX3HKB!d$3)Tm;%0R(SeA@qH?0w*)sLuWW*-d~z z7Dyl>N-UctK#-uD5HTR=CIk!`AVfe^y!juJ8emx#h!!ABDEbXV-mePN4x!Is=@A$Mgc_r(%-RY~qIv)$j%&iz%o`@Zzt?K|DoJ9B@%#l3J# z?n@!}qEPN{O5BS}a$B<9!R*`}>Fy=zxjT2dLpyU{_PFgn8T(@hL7da_6#OpyH`AJ8 z?n#^zWWc4seS6Z8tOIE)Pw(xF9JDW$V_+6K8hB`^dK!*UzUJ?@qTNSfyG*a1>`8Yv ze8jNnROiFiRnJ=aPuP;w@0&B%?;~1}8o0}qWgjrJs{`!5xIX4KxcNwgTQm-=so08g zacq4uz9J5@S>TzB-gyEKip}+KG)l6qtb_7q539nPVCxusxD4KNc?=(kpOW5;H1+kl zcccIB^(Isd7~pv2c&2!ICf<*h)U5LM19pK=Q!#Ll-0Rrz5vYf#Ep3C(ey>POTZq0C8 zJ2wrih-1e97v*oV+mp_8ht@xw#o_*|=NNtF+*i zGc#9adLApbM-LQ?XjkWf?Z}yz8L=k4Q%By<6U8mwsm;G0UUBV^9riI{=ji&!?!yyV z&Hx=)`v{~W?4qm-d=I{9V>o%dgYnG6hFpvH+;+z z4S&irD1hGYhz)j?XO}-EyELY^3gWXaI!p4j-+#u8hk4rG=izs|?ONIKY1kCdT^WY{ z!I^+%_vhU1(xjUJ=5BL49e4^-rb zn~_z?g4!WDc;upDU%Q!?oi@LWzaoc{5sm}KA{NztUDTAd{#IArt?r`AWhJ*pRqXp~ z-_8OT=85es6UIz-J3%=Zx35#OPloLp429PM2sYbksvs6(GU=HouVvbKGldE0#A0?H3z|RpS~p$`3>Ti2Mh^0u75#8|g{uVBP9=+pZ>xk#=fA;O?v;O8>fNuB2`|=lY zt|Mm_SRbG>Uokw|b45YmgS{B&c~w#QBc3ZDHjEoF$mQv=<;{y8JQLOY*&|3%H*!jC zZE{75r;V4pcBZyg+~e{LDryhs2gA6m&r`DSJi!DXiiq-IVi$_>L!UfkYZ(KmPGsgGEMb8lL7mqZrePr!N7bb6d4W1>bPuE%R;laK^ z=Z4RHWB6mgb-%d@w`G`7&vlFJQlvhOXEKVMYZ%o}dj@UWd%vr#Ps5D1VTV6z__AVP zpQMTiZZf8%-}pL9(H`FPjMF_Xj(7&P70koq1Nj+`_)%j$gMZy{>fXrdKR>tUwK4tE z?!h?+DrVN*k?C$<`Bmv}r1{=RflxdzQqt3M&50bHJLr4Y)EvYGx`tOa&yK8b-CsW* z)v7qYJm=rsSCZ_VQq17AGgAN9;2w|i5X|5;tnzT<>UJoUuzdC_2+mfu4oQ7je_c*w|!T6kPUK8SL1Q_|FXh6 zIn@6|cK>hd`hQo_|MP6vq2YJ=FI}K7zl*a9jCvivVo*LBJ$}XDDd&<#`CXe` zEb#i_f0H9%`QP5{|F4QMv8OIvbY0+u&eKJ;DYN#kI=t@O4o^bnlI$7Q@y&gs?9q}# zD$vf}tcuj^9rV^eHlM!OwLW|PFyi^1{d3O}*_+tCB+nVATY>Y|D{!%9km>qJ4DPD@wQQ%aRt&w=LE8o9Q^c{t8es3FGqPMIfMQ#4F{1=aa}43`qD>c9mx7H zD(zgPcbYqD;@j@C!S7{n@Wgu4H}svB6tD+`W0(&*Q#_%?NSuMz+2*0y8~XZMzfIrJ z55t9w%NMpw{I%B9K9+Aof6t*_8AGl7W;l&^6})i(&mwq-^9dEZOU=RG*yQ`V$9U2( zOfbMjKs)tVLxO#(3wq*&Abj_|e5$1AOOAv$?=IWGx96vxUJF{TD9C%(>e*_!!+63W@0qjS+dUtziLpX?&!oGe7xuc*KOox`b+7x@ zmdS6rEF6~ZY*~aobl$U`(+yLR*_vpp#8c9++~+AptS7GGoQAzLQ0#0`wCCM7&qU7F z_V=uR^K_&RgOhG}ti^+ioSqkZjqmSyea)AVEiTs!Ezfy|ufb!!AN0B@+EX|6cqDP) zjs8tzdcFBcry!>uo)%h;syL9mmI`74! zo8?CDz{5KuLspjzZ|K+e{scUmQ&gFSGo0^_wZ?9q;Hy~uf!!%Ux_+l`amLT4 z51WZ}K3}}whdTq2$iE^#WxfcW0a+I!#n=#fpmcaMMsHWl*n+9G0V}TeSeDNvttz&3 z6D~dd$nE`U^Sqeb>mOM5v!=85VZl4B+4t_nm0$U9^f&DC`5yKpuni=mzm#6`u+v$J zL>|6q_c_(rHhTk1`zDg~EjN6(?^|;z=Ubez;ORi@6Pr(kwp-5d;QIH1=5FEI_ez@C z`^|mN8QB1w_8!tW4bv3Yt}{QD6dklpbtPLLcg7?aB-eM{`6{bN8GmyND<-+#xx?tA zhL(VF#}SsxS2`1MZq{>ISqPrqJ1#_?+S0PNv976S-EG!Wk2b#8*z(K9Ay01UGigh% zg=2KZwEwsHOk~}eNI{mrL>@RP?23aspnR`wm@=gi%*LN!%O_yy1j-l|E%%Tm3?h4_%AP57RwO?`~3 zZNrPh__8U!ygF%kHQe#_QU{FJ@UlYt&&2uJ%1}+=g5s)06TG2{Fx+cW0il{nH6(o8 z(wBLN#fM(}lxjr4vxZ;bkUo7N}}bS$WL_@9;A3^5W`czZw@%CPqjE~qGfT^gD~kIlofU`+Qt2h*D#rE6o--{kr*O`UX|v`` zDV&yrpZtEm^HWy#v`J}w=G-x*Ff03xnR#<&PbtisHhW4zR^A^crtVYd@^YxiMZA#(f+$oc9 zzhlnyLe%5s0xIxw0nPAoVJwB5+Y9rvX5-NlpRE7ESXVfo$EgQCCLuN`b}&{XFLt-$ z#{}5ao;-Nrf-7tWYy$E~g!N*)8q@OyVa$s!`-+3TAn_a|VmiL0p1<=2SCz2*cv1kC zFEKBJJ%^Wer@)q7;n>zePQD#t`5_FZ55h9PR*4^jO+~!=Dm?fAyJv_q|3nmy<=zJC zhb_VfDU)GOz@C8(3`5yrn}$32o`B_Y#Erm*e_*3WJ9-K%%XJQxbritpY{os;JNY-j z&O>~Dnls<6u>3uk?)-jKY{Lysy@hXd^4$*0`kRO|NR~f(ykiIBrRrS1B3PEER&0yd z6JotL;f3J%Jt5%uO@y`U2bRlyPVAm6=l8~J$F_)V6KhR&(j~%jz74QUZ{;}pL|B$1 z50<}gm3Rv*=f}Wy4?bWKPkeoOyW3@ZtJmh@R%K zSC|?DeOM+2G7i>uAe;G-SzZQmvrP{3#m5ZP2PwW%G26fKxk~ZXiiappRP0rptT;t+ zs$#$5G{xzP$12WHoT+%c;t7gxQan*{KyjAhY{fZ>a~0<+HWxiupC%aO`mMu6%fR(x z)*agn+4x}BVh8#dKl*SzVl%h%!Ded>z_bMuHYt1Eld)OYf$6xNGGC?*z@n+yY43tH zY3~EG-7sws69dzdP1-ORo2Q+2J8T>#`tQMXkFaSoOl$U;oNqNMU_Z1vOc`!`>_YtO zz}WTK`K$xqCj0^TYT>UH_m8ryv7%>#D}=X!88}~ZD(n_ahrqpsKLqpk0`ft@5 zlas~&8!!%OcG^DDpqVFmC~O_3QA#(*RhBsux>tPWDIYSUEYE)^oow_nrIWFWZT|(} zTZEriKIS;i`5uMNZHZ-z?}gJ3@qZ3%mSq>1fy+WRZStRB9J=j!eG7h6_+dDjw2e%J zKttyC%w^f6bn=fxAB6_Y^+=ydV6(3I@>vEZBbze(0E}*e?Y|Bj5{^P2#cXQ>q|d{& zrtiXK_d{=j#%1TrRVPc@Sj^P487~Wfz_esGIi^hpvr3uvTCmxUCW772SpJ*A3``pU z(=u%?I0MYI>@zX&H`9NjPXlz8fj*nTK3L}Y2XH^(gDNfAEN_R>$>?FZ`d%hs=4==aACLMWSb5hi1w=o;x=L&X+tFmT7;ibTWUZ{xhYMZx{VzrIWd7 z(Ep^;$tIt(N;l_5t`w|O>=U%(1(02Ec1U<>10#qkArz!qfevqA&(IKw_sBb zuPOgOfX(*xG1w>mJl|tr8OSD|Yn4tm`{WFzlg)aZtaLJW#VqG6F!LtgrF_WTl&JF> z0R#Qa^#WH4`t#6NK&!(v7Atx-Ed3t?j}v|kY>uIa!KQxxA2?5Zu7v|LrN!`ZS7U1o9h`YXB%|>#B%-Ale+WEY_!Z?tt`>b53yHuy z$tLa1N+;uRVCOkg>13nx8V>{WG1q%o{?*XAjCGiv19Mwr***rFHvE}NYpxM7Z3hza zC#Jo~Oc0nqnU?wV^x_`^X~2$>SX3aeJ+@RI(a=T_2Xa$>SXG5m>yt*L7+|^ z155n{u-PZKfz3AZ0hrx9=J_d@>BuL+42+ZSf~9_|5C0ITlkbG3{;bl;YegT)lQjhT zlg)l3Rq14-rzxFm$}?W+WaEFc(#>@`R|?iCbRI|QFa?zl*|f12l};W2UoOk5;NHUf zln?nj(N8O#e7)#NJh?+)xyfdqf1T3FWd)umXGV|xM zzoK-qDbGHolTCTvS2~%SIp_P8(#by2uVAA>;PR5`&-tb)oy_fydbZNZH$r3n_bZ)j z%DG1AWYcbcqI7dzmg~J4x~Y@@Rz75I3!K*%N;lVXnYI%;cRMU+UmkQ2xLoEsFMWpl+@ub6y_k+`q9r zBbAT2&P<1317QKgejJ{OfvHsu+_4HkjRLN?p= zP^FWNo}zTJ2kBV;45gEe&TIS(%->w^cctLI1@tCpb^H-K2jkCs0Sxpv_XX(hg?=kE z`Y%xaOO=0EnEvE`;$NqH$bF!*%)H;gz4$ik4dM19a!^C?Z3`}G0gV3i9I=2`4q_CkP z(1)A_%lxarrXBL$2?Kr1eH7-i8an$_%;#Cj8h>y&j-Qr!cTy43SjG7!LJDyqcdjq539i#QDOT$&J7KL%VO>Uu?(%y zTcB}Sg6w1>(1$z`mdmnT>EsI02XF_AK!0)(Ed4`DH}{!1ua(f*b>Y08Rz762T)ZE} zz&y>pDW=^Io!cGLc7X4O<-8_vr6bVa+{2=OC3IAaGcV=yGaYXMMPU9{vZISYe{(;L{>jj(aamHq*uC5ScPM|d+1Bn=y15_6 ze9E9-E%`j8e9XN%`mBa-_RqgoKIT3ieRe_bA^H3ln41sF|GDxv_xtGIsrV9~z-GjLvH+B!^MDV=-;H0Bc%z&`}~kq@~jSa4r3eP)4&!g5|gFa!O_tV8;*7N&m_I0}~j zPlIn4{uIo%NBs*h^CzDJGcZrG$c`%ve9#t zPB!`HDV=Qe*-9tJO8$jPC!4lWrF63K4=bH){2x*}+3593C!2lCkCbl40k~2uYa{fl zQMNivFDV~0Mu0xMptEh$=YaAt;|J)|4!yVd90892Z^0B%{yea7L%&z@ z|4#Xsu@Ur%$>}<_js!ErU?Q7++D%F~<0+Un0Ns@TcI9KnTF_@6bh94s1+zcNW#Kps z2F}Zj$)Nu>=+syz9HYU&xEZfOpWV<+{kJI}`X*!IeSGdy8O#_AwiD|4w(96)wms@a zN+-|7M7^%ZkIr)^#OImrC4m zcO1yZcd_G$(QymQ7a?(tJ*w`yDh`2jGOY=7E?tpeXmL==_tBP$MU4l&+`$F!P*cD-Z%(pitouB7HT)N~wM}o=E#Q!%N zby*I~k1ee$L|s<%{9Ug}#?=gwEXv+#>-3kG0$WnADns&=LPaQayjq-aAY%`{?#OJ|s*c(em|4LX6eKYy3K%7IFO#Cs# zIqc2EnJM#JQj&%F|^KNmMY7$I8xLe$hI4|KWLptU+wcGFW5ceaU z7gIdiZyDnGU~U_XFBg9rrmqLEE=>Gs0NclP^7}6l4}h5`{a>Y{1a5b4AkMb)947w$ zF5(>0R)85Y{z*6g6W!wH5$6!BIkG%`)ke(x2X%`NMV!N*7Rmh55a+O@aj=}>Zo#G$t_WS+a;*TKC;X3TbFux6mn;|%iZ%3TNZ5GS#zw4I%EyT?b8TxaWof!_p zct`z<5%(_zm6SW;h;`(ErYEzZZ9lFGie0O}y~s z{Ob|t@R3cjKA!I8|Eq5C-_ajC^Sh<|?;y@ov9~3^zjyOLjkq@fr>c^Fl-kAG%ZoUN z2XLRj@^BcQ3H<#=#LcaE{(c+cyzOq<>%EAZTj~6L3F5qMjw0FltwG$}7U%DLCXlzl zxgTKsmx%K=Z$#q%i8ybk&Xn|jM4Y!vxgVtehlumGXTA7;jW};3mdo$4rXz+p%YPN( z=2ipKk4C%$=js1}cEI?=ZvMI5;&Z#j3%kWDyTwD@;tzF;Kh`bY*e(7P;zh%7N-yho zJL0^}a=R?w>)rehBhK3--@|(5@_dT8xs}2A*WLW1(3vr}G5C7|;=EB99yTu>q7GK*f{&ctaONb8+IHyCL z-)r4|{}bZo(l>uUj5sfIoAQ6$&Hp^&ynM|*HvK(3&`99&f3I774C1^@{gl*K9^$-Y zyi?j^NjLxH-Quge#Wx_%%fNoji}Qc3+wZ#&=cV3|{QgF_-~Ze#-hntT^==aXPQ-aR z_MZ}uX2(qem+xxCdHEGC_WV;2H)tOQww9g*Y#djuZd;5a;DjQ~n1L=jF|t zr9E=kCoc!U#m@hE#7*G*UqL)4;0#Y<{(nMzHR3$RF@6+rUgG+V#7`k^E|2hcH;y&t zQV8Q5Ldwe?Xp(mNB*e{S4gP)|;^q zTwRVQ>=u=;C@f!Ol~$IQ-iPSYWz}Iss)FMRmsXdT2MdG6q2h&0MdIUORg0>^g{9$8 zwf%keictBI!o?L8c%IHGTZ{+r_)B3$b@2iVkIvm!SQacRx!;K|T~WBSw0KeB!o_9f zC;=YPE5x~XVRiZPawji&9+mG~F#VB2$`CIIBHy^OL3N{w6b^+>-~R-mxN`D zF7v~+3nZ!v7B0U5>)KxNrKQD|ma)v2bjNj^J>#n4>Z%9I3rk8a<;|Rz;xR(5L%Xbn zOIP3lXI6Bm!fp=Xn$qH+g=T{#E?ih#D)ZEe%+3mhOA8m4FDxu6F1>FV(nvH^Ub=XB zdFXy?K_Mz`Di+7G7YNNDga;q(h?zUvM%5C_Uda{qJVF)J_yno7pnQ>e%v0J_Ay&Zh zrMTl)$c9J=mMmLpH-HeH_2dJgmu1fdvn%8Vzn!`Awtcyn3%F7iheFZ@k@K?ZGJ6(S z%OR4pdGWeYVa2jVrQB5Pm0wZ4cyXw(+S$~WV-}bFV3miL7M9^E)%}IbPy^xOP#C3O zfF(j?anP`{yd@=tcxV;NYquBFJXV6kETUcP8Z=D&u-I8bK0<2i&Z-^fw=02-YY{d` zCUP=HqqR5pF2z~Fg@wzcD!FcKjZf@aC?+e!-X05!%djnA7c_?VF9A|^a#>DxtTuup06-aeUX50_3K-iSH#tN5|m2@kLv%)K| z@!1aC!X;m(>snEEHeJ!erN!Y(b9c67dwn{Zy|%iXtx$P!Sz+Z0ot=}$X&Yz=LD?ZV zD^S;>sllaXVXQqTi$c3ST(((q-LbisE)4!p9ZyZ8-Ju0wCyYHmYV4BFrJb?8n_>%F z8eA5#T?(KB~*d3;{kcAj9nq8(zvS;bwvob5(@3T zdU$am4qoT&Y}|F&EFNPkTn{h+uccx*S>Ki-XP)&+M~M4-3lE{C57AbzaQk z=$)>eKZ|L4G`8R*ql`X|ossFv*gxBQNc3y$NLNEe+jcfnyJDP{P`(HUAeNGu;hhL+ z*aoq`G>X0BM{|-&qHO0EDl89$7Kd!Vh2_Od?PjVwVP)kd%W%MFZ_RdMk(|xRX?x7c zE@sW53a4Ls$<6L}I9|@RFBi_?8F(t=ddWunvW)B34)ebY=j#kOHMXypl1B(L-DqK) zcG%Y@cukep)!0XO72zMkHJGSVBgYou9|A6qST3AnG2~*R4>fYE=*-u}86t3gu8}s{ z^Khj&Y|m?y!*-t6I?VF{7Ym5MTb?eQZ!>r?xyF!i4uf+9v+TSjXqK0^5Dm{JOP%B^ zowp^8PcqK640{#xHm}in8`*H9V&2|2`h`FjpHo~*&Om_?RtCDbh8#r|br8lmjDqg8LtT?E+T5+Y~GQ~xT=PRD5*snNMaf)IN?J>)kfD>uM zab&404v#X+$YEK=rv>fHFo$;;<}fkCTXB8CaI@k~iW|u?uM@aFVf>FPKBl-sF^Aw8 ze|&)a5{DIYxS#PU!}S!yMT$B6(CB+`0&dE)i!5zpyW*{6S?|qCZ&JKbF^5%}JQJ0k zpg2zXc$7XH*RV_(^2t(Hxk}GbdO+zM-fPkx#Xi9BVX~C}kkZ?g-lp{Zid)E12Cvcw zlO@khxbA1><-s*eS5IdfiBTL)mV7SYI;i0@WbyA*%tt6po(T%Y3WJ(grFO z^N~I?uY`myjw4H2kJ4k59#}>j_qPES=#nK z>`RPKtKwaXd9T9w`<2dDDVVhTqQO$0RrzqX!i8{<870 z?{!O_Dat2V`FNGiSA&>5gQyzA*cDlP1qb_jGleI@t`Vm1BS=dh=JB|2BJ4OUA9c>> zPGQcUuNa}ua{XR772GDwvh#i}eKNow2=jjXaI6RFT-IBKSqDYJteam5{}T3U_|l*C z$Jd9DS+A+WtnVD*zkwGDzk#$NVXmhYitB`XLVsL%Hqy2z{Z++Fu^u?z&9E;D{|5G5 z;rC&AKaW0kTR=M@vyJo;z8ZFpFkhK*kK$s*{EcbZ)*csT8|3{j>U^!nd11CwzD|RB z3pHW3-cjYlOoK0&m>{)lfEy^ zebq`~z8+$g;x&r-8_U3b-Uear^L7h!zxaVL_m`gwe*??cOE4|>sRR2t%zf<~;dbyn z!rUJ>2y;LEGhx0$;&;MFq5od#p9ph*ABW=t=XDG`NccE-voMbve-h^Lyz7;lKI0*ewVII?dD9mHs5n&z!PYKt8W05cO=W%khun)ic zg_-{iN`Fz9$JpJ%JodgO%wzHeVf$D;z{#Jldl)0k<9WK$i-dX1-yqDsz#oL!M>r_F z4)%Rv_9IRTvwtxP{T40@`yJzi>7OIazR3b%_E{Q)UxnQ$O#df^*~d8~%)Zaxh57o4 zPlVY&`a<{s(tah(d~QVlisfN{s!Vtx>?+|O!8QxC|Mj}C1^d1*`)hp71M^{@u7@!D zbfbmY@0%ga{@~NX>@z+q%s%7agxSaZSeSjxk?4yuf4;IIRdJf)0%7)5ON48{j|exz za(oE$X@&hvnEl-Eq2EiLuU(iUJQ$YaL#Xpr3r`4#VP6!kf#sMHJ5Sg@3GajD*b(ZT z;6cKCy@F4e{qEty?04q~vu{36crh#|=EMH`kA!~?%U3B-XCHr)u-*5^`2zLpVfzU4 z{NM^&nl(=w=mCF4hq}nD_1*thM|oR=J`#o z@JjF^;aYI5@M`d{gzLfoDa`XEz9xao)d>Dbcq7=24iNPw@HN6b$C@V0bFUe~JSV$b zxB~WGVV<`!&U{+H_X%$Y|G+TpW5TybH^KTF3CK3PFW)Cg?&`` z30O|_;W_9h!aPqsDQv$+0T%)3GY7Uv_%YZjVV>je5RxCxcH5 zr-Hv0P63Y^=H$=$Tqn$BA1BP^y-E2j6z1y*o>#nAxDA#Q%N&6Hm+-f+-%ECMKkR75 zHw#aOoiDrqcCl~{(moi??npJ6$1d3jyxpCcUR^{UT>`RM+)!d}?#gcD);OefPOfTM(y!O6lY z;PJw#;A~+(_;%q8aJBG6@M7Ui@M_@z_$A?7@DAY|@SDPU;7;LQDLB4jV%hScCkf96 zj}@K=9w$5>e7kTFc!qEpxKy|jTp?Ty{(*21{E%=M{IYNj__x99;9TK0@Lb_`@Lj@(z~#b6!PUZt!F!B9>_@^K&^fM= z`SX!Pp^dI2Wt^jV?!NyWbsjz+p&!oLC^Q9kDt_qoo=GX_2bh3TKD zc(`J|dVyu|z$Z=VeDwnLIOvmO4cpLbTa0~eV3G*JvN#R}K?}T@QuSj#s z!22h2g{Q)DOe@y~@3E{A=Dn8-l zh2MpJNtpM7UKQp&qBFw0cQkaYGcVp#$`3>B3Fm8-#hkYoTyGEGO0p?}@!Aya$#Ob>27oqwqHH+rrzy{cm)9X2L!u%zJK4 z!oPrhTbTFd+J$+)?w`WDU?al2VXw?|^4tUF7+jWt_xkP=4!|xE&VhYEI2U%Ua2{-v z@ULN?70!ocoO#ZM{k`x!*w=;U!+t7U1p6;xraLEG2J0H{~Dqn%7)Xzd>z9-ZgTQWhW%8S_hzq{=;*v>>lMBMmaki28F*iJsxa^O<_Twj`RWDw zWP(o!^ZxK@;Q;t+;T-Tq;au<)lbp19;O`0NgQp7@z!nSF!2VSDX;@D7x`zKBgy)0b z6rKnEn=tQV^OX$r=l$((g)71Cn;o6^!v_lUp7~Y6yl0*wTm!yYcqMqMa4q;Q;nm<$ z;d*eDa0B=U!jHl7^$#phBlHI0jo=>(H-YyGUxeK+yb1dI!p-0_!dt=gW1ic2 zJ9w#Z3-~v}yTES=?*{)-cn`Q!n00(kxD|SjfRiU*Y0+PpKFPufuv3L6!cG$oz^)e# z!ZrzqVV@SRfqhnZCG1Y&TG%VHocW#u-z@wDY_a0CiW`M5!2bJm}x7NzC`IiQ2L{aA6Gt43UiFf9^n?)L&AJjfju@K<>dI3 zSWGN)H0-s)eD%N>VUB0HL73xQ%7m+6e<94*1Z)#-gxxQ^5tifnnZE@aCmanM5aufY z?iS{lnumlr)@GG3$KY`MKJ($&9DD3OxCQ(wCh8o^a}{Po#-YZ31sHi4c)IBK!Bz_2 z1^a^VcGy>h_rU($<>d1T?8m~7A}_|7Ctvl>XBx?Ty?dwd1K_j5d|mqmVZNgM8n@$b zzy6-gLL$r(o%gBc!QYIDS}8g;vKbTgN6~qoYQFM+PjqTz|nZzkS;7v!$S1|g=VxHnIW=;u=)?Ou zdU-$eA?bgc<3Ck&YUEhaJLz+~<1<@)sF7nu=j-`7FTP%Xi7;Qm9~S0o`d0|^-su_U zndjvByy(=(v7&Dmo%c)6(SN$*|E}oN$g!edpwA4)Cl<@b@=znkitZDA6702#Qx)?! zrsXp6HUDJ$75|94W;*#lBsyQwK#moCljwZie>DANKekhJYGkv2drNfQ&y7+3ABs+m zZ2ZrQ&T{qbFXaS#m^R-jTe9fX$g!f|Ec#^FJB6pf)?+g3;tkQMk?d$BO=?=-xQo0|mQgJO1ZIr$&wyJr;gkFZ`rIobcdy zj587DXAee^XF2&?FZvYN8-)2Og6YEiyg?Jvm^QXcbZTVN#!iaPPawn~y^D_qgjmyGMBYYvu z``7i%U$&80#OXtgY|7c7e1?e+HL~%^5}lt|m?zBq%Y^xfg+`T6o#@oaCZCPU=VkGs zMm9c8%I6*Np++`7TxKo{Kh2>4hc2{H($X;nlE%F}c|BMz~*eYUEha6O|9s zFi&b^CXfr9I>{EDdDN2UIr?ff z-zUU}8rjUZo<8?D{!fVyHFB)zTSVulAbv%j=u3v_Dx}a>fjS$e%{~< zVSXBc_w`v$<{6`yX{hsa3loI-*@Il+S+FyNqhXH=^OFPFS37C>*@NBCO&?>6=+wxj zkMXkT$6((e=Qzv0Uv%E*|0DTcM}Jpzelp<$VSY;Cf-pa^Fa+gb`R|3jS(u+sm@3TA zDtt(mb$3>Dega`XCbJ*&Bs%#}Bb)tL3fP<@Ocft$WOI&ihv+k4Q!$x7+dR>!kxid% ziRksPo@<=>@^c8Sh@1W12+^sL%|7H7(Wk&>3-dDu`&8QLqEjQAv>Zdgy5c7mDujn2 zEyoj3=Vul6t9+glof_HX^M>gBtU{aeZx@{!+4zruAM@wu9NLxtRMDxCjsGF#bEo)F zBO9Ma(K$9DjLGyvo)(=N+4MuUi_XtB>>^8hr~$hcIPL8f@u5bJ6@4XrDjlCchz~V# ztmw7$kv{oR@u5aG>;2zDoqFKsA2_j2dU|nv8*I)86A-6Pjcm>buNFNM7GDm()J~E_ zr$#pQbCc+EVKbF~w&>Kz#=l7P-Nl>z!Q0v{L7TM5jhJ zbv{(|;jlj8TYWgzFzp0;w$>=osgX^cSJFr7_ImN5MmF_Xt$c10A8KUd6QqyS?G*8$ zMmBXGrjOL^Eb*a6Hg#S@AF11W#D^N$)aOd&Qz1Uo$i}CZK2o>U;zNyW>U@jnFTlPj z+y;9ht`7q^L?4?A6$pLp5Iv{G-gMW;qK^|p;ZQg8FchZ@<` z$#&&aAwJZ|#;1ioQg1==p++|Kwu?SeZx4tMHL|I<-Sm-qTP;4+$fi#AD4!pT4>hv! zX{C?U+fT%Y8rjs_KKd+nw(%FlhZ;Fn^!@Y+IzF$64>fYE=xy{_;`rKDdqWvpt;1 z%VC!aXAei;6>QqiL!wh7oA#5Zd>X}v8rk^d(?|BhP2xk1Z1%&?ioO+gvoJqb!?9~D z+dkOOg!x&ZLCKEJPySpboCM2pc=XSLywVb23x5Usv0@jNfj<0%PqgA|g!u^{uVU6a{a?f~&c_fs_5048s!v09<+l2WkppVGqPCMr(fLzNQ z{)Rf1iyAprbk_*zVaMl#k&X{P`SblzU3${Bjvj!WAzTVuL>}*?ttU@%c!T)xQ$YOe zkE_PfVA?{G88Eh51RI zO^UY&^AkJU6u&RbcL$8b#PajAJ!2I6h51>av5GlA`g6S5JYjw!C;@r8e&8%`sp!%KuUEr$#pZUgfhve5jF)&(B5w1?(1Kj#*=z%R=5J%+C(} zPMDu8N>=&5Av!g($v;K;{6&1Ik&O@YGWC|K{QoIBHL~&dE1$2$hZ@=VxKLK+$#Hhk zihBw3Q%OsOt?Myv6BGUU$)fv(`3a(x-@ zS3CY^M5jiM6@38w66Cz~DE%LG{F$D0PK_KZdIx>hI6mp(Lya6O`c0zGg1uSsWb#8! z+B+0ig3WrY6@O~v*jmT`3F>lv>?y^&z^=89&nfCCGc|Io=)37N#qs$@e5jGlzVT}0 z&9o`7dzAlB(W#M*f2;BtEk4x9#%G`M$rB%HWaD$M==^Nee)>z9OGT$fHp{Y6bbhMp zIbn`_T#3o`LuVPciB63iEBY?c`Dv@&d4f10S*MeOQ4!2Q9olqmkihlK2N9QN6 zCJFPCS1W}1nX3ncYhhOl<6U*uQ^NfGRf{k`e>FeD$+H;tVPSs$s^tch=f_TYPJ>w< zYUEhachRTO@kt%$_)sIqiau3zein-p^Wk{Rp9=G{So?(eDXiVhQ`$^##OY6sY}VZ# z`mA&2dyn`~Bgcwf19ok2d{&7MHFB)zjiPf5=Xzm&QtKz=C!Dm5vkdfkMsc&^EoAXO zEIL26^`Y?COpI?-e1RQJp{PY(mmXl*aQ_*j7J?YGA0+>2Aa;)e-6P@Ea$KgEE_JPe3 z=4ZN|BR}Qj^NHyEjMfnJH|ft$Wc8cqFvnmHApgkm=eW#-jSgp$f9CMbWTfS1u>#}= z9G!7<<+`C;T$(^NL?m{F?B7*fwE)j_V!azrlVe{4dx~ z$<|nUysQ3xtjj-#4V*(f} zEBrgy-NLP~j5B}oe+#$6GESYJ`}&j8|02wBrtg!Va+d4wq92DnE6nke5i<5e3~`7X zP9!6L`g~8ApXnN*^c#h5hTVrY<7&3Ev1W=+jT|fbouYGG>VGI+F8mN|4Y|q5XFv1Y z?C>h_p+=4s{aMlZ>9RIehHau#Bbzep5S^bi`>pUr*mkCs{>iJNQzM)H$(zdm&tx1M z7>+7FMV2}ri27n3j)1*d@i6kUPTEnTbDZpQVSZMP6VvX6-6#AP*sq1TUhWGxKC@td zEZhY96XB;}KN9{FmJ{>*0(NMY!&$I=3A{O1%@Ca$*_?;ck7@Z?vS>`k|4z}Vk&SLRk=gEk4h}zDM5b=*L9or^~(;&dJ7gV@xa?$HDd$o((%l zn4j|U3a7yO$XlE|M~glV*01zT#heH8&x7SeE`+^HxC*vdI1F1YJP>xdFh4U^E6lQN zCC_on@L%NT9R5~(j=<(jhJLrB7mzXE1+c}!_rQjQAAxPcWRBf?M5jhJ$L>war&D~W zk&RDmjx(>3us;yyr?VJbF2}}@qaBV@JXo<;F*hyak8b!S#^LM|2NdTj&R0B7agpLm z#X-e2ifa|uD{fTWq_|n}HpMN9cPnmHykBv<;=_tN6dzaIsrZ~?3w3YmFh+5l;=zi& zic=K(6=y0AD9%-!uh<@MEbF~U>6MCuifa_tDy~=DsJKaSv*K-vTNLkB+^TrL;&#P{ z6?Z5;uDDb2ImMP+)xY96#e)@l6{jfXw`$CK%v2mujMaW=Tk|L$tT>sBGz@-BhS7z& z#JP%RD=t!8O^(7pgc?kSS1WE*yh*XWT}awpN^e!%rr2)(;(tu(cAFRdg3@DH|DyAK zpN74P`EDkoXDZH7oUhm(121`2Dm|>YR&j&kCdFG7+ig2})_{e;r( z_9l8X+k>!fV~MJr=ysK%blsNnls-=}zky`hVNfxj9WZ*m;*E-%6>nF(Tk$@{?TU{o zKCbwTVhhV{%HUBvSaGsqzhXXLVAAF)o~^h@akb(a#j6!JD&C}+&nK99?NZ#TxJ@yi zO)&n)6n84Vpg0EmTI0{-zhSRpzAMb=nTq+|Fr()yp0Bu4aaeJ!;s(V{inl6mQM^a7 z{VW6G42P87q4wx zirW<*ReW6W8O0W!Lon;kqj<35WW{`kn(^nik__`%48yY(7b&h*T%&lk;zq@r6!U#; zCjVWETNU#iYR1QY<^t=O;h54p6<<&s)2k~j-~VRv@hVPLoT)fRalYdDiYpa|71t_m zP~4<=tKt^Ldlc_id`NMJ;uDI`DUOcmTHZLtiHcJcXDALR=C_Ybz0FfxrZ}j0rQ&+U z8x=Pz-mZAJ;(dzS6(3c6T=5yjR`0GddlU~=oUGWdc%ouHdt;V;w&Ehi)rxBruU6cs zc$4C7igzh)Rotfdu;OEiI~8A09Mh+({Cu~dSr+@b9@&oUXKjQtl~0c1e8uw>S1JxG zu2tNixJmI=#Vv~WDBiF5km3%-ClsGk939)Wym5*X6{jf9P|Wu&n!3tUJWp|%;-KP{ zit80`RNSn1yW-u7_bF~yd{psq#b*>-==7WNdlU~=oUGWdc%tH5#j_O`DXvyrqjF;H!0qxc$Z>6<7VouP4QvH#}s!ezMwc}U{^i~ioJ?c6=y2u zdu2@-@)gflT&Xy$xK=UWLu>MBQoL1hi{d?s_bWc6xI^&?#e5g7nHS$JYuNsFfV4gP zc{kw{<&&W}pg2$QJjG>-gNj!wu2;NKF`t(+W!tWJx8i+@+Z7*Gd|dGv#nu&F`Fj)( zR-CNZuXv*3T*b2$7b&*C;~@1}qjdWjI?)@IzDe;m#k&-@DsEGJSn)B%or*6gjv3Td z4+)CBiuq1pvo10f=P1rsJYR98;;>>qOK9?JP~4<=tKt^Ldlc_id`L0hJ8belq4=EQ z=qtN?;uI$;PEnkpIG{LB@jS(4iusOXQ=XNI`8=c1H!5ycyj}5b#rqVuD?Y0DxMIHh z*v!j*m$9@x4=(x}eX!zW#eT&T73V6Rt++^Wwc;AZs}=K^Oj8EFZ`trR#k&-@DsEGJ zSn)B%or*6g=5v~6UI~i5ic=M5D$Y@yuXw)VO2uKtwTk)vWm5*eXW1~{r)-$-O*Xto z@qWdJ6n7{-q4=EQ=&QT(j8mMbI7M-W;(+2j#q$)GDGn-LskmP8M#asFw=3SQc%R~S z#YYt%SA0gXHKc3VJ&Fe_PFCz!JW+A3;@OIe6jv**QM_7lqvB19w<+GGxK(kR;=_uM zDehE!L2*oCS3M*s=6keFd$XUnm3>8~(sLB&E1s{oQgK*ut>Om7O^UZF<~z7edH8;9 z!+dVmFrQyF+@bh{;&Y0luj%rSQ=F(cMRA7WfZ{yG^AwjU4k})$xL)x_#m$PhE8eYm zpW=4KM-?Aed`7YLy{={VC?2dhS+QU7M8&y^XDcpJ%y*ZY^(zApa+#a_j!iuwGh$)E4@H=M7S&xablQgK*ut>OkU z?#VGUDZYOEIIj+A8RIh3)5m6JrhC19`v>QLn%_SzBg5+*o0gH8Y3oIO9-fjn)#Y+I znc~08`VUN9Ve3RN?t^F8Qi?Uu!iAx3!IO~qwI^o%=FH-6A_Mle9wZ5d_4Il1U|r81wJTgDJ*{9( zTIj8zp{%&tidL%v3DP>3$Jf2}&DtHIx6WBB;)B7o`!}b%;>Pr^9qaOEruB((XT|k- zvleBJN$Yhzp78Qz#Z{eh9pPMR^IRXgJ&A$bv}qsRdcDizN%^St`VFqX@V9w8ybrco zy>O)`?M`ox^yY2vKR2u4WbVOvn|me4Kq-Op{4Mii9`j9T`l#|$>(4j*`zrsClh(+1 z&$UAuN7pv4eYtO++Eq!lYg%LLYwKOL^=Z$ixcbI)bcDU$v{47QymNN$-CxJ--Cyj+ zi)hw$`r~i>_0Uc4w0ql!q>uLbhrR4gO0s!((cb@9|Kk%uvc7!!k? z_CS2nw~@W)BA(7xujTXo*z3LFY~8iw)Y@JpL%bFKtT zzKpEF8yrqV;9ZdViZ#az$oec&Q2k1bYkxfE>zf^gS##b=5qkN2wO;QVl-OKGWG9T+ z**kIAjRWEmb8a0Fuzb z2JG!PlJ?E414*A{^^X5CD#rb`+luNjwF*in z_Kr?G!&u)jd^2M9<};o*7P?~kPjb7x6FjU*x6AUmTxdMCK9@Ho4Na&PtHknljA?Wi zSVKN+Zx2^Y-#f{bbTr~gzzkd;vgsuKEi%c481jti@Ah7M@O`Q&o_3#ilxKg^;k4sf z=VryAn!H$^h}9Xf+*VQK7OT^0jYMkK$FDjcS#mzI<9uZE1#B*z2jV|V>+L#{Zmku5zj59E_`^xZ z(@aBxr~)byWt-+YkkmW=?I6^!jF4aBzyaqQrgn!Q+3eJ^$O(YhpQfyC~`XtZRqC?UGML;zxfCd{eP- zoyy?N4(uOHKz)qL>b+zPk0GA11@Tck@kEco0EVY3 ze!1dz^)Vff&k3$*EUIV>R$Umy4#pY~{o|yQM%NZQ86>91uQ< zc*e$9ql#lXQW(!Hj#=Uz+nT~9oZxeO|CjBy6ZcRVCcd8b9a?$&H=7SE>0SKUx+AMR z{SJN|LAmyxjhs3YNuO`|W?}=m5&LmZ$TKjeZ+0R!^r2Y#O1xbVzq4qz0Vh#QHxBT|d*h(RcBBAs_znb*nADwKc6`%<-6hZtoD!0LU>} zhl@u~yeIYelKr!Igz+U|9d%nndHZ;TUiI1L@w1Ms>%HWg9d0+)ZD(h^6^ZZcOzX9) zx96IPUaX8aU6`q_^-~;AFI6<^c<;X=o?ay$>;Cw)uFzhoZdOb`ck^OTPoFE^)8np# z&i>T*`q0{)E+6(6S@A8q(_a76r?qXa*8OSESgqAB*S<-7#p`+|c70a7vjw=~NA0a0 z#$7RTwDU`St7&iQ?xQojFSc60jBjpE`}d0jUU;E@+n1heaG<)RHazpfwjM8x?Dg+a zE>GVVUT_b3FlP6`7e@DZVVir<+fdze7xtPTHS)P7*{*o(rLd3cl~6t?wdbB|jy^lF z#|yu>qH|R1ke%M0FSqPSihZ^ARTqle(`Bvv6ZFoT;zvH`iOmiqzwF(SG!=_FdQ4CB z1SZ7)t_{oM_orbeQ1H&#_F<1;fp)fCJ?h}jtavAnxx-I+;!>g6#1>^QPAdO9$YWz9(#i5sT=#9HsLq8$ zPiV8{U(s3>f0ye(TJNN{-L5l{SzkwrPep>kaM6nRqB46n!%sH);%a@~pwC-m&)D-^ zjO8mo>GmdivRm;u(fs(=|s!k>+z@m;Y`rIq4#FLKRkZN*@;u8_ji39 zNpG(0xbENtUyPM`%A1ljYL(lYJ;CQ0=&a&ayv(A1<|=e~{pqbS)|h@y6BvIAUY;oY z`lZ`5Aah4<{JpNx#aO|ib*_SSR^MJLe&Ood1D{It$LEi1&G*HlAzK-bxZ2s7alami zw?O@W?Y#|jRmIu&z4u870e0XdMAVwQo^ya0AmB+r3>4ZV1Pl~3iGZMBa`FYy0|_Ar zTKag1h*+_Pk6LJ<4QLfDZ2_&dcWrw@k)p*K5EZJ{K&_$$4Tu&kb-(}r>}$e6?cF}> zdEd3(^{mdy&iv-u*PcByd-i;vJ-#W{s_$o=e5K5?!WFqw5Z1i5E^l&I+l8y~sgU@j z;rXFd_%ob7gyBP+K9ue9mrM(mO|e(q`O3{!Nl69Jmttj|l#Df|U&;G%D>sh7qM$@6 z8P3WXbaKKMtgQXTM+RRtse&yXH1V@?D%gAe5B0DS?d<8b+Z!iyay%BSiSLE z!PRbIik+KcnXit$nlYHMS>@pPwD|P#?>K$&B<^vuP9|GOb)+oHDCj_Vm+RoW*0Evd zgvr6ZIcFkAr`TC1LsP6{rH2aA+Ddd4>9=SSEZ4Oh1#p&ToL#>OQgtilIMq;w#bn^uUI!SR97zxg4r^cyG zcK+^z3`(AGowLYEN_GZCx`fG&FOW5eDMAXXsv|2H2s~-OsT#7uv9_vTlbz%W)l3F- zDlK(q2R`D)Nxr}pPIq{sgc*s>KnOD_ycoi)oV2HGfNi8&2g7Syi3yO-J0QplP(ebhke96b{i>gYk>jDNI+?3p4z6+S z^-LUilxzFKHzdaX#7x_-Ci&=Z0!e6a_qF233cTtq@(nlkV|&L6w_~HdeM8{LJ?@U> zENz;Ht>3=V-?}o;vXW(2^ZfPM-C@soq+uG}Gap%+==2AKhCPrU@`t^0bp8XrANO`H zhxov-4b~g}&NryLclCk!8_u*H+I(zBG8!uAI>t`hoo8|uSNl%w&QEq?FCse*MsSRd;#r+yl?` zm7k+I!l}XKwY(wouhzT@!jU>s{~+`+lHN3M^y1xzMy9 zaSI-CD=qt}v58}Ly}GkU=|gT_V#)BpsKjTU%J@@!XliKJVH9*wZ6DhiXm2`jZFWb0 zj1`=A*4mpWj;wcQ^hU#RNKt-au<+WU71IJUdnf(S%^24{w6#6d654gjUQ5NK4=#AZ zFJny;4Qg0E%O3U%KF1&YtNTVm$X7Pj2?V%t0qWYwNAAbZj4n9s#>ccw8s3^nNcn{RR#MQ~^F`|qV{%_|a}zp!R`}ypy$X{e z(-XU)oW-N}YJg1t#m>$v`~}XzYy5?c@l$0<{T-{J+g%uW@Fii`s;T?VZp}&8Wnxgp zw>LHTl6xqKo*p``-FMs}nThj+am|H#X>F|sB59{0>Anb>4l_?yM*8iFq#lj*J(1Yfp@w5N=k3Zq zlpDD?zIQwxr!RQ%$=BRBe4%pd<5fMEo(g1RJa7OSnM0ki9K|T!pPeu%6pCDg1dduA z7y=m@_qq+CavMcsim$9sV)y>`Sj%EA%=viyWdUFC-6Lglr%1l!vyVsF^( zhjNkBo)`YbonCHV|m?hFHG+1N((;wS{k#u5q8=-JTtnz(17S=(j2#dTa5> zUT<&t+8V#L>^}F~d5t;Wa5KIUcs#zPAP{N`AojVvXZw1uDzpRf+3~VxFJY~NfhJX< zV3-0$asI&gV5_7kK6rTUwX-L=xosgQF?fd?b8TOt6TIC;dG3ue1sC(A$M$V*X_K4l zw{mYD`pTQuYFgk3iS@>wq@~e- zF>yB7vB&M!tvQG_#w|Zx*|{P9>Em0*J8Q0;)qL%2yILh%75@isatntI_-?Kpp=(XB zU%z{kf-_t^H2uU1uE$$$6|S@K==5`&oznH#c3kUjZSxH|baIO8z4tv*PhD<3mh(w) z7oMEz4n9|~{c%3IErZ*g8sC&3bdkp@d;IUVOh{Me*;4f?{;%nOuwnz9YpM=9 zS+E=XABrtzo!VG+2>;9aAF7zf^JP_soOIZs{)h6ts<`TqZp2xJx!`>_&YXwn;P)u7 zJKaL7y3D#cKRrIC4A9?hh6&*ZpgPvwPMkVR*l$4n)^7uf|t>b%`I~5m+4_LnyehXgkk(pX086r zUG|yl^g_MCT7$!t2U^{wXIm;-0}U;+Q-0J7;mqB9ab;$Q8eWXohAZ-$3U~jdqT=Do z8?5|?p9nwR92@Cx-5Pv!s6D&q=&N#Xuxew!X3gF;0x4<9w2F)>7*x9S<>23#5QU+G zB}IHFg_Q?Y6Ui4k7`FJ(e3b_?*4Q63R8W#srDKUgK-S3IW_5y+V8BK zG<-BND964kDo)25PItDXwzQmHJgQqP*3J%ha&sBty?A7|hRitKzEBA|>Rsue(}Fh4 z$uX(+hd6-wba#SXH$jbw(;dz~jqdhy1@A^aSuk@)UC`-!xOD#qZjYSgltHN&-%<_h ztQ~ECar+gfX1qAL_v92O+3Df*+_~%Q&zC)BZ&-crW)8ijC0kB^=y#|ARr`pGfdNm_ zt|Ul5o4zzloP+G&{PH)jV`b6c6pLLc7FPr9EE+f_-t-U62@!ZubH@|n= zAJ$vw&0spGBBv#mbMNN5)hlS|=u1b(S*OO? z8&9qNmfP{a?1l&I$U2@a%iPd1%^#Z<@EYP}wHx*p94b8)IkO-+M~wpFc{+*rm4#aG z3{UI8m?=j~$8)GOKb-USpX{LtUe)k<#RD!?ro_f~pK$y$<8;SZ0cXt)FX&PFT%>OE z#3L9tU|-8gdLaRY!W($*=mN1Vnh;0N(;1t>J{0qaZ;(AGbx;ubqC3V5RZq=voDr3_ zzi!9GHVhs1*}B>3v1)Q=MvvO;p3dUickDrg&fL4>=^f8M{@DICldQ{r@$-|JwL#H(M6NkQcZf*GEc&zl~d2V&Q&;-gutj%6S~W(bmuAr={K%}?VTFF z-h%TOtwCt*U!xnIbwm%VobZK${#84Jzi`KB2>6c@Z7{E1toOXxUHjnr+#c88x-pc@i$C#@^~W6OyeZ`*CNK zs8CsvbS`N278hM%^K6zkO4TbgsBL=L3H!SUrS7Eejc{V_%xX@}q4%zDah1L1LQnRb zxS);Q@=u;K+HKD*JG}bc&7bTjjP$!bGP7;e{>n&dj|E7xPPf;HQ3c_Wre^DAuaOX& ze%H(+xskLR9`fzE*$N>u^xo21tuEY|8s24BKX-Cx7TC7PI+&m^)Ab%=>s}f_^kMvV9Un%cfObOse3AzmKE9C<_o69UqI_C_6$dQ zcja5Xu8gkYOME8hw?9mb-hUw9N(uyMAAJjfLm8ZEIG+BWanDnCn=#6g4O2+|sh9M{aJnJJGZF z#_&60xy4vj=e35quX)p6Z00&OQha6y2Y=bxQT>2+=BNLmKY+7chIwo?$BcR`D~qJp z?f<0h)UMAW@3WXYklA7N$!~Ap0X~}fCvZo{j*ef(;cU)43TG_FQ@5wC-w%f`^T>N| z48^aYcC>se+;eNpioamx-xdD$CEZ`>IkeZ0tY4-KIvIa6XNqrUr0`8 zY&91;J7tRViG3nrP|nztp^i7$SN3IY=U4B# zAu-`ZFQ?CzNNV1Ztdmo$9;L1IITpMusEqjS-OL1KL4RQoqt}BLC_mL8V{&Bug0L0G zG{B=jw|iL)gHvbsnbO;TO@3>58TuEvDlZj7Iy3g8wS8GpenBulP*F1At{DZzrJ-^7 z488K{C+B>BBjE)f17QD3_sqpqdFg*}n)(}dyA66IH6|qWA zH(gd+5eZgU741oP`6k=jYJ%u{qh4O?7Td8B&eo!1ncM%9;$S$u!|Qd}-=YV5S91jC zOdH2=yr(U#2}>C@eti3aiKUg1v@((#D7T+-i;>??3IHvZro{I3cu-LlL}x zX_dj$$^w5`L8_Bx`SY#NW}iKy#}SMi4BGFc&+dbfI!i<48$2x5Vf*a97&aUHKD$C{*cV+PYhOG$ z1zmyUxHn*x8|>R_cy6Tc^e0Y-Y}Dp>$8=Nm?Xt9xjX6R?^hnvo3!ZQbo^T^iU=XD& zsawPFz-80QCUhH>=$u;W?>@{<=`CY_v7;Qb!;oLLo#H5&nn0Z0C$2?ZF z3dMTg=Z;KVFsO7?M8-$kFcXV$*fkN%=?y#;>E4KuDZI)V ziE-Q=hNjm%fUvDg2*+w)!0$Bz(%KKK?KryjXo3GgLF%d(QE0dMeSz_a8163NI)B{O z6E0UHyce&r{mpi2%lG23`{S{D*0y|m?V19Aa{*H23g(lR1SgHq2gP z>e5kDmw6FrWtBFz^@a) z@z;Ax2;mthq@uIh4|Pq+(YXwhfoa~PN%Ssj*TA0JG7c&@nRixFBnPo z;(Z%$)*YI1|8prsVX}ihDO1=-$Ns%X&@#!j(@q6bF++mP8Jc1rIw@JhD6`RT>S33v z-i#N6) z!014rVeakaRdeea%5NK4UKNQBs|r+ky48Wjbxm`jGW5FKz|c9v`FnaxeY^>_=WY4K z`L*>{@eSqUuDf=^#A_xNg~x`MRORMXRYz(gJq>vdHI+{%%)BYPH3n>e|seA=}W zOQ(%5pIC%b;c(bHRZuu_Y);Q<*N-nRD7^l<$iDvP$=8n!)5GcG%dVez z-L+#wlV=QP3_=u6nRu-}Q9h+$(sgBHbBBkO`gvz2UW+q1>Vkq9|Lg+uj9gGQe)9MN z1nJs>DdWe6%Ek@N#cU~Wtxt3XN+s$!xfhl^#I8#f0aAe&cU_tGFp88J8R|K8;`s7$ z#pB0)_4;X3%8`!e3y^^43vw?M45y&ztK}sHQ;WxjLXu7Vcvh=ye2frwvJb=Lu({9= zzYnq;$a(&0*nGAX7z5#wz0$-ThJ6VZ4h?|4 z4NcE%*!;ma?|T+EsfNuTOY%Pa@nRlq{-}@s@dtOb`QtYF!yhm4Jb%nW|M=qr%JVMw z!h1a6-9Nd%=N~t7V0dV7E6dLE>;`Z%ju;MjVQs;&2?xVW{y7eKsrV4=BH;|A2YyGd z6rE?d!2blNe^Pr(W`q@yw74m$@nsIa(I^-nC zc%e{wCUFt9Lx_iypF8pc;w1ZPS$chD;mnlS{?w?BxhMx05;dG@m@o4XdON`8eU7* z^5GQ1P)^qJt0{z`oUG+vq7a7iF*q1LI}00>z#fZ(_g#(SRve7uSscjvihD_7@LK)8 z@ml6F{6<4vI~shg=&v;N$wNi{Q$w!bSNgLX@(S^1fbU!$8w#f3eZ#`kCo}xbIEoD& zvX1X$Lr&K65<^bb@~MWLtmXVr9u1!nxftAxqZO?4^CRGakZr;7JMhKAM-Bc2%sfP$ z9trpd!+4RkKite-zvJ29T%4!=&4#`%-&-P zy>K#uFbu=*z|&##UL3%up3n#%kF5J|fhE@RocrE=L1KtR3#=*LfhL)}u zsgsNd=0irEV(>)Rye~JfM>VJThu}5BW2OG4KjhgW{|;D(XAihU6O@(qTZ ztmWS~TvZ2EZsOd0tP;DN%fp-?qUrxr;Qqpg4Sh1Fd8u>S zkdqls%F|Ft>T9n8j}UnsI8*omFb%^%)_y(?*7eRoLx-&WKV`^u-;idI&W|TZe8zG8uB?{{XWhE z>vU)V)9_woR@1!ScMUmN$NgE+VR+iXLt&Hu4rWn9?u`OujPN8DCNT70_mi0>`~kjx z_ul~*<2sb8U>3V4b$B!8$!31Z)3)V8|Z_7h0Y_$H6qbFPYDj_w58f1?GJp!AlykJ^k)X zd>HEMF#_tRLp~ld>d!QE^!NdFDj;7fI&euE(=v&f~q#gLOniM(CQiy;`c@b-C4kxJN2jh;PMQ(a^I zyzsDST~keCBx((7tcga3HPtL>vW9VZ(i&E|aG^*&P4668)G#nOuVy~vw9j4(UrwQWtcl5scIeL2dgZ^m$_}Xcvyah?f zZ_M*mOOSJ{YOcb;`%*^3?l0ZiXg|ILK{5`l$L??stpr=^F&mokpq|cdRM&d>22)-= z30VuTC&R~Loq7ykDGt-Wa3+drBY--~&JsOX$_zl3pQ0VG^(8f6`mfCb=xx_0A=J3o zVCn{upq&IUTCWjq9VebzHy2%SoMb#0ejShHV0{fx?NgdaB{BNkop77}ovni#dQ@eP zLHkFyeilIMB9xo=6U1o$XyXxdnT=n;s|rt8mFw^^4f!lh|7I0osKE$`_OHvM&w+&V ze4u|U49}T_uD8IGC7kypsBh*dy3fCB!g(>_c^3HROoFO}OgCeA&LkiOwU11bRD_4= zK-TX5U`CsIJbyK8#zMRK{_$Pb`W0Zl7yA4HFpcN#X5H;MtpMya#P{2<$t)M>ehjuY zd=5`&2W+}`;b0TsXE>;T5cY0(j%=aaM`3fwZG*V~3R@dq-xKFJG=^-h^uGW%hpdud z)4yS`^^g(WUxJ%W-YU_b2sej|E)snX53^a43qPoTE8H9gnkV{8;pQ;U4$;34Hp6kP zawk~dgRKqaJK^RK$Y?PAdme5MWiZ|7egkfHWm90&{SjkBuBBzjBu zzIeg;D=u&kgL_ObR868k_JZ>)580i6O74Hd1?Q_TaL>QMeK*|f+7%;g4DWilEAaCA z@Uqd(VM1*f{{MzsSLZyx_k#1U!mYbMJpb+m=kZc>8Txn81@1v`vupHIoa6OhzTo`z z7r3k8W;bTF=yMMYc0pc{^jHZuoAfA_m46%HW|RF_a{e*6*<^c0-2V-?HVofyE^zOI zo6W9=MgIugodFD=BAyH{_rlOk8M;5C8@k!>D-DrPL0)ZzdycsK!>y+Zc;4cyVAB$B z>X$Q{U4q4p-W;&Svx}>m8l&Y+jghKb%P}2lsVT{-`rB$6%WETbQ6-~K^J*ds%WE5J z7L?c5)-J4RGA?eAD{HGTeOXz_dEc7(<#qGXm}pv3S;_h7-0G@&Orh2+u{7lBQ`Vev z_&;IM{Dt%q^U9I=5jCf6(Fe|Fmg5@lp13cfR9#ixP`PNKMOR}j)OiOem1DZr;ymcc z@`cfwnuhX*NMmH)LW>jNoUf+Vg6c|3PkWp9qRzrdV|g_bs<9?gea^)Yn5ys-Zb~s# z%ha<}+BDVAuc4$IcTfr2SYC-lMaVC3me)tCC74WDFP8L%VW_RDD$kjhJ5Tu}vE~iE znCrwe*W5<<)h!EySLz4UKj4n`*6d zk)o1vGL6fZG*mMa)z8NYeLf4TrfFe$HJY8bm*WYPmoL)ZASMjsy!wTBL=B4(Ek11q zMY5Qrx|bL#)6qNl?PV8UjF8kcHdxiT=R%yUp^sK$Qx!7bJe8P>8jQ;;F*naV#zZ{t z*41?jE9Y2Ec#??ZLIj^rMdfg%i(GJ9b@lM!=h93Ek2Wgf_wIhyJhVm?0HrPKB7%%rZ0c%GOG0g$Tm7DcP^Y}7*{ zs7tyYUirK^<@4k^l@EEfN;Rg_;zsliEWA#2bLJxu<+N428Bhd*@33SnrkqG?ZezW+ z5#@=EqC*>7hGtOAS?M@Oa}#Vb>$yjT*_C-*nA4%G%c%1%jt=2T}XIj26U!{rF9 z>&U!6%P?}+6lg%*R&|#tXPbpx=UyUT52kz*Y}Gyq0${e_Q2q$_68V!N|2b^7nrxB( zO5~K0wf>7DKLq<_;la2c-Sq!G*nc$mh{5j&Q~$WZ9~*oz&e5L?99Ia(aDJpP+aaS2 zULefrXig*YTBc>2Fw^@v@+N7dXUC%utS#NnB#$SI_i6Ik_YlpKiPxSrE0i9 z`%{8?&PLmZ#z7lN%ah6CXCirkr^7~|)<28$TK|l}91ha@S;%l&XMn*0gEI`ige>7n zH`s6JI0h#hoMnGP{TKanhQjsxiQIhzia zbUs6dehKu|_n(n&=!RLHlz#~TqrMR>`fpJ_+LL#XM|sR)VV#D>XnX1RH=iu&Glnew zLY@n!wDh%VUlj=_r{VOo zJA=YSv)ZFauI;2;^wmB-a^JTM{SJfGzCUs;rx&%Kc?M@0JQaNe9X3v<>bP*a*_Jjj zr>eC-$w()yZ;|EMsr}SM{|uhL*5P!yzLsrZ%@qd6QJ!cy+qaro{%C)S@eK66iVV&- znB}&LlU_2s16&4yT-HoGHxbFi4os z;c;O;t1sf&QUCim3WfPRpB3hwY1}J~I(+7}=#-NiVeb+CJ?z(oIdxxvd_o=kG|1wV zI+=NAo-p&&4q;BMzbO0~Z1y>+KLGYLVdlpf!r8EI5)Qz|Cts9)81`er+=J_BVdm>8 zJv^O5;6=iG4@P5HgZFwAHuqy9^If@5nC}p$%PHr(wMqCm_=m!L|6Ud5d&zy2sDB2` zy^Y9xj}M??C-eR0K09PicjIRwinAc^1~=saaBtykaH{YC@Hd6S;KzjN#}Q$cCC7wW z#w1`ci+-}~2@2Q44xqfEoaIx0VU}B*7N_YC;U~|JA_&OwF$Fa z+%3%V@_AvFqns9}|D0;(J}jDF6Xq1|9}PZY=y0zVt^bap^Pa&cggHgrDa>hP{`Q{N za;o`bVNPp*BFw32?)gF;PG7sioZ|N3pq%;{!kls+D?ASN^}?(-qQacs$M40}wbWT+ z@c$A{fxX<|Zy4NS@Ph_#G(7b8tXHQA`@!E7X5IUuFze(GgfqaLs%98iZ+{7MyJXhq+$)64dY*fQ zkXiq8uMjfZ2<5_TBm7R7?T9yp^T8*C+17B-CgHV3;B?_)aJeu(ex}BGsKcr6MIxUI z`ySya>`PH+QipAvA;N6?3=?LXXsj^XN`=D5!LxZxm+RvtIZu@Dkx;;2#TfABh*WKJ1T#lQ4EQ4hQ|b7WPzOwry7lp9XIh zJ_CMS_$;^#ZDU@`c5zgg?d2`PoPvHAY)MlGL zJXe_0vkd`HXAF3uF#BY;3A3+uQP9&l4%wys<-V{73A3MK6K;f%lX9-^k`xfD|u-B653Cunm^k+5f5*#)I z0CN}z<&=?oiToYP@eFC^pnXOiF0K86FqhvRAfw!&IWF=6Xuokzfcjh>J6xDcVn+&d z+yx59}<2R_Es{UEzPe*PMuxC9QUT4zLw+Mnz;wG<~N18 zg!ZH`m(4O9TE`L2gdH%rzc823@|@OJW8et$B*=zSF5xT^9m=l}=8{{w^|ezBUO>j2 zB~3N_OPA+zH#wlh)&?>TE~njS@S|kWe}XK}@er9A4CXRv-*SoWt-@Sp`wL+%n>|Sm zD0ORyv~{^`_9}AFlaDjFRCKt6c9t;P%;g4G3Ug^K&oTUW!ls+dWwwijxy<$sVe0Up z4wu~W9GOdH?-6c+{SAZfH*|Q8`dp&B){w6^_+f(|HTZGiH(_rR=91p+2JaVUU!bS7 z?E~OTg}ID(h%lG#a$btzsfB%`F#8R&4X!Y_%HaEixuo~M$ya#K;(3vCDef!6>|Y!g z=Ca&gXruGKT*k{KwPY@*{VtgW3CtrR=hE7<(6?FOz&s;z%E-M${yUL#kJ%RuK1vop zIsK~r`Al>uBWr(Bq#tn!>^=tf7v_@QX~OKktQ2N{<=ck*F<~zCP2_#Ez3|6HP8qqE z$lFEE^q7S{2GfMgb=AJE!@O&s7CB|)ULxO3xx8zAaZUPQPyc>0{NeK9ZwYhx@Q;MK ze3%DyxO_M++zxw}!E{rH%Zl@GFCCYcMNS!6$K^edv!8Vb4qnS;#eWgzGU47hDCg2( zwNGf+3v;K)DI@n1`5@^Ru%9$cn9GNG&>t=t-iK@S^Bpg8%E{u8gt>%vGOpG6WTnU{BkO#!R^-L-f4#xK73Pv# z9*hf@;=Uow<+pDOvrj`eb>^ZSaLV8WxOH7Kg)HyLOtRERyoT3u>F#a9T)Im)<#)nf zD$H=M6sFF7hP;IFy~<0UUyGbFaxaljrOrrC=ULIAjND7)GpNG`70gSbLm9c3$X^#Z z!!wKe*`9tO+zc~iWS!0fFY@HOU}qV8wZWqe{;DvS65nL71Lgtr;OZ7r#!gz5>@*rU@RUQMj!``(GBBzY3 z%Z(+JOB-gJ=x}-RGs0YwJnUl6{|U?=VC`p27U@kMSA-J71XnzwZlkx$y~ME+u{td6xQI8oXYZ%YnZu%)S_x0aNER z?5Bmf1o#)i>~Ce_pbnS%W<##?&y^yljI8qy^{9Uh>{4Og=LTUe6Al~xREeB2vi661 z^oPrbZx!Y;;rYVsqy1EvOQEktyOsLfyR1~0{jIMFbD8k>gxPQNW3p1@=5RO9Uv@n+>^S2DV7yGG+1`iSD zQf2PdMIA0fR(ppPdGFfaL{1sGm&j*B`qe;BlM29l6*7=>t zxdgk3ev1D`MNS!6-`5p6muWAdzLeqp;byu~M%MZ5nt&(gGVL3M8(_~9UI}}Z@M_pR z=+A?&TZMlBn+N5O!+sF`Co-2{)7Z9WqiNm6Xj*hJiXcnR#{~>#^IFSU9Ba-qIN#u6 zgG&saVQ_`Pa}91Vc!|L=gI5~dV(@x{TMgc7@OFcrHaKqZUW3~WK4fr*!N&{+cBLnp z$z6Pj!2=8q8$8C~VuPm|Tw!q3;3WnxH&~^QJok-;T&0P~pETrggZCM%;x77c8S+kp z&l;QzU7g=JZ>Kq6a5foZAvAepj7QKE8C+uUEQ7g5S?f0$93vyo({Rm-=Jf`1ZJw5M z?X+e!2P)U@HRJ~k?l73+QTp051}7p;TF&`L%^3z~89c(^e1kcjrLX0hSIu0rsky=6 zr3SAwc%8u<@6y+9Gx%wPcN^SpFvqp@wZ{xTZ7>HMwGPL%G+$!y0E5E@k1@E|;Hd^z z7#uZtiNVVaZZUYH!CMV}(%`tk`wTv0@LL9RJ*SSNnv0kGqvq>{Sq5vJfWg@YbBs*u z6d7D%@GOJp8r)=X%-~f9uQ&K%gSQ*}jKO;iK4@@TA{7800OQS%#eBl3J(9;F!Uy4Cb1At^csW+YNrk;JpSPG`PcH zj(KW7&lrrY!MfyrgEI_PYk?$QTvws}$v1ei!7~i5Hn_pyr3SAwc%8wm25&R?X@hqg z+-~se26Nqp4l~zhXjWse5-*42qQaLLJiy?v!D9^OIH|sNs=*ZoM-5(L@N$D&4Blw) zR)e23IBxJhgE{W3!}FHGod%yZI2q%;T0h<3fWg@Y=NVjNaEZZOOQZdqYjBgnF@skb zyx!o44c>0>GY0Q9_@KcZ26Ii04$m2b6FG(~&)sjZT7xHYuFKInY7AWD`G$P5!7~iz z`X7C5gTYG;UTN?;gIf*WW-!OwwVxbs*W7OK>job)__Vq{lfYR*Df%@+uF82ZNzK4Wkq<~6jR zeuFa%&N6s}!TAPHHh6}?)dn{hywu>82Cp-?)!=OgKW*@CgWC;$-QZ&epEj7k8P{=l z48FwR0S1Q+9%FE^!BY*cFgR-P5`&i;tkw_9v)gFMw;KGU!EuB48O$|xI$m5ar#tu7t^m@aRpi&N2?)-(f6W_Q(cDRA91+o2f7OC zUVdSnc5tfS1#m1_8||NVf1dr1-zqr&s(<|UfO$v8$Ba4MIv06&`^Rq`BzL7LS4U(e8n8>vu>IhjCK0VE!HmX4AF=VEn z=Kn9o)zwc=`BURz^;fc9`j_?B)uTpu71+P7zc^3C%%khCG&Gp7SMQz3C>1yp1EUpj z&Zuvk^NZxAAG6P(9l^v%&CU_tMW7b-7^DU$-Zj>7KlC+$9@cI z$D>2RZE49F8@Cs3cCXmp&B~3hu&h8he)R|^klShnTCn9o|AIjod$D)B`kZ>kT@yN8 z20zAsFrR(!6?J$n_1}FFv2>x9#5m&(kUgrfGa{oKtW3A-?9vZh`y@k|8+fo}xIg@r zf>EiNX}vN-$=JUssP5(MQB`ovU3Sd1-*ualtwtal>~ClcH0CE_qnzn~J-hU8 zkw3ZEme@%Pjk6XUb+`N^9y~&y*Qf5RoLGD5gq7G)Vg$BS;mrm#Hw^b<+emVCbL`3V z{9jPMWjJm>HUVQsH@OWSlvu5 z1mYKdf^x3G?Y(W+s_#+Tu9bx*#iseo@{=6jil_JxkoE_m=9sj%YK&1fBV)t*V~^mD`D#&`>)6ez3ek|=7&=80So-c-t%xu z9tek;1K9=eP(5F7O-e@XyB~IoM?vug_m?D)jcM~f!d79clT#O=hBQ@!mF@XVTj5-cfrRl zoO@6MedPMAn%aPtpHgz4C2E~?b`?$khTqt1<8%F{-0+*u3;brj9TP~fs$-7#&fw1W z-`vc!)Ky1=cy$ovigEIOv7;=@N#yU;01^S^;ex-p%hb*mm02rr zeM2oXb0{=n!5R08#?n&d!T=y%;Ix&`CoPzejevwgu{T0|T*mrI|?dD(yUhKUau(s5mS^c5A z>_c*6=BAd#ekloRH=))k_<-_I=BBRqF;u&0$6wsdf1!L$=BDi%{HC{u`hW1L^mx{n_V_$Z^HYF3mc=G zBC5(S%ibiFK-3H)U*=HNvaVMplsFRkH|Z_cx`&NA-zgPdkTMyCX>A?Pr5+BxoAXIQ z58GBXgX0|e$ld>udlEGPLOOIg+Bo}K=~E zP|g(awFv0+LEiH2a_&D8CFc|Dj_pghs_@4zX8QYNhMmm(9+@Rc@P`YA0wo6PugeTiR?%MPOBh+}|6*6PUpg<^?R4#V&7B_qxGTnpNqGrA9TAX?$G zGP8ZPs}hx~0K0(pkKnQM)xR5Wtu%~k@3vp3aA)S-^19XDy%`UlCBfag7`S`c%kF}g zDZHQutu41H>&$7{66dGjm19FZdGftX&cLjeBIbTY&xaP|sE0U5dPq)Eux$ znxEC1dS&<9mD0HHvwm|@n)jXQhnCnDTfJvHeooc0A%z{@=E%1eI_bQ2$c%ii|8eV# zr5zA#88XB2c3Zx62Ar$6xoZY(ytwX5C{Wc)wX^l)nr#-&EO^x2`fAJL{_T%5Y>&O# z+}a6y?yD`e{#Y$Vb+6)@Cm3<>|BmmvgL-)x)aiYE?EVezfs}5q|I%LXhVZMQw7xkH za$n@yzC8;O{PdJwv-&;jB-?vaBdf7<{Lu;4u^iQAEO@}RA8>OXV06%q^{PB+#QqgK zte)41MSIp>;brwFu|HN>YYf3b7;0BtBdt~YPH&ggS~hJj##t@D!^IwIme-K=>HF@{d}~3SyX+RX zv3vE=Vyj_6;`CQfIxH}Pwb;|yvZLzKLMH*D6>%0S=`bW1zYF2Id^(TTX6)fFuKg&yL9lpJJg1Sq>u3a@CP6Y|b;2kb;=k-9Q}2R67y z-i;REe_^z6^PlP55*@etEy9{;ky8x2IXXd|Cl{)YQDL-nfhr6eqh%3Pg~;&H>($xm z_+J*iLH%bQEsV}o|8G?PXRH4e>VLKRU!(rls{eD;|GDb_E$aWR>VH)IpLec&`}cOt zQs0RC&w&2_RRj7Ncs~x};Gh{7LMFndVU;r(2L}X~;t1nFMWW7gQ6FNI4gE ztcT5sZu-l~Z2G$db^taF<74Au+EZ{eILE$YpFpSl;uf-}bf}rH9Vbjn*^5rXWxl(*sF;5B(44jSr^wV(SbgrWQ(juANQEVylaxD4Ek<4Uj&8yD)*P@nt& zZ2JFOFw=|tS1|hxT6&c>gzmD{cUh_!iIiwgp7tdWSs|& zPzXagxi`{-Vfz3!4drB=e{^C|uHP%(E76A^mO#XN@k6>a)Y0!8b&4QoexS~U&rav1 zuN&9u_mtPRK(6EdV?&3`cWeueJ%*f&--{{vYld9E^YrsLgTu<%sfheo-*{w zg(5#==&&rKVZ3y?MnCBZ=N)+8|DuO5)CquTQzr||d{3QW;C`@qUoJ-0aVY`o{9FO1 z;q~Nn*z|{sk(ux556e&*>ge*6I)@;?3o`25BrhIybXiNCrI3F^bduzSqz;++hu8Ko zo;Nd2E0`eaUKG7Rs5 z2Z~M~nT=#P$y(03f`)QkZ}47R(5mls8<=Xm*VhewaxP@N*G~*NnR4nM0qc7u@g^{| z$RXI&;et~dT4b$1#gLP=e!U^rbsWRYMWY4qqZ!8uLx;>H;=MiuKPJpYm-;>00p_!# z&VLhN=!LF3>Hk5xpk1z$7_!~gsHTKvz8BK{9Hv$zbQMGRCnWyp0^O{S63$_j%29lfu9j-GCgnEvsR zYQHIOx&p<#&nrq z?cW@@b=-L>9qny4JsCc}raFALgY`8)D~LLY>({l>=b9ie{hK`2)1!aP{n|gi5;~26 z)=9M2n+amHf3%UbU8X2tSsl2L*X!`nZpdz`y3(9Jf8L%Hh^9(YeLfHFZaB2N7|g0eyJvuD_#9H9Sp%Et$M==r%wGUo z8_L-vF2cb_&GYxbrXT&q{ax7FQ2!^|0h{ihp_x zAIry?#+qAds+z3pizZ%Yy5~k3tCfzN_m)?A+sIoD^YAJEnyOrUXy5#xKQ=jNs>bZS_ z>6wz@d-f`H~2sMiPq^bHbkT4OPcWc{lyV%9??`cuZCwD8f&l@M2-3!K7*yS ztLy5^=hsz7xwdRh`9CJ?d1+r8jm)tsE9pIMSFW7!cuqaPu&=%3Jx6%4;~nZ7unk6| z5q`BxL8L1^B^~B@l1209MHb##UWpA2uz`TuwgG3#RRFP-K-ZoNID774R5n%BTXPx^ z6YO@-fDI3DN<|LoD&8v#JzYhMga0j?Rm|-sxW}G6zo#1NWgq6FMJmA z>roC-o`ZvB5}8A8={Tpq*U0u8<&=^2_Zn+O&h)4ku7kZ?copmw!mDB5E4&Z(B{*!f zDQO9_})?P|D!Op}8{%V!8rhOP1~bm&J^PKg+GGb z9ciQD2%GIrGSh6ba31XIgvY=x6V8Wyhwv@1e;^!#{X^jcusN(sKlx04Da`)qZ-lAC zHWGDK!RB)yzYgv$JPbC6QYq(izEt=v@a2Y1mhdsiCkt~(b*k_f*c?8kKl!ld3D1Vj zHZkQKF4f=fUjkky@};m_g=4TE5nc{E4cGBn=0^^1l9^9O3J-wYBwPV|v2Zo)JA~)L zzE3y`d!29tY_^~2CxED-xIRyJ<;dIyq!u%b@w}n||{7g6o+d+9ke>l{dV{o}J%bS=mzY(xanBN~w zK)J+gIdnSE;7JBY4gR$-hckBxH^Jub+UXC=x%Y(6z~(_Ye^>u^;TY^R^o1y24(4y! z$^5)(Wo&-!9B@m&2s=rxpBt;fKNOcTvtE(qqDL*c|Gld^cKA6ANCKrLP z7A^+o3r_~$D$L)mZxNmfenxl(_=GU)qO-!RqY@p@f7V?o!mQH<3bU@`kSW8^0KQt7 z_2FpYCE#jd)|qz+vo8IvFzeVSgja$&^h!ThfqyI90_HbSDPITvi!kGNQkZr7Y2l4v z{_dIjt>DXqIrN(;%pu#GggG=D5uOj5ziH;R#jrOEa|rgA!b@SlDjb9Tmhf`e9}2I8 zeO8#if4&?;we+(E%-m$lt zI#-JhWn`_xaU6!>HrR3DS77s?{0M9wWY)!7ap*Sc7^xpABkMNmW|4Cmlj91!wh?wj znC-L;=6bR3Uf+uif|F^RZ>TAn(hIE*BJaQgL^!gXC{;x9h|4ZbQk+pt{p`*VGP8nJ2=zWAZ z&8YVgA~)b*I*=C{e3vk%A72*cbmAd{`8{x6%W26!3bT%WOPJG=W57C1J`g!&WF5AA zL+9_JLm64?&@bML{;Tf>NqVM=oHDZ3FNRy+_j1vpjI4Erh@8`*lMVfmBBzY3_0>0u z(4NBYDI@KvewxOw%O@{`MKy&M(+C7HRW9Q0CQM$ z*seJ$%xT+q$ebL5p_}346mF+5^*j2b)KXSD^(c!%eYfU*58vpMfosK=Oc2K$DfKm+b2F8yq4V4VD-IukzXou zPDg*y;M>TVo}agiob9Qn8MZu6{*uTkBli;dGt`lEdrfpGBkMR?Dd)nb_VNmQe#Ut% zCt+apzFw4(dx`uKUVD|NQ%aV4cB=SU4f|&DXiw)>gC8ezvK3|rnGGVCC&}_o{Wm$? zlkX=F^qAj_(P=`7jrIr)UZXDd8_Xoo-w_EI%txi=jJ9SbpXPjniw!O@c!t3h2G2FP z!QdqZ#|&O+aErm~4Q@4ftHIk1e%j!;!Fvq`cBK`vLl<9S@Bo9u29Ghg*kF$P=x0%3 zaMWNGcX?jR4Y`W1$T@bS{ZVlg`ICk`Zty;X4;lQH!JP)5HJD?_`d%D&)EqFF+igBuK9YB0ybwEjASTMgc3@Y4qGHn`nj zj-6>gIToh*w80jhiI)H8TdLkOWgVr{Bw%p1!FdL=PonkNSJC{RZ>f6e`JZp8dg;JE qq|O^l3|4(NPQ3QL&=)d_FVZlbl4l+x@+E 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 zΜ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�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 literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/lib/libssc.a b/Distrib/ESPressif/RTOS/1.5.0/lib/libssc.a new file mode 100644 index 0000000000000000000000000000000000000000..8397bfdbfceea388d405a2f0121ea433ce0df52f GIT binary patch literal 39138 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 Jqj<04{{y~(u;l;% literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/lib/libssl.a b/Distrib/ESPressif/RTOS/1.5.0/lib/libssl.a new file mode 100644 index 0000000000000000000000000000000000000000..f6eb8a0aed7d932d78e86e4d40b29482b1ced0eb GIT binary patch literal 224262 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

    be8Qt+TE(HHuAv~*1$ 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 literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/lib/libwpa.a b/Distrib/ESPressif/RTOS/1.5.0/lib/libwpa.a new file mode 100644 index 0000000000000000000000000000000000000000..38eb656bb6ea31ac7c2bbc6390c3c746bc721286 GIT binary patch literal 163858 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 z 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 B99sYY literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/lib/libwps.a b/Distrib/ESPressif/RTOS/1.5.0/lib/libwps.a new file mode 100644 index 0000000000000000000000000000000000000000..f83c5b33c087c5bf55a3e74d78c40c33d726abe6 GIT binary patch literal 341366 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

    FLL_R%Y7A#-$=kMdMFZz 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 Oml>!AND MODIFIED BY!<< the FreeRTOS exception. + + >>! NOTE: The modification to the GPL is included to allow you to distribute + >>! a combined work that includes FreeRTOS without being obliged to provide + >>! the source code for proprietary components outside of the FreeRTOS + >>! kernel. + + FreeRTOS 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. Full license text is available from the following + link: http://www.freertos.org/a00114.html + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/croutine.h" + +/* + * Some kernel aware debuggers require data to be viewed to be global, rather + * than file scope. + */ +#ifdef portREMOVE_STATIC_QUALIFIER + #define static +#endif + + +/* Lists for ready and blocked co-routines. --------------------*/ +static xList pxReadyCoRoutineLists[ configMAX_CO_ROUTINE_PRIORITIES ]; /*< Prioritised ready co-routines. */ +static xList xDelayedCoRoutineList1; /*< Delayed co-routines. */ +static xList xDelayedCoRoutineList2; /*< Delayed co-routines (two lists are used - one for delays that have overflowed the current tick count. */ +static xList * pxDelayedCoRoutineList; /*< Points to the delayed co-routine list currently being used. */ +static xList * pxOverflowDelayedCoRoutineList; /*< Points to the delayed co-routine list currently being used to hold co-routines that have overflowed the current tick count. */ +static xList xPendingReadyCoRoutineList; /*< Holds co-routines that have been readied by an external event. They cannot be added directly to the ready lists as the ready lists cannot be accessed by interrupts. */ + +/* Other file private variables. --------------------------------*/ +corCRCB * pxCurrentCoRoutine = NULL; +static unsigned portBASE_TYPE uxTopCoRoutineReadyPriority = 0; +static portTickType xCoRoutineTickCount = 0, xLastTickCount = 0, xPassedTicks = 0; + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +/* The initial state of the co-routine when it is created. */ +#define corINITIAL_STATE ( 0 ) + +/* + * Place the co-routine represented by pxCRCB into the appropriate ready queue + * for the priority. It is inserted at the end of the list. + * + * This macro accesses the co-routine ready lists and therefore must not be + * used from within an ISR. + */ +#define prvAddCoRoutineToReadyQueue( pxCRCB ) \ +{ \ + if( pxCRCB->uxPriority > uxTopCoRoutineReadyPriority ) \ + { \ + uxTopCoRoutineReadyPriority = pxCRCB->uxPriority; \ + } \ + vListInsertEnd( ( xList * ) &( pxReadyCoRoutineLists[ pxCRCB->uxPriority ] ), &( pxCRCB->xGenericListItem ) ); \ +} + +/* + * Utility to ready all the lists used by the scheduler. This is called + * automatically upon the creation of the first co-routine. + */ +static void prvInitialiseCoRoutineLists( void ); + +/* + * Co-routines that are readied by an interrupt cannot be placed directly into + * the ready lists (there is no mutual exclusion). Instead they are placed in + * in the pending ready list in order that they can later be moved to the ready + * list by the co-routine scheduler. + */ +static void prvCheckPendingReadyList( void ); + +/* + * Macro that looks at the list of co-routines that are currently delayed to + * see if any require waking. + * + * Co-routines are stored in the queue in the order of their wake time - + * meaning once one co-routine has been found whose timer has not expired + * we need not look any further down the list. + */ +static void prvCheckDelayedList( void ); + +/*-----------------------------------------------------------*/ + +signed portBASE_TYPE xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, unsigned portBASE_TYPE uxPriority, unsigned portBASE_TYPE uxIndex ) +{ +signed portBASE_TYPE xReturn; +corCRCB *pxCoRoutine; + + /* Allocate the memory that will store the co-routine control block. */ + pxCoRoutine = ( corCRCB * ) os_malloc( sizeof( corCRCB ) ); + if( pxCoRoutine ) + { + /* If pxCurrentCoRoutine is NULL then this is the first co-routine to + be created and the co-routine data structures need initialising. */ + if( pxCurrentCoRoutine == NULL ) + { + pxCurrentCoRoutine = pxCoRoutine; + prvInitialiseCoRoutineLists(); + } + + /* Check the priority is within limits. */ + if( uxPriority >= configMAX_CO_ROUTINE_PRIORITIES ) + { + uxPriority = configMAX_CO_ROUTINE_PRIORITIES - 1; + } + + /* Fill out the co-routine control block from the function parameters. */ + pxCoRoutine->uxState = corINITIAL_STATE; + pxCoRoutine->uxPriority = uxPriority; + pxCoRoutine->uxIndex = uxIndex; + pxCoRoutine->pxCoRoutineFunction = pxCoRoutineCode; + + /* Initialise all the other co-routine control block parameters. */ + vListInitialiseItem( &( pxCoRoutine->xGenericListItem ) ); + vListInitialiseItem( &( pxCoRoutine->xEventListItem ) ); + + /* Set the co-routine control block as a link back from the xListItem. + This is so we can get back to the containing CRCB from a generic item + in a list. */ + listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xGenericListItem ), pxCoRoutine ); + listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xEventListItem ), pxCoRoutine ); + + /* Event lists are always in priority order. */ + listSET_LIST_ITEM_VALUE( &( pxCoRoutine->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority ); + + /* Now the co-routine has been initialised it can be added to the ready + list at the correct priority. */ + prvAddCoRoutineToReadyQueue( pxCoRoutine ); + + xReturn = pdPASS; + } + else + { + xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +void vCoRoutineAddToDelayedList( portTickType xTicksToDelay, xList *pxEventList ) +{ +portTickType xTimeToWake; + + /* Calculate the time to wake - this may overflow but this is + not a problem. */ + xTimeToWake = xCoRoutineTickCount + xTicksToDelay; + + /* We must remove ourselves from the ready list before adding + ourselves to the blocked list as the same list item is used for + both lists. */ + ( void ) uxListRemove( ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) ); + + /* The list item will be inserted in wake time order. */ + listSET_LIST_ITEM_VALUE( &( pxCurrentCoRoutine->xGenericListItem ), xTimeToWake ); + + if( xTimeToWake < xCoRoutineTickCount ) + { + /* Wake time has overflowed. Place this item in the + overflow list. */ + vListInsert( ( xList * ) pxOverflowDelayedCoRoutineList, ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) ); + } + else + { + /* The wake time has not overflowed, so we can use the + current block list. */ + vListInsert( ( xList * ) pxDelayedCoRoutineList, ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) ); + } + + if( pxEventList ) + { + /* Also add the co-routine to an event list. If this is done then the + function must be called with interrupts disabled. */ + vListInsert( pxEventList, &( pxCurrentCoRoutine->xEventListItem ) ); + } +} +/*-----------------------------------------------------------*/ + +static void prvCheckPendingReadyList( void ) +{ + /* Are there any co-routines waiting to get moved to the ready list? These + are co-routines that have been readied by an ISR. The ISR cannot access + the ready lists itself. */ + while( listLIST_IS_EMPTY( &xPendingReadyCoRoutineList ) == pdFALSE ) + { + corCRCB *pxUnblockedCRCB; + + /* The pending ready list can be accessed by an ISR. */ + //portDISABLE_INTERRUPTS(); +PortDisableInt_NoNest(); + { + pxUnblockedCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( (&xPendingReadyCoRoutineList) ); + ( void ) uxListRemove( &( pxUnblockedCRCB->xEventListItem ) ); + } +// portENABLE_INTERRUPTS(); +PortEnableInt_NoNest(); + + ( void ) uxListRemove( &( pxUnblockedCRCB->xGenericListItem ) ); + prvAddCoRoutineToReadyQueue( pxUnblockedCRCB ); + } +} +/*-----------------------------------------------------------*/ + +static void prvCheckDelayedList( void ) +{ +corCRCB *pxCRCB; + + xPassedTicks = xTaskGetTickCount() - xLastTickCount; + while( xPassedTicks ) + { + xCoRoutineTickCount++; + xPassedTicks--; + + /* If the tick count has overflowed we need to swap the ready lists. */ + if( xCoRoutineTickCount == 0 ) + { + xList * pxTemp; + + /* Tick count has overflowed so we need to swap the delay lists. If there are + any items in pxDelayedCoRoutineList here then there is an error! */ + pxTemp = pxDelayedCoRoutineList; + pxDelayedCoRoutineList = pxOverflowDelayedCoRoutineList; + pxOverflowDelayedCoRoutineList = pxTemp; + } + + /* See if this tick has made a timeout expire. */ + while( listLIST_IS_EMPTY( pxDelayedCoRoutineList ) == pdFALSE ) + { + pxCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedCoRoutineList ); + + if( xCoRoutineTickCount < listGET_LIST_ITEM_VALUE( &( pxCRCB->xGenericListItem ) ) ) + { + /* Timeout not yet expired. */ + break; + } + + //portDISABLE_INTERRUPTS(); +PortDisableInt_NoNest(); + { + /* The event could have occurred just before this critical + section. If this is the case then the generic list item will + have been moved to the pending ready list and the following + line is still valid. Also the pvContainer parameter will have + been set to NULL so the following lines are also valid. */ + uxListRemove( &( pxCRCB->xGenericListItem ) ); + + /* Is the co-routine waiting on an event also? */ + if( pxCRCB->xEventListItem.pvContainer ) + { + ( void ) uxListRemove( &( pxCRCB->xEventListItem ) ); + } + } +// portENABLE_INTERRUPTS(); +PortEnableInt_NoNest(); + + prvAddCoRoutineToReadyQueue( pxCRCB ); + } + } + + xLastTickCount = xCoRoutineTickCount; +} +/*-----------------------------------------------------------*/ + +void vCoRoutineSchedule( void ) +{ + /* See if any co-routines readied by events need moving to the ready lists. */ + prvCheckPendingReadyList(); + + /* See if any delayed co-routines have timed out. */ + prvCheckDelayedList(); + + /* Find the highest priority queue that contains ready co-routines. */ + while( listLIST_IS_EMPTY( &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) ) ) + { + if( uxTopCoRoutineReadyPriority == 0 ) + { + /* No more co-routines to check. */ + return; + } + --uxTopCoRoutineReadyPriority; + } + + /* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the co-routines + of the same priority get an equal share of the processor time. */ + listGET_OWNER_OF_NEXT_ENTRY( pxCurrentCoRoutine, &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) ); + + /* Call the co-routine. */ + ( pxCurrentCoRoutine->pxCoRoutineFunction )( pxCurrentCoRoutine, pxCurrentCoRoutine->uxIndex ); + + return; +} +/*-----------------------------------------------------------*/ + +static void prvInitialiseCoRoutineLists( void ) +{ +unsigned portBASE_TYPE uxPriority; + + for( uxPriority = 0; uxPriority < configMAX_CO_ROUTINE_PRIORITIES; uxPriority++ ) + { + vListInitialise( ( xList * ) &( pxReadyCoRoutineLists[ uxPriority ] ) ); + } + + vListInitialise( ( xList * ) &xDelayedCoRoutineList1 ); + vListInitialise( ( xList * ) &xDelayedCoRoutineList2 ); + vListInitialise( ( xList * ) &xPendingReadyCoRoutineList ); + + /* Start with pxDelayedCoRoutineList using list1 and the + pxOverflowDelayedCoRoutineList using list2. */ + pxDelayedCoRoutineList = &xDelayedCoRoutineList1; + pxOverflowDelayedCoRoutineList = &xDelayedCoRoutineList2; +} +/*-----------------------------------------------------------*/ + +signed portBASE_TYPE xCoRoutineRemoveFromEventList( const xList *pxEventList ) +{ +corCRCB *pxUnblockedCRCB; +signed portBASE_TYPE xReturn; + + /* This function is called from within an interrupt. It can only access + event lists and the pending ready list. This function assumes that a + check has already been made to ensure pxEventList is not empty. */ + pxUnblockedCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList ); + ( void ) uxListRemove( &( pxUnblockedCRCB->xEventListItem ) ); + vListInsertEnd( ( xList * ) &( xPendingReadyCoRoutineList ), &( pxUnblockedCRCB->xEventListItem ) ); + + if( pxUnblockedCRCB->uxPriority >= pxCurrentCoRoutine->uxPriority ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + + return xReturn; +} + diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/freertos/heap_4.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/freertos/heap_4.c new file mode 100644 index 0000000..48dbf01 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/freertos/heap_4.c @@ -0,0 +1,707 @@ +/* + FreeRTOS V7.5.2 - Copyright (C) 2013 Real Time Engineers Ltd. + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that has become a de facto standard. * + * * + * Help yourself get started quickly and support the FreeRTOS * + * project by purchasing a FreeRTOS tutorial book, reference * + * manual, or both from: http://www.FreeRTOS.org/Documentation * + * * + * Thank you! * + * * + *************************************************************************** + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + >>! NOTE: The modification to the GPL is included to allow you to distribute + >>! a combined work that includes FreeRTOS without being obliged to provide + >>! the source code for proprietary components outside of the FreeRTOS + >>! kernel. + + FreeRTOS 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. Full license text is available from the following + link: http://www.freertos.org/a00114.html + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * A sample implementation of pvPortMalloc() and vPortFree() that combines + * (coalescences) adjacent memory blocks as they are freed, and in so doing + * limits memory fragmentation. + * + * See heap_1.c, heap_2.c and heap_3.c for alternative implementations, and the + * memory management pages of http://www.FreeRTOS.org for more information. + */ +#include +#include + +/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining +all the API functions to use the MPU wrappers. That should only be done when +task.h is included from an application file. */ +#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "espressif/esp8266/ets_sys.h" + +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +#if 1 +#define mem_printf(fmt, args...) ets_printf(fmt,## args) +#else +#define mem_printf(fmt, args...) +#endif + +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 0x40000000 - (uint32)&_heap_start ) ) + +/* Block sizes must not get too small. */ +#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( heapSTRUCT_SIZE * 2 ) ) + +/* Assumes 8bit bytes! */ +#define heapBITS_PER_BYTE ( ( size_t ) 8 ) + +/* A few bytes might be lost to byte aligning the heap start address. */ +#define heapADJUSTED_HEAP_SIZE ( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT ) + +/* Define the linked list structure. This is used to link free blocks in order +of their memory address. */ +typedef struct A_BLOCK_LINK +{ + struct A_BLOCK_LINK *pxNextFreeBlock; /*<< The next free block in the list. */ + size_t xBlockSize; /*<< The size of the free block. */ +#ifdef MEMLEAK_DEBUG + const char *file; + unsigned line; +#endif +} xBlockLink; + +/*-----------------------------------------------------------*/ + +/* + * Inserts a block of memory that is being freed into the correct position in + * the list of free memory blocks. The block being freed will be merged with + * the block in front it and/or the block behind it if the memory blocks are + * adjacent to each other. + */ +static void prvInsertBlockIntoFreeList( xBlockLink *pxBlockToInsert ); + +/* + * Called automatically to setup the required heap structures the first time + * pvPortMalloc() is called. + */ +static void prvHeapInit( void ); + + +extern char _heap_start; +/*-----------------------------------------------------------*/ +/* Allocate the memory for the heap. */ +//static unsigned char ucHeap[ configTOTAL_HEAP_SIZE ]; +static unsigned char *ucHeap; +/* The size of the structure placed at the beginning of each allocated memory +block must by correctly byte aligned. */ +static unsigned short heapSTRUCT_SIZE;// = ( ( sizeof ( xBlockLink ) + ( portBYTE_ALIGNMENT - 1 ) ) & ~portBYTE_ALIGNMENT_MASK ); + +static unsigned short portBYTE_ALIGNMENT_MASK_v; +static unsigned short portBYTE_ALIGNMENT_v; + +/* Create a couple of list links to mark the start and end of the list. */ +static xBlockLink xStart, *pxEnd = NULL; + +#ifdef MEMLEAK_DEBUG +//add by jjj, we Link the used blocks here +static xBlockLink yStart; +static size_t yFreeBytesRemaining; +#endif + +/* Ensure the pxEnd pointer will end up on the correct byte alignment. */ +//static const size_t xTotalHeapSize = ( ( size_t ) heapADJUSTED_HEAP_SIZE ) & ( ( size_t ) ~portBYTE_ALIGNMENT_MASK ); +static size_t xTotalHeapSize; + +/* Keeps track of the number of free bytes remaining, but says nothing about +fragmentation. */ +//static size_t xFreeBytesRemaining = ( ( size_t ) heapADJUSTED_HEAP_SIZE ) & ( ( size_t ) ~portBYTE_ALIGNMENT_MASK ); +static size_t xFreeBytesRemaining; + +/* Gets set to the top bit of an size_t type. When this bit in the xBlockSize +member of an xBlockLink structure is set then the block belongs to the +application. When the bit is free the block is still part of the free heap +space. */ +static size_t xBlockAllocatedBit = 0; + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = "user_app"; +#endif + +/*-----------------------------------------------------------*/ +bool ICACHE_FLASH_ATTR __attribute__((weak)) +check_memleak_debug_enable() +{ + return 0; +} +#ifdef MEMLEAK_DEBUG +#include "spi_flash.h" +//extern SpiFlashChip *flashchip; +extern SpiFlashChip flashchip; +void prvInsertBlockIntoUsedList(xBlockLink *pxBlockToInsert) +{ + xBlockLink *pxIterator; + for( pxIterator = &yStart; pxIterator->pxNextFreeBlock < pxBlockToInsert && pxIterator->pxNextFreeBlock != NULL;pxIterator = pxIterator->pxNextFreeBlock) + { + /* Nothing to do here. */ + } + pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock; + pxIterator->pxNextFreeBlock = pxBlockToInsert; + yFreeBytesRemaining += pxBlockToInsert->xBlockSize; +} + +static const char *ICACHE_FLASH_ATTR +vGetFileName(char *file_name_out, const char *file_name_in) +{ + if (((uint32)file_name_in & 0x40200000) == 0x40200000) { + uint16 str_len = ((strlen(file_name_in) - 1) / 4 + 1) * 4; + + if (str_len > 32) { + str_len = 32; + } + + memcpy(file_name_out, file_name_in, str_len); + file_name_out[str_len] = 0; + + return file_name_out; + } + + return file_name_in; +} + +void pvShowMalloc() +{ + xBlockLink *pxIterator; +//ets_printf("sh0:%d,%d,",heapSTRUCT_SIZE,sizeof( xBlockLink )); + if(heapSTRUCT_SIZE < sizeof( xBlockLink )) + return; + ETS_INTR_LOCK(); + Wait_SPI_Idle(&flashchip); + Cache_Read_Enable_New(); +//ets_printf("sh1,"); + os_printf("--------Show Malloc--------\n"); + for( pxIterator = &yStart; pxIterator->pxNextFreeBlock != NULL;pxIterator = pxIterator->pxNextFreeBlock) { + char file_name[33]; + const char *file_name_printf; +//ets_printf("sh2,"); + file_name_printf = vGetFileName(file_name, pxIterator->pxNextFreeBlock->file); + os_printf("F:%s\tL:%u\tmalloc %u\t@ %x\n", file_name_printf, pxIterator->pxNextFreeBlock->line, pxIterator->pxNextFreeBlock->xBlockSize, ( void * ) ( ( ( unsigned char * ) pxIterator->pxNextFreeBlock ) + heapSTRUCT_SIZE)); +//ets_printf("sh3,"); +// ets_delay_us(2000); + system_soft_wdt_feed(); + } + os_printf("--------Free %d--------\n\n", xFreeBytesRemaining); + +#if 0 + uint32 last_link = (uint32)yStart.pxNextFreeBlock; + uint32 index = 0; + os_printf("'*':used, '-'free, each %d bytes\n", portBYTE_ALIGNMENT_v); + os_printf("%x:", last_link); + for( pxIterator = &yStart; pxIterator->pxNextFreeBlock != NULL;pxIterator = pxIterator->pxNextFreeBlock) { + uint16 i; + for (i = 0; i < ((uint32)pxIterator->pxNextFreeBlock - last_link) / portBYTE_ALIGNMENT_v; i++) { + index++; + os_printf("-"); + if (index % 64 == 0) { + os_printf("\n%x:", (uint32)yStart.pxNextFreeBlock + index * portBYTE_ALIGNMENT_v); + } + } + for (i = 0; i < pxIterator->pxNextFreeBlock->xBlockSize / portBYTE_ALIGNMENT_v; i++) { + index++; + os_printf("*"); + if (index % 64 == 0) { + os_printf("\n%x:", (uint32)yStart.pxNextFreeBlock + index * portBYTE_ALIGNMENT_v); + } + } + last_link = ((uint32)pxIterator->pxNextFreeBlock + pxIterator->pxNextFreeBlock->xBlockSize); + system_soft_wdt_feed(); + } + os_printf("\n\n"); +#endif + +//ets_printf("sh4\n"); + ETS_INTR_UNLOCK(); +} + +void system_show_malloc(void) __attribute__((alias("pvShowMalloc"))); + +int prvRemoveBlockFromUsedList(xBlockLink *pxBlockToRemove) +{ + xBlockLink *pxIterator; + for( pxIterator = &yStart; pxIterator->pxNextFreeBlock != pxBlockToRemove && pxIterator->pxNextFreeBlock != NULL;pxIterator = pxIterator->pxNextFreeBlock) + { + /* Nothing to do here. */ + } + if(pxIterator->pxNextFreeBlock != pxBlockToRemove){ + return -1; + } + pxIterator->pxNextFreeBlock = pxBlockToRemove->pxNextFreeBlock; + yFreeBytesRemaining -= pxBlockToRemove->xBlockSize; + return 0; +} +#endif + +size_t xPortWantedSizeAlign(size_t xWantedSize) +{ + xWantedSize += heapSTRUCT_SIZE; + + /* Ensure that blocks are always aligned to the required number + of bytes. */ + if( ( xWantedSize & portBYTE_ALIGNMENT_MASK_v ) != 0x00 ) + { + /* Byte alignment required. */ + xWantedSize += ( portBYTE_ALIGNMENT_v - ( xWantedSize & portBYTE_ALIGNMENT_MASK_v ) ); + } + + return xWantedSize; +} + + +#ifndef MEMLEAK_DEBUG +void *pvPortMalloc( size_t xWantedSize ) +#else +void *pvPortMalloc( size_t xWantedSize, const char * file, unsigned line) +#endif +{ +xBlockLink *pxBlock, *pxPreviousBlock, *pxNewBlockLink; +void *pvReturn = NULL; + +// printf("%s %d %d\n", __func__, xWantedSize, xFreeBytesRemaining); + +// vTaskSuspendAll(); + ETS_INTR_LOCK(); + { + /* If this is the first call to malloc then the heap will require + initialisation to setup the list of free blocks. */ + if( pxEnd == NULL ) + { + prvHeapInit(); + } + + if( xWantedSize > 0 ) + { + xWantedSize = xPortWantedSizeAlign(xWantedSize); + } + + if( ( xWantedSize > 0 ) && ( xWantedSize < xFreeBytesRemaining ) ) + { + /* Traverse the list from the start (lowest address) block until + one of adequate size is found. */ + pxPreviousBlock = &xStart; + pxBlock = xStart.pxNextFreeBlock; + while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) ) + { + pxPreviousBlock = pxBlock; + pxBlock = pxBlock->pxNextFreeBlock; + } + + /* If the end marker was reached then a block of adequate size + was not found. */ + if( pxBlock != pxEnd ) + { + /* Return the memory space pointed to - jumping over the + xBlockLink structure at its start. */ + pvReturn = ( void * ) ( ( ( unsigned char * ) pxPreviousBlock->pxNextFreeBlock ) + heapSTRUCT_SIZE ); + + /* This block is being returned for use so must be taken out + of the list of free blocks. */ + pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock; + + /* If the block is larger than required it can be split into + two. */ + if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE ) + { + /* This block is to be split into two. Create a new + block following the number of bytes requested. The void + cast is used to prevent byte alignment warnings from the + compiler. */ + pxNewBlockLink = ( void * ) ( ( ( unsigned char * ) pxBlock ) + xWantedSize ); + + /* Calculate the sizes of two blocks split from the + single block. */ + pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize; + pxBlock->xBlockSize = xWantedSize; + + //Insert the new block into the list of free blocks. + //ETS_INTR_LOCK(); + prvInsertBlockIntoFreeList( ( pxNewBlockLink ) ); + //ETS_INTR_UNLOCK(); + } +#ifdef MEMLEAK_DEBUG + pxBlock->pxNextFreeBlock = NULL; +#endif + xFreeBytesRemaining -= pxBlock->xBlockSize; +#ifdef MEMLEAK_DEBUG + if(heapSTRUCT_SIZE >= sizeof( xBlockLink )){ + pxBlock->file = file; + pxBlock->line = line; + } + //link the use block + prvInsertBlockIntoUsedList(pxBlock); +#endif + } + } + } +// xTaskResumeAll(); + ETS_INTR_UNLOCK(); + + #if( configUSE_MALLOC_FAILED_HOOK == 1 ) + { + if( pvReturn == NULL ) + { + //extern void vApplicationMallocFailedHook( void ); + //vApplicationMallocFailedHook(); + ets_printf("E:M %d\n", xWantedSize); + } + } + #endif +//mem_printf("%s %x\n", __func__, pvReturn); +// printf("%s %x %x\n", __func__, pvReturn, pxBlock); + return pvReturn; +} + +//void *malloc(size_t nbytes) __attribute__((alias("pvPortMalloc"))); + +/*-----------------------------------------------------------*/ +#ifndef MEMLEAK_DEBUG +void vPortFree( void *pv ) +#else +void vPortFree(void *pv, const char * file, unsigned line) +#endif +{ +unsigned char *puc = ( unsigned char * ) pv; +xBlockLink *pxLink; + +// printf("%s\n", __func__); + if( pv != NULL ) + { + /* The memory being freed will have an xBlockLink structure immediately + before it. */ + puc -= heapSTRUCT_SIZE; + + /* This casting is to keep the compiler from issuing warnings. */ + pxLink = ( void * ) puc; + +// vTaskSuspendAll(); + ETS_INTR_LOCK(); + { +#ifdef MEMLEAK_DEBUG + if(prvRemoveBlockFromUsedList(pxLink) < 0){ + ets_printf("%x already freed\n", pv); + } + else +#endif + { + /* Add this block to the list of free blocks. */ + xFreeBytesRemaining += pxLink->xBlockSize; + prvInsertBlockIntoFreeList( ( ( xBlockLink * ) pxLink ) ); + } + } +// xTaskResumeAll(); + ETS_INTR_UNLOCK(); + } + +// printf("%s %x %d\n", __func__, pv, xFreeBytesRemaining); +//mem_printf("%s %x %d\n", __func__, pv, xFreeBytesRemaining); +} + +//void free(void *ptr) __attribute__((alias("vPortFree"))); + +#ifndef MEMLEAK_DEBUG +void *malloc(size_t nbytes) __attribute__((alias("pvPortMalloc"))); +void free(void *ptr) __attribute__((alias("vPortFree"))); + +/*-----------------------------------------------------------*/ + +void *pvPortCalloc(size_t count, size_t size) +{ + void *p; + + /* allocate 'count' objects of size 'size' */ + p = pvPortMalloc(count * size); + if (p) { + /* zero the memory */ + memset(p, 0, count * size); + } + return p; +} + +void *calloc(size_t count, size_t nbytes) __attribute__((alias("pvPortCalloc"))); + +/*-----------------------------------------------------------*/ + +void *pvPortZalloc(size_t size) +{ + return pvPortCalloc(1, size); +} + +void *zalloc(size_t nbytes) __attribute__((alias("pvPortZalloc"))); + +/*-----------------------------------------------------------*/ + +void *pvPortRealloc(void *mem, size_t newsize) +{ + if (newsize == 0) { + vPortFree(mem); + return NULL; + } + + void *p; + p = pvPortMalloc(newsize); + if (p) { + /* zero the memory */ + if (mem != NULL) { + memcpy(p, mem, newsize); + vPortFree(mem); + } + } + return p; +} + +void *realloc(void *ptr, size_t nbytes) __attribute__((alias("pvPortRealloc"))); +/*-----------------------------------------------------------*/ + +#else + +/*-----------------------------------------------------------*/ +void *pvPortCalloc(size_t count, size_t size, const char * file, unsigned line) +{ + void *p; +//ets_printf("1,"); + /* allocate 'count' objects of size 'size' */ + p = pvPortMalloc(count * size, file, line); +//ets_printf("2,"); + if (p) { + /* zero the memory */ + memset(p, 0, count * size); + } +//ets_printf("3,"); + return p; +} +/*-----------------------------------------------------------*/ + +void *pvPortZalloc(size_t size, const char * file, unsigned line) +{ + return pvPortCalloc(1, size, file, line); +} +/*-----------------------------------------------------------*/ + +void *pvPortRealloc(void *mem, size_t newsize, const char *file, unsigned line) +{ + if (newsize == 0) { + vPortFree(mem, file, line); + return NULL; + } + + void *p; + p = pvPortMalloc(newsize, file, line); + if (p) { + /* zero the memory */ + if (mem != NULL) { + memcpy(p, mem, newsize); + vPortFree(mem, file, line); + } + } + return p; +} +/*-----------------------------------------------------------*/ +//For user +void *malloc(size_t nbytes) +{ +//ets_printf("u_m\n"); + return pvPortMalloc( nbytes, mem_debug_file, 0); +} + +void free(void *ptr) +{ +//ets_printf("u_f\n"); + vPortFree(ptr, mem_debug_file, 0); +} + +void *zalloc(size_t nbytes) +{ + return pvPortZalloc(nbytes, mem_debug_file, 0); +} + +void *calloc(size_t count, size_t nbytes) +{ + return pvPortCalloc(count, nbytes, mem_debug_file, 0); +} + +void *realloc(void *ptr, size_t nbytes) +{ + return pvPortRealloc(ptr, nbytes, mem_debug_file, 0); +} + +/* +void *malloc(size_t nbytes) __attribute__((alias("malloc1"))); +void free(void *ptr) __attribute__((alias("free1"))); +void *calloc(size_t count, size_t nbytes) __attribute__((alias("zalloc1"))); +void *zalloc(size_t nbytes) __attribute__((alias("calloc1"))); +void *realloc(void *ptr, size_t nbytes) __attribute__((alias("realloc1"))); +*/ +#endif + +size_t ICACHE_FLASH_ATTR +xPortGetFreeHeapSize( void ) +{ + return xFreeBytesRemaining; +} +/*-----------------------------------------------------------*/ + +void ICACHE_FLASH_ATTR +vPortInitialiseBlocks( void ) +{ + /* This just exists to keep the linker quiet. */ +} +/*-----------------------------------------------------------*/ + +static void prvHeapInit( void ) +{ +xBlockLink *pxFirstFreeBlock; +unsigned char *pucHeapEnd, *pucAlignedHeap; + + if( check_memleak_debug_enable() ){ + portBYTE_ALIGNMENT_MASK_v = 0xf; + portBYTE_ALIGNMENT_v = 16; + heapSTRUCT_SIZE = ( (sizeof( xBlockLink ) + portBYTE_ALIGNMENT_MASK_v)& ~portBYTE_ALIGNMENT_MASK_v); + } else { + portBYTE_ALIGNMENT_MASK_v = 0x7; + portBYTE_ALIGNMENT_v = 8; + heapSTRUCT_SIZE = 8; + } + + xFreeBytesRemaining = ( ( size_t ) heapADJUSTED_HEAP_SIZE ) & ( ( size_t ) ~portBYTE_ALIGNMENT_MASK_v ); + xTotalHeapSize = xFreeBytesRemaining ; + ucHeap = &_heap_start; + + /* Ensure the heap starts on a correctly aligned boundary. */ + pucAlignedHeap = ( unsigned char * ) ( ( ( portPOINTER_SIZE_TYPE ) &ucHeap[ portBYTE_ALIGNMENT_MASK_v ] ) & ( ( portPOINTER_SIZE_TYPE ) ~portBYTE_ALIGNMENT_MASK_v ) ); + + /* xStart is used to hold a pointer to the first item in the list of free + blocks. The void cast is used to prevent compiler warnings. */ + xStart.pxNextFreeBlock = ( void * ) pucAlignedHeap; + xStart.xBlockSize = ( size_t ) 0; + + /* pxEnd is used to mark the end of the list of free blocks and is inserted + at the end of the heap space. */ + pucHeapEnd = pucAlignedHeap + xTotalHeapSize; + pucHeapEnd -= heapSTRUCT_SIZE; + pxEnd = ( void * ) pucHeapEnd; + //configASSERT( ( ( ( unsigned long ) pxEnd ) & ( ( unsigned long ) portBYTE_ALIGNMENT_MASK ) ) == 0UL ); + pxEnd->xBlockSize = 0; + pxEnd->pxNextFreeBlock = NULL; + + /* To start with there is a single free block that is sized to take up the + entire heap space, minus the space taken by pxEnd. */ + pxFirstFreeBlock = ( void * ) pucAlignedHeap; + pxFirstFreeBlock->xBlockSize = xTotalHeapSize - heapSTRUCT_SIZE; + pxFirstFreeBlock->pxNextFreeBlock = pxEnd; + + /* The heap now contains pxEnd. */ + xFreeBytesRemaining -= heapSTRUCT_SIZE; + +#ifdef MEMLEAK_DEBUG + //add by jjj + yStart.pxNextFreeBlock = NULL; + yStart.xBlockSize = ( size_t ) 0; + yFreeBytesRemaining = 0; +#endif + +} +/*-----------------------------------------------------------*/ + +static void prvInsertBlockIntoFreeList( xBlockLink *pxBlockToInsert ) +{ +xBlockLink *pxIterator; +unsigned char *puc; + + /* Iterate through the list until a block is found that has a higher address than the block being inserted. */ + for( pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock ) + { + /* Nothing to do here, just iterate to the right position. */ + } + + /* Do the block being inserted, and the block it is being inserted after + make a contiguous block of memory? */ + puc = ( unsigned char * ) pxIterator; + if( ( puc + pxIterator->xBlockSize ) == ( unsigned char * ) pxBlockToInsert ) + { + pxIterator->xBlockSize += pxBlockToInsert->xBlockSize; + pxBlockToInsert = pxIterator; + } + + /* Do the block being inserted, and the block it is being inserted before + make a contiguous block of memory? */ + puc = ( unsigned char * ) pxBlockToInsert; + if( ( puc + pxBlockToInsert->xBlockSize ) == ( unsigned char * ) pxIterator->pxNextFreeBlock ) + { + if( pxIterator->pxNextFreeBlock != pxEnd ) + { + /* Form one big block from the two blocks. */ + pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize; + pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock; + } + else + { + pxBlockToInsert->pxNextFreeBlock = pxEnd; + } + } + else + { + pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock; + } + + /* If the block being inserted plugged a gab, so was merged with the block + before and the block after, then it's pxNextFreeBlock pointer will have + already been set, and should not be set here as that would make it point + to itself. */ + if( pxIterator != pxBlockToInsert ) + { + pxIterator->pxNextFreeBlock = pxBlockToInsert; + } +} + diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/freertos/list.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/freertos/list.c new file mode 100644 index 0000000..c6b23d0 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/freertos/list.c @@ -0,0 +1,208 @@ +/* + FreeRTOS V7.5.2 - Copyright (C) 2013 Real Time Engineers Ltd. + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that has become a de facto standard. * + * * + * Help yourself get started quickly and support the FreeRTOS * + * project by purchasing a FreeRTOS tutorial book, reference * + * manual, or both from: http://www.FreeRTOS.org/Documentation * + * * + * Thank you! * + * * + *************************************************************************** + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + >>! NOTE: The modification to the GPL is included to allow you to distribute + >>! a combined work that includes FreeRTOS without being obliged to provide + >>! the source code for proprietary components outside of the FreeRTOS + >>! kernel. + + FreeRTOS 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. Full license text is available from the following + link: http://www.freertos.org/a00114.html + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + + +#include +#include "freertos/FreeRTOS.h" +#include "freertos/list.h" + +/*----------------------------------------------------------- + * PUBLIC LIST API documented in list.h + *----------------------------------------------------------*/ + +void ICACHE_FLASH_ATTR +vListInitialise( xList * const pxList ) +{ + /* The list structure contains a list item which is used to mark the + end of the list. To initialise the list the list end is inserted + as the only list entry. */ + pxList->pxIndex = ( xListItem * ) &( pxList->xListEnd ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ + + /* The list end value is the highest possible value in the list to + ensure it remains at the end of the list. */ + pxList->xListEnd.xItemValue = portMAX_DELAY; + + /* The list end next and previous pointers point to itself so we know + when the list is empty. */ + pxList->xListEnd.pxNext = ( xListItem * ) &( pxList->xListEnd ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ + pxList->xListEnd.pxPrevious = ( xListItem * ) &( pxList->xListEnd );/*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ + + pxList->uxNumberOfItems = ( unsigned portBASE_TYPE ) 0U; +} +/*-----------------------------------------------------------*/ + +void ICACHE_FLASH_ATTR +vListInitialiseItem( xListItem * const pxItem ) +{ + /* Make sure the list item is not recorded as being on a list. */ + pxItem->pvContainer = NULL; +} +/*-----------------------------------------------------------*/ + +void +vListInsertEnd( xList * const pxList, xListItem * const pxNewListItem ) +{ +xListItem * pxIndex; + + /* Insert a new list item into pxList, but rather than sort the list, + makes the new list item the last item to be removed by a call to + pvListGetOwnerOfNextEntry. */ + pxIndex = pxList->pxIndex; + + pxNewListItem->pxNext = pxIndex; + pxNewListItem->pxPrevious = pxIndex->pxPrevious; + pxIndex->pxPrevious->pxNext = pxNewListItem; + pxIndex->pxPrevious = pxNewListItem; + + /* Remember which list the item is in. */ + pxNewListItem->pvContainer = ( void * ) pxList; + + ( pxList->uxNumberOfItems )++; +} +/*-----------------------------------------------------------*/ + +void ICACHE_FLASH_ATTR +vListInsert( xList * const pxList, xListItem * const pxNewListItem ) +{ +xListItem *pxIterator; +portTickType xValueOfInsertion; + + /* Insert the new list item into the list, sorted in ulListItem order. */ + xValueOfInsertion = pxNewListItem->xItemValue; + + /* If the list already contains a list item with the same item value then + the new list item should be placed after it. This ensures that TCB's which + are stored in ready lists (all of which have the same ulListItem value) + get an equal share of the CPU. However, if the xItemValue is the same as + the back marker the iteration loop below will not end. This means we need + to guard against this by checking the value first and modifying the + algorithm slightly if necessary. */ + if( xValueOfInsertion == portMAX_DELAY ) + { + pxIterator = pxList->xListEnd.pxPrevious; + } + else + { + /* *** NOTE *********************************************************** + If you find your application is crashing here then likely causes are: + 1) Stack overflow - + see http://www.freertos.org/Stacks-and-stack-overflow-checking.html + 2) Incorrect interrupt priority assignment, especially on Cortex-M3 + parts where numerically high priority values denote low actual + interrupt priories, which can seem counter intuitive. See + configMAX_SYSCALL_INTERRUPT_PRIORITY on http://www.freertos.org/a00110.html + 3) Calling an API function from within a critical section or when + the scheduler is suspended, or calling an API function that does + not end in "FromISR" from an interrupt. + 4) Using a queue or semaphore before it has been initialised or + before the scheduler has been started (are interrupts firing + before vTaskStartScheduler() has been called?). + See http://www.freertos.org/FAQHelp.html for more tips. + **********************************************************************/ + + for( pxIterator = ( xListItem * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ + { + /* There is nothing to do here, we are just iterating to the + wanted insertion position. */ + } + } + + pxNewListItem->pxNext = pxIterator->pxNext; + pxNewListItem->pxNext->pxPrevious = pxNewListItem; + pxNewListItem->pxPrevious = pxIterator; + pxIterator->pxNext = pxNewListItem; + + /* Remember which list the item is in. This allows fast removal of the + item later. */ + pxNewListItem->pvContainer = ( void * ) pxList; + + ( pxList->uxNumberOfItems )++; +} +/*-----------------------------------------------------------*/ + +unsigned portBASE_TYPE +uxListRemove( xListItem * const pxItemToRemove ) +{ +xList * pxList; + + pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious; + pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext; + + /* The list item knows which list it is in. Obtain the list from the list + item. */ + pxList = ( xList * ) pxItemToRemove->pvContainer; + + /* Make sure the index is left pointing to a valid item. */ + if( pxList->pxIndex == pxItemToRemove ) + { + pxList->pxIndex = pxItemToRemove->pxPrevious; + } + + pxItemToRemove->pvContainer = NULL; + ( pxList->uxNumberOfItems )--; + + return pxList->uxNumberOfItems; +} +/*-----------------------------------------------------------*/ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/freertos/port.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/freertos/port.c new file mode 100644 index 0000000..415c9d0 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/freertos/port.c @@ -0,0 +1,401 @@ +/* + FreeRTOS V7.5.2 - Copyright (C) 2013 Real Time Engineers Ltd. + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that has become a de facto standard. * + * * + * Help yourself get started quickly and support the FreeRTOS * + * project by purchasing a FreeRTOS tutorial book, reference * + * manual, or both from: http://www.FreeRTOS.org/Documentation * + * * + * Thank you! * + * * + *************************************************************************** + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + >>! NOTE: The modification to the GPL is included to allow you to distribute + >>! a combined work that includes FreeRTOS without being obliged to provide + >>! the source code for proprietary components outside of the FreeRTOS + >>! kernel. + + FreeRTOS 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. Full license text is available from the following + link: http://www.freertos.org/a00114.html + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/*----------------------------------------------------------- + * Implementation of functions defined in portable.h for the ARM CM3 port. + *----------------------------------------------------------*/ + +/* Scheduler includes. */ +#include +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/xtensa_rtos.h" + +#define PORT_ASSERT(x) do { if (!(x)) {ets_printf("%s %u\n", "rtos_port", __LINE__); while(1){}; }} while (0) + +extern char NMIIrqIsOn; +static char HdlMacSig = 0; +static char SWReq = 0; +static char PendSvIsPosted = 0; + +unsigned cpu_sr; + +/* Each task maintains its own interrupt status in the critical nesting +variable. */ +static unsigned portBASE_TYPE uxCriticalNesting = 0; + +void vPortEnterCritical( void ); +void vPortExitCritical( void ); +/* + * See header file for description. + */ +portSTACK_TYPE * ICACHE_FLASH_ATTR +pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters ) +{ + #define SET_STKREG(r,v) sp[(r) >> 2] = (portSTACK_TYPE)(v) + portSTACK_TYPE *sp, *tp; + + /* Create interrupt stack frame aligned to 16 byte boundary */ + sp = (portSTACK_TYPE*) (((INT32U)(pxTopOfStack+1) - XT_CP_SIZE - XT_STK_FRMSZ) & ~0xf); + + /* Clear the entire frame (do not use memset() because we don't depend on C library) */ + for (tp = sp; tp <= pxTopOfStack; ++tp) + *tp = 0; + + /* Explicitly initialize certain saved registers */ + SET_STKREG( XT_STK_PC, pxCode ); /* task entrypoint */ + SET_STKREG( XT_STK_A0, 0 ); /* to terminate GDB backtrace */ + SET_STKREG( XT_STK_A1, (INT32U)sp + XT_STK_FRMSZ ); /* physical top of stack frame */ + SET_STKREG( XT_STK_A2, pvParameters ); /* parameters */ + SET_STKREG( XT_STK_EXIT, _xt_user_exit ); /* user exception exit dispatcher */ + + /* Set initial PS to int level 0, EXCM disabled ('rfe' will enable), user mode. */ + #ifdef __XTENSA_CALL0_ABI__ + SET_STKREG( XT_STK_PS, PS_UM | PS_EXCM ); + #else + /* + for windowed ABI also set WOE and CALLINC (pretend task was 'call4'd). */ + SET_STKREG( XT_STK_PS, PS_UM | PS_EXCM | PS_WOE | PS_CALLINC(1) ); + #endif + + return sp; +} + + +void PendSV( char req ) +{ + char tmp=0; +//ETS_INTR_LOCK(); + + if( NMIIrqIsOn == 0 ) + { + vPortEnterCritical(); + //PortDisableInt_NoNest(); + tmp = 1; + } + + if(req ==1) + { + SWReq = 1; + } + else if(req ==2) + HdlMacSig= 1; +#if 0 + GPIO_REG_WRITE(GPIO_STATUS_W1TS_ADDRESS, 0x40); +#else + if(PendSvIsPosted == 0) + { + PendSvIsPosted = 1; + xthal_set_intset(1< 0) + { + uxCriticalNesting--; + if( uxCriticalNesting == 0 ) + { + if( ClosedLv1Isr ==1 ) + { + ClosedLv1Isr = 0; + portENABLE_INTERRUPTS(); + } + } + } + else + { + ets_printf("E:C:%d\n",uxCriticalNesting); + PORT_ASSERT((uxCriticalNesting>0)); + } + } +} + +void ShowCritical(void) +{ + ets_printf("ShowCritical:%d\n",uxCriticalNesting); + ets_delay_us(50000); +} + + +void vPortETSIntrLock( void ) +{ + ETS_INTR_LOCK(); +} + +void vPortETSIntrUnlock( void ) +{ + ETS_INTR_UNLOCK(); +} + +void +PortDisableInt_NoNest( void ) +{ +// printf("ERRRRRRR\n"); + if(NMIIrqIsOn == 0) + { + if( ClosedLv1Isr !=1 ) + { + portDISABLE_INTERRUPTS(); + ClosedLv1Isr = 1; + } + } +} + +void +PortEnableInt_NoNest( void ) +{ +// printf("ERRRRR\n"); + + if(NMIIrqIsOn == 0) + { + if( ClosedLv1Isr ==1 ) + { + ClosedLv1Isr = 0; + portENABLE_INTERRUPTS(); + } + } +} + +/*-----------------------------------------------------------*/ +void ICACHE_FLASH_ATTR ResetCcountVal( unsigned int cnt_val ) +{ +// XT_WSR_CCOUNT(cnt_val); + asm volatile("wsr a2, ccount"); +} + +_xt_isr_entry isr[16]; +char _xt_isr_status = 0; + +void ICACHE_FLASH_ATTR +_xt_isr_attach(uint8 i, _xt_isr func, void *arg) +{ + isr[i].handler = func; + isr[i].arg = arg; +} + +uint16 _xt_isr_handler(uint16 i) +{ + uint8 index; + + if (i & (1 << ETS_WDT_INUM)) { +// printf("i %x %u\n", i, REG_READ(0x3ff20c00)); + index = ETS_WDT_INUM; + } + else if (i & (1 << ETS_GPIO_INUM)) { + index = ETS_GPIO_INUM; + }else { + index = __builtin_ffs(i) - 1; + + if (index == ETS_MAX_INUM) { + i &= ~(1 << ETS_MAX_INUM); + index = __builtin_ffs(i) - 1; + } + } + + _xt_clear_ints(1<>!AND MODIFIED BY!<< the FreeRTOS exception. + + >>! NOTE: The modification to the GPL is included to allow you to distribute + >>! a combined work that includes FreeRTOS without being obliged to provide + >>! the source code for proprietary components outside of the FreeRTOS + >>! kernel. + + FreeRTOS 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. Full license text is available from the following + link: http://www.freertos.org/a00114.html + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#include +#include + +/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining +all the API functions to use the MPU wrappers. That should only be done when +task.h is included from an application file. */ +#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" + +#if ( configUSE_CO_ROUTINES == 1 ) + #include "freertos/croutine.h" +#endif + +/* Lint e961 and e750 are suppressed as a MISRA exception justified because the +MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the +header files above, but not in this file, in order to generate the correct +privileged Vs unprivileged linkage and placement. */ +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */ + + +/* Constants used with the cRxLock and xTxLock structure members. */ +#define queueUNLOCKED ( ( signed portBASE_TYPE ) -1 ) +#define queueLOCKED_UNMODIFIED ( ( signed portBASE_TYPE ) 0 ) + +/* When the xQUEUE structure is used to represent a base queue its pcHead and +pcTail members are used as pointers into the queue storage area. When the +xQUEUE structure is used to represent a mutex pcHead and pcTail pointers are +not necessary, and the pcHead pointer is set to NULL to indicate that the +pcTail pointer actually points to the mutex holder (if any). Map alternative +names to the pcHead and pcTail structure members to ensure the readability of +the code is maintained despite this dual use of two structure members. An +alternative implementation would be to use a union, but use of a union is +against the coding standard (although an exception to the standard has been +permitted where the dual use also significantly changes the type of the +structure member). */ +#define pxMutexHolder pcTail +#define uxQueueType pcHead +#define queueQUEUE_IS_MUTEX NULL + +/* Semaphores do not actually store or copy data, so have an item size of +zero. */ +#define queueSEMAPHORE_QUEUE_ITEM_LENGTH ( ( unsigned portBASE_TYPE ) 0 ) +#define queueMUTEX_GIVE_BLOCK_TIME ( ( portTickType ) 0U ) + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + + +/* + * Definition of the queue used by the scheduler. + * Items are queued by copy, not reference. + */ +typedef struct QueueDefinition +{ + signed char *pcHead; /*< Points to the beginning of the queue storage area. */ + signed char *pcTail; /*< Points to the byte at the end of the queue storage area. Once more byte is allocated than necessary to store the queue items, this is used as a marker. */ + + signed char *pcWriteTo; /*< Points to the free next place in the storage area. */ + + union /* Use of a union is an exception to the coding standard to ensure two mutually exclusive structure members don't appear simultaneously (wasting RAM). */ + { + signed char *pcReadFrom; /*< Points to the last place that a queued item was read from when the structure is used as a queue. */ + unsigned portBASE_TYPE uxRecursiveCallCount;/*< Maintains a count of the numebr of times a recursive mutex has been recursively 'taken' when the structure is used as a mutex. */ + } u; + + xList xTasksWaitingToSend; /*< List of tasks that are blocked waiting to post onto this queue. Stored in priority order. */ + xList xTasksWaitingToReceive; /*< List of tasks that are blocked waiting to read from this queue. Stored in priority order. */ + + volatile unsigned portBASE_TYPE uxMessagesWaiting;/*< The number of items currently in the queue. */ + unsigned portBASE_TYPE uxLength; /*< The length of the queue defined as the number of items it will hold, not the number of bytes. */ + unsigned portBASE_TYPE uxItemSize; /*< The size of each items that the queue will hold. */ + + volatile signed portBASE_TYPE xRxLock; /*< Stores the number of items received from the queue (removed from the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */ + volatile signed portBASE_TYPE xTxLock; /*< Stores the number of items transmitted to the queue (added to the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */ + + #if ( configUSE_TRACE_FACILITY == 1 ) + unsigned char ucQueueNumber; + unsigned char ucQueueType; + #endif + + #if ( configUSE_QUEUE_SETS == 1 ) + struct QueueDefinition *pxQueueSetContainer; + #endif + +} xQUEUE; +/*-----------------------------------------------------------*/ + +/* + * The queue registry is just a means for kernel aware debuggers to locate + * queue structures. It has no other purpose so is an optional component. + */ +#if ( configQUEUE_REGISTRY_SIZE > 0 ) + + /* The type stored within the queue registry array. This allows a name + to be assigned to each queue making kernel aware debugging a little + more user friendly. */ + typedef struct QUEUE_REGISTRY_ITEM + { + signed char *pcQueueName; + xQueueHandle xHandle; + } xQueueRegistryItem; + + /* The queue registry is simply an array of xQueueRegistryItem structures. + The pcQueueName member of a structure being NULL is indicative of the + array position being vacant. */ + xQueueRegistryItem xQueueRegistry[ configQUEUE_REGISTRY_SIZE ]; + +#endif /* configQUEUE_REGISTRY_SIZE */ + +/* + * Unlocks a queue locked by a call to prvLockQueue. Locking a queue does not + * prevent an ISR from adding or removing items to the queue, but does prevent + * an ISR from removing tasks from the queue event lists. If an ISR finds a + * queue is locked it will instead increment the appropriate queue lock count + * to indicate that a task may require unblocking. When the queue in unlocked + * these lock counts are inspected, and the appropriate action taken. + */ +static void prvUnlockQueue( xQUEUE *pxQueue ) PRIVILEGED_FUNCTION; + +/* + * Uses a critical section to determine if there is any data in a queue. + * + * @return pdTRUE if the queue contains no items, otherwise pdFALSE. + */ +static signed portBASE_TYPE prvIsQueueEmpty( const xQUEUE *pxQueue ) PRIVILEGED_FUNCTION; + +/* + * Uses a critical section to determine if there is any space in a queue. + * + * @return pdTRUE if there is no space, otherwise pdFALSE; + */ +static signed portBASE_TYPE prvIsQueueFull( const xQUEUE *pxQueue ) PRIVILEGED_FUNCTION; + +/* + * Copies an item into the queue, either at the front of the queue or the + * back of the queue. + */ +static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition ) PRIVILEGED_FUNCTION; + +/* + * Copies an item out of a queue. + */ +static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void * const pvBuffer ) PRIVILEGED_FUNCTION; + +#if ( configUSE_QUEUE_SETS == 1 ) + /* + * Checks to see if a queue is a member of a queue set, and if so, notifies + * the queue set that the queue contains data. + */ + static portBASE_TYPE prvNotifyQueueSetContainer( const xQUEUE * const pxQueue, portBASE_TYPE xCopyPosition ) PRIVILEGED_FUNCTION; +#endif + +/*-----------------------------------------------------------*/ + +/* + * Macro to mark a queue as locked. Locking a queue prevents an ISR from + * accessing the queue event lists. + */ +#define prvLockQueue( pxQueue ) \ + taskENTER_CRITICAL(); \ + { \ + if( ( pxQueue )->xRxLock == queueUNLOCKED ) \ + { \ + ( pxQueue )->xRxLock = queueLOCKED_UNMODIFIED; \ + } \ + if( ( pxQueue )->xTxLock == queueUNLOCKED ) \ + { \ + ( pxQueue )->xTxLock = queueLOCKED_UNMODIFIED; \ + } \ + } \ + taskEXIT_CRITICAL() +/*-----------------------------------------------------------*/ + +portBASE_TYPE ICACHE_FLASH_ATTR +xQueueGenericReset( xQueueHandle xQueue, portBASE_TYPE xNewQueue ) +{ +xQUEUE * const pxQueue = ( xQUEUE * ) xQueue; + + configASSERT( pxQueue ); + + taskENTER_CRITICAL(); + { + pxQueue->pcTail = pxQueue->pcHead + ( pxQueue->uxLength * pxQueue->uxItemSize ); + pxQueue->uxMessagesWaiting = ( unsigned portBASE_TYPE ) 0U; + pxQueue->pcWriteTo = pxQueue->pcHead; + pxQueue->u.pcReadFrom = pxQueue->pcHead + ( ( pxQueue->uxLength - ( unsigned portBASE_TYPE ) 1U ) * pxQueue->uxItemSize ); + pxQueue->xRxLock = queueUNLOCKED; + pxQueue->xTxLock = queueUNLOCKED; + + if( xNewQueue == pdFALSE ) + { + /* If there are tasks blocked waiting to read from the queue, then + the tasks will remain blocked as after this function exits the queue + will still be empty. If there are tasks blocked waiting to write to + the queue, then one should be unblocked as after this function exits + it will be possible to write to it. */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE ) + { + portYIELD_WITHIN_API(); + } + } + } + else + { + /* Ensure the event queues start in the correct state. */ + vListInitialise( &( pxQueue->xTasksWaitingToSend ) ); + vListInitialise( &( pxQueue->xTasksWaitingToReceive ) ); + } + } + taskEXIT_CRITICAL(); + + /* A value is returned for calling semantic consistency with previous + versions. */ + return pdPASS; +} +/*-----------------------------------------------------------*/ + +xQueueHandle ICACHE_FLASH_ATTR +xQueueGenericCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize, unsigned char ucQueueType ) +{ +xQUEUE *pxNewQueue; +size_t xQueueSizeInBytes; +xQueueHandle xReturn = NULL; + + /* Remove compiler warnings about unused parameters should + configUSE_TRACE_FACILITY not be set to 1. */ + ( void ) ucQueueType; + + /* Allocate the new queue structure. */ + if( uxQueueLength > ( unsigned portBASE_TYPE ) 0 ) + { + pxNewQueue = ( xQUEUE * ) os_malloc( sizeof( xQUEUE ) ); + if( pxNewQueue != NULL ) + { + /* Create the list of pointers to queue items. The queue is one byte + longer than asked for to make wrap checking easier/faster. */ + xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ) + ( size_t ) 1; /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + + pxNewQueue->pcHead = ( signed char * ) os_malloc( xQueueSizeInBytes ); + if( pxNewQueue->pcHead != NULL ) + { + /* Initialise the queue members as described above where the + queue type is defined. */ + pxNewQueue->uxLength = uxQueueLength; + pxNewQueue->uxItemSize = uxItemSize; + ( void ) xQueueGenericReset( pxNewQueue, pdTRUE ); + + #if ( configUSE_TRACE_FACILITY == 1 ) + { + pxNewQueue->ucQueueType = ucQueueType; + } + #endif /* configUSE_TRACE_FACILITY */ + + #if( configUSE_QUEUE_SETS == 1 ) + { + pxNewQueue->pxQueueSetContainer = NULL; + } + #endif /* configUSE_QUEUE_SETS */ + + traceQUEUE_CREATE( pxNewQueue ); + xReturn = pxNewQueue; + } + else + { + traceQUEUE_CREATE_FAILED( ucQueueType ); + os_free( pxNewQueue ); + } + } + } + + configASSERT( xReturn ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +#if ( configUSE_MUTEXES == 1 ) + + xQueueHandle ICACHE_FLASH_ATTR + xQueueCreateMutex( unsigned char ucQueueType ) + { + xQUEUE *pxNewQueue; + + /* Prevent compiler warnings about unused parameters if + configUSE_TRACE_FACILITY does not equal 1. */ + ( void ) ucQueueType; + + /* Allocate the new queue structure. */ + pxNewQueue = ( xQUEUE * ) os_malloc( sizeof( xQUEUE ) ); + if( pxNewQueue != NULL ) + { + /* Information required for priority inheritance. */ + pxNewQueue->pxMutexHolder = NULL; + pxNewQueue->uxQueueType = queueQUEUE_IS_MUTEX; + + /* Queues used as a mutex no data is actually copied into or out + of the queue. */ + pxNewQueue->pcWriteTo = NULL; + pxNewQueue->u.pcReadFrom = NULL; + + /* Each mutex has a length of 1 (like a binary semaphore) and + an item size of 0 as nothing is actually copied into or out + of the mutex. */ + pxNewQueue->uxMessagesWaiting = ( unsigned portBASE_TYPE ) 0U; + pxNewQueue->uxLength = ( unsigned portBASE_TYPE ) 1U; + pxNewQueue->uxItemSize = ( unsigned portBASE_TYPE ) 0U; + pxNewQueue->xRxLock = queueUNLOCKED; + pxNewQueue->xTxLock = queueUNLOCKED; + + #if ( configUSE_TRACE_FACILITY == 1 ) + { + pxNewQueue->ucQueueType = ucQueueType; + } + #endif + + #if ( configUSE_QUEUE_SETS == 1 ) + { + pxNewQueue->pxQueueSetContainer = NULL; + } + #endif + + /* Ensure the event queues start with the correct state. */ + vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) ); + vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) ); + + traceCREATE_MUTEX( pxNewQueue ); + + /* Start with the semaphore in the expected state. */ + ( void ) xQueueGenericSend( pxNewQueue, NULL, ( portTickType ) 0U, queueSEND_TO_BACK ); + } + else + { + traceCREATE_MUTEX_FAILED(); + } + + configASSERT( pxNewQueue ); + return pxNewQueue; + } + +#endif /* configUSE_MUTEXES */ +/*-----------------------------------------------------------*/ + +#if ( ( configUSE_MUTEXES == 1 ) && ( INCLUDE_xSemaphoreGetMutexHolder == 1 ) ) + + void* ICACHE_FLASH_ATTR + xQueueGetMutexHolder( xQueueHandle xSemaphore ) + { + void *pxReturn; + + /* This function is called by xSemaphoreGetMutexHolder(), and should not + be called directly. Note: This is is a good way of determining if the + calling task is the mutex holder, but not a good way of determining the + identity of the mutex holder, as the holder may change between the + following critical section exiting and the function returning. */ + taskENTER_CRITICAL(); + { + if( ( ( xQUEUE * ) xSemaphore )->uxQueueType == queueQUEUE_IS_MUTEX ) + { + pxReturn = ( void * ) ( ( xQUEUE * ) xSemaphore )->pxMutexHolder; + } + else + { + pxReturn = NULL; + } + } + taskEXIT_CRITICAL(); + + return pxReturn; + } + +#endif +/*-----------------------------------------------------------*/ + +#if ( configUSE_RECURSIVE_MUTEXES == 1 ) + + portBASE_TYPE ICACHE_FLASH_ATTR + xQueueGiveMutexRecursive( xQueueHandle xMutex ) + { + portBASE_TYPE xReturn; + xQUEUE * const pxMutex = ( xQUEUE * ) xMutex; + + configASSERT( pxMutex ); + + /* If this is the task that holds the mutex then pxMutexHolder will not + change outside of this task. If this task does not hold the mutex then + pxMutexHolder can never coincidentally equal the tasks handle, and as + this is the only condition we are interested in it does not matter if + pxMutexHolder is accessed simultaneously by another task. Therefore no + mutual exclusion is required to test the pxMutexHolder variable. */ + if( pxMutex->pxMutexHolder == ( void * ) xTaskGetCurrentTaskHandle() ) /*lint !e961 Not a redundant cast as xTaskHandle is a typedef. */ + { + traceGIVE_MUTEX_RECURSIVE( pxMutex ); + + /* uxRecursiveCallCount cannot be zero if pxMutexHolder is equal to + the task handle, therefore no underflow check is required. Also, + uxRecursiveCallCount is only modified by the mutex holder, and as + there can only be one, no mutual exclusion is required to modify the + uxRecursiveCallCount member. */ + ( pxMutex->u.uxRecursiveCallCount )--; + + /* Have we unwound the call count? */ + if( pxMutex->u.uxRecursiveCallCount == ( unsigned portBASE_TYPE ) 0 ) + { + /* Return the mutex. This will automatically unblock any other + task that might be waiting to access the mutex. */ + ( void ) xQueueGenericSend( pxMutex, NULL, queueMUTEX_GIVE_BLOCK_TIME, queueSEND_TO_BACK ); + } + + xReturn = pdPASS; + } + else + { + /* We cannot give the mutex because we are not the holder. */ + xReturn = pdFAIL; + + traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex ); + } + + return xReturn; + } + +#endif /* configUSE_RECURSIVE_MUTEXES */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_RECURSIVE_MUTEXES == 1 ) + + portBASE_TYPE ICACHE_FLASH_ATTR + xQueueTakeMutexRecursive( xQueueHandle xMutex, portTickType xBlockTime ) + { + portBASE_TYPE xReturn; + xQUEUE * const pxMutex = ( xQUEUE * ) xMutex; + + configASSERT( pxMutex ); + + /* Comments regarding mutual exclusion as per those within + xQueueGiveMutexRecursive(). */ + + traceTAKE_MUTEX_RECURSIVE( pxMutex ); + + if( pxMutex->pxMutexHolder == ( void * ) xTaskGetCurrentTaskHandle() ) /*lint !e961 Cast is not redundant as xTaskHandle is a typedef. */ + { + ( pxMutex->u.uxRecursiveCallCount )++; + xReturn = pdPASS; + } + else + { + xReturn = xQueueGenericReceive( pxMutex, NULL, xBlockTime, pdFALSE ); + + /* pdPASS will only be returned if we successfully obtained the mutex, + we may have blocked to reach here. */ + if( xReturn == pdPASS ) + { + ( pxMutex->u.uxRecursiveCallCount )++; + } + else + { + traceTAKE_MUTEX_RECURSIVE_FAILED( pxMutex ); + } + } + + return xReturn; + } + +#endif /* configUSE_RECURSIVE_MUTEXES */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_COUNTING_SEMAPHORES == 1 ) + + xQueueHandle ICACHE_FLASH_ATTR + xQueueCreateCountingSemaphore( unsigned portBASE_TYPE uxCountValue, unsigned portBASE_TYPE uxInitialCount ) + { + xQueueHandle xHandle; + + xHandle = xQueueGenericCreate( uxCountValue, queueSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_COUNTING_SEMAPHORE ); + + if( xHandle != NULL ) + { + ( ( xQUEUE * ) xHandle )->uxMessagesWaiting = uxInitialCount; + + traceCREATE_COUNTING_SEMAPHORE(); + } + else + { + traceCREATE_COUNTING_SEMAPHORE_FAILED(); + } + + configASSERT( xHandle ); + return xHandle; + } + +#endif /* configUSE_COUNTING_SEMAPHORES */ +/*-----------------------------------------------------------*/ + +signed portBASE_TYPE ICACHE_FLASH_ATTR +xQueueGenericSend( xQueueHandle xQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ) +{ +signed portBASE_TYPE xEntryTimeSet = pdFALSE; +xTimeOutType xTimeOut; +xQUEUE * const pxQueue = ( xQUEUE * ) xQueue; + + configASSERT( pxQueue ); + configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) ); + configASSERT( !( ( xCopyPosition == queueOVERWRITE ) && ( pxQueue->uxLength != 1 ) ) ); + + /* This function relaxes the coding standard somewhat to allow return + statements within the function itself. This is done in the interest + of execution time efficiency. */ + for( ;; ) + { + taskENTER_CRITICAL(); + { + /* Is there room on the queue now? The running task must be + the highest priority task wanting to access the queue. If + the head item in the queue is to be overwritten then it does + not matter if the queue is full. */ + if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) ) + { + traceQUEUE_SEND( pxQueue ); + prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition ); + + #if ( configUSE_QUEUE_SETS == 1 ) + { + if( pxQueue->pxQueueSetContainer != NULL ) + { + if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) == pdTRUE ) + { + /* The queue is a member of a queue set, and posting + to the queue set caused a higher priority task to + unblock. A context switch is required. */ + portYIELD_WITHIN_API(); + } + } + else + { + /* If there was a task waiting for data to arrive on the + queue then unblock it now. */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE ) + { + /* The unblocked task has a priority higher than + our own so yield immediately. Yes it is ok to + do this from within the critical section - the + kernel takes care of that. */ + portYIELD_WITHIN_API(); + } + } + } + } + #else /* configUSE_QUEUE_SETS */ + { + /* If there was a task waiting for data to arrive on the + queue then unblock it now. */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE ) + { + /* The unblocked task has a priority higher than + our own so yield immediately. Yes it is ok to do + this from within the critical section - the kernel + takes care of that. */ + portYIELD_WITHIN_API(); + } + } + } + #endif /* configUSE_QUEUE_SETS */ + + taskEXIT_CRITICAL(); + + /* Return to the original privilege level before exiting the + function. */ + return pdPASS; + } + else + { + if( xTicksToWait == ( portTickType ) 0 ) + { + /* The queue was full and no block time is specified (or + the block time has expired) so leave now. */ + taskEXIT_CRITICAL(); + + /* Return to the original privilege level before exiting + the function. */ + traceQUEUE_SEND_FAILED( pxQueue ); + return errQUEUE_FULL; + } + else if( xEntryTimeSet == pdFALSE ) + { + /* The queue was full and a block time was specified so + configure the timeout structure. */ + vTaskSetTimeOutState( &xTimeOut ); + xEntryTimeSet = pdTRUE; + } + else + { + /* Entry time was already set. */ + } + } + } + taskEXIT_CRITICAL(); + + /* Interrupts and other tasks can send to and receive from the queue + now the critical section has been exited. */ + + vTaskSuspendAll(); + prvLockQueue( pxQueue ); + + /* Update the timeout state to see if it has expired yet. */ + if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) + { + if( prvIsQueueFull( pxQueue ) != pdFALSE ) + { + traceBLOCKING_ON_QUEUE_SEND( pxQueue ); + vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait ); + + /* Unlocking the queue means queue events can effect the + event list. It is possible that interrupts occurring now + remove this task from the event list again - but as the + scheduler is suspended the task will go onto the pending + ready last instead of the actual ready list. */ + prvUnlockQueue( pxQueue ); + + /* Resuming the scheduler will move tasks from the pending + ready list into the ready list - so it is feasible that this + task is already in a ready list before it yields - in which + case the yield will not cause a context switch unless there + is also a higher priority task in the pending ready list. */ + if( xTaskResumeAll() == pdFALSE ) + { + portYIELD_WITHIN_API(); + } + } + else + { + /* Try again. */ + prvUnlockQueue( pxQueue ); + ( void ) xTaskResumeAll(); + } + } + else + { + /* The timeout has expired. */ + prvUnlockQueue( pxQueue ); + ( void ) xTaskResumeAll(); + + /* Return to the original privilege level before exiting the + function. */ + traceQUEUE_SEND_FAILED( pxQueue ); + return errQUEUE_FULL; + } + } +} +/*-----------------------------------------------------------*/ + +#if ( configUSE_ALTERNATIVE_API == 1 ) + + signed portBASE_TYPE ICACHE_FLASH_ATTR + xQueueAltGenericSend( xQueueHandle xQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ) + { + signed portBASE_TYPE xEntryTimeSet = pdFALSE; + xTimeOutType xTimeOut; + xQUEUE * const pxQueue = ( xQUEUE * ) xQueue; + + configASSERT( pxQueue ); + configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) ); + + for( ;; ) + { + taskENTER_CRITICAL(); + { + /* Is there room on the queue now? To be running we must be + the highest priority task wanting to access the queue. */ + if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) + { + traceQUEUE_SEND( pxQueue ); + prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition ); + + /* If there was a task waiting for data to arrive on the + queue then unblock it now. */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE ) + { + /* The unblocked task has a priority higher than + our own so yield immediately. */ + portYIELD_WITHIN_API(); + } + } + + taskEXIT_CRITICAL(); + return pdPASS; + } + else + { + if( xTicksToWait == ( portTickType ) 0 ) + { + taskEXIT_CRITICAL(); + return errQUEUE_FULL; + } + else if( xEntryTimeSet == pdFALSE ) + { + vTaskSetTimeOutState( &xTimeOut ); + xEntryTimeSet = pdTRUE; + } + } + } + taskEXIT_CRITICAL(); + + taskENTER_CRITICAL(); + { + if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) + { + if( prvIsQueueFull( pxQueue ) != pdFALSE ) + { + traceBLOCKING_ON_QUEUE_SEND( pxQueue ); + vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait ); + portYIELD_WITHIN_API(); + } + } + else + { + taskEXIT_CRITICAL(); + traceQUEUE_SEND_FAILED( pxQueue ); + return errQUEUE_FULL; + } + } + taskEXIT_CRITICAL(); + } + } + +#endif /* configUSE_ALTERNATIVE_API */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_ALTERNATIVE_API == 1 ) + + signed portBASE_TYPE ICACHE_FLASH_ATTR + xQueueAltGenericReceive( xQueueHandle xQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking ) + { + signed portBASE_TYPE xEntryTimeSet = pdFALSE; + xTimeOutType xTimeOut; + signed char *pcOriginalReadPosition; + xQUEUE * const pxQueue = ( xQUEUE * ) xQueue; + + configASSERT( pxQueue ); + configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) ); + + for( ;; ) + { + taskENTER_CRITICAL(); + { + if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) + { + /* Remember our read position in case we are just peeking. */ + pcOriginalReadPosition = pxQueue->u.pcReadFrom; + + prvCopyDataFromQueue( pxQueue, pvBuffer ); + + if( xJustPeeking == pdFALSE ) + { + traceQUEUE_RECEIVE( pxQueue ); + + /* Data is actually being removed (not just peeked). */ + --( pxQueue->uxMessagesWaiting ); + + #if ( configUSE_MUTEXES == 1 ) + { + if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) + { + /* Record the information required to implement + priority inheritance should it become necessary. */ + pxQueue->pxMutexHolder = ( signed char * ) xTaskGetCurrentTaskHandle(); + } + } + #endif + + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE ) + { + portYIELD_WITHIN_API(); + } + } + } + else + { + traceQUEUE_PEEK( pxQueue ); + + /* We are not removing the data, so reset our read + pointer. */ + pxQueue->u.pcReadFrom = pcOriginalReadPosition; + + /* The data is being left in the queue, so see if there are + any other tasks waiting for the data. */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + /* Tasks that are removed from the event list will get added to + the pending ready list as the scheduler is still suspended. */ + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The task waiting has a higher priority than this task. */ + portYIELD_WITHIN_API(); + } + } + + } + + taskEXIT_CRITICAL(); + return pdPASS; + } + else + { + if( xTicksToWait == ( portTickType ) 0 ) + { + taskEXIT_CRITICAL(); + traceQUEUE_RECEIVE_FAILED( pxQueue ); + return errQUEUE_EMPTY; + } + else if( xEntryTimeSet == pdFALSE ) + { + vTaskSetTimeOutState( &xTimeOut ); + xEntryTimeSet = pdTRUE; + } + } + } + taskEXIT_CRITICAL(); + + taskENTER_CRITICAL(); + { + if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) + { + if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) + { + traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ); + + #if ( configUSE_MUTEXES == 1 ) + { + if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) + { + portENTER_CRITICAL(); + { + vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder ); + } + portEXIT_CRITICAL(); + } + } + #endif + + vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); + portYIELD_WITHIN_API(); + } + } + else + { + taskEXIT_CRITICAL(); + traceQUEUE_RECEIVE_FAILED( pxQueue ); + return errQUEUE_EMPTY; + } + } + taskEXIT_CRITICAL(); + } + } + + +#endif /* configUSE_ALTERNATIVE_API */ +/*-----------------------------------------------------------*/ + +signed portBASE_TYPE ICACHE_FLASH_ATTR +xQueueGenericSendFromISR( xQueueHandle xQueue, const void * const pvItemToQueue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portBASE_TYPE xCopyPosition ) +{ +signed portBASE_TYPE xReturn; +unsigned portBASE_TYPE uxSavedInterruptStatus; +xQUEUE * const pxQueue = ( xQUEUE * ) xQueue; + + configASSERT( pxQueue ); + configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) ); + configASSERT( !( ( xCopyPosition == queueOVERWRITE ) && ( pxQueue->uxLength != 1 ) ) ); + + /* RTOS ports that support interrupt nesting have the concept of a maximum + system call (or maximum API call) interrupt priority. Interrupts that are + above the maximum system call priority are keep permanently enabled, even + when the RTOS kernel is in a critical section, but cannot make any calls to + FreeRTOS API functions. If configASSERT() is defined in FreeRTOSConfig.h + then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has been + assigned a priority above the configured maximum system call priority. + Only FreeRTOS functions that end in FromISR can be called from interrupts + that have been assigned a priority at or (logically) below the maximum + system call interrupt priority. FreeRTOS maintains a separate interrupt + safe API to ensure interrupt entry is as fast and as simple as possible. + More information (albeit Cortex-M specific) is provided on the following + link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + + /* Similar to xQueueGenericSend, except we don't block if there is no room + in the queue. Also we don't directly wake a task that was blocked on a + queue read, instead we return a flag to say whether a context switch is + required or not (i.e. has a task with a higher priority than us been woken + by this post). */ +// uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + portSET_INTERRUPT_MASK_FROM_ISR(); + + { + if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) ) + { + traceQUEUE_SEND_FROM_ISR( pxQueue ); + + prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition ); + + /* If the queue is locked we do not alter the event list. This will + be done when the queue is unlocked later. */ + if( pxQueue->xTxLock == queueUNLOCKED ) + { + #if ( configUSE_QUEUE_SETS == 1 ) + { + if( pxQueue->pxQueueSetContainer != NULL ) + { + if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) == pdTRUE ) + { + /* The queue is a member of a queue set, and posting + to the queue set caused a higher priority task to + unblock. A context switch is required. */ + if( pxHigherPriorityTaskWoken != NULL ) + { + *pxHigherPriorityTaskWoken = pdTRUE; + } + } + } + else + { + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The task waiting has a higher priority so record that a + context switch is required. */ + if( pxHigherPriorityTaskWoken != NULL ) + { + *pxHigherPriorityTaskWoken = pdTRUE; + } + } + } + } + } + #else /* configUSE_QUEUE_SETS */ + { + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The task waiting has a higher priority so record that a + context switch is required. */ + if( pxHigherPriorityTaskWoken != NULL ) + { + *pxHigherPriorityTaskWoken = pdTRUE; + } + } + } + } + #endif /* configUSE_QUEUE_SETS */ + } + else + { + /* Increment the lock count so the task that unlocks the queue + knows that data was posted while it was locked. */ + ++( pxQueue->xTxLock ); + } + + xReturn = pdPASS; + } + else + { + traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue ); + xReturn = errQUEUE_FULL; + } + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +signed portBASE_TYPE ICACHE_FLASH_ATTR +xQueueGenericReceive( xQueueHandle xQueue, const void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking ) +{ +signed portBASE_TYPE xEntryTimeSet = pdFALSE; +xTimeOutType xTimeOut; +signed char *pcOriginalReadPosition; +xQUEUE * const pxQueue = ( xQUEUE * ) xQueue; + + configASSERT( pxQueue ); + configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) ); + + /* This function relaxes the coding standard somewhat to allow return + statements within the function itself. This is done in the interest + of execution time efficiency. */ + + for( ;; ) + { + taskENTER_CRITICAL(); + { + /* Is there data in the queue now? To be running we must be + the highest priority task wanting to access the queue. */ + if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) + { + /* Remember the read position in case the queue is only being + peeked. */ + pcOriginalReadPosition = pxQueue->u.pcReadFrom; + + prvCopyDataFromQueue( pxQueue, pvBuffer ); + + if( xJustPeeking == pdFALSE ) + { + traceQUEUE_RECEIVE( pxQueue ); + + /* Actually removing data, not just peeking. */ + --( pxQueue->uxMessagesWaiting ); + + #if ( configUSE_MUTEXES == 1 ) + { + if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) + { + /* Record the information required to implement + priority inheritance should it become necessary. */ + pxQueue->pxMutexHolder = ( signed char * ) xTaskGetCurrentTaskHandle(); /*lint !e961 Cast is not redundant as xTaskHandle is a typedef. */ + } + } + #endif + + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE ) + { + portYIELD_WITHIN_API(); + } + } + } + else + { + traceQUEUE_PEEK( pxQueue ); + + /* The data is not being removed, so reset the read + pointer. */ + pxQueue->u.pcReadFrom = pcOriginalReadPosition; + + /* The data is being left in the queue, so see if there are + any other tasks waiting for the data. */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + /* Tasks that are removed from the event list will get added to + the pending ready list as the scheduler is still suspended. */ + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The task waiting has a higher priority than this task. */ + portYIELD_WITHIN_API(); + } + } + } + + taskEXIT_CRITICAL(); + return pdPASS; + } + else + { + if( xTicksToWait == ( portTickType ) 0 ) + { + /* The queue was empty and no block time is specified (or + the block time has expired) so leave now. */ + taskEXIT_CRITICAL(); + traceQUEUE_RECEIVE_FAILED( pxQueue ); + return errQUEUE_EMPTY; + } + else if( xEntryTimeSet == pdFALSE ) + { + /* The queue was empty and a block time was specified so + configure the timeout structure. */ + vTaskSetTimeOutState( &xTimeOut ); + xEntryTimeSet = pdTRUE; + } + else + { + /* Entry time was already set. */ + } + } + } + taskEXIT_CRITICAL(); + + /* Interrupts and other tasks can send to and receive from the queue + now the critical section has been exited. */ + + vTaskSuspendAll(); + prvLockQueue( pxQueue ); + + /* Update the timeout state to see if it has expired yet. */ + if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) + { + if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) + { + traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ); + + #if ( configUSE_MUTEXES == 1 ) + { + if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) + { + portENTER_CRITICAL(); + { + vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder ); + } + portEXIT_CRITICAL(); + } + } + #endif + + vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); + prvUnlockQueue( pxQueue ); + if( xTaskResumeAll() == pdFALSE ) + { + portYIELD_WITHIN_API(); + } + } + else + { + /* Try again. */ + prvUnlockQueue( pxQueue ); + ( void ) xTaskResumeAll(); + } + } + else + { + prvUnlockQueue( pxQueue ); + ( void ) xTaskResumeAll(); + traceQUEUE_RECEIVE_FAILED( pxQueue ); + return errQUEUE_EMPTY; + } + } +} +/*-----------------------------------------------------------*/ + +signed portBASE_TYPE ICACHE_FLASH_ATTR +xQueueReceiveFromISR( xQueueHandle xQueue, const void * const pvBuffer, signed portBASE_TYPE *pxHigherPriorityTaskWoken ) +{ +signed portBASE_TYPE xReturn; +unsigned portBASE_TYPE uxSavedInterruptStatus; +xQUEUE * const pxQueue = ( xQUEUE * ) xQueue; + + configASSERT( pxQueue ); + configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) ); + + /* RTOS ports that support interrupt nesting have the concept of a maximum + system call (or maximum API call) interrupt priority. Interrupts that are + above the maximum system call priority are keep permanently enabled, even + when the RTOS kernel is in a critical section, but cannot make any calls to + FreeRTOS API functions. If configASSERT() is defined in FreeRTOSConfig.h + then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has been + assigned a priority above the configured maximum system call priority. + Only FreeRTOS functions that end in FromISR can be called from interrupts + that have been assigned a priority at or (logically) below the maximum + system call interrupt priority. FreeRTOS maintains a separate interrupt + safe API to ensure interrupt entry is as fast and as simple as possible. + More information (albeit Cortex-M specific) is provided on the following + link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + +// uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + portSET_INTERRUPT_MASK_FROM_ISR(); + + { + /* Cannot block in an ISR, so check there is data available. */ + if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) + { + traceQUEUE_RECEIVE_FROM_ISR( pxQueue ); + + prvCopyDataFromQueue( pxQueue, pvBuffer ); + --( pxQueue->uxMessagesWaiting ); + + /* If the queue is locked the event list will not be modified. + Instead update the lock count so the task that unlocks the queue + will know that an ISR has removed data while the queue was + locked. */ + if( pxQueue->xRxLock == queueUNLOCKED ) + { + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) + { + /* The task waiting has a higher priority than us so + force a context switch. */ + if( pxHigherPriorityTaskWoken != NULL ) + { + *pxHigherPriorityTaskWoken = pdTRUE; + } + } + } + } + else + { + /* Increment the lock count so the task that unlocks the queue + knows that data was removed while it was locked. */ + ++( pxQueue->xRxLock ); + } + + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue ); + } + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +signed portBASE_TYPE ICACHE_FLASH_ATTR +xQueuePeekFromISR( xQueueHandle xQueue, const void * const pvBuffer ) +{ +signed portBASE_TYPE xReturn; +unsigned portBASE_TYPE uxSavedInterruptStatus; +signed char *pcOriginalReadPosition; +xQUEUE * const pxQueue = ( xQUEUE * ) xQueue; + + configASSERT( pxQueue ); + configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) ); + + /* RTOS ports that support interrupt nesting have the concept of a maximum + system call (or maximum API call) interrupt priority. Interrupts that are + above the maximum system call priority are keep permanently enabled, even + when the RTOS kernel is in a critical section, but cannot make any calls to + FreeRTOS API functions. If configASSERT() is defined in FreeRTOSConfig.h + then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has been + assigned a priority above the configured maximum system call priority. + Only FreeRTOS functions that end in FromISR can be called from interrupts + that have been assigned a priority at or (logically) below the maximum + system call interrupt priority. FreeRTOS maintains a separate interrupt + safe API to ensure interrupt entry is as fast and as simple as possible. + More information (albeit Cortex-M specific) is provided on the following + link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + +// uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + portSET_INTERRUPT_MASK_FROM_ISR(); + + { + /* Cannot block in an ISR, so check there is data available. */ + if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) + { + traceQUEUE_PEEK_FROM_ISR( pxQueue ); + + /* Remember the read position so it can be reset as nothing is + actually being removed from the queue. */ + pcOriginalReadPosition = pxQueue->u.pcReadFrom; + prvCopyDataFromQueue( pxQueue, pvBuffer ); + pxQueue->u.pcReadFrom = pcOriginalReadPosition; + + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + traceQUEUE_PEEK_FROM_ISR_FAILED( pxQueue ); + } + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +unsigned portBASE_TYPE ICACHE_FLASH_ATTR +uxQueueMessagesWaiting( const xQueueHandle xQueue ) +{ +unsigned portBASE_TYPE uxReturn; + + configASSERT( xQueue ); + + taskENTER_CRITICAL(); + uxReturn = ( ( xQUEUE * ) xQueue )->uxMessagesWaiting; + taskEXIT_CRITICAL(); + + return uxReturn; +} /*lint !e818 Pointer cannot be declared const as xQueue is a typedef not pointer. */ +/*-----------------------------------------------------------*/ + +unsigned portBASE_TYPE +uxQueueMessagesWaitingFromISR( const xQueueHandle xQueue ) +{ +unsigned portBASE_TYPE uxReturn; + + configASSERT( xQueue ); + + uxReturn = ( ( xQUEUE * ) xQueue )->uxMessagesWaiting; + + return uxReturn; +} /*lint !e818 Pointer cannot be declared const as xQueue is a typedef not pointer. */ +/*-----------------------------------------------------------*/ + +void ICACHE_FLASH_ATTR +vQueueDelete( xQueueHandle xQueue ) +{ +xQUEUE * const pxQueue = ( xQUEUE * ) xQueue; + + configASSERT( pxQueue ); + + traceQUEUE_DELETE( pxQueue ); + #if ( configQUEUE_REGISTRY_SIZE > 0 ) + { + vQueueUnregisterQueue( pxQueue ); + } + #endif + os_free( pxQueue->pcHead ); + os_free( pxQueue ); +} +/*-----------------------------------------------------------*/ + +#if ( configUSE_TRACE_FACILITY == 1 ) + + unsigned char ICACHE_FLASH_ATTR + ucQueueGetQueueNumber( xQueueHandle xQueue ) + { + return ( ( xQUEUE * ) xQueue )->ucQueueNumber; + } + +#endif /* configUSE_TRACE_FACILITY */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_TRACE_FACILITY == 1 ) + + void ICACHE_FLASH_ATTR + vQueueSetQueueNumber( xQueueHandle xQueue, unsigned char ucQueueNumber ) + { + ( ( xQUEUE * ) xQueue )->ucQueueNumber = ucQueueNumber; + } + +#endif /* configUSE_TRACE_FACILITY */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_TRACE_FACILITY == 1 ) + + unsigned char ICACHE_FLASH_ATTR + ucQueueGetQueueType( xQueueHandle xQueue ) + { + return ( ( xQUEUE * ) xQueue )->ucQueueType; + } + +#endif /* configUSE_TRACE_FACILITY */ +/*-----------------------------------------------------------*/ + +static void +prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition ) +{ + if( pxQueue->uxItemSize == ( unsigned portBASE_TYPE ) 0 ) + { + #if ( configUSE_MUTEXES == 1 ) + { + if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) + { + /* The mutex is no longer being held. */ + vTaskPriorityDisinherit( ( void * ) pxQueue->pxMutexHolder ); + pxQueue->pxMutexHolder = NULL; + } + } + #endif /* configUSE_MUTEXES */ + } + else if( xPosition == queueSEND_TO_BACK ) + { + ( void ) memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( size_t ) pxQueue->uxItemSize ); /*lint !e961 !e418 MISRA exception as the casts are only redundant for some ports, plus previous logic ensures a null pointer can only be passed to memcpy() if the copy size is 0. */ + pxQueue->pcWriteTo += pxQueue->uxItemSize; + if( pxQueue->pcWriteTo >= pxQueue->pcTail ) /*lint !e946 MISRA exception justified as comparison of pointers is the cleanest solution. */ + { + pxQueue->pcWriteTo = pxQueue->pcHead; + } + } + else + { + ( void ) memcpy( ( void * ) pxQueue->u.pcReadFrom, pvItemToQueue, ( size_t ) pxQueue->uxItemSize ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + pxQueue->u.pcReadFrom -= pxQueue->uxItemSize; + if( pxQueue->u.pcReadFrom < pxQueue->pcHead ) /*lint !e946 MISRA exception justified as comparison of pointers is the cleanest solution. */ + { + pxQueue->u.pcReadFrom = ( pxQueue->pcTail - pxQueue->uxItemSize ); + } + + if( xPosition == queueOVERWRITE ) + { + if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) + { + /* An item is not being added but overwritten, so subtract + one from the recorded number of items in the queue so when + one is added again below the number of recorded items remains + correct. */ + --( pxQueue->uxMessagesWaiting ); + } + } + } + + ++( pxQueue->uxMessagesWaiting ); +} +/*-----------------------------------------------------------*/ + +static void +prvCopyDataFromQueue( xQUEUE * const pxQueue, const void * const pvBuffer ) +{ + if( pxQueue->uxQueueType != queueQUEUE_IS_MUTEX ) + { + pxQueue->u.pcReadFrom += pxQueue->uxItemSize; + if( pxQueue->u.pcReadFrom >= pxQueue->pcTail ) /*lint !e946 MISRA exception justified as use of the relational operator is the cleanest solutions. */ + { + pxQueue->u.pcReadFrom = pxQueue->pcHead; + } + ( void ) memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->u.pcReadFrom, ( size_t ) pxQueue->uxItemSize ); /*lint !e961 !e418 MISRA exception as the casts are only redundant for some ports. Also previous logic ensures a null pointer can only be passed to memcpy() when the count is 0. */ + } +} +/*-----------------------------------------------------------*/ + +static void ICACHE_FLASH_ATTR +prvUnlockQueue( xQUEUE *pxQueue ) +{ + /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */ + + /* The lock counts contains the number of extra data items placed or + removed from the queue while the queue was locked. When a queue is + locked items can be added or removed, but the event lists cannot be + updated. */ + taskENTER_CRITICAL(); + { + /* See if data was added to the queue while it was locked. */ + while( pxQueue->xTxLock > queueLOCKED_UNMODIFIED ) + { + /* Data was posted while the queue was locked. Are any tasks + blocked waiting for data to become available? */ + #if ( configUSE_QUEUE_SETS == 1 ) + { + if( pxQueue->pxQueueSetContainer != NULL ) + { + if( prvNotifyQueueSetContainer( pxQueue, queueSEND_TO_BACK ) == pdTRUE ) + { + /* The queue is a member of a queue set, and posting to + the queue set caused a higher priority task to unblock. + A context switch is required. */ + vTaskMissedYield(); + } + } + else + { + /* Tasks that are removed from the event list will get added to + the pending ready list as the scheduler is still suspended. */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The task waiting has a higher priority so record that a + context switch is required. */ + vTaskMissedYield(); + } + } + else + { + break; + } + } + } + #else /* configUSE_QUEUE_SETS */ + { + /* Tasks that are removed from the event list will get added to + the pending ready list as the scheduler is still suspended. */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The task waiting has a higher priority so record that a + context switch is required. */ + vTaskMissedYield(); + } + } + else + { + break; + } + } + #endif /* configUSE_QUEUE_SETS */ + + --( pxQueue->xTxLock ); + } + + pxQueue->xTxLock = queueUNLOCKED; + } + taskEXIT_CRITICAL(); + + /* Do the same for the Rx lock. */ + taskENTER_CRITICAL(); + { + while( pxQueue->xRxLock > queueLOCKED_UNMODIFIED ) + { + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) + { + vTaskMissedYield(); + } + + --( pxQueue->xRxLock ); + } + else + { + break; + } + } + + pxQueue->xRxLock = queueUNLOCKED; + } + taskEXIT_CRITICAL(); +} +/*-----------------------------------------------------------*/ + +static signed portBASE_TYPE ICACHE_FLASH_ATTR +prvIsQueueEmpty( const xQUEUE *pxQueue ) +{ +signed portBASE_TYPE xReturn; + + taskENTER_CRITICAL(); + { + if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + } + taskEXIT_CRITICAL(); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +signed portBASE_TYPE ICACHE_FLASH_ATTR +xQueueIsQueueEmptyFromISR( const xQueueHandle xQueue ) +{ +signed portBASE_TYPE xReturn; + + configASSERT( xQueue ); + if( ( ( xQUEUE * ) xQueue )->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + + return xReturn; +} /*lint !e818 xQueue could not be pointer to const because it is a typedef. */ +/*-----------------------------------------------------------*/ + +static signed portBASE_TYPE ICACHE_FLASH_ATTR +prvIsQueueFull( const xQUEUE *pxQueue ) +{ +signed portBASE_TYPE xReturn; + + taskENTER_CRITICAL(); + { + if( pxQueue->uxMessagesWaiting == pxQueue->uxLength ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + } + taskEXIT_CRITICAL(); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +signed portBASE_TYPE ICACHE_FLASH_ATTR +xQueueIsQueueFullFromISR( const xQueueHandle xQueue ) +{ +signed portBASE_TYPE xReturn; + + configASSERT( xQueue ); + if( ( ( xQUEUE * ) xQueue )->uxMessagesWaiting == ( ( xQUEUE * ) xQueue )->uxLength ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + + return xReturn; +} /*lint !e818 xQueue could not be pointer to const because it is a typedef. */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_CO_ROUTINES == 1 ) + + signed portBASE_TYPE ICACHE_FLASH_ATTR + xQueueCRSend( xQueueHandle xQueue, const void *pvItemToQueue, portTickType xTicksToWait ) + { + signed portBASE_TYPE xReturn; + xQUEUE * const pxQueue = ( xQUEUE * ) xQueue; + + /* If the queue is already full we may have to block. A critical section + is required to prevent an interrupt removing something from the queue + between the check to see if the queue is full and blocking on the queue. */ + + //portDISABLE_INTERRUPTS(); +PortDisableInt_NoNest(); + { + if( prvIsQueueFull( pxQueue ) != pdFALSE ) + { + /* The queue is full - do we want to block or just leave without + posting? */ + if( xTicksToWait > ( portTickType ) 0 ) + { + /* As this is called from a coroutine we cannot block directly, but + return indicating that we need to block. */ + vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToSend ) ); + //portENABLE_INTERRUPTS(); +PortEnableInt_NoNest(); + return errQUEUE_BLOCKED; + } + else + { + //portENABLE_INTERRUPTS(); +PortEnableInt_NoNest(); + return errQUEUE_FULL; + } + } + } + //portENABLE_INTERRUPTS(); +PortEnableInt_NoNest(); + + //portDISABLE_INTERRUPTS(); +PortDisableInt_NoNest(); + { + if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) + { + /* There is room in the queue, copy the data into the queue. */ + prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK ); + xReturn = pdPASS; + + /* Were any co-routines waiting for data to become available? */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + /* In this instance the co-routine could be placed directly + into the ready list as we are within a critical section. + Instead the same pending ready list mechanism is used as if + the event were caused from within an interrupt. */ + if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The co-routine waiting has a higher priority so record + that a yield might be appropriate. */ + xReturn = errQUEUE_YIELD; + } + } + } + else + { + xReturn = errQUEUE_FULL; + } + } + //portENABLE_INTERRUPTS(); +PortEnableInt_NoNest(); + return xReturn; + } + +#endif /* configUSE_CO_ROUTINES */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_CO_ROUTINES == 1 ) + + signed portBASE_TYPE ICACHE_FLASH_ATTR + xQueueCRReceive( xQueueHandle xQueue, void *pvBuffer, portTickType xTicksToWait ) + { + signed portBASE_TYPE xReturn; + xQUEUE * const pxQueue = ( xQUEUE * ) xQueue; + + /* If the queue is already empty we may have to block. A critical section + is required to prevent an interrupt adding something to the queue + between the check to see if the queue is empty and blocking on the queue. */ + + //portDISABLE_INTERRUPTS(); +PortDisableInt_NoNest(); + { + if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 ) + { + /* There are no messages in the queue, do we want to block or just + leave with nothing? */ + if( xTicksToWait > ( portTickType ) 0 ) + { + /* As this is a co-routine we cannot block directly, but return + indicating that we need to block. */ + vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToReceive ) ); + //portENABLE_INTERRUPTS(); +PortEnableInt_NoNest(); + return errQUEUE_BLOCKED; + } + else + { + //portENABLE_INTERRUPTS(); +PortEnableInt_NoNest(); + return errQUEUE_FULL; + } + } + } + //portENABLE_INTERRUPTS(); +PortEnableInt_NoNest(); + + //portDISABLE_INTERRUPTS(); +PortDisableInt_NoNest(); + { + if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) + { + /* Data is available from the queue. */ + pxQueue->u.pcReadFrom += pxQueue->uxItemSize; + if( pxQueue->u.pcReadFrom >= pxQueue->pcTail ) + { + pxQueue->u.pcReadFrom = pxQueue->pcHead; + } + --( pxQueue->uxMessagesWaiting ); + ( void ) memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->u.pcReadFrom, ( unsigned ) pxQueue->uxItemSize ); + + xReturn = pdPASS; + + /* Were any co-routines waiting for space to become available? */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) + { + /* In this instance the co-routine could be placed directly + into the ready list as we are within a critical section. + Instead the same pending ready list mechanism is used as if + the event were caused from within an interrupt. */ + if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) + { + xReturn = errQUEUE_YIELD; + } + } + } + else + { + xReturn = pdFAIL; + } + } + //portENABLE_INTERRUPTS(); +PortEnableInt_NoNest(); + + return xReturn; + } + +#endif /* configUSE_CO_ROUTINES */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_CO_ROUTINES == 1 ) + + signed portBASE_TYPE ICACHE_FLASH_ATTR + xQueueCRSendFromISR( xQueueHandle xQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken ) + { + xQUEUE * const pxQueue = ( xQUEUE * ) xQueue; + + /* Cannot block within an ISR so if there is no space on the queue then + exit without doing anything. */ + if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) + { + prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK ); + + /* We only want to wake one co-routine per ISR, so check that a + co-routine has not already been woken. */ + if( xCoRoutinePreviouslyWoken == pdFALSE ) + { + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + return pdTRUE; + } + } + } + } + + return xCoRoutinePreviouslyWoken; + } + +#endif /* configUSE_CO_ROUTINES */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_CO_ROUTINES == 1 ) + + signed portBASE_TYPE ICACHE_FLASH_ATTR + xQueueCRReceiveFromISR( xQueueHandle xQueue, void *pvBuffer, signed portBASE_TYPE *pxCoRoutineWoken ) + { + signed portBASE_TYPE xReturn; + xQUEUE * const pxQueue = ( xQUEUE * ) xQueue; + + /* We cannot block from an ISR, so check there is data available. If + not then just leave without doing anything. */ + if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) + { + /* Copy the data from the queue. */ + pxQueue->u.pcReadFrom += pxQueue->uxItemSize; + if( pxQueue->u.pcReadFrom >= pxQueue->pcTail ) + { + pxQueue->u.pcReadFrom = pxQueue->pcHead; + } + --( pxQueue->uxMessagesWaiting ); + ( void ) memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->u.pcReadFrom, ( unsigned ) pxQueue->uxItemSize ); + + if( ( *pxCoRoutineWoken ) == pdFALSE ) + { + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) + { + if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) + { + *pxCoRoutineWoken = pdTRUE; + } + } + } + + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + } + + return xReturn; + } + +#endif /* configUSE_CO_ROUTINES */ +/*-----------------------------------------------------------*/ + +#if ( configQUEUE_REGISTRY_SIZE > 0 ) + + void ICACHE_FLASH_ATTR + vQueueAddToRegistry( xQueueHandle xQueue, signed char *pcQueueName ) + { + unsigned portBASE_TYPE ux; + + /* See if there is an empty space in the registry. A NULL name denotes + a free slot. */ + for( ux = ( unsigned portBASE_TYPE ) 0U; ux < ( unsigned portBASE_TYPE ) configQUEUE_REGISTRY_SIZE; ux++ ) + { + if( xQueueRegistry[ ux ].pcQueueName == NULL ) + { + /* Store the information on this queue. */ + xQueueRegistry[ ux ].pcQueueName = pcQueueName; + xQueueRegistry[ ux ].xHandle = xQueue; + break; + } + } + } + +#endif /* configQUEUE_REGISTRY_SIZE */ +/*-----------------------------------------------------------*/ + +#if ( configQUEUE_REGISTRY_SIZE > 0 ) + + void ICACHE_FLASH_ATTR + vQueueUnregisterQueue( xQueueHandle xQueue ) + { + unsigned portBASE_TYPE ux; + + /* See if the handle of the queue being unregistered in actually in the + registry. */ + for( ux = ( unsigned portBASE_TYPE ) 0U; ux < ( unsigned portBASE_TYPE ) configQUEUE_REGISTRY_SIZE; ux++ ) + { + if( xQueueRegistry[ ux ].xHandle == xQueue ) + { + /* Set the name to NULL to show that this slot if free again. */ + xQueueRegistry[ ux ].pcQueueName = NULL; + break; + } + } + + } /*lint !e818 xQueue could not be pointer to const because it is a typedef. */ + +#endif /* configQUEUE_REGISTRY_SIZE */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_TIMERS == 1 ) + + void ICACHE_FLASH_ATTR + vQueueWaitForMessageRestricted( xQueueHandle xQueue, portTickType xTicksToWait ) + { + xQUEUE * const pxQueue = ( xQUEUE * ) xQueue; + + /* This function should not be called by application code hence the + 'Restricted' in its name. It is not part of the public API. It is + designed for use by kernel code, and has special calling requirements. + It can result in vListInsert() being called on a list that can only + possibly ever have one item in it, so the list will be fast, but even + so it should be called with the scheduler locked and not from a critical + section. */ + + /* Only do anything if there are no messages in the queue. This function + will not actually cause the task to block, just place it on a blocked + list. It will not block until the scheduler is unlocked - at which + time a yield will be performed. If an item is added to the queue while + the queue is locked, and the calling task blocks on the queue, then the + calling task will be immediately unblocked when the queue is unlocked. */ + prvLockQueue( pxQueue ); + if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0U ) + { + /* There is nothing in the queue, block for the specified period. */ + vTaskPlaceOnEventListRestricted( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); + } + prvUnlockQueue( pxQueue ); + } + +#endif /* configUSE_TIMERS */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_QUEUE_SETS == 1 ) + + xQueueSetHandle ICACHE_FLASH_ATTR + xQueueCreateSet( unsigned portBASE_TYPE uxEventQueueLength ) + { + xQueueSetHandle pxQueue; + + pxQueue = xQueueGenericCreate( uxEventQueueLength, sizeof( xQUEUE * ), queueQUEUE_TYPE_SET ); + + return pxQueue; + } + +#endif /* configUSE_QUEUE_SETS */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_QUEUE_SETS == 1 ) + + portBASE_TYPE ICACHE_FLASH_ATTR + xQueueAddToSet( xQueueSetMemberHandle xQueueOrSemaphore, xQueueSetHandle xQueueSet ) + { + portBASE_TYPE xReturn; + + if( ( ( xQUEUE * ) xQueueOrSemaphore )->pxQueueSetContainer != NULL ) + { + /* Cannot add a queue/semaphore to more than one queue set. */ + xReturn = pdFAIL; + } + else if( ( ( xQUEUE * ) xQueueOrSemaphore )->uxMessagesWaiting != ( unsigned portBASE_TYPE ) 0 ) + { + /* Cannot add a queue/semaphore to a queue set if there are already + items in the queue/semaphore. */ + xReturn = pdFAIL; + } + else + { + taskENTER_CRITICAL(); + { + ( ( xQUEUE * ) xQueueOrSemaphore )->pxQueueSetContainer = xQueueSet; + } + taskEXIT_CRITICAL(); + xReturn = pdPASS; + } + + return xReturn; + } + +#endif /* configUSE_QUEUE_SETS */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_QUEUE_SETS == 1 ) + + portBASE_TYPE ICACHE_FLASH_ATTR + xQueueRemoveFromSet( xQueueSetMemberHandle xQueueOrSemaphore, xQueueSetHandle xQueueSet ) + { + portBASE_TYPE xReturn; + xQUEUE * const pxQueueOrSemaphore = ( xQUEUE * ) xQueueOrSemaphore; + + if( pxQueueOrSemaphore->pxQueueSetContainer != xQueueSet ) + { + /* The queue was not a member of the set. */ + xReturn = pdFAIL; + } + else if( pxQueueOrSemaphore->uxMessagesWaiting != ( unsigned portBASE_TYPE ) 0 ) + { + /* It is dangerous to remove a queue from a set when the queue is + not empty because the queue set will still hold pending events for + the queue. */ + xReturn = pdFAIL; + } + else + { + taskENTER_CRITICAL(); + { + /* The queue is no longer contained in the set. */ + pxQueueOrSemaphore->pxQueueSetContainer = NULL; + } + taskEXIT_CRITICAL(); + xReturn = pdPASS; + } + + return xReturn; + } /*lint !e818 xQueueSet could not be declared as pointing to const as it is a typedef. */ + +#endif /* configUSE_QUEUE_SETS */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_QUEUE_SETS == 1 ) + + xQueueSetMemberHandle ICACHE_FLASH_ATTR + xQueueSelectFromSet( xQueueSetHandle xQueueSet, portTickType xBlockTimeTicks ) + { + xQueueSetMemberHandle xReturn = NULL; + + ( void ) xQueueGenericReceive( ( xQueueHandle ) xQueueSet, &xReturn, xBlockTimeTicks, pdFALSE ); /*lint !e961 Casting from one typedef to another is not redundant. */ + return xReturn; + } + +#endif /* configUSE_QUEUE_SETS */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_QUEUE_SETS == 1 ) + + xQueueSetMemberHandle ICACHE_FLASH_ATTR + xQueueSelectFromSetFromISR( xQueueSetHandle xQueueSet ) + { + xQueueSetMemberHandle xReturn = NULL; + + ( void ) xQueueReceiveFromISR( ( xQueueHandle ) xQueueSet, &xReturn, NULL ); /*lint !e961 Casting from one typedef to another is not redundant. */ + return xReturn; + } + +#endif /* configUSE_QUEUE_SETS */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_QUEUE_SETS == 1 ) + + static portBASE_TYPE ICACHE_FLASH_ATTR + prvNotifyQueueSetContainer( const xQUEUE * const pxQueue, portBASE_TYPE xCopyPosition ) + { + xQUEUE *pxQueueSetContainer = pxQueue->pxQueueSetContainer; + portBASE_TYPE xReturn = pdFALSE; + + configASSERT( pxQueueSetContainer ); + configASSERT( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength ); + + if( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength ) + { + traceQUEUE_SEND( pxQueueSetContainer ); + /* The data copies is the handle of the queue that contains data. */ + prvCopyDataToQueue( pxQueueSetContainer, &pxQueue, xCopyPosition ); + if( listLIST_IS_EMPTY( &( pxQueueSetContainer->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueueSetContainer->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The task waiting has a higher priority */ + xReturn = pdTRUE; + } + } + } + + return xReturn; + } + +#endif /* configUSE_QUEUE_SETS */ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/freertos/readme.txt b/Distrib/ESPressif/RTOS/1.5.0/third_party/freertos/readme.txt new file mode 100644 index 0000000..81518ec --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/freertos/readme.txt @@ -0,0 +1,17 @@ +Each real time kernel port consists of three files that contain the core kernel +components and are common to every port, and one or more files that are +specific to a particular microcontroller and or compiler. + ++ The FreeRTOS/Source directory contains the three files that are common to +every port - list.c, queue.c and tasks.c. The kernel is contained within these +three files. croutine.c implements the optional co-routine functionality - which +is normally only used on very memory limited systems. + ++ The FreeRTOS/Source/Portable directory contains the files that are specific to +a particular microcontroller and or compiler. + ++ The FreeRTOS/Source/include directory contains the real time kernel header +files. + +See the readme file in the FreeRTOS/Source/Portable directory for more +information. \ No newline at end of file diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/freertos/tasks.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/freertos/tasks.c new file mode 100644 index 0000000..1a6752b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/freertos/tasks.c @@ -0,0 +1,3000 @@ +/* + FreeRTOS V7.5.2 - Copyright (C) 2013 Real Time Engineers Ltd. + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that has become a de facto standard. * + * * + * Help yourself get started quickly and support the FreeRTOS * + * project by purchasing a FreeRTOS tutorial book, reference * + * manual, or both from: http://www.FreeRTOS.org/Documentation * + * * + * Thank you! * + * * + *************************************************************************** + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + >>! NOTE: The modification to the GPL is included to allow you to distribute + >>! a combined work that includes FreeRTOS without being obliged to provide + >>! the source code for proprietary components outside of the FreeRTOS + >>! kernel. + + FreeRTOS 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. Full license text is available from the following + link: http://www.freertos.org/a00114.html + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* Standard includes. */ +#include +#include + +/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining +all the API functions to use the MPU wrappers. That should only be done when +task.h is included from an application file. */ +#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +/* FreeRTOS includes. */ +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/timers.h" +#include "freertos/StackMacros.h" + +/* Lint e961 and e750 are suppressed as a MISRA exception justified because the +MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the +header files above, but not in this file, in order to generate the correct +privileged Vs unprivileged linkage and placement. */ +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */ + +#if ( configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) + /* At the bottom of this file are two optional functions that can be used + to generate human readable text from the raw data generated by the + uxTaskGetSystemState() function. Note the formatting functions are provided + for convenience only, and are NOT considered part of the kernel. */ + #include +#endif /* ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) ) */ + +/* Sanity check the configuration. */ +#if configUSE_TICKLESS_IDLE != 0 + #if INCLUDE_vTaskSuspend != 1 + #error INCLUDE_vTaskSuspend must be set to 1 if configUSE_TICKLESS_IDLE is not set to 0 + #endif /* INCLUDE_vTaskSuspend */ +#endif /* configUSE_TICKLESS_IDLE */ + +/* + * Defines the size, in words, of the stack allocated to the idle task. + */ +#define tskIDLE_STACK_SIZE 384 + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +/* + * Task control block. A task control block (TCB) is allocated for each task, + * and stores task state information, including a pointer to the task's context + * (the task's run time environment, including register values) + */ +typedef struct tskTaskControlBlock +{ + volatile portSTACK_TYPE *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */ + + #if ( portUSING_MPU_WRAPPERS == 1 ) + xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */ + #endif + + xListItem xGenericListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */ + xListItem xEventListItem; /*< Used to reference a task from an event list. */ + unsigned portBASE_TYPE uxPriority; /*< The priority of the task. 0 is the lowest priority. */ + portSTACK_TYPE *pxStack; /*< Points to the start of the stack. */ + signed char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */ + + #if ( portSTACK_GROWTH > 0 ) + portSTACK_TYPE *pxEndOfStack; /*< Points to the end of the stack on architectures where the stack grows up from low memory. */ + #endif + + #if ( portCRITICAL_NESTING_IN_TCB == 1 ) + unsigned portBASE_TYPE uxCriticalNesting; /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */ + #endif + + #if ( configUSE_TRACE_FACILITY == 1 ) + unsigned portBASE_TYPE uxTCBNumber; /*< Stores a number that increments each time a TCB is created. It allows debuggers to determine when a task has been deleted and then recreated. */ + unsigned portBASE_TYPE uxTaskNumber; /*< Stores a number specifically for use by third party trace code. */ + #endif + + #if ( configUSE_MUTEXES == 1 ) + unsigned portBASE_TYPE uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */ + #endif + + #if ( configUSE_APPLICATION_TASK_TAG == 1 ) + pdTASK_HOOK_CODE pxTaskTag; + #endif + + #if ( configGENERATE_RUN_TIME_STATS == 1 ) + unsigned long ulRunTimeCounter; /*< Stores the amount of time the task has spent in the Running state. */ + #endif + + #if ( configUSE_NEWLIB_REENTRANT == 1 ) + /* Allocate a Newlib reent structure that is specific to this task. + Note Newlib support has been included by popular demand, but is not + used by the FreeRTOS maintainers themselves. FreeRTOS is not + responsible for resulting newlib operation. User must be familiar with + newlib and must provide system-wide implementations of the necessary + stubs. Be warned that (at the time of writing) the current newlib design + implements a system-wide malloc() that must be provided with locks. */ + struct _reent xNewLib_reent; + #endif + +} tskTCB; + + +/* + * Some kernel aware debuggers require the data the debugger needs access to to + * be global, rather than file scope. + */ +#ifdef portREMOVE_STATIC_QUALIFIER + #define static +#endif + +/*lint -e956 A manual analysis and inspection has been used to determine which +static variables must be declared volatile. */ + +PRIVILEGED_DATA tskTCB * volatile pxCurrentTCB = NULL; + +/* Lists for ready and blocked tasks. --------------------*/ +PRIVILEGED_DATA static xList pxReadyTasksLists[ configMAX_PRIORITIES ]; /*< Prioritised ready tasks. */ +PRIVILEGED_DATA static xList xDelayedTaskList1; /*< Delayed tasks. */ +PRIVILEGED_DATA static xList xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */ +PRIVILEGED_DATA static xList * volatile pxDelayedTaskList; /*< Points to the delayed task list currently being used. */ +PRIVILEGED_DATA static xList * volatile pxOverflowDelayedTaskList; /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */ +PRIVILEGED_DATA static xList xPendingReadyList; /*< Tasks that have been readied while the scheduler was suspended. They will be moved to the ready list when the scheduler is resumed. */ + +#if ( INCLUDE_vTaskDelete == 1 ) + + PRIVILEGED_DATA static xList xTasksWaitingTermination; /*< Tasks that have been deleted - but the their memory not yet freed. */ + PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTasksDeleted = ( unsigned portBASE_TYPE ) 0U; + +#endif + +#if ( INCLUDE_vTaskSuspend == 1 ) + + PRIVILEGED_DATA static xList xSuspendedTaskList; /*< Tasks that are currently suspended. */ + +#endif + +#if ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) + + PRIVILEGED_DATA static xTaskHandle xIdleTaskHandle = NULL; /*< Holds the handle of the idle task. The idle task is created automatically when the scheduler is started. */ + +#endif + +/* Other file private variables. --------------------------------*/ +PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxCurrentNumberOfTasks = ( unsigned portBASE_TYPE ) 0U; +PRIVILEGED_DATA static volatile portTickType xTickCount = ( portTickType ) 0U; +PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTopReadyPriority = tskIDLE_PRIORITY; +PRIVILEGED_DATA static volatile signed portBASE_TYPE xSchedulerRunning = pdFALSE; +PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxSchedulerSuspended = ( unsigned portBASE_TYPE ) pdFALSE; +PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxPendedTicks = ( unsigned portBASE_TYPE ) 0U; +PRIVILEGED_DATA static volatile portBASE_TYPE xYieldPending = pdFALSE; +PRIVILEGED_DATA static volatile portBASE_TYPE xNumOfOverflows = ( portBASE_TYPE ) 0; +PRIVILEGED_DATA static unsigned portBASE_TYPE uxTaskNumber = ( unsigned portBASE_TYPE ) 0U; +PRIVILEGED_DATA static volatile portTickType xNextTaskUnblockTime = portMAX_DELAY; + +#if ( configGENERATE_RUN_TIME_STATS == 1 ) + + PRIVILEGED_DATA static unsigned long ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */ + PRIVILEGED_DATA static unsigned long ulTotalRunTime = 0UL; /*< Holds the total amount of execution time as defined by the run time counter clock. */ + +#endif + +/*lint +e956 */ + +/* Debugging and trace facilities private variables and macros. ------------*/ + +/* + * The value used to fill the stack of a task when the task is created. This + * is used purely for checking the high water mark for tasks. + */ +#define tskSTACK_FILL_BYTE ( 0xa5U ) + +/* + * Macros used by vListTask to indicate which state a task is in. + */ +#define tskBLOCKED_CHAR ( ( signed char ) 'B' ) +#define tskREADY_CHAR ( ( signed char ) 'R' ) +#define tskDELETED_CHAR ( ( signed char ) 'D' ) +#define tskSUSPENDED_CHAR ( ( signed char ) 'S' ) + +/*-----------------------------------------------------------*/ + +#if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 ) + + /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is + performed in a generic way that is not optimised to any particular + microcontroller architecture. */ + + /* uxTopReadyPriority holds the priority of the highest priority ready + state task. */ + #define taskRECORD_READY_PRIORITY( uxPriority ) \ + { \ + if( ( uxPriority ) > uxTopReadyPriority ) \ + { \ + uxTopReadyPriority = ( uxPriority ); \ + } \ + } /* taskRECORD_READY_PRIORITY */ + + /*-----------------------------------------------------------*/ + + #define taskSELECT_HIGHEST_PRIORITY_TASK() \ + { \ + /* Find the highest priority queue that contains ready tasks. */ \ + while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) ) \ + { \ + configASSERT( uxTopReadyPriority ); \ + --uxTopReadyPriority; \ + } \ + \ + /* listGET_OWNER_OF_NEXT_ENTRY indexes through the list, so the tasks of \ + the same priority get an equal share of the processor time. */ \ + listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) ); \ + } /* taskSELECT_HIGHEST_PRIORITY_TASK */ + + /*-----------------------------------------------------------*/ + + /* Define away taskRESET_READY_PRIORITY() and portRESET_READY_PRIORITY() as + they are only required when a port optimised method of task selection is + being used. */ + #define taskRESET_READY_PRIORITY( uxPriority ) + #define portRESET_READY_PRIORITY( uxPriority, uxTopReadyPriority ) + +#else /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ + + /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 1 then task selection is + performed in a way that is tailored to the particular microcontroller + architecture being used. */ + + /* A port optimised version is provided. Call the port defined macros. */ + #define taskRECORD_READY_PRIORITY( uxPriority ) portRECORD_READY_PRIORITY( uxPriority, uxTopReadyPriority ) + + /*-----------------------------------------------------------*/ + + #define taskSELECT_HIGHEST_PRIORITY_TASK() \ + { \ + unsigned portBASE_TYPE uxTopPriority; \ + \ + /* Find the highest priority queue that contains ready tasks. */ \ + portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority ); \ + configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); \ + listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \ + } /* taskSELECT_HIGHEST_PRIORITY_TASK() */ + + /*-----------------------------------------------------------*/ + + /* A port optimised version is provided, call it only if the TCB being reset + is being referenced from a ready list. If it is referenced from a delayed + or suspended list then it won't be in a ready list. */ + #define taskRESET_READY_PRIORITY( uxPriority ) \ + { \ + if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ ( uxPriority ) ] ) ) == 0 ) \ + { \ + portRESET_READY_PRIORITY( ( uxPriority ), ( uxTopReadyPriority ) ); \ + } \ + } + +#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ + +/*-----------------------------------------------------------*/ + +/* pxDelayedTaskList and pxOverflowDelayedTaskList are switched when the tick +count overflows. */ +#define taskSWITCH_DELAYED_LISTS() \ +{ \ + xList *pxTemp; \ + \ + /* The delayed tasks list should be empty when the lists are switched. */ \ + configASSERT( ( listLIST_IS_EMPTY( pxDelayedTaskList ) ) ); \ + \ + pxTemp = pxDelayedTaskList; \ + pxDelayedTaskList = pxOverflowDelayedTaskList; \ + pxOverflowDelayedTaskList = pxTemp; \ + xNumOfOverflows++; \ + \ + if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) \ + { \ + /* The new current delayed list is empty. Set \ + xNextTaskUnblockTime to the maximum possible value so it is \ + extremely unlikely that the \ + if( xTickCount >= xNextTaskUnblockTime ) test will pass until \ + there is an item in the delayed list. */ \ + xNextTaskUnblockTime = portMAX_DELAY; \ + } \ + else \ + { \ + /* The new current delayed list is not empty, get the value of \ + the item at the head of the delayed list. This is the time at \ + which the task at the head of the delayed list should be removed \ + from the Blocked state. */ \ + pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); \ + xNextTaskUnblockTime = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ); \ + } \ +} + +/*-----------------------------------------------------------*/ + +/* + * Place the task represented by pxTCB into the appropriate ready list for + * the task. It is inserted at the end of the list. + */ +#define prvAddTaskToReadyList( pxTCB ) \ + traceMOVED_TASK_TO_READY_STATE( pxTCB ) \ + taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority ); \ + vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xGenericListItem ) ) +/*-----------------------------------------------------------*/ + +/* + * Several functions take an xTaskHandle parameter that can optionally be NULL, + * where NULL is used to indicate that the handle of the currently executing + * task should be used in place of the parameter. This macro simply checks to + * see if the parameter is NULL and returns a pointer to the appropriate TCB. + */ +#define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? ( tskTCB * ) pxCurrentTCB : ( tskTCB * ) ( pxHandle ) ) + +/* Callback function prototypes. --------------------------*/ +extern void vApplicationStackOverflowHook( xTaskHandle xTask, signed char *pcTaskName ); +extern void vApplicationTickHook( void ); + +/* File private functions. --------------------------------*/ + +/* + * Utility to ready a TCB for a given task. Mainly just copies the parameters + * into the TCB structure. + */ +static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth ) PRIVILEGED_FUNCTION; + +/* + * Utility to ready all the lists used by the scheduler. This is called + * automatically upon the creation of the first task. + */ +static void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION; + +/* + * The idle task, which as all tasks is implemented as a never ending loop. + * The idle task is automatically created and added to the ready lists upon + * creation of the first user task. + * + * The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific + * language extensions. The equivalent prototype for this function is: + * + * void prvIdleTask( void *pvParameters ); + * + */ +static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters ); + +/* + * Utility to free all memory allocated by the scheduler to hold a TCB, + * including the stack pointed to by the TCB. + * + * This does not free memory allocated by the task itself (i.e. memory + * allocated by calls to pvPortMalloc from within the tasks application code). + */ +#if ( INCLUDE_vTaskDelete == 1 ) + + static void prvDeleteTCB( tskTCB *pxTCB ) PRIVILEGED_FUNCTION; + +#endif + +/* + * Used only by the idle task. This checks to see if anything has been placed + * in the list of tasks waiting to be deleted. If so the task is cleaned up + * and its TCB deleted. + */ +static void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION; + +/* + * The currently executing task is entering the Blocked state. Add the task to + * either the current or the overflow delayed task list. + */ +static void prvAddCurrentTaskToDelayedList( portTickType xTimeToWake ) PRIVILEGED_FUNCTION; + +/* + * Allocates memory from the heap for a TCB and associated stack. Checks the + * allocation was successful. + */ +static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer ) PRIVILEGED_FUNCTION; + +/* + * Fills an xTaskStatusType structure with information on each task that is + * referenced from the pxList list (which may be a ready list, a delayed list, + * a suspended list, etc.). + * + * THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM + * NORMAL APPLICATION CODE. + */ +#if ( configUSE_TRACE_FACILITY == 1 ) + + static unsigned portBASE_TYPE prvListTaskWithinSingleList( xTaskStatusType *pxTaskStatusArray, xList *pxList, eTaskState eState ) PRIVILEGED_FUNCTION; + +#endif + +/* + * When a task is created, the stack of the task is filled with a known value. + * This function determines the 'high water mark' of the task stack by + * determining how much of the stack remains at the original preset value. + */ +#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) + + static unsigned short prvTaskCheckFreeStackSpace( const unsigned char * pucStackByte ) PRIVILEGED_FUNCTION; + +#endif + +/* + * Return the amount of time, in ticks, that will pass before the kernel will + * next move a task from the Blocked state to the Running state. + * + * This conditional compilation should use inequality to 0, not equality to 1. + * This is to ensure portSUPPRESS_TICKS_AND_SLEEP() can be called when user + * defined low power mode implementations require configUSE_TICKLESS_IDLE to be + * set to a value other than 1. + */ +#if ( configUSE_TICKLESS_IDLE != 0 ) + + //static portTickType prvGetExpectedIdleTime( void ) PRIVILEGED_FUNCTION; + //portTickType ICACHE_FLASH_ATTR prvGetExpectedIdleTime( void ) PRIVILEGED_FUNCTION; +#endif + +signed portBASE_TYPE ICACHE_FLASH_ATTR +xTaskGenericCreate( pdTASK_CODE pxTaskCode, const signed char * const pcName, unsigned short usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask, portSTACK_TYPE *puxStackBuffer, const xMemoryRegion * const xRegions ) +{ +signed portBASE_TYPE xReturn; +tskTCB * pxNewTCB; + + configASSERT( pxTaskCode ); + configASSERT( ( ( uxPriority & ( ~portPRIVILEGE_BIT ) ) < configMAX_PRIORITIES ) ); + + /* Allocate the memory required by the TCB and stack for the new task, + checking that the allocation was successful. */ + pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer ); + + if( pxNewTCB != NULL ) + { + portSTACK_TYPE *pxTopOfStack; + + #if( portUSING_MPU_WRAPPERS == 1 ) + /* Should the task be created in privileged mode? */ + portBASE_TYPE xRunPrivileged; + if( ( uxPriority & portPRIVILEGE_BIT ) != 0U ) + { + xRunPrivileged = pdTRUE; + } + else + { + xRunPrivileged = pdFALSE; + } + uxPriority &= ~portPRIVILEGE_BIT; + #endif /* portUSING_MPU_WRAPPERS == 1 */ + + /* Calculate the top of stack address. This depends on whether the + stack grows from high memory to low (as per the 80x86) or visa versa. + portSTACK_GROWTH is used to make the result positive or negative as + required by the port. */ + #if( portSTACK_GROWTH < 0 ) + { + pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - ( unsigned short ) 1 ); + pxTopOfStack = ( portSTACK_TYPE * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ( portPOINTER_SIZE_TYPE ) ~portBYTE_ALIGNMENT_MASK ) ); /*lint !e923 MISRA exception. Avoiding casts between pointers and integers is not practical. Size differences accounted for using portPOINTER_SIZE_TYPE type. */ + + /* Check the alignment of the calculated top of stack is correct. */ + configASSERT( ( ( ( unsigned long ) pxTopOfStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); + } + #else /* portSTACK_GROWTH */ + { + pxTopOfStack = pxNewTCB->pxStack; + + /* Check the alignment of the stack buffer is correct. */ + configASSERT( ( ( ( unsigned long ) pxNewTCB->pxStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); + + /* If we want to use stack checking on architectures that use + a positive stack growth direction then we also need to store the + other extreme of the stack space. */ + pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 ); + } + #endif /* portSTACK_GROWTH */ + + /* Setup the newly allocated TCB with the initial state of the task. */ + prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority, xRegions, usStackDepth ); + + /* Initialize the TCB stack to look as if the task was already running, + but had been interrupted by the scheduler. The return address is set + to the start of the task function. Once the stack has been initialised + the top of stack variable is updated. */ + #if( portUSING_MPU_WRAPPERS == 1 ) + { + pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged ); + } + #else /* portUSING_MPU_WRAPPERS */ + { + pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters ); + } + #endif /* portUSING_MPU_WRAPPERS */ + + if( ( void * ) pxCreatedTask != NULL ) + { + /* Pass the TCB out - in an anonymous way. The calling function/ + task can use this as a handle to delete the task later if + required.*/ + *pxCreatedTask = ( xTaskHandle ) pxNewTCB; + } + + /* Ensure interrupts don't access the task lists while they are being + updated. */ + taskENTER_CRITICAL(); + { + uxCurrentNumberOfTasks++; + if( pxCurrentTCB == NULL ) + { + /* There are no other tasks, or all the other tasks are in + the suspended state - make this the current task. */ + pxCurrentTCB = pxNewTCB; + + if( uxCurrentNumberOfTasks == ( unsigned portBASE_TYPE ) 1 ) + { + /* This is the first task to be created so do the preliminary + initialisation required. We will not recover if this call + fails, but we will report the failure. */ + prvInitialiseTaskLists(); + } + } + else + { + /* If the scheduler is not already running, make this task the + current task if it is the highest priority task to be created + so far. */ + if( xSchedulerRunning == pdFALSE ) + { + if( pxCurrentTCB->uxPriority <= uxPriority ) + { + pxCurrentTCB = pxNewTCB; + } + } + } + + uxTaskNumber++; + + #if ( configUSE_TRACE_FACILITY == 1 ) + { + /* Add a counter into the TCB for tracing only. */ + pxNewTCB->uxTCBNumber = uxTaskNumber; + } + #endif /* configUSE_TRACE_FACILITY */ + traceTASK_CREATE( pxNewTCB ); + + prvAddTaskToReadyList( pxNewTCB ); + + xReturn = pdPASS; + portSETUP_TCB( pxNewTCB ); + } + taskEXIT_CRITICAL(); + } + else + { + xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; + traceTASK_CREATE_FAILED(); + } + + if( xReturn == pdPASS ) + { + if( xSchedulerRunning != pdFALSE ) + { + /* If the created task is of a higher priority than the current task + then it should run now. */ + if( pxCurrentTCB->uxPriority < uxPriority ) + { + portYIELD_WITHIN_API(); + } + } + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_vTaskDelete == 1 ) + + void ICACHE_FLASH_ATTR + vTaskDelete( xTaskHandle xTaskToDelete ) + { + tskTCB *pxTCB; + + taskENTER_CRITICAL(); + { + /* If null is passed in here then we are deleting ourselves. */ + pxTCB = prvGetTCBFromHandle( xTaskToDelete ); + + /* Remove task from the ready list and place in the termination list. + This will stop the task from be scheduled. The idle task will check + the termination list and free up any memory allocated by the + scheduler for the TCB and stack. */ + if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( unsigned portBASE_TYPE ) 0 ) + { + taskRESET_READY_PRIORITY( pxTCB->uxPriority ); + } + + /* Is the task waiting on an event also? */ + if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) + { + ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); + } + + vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) ); + + /* Increment the ucTasksDeleted variable so the idle task knows + there is a task that has been deleted and that it should therefore + check the xTasksWaitingTermination list. */ + ++uxTasksDeleted; + + /* Increment the uxTaskNumberVariable also so kernel aware debuggers + can detect that the task lists need re-generating. */ + uxTaskNumber++; + + traceTASK_DELETE( pxTCB ); + } + taskEXIT_CRITICAL(); + + /* Force a reschedule if we have just deleted the current task. */ + if( xSchedulerRunning != pdFALSE ) + { + if( pxTCB == pxCurrentTCB ) + { + portYIELD_WITHIN_API(); + } + } + } + +#endif /* INCLUDE_vTaskDelete */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_vTaskDelayUntil == 1 ) + + void ICACHE_FLASH_ATTR + vTaskDelayUntil( portTickType * const pxPreviousWakeTime, portTickType xTimeIncrement ) + { + portTickType xTimeToWake; + portBASE_TYPE xAlreadyYielded, xShouldDelay = pdFALSE; + + configASSERT( pxPreviousWakeTime ); + configASSERT( ( xTimeIncrement > 0U ) ); + + vTaskSuspendAll(); + { + /* Minor optimisation. The tick count cannot change in this + block. */ + const portTickType xConstTickCount = xTickCount; + + /* Generate the tick time at which the task wants to wake. */ + xTimeToWake = *pxPreviousWakeTime + xTimeIncrement; + + if( xConstTickCount < *pxPreviousWakeTime ) + { + /* The tick count has overflowed since this function was + lasted called. In this case the only time we should ever + actually delay is if the wake time has also overflowed, + and the wake time is greater than the tick time. When this + is the case it is as if neither time had overflowed. */ + if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xConstTickCount ) ) + { + xShouldDelay = pdTRUE; + } + } + else + { + /* The tick time has not overflowed. In this case we will + delay if either the wake time has overflowed, and/or the + tick time is less than the wake time. */ + if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xConstTickCount ) ) + { + xShouldDelay = pdTRUE; + } + } + + /* Update the wake time ready for the next call. */ + *pxPreviousWakeTime = xTimeToWake; + + if( xShouldDelay != pdFALSE ) + { + traceTASK_DELAY_UNTIL(); + + /* We must remove ourselves from the ready list before adding + ourselves to the blocked list as the same list item is used for + both lists. */ + if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( unsigned portBASE_TYPE ) 0 ) + { + /* The current task must be in a ready list, so there is + no need to check, and the port reset macro can be called + directly. */ + portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); + } + + prvAddCurrentTaskToDelayedList( xTimeToWake ); + } + } + xAlreadyYielded = xTaskResumeAll(); + + /* Force a reschedule if xTaskResumeAll has not already done so, we may + have put ourselves to sleep. */ + if( xAlreadyYielded == pdFALSE ) + { + portYIELD_WITHIN_API(); + } + } + +#endif /* INCLUDE_vTaskDelayUntil */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_vTaskDelay == 1 ) + + void ICACHE_FLASH_ATTR + vTaskDelay( portTickType xTicksToDelay ) + { + portTickType xTimeToWake; + signed portBASE_TYPE xAlreadyYielded = pdFALSE; + + /* A delay time of zero just forces a reschedule. */ + if( xTicksToDelay > ( portTickType ) 0U ) + { + vTaskSuspendAll(); + { + traceTASK_DELAY(); + + /* A task that is removed from the event list while the + scheduler is suspended will not get placed in the ready + list or removed from the blocked list until the scheduler + is resumed. + + This task cannot be in an event list as it is the currently + executing task. */ + + /* Calculate the time to wake - this may overflow but this is + not a problem. */ + xTimeToWake = xTickCount + xTicksToDelay; + + /* We must remove ourselves from the ready list before adding + ourselves to the blocked list as the same list item is used for + both lists. */ + if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( unsigned portBASE_TYPE ) 0 ) + { + /* The current task must be in a ready list, so there is + no need to check, and the port reset macro can be called + directly. */ + portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); + } + prvAddCurrentTaskToDelayedList( xTimeToWake ); + } + xAlreadyYielded = xTaskResumeAll(); + } + + /* Force a reschedule if xTaskResumeAll has not already done so, we may + have put ourselves to sleep. */ + if( xAlreadyYielded == pdFALSE ) + { + portYIELD_WITHIN_API(); + } + } + +#endif /* INCLUDE_vTaskDelay */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_eTaskGetState == 1 ) + + eTaskState ICACHE_FLASH_ATTR + eTaskGetState( xTaskHandle xTask ) + { + eTaskState eReturn; + xList *pxStateList; + const tskTCB * const pxTCB = ( tskTCB * ) xTask; + + if( pxTCB == pxCurrentTCB ) + { + /* The task calling this function is querying its own state. */ + eReturn = eRunning; + } + else + { + taskENTER_CRITICAL(); + { + pxStateList = ( xList * ) listLIST_ITEM_CONTAINER( &( pxTCB->xGenericListItem ) ); + } + taskEXIT_CRITICAL(); + + if( ( pxStateList == pxDelayedTaskList ) || ( pxStateList == pxOverflowDelayedTaskList ) ) + { + /* The task being queried is referenced from one of the Blocked + lists. */ + eReturn = eBlocked; + } + + #if ( INCLUDE_vTaskSuspend == 1 ) + else if( pxStateList == &xSuspendedTaskList ) + { + /* The task being queried is referenced from the suspended + list. */ + eReturn = eSuspended; + } + #endif + + #if ( INCLUDE_vTaskDelete == 1 ) + else if( pxStateList == &xTasksWaitingTermination ) + { + /* The task being queried is referenced from the deleted + tasks list. */ + eReturn = eDeleted; + } + #endif + + else + { + /* If the task is not in any other state, it must be in the + Ready (including pending ready) state. */ + eReturn = eReady; + } + } + + return eReturn; + } + +#endif /* INCLUDE_eTaskGetState */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_uxTaskPriorityGet == 1 ) + + unsigned portBASE_TYPE ICACHE_FLASH_ATTR + uxTaskPriorityGet( xTaskHandle xTask ) + { + tskTCB *pxTCB; + unsigned portBASE_TYPE uxReturn; + + taskENTER_CRITICAL(); + { + /* If null is passed in here then we are changing the + priority of the calling function. */ + pxTCB = prvGetTCBFromHandle( xTask ); + uxReturn = pxTCB->uxPriority; + } + taskEXIT_CRITICAL(); + + return uxReturn; + } + +#endif /* INCLUDE_uxTaskPriorityGet */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_vTaskPrioritySet == 1 ) + + void ICACHE_FLASH_ATTR + vTaskPrioritySet( xTaskHandle xTask, unsigned portBASE_TYPE uxNewPriority ) + { + tskTCB *pxTCB; + unsigned portBASE_TYPE uxCurrentBasePriority, uxPriorityUsedOnEntry; + portBASE_TYPE xYieldRequired = pdFALSE; + + configASSERT( ( uxNewPriority < configMAX_PRIORITIES ) ); + + /* Ensure the new priority is valid. */ + if( uxNewPriority >= ( unsigned portBASE_TYPE ) configMAX_PRIORITIES ) + { + uxNewPriority = ( unsigned portBASE_TYPE ) configMAX_PRIORITIES - ( unsigned portBASE_TYPE ) 1U; + } + + taskENTER_CRITICAL(); + { + /* If null is passed in here then it is the priority of the calling + task that is being changed. */ + pxTCB = prvGetTCBFromHandle( xTask ); + + traceTASK_PRIORITY_SET( pxTCB, uxNewPriority ); + + #if ( configUSE_MUTEXES == 1 ) + { + uxCurrentBasePriority = pxTCB->uxBasePriority; + } + #else + { + uxCurrentBasePriority = pxTCB->uxPriority; + } + #endif + + if( uxCurrentBasePriority != uxNewPriority ) + { + /* The priority change may have readied a task of higher + priority than the calling task. */ + if( uxNewPriority > uxCurrentBasePriority ) + { + if( pxTCB != pxCurrentTCB ) + { + /* The priority of a task other than the currently + running task is being raised. Is the priority being + raised above that of the running task? */ + if( uxNewPriority >= pxCurrentTCB->uxPriority ) + { + xYieldRequired = pdTRUE; + } + } + else + { + /* The priority of the running task is being raised, + but the running task must already be the highest + priority task able to run so no yield is required. */ + } + } + else if( pxTCB == pxCurrentTCB ) + { + /* Setting the priority of the running task down means + there may now be another task of higher priority that + is ready to execute. */ + xYieldRequired = pdTRUE; + } + else + { + /* Setting the priority of any other task down does not + require a yield as the running task must be above the + new priority of the task being modified. */ + } + + /* Remember the ready list the task might be referenced from + before its uxPriority member is changed so the + taskRESET_READY_PRIORITY() macro can function correctly. */ + uxPriorityUsedOnEntry = pxTCB->uxPriority; + + #if ( configUSE_MUTEXES == 1 ) + { + /* Only change the priority being used if the task is not + currently using an inherited priority. */ + if( pxTCB->uxBasePriority == pxTCB->uxPriority ) + { + pxTCB->uxPriority = uxNewPriority; + } + + /* The base priority gets set whatever. */ + pxTCB->uxBasePriority = uxNewPriority; + } + #else + { + pxTCB->uxPriority = uxNewPriority; + } + #endif + + listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( ( portTickType ) configMAX_PRIORITIES - ( portTickType ) uxNewPriority ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + + /* If the task is in the blocked or suspended list we need do + nothing more than change it's priority variable. However, if + the task is in a ready list it needs to be removed and placed + in the list appropriate to its new priority. */ + if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xGenericListItem ) ) != pdFALSE ) + { + /* The task is currently in its ready list - remove before adding + it to it's new ready list. As we are in a critical section we + can do this even if the scheduler is suspended. */ + if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( unsigned portBASE_TYPE ) 0 ) + { + /* It is known that the task is in its ready list so + there is no need to check again and the port level + reset macro can be called directly. */ + portRESET_READY_PRIORITY( uxPriorityUsedOnEntry, uxTopReadyPriority ); + } + prvAddTaskToReadyList( pxTCB ); + } + + if( xYieldRequired == pdTRUE ) + { + portYIELD_WITHIN_API(); + } + + /* Remove compiler warning about unused variables when the port + optimised task selection is not being used. */ + ( void ) uxPriorityUsedOnEntry; + } + } + taskEXIT_CRITICAL(); + } + +#endif /* INCLUDE_vTaskPrioritySet */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_vTaskSuspend == 1 ) + + void ICACHE_FLASH_ATTR + vTaskSuspend( xTaskHandle xTaskToSuspend ) + { + tskTCB *pxTCB; + + taskENTER_CRITICAL(); + { + /* If null is passed in here then it is the running task that is + being suspended. */ + pxTCB = prvGetTCBFromHandle( xTaskToSuspend ); + + traceTASK_SUSPEND( pxTCB ); + + /* Remove task from the ready/delayed list and place in the suspended list. */ + if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( unsigned portBASE_TYPE ) 0 ) + { + taskRESET_READY_PRIORITY( pxTCB->uxPriority ); + } + + /* Is the task waiting on an event also? */ + if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) + { + ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); + } + + vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ); + } + taskEXIT_CRITICAL(); + + if( pxTCB == pxCurrentTCB ) + { + if( xSchedulerRunning != pdFALSE ) + { + /* The current task has just been suspended. */ + portYIELD_WITHIN_API(); + } + else + { + /* The scheduler is not running, but the task that was pointed + to by pxCurrentTCB has just been suspended and pxCurrentTCB + must be adjusted to point to a different task. */ + if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks ) + { + /* No other tasks are ready, so set pxCurrentTCB back to + NULL so when the next task is created pxCurrentTCB will + be set to point to it no matter what its relative priority + is. */ + pxCurrentTCB = NULL; + } + else + { + vTaskSwitchContext(); + } + } + } + } + +#endif /* INCLUDE_vTaskSuspend */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_vTaskSuspend == 1 ) + + signed portBASE_TYPE ICACHE_FLASH_ATTR + xTaskIsTaskSuspended( xTaskHandle xTask ) + { + portBASE_TYPE xReturn = pdFALSE; + const tskTCB * const pxTCB = ( tskTCB * ) xTask; + + /* It does not make sense to check if the calling task is suspended. */ + configASSERT( xTask ); + + /* Is the task we are attempting to resume actually in the + suspended list? */ + if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ) != pdFALSE ) + { + /* Has the task already been resumed from within an ISR? */ + if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) == pdFALSE ) + { + /* Is it in the suspended list because it is in the + Suspended state? It is possible to be in the suspended + list because it is blocked on a task with no timeout + specified. */ + if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) != pdFALSE ) + { + xReturn = pdTRUE; + } + } + } + + return xReturn; + } /*lint !e818 xTask cannot be a pointer to const because it is a typedef. */ + +#endif /* INCLUDE_vTaskSuspend */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_vTaskSuspend == 1 ) + + void ICACHE_FLASH_ATTR + vTaskResume( xTaskHandle xTaskToResume ) + { + tskTCB * const pxTCB = ( tskTCB * ) xTaskToResume; + + /* It does not make sense to resume the calling task. */ + configASSERT( xTaskToResume ); + + /* The parameter cannot be NULL as it is impossible to resume the + currently executing task. */ + if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) ) + { + taskENTER_CRITICAL(); + { + if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE ) + { + traceTASK_RESUME( pxTCB ); + + /* As we are in a critical section we can access the ready + lists even if the scheduler is suspended. */ + ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); + prvAddTaskToReadyList( pxTCB ); + + /* We may have just resumed a higher priority task. */ + if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) + { + /* This yield may not cause the task just resumed to run, but + will leave the lists in the correct state for the next yield. */ + portYIELD_WITHIN_API(); + } + } + } + taskEXIT_CRITICAL(); + } + } + +#endif /* INCLUDE_vTaskSuspend */ + +/*-----------------------------------------------------------*/ + +#if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) ) + + portBASE_TYPE ICACHE_FLASH_ATTR + xTaskResumeFromISR( xTaskHandle xTaskToResume ) + { + portBASE_TYPE xYieldRequired = pdFALSE; + tskTCB * const pxTCB = ( tskTCB * ) xTaskToResume; + unsigned portBASE_TYPE uxSavedInterruptStatus; + + configASSERT( xTaskToResume ); + + /* RTOS ports that support interrupt nesting have the concept of a + maximum system call (or maximum API call) interrupt priority. + Interrupts that are above the maximum system call priority are keep + permanently enabled, even when the RTOS kernel is in a critical section, + but cannot make any calls to FreeRTOS API functions. If configASSERT() + is defined in FreeRTOSConfig.h then + portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has + been assigned a priority above the configured maximum system call + priority. Only FreeRTOS functions that end in FromISR can be called + from interrupts that have been assigned a priority at or (logically) + below the maximum system call interrupt priority. FreeRTOS maintains a + separate interrupt safe API to ensure interrupt entry is as fast and as + simple as possible. More information (albeit Cortex-M specific) is + provided on the following link: + http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + +// uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + portSET_INTERRUPT_MASK_FROM_ISR(); + + { + if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE ) + { + traceTASK_RESUME_FROM_ISR( pxTCB ); + + if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE ) + { + xYieldRequired = ( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ); + ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); + prvAddTaskToReadyList( pxTCB ); + } + else + { + /* We cannot access the delayed or ready lists, so will hold this + task pending until the scheduler is resumed, at which point a + yield will be performed if necessary. */ + vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) ); + } + } + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + + return xYieldRequired; + } + +#endif /* ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) ) */ +/*-----------------------------------------------------------*/ + +void ICACHE_FLASH_ATTR +vTaskStartScheduler( void ) +{ +portBASE_TYPE xReturn; + + /* Add the idle task at the lowest priority. */ + #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) + { + /* Create the idle task, storing its handle in xIdleTaskHandle so it can + be returned by the xTaskGetIdleTaskHandle() function. */ + xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), &xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ + } + #else + { + /* Create the idle task without storing its handle. */ + xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), NULL ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ + } + #endif /* INCLUDE_xTaskGetIdleTaskHandle */ + + #if ( configUSE_TIMERS == 1 ) + { + if( xReturn == pdPASS ) + { + xReturn = xTimerCreateTimerTask(); + } + } + #endif /* configUSE_TIMERS */ + + if( xReturn == pdPASS ) + { + /* Interrupts are turned off here, to ensure a tick does not occur + before or during the call to xPortStartScheduler(). The stacks of + the created tasks contain a status word with interrupts switched on + so interrupts will automatically get re-enabled when the first task + starts to run. + + STEPPING THROUGH HERE USING A DEBUGGER CAN CAUSE BIG PROBLEMS IF THE + DEBUGGER ALLOWS INTERRUPTS TO BE PROCESSED. */ + //portDISABLE_INTERRUPTS(); +//PortDisableInt_NoNest(); + + xSchedulerRunning = pdTRUE; + xTickCount = ( portTickType ) 0U; + + /* If configGENERATE_RUN_TIME_STATS is defined then the following + macro must be defined to configure the timer/counter used to generate + the run time counter time base. */ + portCONFIGURE_TIMER_FOR_RUN_TIME_STATS(); + + /* Setting up the timer tick is hardware specific and thus in the + portable interface. */ + if( xPortStartScheduler() != pdFALSE ) + { + /* Should not reach here as if the scheduler is running the + function will not return. */ + } + else + { + /* Should only reach here if a task calls xTaskEndScheduler(). */ + } + } + else + { + /* This line will only be reached if the kernel could not be started, + because there was not enough FreeRTOS heap to create the idle task + or the timer task. */ + configASSERT( xReturn ); + } +} +/*-----------------------------------------------------------*/ + +void ICACHE_FLASH_ATTR +vTaskEndScheduler( void ) +{ + /* Stop the scheduler interrupts and call the portable scheduler end + routine so the original ISRs can be restored if necessary. The port + layer must ensure interrupts enable bit is left in the correct state. */ + + //portDISABLE_INTERRUPTS(); +PortDisableInt_NoNest(); + xSchedulerRunning = pdFALSE; + vPortEndScheduler(); +} +/*----------------------------------------------------------*/ + +void ICACHE_FLASH_ATTR +vTaskSuspendAll( void ) +{ + /* A critical section is not required as the variable is of type + portBASE_TYPE. */ + ++uxSchedulerSuspended; +} +/*----------------------------------------------------------*/ + +#if ( configUSE_TICKLESS_IDLE != 0 ) + + //static portTickType ICACHE_FLASH_ATTR + portTickType ICACHE_FLASH_ATTR prvGetExpectedIdleTime( void ) + { + portTickType xReturn; + + if( pxCurrentTCB->uxPriority > tskIDLE_PRIORITY ) + { + xReturn = 0; + } + else if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > 1 ) + { + /* There are other idle priority tasks in the ready state. If + time slicing is used then the very next tick interrupt must be + processed. */ + xReturn = 0; + } + else + { + xReturn = xNextTaskUnblockTime - xTickCount; + } + + return xReturn; + } + +#endif /* configUSE_TICKLESS_IDLE */ +/*----------------------------------------------------------*/ + +signed portBASE_TYPE ICACHE_FLASH_ATTR +xTaskResumeAll( void ) +{ +tskTCB *pxTCB; +portBASE_TYPE xAlreadyYielded = pdFALSE; +portBASE_TYPE xYieldRequired = pdFALSE; + + /* If uxSchedulerSuspended is zero then this function does not match a + previous call to vTaskSuspendAll(). */ + configASSERT( uxSchedulerSuspended ); + + /* It is possible that an ISR caused a task to be removed from an event + list while the scheduler was suspended. If this was the case then the + removed task will have been added to the xPendingReadyList. Once the + scheduler has been resumed it is safe to move all the pending ready + tasks from this list into their appropriate ready list. */ + taskENTER_CRITICAL(); + { + --uxSchedulerSuspended; + + if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE ) + { + if( uxCurrentNumberOfTasks > ( unsigned portBASE_TYPE ) 0U ) + { + /* Move any readied tasks from the pending list into the + appropriate ready list. */ + while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE ) + { + pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) ); + ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); + ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); + prvAddTaskToReadyList( pxTCB ); + + /* If we have moved a task that has a priority higher than + the current task then we should yield. */ + if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) + { + xYieldRequired = pdTRUE; + } + } + + /* If any ticks occurred while the scheduler was suspended then + they should be processed now. This ensures the tick count does not + slip, and that any delayed tasks are resumed at the correct time. */ + if( uxPendedTicks > ( unsigned portBASE_TYPE ) 0U ) + { + while( uxPendedTicks > ( unsigned portBASE_TYPE ) 0U ) + { + if( xTaskIncrementTick() != pdFALSE ) + { + xYieldRequired = pdTRUE; + } + --uxPendedTicks; + } + } + + if( ( xYieldRequired == pdTRUE ) || ( xYieldPending == pdTRUE ) ) + { + xAlreadyYielded = pdTRUE; + xYieldPending = pdFALSE; + portYIELD_WITHIN_API(); + } + } + } + } + taskEXIT_CRITICAL(); + + return xAlreadyYielded; +} +/*-----------------------------------------------------------*/ + +portTickType ICACHE_FLASH_ATTR +xTaskGetTickCount( void ) +{ +portTickType xTicks; + + /* Critical section required if running on a 16 bit processor. */ + taskENTER_CRITICAL(); + { + xTicks = xTickCount; + } + taskEXIT_CRITICAL(); + + return xTicks; +} +/*-----------------------------------------------------------*/ + +portTickType ICACHE_FLASH_ATTR +xTaskGetTickCountFromISR( void ) +{ +portTickType xReturn; +unsigned portBASE_TYPE uxSavedInterruptStatus; + + /* RTOS ports that support interrupt nesting have the concept of a maximum + system call (or maximum API call) interrupt priority. Interrupts that are + above the maximum system call priority are keep permanently enabled, even + when the RTOS kernel is in a critical section, but cannot make any calls to + FreeRTOS API functions. If configASSERT() is defined in FreeRTOSConfig.h + then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has been + assigned a priority above the configured maximum system call priority. + Only FreeRTOS functions that end in FromISR can be called from interrupts + that have been assigned a priority at or (logically) below the maximum + system call interrupt priority. FreeRTOS maintains a separate interrupt + safe API to ensure interrupt entry is as fast and as simple as possible. + More information (albeit Cortex-M specific) is provided on the following + link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + +// uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + portSET_INTERRUPT_MASK_FROM_ISR(); + + xReturn = xTickCount; + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +unsigned portBASE_TYPE ICACHE_FLASH_ATTR +uxTaskGetNumberOfTasks( void ) +{ + /* A critical section is not required because the variables are of type + portBASE_TYPE. */ + return uxCurrentNumberOfTasks; +} +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_pcTaskGetTaskName == 1 ) + + signed char * ICACHE_FLASH_ATTR + pcTaskGetTaskName( xTaskHandle xTaskToQuery ) + { + tskTCB *pxTCB; + + /* If null is passed in here then the name of the calling task is being queried. */ + pxTCB = prvGetTCBFromHandle( xTaskToQuery ); + configASSERT( pxTCB ); + return &( pxTCB->pcTaskName[ 0 ] ); + } + +#endif /* INCLUDE_pcTaskGetTaskName */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_TRACE_FACILITY == 1 ) + + unsigned portBASE_TYPE ICACHE_FLASH_ATTR + uxTaskGetSystemState( xTaskStatusType *pxTaskStatusArray, unsigned portBASE_TYPE uxArraySize, unsigned long *pulTotalRunTime ) + { + unsigned portBASE_TYPE uxTask = 0, uxQueue = configMAX_PRIORITIES; + + vTaskSuspendAll(); + { + /* Is there a space in the array for each task in the system? */ + if( uxArraySize >= uxCurrentNumberOfTasks ) + { + /* Fill in an xTaskStatusType structure with information on each + task in the Ready state. */ + do + { + uxQueue--; + uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &( pxReadyTasksLists[ uxQueue ] ), eReady ); + + } while( uxQueue > ( unsigned portBASE_TYPE ) tskIDLE_PRIORITY ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + + /* Fill in an xTaskStatusType structure with information on each + task in the Blocked state. */ + uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( xList * ) pxDelayedTaskList, eBlocked ); + uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( xList * ) pxOverflowDelayedTaskList, eBlocked ); + + #if( INCLUDE_vTaskDelete == 1 ) + { + /* Fill in an xTaskStatusType structure with information on + each task that has been deleted but not yet cleaned up. */ + uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xTasksWaitingTermination, eDeleted ); + } + #endif + + #if ( INCLUDE_vTaskSuspend == 1 ) + { + /* Fill in an xTaskStatusType structure with information on + each task in the Suspended state. */ + uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xSuspendedTaskList, eSuspended ); + } + #endif + + #if ( configGENERATE_RUN_TIME_STATS == 1) + { + if( pulTotalRunTime != NULL ) + { + *pulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE(); + } + } + #else + { + if( pulTotalRunTime != NULL ) + { + *pulTotalRunTime = 0; + } + } + #endif + } + } + ( void ) xTaskResumeAll(); + + return uxTask; + } + +#endif /* configUSE_TRACE_FACILITY */ +/*----------------------------------------------------------*/ + +#if ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) + + xTaskHandle ICACHE_FLASH_ATTR + xTaskGetIdleTaskHandle( void ) + { + /* If xTaskGetIdleTaskHandle() is called before the scheduler has been + started, then xIdleTaskHandle will be NULL. */ + configASSERT( ( xIdleTaskHandle != NULL ) ); + return xIdleTaskHandle; + } + +#endif /* INCLUDE_xTaskGetIdleTaskHandle */ +/*----------------------------------------------------------*/ + +/* This conditional compilation should use inequality to 0, not equality to 1. +This is to ensure vTaskStepTick() is available when user defined low power mode +implementations require configUSE_TICKLESS_IDLE to be set to a value other than +1. */ +#if ( configUSE_TICKLESS_IDLE != 0 ) + + void ICACHE_FLASH_ATTR + vTaskStepTick( portTickType xTicksToJump ) + { + /* Correct the tick count value after a period during which the tick + was suppressed. Note this does *not* call the tick hook function for + each stepped tick. */ + configASSERT( ( xTickCount + xTicksToJump ) <= xNextTaskUnblockTime ); + xTickCount += xTicksToJump; + traceINCREASE_TICK_COUNT( xTicksToJump ); + } + +#endif /* configUSE_TICKLESS_IDLE */ +/*----------------------------------------------------------*/ + +portBASE_TYPE +xTaskIncrementTick( void ) +{ +tskTCB * pxTCB; +portTickType xItemValue; +portBASE_TYPE xSwitchRequired = pdFALSE; + + /* Called by the portable layer each time a tick interrupt occurs. + Increments the tick then checks to see if the new tick value will cause any + tasks to be unblocked. */ + traceTASK_INCREMENT_TICK( xTickCount ); + if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE ) + { + /* Increment the RTOS tick, switching the delayed and overflowed + delayed lists if it wraps to 0. */ + ++xTickCount; + + { + /* Minor optimisation. The tick count cannot change in this + block. */ + const portTickType xConstTickCount = xTickCount; + + if( xConstTickCount == ( portTickType ) 0U ) + { + taskSWITCH_DELAYED_LISTS(); + } + + /* See if this tick has made a timeout expire. Tasks are stored in the + queue in the order of their wake time - meaning once one tasks has been + found whose block time has not expired there is no need not look any + further down the list. */ + if( xConstTickCount >= xNextTaskUnblockTime ) + { + for( ;; ) + { + if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) + { + /* The delayed list is empty. Set xNextTaskUnblockTime to + the maximum possible value so it is extremely unlikely that + the if( xTickCount >= xNextTaskUnblockTime ) test will pass + next time through. */ + xNextTaskUnblockTime = portMAX_DELAY; + break; + } + else + { + /* The delayed list is not empty, get the value of the item + at the head of the delayed list. This is the time at which + the task at the head of the delayed list must be removed + from the Blocked state. */ + pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); + xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ); + + if( xConstTickCount < xItemValue ) + { + /* It is not time to unblock this item yet, but the item + value is the time at which the task at the head of the + blocked list must be removed from the Blocked state - + so record the item value in xNextTaskUnblockTime. */ + xNextTaskUnblockTime = xItemValue; + break; + } + + /* It is time to remove the item from the Blocked state. */ + ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); + + /* Is the task waiting on an event also? If so remove it + from the event list. */ + if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) + { + ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); + } + + /* Place the unblocked task into the appropriate ready + list. */ + prvAddTaskToReadyList( pxTCB ); + + /* A task being unblocked cannot cause an immediate context + switch if preemption is turned off. */ + #if ( configUSE_PREEMPTION == 1 ) + { + /* Preemption is on, but a context switch should only + be performed if the unblocked task has a priority that + is equal to or higher than the currently executing + task. */ + if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) + { + xSwitchRequired = pdTRUE; + } + } + #endif /* configUSE_PREEMPTION */ + } + } + } + } + + /* Tasks of equal priority to the currently running task will share + processing time (time slice) if preemption is on, and the application + writer has not explicitly turned time slicing off. */ + #if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) + { + if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > ( unsigned portBASE_TYPE ) 1 ) + { + xSwitchRequired = pdTRUE; + } + } + #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */ + } + else + { + ++uxPendedTicks; + + /* The tick hook gets called at regular intervals, even if the + scheduler is locked. */ + #if ( configUSE_TICK_HOOK == 1 ) + { + vApplicationTickHook(); + } + #endif + } + + #if ( configUSE_TICK_HOOK == 1 ) + { + /* Guard against the tick hook being called when the missed tick + count is being unwound (when the scheduler is being unlocked). */ + if( uxPendedTicks == ( unsigned portBASE_TYPE ) 0U ) + { + vApplicationTickHook(); + } + } + #endif /* configUSE_TICK_HOOK */ + + return xSwitchRequired; +} +/*-----------------------------------------------------------*/ + +#if ( configUSE_APPLICATION_TASK_TAG == 1 ) + + void ICACHE_FLASH_ATTR + vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxHookFunction ) + { + tskTCB *xTCB; + + /* If xTask is NULL then we are setting our own task hook. */ + if( xTask == NULL ) + { + xTCB = ( tskTCB * ) pxCurrentTCB; + } + else + { + xTCB = ( tskTCB * ) xTask; + } + + /* Save the hook function in the TCB. A critical section is required as + the value can be accessed from an interrupt. */ + taskENTER_CRITICAL(); + xTCB->pxTaskTag = pxHookFunction; + taskEXIT_CRITICAL(); + } + +#endif /* configUSE_APPLICATION_TASK_TAG */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_APPLICATION_TASK_TAG == 1 ) + + pdTASK_HOOK_CODE ICACHE_FLASH_ATTR + xTaskGetApplicationTaskTag( xTaskHandle xTask ) + { + tskTCB *xTCB; + pdTASK_HOOK_CODE xReturn; + + /* If xTask is NULL then we are setting our own task hook. */ + if( xTask == NULL ) + { + xTCB = ( tskTCB * ) pxCurrentTCB; + } + else + { + xTCB = ( tskTCB * ) xTask; + } + + /* Save the hook function in the TCB. A critical section is required as + the value can be accessed from an interrupt. */ + taskENTER_CRITICAL(); + xReturn = xTCB->pxTaskTag; + taskEXIT_CRITICAL(); + + return xReturn; + } + +#endif /* configUSE_APPLICATION_TASK_TAG */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_APPLICATION_TASK_TAG == 1 ) + + portBASE_TYPE ICACHE_FLASH_ATTR + xTaskCallApplicationTaskHook( xTaskHandle xTask, void *pvParameter ) + { + tskTCB *xTCB; + portBASE_TYPE xReturn; + + /* If xTask is NULL then we are calling our own task hook. */ + if( xTask == NULL ) + { + xTCB = ( tskTCB * ) pxCurrentTCB; + } + else + { + xTCB = ( tskTCB * ) xTask; + } + + if( xTCB->pxTaskTag != NULL ) + { + xReturn = xTCB->pxTaskTag( pvParameter ); + } + else + { + xReturn = pdFAIL; + } + + return xReturn; + } + +#endif /* configUSE_APPLICATION_TASK_TAG */ +/*-----------------------------------------------------------*/ + +void +vTaskSwitchContext( void ) +{ + if( uxSchedulerSuspended != ( unsigned portBASE_TYPE ) pdFALSE ) + { + /* The scheduler is currently suspended - do not allow a context + switch. */ + xYieldPending = pdTRUE; + } + else + { + traceTASK_SWITCHED_OUT(); + + #if ( configGENERATE_RUN_TIME_STATS == 1 ) + { + #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE + portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime ); + #else + ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE(); + #endif + + /* Add the amount of time the task has been running to the + accumulated time so far. The time the task started running was + stored in ulTaskSwitchedInTime. Note that there is no overflow + protection here so count values are only valid until the timer + overflows. The guard against negative values is to protect + against suspect run time stat counter implementations - which + are provided by the application, not the kernel. */ + if( ulTotalRunTime > ulTaskSwitchedInTime ) + { + pxCurrentTCB->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime ); + } + ulTaskSwitchedInTime = ulTotalRunTime; + } + #endif /* configGENERATE_RUN_TIME_STATS */ + + taskFIRST_CHECK_FOR_STACK_OVERFLOW(); + taskSECOND_CHECK_FOR_STACK_OVERFLOW(); + + taskSELECT_HIGHEST_PRIORITY_TASK(); + + traceTASK_SWITCHED_IN(); + + #if ( configUSE_NEWLIB_REENTRANT == 1 ) + { + /* Switch Newlib's _impure_ptr variable to point to the _reent + structure specific to this task. */ + _impure_ptr = &( pxCurrentTCB->xNewLib_reent ); + } + #endif /* configUSE_NEWLIB_REENTRANT */ + } +} +/*-----------------------------------------------------------*/ + +void ICACHE_FLASH_ATTR +vTaskPlaceOnEventList( xList * const pxEventList, portTickType xTicksToWait ) +{ +portTickType xTimeToWake; + + configASSERT( pxEventList ); + + /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE + SCHEDULER SUSPENDED. */ + + /* Place the event list item of the TCB in the appropriate event list. + This is placed in the list in priority order so the highest priority task + is the first to be woken by the event. */ + vListInsert( pxEventList, &( pxCurrentTCB->xEventListItem ) ); + + /* We must remove ourselves from the ready list before adding ourselves + to the blocked list as the same list item is used for both lists. We have + exclusive access to the ready lists as the scheduler is locked. */ + if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( unsigned portBASE_TYPE ) 0 ) + { + /* The current task must be in a ready list, so there is no need to + check, and the port reset macro can be called directly. */ + portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); + } + + #if ( INCLUDE_vTaskSuspend == 1 ) + { + if( xTicksToWait == portMAX_DELAY ) + { + /* Add ourselves to the suspended task list instead of a delayed task + list to ensure we are not woken by a timing event. We will block + indefinitely. */ + vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xGenericListItem ) ); + } + else + { + /* Calculate the time at which the task should be woken if the event does + not occur. This may overflow but this doesn't matter. */ + xTimeToWake = xTickCount + xTicksToWait; + prvAddCurrentTaskToDelayedList( xTimeToWake ); + } + } + #else /* INCLUDE_vTaskSuspend */ + { + /* Calculate the time at which the task should be woken if the event does + not occur. This may overflow but this doesn't matter. */ + xTimeToWake = xTickCount + xTicksToWait; + prvAddCurrentTaskToDelayedList( xTimeToWake ); + } + #endif /* INCLUDE_vTaskSuspend */ +} +/*-----------------------------------------------------------*/ + +#if configUSE_TIMERS == 1 + + void ICACHE_FLASH_ATTR + vTaskPlaceOnEventListRestricted( xList * const pxEventList, portTickType xTicksToWait ) + { + portTickType xTimeToWake; + + configASSERT( pxEventList ); + + /* This function should not be called by application code hence the + 'Restricted' in its name. It is not part of the public API. It is + designed for use by kernel code, and has special calling requirements - + it should be called from a critical section. */ + + + /* Place the event list item of the TCB in the appropriate event list. + In this case it is assume that this is the only task that is going to + be waiting on this event list, so the faster vListInsertEnd() function + can be used in place of vListInsert. */ + vListInsertEnd( pxEventList, &( pxCurrentTCB->xEventListItem ) ); + + /* We must remove this task from the ready list before adding it to the + blocked list as the same list item is used for both lists. This + function is called form a critical section. */ + if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( unsigned portBASE_TYPE ) 0 ) + { + /* The current task must be in a ready list, so there is no need to + check, and the port reset macro can be called directly. */ + portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); + } + + /* Calculate the time at which the task should be woken if the event does + not occur. This may overflow but this doesn't matter. */ + xTimeToWake = xTickCount + xTicksToWait; + + traceTASK_DELAY_UNTIL(); + prvAddCurrentTaskToDelayedList( xTimeToWake ); + } + +#endif /* configUSE_TIMERS */ +/*-----------------------------------------------------------*/ + +signed portBASE_TYPE ICACHE_FLASH_ATTR +xTaskRemoveFromEventList( const xList * const pxEventList ) +{ +tskTCB *pxUnblockedTCB; +portBASE_TYPE xReturn; + + /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE + SCHEDULER SUSPENDED. It can also be called from within an ISR. */ + + /* The event list is sorted in priority order, so we can remove the + first in the list, remove the TCB from the delayed list, and add + it to the ready list. + + If an event is for a queue that is locked then this function will never + get called - the lock count on the queue will get modified instead. This + means we can always expect exclusive access to the event list here. + + This function assumes that a check has already been made to ensure that + pxEventList is not empty. */ + pxUnblockedTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList ); + configASSERT( pxUnblockedTCB ); + ( void ) uxListRemove( &( pxUnblockedTCB->xEventListItem ) ); + + if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE ) + { + ( void ) uxListRemove( &( pxUnblockedTCB->xGenericListItem ) ); + prvAddTaskToReadyList( pxUnblockedTCB ); + } + else + { + /* We cannot access the delayed or ready lists, so will hold this + task pending until the scheduler is resumed. */ + vListInsertEnd( &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) ); + } + + if( pxUnblockedTCB->uxPriority >= pxCurrentTCB->uxPriority ) + { + /* Return true if the task removed from the event list has + a higher priority than the calling task. This allows + the calling task to know if it should force a context + switch now. */ + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +void ICACHE_FLASH_ATTR +vTaskSetTimeOutState( xTimeOutType * const pxTimeOut ) +{ + configASSERT( pxTimeOut ); + pxTimeOut->xOverflowCount = xNumOfOverflows; + pxTimeOut->xTimeOnEntering = xTickCount; +} +/*-----------------------------------------------------------*/ + +portBASE_TYPE ICACHE_FLASH_ATTR +xTaskCheckForTimeOut( xTimeOutType * const pxTimeOut, portTickType * const pxTicksToWait ) +{ +portBASE_TYPE xReturn; + + configASSERT( pxTimeOut ); + configASSERT( pxTicksToWait ); + + taskENTER_CRITICAL(); + { + /* Minor optimisation. The tick count cannot change in this block. */ + const portTickType xConstTickCount = xTickCount; + + #if ( INCLUDE_vTaskSuspend == 1 ) + /* If INCLUDE_vTaskSuspend is set to 1 and the block time specified is + the maximum block time then the task should block indefinitely, and + therefore never time out. */ + if( *pxTicksToWait == portMAX_DELAY ) + { + xReturn = pdFALSE; + } + else /* We are not blocking indefinitely, perform the checks below. */ + #endif + + if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( xConstTickCount >= pxTimeOut->xTimeOnEntering ) ) /*lint !e525 Indentation preferred as is to make code within pre-processor directives clearer. */ + { + /* The tick count is greater than the time at which vTaskSetTimeout() + was called, but has also overflowed since vTaskSetTimeOut() was called. + It must have wrapped all the way around and gone past us again. This + passed since vTaskSetTimeout() was called. */ + xReturn = pdTRUE; + } + else if( ( xConstTickCount - pxTimeOut->xTimeOnEntering ) < *pxTicksToWait ) + { + /* Not a genuine timeout. Adjust parameters for time remaining. */ + *pxTicksToWait -= ( xConstTickCount - pxTimeOut->xTimeOnEntering ); + vTaskSetTimeOutState( pxTimeOut ); + xReturn = pdFALSE; + } + else + { + xReturn = pdTRUE; + } + } + taskEXIT_CRITICAL(); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +void ICACHE_FLASH_ATTR +vTaskMissedYield( void ) +{ + xYieldPending = pdTRUE; +} +/*-----------------------------------------------------------*/ + +#if ( configUSE_TRACE_FACILITY == 1 ) + + unsigned portBASE_TYPE ICACHE_FLASH_ATTR + uxTaskGetTaskNumber( xTaskHandle xTask ) + { + unsigned portBASE_TYPE uxReturn; + tskTCB *pxTCB; + + if( xTask != NULL ) + { + pxTCB = ( tskTCB * ) xTask; + uxReturn = pxTCB->uxTaskNumber; + } + else + { + uxReturn = 0U; + } + + return uxReturn; + } + +#endif /* configUSE_TRACE_FACILITY */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_TRACE_FACILITY == 1 ) + + void ICACHE_FLASH_ATTR + vTaskSetTaskNumber( xTaskHandle xTask, unsigned portBASE_TYPE uxHandle ) + { + tskTCB *pxTCB; + + if( xTask != NULL ) + { + pxTCB = ( tskTCB * ) xTask; + pxTCB->uxTaskNumber = uxHandle; + } + } + +#endif /* configUSE_TRACE_FACILITY */ + +/* + * ----------------------------------------------------------- + * The Idle task. + * ---------------------------------------------------------- + * + * The portTASK_FUNCTION() macro is used to allow port/compiler specific + * language extensions. The equivalent prototype for this function is: + * + * void prvIdleTask( void *pvParameters ); + * + */ +static ICACHE_FLASH_ATTR +portTASK_FUNCTION( prvIdleTask, pvParameters ) +{ + /* Stop warnings. */ + ( void ) pvParameters; + + for( ;; ) + { + /* See if any tasks have been deleted. */ + prvCheckTasksWaitingTermination(); + + #if ( configUSE_PREEMPTION == 0 ) + { + /* If we are not using preemption we keep forcing a task switch to + see if any other task has become available. If we are using + preemption we don't need to do this as any task becoming available + will automatically get the processor anyway. */ + taskYIELD(); + } + #endif /* configUSE_PREEMPTION */ + + #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) + { + /* When using preemption tasks of equal priority will be + timesliced. If a task that is sharing the idle priority is ready + to run then the idle task should yield before the end of the + timeslice. + + A critical region is not required here as we are just reading from + the list, and an occasional incorrect value will not matter. If + the ready list at the idle priority contains more than one task + then a task other than the idle task is ready to execute. */ + if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( unsigned portBASE_TYPE ) 1 ) + { + taskYIELD(); + } + } + #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) */ + + #if ( configUSE_IDLE_HOOK == 1 ) + { + extern void vApplicationIdleHook( void ); + + /* Call the user defined function from within the idle task. This + allows the application designer to add background functionality + without the overhead of a separate task. + NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES, + CALL A FUNCTION THAT MIGHT BLOCK. */ + vApplicationIdleHook(); + } + #endif /* configUSE_IDLE_HOOK */ + + /* This conditional compilation should use inequality to 0, not equality + to 1. This is to ensure portSUPPRESS_TICKS_AND_SLEEP() is called when + user defined low power mode implementations require + configUSE_TICKLESS_IDLE to be set to a value other than 1. */ + + //#if ( configUSE_TICKLESS_IDLE != 0 ) + #if 0 + { + portTickType xExpectedIdleTime; + + /* It is not desirable to suspend then resume the scheduler on + each iteration of the idle task. Therefore, a preliminary + test of the expected idle time is performed without the + scheduler suspended. The result here is not necessarily + valid. */ + xExpectedIdleTime = prvGetExpectedIdleTime(); + + if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP ) + { + vTaskSuspendAll(); + { + /* Now the scheduler is suspended, the expected idle + time can be sampled again, and this time its value can + be used. */ + configASSERT( xNextTaskUnblockTime >= xTickCount ); + xExpectedIdleTime = prvGetExpectedIdleTime(); + + if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP ) + { + traceLOW_POWER_IDLE_BEGIN(); + portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ); + traceLOW_POWER_IDLE_END(); + } + } + ( void ) xTaskResumeAll(); + } + } + #endif /* configUSE_TICKLESS_IDLE */ + } +} +/*-----------------------------------------------------------*/ + +#if configUSE_TICKLESS_IDLE != 0 + + eSleepModeStatus ICACHE_FLASH_ATTR + eTaskConfirmSleepModeStatus( void ) + { + eSleepModeStatus eReturn = eStandardSleep; + + if( listCURRENT_LIST_LENGTH( &xPendingReadyList ) != 0 ) + { + /* A task was made ready while the scheduler was suspended. */ + eReturn = eAbortSleep; + } + else if( xYieldPending != pdFALSE ) + { + /* A yield was pended while the scheduler was suspended. */ + eReturn = eAbortSleep; + } + else + { + #if configUSE_TIMERS == 0 + { + /* The idle task exists in addition to the application tasks. */ + const unsigned portBASE_TYPE uxNonApplicationTasks = 1; + + /* If timers are not being used and all the tasks are in the + suspended list (which might mean they have an infinite block + time rather than actually being suspended) then it is safe to + turn all clocks off and just wait for external interrupts. */ + if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == ( uxCurrentNumberOfTasks - uxNonApplicationTasks ) ) + { + eReturn = eNoTasksWaitingTimeout; + } + } + #endif /* configUSE_TIMERS */ + } + + return eReturn; + } +#endif /* configUSE_TICKLESS_IDLE */ +/*-----------------------------------------------------------*/ + +static void ICACHE_FLASH_ATTR +prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth ) +{ +unsigned portBASE_TYPE x; + + /* Store the task name in the TCB. */ + for( x = ( unsigned portBASE_TYPE ) 0; x < ( unsigned portBASE_TYPE ) configMAX_TASK_NAME_LEN; x++ ) + { + pxTCB->pcTaskName[ x ] = pcName[ x ]; + + /* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than + configMAX_TASK_NAME_LEN characters just in case the memory after the + string is not accessible (extremely unlikely). */ + if( pcName[ x ] == 0x00 ) + { + break; + } + } + + /* Ensure the name string is terminated in the case that the string length + was greater or equal to configMAX_TASK_NAME_LEN. */ + pxTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = ( signed char ) '\0'; + + /* This is used as an array index so must ensure it's not too large. First + remove the privilege bit if one is present. */ + if( uxPriority >= ( unsigned portBASE_TYPE ) configMAX_PRIORITIES ) + { + uxPriority = ( unsigned portBASE_TYPE ) configMAX_PRIORITIES - ( unsigned portBASE_TYPE ) 1U; + } + + pxTCB->uxPriority = uxPriority; + #if ( configUSE_MUTEXES == 1 ) + { + pxTCB->uxBasePriority = uxPriority; + } + #endif /* configUSE_MUTEXES */ + + vListInitialiseItem( &( pxTCB->xGenericListItem ) ); + vListInitialiseItem( &( pxTCB->xEventListItem ) ); + + /* Set the pxTCB as a link back from the xListItem. This is so we can get + back to the containing TCB from a generic item in a list. */ + listSET_LIST_ITEM_OWNER( &( pxTCB->xGenericListItem ), pxTCB ); + + /* Event lists are always in priority order. */ + listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( portTickType ) configMAX_PRIORITIES - ( portTickType ) uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + listSET_LIST_ITEM_OWNER( &( pxTCB->xEventListItem ), pxTCB ); + + #if ( portCRITICAL_NESTING_IN_TCB == 1 ) + { + pxTCB->uxCriticalNesting = ( unsigned portBASE_TYPE ) 0U; + } + #endif /* portCRITICAL_NESTING_IN_TCB */ + + #if ( configUSE_APPLICATION_TASK_TAG == 1 ) + { + pxTCB->pxTaskTag = NULL; + } + #endif /* configUSE_APPLICATION_TASK_TAG */ + + #if ( configGENERATE_RUN_TIME_STATS == 1 ) + { + pxTCB->ulRunTimeCounter = 0UL; + } + #endif /* configGENERATE_RUN_TIME_STATS */ + + #if ( portUSING_MPU_WRAPPERS == 1 ) + { + vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, pxTCB->pxStack, usStackDepth ); + } + #else /* portUSING_MPU_WRAPPERS */ + { + ( void ) xRegions; + ( void ) usStackDepth; + } + #endif /* portUSING_MPU_WRAPPERS */ + + #if ( configUSE_NEWLIB_REENTRANT == 1 ) + { + /* Initialise this task's Newlib reent structure. */ + _REENT_INIT_PTR( ( &( pxTCB->xNewLib_reent ) ) ); + } + #endif /* configUSE_NEWLIB_REENTRANT */ +} +/*-----------------------------------------------------------*/ + +#if ( portUSING_MPU_WRAPPERS == 1 ) + + void ICACHE_FLASH_ATTR + vTaskAllocateMPURegions( xTaskHandle xTaskToModify, const xMemoryRegion * const xRegions ) + { + tskTCB *pxTCB; + + /* If null is passed in here then we are deleting ourselves. */ + pxTCB = prvGetTCBFromHandle( xTaskToModify ); + + vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 ); + } + +#endif /* portUSING_MPU_WRAPPERS */ +/*-----------------------------------------------------------*/ + +static void ICACHE_FLASH_ATTR +prvInitialiseTaskLists( void ) +{ +unsigned portBASE_TYPE uxPriority; + + for( uxPriority = ( unsigned portBASE_TYPE ) 0U; uxPriority < ( unsigned portBASE_TYPE ) configMAX_PRIORITIES; uxPriority++ ) + { + vListInitialise( &( pxReadyTasksLists[ uxPriority ] ) ); + } + + vListInitialise( &xDelayedTaskList1 ); + vListInitialise( &xDelayedTaskList2 ); + vListInitialise( &xPendingReadyList ); + + #if ( INCLUDE_vTaskDelete == 1 ) + { + vListInitialise( &xTasksWaitingTermination ); + } + #endif /* INCLUDE_vTaskDelete */ + + #if ( INCLUDE_vTaskSuspend == 1 ) + { + vListInitialise( &xSuspendedTaskList ); + } + #endif /* INCLUDE_vTaskSuspend */ + + /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList + using list2. */ + pxDelayedTaskList = &xDelayedTaskList1; + pxOverflowDelayedTaskList = &xDelayedTaskList2; +} +/*-----------------------------------------------------------*/ + +static void ICACHE_FLASH_ATTR +prvCheckTasksWaitingTermination( void ) +{ + #if ( INCLUDE_vTaskDelete == 1 ) + { + portBASE_TYPE xListIsEmpty; + + /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called + too often in the idle task. */ + while( uxTasksDeleted > ( unsigned portBASE_TYPE ) 0U ) + { + vTaskSuspendAll(); + xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination ); + ( void ) xTaskResumeAll(); + + if( xListIsEmpty == pdFALSE ) + { + tskTCB *pxTCB; + + taskENTER_CRITICAL(); + { + pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) ); + ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); + --uxCurrentNumberOfTasks; + --uxTasksDeleted; + } + taskEXIT_CRITICAL(); + + prvDeleteTCB( pxTCB ); + } + } + } + #endif /* vTaskDelete */ +} +/*-----------------------------------------------------------*/ + +static void ICACHE_FLASH_ATTR +prvAddCurrentTaskToDelayedList( portTickType xTimeToWake ) +{ + /* The list item will be inserted in wake time order. */ + listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake ); + + if( xTimeToWake < xTickCount ) + { + /* Wake time has overflowed. Place this item in the overflow list. */ + vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xGenericListItem ) ); + } + else + { + /* The wake time has not overflowed, so we can use the current block list. */ + vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xGenericListItem ) ); + + /* If the task entering the blocked state was placed at the head of the + list of blocked tasks then xNextTaskUnblockTime needs to be updated + too. */ + if( xTimeToWake < xNextTaskUnblockTime ) + { + xNextTaskUnblockTime = xTimeToWake; + } + } +} +/*-----------------------------------------------------------*/ + +static tskTCB * ICACHE_FLASH_ATTR +prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer ) +{ +tskTCB *pxNewTCB; + + /* Allocate space for the TCB. Where the memory comes from depends on + the implementation of the port malloc function. */ + pxNewTCB = ( tskTCB * ) os_malloc( sizeof( tskTCB ) ); + + if( pxNewTCB != NULL ) + { + /* Allocate space for the stack used by the task being created. + The base of the stack memory stored in the TCB so the task can + be deleted later if required. */ + pxNewTCB->pxStack = ( portSTACK_TYPE * ) pvPortMallocAligned( ( ( ( size_t ) usStackDepth ) * sizeof( portSTACK_TYPE ) ), puxStackBuffer ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + if( pxNewTCB->pxStack == NULL ) + { + /* Could not allocate the stack. Delete the allocated TCB. */ + os_free( pxNewTCB ); + pxNewTCB = NULL; + } + else + { + /* Just to help debugging. */ + ( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) usStackDepth * sizeof( portSTACK_TYPE ) ); + } + } + + return pxNewTCB; +} +/*-----------------------------------------------------------*/ + +#if ( configUSE_TRACE_FACILITY == 1 ) + + static unsigned portBASE_TYPE ICACHE_FLASH_ATTR + prvListTaskWithinSingleList( xTaskStatusType *pxTaskStatusArray, xList *pxList, eTaskState eState ) + { + volatile tskTCB *pxNextTCB, *pxFirstTCB; + unsigned portBASE_TYPE uxTask = 0; + + if( listCURRENT_LIST_LENGTH( pxList ) > ( unsigned portBASE_TYPE ) 0 ) + { + listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList ); + + /* Populate an xTaskStatusType structure within the + pxTaskStatusArray array for each task that is referenced from + pxList. See the definition of xTaskStatusType in task.h for the + meaning of each xTaskStatusType structure member. */ + do + { + listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList ); + + pxTaskStatusArray[ uxTask ].xHandle = ( xTaskHandle ) pxNextTCB; + pxTaskStatusArray[ uxTask ].pcTaskName = ( const signed char * ) &( pxNextTCB->pcTaskName [ 0 ] ); + pxTaskStatusArray[ uxTask ].xTaskNumber = pxNextTCB->uxTCBNumber; + pxTaskStatusArray[ uxTask ].eCurrentState = eState; + pxTaskStatusArray[ uxTask ].uxCurrentPriority = pxNextTCB->uxPriority; + + #if ( configUSE_MUTEXES == 1 ) + { + pxTaskStatusArray[ uxTask ].uxBasePriority = pxNextTCB->uxBasePriority; + } + #else + { + pxTaskStatusArray[ uxTask ].uxBasePriority = 0; + } + #endif + + #if ( configGENERATE_RUN_TIME_STATS == 1 ) + { + pxTaskStatusArray[ uxTask ].ulRunTimeCounter = pxNextTCB->ulRunTimeCounter; + } + #else + { + pxTaskStatusArray[ uxTask ].ulRunTimeCounter = 0; + } + #endif + + #if ( portSTACK_GROWTH > 0 ) + { + ppxTaskStatusArray[ uxTask ].usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxEndOfStack ); + } + #else + { + pxTaskStatusArray[ uxTask ].usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxStack ); + } + #endif + + uxTask++; + + } while( pxNextTCB != pxFirstTCB ); + } + + return uxTask; + } + +#endif /* configUSE_TRACE_FACILITY */ +/*-----------------------------------------------------------*/ + +#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) + + static unsigned short ICACHE_FLASH_ATTR + prvTaskCheckFreeStackSpace( const unsigned char * pucStackByte ) + { + register unsigned short usCount = 0U; + + while( *pucStackByte == tskSTACK_FILL_BYTE ) + { + pucStackByte -= portSTACK_GROWTH; + usCount++; + } + + usCount /= sizeof( portSTACK_TYPE ); + + return usCount; + } + +#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) + + unsigned portBASE_TYPE ICACHE_FLASH_ATTR + uxTaskGetStackHighWaterMark( xTaskHandle xTask ) + { + tskTCB *pxTCB; + unsigned char *pcEndOfStack; + unsigned portBASE_TYPE uxReturn; + + pxTCB = prvGetTCBFromHandle( xTask ); + + #if portSTACK_GROWTH < 0 + { + pcEndOfStack = ( unsigned char * ) pxTCB->pxStack; + } + #else + { + pcEndOfStack = ( unsigned char * ) pxTCB->pxEndOfStack; + } + #endif + + uxReturn = ( unsigned portBASE_TYPE ) prvTaskCheckFreeStackSpace( pcEndOfStack ); + + return uxReturn; + } + +#endif /* INCLUDE_uxTaskGetStackHighWaterMark */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_vTaskDelete == 1 ) + + static void ICACHE_FLASH_ATTR + prvDeleteTCB( tskTCB *pxTCB ) + { + /* This call is required specifically for the TriCore port. It must be + above the vPortFree() calls. The call is also used by ports/demos that + want to allocate and clean RAM statically. */ + portCLEAN_UP_TCB( pxTCB ); + + /* Free up the memory allocated by the scheduler for the task. It is up to + the task to free any memory allocated at the application level. */ + vPortFreeAligned( pxTCB->pxStack ); + os_free( pxTCB ); + } + +#endif /* INCLUDE_vTaskDelete */ +/*-----------------------------------------------------------*/ + +#if ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) + + xTaskHandle ICACHE_FLASH_ATTR + xTaskGetCurrentTaskHandle( void ) + { + xTaskHandle xReturn; + + /* A critical section is not required as this is not called from + an interrupt and the current TCB will always be the same for any + individual execution thread. */ + xReturn = pxCurrentTCB; + + return xReturn; + } + +#endif /* ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) */ +/*-----------------------------------------------------------*/ + +#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) + + portBASE_TYPE ICACHE_FLASH_ATTR + xTaskGetSchedulerState( void ) + { + portBASE_TYPE xReturn; + + if( xSchedulerRunning == pdFALSE ) + { + xReturn = taskSCHEDULER_NOT_STARTED; + } + else + { + if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE ) + { + xReturn = taskSCHEDULER_RUNNING; + } + else + { + xReturn = taskSCHEDULER_SUSPENDED; + } + } + + return xReturn; + } + +#endif /* ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_MUTEXES == 1 ) + + void ICACHE_FLASH_ATTR + vTaskPriorityInherit( xTaskHandle const pxMutexHolder ) + { + tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder; + + /* If the mutex was given back by an interrupt while the queue was + locked then the mutex holder might now be NULL. */ + if( pxMutexHolder != NULL ) + { + if( pxTCB->uxPriority < pxCurrentTCB->uxPriority ) + { + /* Adjust the mutex holder state to account for its new priority. */ + listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( portTickType ) configMAX_PRIORITIES - ( portTickType ) pxCurrentTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + + /* If the task being modified is in the ready state it will need to + be moved into a new list. */ + if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ) != pdFALSE ) + { + if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( unsigned portBASE_TYPE ) 0 ) + { + taskRESET_READY_PRIORITY( pxTCB->uxPriority ); + } + + /* Inherit the priority before being moved into the new list. */ + pxTCB->uxPriority = pxCurrentTCB->uxPriority; + prvAddTaskToReadyList( pxTCB ); + } + else + { + /* Just inherit the priority. */ + pxTCB->uxPriority = pxCurrentTCB->uxPriority; + } + + traceTASK_PRIORITY_INHERIT( pxTCB, pxCurrentTCB->uxPriority ); + } + } + } + +#endif /* configUSE_MUTEXES */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_MUTEXES == 1 ) + + void + vTaskPriorityDisinherit( xTaskHandle const pxMutexHolder ) + { + tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder; + + if( pxMutexHolder != NULL ) + { + if( pxTCB->uxPriority != pxTCB->uxBasePriority ) + { + /* We must be the running task to be able to give the mutex back. + Remove ourselves from the ready list we currently appear in. */ + if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( unsigned portBASE_TYPE ) 0 ) + { + taskRESET_READY_PRIORITY( pxTCB->uxPriority ); + } + + /* Disinherit the priority before adding the task into the new + ready list. */ + traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority ); + pxTCB->uxPriority = pxTCB->uxBasePriority; + listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( portTickType ) configMAX_PRIORITIES - ( portTickType ) pxTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + prvAddTaskToReadyList( pxTCB ); + } + } + } + +#endif /* configUSE_MUTEXES */ +/*-----------------------------------------------------------*/ + +#if ( portCRITICAL_NESTING_IN_TCB == 1 ) + + void ICACHE_FLASH_ATTR + vTaskEnterCritical( void ) + { + //portDISABLE_INTERRUPTS(); +PortDisableInt_NoNest(); + if( xSchedulerRunning != pdFALSE ) + { + ( pxCurrentTCB->uxCriticalNesting )++; + } + } + +#endif /* portCRITICAL_NESTING_IN_TCB */ +/*-----------------------------------------------------------*/ + +#if ( portCRITICAL_NESTING_IN_TCB == 1 ) + + void ICACHE_FLASH_ATTR + vTaskExitCritical( void ) + { + if( xSchedulerRunning != pdFALSE ) + { + if( pxCurrentTCB->uxCriticalNesting > 0U ) + { + ( pxCurrentTCB->uxCriticalNesting )--; + + if( pxCurrentTCB->uxCriticalNesting == 0U ) + { + //portENABLE_INTERRUPTS(); + PortEnableInt_NoNest(); + } + } + } + } + +#endif /* portCRITICAL_NESTING_IN_TCB */ +/*-----------------------------------------------------------*/ + +#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) ) + + void ICACHE_FLASH_ATTR + vTaskList( signed char *pcWriteBuffer ) + { + xTaskStatusType *pxTaskStatusArray; + volatile unsigned portBASE_TYPE uxArraySize, x; + char cStatus; + + /* + * PLEASE NOTE: + * + * This function is provided for convenience only, and is used by many + * of the demo applications. Do not consider it to be part of the + * scheduler. + * + * vTaskList() calls uxTaskGetSystemState(), then formats part of the + * uxTaskGetSystemState() output into a human readable table that + * displays task names, states and stack usage. + * + * vTaskList() has a dependency on the sprintf() C library function that + * might bloat the code size, use a lot of stack, and provide different + * results on different platforms. An alternative, tiny, third party, + * and limited functionality implementation of sprintf() is provided in + * many of the FreeRTOS/Demo sub-directories in a file called + * printf-stdarg.c (note printf-stdarg.c does not provide a full + * snprintf() implementation!). + * + * It is recommended that production systems call uxTaskGetSystemState() + * directly to get access to raw stats data, rather than indirectly + * through a call to vTaskList(). + */ + + + /* Make sure the write buffer does not contain a string. */ + *pcWriteBuffer = 0x00; + + /* Take a snapshot of the number of tasks in case it changes while this + function is executing. */ + uxArraySize = uxCurrentNumberOfTasks; + + /* Allocate an array index for each task. */ + pxTaskStatusArray = os_malloc( uxCurrentNumberOfTasks * sizeof( xTaskStatusType ) ); + + if( pxTaskStatusArray != NULL ) + { + /* Generate the (binary) data. */ + uxArraySize = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, NULL ); + + /* Create a human readable table from the binary data. */ + for( x = 0; x < uxArraySize; x++ ) + { + switch( pxTaskStatusArray[ x ].eCurrentState ) + { + case eReady: cStatus = tskREADY_CHAR; + break; + + case eBlocked: cStatus = tskBLOCKED_CHAR; + break; + + case eSuspended: cStatus = tskSUSPENDED_CHAR; + break; + + case eDeleted: cStatus = tskDELETED_CHAR; + break; + + default: /* Should not get here, but it is included + to prevent static checking errors. */ + cStatus = 0x00; + break; + } + + sprintf( ( char * ) pcWriteBuffer, ( char * ) "%s\t\t%c\t%u\t%u\t%u\r\n", pxTaskStatusArray[ x ].pcTaskName, cStatus, ( unsigned int ) pxTaskStatusArray[ x ].uxCurrentPriority, ( unsigned int ) pxTaskStatusArray[ x ].usStackHighWaterMark, ( unsigned int ) pxTaskStatusArray[ x ].xTaskNumber ); + pcWriteBuffer += strlen( ( char * ) pcWriteBuffer ); + } + + /* Free the array again. */ + os_free( pxTaskStatusArray ); + } + } + +#endif /* configUSE_TRACE_FACILITY */ +/*----------------------------------------------------------*/ + +#if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) ) + + void ICACHE_FLASH_ATTR + vTaskGetRunTimeStats( signed char *pcWriteBuffer ) + { + xTaskStatusType *pxTaskStatusArray; + volatile unsigned portBASE_TYPE uxArraySize, x; + unsigned long ulTotalTime, ulStatsAsPercentage; + + /* + * PLEASE NOTE: + * + * This function is provided for convenience only, and is used by many + * of the demo applications. Do not consider it to be part of the + * scheduler. + * + * vTaskGetRunTimeStats() calls uxTaskGetSystemState(), then formats part + * of the uxTaskGetSystemState() output into a human readable table that + * displays the amount of time each task has spent in the Running state + * in both absolute and percentage terms. + * + * vTaskGetRunTimeStats() has a dependency on the sprintf() C library + * function that might bloat the code size, use a lot of stack, and + * provide different results on different platforms. An alternative, + * tiny, third party, and limited functionality implementation of + * sprintf() is provided in many of the FreeRTOS/Demo sub-directories in + * a file called printf-stdarg.c (note printf-stdarg.c does not provide + * a full snprintf() implementation!). + * + * It is recommended that production systems call uxTaskGetSystemState() + * directly to get access to raw stats data, rather than indirectly + * through a call to vTaskGetRunTimeStats(). + */ + + /* Make sure the write buffer does not contain a string. */ + *pcWriteBuffer = 0x00; + + /* Take a snapshot of the number of tasks in case it changes while this + function is executing. */ + uxArraySize = uxCurrentNumberOfTasks; + + /* Allocate an array index for each task. */ + pxTaskStatusArray = os_malloc( uxCurrentNumberOfTasks * sizeof( xTaskStatusType ) ); + + if( pxTaskStatusArray != NULL ) + { + /* Generate the (binary) data. */ + uxArraySize = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, &ulTotalTime ); + + /* For percentage calculations. */ + ulTotalTime /= 100UL; + + /* Avoid divide by zero errors. */ + if( ulTotalTime > 0 ) + { + /* Create a human readable table from the binary data. */ + for( x = 0; x < uxArraySize; x++ ) + { + /* What percentage of the total run time has the task used? + This will always be rounded down to the nearest integer. + ulTotalRunTimeDiv100 has already been divided by 100. */ + ulStatsAsPercentage = pxTaskStatusArray[ x ].ulRunTimeCounter / ulTotalTime; + + if( ulStatsAsPercentage > 0UL ) + { + #ifdef portLU_PRINTF_SPECIFIER_REQUIRED + { + sprintf( ( char * ) pcWriteBuffer, ( char * ) "%s\t\t%lu\t\t%lu%%\r\n", pxTaskStatusArray[ x ].pcTaskName, pxTaskStatusArray[ x ].ulRunTimeCounter, ulStatsAsPercentage ); + } + #else + { + /* sizeof( int ) == sizeof( long ) so a smaller + printf() library can be used. */ + sprintf( ( char * ) pcWriteBuffer, ( char * ) "%s\t\t%u\t\t%u%%\r\n", pxTaskStatusArray[ x ].pcTaskName, ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage ); + } + #endif + } + else + { + /* If the percentage is zero here then the task has + consumed less than 1% of the total run time. */ + #ifdef portLU_PRINTF_SPECIFIER_REQUIRED + { + sprintf( ( char * ) pcWriteBuffer, ( char * ) "%s\t\t%lu\t\t<1%%\r\n", pxTaskStatusArray[ x ].pcTaskName, pxTaskStatusArray[ x ].ulRunTimeCounter ); + } + #else + { + /* sizeof( int ) == sizeof( long ) so a smaller + printf() library can be used. */ + sprintf( ( char * ) pcWriteBuffer, ( char * ) "%s\t\t%u\t\t<1%%\r\n", pxTaskStatusArray[ x ].pcTaskName, ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter ); + } + #endif + } + + pcWriteBuffer += strlen( ( char * ) pcWriteBuffer ); + } + } + + /* Free the array again. */ + os_free( pxTaskStatusArray ); + } + } + +#endif /* configGENERATE_RUN_TIME_STATS */ + + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/freertos/timers.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/freertos/timers.c new file mode 100644 index 0000000..a4722be --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/freertos/timers.c @@ -0,0 +1,718 @@ +/* + FreeRTOS V7.5.2 - Copyright (C) 2013 Real Time Engineers Ltd. + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that has become a de facto standard. * + * * + * Help yourself get started quickly and support the FreeRTOS * + * project by purchasing a FreeRTOS tutorial book, reference * + * manual, or both from: http://www.FreeRTOS.org/Documentation * + * * + * Thank you! * + * * + *************************************************************************** + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + >>! NOTE: The modification to the GPL is included to allow you to distribute + >>! a combined work that includes FreeRTOS without being obliged to provide + >>! the source code for proprietary components outside of the FreeRTOS + >>! kernel. + + FreeRTOS 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. Full license text is available from the following + link: http://www.freertos.org/a00114.html + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* Standard includes. */ +#include + +/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining +all the API functions to use the MPU wrappers. That should only be done when +task.h is included from an application file. */ +#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/timers.h" + +/* Lint e961 and e750 are suppressed as a MISRA exception justified because the +MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the +header files above, but not in this file, in order to generate the correct +privileged Vs unprivileged linkage and placement. */ +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */ + + +/* This entire source file will be skipped if the application is not configured +to include software timer functionality. This #if is closed at the very bottom +of this file. If you want to include software timer functionality then ensure +configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */ +#if ( configUSE_TIMERS == 1 ) + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +/* Misc definitions. */ +#define tmrNO_DELAY ( portTickType ) 0U + +/* The definition of the timers themselves. */ +typedef struct tmrTimerControl +{ + const signed char *pcTimerName; /*<< Text name. This is not used by the kernel, it is included simply to make debugging easier. */ + xListItem xTimerListItem; /*<< Standard linked list item as used by all kernel features for event management. */ + portTickType xTimerPeriodInTicks;/*<< How quickly and often the timer expires. */ + unsigned portBASE_TYPE uxAutoReload; /*<< Set to pdTRUE if the timer should be automatically restarted once expired. Set to pdFALSE if the timer is, in effect, a one shot timer. */ + void *pvTimerID; /*<< An ID to identify the timer. This allows the timer to be identified when the same callback is used for multiple timers. */ + tmrTIMER_CALLBACK pxCallbackFunction; /*<< The function that will be called when the timer expires. */ +} xTIMER; + +/* The definition of messages that can be sent and received on the timer +queue. */ +typedef struct tmrTimerQueueMessage +{ + portBASE_TYPE xMessageID; /*<< The command being sent to the timer service task. */ + portTickType xMessageValue; /*<< An optional value used by a subset of commands, for example, when changing the period of a timer. */ + xTIMER * pxTimer; /*<< The timer to which the command will be applied. */ +} xTIMER_MESSAGE; + +/*lint -e956 A manual analysis and inspection has been used to determine which +static variables must be declared volatile. */ + +/* The list in which active timers are stored. Timers are referenced in expire +time order, with the nearest expiry time at the front of the list. Only the +timer service task is allowed to access xActiveTimerList. */ +PRIVILEGED_DATA static xList xActiveTimerList1; +PRIVILEGED_DATA static xList xActiveTimerList2; +PRIVILEGED_DATA static xList *pxCurrentTimerList; +PRIVILEGED_DATA static xList *pxOverflowTimerList; + +/* A queue that is used to send commands to the timer service task. */ +PRIVILEGED_DATA static xQueueHandle xTimerQueue = NULL; + +#if ( INCLUDE_xTimerGetTimerDaemonTaskHandle == 1 ) + + PRIVILEGED_DATA static xTaskHandle xTimerTaskHandle = NULL; + +#endif + +/*lint +e956 */ + +/*-----------------------------------------------------------*/ + +/* + * Initialise the infrastructure used by the timer service task if it has not + * been initialised already. + */ +static void prvCheckForValidListAndQueue( void ) PRIVILEGED_FUNCTION; + +/* + * The timer service task (daemon). Timer functionality is controlled by this + * task. Other tasks communicate with the timer service task using the + * xTimerQueue queue. + */ +static void prvTimerTask( void *pvParameters ) PRIVILEGED_FUNCTION; + +/* + * Called by the timer service task to interpret and process a command it + * received on the timer queue. + */ +static void prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION; + +/* + * Insert the timer into either xActiveTimerList1, or xActiveTimerList2, + * depending on if the expire time causes a timer counter overflow. + */ +static portBASE_TYPE prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpiryTime, portTickType xTimeNow, portTickType xCommandTime ) PRIVILEGED_FUNCTION; + +/* + * An active timer has reached its expire time. Reload the timer if it is an + * auto reload timer, then call its callback. + */ +static void prvProcessExpiredTimer( portTickType xNextExpireTime, portTickType xTimeNow ) PRIVILEGED_FUNCTION; + +/* + * The tick count has overflowed. Switch the timer lists after ensuring the + * current timer list does not still reference some timers. + */ +static void prvSwitchTimerLists( portTickType xLastTime ) PRIVILEGED_FUNCTION; + +/* + * Obtain the current tick count, setting *pxTimerListsWereSwitched to pdTRUE + * if a tick count overflow occurred since prvSampleTimeNow() was last called. + */ +static portTickType prvSampleTimeNow( portBASE_TYPE *pxTimerListsWereSwitched ) PRIVILEGED_FUNCTION; + +/* + * If the timer list contains any active timers then return the expire time of + * the timer that will expire first and set *pxListWasEmpty to false. If the + * timer list does not contain any timers then return 0 and set *pxListWasEmpty + * to pdTRUE. + */ +static portTickType prvGetNextExpireTime( portBASE_TYPE *pxListWasEmpty ) PRIVILEGED_FUNCTION; + +/* + * If a timer has expired, process it. Otherwise, block the timer service task + * until either a timer does expire or a command is received. + */ +static void prvProcessTimerOrBlockTask( portTickType xNextExpireTime, portBASE_TYPE xListWasEmpty ) PRIVILEGED_FUNCTION; + +/*-----------------------------------------------------------*/ + +portBASE_TYPE ICACHE_FLASH_ATTR +xTimerCreateTimerTask( void ) +{ +portBASE_TYPE xReturn = pdFAIL; + + /* This function is called when the scheduler is started if + configUSE_TIMERS is set to 1. Check that the infrastructure used by the + timer service task has been created/initialised. If timers have already + been created then the initialisation will already have been performed. */ + prvCheckForValidListAndQueue(); + + if( xTimerQueue != NULL ) + { + #if ( INCLUDE_xTimerGetTimerDaemonTaskHandle == 1 ) + { + /* Create the timer task, storing its handle in xTimerTaskHandle so + it can be returned by the xTimerGetTimerDaemonTaskHandle() function. */ + xReturn = xTaskCreate( prvTimerTask, ( const signed char * ) "Tmr Svc", ( unsigned short ) configTIMER_TASK_STACK_DEPTH, NULL, ( ( unsigned portBASE_TYPE ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, &xTimerTaskHandle ); + } + #else + { + /* Create the timer task without storing its handle. */ + xReturn = xTaskCreate( prvTimerTask, ( const signed char * ) "Tmr Svc", ( unsigned short ) configTIMER_TASK_STACK_DEPTH, NULL, ( ( unsigned portBASE_TYPE ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, NULL); + } + #endif + } + + configASSERT( xReturn ); + return xReturn; +} +/*-----------------------------------------------------------*/ + +xTimerHandle ICACHE_FLASH_ATTR +xTimerCreate( const signed char * const pcTimerName, portTickType xTimerPeriodInTicks, unsigned portBASE_TYPE uxAutoReload, void *pvTimerID, tmrTIMER_CALLBACK pxCallbackFunction ) +{ +xTIMER *pxNewTimer; + + /* Allocate the timer structure. */ + if( xTimerPeriodInTicks == ( portTickType ) 0U ) + { + pxNewTimer = NULL; + configASSERT( ( xTimerPeriodInTicks > 0 ) ); + } + else + { + pxNewTimer = ( xTIMER * ) os_malloc( sizeof( xTIMER ) ); + if( pxNewTimer != NULL ) + { + /* Ensure the infrastructure used by the timer service task has been + created/initialised. */ + prvCheckForValidListAndQueue(); + + /* Initialise the timer structure members using the function parameters. */ + pxNewTimer->pcTimerName = pcTimerName; + pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks; + pxNewTimer->uxAutoReload = uxAutoReload; + pxNewTimer->pvTimerID = pvTimerID; + pxNewTimer->pxCallbackFunction = pxCallbackFunction; + vListInitialiseItem( &( pxNewTimer->xTimerListItem ) ); + + traceTIMER_CREATE( pxNewTimer ); + } + else + { + traceTIMER_CREATE_FAILED(); + } + } + + return ( xTimerHandle ) pxNewTimer; +} +/*-----------------------------------------------------------*/ + +portBASE_TYPE ICACHE_FLASH_ATTR +xTimerGenericCommand( xTimerHandle xTimer, portBASE_TYPE xCommandID, portTickType xOptionalValue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portTickType xBlockTime ) +{ +portBASE_TYPE xReturn = pdFAIL; +xTIMER_MESSAGE xMessage; + + /* Send a message to the timer service task to perform a particular action + on a particular timer definition. */ + if( xTimerQueue != NULL ) + { + /* Send a command to the timer service task to start the xTimer timer. */ + xMessage.xMessageID = xCommandID; + xMessage.xMessageValue = xOptionalValue; + xMessage.pxTimer = ( xTIMER * ) xTimer; + + if( pxHigherPriorityTaskWoken == NULL ) + { + if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING ) + { + xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xBlockTime ); + } + else + { + xReturn = xQueueSendToBack( xTimerQueue, &xMessage, tmrNO_DELAY ); + } + } + else + { + xReturn = xQueueSendToBackFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken ); + } + + traceTIMER_COMMAND_SEND( xTimer, xCommandID, xOptionalValue, xReturn ); + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_xTimerGetTimerDaemonTaskHandle == 1 ) + + xTaskHandle ICACHE_FLASH_ATTR + xTimerGetTimerDaemonTaskHandle( void ) + { + /* If xTimerGetTimerDaemonTaskHandle() is called before the scheduler has been + started, then xTimerTaskHandle will be NULL. */ + configASSERT( ( xTimerTaskHandle != NULL ) ); + return xTimerTaskHandle; + } + +#endif +/*-----------------------------------------------------------*/ + +static void ICACHE_FLASH_ATTR +prvProcessExpiredTimer( portTickType xNextExpireTime, portTickType xTimeNow ) +{ +xTIMER *pxTimer; +portBASE_TYPE xResult; + + /* Remove the timer from the list of active timers. A check has already + been performed to ensure the list is not empty. */ + pxTimer = ( xTIMER * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList ); + ( void ) uxListRemove( &( pxTimer->xTimerListItem ) ); + traceTIMER_EXPIRED( pxTimer ); + + /* If the timer is an auto reload timer then calculate the next + expiry time and re-insert the timer in the list of active timers. */ + if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE ) + { + /* This is the only time a timer is inserted into a list using + a time relative to anything other than the current time. It + will therefore be inserted into the correct list relative to + the time this task thinks it is now, even if a command to + switch lists due to a tick count overflow is already waiting in + the timer queue. */ + if( prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xNextExpireTime ) == pdTRUE ) + { + /* The timer expired before it was added to the active timer + list. Reload it now. */ + xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xNextExpireTime, NULL, tmrNO_DELAY ); + configASSERT( xResult ); + ( void ) xResult; + } + } + + /* Call the timer callback. */ + pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer ); + //pxTimer->pxCallbackFunction( ( void * ) (pxTimer->pvTimerID) ); + +} +/*-----------------------------------------------------------*/ + +static void ICACHE_FLASH_ATTR +prvTimerTask( void *pvParameters ) +{ +portTickType xNextExpireTime; +portBASE_TYPE xListWasEmpty; + + /* Just to avoid compiler warnings. */ + ( void ) pvParameters; + + for( ;; ) + { + /* Query the timers list to see if it contains any timers, and if so, + obtain the time at which the next timer will expire. */ + xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty ); + + /* If a timer has expired, process it. Otherwise, block this task + until either a timer does expire, or a command is received. */ + prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty ); + + /* Empty the command queue. */ + prvProcessReceivedCommands(); + } +} +/*-----------------------------------------------------------*/ + +static void ICACHE_FLASH_ATTR +prvProcessTimerOrBlockTask( portTickType xNextExpireTime, portBASE_TYPE xListWasEmpty ) +{ +portTickType xTimeNow; +portBASE_TYPE xTimerListsWereSwitched; + + vTaskSuspendAll(); + { + /* Obtain the time now to make an assessment as to whether the timer + has expired or not. If obtaining the time causes the lists to switch + then don't process this timer as any timers that remained in the list + when the lists were switched will have been processed within the + prvSampelTimeNow() function. */ + xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched ); + if( xTimerListsWereSwitched == pdFALSE ) + { + /* The tick count has not overflowed, has the timer expired? */ + if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) ) + { + ( void ) xTaskResumeAll(); + prvProcessExpiredTimer( xNextExpireTime, xTimeNow ); + } + else + { + /* The tick count has not overflowed, and the next expire + time has not been reached yet. This task should therefore + block to wait for the next expire time or a command to be + received - whichever comes first. The following line cannot + be reached unless xNextExpireTime > xTimeNow, except in the + case when the current timer list is empty. */ + vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ) ); + + if( xTaskResumeAll() == pdFALSE ) + { + /* Yield to wait for either a command to arrive, or the block time + to expire. If a command arrived between the critical section being + exited and this yield then the yield will not cause the task + to block. */ + portYIELD_WITHIN_API(); + } + } + } + else + { + ( void ) xTaskResumeAll(); + } + } +} +/*-----------------------------------------------------------*/ + +static portTickType ICACHE_FLASH_ATTR +prvGetNextExpireTime( portBASE_TYPE *pxListWasEmpty ) +{ +portTickType xNextExpireTime; + + /* Timers are listed in expiry time order, with the head of the list + referencing the task that will expire first. Obtain the time at which + the timer with the nearest expiry time will expire. If there are no + active timers then just set the next expire time to 0. That will cause + this task to unblock when the tick count overflows, at which point the + timer lists will be switched and the next expiry time can be + re-assessed. */ + *pxListWasEmpty = listLIST_IS_EMPTY( pxCurrentTimerList ); + if( *pxListWasEmpty == pdFALSE ) + { + xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList ); + } + else + { + /* Ensure the task unblocks when the tick count rolls over. */ + xNextExpireTime = ( portTickType ) 0U; + } + + return xNextExpireTime; +} +/*-----------------------------------------------------------*/ + +static portTickType ICACHE_FLASH_ATTR +prvSampleTimeNow( portBASE_TYPE *pxTimerListsWereSwitched ) +{ +portTickType xTimeNow; +PRIVILEGED_DATA static portTickType xLastTime = ( portTickType ) 0U; /*lint !e956 Variable is only accessible to one task. */ + + xTimeNow = xTaskGetTickCount(); + + if( xTimeNow < xLastTime ) + { + prvSwitchTimerLists( xLastTime ); + *pxTimerListsWereSwitched = pdTRUE; + } + else + { + *pxTimerListsWereSwitched = pdFALSE; + } + + xLastTime = xTimeNow; + + return xTimeNow; +} +/*-----------------------------------------------------------*/ + +static portBASE_TYPE ICACHE_FLASH_ATTR +prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpiryTime, portTickType xTimeNow, portTickType xCommandTime ) +{ +portBASE_TYPE xProcessTimerNow = pdFALSE; + + listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xNextExpiryTime ); + listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer ); + + if( xNextExpiryTime <= xTimeNow ) + { + /* Has the expiry time elapsed between the command to start/reset a + timer was issued, and the time the command was processed? */ + if( ( xTimeNow - xCommandTime ) >= pxTimer->xTimerPeriodInTicks ) + { + /* The time between a command being issued and the command being + processed actually exceeds the timers period. */ + xProcessTimerNow = pdTRUE; + } + else + { + vListInsert( pxOverflowTimerList, &( pxTimer->xTimerListItem ) ); + } + } + else + { + if( ( xTimeNow < xCommandTime ) && ( xNextExpiryTime >= xCommandTime ) ) + { + /* If, since the command was issued, the tick count has overflowed + but the expiry time has not, then the timer must have already passed + its expiry time and should be processed immediately. */ + xProcessTimerNow = pdTRUE; + } + else + { + vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) ); + } + } + + return xProcessTimerNow; +} +/*-----------------------------------------------------------*/ + +static void ICACHE_FLASH_ATTR +prvProcessReceivedCommands( void ) +{ +xTIMER_MESSAGE xMessage; +xTIMER *pxTimer; +portBASE_TYPE xTimerListsWereSwitched, xResult; +portTickType xTimeNow; + + while( xQueueReceive( xTimerQueue, &xMessage, tmrNO_DELAY ) != pdFAIL ) /*lint !e603 xMessage does not have to be initialised as it is passed out, not in, and it is not used unless xQueueReceive() returns pdTRUE. */ + { + pxTimer = xMessage.pxTimer; + + if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE ) + { + /* The timer is in a list, remove it. */ + ( void ) uxListRemove( &( pxTimer->xTimerListItem ) ); + } + + traceTIMER_COMMAND_RECEIVED( pxTimer, xMessage.xMessageID, xMessage.xMessageValue ); + + /* In this case the xTimerListsWereSwitched parameter is not used, but + it must be present in the function call. prvSampleTimeNow() must be + called after the message is received from xTimerQueue so there is no + possibility of a higher priority task adding a message to the message + queue with a time that is ahead of the timer daemon task (because it + pre-empted the timer daemon task after the xTimeNow value was set). */ + xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched ); + + switch( xMessage.xMessageID ) + { + case tmrCOMMAND_START : + /* Start or restart a timer. */ + if( prvInsertTimerInActiveList( pxTimer, xMessage.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.xMessageValue ) == pdTRUE ) + { + /* The timer expired before it was added to the active timer + list. Process it now. */ + pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer ); + //pxTimer->pxCallbackFunction( ( void * ) (pxTimer->pvTimerID) ); + + if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE ) + { + xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xMessage.xMessageValue + pxTimer->xTimerPeriodInTicks, NULL, tmrNO_DELAY ); + configASSERT( xResult ); + ( void ) xResult; + } + } + break; + + case tmrCOMMAND_STOP : + /* The timer has already been removed from the active list. + There is nothing to do here. */ + break; + + case tmrCOMMAND_CHANGE_PERIOD : + pxTimer->xTimerPeriodInTicks = xMessage.xMessageValue; + configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) ); + ( void ) prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow, xTimeNow ); + break; + + case tmrCOMMAND_DELETE : + /* The timer has already been removed from the active list, + just free up the memory. */ + os_free( pxTimer ); + break; + + default : + /* Don't expect to get here. */ + break; + } + } +} +/*-----------------------------------------------------------*/ + +static void ICACHE_FLASH_ATTR +prvSwitchTimerLists( portTickType xLastTime ) +{ +portTickType xNextExpireTime, xReloadTime; +xList *pxTemp; +xTIMER *pxTimer; +portBASE_TYPE xResult; + + /* Remove compiler warnings if configASSERT() is not defined. */ + ( void ) xLastTime; + + /* The tick count has overflowed. The timer lists must be switched. + If there are any timers still referenced from the current timer list + then they must have expired and should be processed before the lists + are switched. */ + while( listLIST_IS_EMPTY( pxCurrentTimerList ) == pdFALSE ) + { + xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList ); + + /* Remove the timer from the list. */ + pxTimer = ( xTIMER * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList ); + ( void ) uxListRemove( &( pxTimer->xTimerListItem ) ); + + /* Execute its callback, then send a command to restart the timer if + it is an auto-reload timer. It cannot be restarted here as the lists + have not yet been switched. */ + pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer ); + //pxTimer->pxCallbackFunction( ( void * ) (pxTimer->pvTimerID) ); + + if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE ) + { + /* Calculate the reload value, and if the reload value results in + the timer going into the same timer list then it has already expired + and the timer should be re-inserted into the current list so it is + processed again within this loop. Otherwise a command should be sent + to restart the timer to ensure it is only inserted into a list after + the lists have been swapped. */ + xReloadTime = ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ); + if( xReloadTime > xNextExpireTime ) + { + listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xReloadTime ); + listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer ); + vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) ); + } + else + { + xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xNextExpireTime, NULL, tmrNO_DELAY ); + configASSERT( xResult ); + ( void ) xResult; + } + } + } + + pxTemp = pxCurrentTimerList; + pxCurrentTimerList = pxOverflowTimerList; + pxOverflowTimerList = pxTemp; +} +/*-----------------------------------------------------------*/ + +static void ICACHE_FLASH_ATTR +prvCheckForValidListAndQueue( void ) +{ + /* Check that the list from which active timers are referenced, and the + queue used to communicate with the timer service, have been + initialised. */ + taskENTER_CRITICAL(); + { + if( xTimerQueue == NULL ) + { + vListInitialise( &xActiveTimerList1 ); + vListInitialise( &xActiveTimerList2 ); + pxCurrentTimerList = &xActiveTimerList1; + pxOverflowTimerList = &xActiveTimerList2; + xTimerQueue = xQueueCreate( ( unsigned portBASE_TYPE ) configTIMER_QUEUE_LENGTH, sizeof( xTIMER_MESSAGE ) ); + } + } + taskEXIT_CRITICAL(); +} +/*-----------------------------------------------------------*/ + +portBASE_TYPE ICACHE_FLASH_ATTR +xTimerIsTimerActive( xTimerHandle xTimer ) +{ +portBASE_TYPE xTimerIsInActiveList; +xTIMER *pxTimer = ( xTIMER * ) xTimer; + + /* Is the timer in the list of active timers? */ + taskENTER_CRITICAL(); + { + /* Checking to see if it is in the NULL list in effect checks to see if + it is referenced from either the current or the overflow timer lists in + one go, but the logic has to be reversed, hence the '!'. */ + xTimerIsInActiveList = !( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) ); + } + taskEXIT_CRITICAL(); + + return xTimerIsInActiveList; +} +/*-----------------------------------------------------------*/ + +void * ICACHE_FLASH_ATTR +pvTimerGetTimerID( xTimerHandle xTimer ) +{ +xTIMER *pxTimer = ( xTIMER * ) xTimer; + + return pxTimer->pvTimerID; +} +/*-----------------------------------------------------------*/ + +/* This entire source file will be skipped if the application is not configured +to include software timer functionality. If you want to include software timer +functionality then ensure configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */ + +#endif /* configUSE_TIMERS == 1 */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/json/Makefile b/Distrib/ESPressif/RTOS/1.5.0/third_party/json/Makefile new file mode 100644 index 0000000..5cad8a3 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/json/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 = libjson.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/Distrib/ESPressif/RTOS/1.5.0/third_party/json/cJSON.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/json/cJSON.c new file mode 100644 index 0000000..a330f69 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/json/cJSON.c @@ -0,0 +1,750 @@ +/* + Copyright (c) 2009 Dave Gamble + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +/* cJSON */ +/* JSON parser in C. */ + +#include +#include +#include +#include +#include +#include +#include +#include "cJSON.h" + +static const char *ep; + +const char *cJSON_GetErrorPtr(void) {return ep;} + +static int cJSON_strcasecmp(const char *s1,const char *s2) +{ + if (!s1) return (s1==s2)?0:1;if (!s2) return 1; + for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0; + return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2); +} + +static void *(*cJSON_malloc)(size_t sz) = malloc; +static void (*cJSON_free)(void *ptr) = free; + +static char* cJSON_strdup(const char* str) +{ + size_t len; + char* copy; + + len = strlen(str) + 1; + if (!(copy = (char*)cJSON_malloc(len))) return 0; + memcpy(copy,str,len); + return copy; +} + +void cJSON_InitHooks(cJSON_Hooks* hooks) +{ + if (!hooks) { /* Reset hooks */ + cJSON_malloc = malloc; + cJSON_free = free; + return; + } + + cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc; + cJSON_free = (hooks->free_fn)?hooks->free_fn:free; +} + +/* Internal constructor. */ +static cJSON *cJSON_New_Item(void) +{ + cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); + if (node) memset(node,0,sizeof(cJSON)); + return node; +} + +/* Delete a cJSON structure. */ +void cJSON_Delete(cJSON *c) +{ + cJSON *next; + while (c) + { + next=c->next; + if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child); + if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring); + if (!(c->type&cJSON_StringIsConst) && c->string) cJSON_free(c->string); + cJSON_free(c); + c=next; + } +} + +/* Parse the input text to generate a number, and populate the result into item. */ +static const char *parse_number(cJSON *item,const char *num) +{ + double n=0,sign=1,scale=0;int subscale=0,signsubscale=1; + + if (*num=='-') sign=-1,num++; /* Has sign? */ + if (*num=='0') num++; /* is zero */ + if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */ + if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */ + if (*num=='e' || *num=='E') /* Exponent? */ + { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */ + while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */ + } + + n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */ + + item->valuedouble=n; + item->valueint=(int)n; + item->type=cJSON_Number; + return num; +} + +static int pow2gt (int x) { --x; x|=x>>1; x|=x>>2; x|=x>>4; x|=x>>8; x|=x>>16; return x+1; } + +typedef struct {char *buffer; int length; int offset; } printbuffer; + +static char* ensure(printbuffer *p,int needed) +{ + char *newbuffer;int newsize; + if (!p || !p->buffer) return 0; + needed+=p->offset; + if (needed<=p->length) return p->buffer+p->offset; + + newsize=pow2gt(needed); + newbuffer=(char*)cJSON_malloc(newsize); + if (!newbuffer) {cJSON_free(p->buffer);p->length=0,p->buffer=0;return 0;} + if (newbuffer) memcpy(newbuffer,p->buffer,p->length); + cJSON_free(p->buffer); + p->length=newsize; + p->buffer=newbuffer; + return newbuffer+p->offset; +} + +static int update(printbuffer *p) +{ + char *str; + if (!p || !p->buffer) return 0; + str=p->buffer+p->offset; + return p->offset+strlen(str); +} + +/* Render the number nicely from the given item into a string. */ +static char *print_number(cJSON *item,printbuffer *p) +{ + char *str=0; + double d=item->valuedouble; + if (d==0) + { + if (p) str=ensure(p,2); + else str=(char*)cJSON_malloc(2); /* special case for 0. */ + if (str) strcpy(str,"0"); + } + else if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN) + { + if (p) str=ensure(p,21); + else str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */ + if (str) sprintf(str,"%d",item->valueint); + } + else + { + if (p) str=ensure(p,64); + else str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */ + if (str) + { + if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d); + else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d); + else sprintf(str,"%f",d); + } + } + return str; +} + +static unsigned parse_hex4(const char *str) +{ + unsigned h=0; + if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; + h=h<<4;str++; + if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; + h=h<<4;str++; + if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; + h=h<<4;str++; + if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; + return h; +} + +/* Parse the input text into an unescaped cstring, and populate item. */ +static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; +static const char *parse_string(cJSON *item,const char *str) +{ + const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2; + if (*str!='\"') {ep=str;return 0;} /* not a string! */ + + while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */ + + out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */ + if (!out) return 0; + + ptr=str+1;ptr2=out; + while (*ptr!='\"' && *ptr) + { + if (*ptr!='\\') *ptr2++=*ptr++; + else + { + ptr++; + switch (*ptr) + { + case 'b': *ptr2++='\b'; break; + case 'f': *ptr2++='\f'; break; + case 'n': *ptr2++='\n'; break; + case 'r': *ptr2++='\r'; break; + case 't': *ptr2++='\t'; break; + case 'u': /* transcode utf16 to utf8. */ + uc=parse_hex4(ptr+1);ptr+=4; /* get the unicode char. */ + + if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; /* check for invalid. */ + + if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */ + { + if (ptr[1]!='\\' || ptr[2]!='u') break; /* missing second-half of surrogate. */ + uc2=parse_hex4(ptr+3);ptr+=6; + if (uc2<0xDC00 || uc2>0xDFFF) break; /* invalid second-half of surrogate. */ + uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF)); + } + + len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len; + + switch (len) { + case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; + case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; + case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; + case 1: *--ptr2 =(uc | firstByteMark[len]); + } + ptr2+=len; + break; + default: *ptr2++=*ptr; break; + } + ptr++; + } + } + *ptr2=0; + if (*ptr=='\"') ptr++; + item->valuestring=out; + item->type=cJSON_String; + return ptr; +} + +/* Render the cstring provided to an escaped version that can be printed. */ +static char *print_string_ptr(const char *str,printbuffer *p) +{ + const char *ptr;char *ptr2,*out;int len=0,flag=0;unsigned char token; + + for (ptr=str;*ptr;ptr++) flag|=((*ptr>0 && *ptr<32)||(*ptr=='\"')||(*ptr=='\\'))?1:0; + if (!flag) + { + len=ptr-str; + if (p) out=ensure(p,len+3); + else out=(char*)cJSON_malloc(len+3); + if (!out) return 0; + ptr2=out;*ptr2++='\"'; + strcpy(ptr2,str); + ptr2[len]='\"'; + ptr2[len+1]=0; + return out; + } + + if (!str) + { + if (p) out=ensure(p,3); + else out=(char*)cJSON_malloc(3); + if (!out) return 0; + strcpy(out,"\"\""); + return out; + } + ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;} + + if (p) out=ensure(p,len+3); + else out=(char*)cJSON_malloc(len+3); + if (!out) return 0; + + ptr2=out;ptr=str; + *ptr2++='\"'; + while (*ptr) + { + if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++; + else + { + *ptr2++='\\'; + switch (token=*ptr++) + { + case '\\': *ptr2++='\\'; break; + case '\"': *ptr2++='\"'; break; + case '\b': *ptr2++='b'; break; + case '\f': *ptr2++='f'; break; + case '\n': *ptr2++='n'; break; + case '\r': *ptr2++='r'; break; + case '\t': *ptr2++='t'; break; + default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */ + } + } + } + *ptr2++='\"';*ptr2++=0; + return out; +} +/* Invote print_string_ptr (which is useful) on an item. */ +static char *print_string(cJSON *item,printbuffer *p) {return print_string_ptr(item->valuestring,p);} + +/* Predeclare these prototypes. */ +static const char *parse_value(cJSON *item,const char *value); +static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p); +static const char *parse_array(cJSON *item,const char *value); +static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p); +static const char *parse_object(cJSON *item,const char *value); +static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p); + +/* Utility to jump whitespace and cr/lf */ +static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;} + +/* Parse an object - create a new root, and populate. */ +cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated) +{ + const char *end=0; + cJSON *c=cJSON_New_Item(); + ep=0; + if (!c) return 0; /* memory fail */ + + end=parse_value(c,skip(value)); + if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */ + + /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ + if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}} + if (return_parse_end) *return_parse_end=end; + return c; +} +/* Default options for cJSON_Parse */ +cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);} + +/* Render a cJSON item/entity/structure to text. */ +char *cJSON_Print(cJSON *item) {return print_value(item,0,1,0);} +char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0,0);} + +char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt) +{ + printbuffer p; + p.buffer=(char*)cJSON_malloc(prebuffer); + p.length=prebuffer; + p.offset=0; + return print_value(item,0,fmt,&p); + return p.buffer; +} + + +/* Parser core - when encountering text, process appropriately. */ +static const char *parse_value(cJSON *item,const char *value) +{ + if (!value) return 0; /* Fail on null. */ + if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; } + if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; } + if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; } + if (*value=='\"') { return parse_string(item,value); } + if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); } + if (*value=='[') { return parse_array(item,value); } + if (*value=='{') { return parse_object(item,value); } + + ep=value;return 0; /* failure. */ +} + +/* Render a value to text. */ +static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p) +{ + char *out=0; + if (!item) return 0; + if (p) + { + switch ((item->type)&255) + { + case cJSON_NULL: {out=ensure(p,5); if (out) strcpy(out,"null"); break;} + case cJSON_False: {out=ensure(p,6); if (out) strcpy(out,"false"); break;} + case cJSON_True: {out=ensure(p,5); if (out) strcpy(out,"true"); break;} + case cJSON_Number: out=print_number(item,p);break; + case cJSON_String: out=print_string(item,p);break; + case cJSON_Array: out=print_array(item,depth,fmt,p);break; + case cJSON_Object: out=print_object(item,depth,fmt,p);break; + } + } + else + { + switch ((item->type)&255) + { + case cJSON_NULL: out=cJSON_strdup("null"); break; + case cJSON_False: out=cJSON_strdup("false");break; + case cJSON_True: out=cJSON_strdup("true"); break; + case cJSON_Number: out=print_number(item,0);break; + case cJSON_String: out=print_string(item,0);break; + case cJSON_Array: out=print_array(item,depth,fmt,0);break; + case cJSON_Object: out=print_object(item,depth,fmt,0);break; + } + } + return out; +} + +/* Build an array from input text. */ +static const char *parse_array(cJSON *item,const char *value) +{ + cJSON *child; + if (*value!='[') {ep=value;return 0;} /* not an array! */ + + item->type=cJSON_Array; + value=skip(value+1); + if (*value==']') return value+1; /* empty array. */ + + item->child=child=cJSON_New_Item(); + if (!item->child) return 0; /* memory fail */ + value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */ + if (!value) return 0; + + while (*value==',') + { + cJSON *new_item; + if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ + child->next=new_item;new_item->prev=child;child=new_item; + value=skip(parse_value(child,skip(value+1))); + if (!value) return 0; /* memory fail */ + } + + if (*value==']') return value+1; /* end of array */ + ep=value;return 0; /* malformed. */ +} + +/* Render an array to text */ +static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p) +{ + char **entries; + char *out=0,*ptr,*ret;int len=5; + cJSON *child=item->child; + int numentries=0,i=0,fail=0; + size_t tmplen=0; + + /* How many entries in the array? */ + while (child) numentries++,child=child->next; + /* Explicitly handle numentries==0 */ + if (!numentries) + { + if (p) out=ensure(p,3); + else out=(char*)cJSON_malloc(3); + if (out) strcpy(out,"[]"); + return out; + } + + if (p) + { + /* Compose the output array. */ + i=p->offset; + ptr=ensure(p,1);if (!ptr) return 0; *ptr='['; p->offset++; + child=item->child; + while (child && !fail) + { + print_value(child,depth+1,fmt,p); + p->offset=update(p); + if (child->next) {len=fmt?2:1;ptr=ensure(p,len+1);if (!ptr) return 0;*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;p->offset+=len;} + child=child->next; + } + ptr=ensure(p,2);if (!ptr) return 0; *ptr++=']';*ptr=0; + out=(p->buffer)+i; + } + else + { + /* Allocate an array to hold the values for each */ + entries=(char**)cJSON_malloc(numentries*sizeof(char*)); + if (!entries) return 0; + memset(entries,0,numentries*sizeof(char*)); + /* Retrieve all the results: */ + child=item->child; + while (child && !fail) + { + ret=print_value(child,depth+1,fmt,0); + entries[i++]=ret; + if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1; + child=child->next; + } + + /* If we didn't fail, try to malloc the output string */ + if (!fail) out=(char*)cJSON_malloc(len); + /* If that fails, we fail. */ + if (!out) fail=1; + + /* Handle failure. */ + if (fail) + { + for (i=0;itype=cJSON_Object; + value=skip(value+1); + if (*value=='}') return value+1; /* empty array. */ + + item->child=child=cJSON_New_Item(); + if (!item->child) return 0; + value=skip(parse_string(child,skip(value))); + if (!value) return 0; + child->string=child->valuestring;child->valuestring=0; + if (*value!=':') {ep=value;return 0;} /* fail! */ + value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ + if (!value) return 0; + + while (*value==',') + { + cJSON *new_item; + if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ + child->next=new_item;new_item->prev=child;child=new_item; + value=skip(parse_string(child,skip(value+1))); + if (!value) return 0; + child->string=child->valuestring;child->valuestring=0; + if (*value!=':') {ep=value;return 0;} /* fail! */ + value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ + if (!value) return 0; + } + + if (*value=='}') return value+1; /* end of array */ + ep=value;return 0; /* malformed. */ +} + +/* Render an object to text. */ +static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p) +{ + char **entries=0,**names=0; + char *out=0,*ptr,*ret,*str;int len=7,i=0,j; + cJSON *child=item->child; + int numentries=0,fail=0; + size_t tmplen=0; + /* Count the number of entries. */ + while (child) numentries++,child=child->next; + /* Explicitly handle empty object case */ + if (!numentries) + { + if (p) out=ensure(p,fmt?depth+4:3); + else out=(char*)cJSON_malloc(fmt?depth+4:3); + if (!out) return 0; + ptr=out;*ptr++='{'; + if (fmt) {*ptr++='\n';for (i=0;ioffset; + len=fmt?2:1; ptr=ensure(p,len+1); if (!ptr) return 0; + *ptr++='{'; if (fmt) *ptr++='\n'; *ptr=0; p->offset+=len; + child=item->child;depth++; + while (child) + { + if (fmt) + { + ptr=ensure(p,depth); if (!ptr) return 0; + for (j=0;joffset+=depth; + } + print_string_ptr(child->string,p); + p->offset=update(p); + + len=fmt?2:1; + ptr=ensure(p,len); if (!ptr) return 0; + *ptr++=':';if (fmt) *ptr++='\t'; + p->offset+=len; + + print_value(child,depth,fmt,p); + p->offset=update(p); + + len=(fmt?1:0)+(child->next?1:0); + ptr=ensure(p,len+1); if (!ptr) return 0; + if (child->next) *ptr++=','; + if (fmt) *ptr++='\n';*ptr=0; + p->offset+=len; + child=child->next; + } + ptr=ensure(p,fmt?(depth+1):2); if (!ptr) return 0; + if (fmt) for (i=0;ibuffer)+i; + } + else + { + /* Allocate space for the names and the objects */ + entries=(char**)cJSON_malloc(numentries*sizeof(char*)); + if (!entries) return 0; + names=(char**)cJSON_malloc(numentries*sizeof(char*)); + if (!names) {cJSON_free(entries);return 0;} + memset(entries,0,sizeof(char*)*numentries); + memset(names,0,sizeof(char*)*numentries); + + /* Collect all the results into our arrays: */ + child=item->child;depth++;if (fmt) len+=depth; + while (child) + { + names[i]=str=print_string_ptr(child->string,0); + entries[i++]=ret=print_value(child,depth,fmt,0); + if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1; + child=child->next; + } + + /* Try to allocate the output string */ + if (!fail) out=(char*)cJSON_malloc(len); + if (!out) fail=1; + + /* Handle failure */ + if (fail) + { + for (i=0;ichild;int i=0;while(c)i++,c=c->next;return i;} +cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;} +cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;} + +/* Utility for array list handling. */ +static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} +/* Utility for handling references. */ +static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;} + +/* Add item to array/object. */ +void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}} +void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);} +void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (!(item->type&cJSON_StringIsConst) && item->string) cJSON_free(item->string);item->string=(char*)string;item->type|=cJSON_StringIsConst;cJSON_AddItemToArray(object,item);} +void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));} +void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));} + +cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0; + if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;} +void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));} +cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;} +void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} + +/* Replace array/object items with new ones. */ +void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) {cJSON_AddItemToArray(array,newitem);return;} + newitem->next=c;newitem->prev=c->prev;c->prev=newitem;if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;} +void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; + newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem; + if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);} +void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}} + +/* Create basic types: */ +cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;} +cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;} +cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;} +cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;} +cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;} +cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;} +cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;} +cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} + +/* Create Arrays: */ +cJSON *cJSON_CreateIntArray(const int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateFloatArray(const float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateDoubleArray(const double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} + +/* Duplication */ +cJSON *cJSON_Duplicate(cJSON *item,int recurse) +{ + cJSON *newitem,*cptr,*nptr=0,*newchild; + /* Bail on bad ptr */ + if (!item) return 0; + /* Create new item */ + newitem=cJSON_New_Item(); + if (!newitem) return 0; + /* Copy over all vars */ + newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble; + if (item->valuestring) {newitem->valuestring=cJSON_strdup(item->valuestring); if (!newitem->valuestring) {cJSON_Delete(newitem);return 0;}} + if (item->string) {newitem->string=cJSON_strdup(item->string); if (!newitem->string) {cJSON_Delete(newitem);return 0;}} + /* If non-recursive, then we're done! */ + if (!recurse) return newitem; + /* Walk the ->next chain for the child. */ + cptr=item->child; + while (cptr) + { + newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */ + if (!newchild) {cJSON_Delete(newitem);return 0;} + if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */ + else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */ + cptr=cptr->next; + } + return newitem; +} + +void cJSON_Minify(char *json) +{ + char *into=json; + while (*json) + { + if (*json==' ') json++; + else if (*json=='\t') json++; /* Whitespace characters. */ + else if (*json=='\r') json++; + else if (*json=='\n') json++; + else if (*json=='/' && json[1]=='/') while (*json && *json!='\n') json++; /* double-slash comments, to end of line. */ + else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;} /* multiline comments. */ + else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} /* string literals, which are \" sensitive. */ + else *into++=*json++; /* All other characters. */ + } + *into=0; /* and null-terminate. */ +} diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/FILES b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/FILES new file mode 100644 index 0000000..952aeab --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/FILES @@ -0,0 +1,13 @@ +api/ - The code for the high-level wrapper API. Not needed if + you use the lowel-level call-back/raw API. + +core/ - The core of the TPC/IP stack; protocol implementations, + memory and buffer management, and the low-level raw API. + +include/ - lwIP include files. + +netif/ - Generic network interface device drivers are kept here, + as well as the ARP module. + +For more information on the various subdirectories, check the FILES +file in each directory. diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/Makefile b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/Makefile new file mode 100644 index 0000000..efd5a35 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/Makefile @@ -0,0 +1,56 @@ + +############################################################# +# 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 \ + arch/liblwiparch.a \ + core/liblwipcore.a \ + core/ipv4/liblwipipv4.a \ + core/ipv6/liblwipipv6.a \ + netif/liblwipnetif.a \ + apps/liblwipapps.a +endif + +CCFLAGS += -fno-aggressive-loop-optimizations + +############################################################# +# 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 += -D_POSIX_SOURCE \ + -DLWIP_OPEN_SRC \ + -DPBUF_RSV_FOR_WLAN \ + -DEBUF_LWIP + +############################################################# +# 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/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/Makefile b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/Makefile new file mode 100644 index 0000000..69b027d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/api_lib.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/api_lib.c new file mode 100644 index 0000000..f862d75 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/api_lib.c @@ -0,0 +1,802 @@ +/** + * @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 + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +/** + * 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) { + err_t err; + msg.msg.msg.n.proto = proto; + msg.msg.conn = conn; + TCPIP_APIMSG((&msg), lwip_netconn_do_newconn, err); + if (err != 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_sem_free(&conn->snd_op_completed); + sys_sem_free(&conn->ioctrl_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 = lwip_netconn_do_delconn; + msg.msg.conn = conn; + tcpip_apimsg(&msg); + + netconn_free(conn); + + /* don't care for return value of lwip_netconn_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.msg.conn = conn; + msg.msg.msg.ad.ipaddr = ip_2_ipX(addr); + msg.msg.msg.ad.port = port; + msg.msg.msg.ad.local = local; + TCPIP_APIMSG(&msg, lwip_netconn_do_getaddr, err); + + 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.msg.conn = conn; + msg.msg.msg.bc.ipaddr = addr; + msg.msg.msg.bc.port = port; + TCPIP_APIMSG(&msg, lwip_netconn_do_bind, err); + + 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.msg.conn = conn; + msg.msg.msg.bc.ipaddr = addr; + msg.msg.msg.bc.port = port; +#if LWIP_TCP +#if (LWIP_UDP || LWIP_RAW) + if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) +#endif /* (LWIP_UDP || LWIP_RAW) */ + { + /* The TCP version waits for the connect to succeed, + so always needs to use message passing. */ + msg.function = lwip_netconn_do_connect; + err = tcpip_apimsg(&msg); + } +#endif /* LWIP_TCP */ +#if (LWIP_UDP || LWIP_RAW) && LWIP_TCP + else +#endif /* (LWIP_UDP || LWIP_RAW) && LWIP_TCP */ +#if (LWIP_UDP || LWIP_RAW) + { + /* UDP and RAW only set flags, so we can use core-locking. */ + TCPIP_APIMSG(&msg, lwip_netconn_do_connect, err); + } +#endif /* (LWIP_UDP || LWIP_RAW) */ + + 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.msg.conn = conn; + TCPIP_APIMSG(&msg, lwip_netconn_do_disconnect, err); + + 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.msg.conn = conn; +#if TCP_LISTEN_BACKLOG + msg.msg.msg.lb.backlog = backlog; +#endif /* TCP_LISTEN_BACKLOG */ + TCPIP_APIMSG(&msg, lwip_netconn_do_listen, err); + + 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 aborted */ + NETCONN_SET_SAFE_ERR(conn, ERR_ABRT); + return ERR_ABRT; + } +#if TCP_LISTEN_BACKLOG + /* Let the stack know that we have accepted the connection. */ + msg.msg.conn = conn; + /* don't care for the return value of lwip_netconn_do_recv */ + TCPIP_APIMSG_NOERR(&msg, lwip_netconn_do_recv); +#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 (LWIP_UDP || LWIP_RAW) + if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) +#endif /* (LWIP_UDP || LWIP_RAW) */ + { + 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.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 lwip_netconn_do_recv */ + TCPIP_APIMSG_NOERR(&msg, lwip_netconn_do_recv); + } + + /* 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); + /*start for mutlix thread by liuhan*/ + 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; + } + /*finish for mutlix thread by liuhan*/ + 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) && + NETCONNTYPE_GROUP(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 (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) { + 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; + ipX_addr_set_any(LWIP_IPV6, &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) */ + } +} + +/** + * 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) && (NETCONNTYPE_GROUP(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.msg.conn = conn; + msg.msg.msg.r.len = length; + /* don't care for the return value of lwip_netconn_do_recv */ + TCPIP_APIMSG_NOERR(&msg, lwip_netconn_do_recv); + } +#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) { + ipX_addr_set_ipaddr(PCB_ISIPV6(conn->pcb.ip), &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.msg.conn = conn; + msg.msg.msg.b = buf; + TCPIP_APIMSG(&msg, lwip_netconn_do_send, err); + + 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 + * @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) +{ + struct api_msg msg; + err_t err; + u8_t dontblock; + + LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;); + LWIP_ERROR("netconn_write: invalid conn->type", (NETCONNTYPE_GROUP(conn->type)== NETCONN_TCP), return ERR_VAL;); + if (size == 0) { + return ERR_OK; + } + dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK); + if (dontblock && !bytes_written) { + /* This implies netconn_write() cannot be used for non-blocking send, since + it has no way to return the number of bytes written. */ + return ERR_VAL; + } + + /* non-blocking write sends as much */ + msg.msg.conn = conn; + msg.msg.msg.w.dataptr = dataptr; + msg.msg.msg.w.apiflags = apiflags; + msg.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 */ + msg.msg.msg.w.time_started = sys_now(); + } else { + msg.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. */ + TCPIP_APIMSG(&msg, lwip_netconn_do_write, err); + if ((err == ERR_OK) && (bytes_written != NULL)) { + if (dontblock +#if LWIP_SO_SNDTIMEO + || (conn->send_timeout != 0) +#endif /* LWIP_SO_SNDTIMEO */ + ) { + /* nonblocking write: maybe the data has been sent partly */ + *bytes_written = msg.msg.msg.w.len; + } else { + /* blocking call succeeded: all data has been sent if it */ + *bytes_written = size; + } + } + + 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 = lwip_netconn_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 lwip_netconn_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 || (LWIP_IPV6 && LWIP_IPV6_MLD) +/** + * 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.msg.conn = conn; + msg.msg.msg.jl.multiaddr = ip_2_ipX(multiaddr); + msg.msg.msg.jl.netif_addr = ip_2_ipX(netif_addr); + msg.msg.msg.jl.join_or_leave = join_or_leave; + TCPIP_APIMSG(&msg, lwip_netconn_do_join_leave_group, err); + + NETCONN_SET_SAFE_ERR(conn, err); + return err; +} +#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ + +#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(lwip_netconn_do_gethostbyname, &msg); + sys_sem_wait(&sem); + sys_sem_free(&sem); + + return err; +} +#endif /* LWIP_DNS*/ + +#endif /* LWIP_NETCONN */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/api_msg.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/api_msg.c new file mode 100644 index 0000000..e375518 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/api_msg.c @@ -0,0 +1,1712 @@ +/** + * @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 "lwip/mld6.h" + +#include + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +#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 lwip_netconn_do_writemore(struct netconn *conn); +static void lwip_netconn_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; + ipX_addr_copy(PCB_ISIPV6(pcb), buf->addr, *ipX_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; + ipX_addr_set_ipaddr(ip_current_is_v6(), &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 = ipX_next_header_ptr(); +#if LWIP_CHECKSUM_ON_COPY + buf->flags = NETBUF_FLAG_DESTADDR; +#endif /* LWIP_CHECKSUM_ON_COPY */ + ipX_addr_set(ip_current_is_v6(), &buf->toaddr, ipX_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! */ + 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! */ +#ifdef SOCKETS_TCP_TRACE + ADD_TCP_RECV_BYTES_ERR(conn, len); +#endif + 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); + } +#ifdef SOCKETS_TCP_TRACE + ADD_TCP_RECV_BYTES(conn, len); +#endif + 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); + } else if (conn->state == NETCONN_CLOSE) { + lwip_netconn_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) { + lwip_netconn_do_writemore(conn); + } else if (conn->state == NETCONN_CLOSE) { + lwip_netconn_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); + } + +#ifdef SOCKETS_TCP_TRACE + ADD_TCP_SEND_BYTES_OK(conn, len); +#endif + } + + 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 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) { + /* set error return code */ + LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); + //Jack, temp modify here, We haven't find the root cause; + if(conn->current_msg != NULL) + conn->current_msg->err = err; + conn->current_msg = NULL; + /* wake up the waiting task */ + if (old_state == NETCONN_WRITE) { + sys_sem_signal(&conn->snd_op_completed); + } else { + 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! */ + /* 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, 4); + tcp_err(pcb, NULL); + /* remove reference from to the pcb from this netconn */ + newconn->pcb.tcp = NULL; + /* no need to drain since we know the recvmbox is empty. */ + sys_mbox_free(&newconn->recvmbox); + sys_mbox_set_invalid(&newconn->recvmbox); + netconn_free(newconn); + return ERR_MEM; + } else { + /* Register event with callback */ + API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); + } + + return ERR_OK; +} +#endif /* LWIP_TCP */ + +/** + * Create a new pcb of a specific type. + * Called from lwip_netconn_do_newconn(). + * + * @param msg the api_msg_msg describing the connection type + * @return msg->conn->err, but the return value is currently ignored + */ +static void +pcb_new(struct api_msg_msg *msg) +{ + LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL); + + /* Allocate a PCB for this connection */ + switch(NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW + case NETCONN_RAW: + msg->conn->pcb.raw = raw_new(msg->msg.n.proto); + if(msg->conn->pcb.raw != NULL) { + raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn); + } + break; +#endif /* LWIP_RAW */ +#if LWIP_UDP + case NETCONN_UDP: + msg->conn->pcb.udp = udp_new(); + if(msg->conn->pcb.udp != NULL) { +#if LWIP_UDPLITE + if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) { + udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE); + } +#endif /* LWIP_UDPLITE */ + if (NETCONNTYPE_ISUDPNOCHKSUM(msg->conn->type)) { + udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); + } + udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn); + } + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP + case NETCONN_TCP: + msg->conn->pcb.tcp = tcp_new(); + if(msg->conn->pcb.tcp != NULL) { + setup_tcp(msg->conn); + } + break; +#endif /* LWIP_TCP */ + default: + /* Unsupported netconn type, e.g. protocol disabled */ + msg->err = ERR_VAL; + return; + } + if (msg->conn->pcb.ip == NULL) { + msg->err = ERR_MEM; + } +#if LWIP_IPV6 + else { + if (NETCONNTYPE_ISIPV6(msg->conn->type)) { + ip_set_v6(msg->conn->pcb.ip, 1); + } + } +#endif /* LWIP_IPV6 */ +} + +/** + * 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 +lwip_netconn_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 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_sem_new(&conn->op_completed, 0) != ERR_OK) { + goto free_and_return; + } + if (sys_sem_new(&conn->snd_op_completed, 0) != ERR_OK) { + sys_sem_free(&conn->op_completed); + goto free_and_return; + } + if (sys_sem_new(&conn->ioctrl_completed, 0) != ERR_OK) { + sys_sem_free(&conn->snd_op_completed); + sys_sem_free(&conn->op_completed); + goto free_and_return; + } + + if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) { + sys_sem_free(&conn->op_completed); + sys_sem_free(&conn->snd_op_completed); + sys_sem_free(&conn->ioctrl_completed); + goto free_and_return; + } + +#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; + conn->recv_holded_buf_Len = 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 = 0; +#endif +#ifdef SOCKETS_TCP_TRACE + ADD_TCP_RECV_BYTES_CLEAR(conn); + ADD_TCP_RECV_BYTES_ERR_CLEAR(conn) + + ADD_TCP_SEND_BYTES_CLEAR(conn); + ADD_TCP_SEND_BYTES_OK_CLEAR(conn); + ADD_TCP_SEND_BYTES_NOMEM_CLEAR(conn); +#endif + 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 */ + + sys_sem_free(&conn->op_completed); + sys_sem_free(&conn->snd_op_completed); + sys_sem_free(&conn->ioctrl_completed); + sys_sem_set_invalid(&conn->op_completed); + sys_sem_set_invalid(&conn->snd_op_completed); + sys_sem_set_invalid(&conn->ioctrl_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 (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 */ + { + if (mem) + 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 */ + if (newconn) { + 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 +lwip_netconn_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", (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); + + 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); + } + } + +#if LWIP_SO_LINGER + /* Add by DongHeng, for TCP free by multi-thread */ + if (conn->linger > 0) { + tcp_abort(conn->pcb.tcp); + err = ERR_OK; + } + else +#endif + if (close) { /* Try to close the connection */ + err = tcp_close(conn->pcb.tcp); + } else { + err = tcp_shutdown(conn->pcb.tcp, shut_rx, shut_tx); + } + + if (err == ERR_OK) { + /* Closing succeeded */ + //Jack, temp modify here, We haven't find the root cause; + if(conn->current_msg != NULL) + conn->current_msg->err = ERR_OK; + conn->current_msg = NULL; + conn->state = NETCONN_NONE; + 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); + } + /* wake up the application task */ + sys_sem_signal(&conn->op_completed); + +// if (conn->state == NETCONN_WRITE) { +// sys_sem_signal(&conn->snd_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 +lwip_netconn_do_delconn(struct api_msg_msg *msg) +{ +#if 1 + /* @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("NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP", + NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP); + msg->err = ERR_INPROGRESS; + } else +#endif + { + 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; + lwip_netconn_do_close_internal(msg->conn); + /* 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(&msg->conn->op_completed)) { + sys_sem_signal(&msg->conn->op_completed); + +// if (msg->conn->state == NETCONN_WRITE) { +// sys_sem_signal(&msg->conn->snd_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 +lwip_netconn_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/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; + + 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)); + + //Jack, temp modify here, We haven't find the root cause; + if (conn->current_msg != NULL) { + conn->current_msg->err = err; + } + if ((NETCONNTYPE_GROUP(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) { + NETCONN_SET_SAFE_ERR(conn, ERR_OK); + } + 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 +lwip_netconn_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; + if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { + /* For TCP, netconn_connect() calls tcpip_apimsg(), so signal op_completed here. */ + sys_sem_signal(&msg->conn->op_completed); + return; + } + } 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) { +#ifdef LWIP_ESP8266 + if (msg->conn->pcb.tcp->state == ESTABLISHED) + msg->err = ERR_ISCONN; + else + msg->err = ERR_ALREADY; +#else + msg->err = ERR_ISCONN; +#endif + } else { + setup_tcp(msg->conn); + msg->err = tcp_connect(msg->conn->pcb.tcp, 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! */ + return; + } + } + } + /* For TCP, netconn_connect() calls tcpip_apimsg(), so signal op_completed here. */ + sys_sem_signal(&msg->conn->op_completed); + return; +#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); +} + +/** + * 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 +lwip_netconn_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 +lwip_netconn_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 (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { + if (msg->conn->state == NETCONN_NONE) { + struct tcp_pcb* lpcb; +#if LWIP_IPV6 + if ((msg->conn->flags & NETCONN_FLAG_IPV6_V6ONLY) == 0) { +#if TCP_LISTEN_BACKLOG + lpcb = tcp_listen_dual_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog); +#else /* TCP_LISTEN_BACKLOG */ + lpcb = tcp_listen_dual(msg->conn->pcb.tcp); +#endif /* TCP_LISTEN_BACKLOG */ + } else +#endif /* LWIP_IPV6 */ + { +#if TCP_LISTEN_BACKLOG + lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog); +#else /* TCP_LISTEN_BACKLOG */ + lpcb = tcp_listen(msg->conn->pcb.tcp); +#endif /* TCP_LISTEN_BACKLOG */ + } + if (lpcb == NULL) { + /* in this case, the old pcb is still allocated */ + msg->err = ERR_MEM; + } else { + /* delete the recvmbox and allocate the acceptmbox */ + if (sys_mbox_valid(&msg->conn->recvmbox)) { + /** @todo: should we drain the recvmbox here? */ + sys_mbox_free(&msg->conn->recvmbox); + sys_mbox_set_invalid(&msg->conn->recvmbox); + } + msg->err = ERR_OK; + if (!sys_mbox_valid(&msg->conn->acceptmbox)) { + msg->err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE); + } + if (msg->err == ERR_OK) { + msg->conn->state = NETCONN_LISTEN; + msg->conn->pcb.tcp = lpcb; + tcp_arg(msg->conn->pcb.tcp, msg->conn); + tcp_accept(msg->conn->pcb.tcp, accept_function); + } else { + /* since the old pcb is already deallocated, free lpcb now */ + tcp_close(lpcb); + msg->conn->pcb.tcp = NULL; + } + } + } + } else { + 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 msg the api_msg_msg pointing to the connection + */ +void +lwip_netconn_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 (ipX_addr_isany(PCB_ISIPV6(msg->conn->pcb.ip), &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, ipX_2_ip(&msg->msg.b->addr)); + } + break; +#endif +#if LWIP_UDP + case NETCONN_UDP: +#if LWIP_CHECKSUM_ON_COPY + if (ipX_addr_isany(PCB_ISIPV6(msg->conn->pcb.ip), &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, + ipX_2_ip(&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 (ipX_addr_isany(PCB_ISIPV6(msg->conn->pcb.ip), &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, ipX_2_ip(&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 +lwip_netconn_do_recv(struct api_msg_msg *msg) +{ + msg->err = ERR_OK; + if (msg->conn->pcb.tcp != NULL) { + if (NETCONNTYPE_GROUP(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 */ + { + //***********Code for WIFI_BLOCK from upper************** + if( ((msg->conn)->flags & NETCONN_FLAG_RECV_HOLD) != 0 ) { + msg->conn->recv_holded_buf_Len += msg->msg.r.len; + } else { + 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 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) +{ + err_t err; + 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); + +#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; + } + } else +#endif /* LWIP_SO_SNDTIMEO */ + { + 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 (dontblock){ + if (!len) { + err = ERR_WOULDBLOCK; + goto err_mem; + } + } else { +#if LWIP_TCPIP_CORE_LOCKING + conn->flags |= NETCONN_FLAG_WRITE_DELAYED; +#endif + 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); +#ifdef SOCKETS_TCP_TRACE + if (ERR_OK == err) { + ADD_TCP_SEND_BYTES(conn, len); + } else if (ERR_MEM == err) { + ADD_TCP_SEND_BYTES_NOMEM(conn, len); + } +#endif + /* 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) { + 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; + conn->write_offset = 0; + } + tcp_output(conn->pcb.tcp); + } else if ((err == ERR_MEM) && !dontblock) { + /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called + we do NOT return to the application thread, since ERR_MEM is + only a temporary error! */ + + /* tcp_write returned ERR_MEM, try tcp_output anyway */ + 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; + conn->current_msg->msg.w.len = 0; + } + } + if (write_finished) { + /* everything was written: set back connection state + and back to application task */ + //Jack, temp modify here, We haven't find the root cause; + if(conn->current_msg != NULL) + 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); + sys_sem_signal(&conn->snd_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 +lwip_netconn_do_write(struct api_msg_msg *msg) +{ + 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 + msg->conn->flags &= ~NETCONN_FLAG_WRITE_DELAYED; + if (lwip_netconn_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); + sys_arch_sem_wait(&msg->conn->snd_op_completed, 0); + LOCK_TCPIP_CORE(); + LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE); + } +#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); + TCPIP_APIMSG_ACK_SND(msg); +} + +/** + * Return a connection's local or remote address + * Called from netconn_getaddr + * + * @param msg the api_msg_msg pointing to the connection + */ +void +lwip_netconn_do_getaddr(struct api_msg_msg *msg) +{ + if (msg->conn->pcb.ip != NULL) { + if (msg->msg.ad.local) { + ipX_addr_copy(PCB_ISIPV6(msg->conn->pcb.ip), *(msg->msg.ad.ipaddr), + msg->conn->pcb.ip->local_ip); + } else { + ipX_addr_copy(PCB_ISIPV6(msg->conn->pcb.ip), *(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) { + *(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 +lwip_netconn_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("NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP", + NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP); + msg->err = ERR_INPROGRESS; + } else if ((msg->conn->pcb.tcp != NULL) && (NETCONNTYPE_GROUP(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; + lwip_netconn_do_close_internal(msg->conn); + /* for tcp netconns, lwip_netconn_do_close_internal ACKs the message */ + return; + } + } else +#endif /* LWIP_TCP */ + { + msg->err = ERR_VAL; + } + sys_sem_signal(&msg->conn->op_completed); + +// if (msg->conn->state == NETCONN_WRITE) { +// sys_sem_signal(&msg->conn->snd_op_completed); +// } +} + +#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) +/** + * Join multicast groups for UDP netconns. + * Called from netconn_join_leave_group + * + * @param msg the api_msg_msg pointing to the connection + */ +void +lwip_netconn_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 LWIP_IPV6 && LWIP_IPV6_MLD + if (PCB_ISIPV6(msg->conn->pcb.udp)) { + if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { + msg->err = mld6_joingroup(ipX_2_ip6(msg->msg.jl.netif_addr), + ipX_2_ip6(msg->msg.jl.multiaddr)); + } else { + msg->err = mld6_leavegroup(ipX_2_ip6(msg->msg.jl.netif_addr), + ipX_2_ip6(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(ipX_2_ip(msg->msg.jl.netif_addr), + ipX_2_ip(msg->msg.jl.multiaddr)); + } else { + msg->err = igmp_leavegroup(ipX_2_ip(msg->msg.jl.netif_addr), + ipX_2_ip(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, 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 +lwip_netconn_do_gethostbyname(void *arg) +{ + struct dns_api_msg *msg = (struct dns_api_msg*)arg; + + *msg->err = dns_gethostbyname(msg->name, msg->addr, lwip_netconn_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/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/err.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/err.c new file mode 100644 index 0000000..92fa8b7 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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 */ + "Address in use.", /* ERR_USE -8 */ + "Already connected.", /* ERR_ISCONN -9 */ + "Connection aborted.", /* ERR_ABRT -10 */ + "Connection reset.", /* ERR_RST -11 */ + "Connection closed.", /* ERR_CLSD -12 */ + "Not connected.", /* ERR_CONN -13 */ + "Illegal argument.", /* ERR_ARG -14 */ + "Low-level netif error.", /* ERR_IF -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/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/multi-threads/sockets_mt.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/multi-threads/sockets_mt.c new file mode 100644 index 0000000..64cea2b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/multi-threads/sockets_mt.c @@ -0,0 +1,829 @@ + +#ifdef SOCKETS_MT + +#ifndef LWIP_SYNC_MT_SLEEP_MS + #define LWIP_SYNC_MT_SLEEP_MS 10 +#endif + +#ifndef SOCK_MT_DEBUG_LEVEL +#define SOCK_MT_DEBUG_LEVEL 255 +#endif + +typedef int (*lwip_io_mt_fn)(int , int ); + +enum sock_mt_stat{ + SOCK_MT_STATE_NONE = 0, + SOCK_MT_STATE_BIND, + SOCK_MT_STATE_LISTEN, + SOCK_MT_STATE_ACCEPT, + SOCK_MT_STATE_CONNECT, + SOCK_MT_STATE_SEND, +}; + +enum sock_mt_shutdown { + SOCK_MT_SHUTDOWN_NONE = 0, + SOCK_MT_SHUTDOWN_OK +}; + +enum sock_mt_module { + SOCK_MT_STATE, + SOCK_MT_RECV, + SOCK_MT_IOCTL, + SOCK_MT_SELECT, + + SOCK_MT_SHUTDOWN, + + SOCK_MT_CLOSE, + + SOCK_MT_MODULE_MAX, +}; + +enum sock_mt_lock { + SOCK_MT_STATE_LOCK, + SOCK_MT_RECV_LOCK, + SOCK_MT_IOCTRL_LOCK, + + SOCK_MT_LOCK_MAX, +}; + +struct _sock_mt { + + enum sock_mt_shutdown shutdown; + + enum sock_mt_stat state; + + int sel; + + sys_mutex_t lock[SOCK_MT_LOCK_MAX]; +}; +typedef struct _sock_mt sock_mt_t; + +#if (SOCK_MT_DEBUG_LEVEL < 16) + #define SOCK_MT_DEBUG(level, ...) \ + if (level >= SOCK_MT_DEBUG_LEVEL) \ + os_printf(__VA_ARGS__); +#else + #define SOCK_MT_DEBUG(level, ...) +#endif + +#define SOCK_MT_LOCK(s, l) \ +{ \ + SOCK_MT_DEBUG(1, "s %d l %d enter ", s, l); \ + sys_mutex_lock(&sockets_mt[s].lock[l]); \ + SOCK_MT_DEBUG(1, "OK\n"); \ +} + +#define SOCK_MT_TRYLOCK(s, l, r) \ +{ \ + SOCK_MT_DEBUG(1, "s %d l %d try enter ", s, l); \ + r = sys_mutex_trylock(&sockets_mt[s].lock[l]); \ + SOCK_MT_DEBUG(1, "ret %d OK\n", r); \ +} + +#define SOCK_MT_UNLOCK(s, l) \ +{ \ + SOCK_MT_DEBUG(1, "s %d l %d exit ", s, l); \ + sys_mutex_unlock(&sockets_mt[s].lock[l]); \ + SOCK_MT_DEBUG(1, "OK\n"); \ +} + + +#define SOCK_MT_SET_STATE(s, stat) \ +{ \ + SYS_ARCH_DECL_PROTECT(lev); \ + SYS_ARCH_PROTECT(lev); \ + sockets_mt[s].state = stat; \ + SYS_ARCH_UNPROTECT(lev); \ +} + +#define SOCK_MT_GET_STATE(s) \ + sockets_mt[s].state + +#define SOCK_MT_SET_SHUTDOWN(s, d) \ +{ \ + SYS_ARCH_DECL_PROTECT(lev); \ + SYS_ARCH_PROTECT(lev); \ + sockets_mt[s].shutdown = d; \ + SYS_ARCH_UNPROTECT(lev); \ +} + +#define SOCK_MT_GET_SHUTDOWN(s) \ + sockets_mt[s].shutdown + +#define SOCK_MT_SET_WRITE_SEL(s) \ +{ \ + SYS_ARCH_DECL_PROTECT(lev); \ + SYS_ARCH_PROTECT(lev); \ + sockets_mt[s].sel |= 0x1; \ + SYS_ARCH_UNPROTECT(lev); \ +} + +#define SOCK_MT_RESET_WRITE_SEL(s) \ +{ \ + SYS_ARCH_DECL_PROTECT(lev); \ + SYS_ARCH_PROTECT(lev); \ + sockets_mt[s].sel &= ~0x1; \ + SYS_ARCH_UNPROTECT(lev); \ +} + +#define SOCK_MT_GET_WRITE_SEL(s) \ + (sockets_mt[s].sel & 0x01) + +#define SOCK_MT_SET_READ_SEL(s) \ +{ \ + SYS_ARCH_DECL_PROTECT(lev); \ + SYS_ARCH_PROTECT(lev); \ + sockets_mt[s].sel |= 0x2; \ + SYS_ARCH_UNPROTECT(lev); \ +} + +#define SOCK_MT_RESET_READ_SEL(s) \ +{ \ + SYS_ARCH_DECL_PROTECT(lev); \ + SYS_ARCH_PROTECT(lev); \ + sockets_mt[s].sel &= ~0x2; \ + SYS_ARCH_UNPROTECT(lev); \ +} + +#define SOCK_MT_GET_READ_SEL(s) \ + (sockets_mt[s].sel & 0x02) + +#define SOCK_MT_GET_SEL(s) \ + sockets_mt[s].sel + +#define SOCK_MT_SET_LINGER(sock) \ +{ \ + SYS_ARCH_DECL_PROTECT(lev); \ + SYS_ARCH_PROTECT(lev); \ + sock->conn->linger = 1; \ + SYS_ARCH_UNPROTECT(lev); \ +} + +#define LWIP_ENTER_MT(s, m, p) \ +{ \ + int r; \ + SOCK_MT_DEBUG(1, "enter s %d module %d args %d\n", s, m, p); \ + r = lwip_enter_mt_table[m](s, p); \ + SOCK_MT_DEBUG(1, "enter s %d ret %d\n", s, r); \ + if (r) \ + return -1; \ +} + +#define LWIP_EXIT_MT(s, m, p) \ +{ \ + int r; \ + SOCK_MT_DEBUG(1, "exit s %d module %d args %d\n", s, m, p); \ + r = lwip_exit_mt_table[m](s, p); \ + SOCK_MT_DEBUG(1, "exit s %d ret %d\n", s, r); \ + if (r) \ + return -1; \ +} + + +LOCAL sock_mt_t sockets_mt[NUM_SOCKETS]; + +LOCAL int lwip_enter_mt_state(int s, int arg) +{ + if(tryget_socket(s) == NULL || + SOCK_MT_GET_STATE(s) != SOCK_MT_STATE_NONE || + SOCK_MT_GET_WRITE_SEL(s)) + return -1; + + SOCK_MT_LOCK(s, SOCK_MT_STATE_LOCK); + if (SOCK_MT_GET_SHUTDOWN(s) != SOCK_MT_SHUTDOWN_NONE) { + goto failed; + } + SOCK_MT_SET_STATE(s, arg); + + return 0; + +failed: + SOCK_MT_UNLOCK(s, SOCK_MT_STATE_LOCK); + return -1; +} + +LOCAL int lwip_enter_mt_recv(int s, int arg) +{ + if(tryget_socket(s) == NULL || + SOCK_MT_GET_READ_SEL(s)) + return -1; + + SOCK_MT_LOCK(s, SOCK_MT_RECV_LOCK); + if (SOCK_MT_GET_SHUTDOWN(s) != SOCK_MT_SHUTDOWN_NONE) { + goto failed; + } + + return 0; + +failed: + SOCK_MT_UNLOCK(s, SOCK_MT_RECV_LOCK); + return -1; +} + +LOCAL int lwip_enter_mt_shutdown(int s, int arg) +{ + if(tryget_socket(s) == NULL) + return -1; + + SOCK_MT_SET_SHUTDOWN(s, SOCK_MT_SHUTDOWN_OK); + + return 0; +} + +LOCAL int lwip_enter_mt_close(int s, int arg) +{ + if(tryget_socket(s) == NULL) + return -1; + + SOCK_MT_SET_SHUTDOWN(s, SOCK_MT_SHUTDOWN_OK); + + return 0; +} + + +LOCAL int lwip_enter_mt_select(int s, int arg) +{ + int i; + int *fdset = (int *)arg; + fd_set *read_set = (fd_set *)fdset[0]; + fd_set *write_set = (fd_set *)fdset[1]; + + if (s > NUM_SOCKETS || s < 0) + return -1; + + for (i = 0; i < s; i++) { + if(FD_ISSET(i, read_set) || FD_ISSET(i, write_set)) + if (tryget_socket(i) == NULL) + goto failed1; + + if (FD_ISSET(i, read_set)) { + SOCK_MT_SET_READ_SEL(i); + SOCK_MT_LOCK(i, SOCK_MT_RECV_LOCK); + if (SOCK_MT_GET_SHUTDOWN(i) != SOCK_MT_SHUTDOWN_NONE) { + goto failed2; + } + } + + if (FD_ISSET(i, write_set)) { + SOCK_MT_SET_WRITE_SEL(i); + SOCK_MT_LOCK(i, SOCK_MT_STATE_LOCK); + if (SOCK_MT_GET_SHUTDOWN(i) != SOCK_MT_SHUTDOWN_NONE) { + goto failed3; + } + } + } + + return 0; + +failed3: + SOCK_MT_UNLOCK(i, SOCK_MT_STATE_LOCK); + SOCK_MT_RESET_WRITE_SEL(i); +failed2: + if (FD_ISSET(i, read_set)) { + SOCK_MT_UNLOCK(i, SOCK_MT_RECV_LOCK); + SOCK_MT_RESET_READ_SEL(i); + } +failed1: + for (i--; i >=0; i--) { + if (FD_ISSET(i, read_set) ){ + SOCK_MT_UNLOCK(i, SOCK_MT_RECV_LOCK); + SOCK_MT_RESET_READ_SEL(i); + } + + if (FD_ISSET(i, write_set)) { + SOCK_MT_UNLOCK(i, SOCK_MT_STATE_LOCK); + SOCK_MT_RESET_WRITE_SEL(i); + } + } + + return -1; +} + +LOCAL int lwip_enter_mt_ioctrl(int s, int arg) +{ + if(tryget_socket(s) == NULL) + return -1; + + SOCK_MT_LOCK(s, SOCK_MT_IOCTRL_LOCK); + if (SOCK_MT_GET_SHUTDOWN(s) != SOCK_MT_SHUTDOWN_NONE) { + goto failed; + } + + return 0; + +failed: + SOCK_MT_UNLOCK(s, SOCK_MT_IOCTRL_LOCK); + return -1; +} + +LOCAL int lwip_exit_mt_state(int s, int arg) +{ + SOCK_MT_SET_STATE(s, SOCK_MT_STATE_NONE); + SOCK_MT_UNLOCK(s, SOCK_MT_STATE_LOCK); + + if (SOCK_MT_GET_SHUTDOWN(s) != SOCK_MT_SHUTDOWN_NONE) { + return -1; + } + + return 0; +} + +LOCAL int lwip_exit_mt_recv(int s, int arg) +{ + SOCK_MT_UNLOCK(s, SOCK_MT_RECV_LOCK); + + if (SOCK_MT_GET_SHUTDOWN(s) != SOCK_MT_SHUTDOWN_NONE) { + return -1; + } + + return 0; +} + +LOCAL int lwip_exit_mt_shutdown(int s, int arg) +{ + SOCK_MT_SET_SHUTDOWN(s, SOCK_MT_STATE_NONE); + return 0; +} + +LOCAL int lwip_exit_mt_close(int s, int arg) +{ + return 0; +} + +LOCAL int lwip_exit_mt_select(int s, int arg) +{ + int i; + int *fdset = (int *)arg; + fd_set *read_set = (fd_set *)fdset[0]; + fd_set *write_set = (fd_set *)fdset[1]; + + for (i = 0; i < s; i++) { + if (FD_ISSET(i, read_set)) { + SOCK_MT_UNLOCK(i, SOCK_MT_RECV_LOCK); + SOCK_MT_RESET_READ_SEL(i); + } + + if (FD_ISSET(i, write_set)) { + SOCK_MT_UNLOCK(i, SOCK_MT_STATE_LOCK); + SOCK_MT_RESET_WRITE_SEL(i); + } + } + + for (i = 0; i < s; i++) { + if (SOCK_MT_GET_SHUTDOWN(i) != SOCK_MT_SHUTDOWN_NONE) { + return -1; + } + } + + return 0; +} + +LOCAL int lwip_exit_mt_ioctrl(int s, int arg) +{ + SOCK_MT_UNLOCK(s, SOCK_MT_IOCTRL_LOCK); + + if (SOCK_MT_GET_SHUTDOWN(s) != SOCK_MT_SHUTDOWN_NONE) { + return -1; + } + + return 0; +} + +LOCAL const ICACHE_RODATA_ATTR STORE_ATTR lwip_io_mt_fn lwip_enter_mt_table[] = { + lwip_enter_mt_state, + lwip_enter_mt_recv, + lwip_enter_mt_ioctrl, + lwip_enter_mt_select, + lwip_enter_mt_shutdown, + lwip_enter_mt_close +}; + +LOCAL const ICACHE_RODATA_ATTR STORE_ATTR lwip_io_mt_fn lwip_exit_mt_table[] = { + lwip_exit_mt_state, + lwip_exit_mt_recv, + lwip_exit_mt_ioctrl, + lwip_exit_mt_select, + lwip_exit_mt_shutdown, + lwip_exit_mt_close +}; + +LOCAL void lwip_sync_state_mt(struct lwip_sock *sock , int state) +{ + SOCK_MT_DEBUG(1, "sync state %d\n", state); + + switch (state) { + case SOCK_MT_STATE_ACCEPT : + if (sys_mbox_valid(&sock->conn->acceptmbox)) + sys_mbox_trypost(&sock->conn->acceptmbox, NULL); + break; + case SOCK_MT_STATE_SEND : + { + SYS_ARCH_DECL_PROTECT(lev); + SYS_ARCH_PROTECT(lev); + if (sock->conn->current_msg) { + sock->conn->current_msg->err = ERR_OK; + sock->conn->current_msg = NULL; + } + sock->conn->state = NETCONN_NONE; + SYS_ARCH_UNPROTECT(lev); + if (sys_sem_valid(&(sock->conn->snd_op_completed))) + sys_sem_signal(&(sock->conn->snd_op_completed)); + break; + } + case SOCK_MT_STATE_CONNECT : + if (sys_sem_valid(&(sock->conn->op_completed))) + sys_sem_signal(&(sock->conn->op_completed)); + break; + default : + break; + } +} + +LOCAL void lwip_sync_recv_mt(struct lwip_sock *sock) +{ + SOCK_MT_DEBUG(1, "sync recv %d\n", sock->conn->socket); + if (sys_mbox_valid(&sock->conn->recvmbox)) + sys_mbox_trypost(&sock->conn->recvmbox, NULL); +} + +LOCAL void lwip_sync_select_mt(struct lwip_sock *sock) +{ + SOCK_MT_DEBUG(1, "sync select %d\n", sock->conn->socket); + event_callback(sock->conn, NETCONN_EVT_ERROR, 0); +} + + +LOCAL void lwip_sync_mt(int s) +{ + int module = 0; + int ret; + + while (module < SOCK_MT_SELECT) { + extern void sys_arch_msleep(int ms); + int ret; + struct lwip_sock *sock; + + SOCK_MT_TRYLOCK(s, module, ret); + if (ret == ERR_OK) { + SOCK_MT_UNLOCK(s, module); + module++; + continue; + } + + sock = get_socket(s); +#if LWIP_SO_LINGER + if (SOCK_MT_GET_STATE(s) == SOCK_MT_STATE_SEND) { + SOCK_MT_SET_LINGER(sock); + } +#endif + if (!SOCK_MT_GET_SEL(s)) { + switch (module) { + case SOCK_MT_STATE: + lwip_sync_state_mt(sock, SOCK_MT_GET_STATE(s)); + break; + case SOCK_MT_RECV: + lwip_sync_recv_mt(sock); + break; + default : + break; + } + } else { + lwip_sync_select_mt(sock); + } + + sys_arch_msleep(LWIP_SYNC_MT_SLEEP_MS); + } +} + +int lwip_socket_mt(int domain, int type, int protocol) +{ + int s; + int i; + + s = lwip_socket(domain, type, protocol); + if (s < 0) + return -1; + + for (i = 0; i < SOCK_MT_LOCK_MAX; i++) { + if (sys_mutex_new(&sockets_mt[s].lock[i]) != ERR_OK) + break; + } + if (i < SOCK_MT_LOCK_MAX) { + for (i-- ; i >= 0; i--) { + sys_mutex_free(&sockets_mt[s].lock[i]); + sockets_mt[s].lock[i] = NULL; + } + + lwip_close(s); + s = -1; + } + + if (s >= 0) + SOCK_MT_SET_SHUTDOWN(s, SOCK_MT_SHUTDOWN_NONE); + + return s; +} + +int lwip_bind_mt(int s, const struct sockaddr *name, socklen_t namelen) +{ + int ret; + + LWIP_ENTER_MT(s, SOCK_MT_STATE, SOCK_MT_STATE_BIND); + + ret = lwip_bind(s, name, namelen); + + LWIP_EXIT_MT(s, SOCK_MT_STATE, SOCK_MT_STATE_BIND); + + + return ret; +} + +int lwip_connect_mt(int s, const struct sockaddr *name, socklen_t namelen) +{ + int ret; + + LWIP_ENTER_MT(s, SOCK_MT_STATE, SOCK_MT_STATE_CONNECT); + + ret = lwip_connect(s, name, namelen); + + LWIP_EXIT_MT(s, SOCK_MT_STATE, SOCK_MT_STATE_CONNECT); + + return ret; +} + +int lwip_listen_mt(int s, int backlog) +{ + int ret; + + LWIP_ENTER_MT(s, SOCK_MT_STATE, SOCK_MT_STATE_LISTEN); + + ret = lwip_listen(s, backlog); + + LWIP_EXIT_MT(s, SOCK_MT_STATE, SOCK_MT_STATE_LISTEN); + + return ret; +} + +int lwip_accept_mt(int s, struct sockaddr *addr, socklen_t *addrlen) +{ + int i; + int ret; + + LWIP_ENTER_MT(s, SOCK_MT_STATE, SOCK_MT_STATE_ACCEPT) + + ret = lwip_accept(s, addr, addrlen); + + LWIP_EXIT_MT(s, SOCK_MT_STATE, SOCK_MT_STATE_ACCEPT); + + if (ret < 0) + return -1; + + for (i = 0; i < SOCK_MT_LOCK_MAX; i++) { + if (sys_mutex_new(&sockets_mt[ret].lock[i]) != ERR_OK) + break; + } + if (i < SOCK_MT_LOCK_MAX) { + for (i-- ; i >= 0; i--) { + sys_mutex_free(&sockets_mt[ret].lock[i]); + sockets_mt[ret].lock[i] = NULL; + } + + lwip_close(ret); + ret = -1; + } + + if (ret >= 0) + SOCK_MT_SET_SHUTDOWN(ret, SOCK_MT_SHUTDOWN_NONE); + + return ret; +} + +int lwip_getpeername_mt(int s, struct sockaddr *name, socklen_t *namelen) +{ + int ret; + + LWIP_ENTER_MT(s, SOCK_MT_IOCTL, 0); + + ret = lwip_getpeername(s, name, namelen); + + LWIP_EXIT_MT(s, SOCK_MT_IOCTL, 0); + + return ret; +} + +int lwip_getsockname_mt(int s, struct sockaddr *name, socklen_t *namelen) +{ + int ret; + + LWIP_ENTER_MT(s, SOCK_MT_IOCTL, 0); + + ret = lwip_getsockname(s, name, namelen); + + LWIP_EXIT_MT(s, SOCK_MT_IOCTL, 0); + + return ret; +} + +int lwip_setsockopt_mt(int s, int level, int optname, const void *optval, socklen_t optlen) +{ + int ret; + + LWIP_ENTER_MT(s, SOCK_MT_IOCTL, 0); + + ret = lwip_setsockopt(s, level, optname, optval, optlen); + + LWIP_EXIT_MT(s, SOCK_MT_IOCTL, 0); + + return ret; +} + +int lwip_getsockopt_mt(int s, int level, int optname, void *optval, socklen_t *optlen) +{ + int ret; + + if (optname == SO_ERROR ) { + int retval = 0; + + if (SOCK_MT_GET_SHUTDOWN(s) != SOCK_MT_SHUTDOWN_NONE) + retval = ENOTCONN; + + if (retval) { + *(int *)optval = retval; + return 0; + } + } + + LWIP_ENTER_MT(s, SOCK_MT_IOCTL, 0); + + ret = lwip_getsockopt(s, level, optname, optval, optlen); + + LWIP_EXIT_MT(s, SOCK_MT_IOCTL, 0); + + return ret; +} + +int lwip_ioctl_mt(int s, long cmd, void *argp) +{ + int ret; + + LWIP_ENTER_MT(s, SOCK_MT_IOCTL, 0) + + ret = lwip_ioctl(s, cmd, argp); + + LWIP_EXIT_MT(s, SOCK_MT_IOCTL, 0); + + return ret; +} + +int lwip_sendto_mt(int s, const void *data, size_t size, int flags, + const struct sockaddr *to, socklen_t tolen) +{ + int ret; + + LWIP_ENTER_MT(s, SOCK_MT_STATE, SOCK_MT_STATE_SEND); + + ret = lwip_sendto(s, data, size, flags, to, tolen); + + LWIP_EXIT_MT(s, SOCK_MT_STATE, SOCK_MT_STATE_SEND); + + return ret; +} + +int lwip_send_mt(int s, const void *data, size_t size, int flags) +{ + int ret; + + LWIP_ENTER_MT(s, SOCK_MT_STATE, SOCK_MT_STATE_SEND); + + ret = lwip_send(s, data, size, flags); + + LWIP_EXIT_MT(s, SOCK_MT_STATE, SOCK_MT_STATE_SEND); + + return ret; +} + +int lwip_recvfrom_mt(int s, void *mem, size_t len, int flags, + struct sockaddr *from, socklen_t *fromlen) +{ + int ret; + + LWIP_ENTER_MT(s, SOCK_MT_RECV, 0); + + ret = lwip_recvfrom(s, mem, len, flags, from, fromlen); + + LWIP_EXIT_MT(s, SOCK_MT_RECV, 0); + + return ret; +} + +int lwip_recv_mt(int s, void *mem, size_t len, int flags) +{ + return lwip_recvfrom_mt(s, mem, len, flags, NULL, NULL); +} + +int lwip_read_mt(int s, void *mem, size_t len) +{ + return lwip_recvfrom_mt(s, mem, len, 0, NULL, NULL); +} + +int lwip_write_mt(int s, const void *data, size_t size) +{ + return lwip_send_mt(s, data, size, 0); +} + +int lwip_fcntl_mt(int s, int cmd, int val) +{ + int ret; + + LWIP_ENTER_MT(s, SOCK_MT_IOCTL, 0); + + ret = lwip_fcntl(s, cmd, val); + + LWIP_EXIT_MT(s, SOCK_MT_IOCTL, 0); + + return ret; +} + +int lwip_shutdown_mt(int s, int how) +{ + int ret; + + LWIP_ENTER_MT(s, SOCK_MT_SHUTDOWN, 0); + + lwip_sync_mt(s); + + ret = lwip_shutdown(s, how); + + LWIP_EXIT_MT(s, SOCK_MT_SHUTDOWN, 0); + + return ret; +} + +int lwip_close_mt(int s) +{ + int ret; + int i; + + lwip_shutdown_mt(s, SHUT_RDWR); + + LWIP_ENTER_MT(s, SOCK_MT_CLOSE, 0); + + ret = lwip_close(s); + + LWIP_EXIT_MT(s, SOCK_MT_CLOSE, 0); + + for (i = 0 ; i < SOCK_MT_LOCK_MAX; i++) { + sys_mutex_free(&sockets_mt[s].lock[i]); + sockets_mt[s].lock[i] = NULL; + } + + return ret; +} + +int lwip_select_mt(int maxfdp1, fd_set *readset, fd_set *writeset, + fd_set *exceptset, struct timeval *timeout) +{ + int ret; + fd_set read_set, write_set; + int pset[2] = {(int)&read_set, (int)&write_set}; + + FD_ZERO(&read_set); + FD_ZERO(&write_set); + + if (readset) + MEMCPY(&read_set, readset, sizeof(fd_set)); + + if (writeset) + MEMCPY(&write_set, writeset, sizeof(fd_set)); + + LWIP_ENTER_MT(maxfdp1, SOCK_MT_SELECT, (int)pset); + + ret = lwip_select(maxfdp1, readset, writeset, exceptset, timeout); + + LWIP_EXIT_MT(maxfdp1, SOCK_MT_SELECT, (int)pset); + + return ret; +} + +#ifdef SOCKETS_TCP_TRACE + +int lwip_trace_tcp(int s, int cmd, void *arg) +{ + struct lwip_sock *sock; + u32_t *pbuf = (u32_t *)arg; + + if (!(sock = tryget_socket(s))) + return -1; + + ADD_TCP_SEND_BYTES_GET(sock->conn, &pbuf[0]); + ADD_TCP_SEND_BYTES_OK_GET(sock->conn, &pbuf[2]); + ADD_TCP_SEND_BYTES_NOMEM_GET(sock->conn, &pbuf[4]); + + ADD_TCP_RECV_BYTES_GET(sock->conn, &pbuf[6]); + ADD_TCP_RECV_BYTES_ERR_GET(sock->conn, &pbuf[8]); + + return 0; +} +#endif + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/netbuf.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/netbuf.c new file mode 100644 index 0000000..1ea970b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/netbuf.c @@ -0,0 +1,249 @@ +/** + * @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 + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +/** + * Create (allocate) and initialize a new netbuf. + * The netbuf doesn't yet contain a packet buffer! + * + * @return a pointer to a new netbuf + * NULL on lack of memory + */ +struct +netbuf *netbuf_new(void) +{ + struct netbuf *buf; + + buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); + if (buf != NULL) { + buf->p = NULL; + buf->ptr = NULL; + ipX_addr_set_any(LWIP_IPV6, &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 + ipX_addr_set_any(LWIP_IPV6, &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(). + * + * @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. + * + * @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 + * + * @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/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/netdb.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/netdb.c new file mode 100644 index 0000000..5ba6a7a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/netdb.c @@ -0,0 +1,357 @@ +/** + * @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 + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +/** 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]; + + /* 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 == 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 + */ +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/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/netifapi.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/netifapi.c new file mode 100644 index 0000000..81403f8 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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. + */ +static void +netifapi_do_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. + */ +static void +netifapi_do_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. + */ +static void +netifapi_do_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 = netifapi_do_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 = netifapi_do_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 = netifapi_do_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/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/sockets.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/sockets.c new file mode 100644 index 0000000..a699b83 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/sockets.c @@ -0,0 +1,2711 @@ +/** + * @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/api.h" +#include "lwip/sockets.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 + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +#define IP4ADDR_PORT_TO_SOCKADDR(sin, ipXaddr, port) do { \ + (sin)->sin_len = sizeof(struct sockaddr_in); \ + (sin)->sin_family = AF_INET; \ + (sin)->sin_port = htons((port)); \ + inet_addr_from_ipaddr(&(sin)->sin_addr, ipX_2_ip(ipXaddr)); \ + memset((sin)->sin_zero, 0, SIN_ZERO_LEN); }while(0) +#define SOCKADDR4_TO_IP4ADDR_PORT(sin, ipXaddr, port) do { \ + inet_addr_to_ipaddr(ipX_2_ip(ipXaddr), &((sin)->sin_addr)); \ + (port) = ntohs((sin)->sin_port); }while(0) + +#if LWIP_IPV6 +#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 IP6ADDR_PORT_TO_SOCKADDR(sin6, ipXaddr, port) do { \ + (sin6)->sin6_len = sizeof(struct sockaddr_in6); \ + (sin6)->sin6_family = AF_INET6; \ + (sin6)->sin6_port = htons((port)); \ + (sin6)->sin6_flowinfo = 0; \ + inet6_addr_from_ip6addr(&(sin6)->sin6_addr, ipX_2_ip6(ipXaddr)); }while(0) +#define IPXADDR_PORT_TO_SOCKADDR(isipv6, sockaddr, ipXaddr, port) do { \ + if (isipv6) { \ + IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ipXaddr, port); \ + } else { \ + IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ipXaddr, port); \ + } } while(0) +#define SOCKADDR6_TO_IP6ADDR_PORT(sin6, ipXaddr, port) do { \ + inet6_addr_to_ip6addr(ipX_2_ip6(ipXaddr), &((sin6)->sin6_addr)); \ + (port) = ntohs((sin6)->sin6_port); }while(0) +#define SOCKADDR_TO_IPXADDR_PORT(isipv6, sockaddr, ipXaddr, port) do { \ + if (isipv6) { \ + SOCKADDR6_TO_IP6ADDR_PORT((struct sockaddr_in6*)(void*)(sockaddr), ipXaddr, port); \ + } else { \ + SOCKADDR4_TO_IP4ADDR_PORT((struct sockaddr_in*)(void*)(sockaddr), ipXaddr, port); \ + } } while(0) +#define DOMAIN_TO_NETCONN_TYPE(domain, type) (((domain) == AF_INET) ? \ + (type) : (enum netconn_type)((type) | NETCONN_TYPE_IPV6)) +#else /* 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 IPXADDR_PORT_TO_SOCKADDR(isipv6, sockaddr, ipXaddr, port) \ + IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ipXaddr, port) +#define SOCKADDR_TO_IPXADDR_PORT(isipv6, sockaddr, ipXaddr, port) \ + SOCKADDR4_TO_IP4ADDR_PORT((struct sockaddr_in*)(void*)(sockaddr), ipXaddr, 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 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; +}; + +/** 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 */ + struct sockaddr_in sin; +}; + +/** 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[] ICACHE_RODATA_ATTR STORE_ATTR = { + 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. */ +#ifdef LWIP_ESP8266 + EALREADY, /* ERR_ALREADY -9 Already connected. */ + EISCONN, /* ERR_ISCONN -10 Conn already established */ + ECONNABORTED, /* ERR_ABRT -11 Connection aborted. */ + ECONNRESET, /* ERR_RST -12 Connection reset. */ + ENOTCONN, /* ERR_CLSD -13 Connection closed. */ + ENOTCONN, /* ERR_CONN -14 Not connected. */ + EIO, /* ERR_ARG -15 Illegal argument. */ + -1, /* ERR_IF -16 Low-level netif error */ +#else + EALREADY, /* ERR_ISCONN -9 Already connected. */ + ECONNABORTED, /* ERR_ABRT -10 Connection aborted. */ + ECONNRESET, /* ERR_RST -11 Connection reset. */ + ENOTCONN, /* ERR_CLSD -12 Connection closed. */ + ENOTCONN, /* ERR_CONN -13 Not connected. */ + EIO, /* ERR_ARG -14 Illegal argument. */ + -1, /* ERR_IF -15 Low-level netif error */ +#endif +}; + +#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 = (NETCONNTYPE_GROUP(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; + ipX_addr_t naddr; + u16_t port = 0; + int newsock; + err_t err; + SYS_ARCH_DECL_PROTECT(lev); + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s)); + sock = get_socket(s); + if (!sock) { + return -1; + } + + if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s)); + sock_set_errno(sock, EWOULDBLOCK); + return -1; + } + + /* wait for a new connection */ + err = netconn_accept(sock->conn, &newconn); + if (err != ERR_OK) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err)); + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { + sock_set_errno(sock, EOPNOTSUPP); + return EOPNOTSUPP; + } + 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); + + //***********Code for WIFI_BLOCK from upper************** + (newconn)->flags &= ~ NETCONN_FLAG_RECV_HOLD; + + /* 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, ipX_2_ip(&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; + } + LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL); + + IPXADDR_PORT_TO_SOCKADDR(NETCONNTYPE_ISIPV6(newconn->type), &tempaddr, &naddr, port); + if (*addrlen > tempaddr.sa.sa_len) { + *addrlen = tempaddr.sa.sa_len; + } + MEMCPY(addr, &tempaddr, *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", s, newsock)); + if (addr != NULL) { + LWIP_DEBUGF(SOCKETS_DEBUG, (" addr=")); + ipX_addr_debug_print(NETCONNTYPE_ISIPV6(newconn->type), 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; + ipX_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, familiy 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_IPXADDR_PORT((name->sa_family == AF_INET6), name, &local_addr, local_port); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s)); + ipX_addr_debug_print(name->sa_family == AF_INET6, SOCKETS_DEBUG, &local_addr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port)); + + err = netconn_bind(sock->conn, ipX_2_ip(&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; + + 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); + } + + 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; + + 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; + } + + /* check size, familiy 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;); + 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 { + ipX_addr_t remote_addr; + u16_t remote_port; + SOCKADDR_TO_IPXADDR_PORT((name->sa_family == AF_INET6), name, &remote_addr, remote_port); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s)); + ipX_addr_debug_print(name->sa_family == AF_INET6, SOCKETS_DEBUG, &remote_addr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", remote_port)); + + err = netconn_connect(sock->conn, ipX_2_ip(&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 EOPNOTSUPP; + } + sock_set_errno(sock, err_to_errno(err)); + return -1; + } + + sock_set_errno(sock, 0); + return 0; +} + +int +lwip_recvhold(int s) +{ + struct lwip_sock *sock; + sock = get_socket(s); + + if (!sock) { + return -1; + } + + if(sock->conn == NULL) { + return -2; + } + + if(NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP || (sock->conn->pcb.tcp == NULL)) { + return -3; + } + + if(((sock->conn)->flags & NETCONN_FLAG_RECV_HOLD) == 0) { + (sock->conn)->flags |= NETCONN_FLAG_RECV_HOLD; + //(sock->conn)->recv_holded_buf_Len = 0; + } + + return 0; +} + +int +lwip_recvunhold(int s) +{ + struct lwip_sock *sock; + sock = get_socket(s); + + if (!sock) { + return -1; + } + + if(sock->conn == NULL) { + return -2; + } + + if(NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP || (sock->conn->pcb.tcp == NULL)) { + return -3; + } + + if(((sock->conn)->flags & NETCONN_FLAG_RECV_HOLD) != 0) { + u32_t remaining = (sock->conn)->recv_holded_buf_Len; + while(remaining > 0) { + u16_t recved = (remaining > 0xffff) ? 0xffff : (u16_t)remaining; + + if(sock->conn->pcb.tcp != NULL) { + tcp_recved(sock->conn->pcb.tcp, recved); + } else { + break; + } + + remaining -= recved; + } + + (sock->conn)->recv_holded_buf_Len = 0; + (sock->conn)->flags &= ~ NETCONN_FLAG_RECV_HOLD; + } + + 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) { + /* 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 (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) { + /* 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 (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; + ipX_addr_t tmpaddr; + ipX_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; + /* @todo: this does not work for IPv6, yet */ + netconn_getaddr(sock->conn, ipX_2_ip(fromaddr), &port, 0); + } else { + port = netbuf_fromport((struct netbuf *)buf); + fromaddr = netbuf_fromaddr_ipX((struct netbuf *)buf); + } + IPXADDR_PORT_TO_SOCKADDR(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), + &saddr, fromaddr, port); + ipX_addr_debug_print(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), + 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); + } else { + /*fix the code for setting the UDP PROTO's remote infomation by liuh at 2014.8.27*/ + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_UDP){ +#if LWIP_IPV6 + sock->conn->pcb.udp->remote_ip.ip4.addr = fromaddr->ip4.addr; +#else + sock->conn->pcb.udp->remote_ip.addr = fromaddr->addr; +#endif + sock->conn->pcb.udp->remote_port = port; + } + } + } + } + + /* 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); + } + } + } + } while (!done); + + if ((off > 0) && (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP)) { + /* 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; + 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) + int ret; + ret = lwip_sendto(s, data, size, flags, NULL, 0); + return ret; +#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_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; +#if !LWIP_TCPIP_CORE_LOCKING + struct netbuf buf; +#endif + + sock = get_socket(s); + if (!sock) { + return -1; + } + + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { +#if LWIP_TCP + return lwip_send(s, data, size, flags); +#else /* LWIP_TCP */ + LWIP_UNUSED_ARG(flags); + sock_set_errno(sock, err_to_errno(ERR_ARG)); + return -1; +#endif /* LWIP_TCP */ + } + + if ((to != NULL) && !SOCK_ADDR_TYPE_MATCH(to, sock)) { + /* sockaddr does not match socket type (IPv4/IPv6) */ + sock_set_errno(sock, err_to_errno(ERR_VAL)); + return -1; + } + + /* @todo: split into multiple sendto's? */ + LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff); + short_size = (u16_t)size; + LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) || + (IS_SOCK_ADDR_LEN_VALID(tolen) && + IS_SOCK_ADDR_TYPE_VALID(to) && IS_SOCK_ADDR_ALIGNED(to))), + sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); + LWIP_UNUSED_ARG(tolen); + +#if LWIP_TCPIP_CORE_LOCKING + /* Special speedup for fast UDP/RAW sending: call the raw API directly + instead of using the netconn functions. */ + { + struct pbuf* p; + ipX_addr_t *remote_addr; + ipX_addr_t remote_addr_tmp; + +#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 (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != 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 != NULL) { + SOCKADDR_TO_IPXADDR_PORT(to->sa_family == AF_INET6, + to, &remote_addr_tmp, remote_port); + remote_addr = &remote_addr_tmp; + } else { + remote_addr = &sock->conn->pcb.ip->remote_ip; +#if LWIP_UDP + if (NETCONNTYPE_GROUP(sock->conn->type) == NETCONN_UDP) { + remote_port = sock->conn->pcb.udp->remote_port; + } else +#endif /* LWIP_UDP */ + { + remote_port = 0; + } + } + + LOCK_TCPIP_CORE(); + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_RAW) { +#if LWIP_RAW + err = sock->conn->last_err = raw_sendto(sock->conn->pcb.raw, p, ipX_2_ip(remote_addr)); +#else /* LWIP_RAW */ + err = ERR_ARG; +#endif /* LWIP_RAW */ + } +#if LWIP_UDP && LWIP_RAW + else +#endif /* LWIP_UDP && LWIP_RAW */ + { +#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, + ipX_2_ip(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, + ipX_2_ip(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) { + SOCKADDR_TO_IPXADDR_PORT((to->sa_family) == AF_INET6, to, &buf.addr, remote_port); + } else { + /*fix the code for getting the UDP proto's remote information by liuh at 2014.8.27*/ +// ipX_addr_set_any(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), &buf.addr); + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_UDP){ +#if LWIP_IPV6 + buf.addr.ip4.addr = sock->conn->pcb.udp->remote_ip.ip4.addr; +#else + buf.addr.addr = sock->conn->pcb.udp->remote_ip.addr; +#endif + remote_port = sock->conn->pcb.udp->remote_port; + } else { + remote_port = 0; + ipX_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)); + ipX_addr_debug_print(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), + 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); + 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; + +#if !LWIP_IPV6 + LWIP_UNUSED_ARG(domain); /* @todo: check this */ +#endif /* LWIP_IPV6 */ + + /* create a netconn */ + switch (type) { + case SOCK_RAW: + conn = netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_RAW), + (u8_t)protocol, event_callback); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", + domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); + break; + case SOCK_DGRAM: + conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, + ((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP)) , + event_callback); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ", + domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); + break; + case SOCK_STREAM: + conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_TCP), event_callback); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ", + domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); + if (conn != NULL) { + /* Prevent automatic window updates, we do this on our own! */ + netconn_set_noautorecved(conn, 1); + + //***********Code for WIFI_BLOCK from upper************** + (conn)->flags &= ~ NETCONN_FLAG_RECV_HOLD; + } + 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) +{ +#ifndef LWIP_ESP8266 + 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 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); +#else + return ERR_OK; +#endif +} + +static int +lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) +{ + struct lwip_sock *sock; + union sockaddr_aligned saddr; + ipX_addr_t naddr; + u16_t port; + + sock = get_socket(s); + if (!sock) { + return -1; + } + + /* get the IP address and port */ + /* @todo: this does not work for IPv6, yet */ + netconn_getaddr(sock->conn, ipX_2_ip(&naddr), &port, local); + IPXADDR_PORT_TO_SOCKADDR(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), + &saddr, &naddr, port); + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s)); + ipX_addr_debug_print(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), + 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) +{ + 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: */ +#if LWIP_SO_SNDTIMEO + case SO_SNDTIMEO: +#endif /* LWIP_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 (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != 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; +#if LWIP_SO_LINGER + case SO_LINGER: + { + s16_t conn_linger; + struct linger* linger = (struct linger*)optval; + 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 */ + + 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(netconn_type(sock->conn)) != 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 (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != 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_IPV6 +/* Level: IPPROTO_IPV6 */ + case IPPROTO_IPV6: + switch (optname) { + case IPV6_V6ONLY: + if (*optlen < sizeof(int)) { + err = EINVAL; + } + /* @todo: this does not work for datagram sockets, yet */ + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) + return 0; + break; + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + } /* switch (optname) */ + break; +#endif /* LWIP_IPV6 */ + +#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 (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) { + 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->ioctrl_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 = 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: + 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: + /* 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_SNDTIMEO + case SO_SNDTIMEO: + *(int *)optval = netconn_get_sendtimeout(sock->conn); + break; +#endif /* LWIP_SO_SNDTIMEO */ +#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_IPV6 +/* Level: IPPROTO_IPV6 */ + case IPPROTO_IPV6: + switch (optname) { + case IPV6_V6ONLY: + *(int*)optval = ((sock->conn->flags & NETCONN_FLAG_IPV6_V6ONLY) ? 1 : 0); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY) = %d\n", + s, *(int *)optval)); + break; + default: + LWIP_ASSERT("unhandled optname", 0); + break; + } /* switch (optname) */ + break; +#endif /* LWIP_IPV6 */ + +#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->ioctrl_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: */ +#if LWIP_SO_SNDTIMEO + case SO_SNDTIMEO: +#endif /* LWIP_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 ((NETCONNTYPE_GROUP(netconn_type(sock->conn)) != 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; +#if LWIP_SO_LINGER + case SO_LINGER: + { + const struct linger* linger = (const struct linger*)optval; + 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 */ + + 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(netconn_type(sock->conn)) != NETCONN_UDP) { + err = EAFNOSUPPORT; + } + break; + case IP_MULTICAST_IF: + if (optlen < sizeof(struct in_addr)) { + err = EINVAL; + } + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { + err = EAFNOSUPPORT; + } + break; + case IP_MULTICAST_LOOP: + if (optlen < sizeof(u8_t)) { + err = EINVAL; + } + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { + err = EAFNOSUPPORT; + } + break; + case IP_ADD_MEMBERSHIP: + case IP_DROP_MEMBERSHIP: + if (optlen < sizeof(struct ip_mreq)) { + err = EINVAL; + } + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != 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 (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != 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_IPV6 +/* Level: IPPROTO_IPV6 */ + case IPPROTO_IPV6: + switch (optname) { + case IPV6_V6ONLY: + if (optlen < sizeof(int)) { + err = EINVAL; + } + + /* @todo: this does not work for datagram sockets, yet */ + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) + return 0; + + break; + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + } /* switch (optname) */ + break; +#endif /* LWIP_IPV6 */ + +#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 (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) + 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->ioctrl_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) { + 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, (*(int*)optval?"on":"off"))); + break; +#if LWIP_SO_SNDTIMEO + case SO_SNDTIMEO: + netconn_set_sendtimeout(sock->conn, (s32_t)*(int*)optval); + break; +#endif /* LWIP_SO_SNDTIMEO */ +#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_IPV6 +/* Level: IPPROTO_IPV6 */ + case IPPROTO_IPV6: + switch (optname) { + case IPV6_V6ONLY: + if (*(int*)optval) { + sock->conn->flags |= NETCONN_FLAG_IPV6_V6ONLY; + } else { + sock->conn->flags &= ~NETCONN_FLAG_IPV6_V6ONLY; + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY, ..) -> %d\n", + s, ((sock->conn->flags & NETCONN_FLAG_IPV6_V6ONLY) ? 1 : 0))); + break; + default: + LWIP_ASSERT("unhandled optname", 0); + break; + } /* switch (optname) */ + break; +#endif /* LWIP_IPV6 */ + +#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->ioctrl_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 || 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; + } else { + struct netbuf *rxbuf; + err_t err; + if (sock->rcvevent <= 0) { + *((u16_t*)argp) = 0; + } else { + err = netconn_recv(sock->conn, &rxbuf); + if (err != ERR_OK) { + *((u16_t*)argp) = 0; + } else { + sock->lastdata = rxbuf; + *((u16_t*)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; + } + *((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 (NETCONNTYPE_GROUP(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; +#else /* LWIP_SO_RCVBUF */ + break; +#endif /* LWIP_SO_RCVBUF */ +#endif /* LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE */ + + 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: + 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 || !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; +} + +#include "multi-threads/sockets_mt.c" + +#endif /* LWIP_SOCKET */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/tcpip.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/tcpip.c new file mode 100644 index 0000000..53a9f2e --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/api/tcpip.c @@ -0,0 +1,527 @@ +/** + * @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" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +/* global variables */ +static tcpip_init_done_fn tcpip_init_done; +static void *tcpip_init_done_arg; +static sys_mbox_t mbox; +sys_thread_t xLwipTaskHandle; + +#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: + 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(msg->msg.inp.p != NULL && msg->msg.inp.netif != NULL) { +#if LWIP_ETHERNET + if (msg->msg.inp.netif->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) { + ethernet_input(msg->msg.inp.p, msg->msg.inp.netif); + } else +#endif /* LWIP_ETHERNET */ +#if LWIP_IPV6 + if ((*((unsigned char *)(msg->msg.inp.p->payload)) & 0xf0) == 0x60) { + ip6_input(msg->msg.inp.p, msg->msg.inp.netif); + } else +#endif /* LWIP_IPV6 */ + { + ip_input(msg->msg.inp.p, msg->msg.inp.netif); + } + } + 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 */ + +#if LWIP_TCPIP_TIMEOUT + case TCPIP_MSG_TIMEOUT: + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg)); + sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg); + memp_free(MEMP_TCPIP_MSG_API, msg); + break; + case TCPIP_MSG_UNTIMEOUT: + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg)); + sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg); + memp_free(MEMP_TCPIP_MSG_API, msg); + break; +#endif /* LWIP_TCPIP_TIMEOUT */ + + case TCPIP_MSG_CALLBACK: + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg)); + msg->msg.cb.function(msg->msg.cb.ctx); + memp_free(MEMP_TCPIP_MSG_API, msg); + break; + + case TCPIP_MSG_CALLBACK_STATIC: + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK_STATIC %p\n", (void *)msg)); + msg->msg.cb.function(msg->msg.cb.ctx); + break; + + default: + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type)); + LWIP_ASSERT("tcpip_thread: invalid message", 0); + break; + } + } +} + +/** + * Pass a received packet to tcpip_thread for input processing + * + * @param p the received packet, 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)) { + return ERR_VAL; + } + 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; +#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 + */ +//static sys_mutex_t ApiMsgMutex = NULL; + +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; + +if(apimsg->function == lwip_netconn_do_write) +{ + sys_mbox_post(&mbox, &msg); + sys_arch_sem_wait(&apimsg->msg.conn->snd_op_completed, 0); +} +else +{ +//sys_mutex_lock(&ApiMsgMutex); + + sys_mbox_post(&mbox, &msg); + sys_arch_sem_wait(&apimsg->msg.conn->op_completed, 0); + +//sys_mutex_unlock(&ApiMsgMutex); +} + + return apimsg->msg.err; + } + return ERR_VAL; +} + +#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 */ + +/** + * 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) +{ + if (!sys_mbox_valid(&mbox)) { + return ERR_VAL; + } + return sys_mbox_trypost(&mbox, msg); +} + +/** + * 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_mutex_new(&ApiMsgMutex); +//if(ApiMsgMutex==NULL) +// os_printf("ApiMsgMutex create fail\n"); +//else +// os_printf("ApiMsgMutex created\n"); + + xLwipTaskHandle = 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 + */ +static void mem_free_local(void *arg) +{ + mem_free(arg); +} + +err_t +mem_free_callback(void *m) +{ + return tcpip_callback_with_block(mem_free_local, m, 0); +} + +#endif /* !NO_SYS */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/apps/Makefile b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/apps/Makefile new file mode 100644 index 0000000..ba6caca --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/apps/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 = liblwipapps.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/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/apps/sntp.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/apps/sntp.c new file mode 100644 index 0000000..14c35b5 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/apps/sntp.c @@ -0,0 +1,717 @@ +/** + * @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? + */ + +/* + * 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 + */ + +#include "apps/sntp.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/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 +#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 operating mode */ +static u8_t sntp_opmode; + +/** The UDP pcb used by the SNTP client */ +static struct udp_pcb* sntp_pcb; +/** Names/Addresses of servers */ +struct sntp_server { +#if SNTP_SERVER_DNS + char* name; +#endif /* SNTP_SERVER_DNS */ + ip_addr_t addr; +}; +static struct sntp_server sntp_servers[SNTP_MAX_SERVERS]; + +#if SNTP_GET_SERVERS_FROM_DHCP +static u8_t sntp_set_servers_from_dhcp; +#endif /* SNTP_GET_SERVERS_FROM_DHCP */ +#if SNTP_SUPPORT_MULTIPLE_SERVERS +/** The currently used server (initialized to 0) */ +static u8_t sntp_current_server; +#else /* SNTP_SUPPORT_MULTIPLE_SERVERS */ +#define sntp_current_server 0 +#endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */ + +#if SNTP_RETRY_TIMEOUT_EXP +#define SNTP_RESET_RETRY_TIMEOUT() sntp_retry_timeout = SNTP_RETRY_TIMEOUT +/** Retry time, initialized with SNTP_RETRY_TIMEOUT and doubled with each retry. */ +static u32_t sntp_retry_timeout; +#else /* SNTP_RETRY_TIMEOUT_EXP */ +#define SNTP_RESET_RETRY_TIMEOUT() +#define sntp_retry_timeout SNTP_RETRY_TIMEOUT +#endif /* SNTP_RETRY_TIMEOUT_EXP */ + +#if SNTP_CHECK_RESPONSE >= 1 +/** Saves the last server address to compare with response */ +static ip_addr_t sntp_last_server_address; +#endif /* SNTP_CHECK_RESPONSE >= 1 */ + +#if SNTP_CHECK_RESPONSE >= 2 +/** Saves the last timestamp sent (which is sent back by the server) + * to compare against in response */ +static u32_t sntp_last_timestamp_sent[2]; +#endif /* SNTP_CHECK_RESPONSE >= 2 */ + +/** + * SNTP processing of received timestamp + */ +static void +sntp_process(u32_t *receive_timestamp) +{ + /* convert SNTP time (1900-based) to unix GMT time (1970-based) + * if MSB is 0, SNTP time is 2036-based! + */ + u32_t rx_secs = ntohl(receive_timestamp[0]); + int is_1900_based = ((rx_secs & 0x80000000) != 0); + u32_t t = is_1900_based ? (rx_secs - DIFF_SEC_1900_1970) : (rx_secs + DIFF_SEC_1970_2036); + time_t tim = t; + +#if SNTP_CALC_TIME_US + u32_t us = ntohl(receive_timestamp[1]) / 4295; + SNTP_SET_SYSTEM_TIME_US(t, us); + /* display local time from GMT time */ + LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s, %"U32_F" us", ctime(&tim), us)); + +#else /* SNTP_CALC_TIME_US */ + + /* change system time and/or the update the RTC clock */ + SNTP_SET_SYSTEM_TIME(t); + /* display local time from GMT time */ + + LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s", ctime(&tim))); +#endif /* SNTP_CALC_TIME_US */ + LWIP_UNUSED_ARG(tim); +} + +/** + * Initialize request struct to be sent to server. + */ +static void +sntp_initialize_request(struct sntp_msg *req) +{ + memset(req, 0, SNTP_MSG_LEN); + req->li_vn_mode = SNTP_LI_NO_WARNING | SNTP_VERSION | SNTP_MODE_CLIENT; + +#if SNTP_CHECK_RESPONSE >= 2 + { + u32_t sntp_time_sec, sntp_time_us; + /* fill in transmit timestamp and save it in 'sntp_last_timestamp_sent' */ + SNTP_GET_SYSTEM_TIME(sntp_time_sec, sntp_time_us); + sntp_last_timestamp_sent[0] = htonl(sntp_time_sec + DIFF_SEC_1900_1970); + req->transmit_timestamp[0] = sntp_last_timestamp_sent[0]; + /* we send/save us instead of fraction to be faster... */ + sntp_last_timestamp_sent[1] = htonl(sntp_time_us); + req->transmit_timestamp[1] = sntp_last_timestamp_sent[1]; + } +#endif /* SNTP_CHECK_RESPONSE >= 2 */ +} + +/** + * Retry: send a new request (and increase retry timeout). + * + * @param arg is unused (only necessary to conform to sys_timeout) + */ +static void +sntp_retry(void* arg) +{ + LWIP_UNUSED_ARG(arg); + + LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_retry: Next request will be sent in %"U32_F" ms\n", + sntp_retry_timeout)); + + /* set up a timer to send a retry and increase the retry delay */ + sys_timeout(sntp_retry_timeout, sntp_request, NULL); + +#if SNTP_RETRY_TIMEOUT_EXP + { + u32_t new_retry_timeout; + /* increase the timeout for next retry */ + new_retry_timeout = sntp_retry_timeout << 1; + /* limit to maximum timeout and prevent overflow */ + if ((new_retry_timeout <= SNTP_RETRY_TIMEOUT_MAX) && + (new_retry_timeout > sntp_retry_timeout)) { + sntp_retry_timeout = new_retry_timeout; + } + } +#endif /* SNTP_RETRY_TIMEOUT_EXP */ +} + +#if SNTP_SUPPORT_MULTIPLE_SERVERS +/** + * If Kiss-of-Death is received (or another packet parsing error), + * try the next server or retry the current server and increase the retry + * timeout if only one server is available. + * (implicitly, SNTP_MAX_SERVERS > 1) + * + * @param arg is unused (only necessary to conform to sys_timeout) + */ +static void +sntp_try_next_server(void* arg) +{ + u8_t old_server, i; + LWIP_UNUSED_ARG(arg); + + old_server = sntp_current_server; + for (i = 0; i < SNTP_MAX_SERVERS - 1; i++) { + sntp_current_server++; + if (sntp_current_server >= SNTP_MAX_SERVERS) { + sntp_current_server = 0; + } + if (!ip_addr_isany(&sntp_servers[sntp_current_server].addr) +#if SNTP_SERVER_DNS + || (sntp_servers[sntp_current_server].name != NULL) +#endif + ) { + LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_try_next_server: Sending request to server %"U16_F"\n", + (u16_t)sntp_current_server)); + /* new server: reset retry timeout */ + SNTP_RESET_RETRY_TIMEOUT(); + /* instantly send a request to the next server */ + sntp_request(NULL); + return; + } + } + /* no other valid server found */ + sntp_current_server = old_server; + sntp_retry(NULL); +} +#else /* SNTP_SUPPORT_MULTIPLE_SERVERS */ +/* Always retry on error if only one server is supported */ +#define sntp_try_next_server sntp_retry +#endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */ + +/** UDP recv callback for the sntp pcb */ +static void +sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, 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, (ip_addr_t *)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 +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(&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); + } +} + +/** + * 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(); + 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, IPADDR_ANY, SNTP_PORT); + } + } + } +} + +/** + * Stop this module. + */ +void +sntp_stop(void) +{ + if (sntp_pcb != NULL) { + sys_untimeout(sntp_request, NULL); + udp_remove(sntp_pcb); + sntp_pcb = NULL; + } +} + +/** + * Get enabled state. + */ +u8_t sntp_enabled(void) +{ + return (sntp_pcb != NULL)? 1 : 0; +} + +/** + * 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; +} + +/** + * 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 */ + +/** + * 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(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 */ + +/** + * 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(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/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/apps/sntp_time.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/apps/sntp_time.c new file mode 100644 index 0000000..730476b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/apps/sntp_time.c @@ -0,0 +1,326 @@ +/* + * sntp_time.c + * + * Created on: 2016-11-9 + * Author: LiuHan + */ +#include "apps/sntp_opts.h" +#include "apps/sntp_time.h" +#include "esp_timer.h" + +static s8_t sntp_time_timezone = 8; +static u32_t sntp_time_realtime = 0; + +static int sntp_time_month; +static int sntp_time_year; +static char sntp_time_result[100]; +static sntp_tm_type sntp_time_rule[2]; +static sntp_tm sntp_time_result_buf; + +static const int sntp_time_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 sntp_time_year_lengths[2] = { + 365, + 366 +}; + +static os_timer_t sntp_system_timer; + +static sntp_tm *sntp_mktm_r(const sntp_time_t *tim_p, sntp_tm *res, int is_gmtime) +{ + long days, rem; + sntp_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 < sntp_time_year_lengths[yleap]) + break; + y++; + days -= sntp_time_year_lengths[yleap]; + } + } + else + { + do + { + --y; + yleap = isleap(y); + days += sntp_time_year_lengths[yleap]; + } while (days < 0); + } + + res->tm_year = y - YEAR_BASE; + res->tm_yday = days; + ip = sntp_time_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; + + res->tm_isdst = 0; + + offset = (res->tm_isdst == 1 ? sntp_time_rule[1].offset : sntp_time_rule[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]; + } + } + } + else + res->tm_isdst = 0; + + return (res); +} + +static sntp_tm *sntp_localtime_r(const sntp_time_t *tim_p, sntp_tm *res) +{ + return sntp_mktm_r (tim_p, res, 0); +} + +static sntp_tm *sntp_localtime(const sntp_time_t *tim_p) +{ + return sntp_localtime_r (tim_p, &sntp_time_result_buf); +} + +static int sntp_limitstime(int year) +{ + int days, year_days, years; + int i, j; + + if (year < EPOCH_YEAR) + return 0; + + sntp_time_year = 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_time_rule[i].ch == 'J') + days = year_days + sntp_time_rule[i].d + (isleap(year) && sntp_time_rule[i].d >= 60); + else if (sntp_time_rule[i].ch == 'D') + days = year_days + sntp_time_rule[i].d; + else + { + int yleap = isleap(year); + int m_day, m_wday, wday_diff; + const int *ip = sntp_time_mon_lengths[yleap]; + + days = year_days; + + for (j = 1; j < sntp_time_rule[i].m; ++j) + days += ip[j-1]; + + m_wday = (EPOCH_WDAY + days) % DAYSPERWEEK; + + wday_diff = sntp_time_rule[i].d - m_wday; + if (wday_diff < 0) + wday_diff += DAYSPERWEEK; + m_day = (sntp_time_rule[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_time_rule[i].change = days * SECSPERDAY + sntp_time_rule[i].s + sntp_time_rule[i].offset; + } + + sntp_time_month = (sntp_time_rule[0].change < sntp_time_rule[1].change); + + return 1; +} + +static char *sntp_asctime_r(sntp_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" + }; + 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; +} + +static char *sntp_asctime(sntp_tm *tim_p) +{ + return sntp_asctime_r (tim_p, sntp_time_result); +} + +u32_t sntp_get_current_timestamp(void) +{ + if(sntp_time_realtime == 0){ + printf("please start sntp first !\n"); + return 0; + } else { + return sntp_time_realtime; + } +} + +char* sntp_get_real_time(sntp_time_t t) +{ + return sntp_asctime(sntp_localtime (&t)); +} + +/** + * SNTP get sntp_time_timezone default GMT + 8 + */ +s8_t sntp_get_timezone(void) +{ + return sntp_time_timezone; +} + +/** + * SNTP set sntp_time_timezone default GMT + 8 + */ +bool sntp_set_timezone(s8_t timezone) +{ + if(timezone >= -11 && timezone <= 13) { + sntp_time_timezone = timezone; + return true; + } else { + return false; + } + +} + +void sntp_set_update_delay(uint32 ms) +{ +// SNTP_UPDATE_DELAY = (ms > 15000) ? ms : 15000; +} + +static void sntp_inc_time(void* arg) +{ + sntp_time_realtime ++; +} + +void sntp_set_system_time(sntp_time_t GMT_Time) +{ + sntp_time_t Local_Time = GMT_Time; + Local_Time += sntp_time_timezone * 60 * 60; + sntp_time_realtime = Local_Time; + os_timer_disarm(&sntp_system_timer); + os_timer_setfn(&sntp_system_timer, (os_timer_func_t *)sntp_inc_time, NULL); + os_timer_arm(&sntp_system_timer, 1000, 1); +} + diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/apps/time.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/apps/time.c new file mode 100644 index 0000000..1e0cfbb --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/apps/time.c @@ -0,0 +1,121 @@ +/* + time.c - implementation of Time API for esp8266 + + Copyright (c) 2014 Ivan Grokhotkov. 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 "c_types.h" +#include "esp_timer.h" + +#include "lwip/apps/sntp.h" +#include "lwip/apps/time.h" +#include "lwip/apps/sntp_time.h" + +static os_timer_t micros_overflow_timer; +static uint32 micros_at_last_overflow_tick = 0; +static uint32 micros_overflow_count = 0; + +static void micros_overflow_tick(void * arg) +{ + uint32 m = system_get_time(); + if (m < micros_at_last_overflow_tick) + micros_overflow_count ++; + + micros_at_last_overflow_tick = m; +} + +static void micros_set_default_time(void) +{ + os_timer_disarm(µs_overflow_timer); + os_timer_setfn(µs_overflow_timer, (os_timer_func_t *)micros_overflow_tick, 0); + os_timer_arm(µs_overflow_timer, 60 * 1000, 1); +} + +unsigned long millis(void) +{ + uint32 m = system_get_time(); + uint32 c = micros_overflow_count + ((m < micros_at_last_overflow_tick) ? 1 : 0); + return c * 4294967 + m / 1000000; +} + +unsigned long micros(void) +{ + return system_get_time(); +} + +void updateTime(uint32 ms) +{ + sntp_set_update_delay(ms); +} + +static void setServer(int id, const char* name_or_ip) +{ + if (name_or_ip){ + sntp_setservername(id, (char*)name_or_ip); + } +} + +bool configTime(int timezone, int daylightOffset, char *server1, char *server2, char *server3, bool enable) +{ + if (server1 == NULL && server2 == NULL && server3 == NULL) + return false; + + sntp_stop(); + + setServer(0, server1); + setServer(1, server2); + setServer(2, server3); + + sntp_set_timezone(timezone); + + sntp_init(); + + return true; +} + +time_t time(time_t *t) +{ + time_t seconds = sntp_get_current_timestamp(); + if (seconds == 0){ + micros_set_default_time(); + seconds = millis(); + } + + if (t){ + *t = seconds; + } + return seconds; +} + +int __attribute__((weak)) +_gettimeofday_r(void *ptr, struct timeval *ptimeval, void *ptimezone) +{ + if (ptimeval){ + ptimeval->tv_sec = time(NULL); + + ptimeval->tv_usec = 0; + } + + return 0; +} + +char* getrealtimeofday(void) +{ + struct timeval t; + gettimeofday(&t, NULL); + return sntp_get_real_time(t.tv_sec); +} diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/arch/Makefile b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/arch/Makefile new file mode 100644 index 0000000..682e8a1 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/arch/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 = liblwiparch.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/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/arch/sys_arch.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/arch/sys_arch.c new file mode 100644 index 0000000..e62a537 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/arch/sys_arch.c @@ -0,0 +1,426 @@ +/* + * 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 + * + */ + +/* lwIP includes. */ + +#include "lwip/debug.h" +#include "lwip/def.h" +#include "lwip/sys.h" +#include "lwip/mem.h" +#include "arch/sys_arch.h" + + +/* Message queue constants. */ +#define archMESG_QUEUE_LENGTH (100)//( 6 ) +#define archPOST_BLOCK_TIME_MS ( ( unsigned portLONG ) 10000 ) + + +struct timeoutlist { + //struct sys_timeouts timeouts; + xTaskHandle pid; +}; + +/* This is the number of threads that can be started with sys_thread_new() */ +#define SYS_THREAD_MAX 4 + +//static struct timeoutlist timeoutlist[SYS_THREAD_MAX]; +//static u16_t nextthread = 0; +int intlevel = 0; + +/*-----------------------------------------------------------------------------------*/ +// Initialize sys arch +void +sys_init(void) +{ +} + +/*-----------------------------------------------------------------------------------*/ +// Creates and returns a new semaphore. The "count" argument specifies +// the initial state of the semaphore. TBD finish and test +err_t +sys_sem_new(sys_sem_t *sem, u8_t count) +{ + err_t xReturn = ERR_MEM; + vSemaphoreCreateBinary(*sem); + + if ((*sem) != NULL) { + if (count == 0) { // Means it can't be taken + xSemaphoreTake(*sem, 1); + } + + xReturn = ERR_OK; + } else { + ; // TBD need assert + } + + return xReturn; +} + + +/*-----------------------------------------------------------------------------------*/ +// Deallocates a semaphore +void +sys_sem_free(sys_sem_t *sem) +{ + //vQueueDelete( sem ); + vSemaphoreDelete(*sem); +} + + +/*-----------------------------------------------------------------------------------*/ +// Signals a semaphore +void +sys_sem_signal(sys_sem_t *sem) +{ + xSemaphoreGive(*sem); +} + + +/*-----------------------------------------------------------------------------------*/ +/* + Blocks the thread while waiting for the semaphore to be + signaled. If the "timeout" argument is non-zero, the thread should + only be blocked for the specified time (measured in + milliseconds). + + If the timeout argument is 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. +*/ +u32_t +sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout) +{ + portTickType StartTime, EndTime, Elapsed; + unsigned long ulReturn; + + StartTime = xTaskGetTickCount(); + + if (timeout != 0) { + if (xSemaphoreTake(*sem, timeout / portTICK_RATE_MS) == pdTRUE) { + EndTime = xTaskGetTickCount(); + Elapsed = (EndTime - StartTime) * portTICK_RATE_MS; + + if (Elapsed == 0) { + Elapsed = 1; + } + + ulReturn = Elapsed; + } else { + ulReturn = SYS_ARCH_TIMEOUT; + } + } else { // must block without a timeout + while (xSemaphoreTake(*sem, portMAX_DELAY) != pdTRUE); + + EndTime = xTaskGetTickCount(); + Elapsed = (EndTime - StartTime) * portTICK_RATE_MS; + + if (Elapsed == 0) { + Elapsed = 1; + } + + ulReturn = Elapsed; + } + + return ulReturn ; // return time blocked +} + +/*-----------------------------------------------------------------------------------*/ +// Creates an empty mailbox. +err_t +sys_mbox_new(sys_mbox_t *mbox, int size) +{ + err_t xReturn = ERR_MEM; + + *mbox = xQueueCreate(size, sizeof(void *)); + + if (*mbox != NULL) { + xReturn = ERR_OK; + } + + return xReturn; +} + +/*-----------------------------------------------------------------------------------*/ +/* + 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_free(sys_mbox_t *mbox) +{ + if (uxQueueMessagesWaiting(*mbox)) { + /* Line for breakpoint. Should never break here! */ +// __asm volatile ( "NOP" ); + } + + vQueueDelete(*mbox); +} + +/*-----------------------------------------------------------------------------------*/ +// Posts the "msg" to the mailbox. +void +sys_mbox_post(sys_mbox_t *mbox, void *msg) +{ + while (xQueueSendToBack(*mbox, &msg, portMAX_DELAY) != pdTRUE); +} + +err_t +sys_mbox_trypost(sys_mbox_t *mbox, void *msg) +{ + err_t xReturn; + + if (xQueueSend(*mbox, &msg, (portTickType)0) == pdPASS) { + xReturn = ERR_OK; + } else { + xReturn = ERR_MEM; + } + + return xReturn; +} + +/*-----------------------------------------------------------------------------------*/ +/* + 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). 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_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout) +{ + void *dummyptr; + portTickType StartTime, EndTime, Elapsed; + unsigned long ulReturn; + + StartTime = xTaskGetTickCount(); + + if (msg == NULL) { + msg = &dummyptr; + } + + if (timeout != 0) { + if (pdTRUE == xQueueReceive(*mbox, &(*msg), timeout / portTICK_RATE_MS)) { + EndTime = xTaskGetTickCount(); + Elapsed = (EndTime - StartTime) * portTICK_RATE_MS; + + if (Elapsed == 0) { + Elapsed = 1; + } + + ulReturn = Elapsed; + } else { // timed out blocking for message + *msg = NULL; + ulReturn = SYS_ARCH_TIMEOUT; + } + } else { // block forever for a message. + while (pdTRUE != xQueueReceive(*mbox, &(*msg), portMAX_DELAY)); + + EndTime = xTaskGetTickCount(); + Elapsed = (EndTime - StartTime) * portTICK_RATE_MS; + + if (Elapsed == 0) { + Elapsed = 1; + } + + ulReturn = Elapsed; + } + + return ulReturn ; // return time blocked TBD test +} + +u32_t +sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg) +{ + void *pvDummy; + unsigned long ulReturn; + + if (msg == NULL) { + msg = &pvDummy; + } + + if (pdTRUE == xQueueReceive(*mbox, &(*msg), 0)) { + ulReturn = ERR_OK; + } else { + ulReturn = SYS_MBOX_EMPTY; + } + + return ulReturn; +} + +/** Create a new mutex + * @param mutex pointer to the mutex to create + * @return a new mutex */ +err_t +sys_mutex_new(sys_mutex_t *pxMutex) +{ + err_t xReturn = ERR_MEM; + + *pxMutex = xSemaphoreCreateMutex(); + + if (*pxMutex != NULL) { + xReturn = ERR_OK; + + } else { + ; + } + + return xReturn; +} + +/** Lock a mutex + * @param mutex the mutex to lock */ +void +sys_mutex_lock(sys_mutex_t *pxMutex) +{ + while (xSemaphoreTake(*pxMutex, portMAX_DELAY) != pdPASS); +} + +err_t +sys_mutex_trylock(sys_mutex_t *pxMutex) +{ + if (xSemaphoreTake(*pxMutex, 0) == pdPASS) return 0; + else return -1; +} + +/** Unlock a mutex + * @param mutex the mutex to unlock */ +void +sys_mutex_unlock(sys_mutex_t *pxMutex) +{ + xSemaphoreGive(*pxMutex); +} + + +/** Delete a semaphore + * @param mutex the mutex to delete */ +void +sys_mutex_free(sys_mutex_t *pxMutex) +{ + vQueueDelete(*pxMutex); +} + +u32_t +sys_now(void) +{ + return xTaskGetTickCount(); +} + +/*-----------------------------------------------------------------------------------*/ +/*-----------------------------------------------------------------------------------*/ +// TBD +/*-----------------------------------------------------------------------------------*/ +/* + Starts a new thread 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 id of the new thread is returned. Both the id and + the priority are system dependent. +*/ +sys_thread_t +sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio) +{ + xTaskHandle CreatedTask; + portBASE_TYPE result; + + result = xTaskCreate(thread, (signed char *)name, stacksize, arg, prio, &CreatedTask); + + if (result == pdPASS) { + return CreatedTask; + } else { + return NULL; + } +} + +/* + 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. +*/ +sys_prot_t +sys_arch_protect(void) +{ + vPortEnterCritical(); + return (sys_prot_t) 1; +} + +/* + 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. +*/ +void +sys_arch_unprotect(sys_prot_t pval) +{ + (void) pval; + vPortExitCritical(); +} + +/* + * Prints an assertion messages and aborts execution. + */ +void +sys_arch_assert(const char *file, int line) +{ + os_printf("\nAssertion: %d in %s\n", line, file); + + while(1); +} + +void +sys_arch_msleep(int ms) +{ + vTaskDelay(ms / portTICK_RATE_MS); +} + diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/Makefile b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/Makefile new file mode 100644 index 0000000..7cbb57b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/def.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/def.c new file mode 100644 index 0000000..352b552 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/dhcp.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/dhcp.c new file mode 100644 index 0000000..9199121 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/dhcp.c @@ -0,0 +1,2010 @@ +/** + * @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/sys.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 "netif/etharp.h" + +#include + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +/** DHCP_CREATE_RAND_XID: if this is set to 1, the xid is created using + * LWIP_RAND() (this overrides DHCP_GLOBAL_XID) + */ +#ifndef DHCP_CREATE_RAND_XID +#define DHCP_CREATE_RAND_XID 1 +#endif + +/** Default for DHCP_GLOBAL_XID is 0xABCD0000 + * This can be changed by defining DHCP_GLOBAL_XID and DHCP_GLOBAL_XID_HEADER, e.g. + * #define DHCP_GLOBAL_XID_HEADER "stdlib.h" + * #define DHCP_GLOBAL_XID rand() + */ +#ifdef DHCP_GLOBAL_XID_HEADER +#include DHCP_GLOBAL_XID_HEADER /* include optional starting XID generation prototypes */ +#endif + +/** DHCP_OPTION_MAX_MSG_SIZE is set to the MTU + * MTU is checked to be big enough in dhcp_start */ +#define DHCP_MAX_MSG_LEN(netif) (netif->mtu) +#define DHCP_MAX_MSG_LEN_MIN_REQUIRED 576 +/** Minimum length for reply before packet is parsed */ +#define DHCP_MIN_REPLY_LEN 44 + +#define REBOOT_TRIES 2 + +/** 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]; + +#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)) + + +/* 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); +#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); + +/** + * Back-off the DHCP client (because of a received NAK response). + * + * Back-off the DHCP client because of a received NAK. Receiving a + * NAK means the client asked for something non-sensible, for + * example when it tries to renew a lease obtained on another network. + * + * We clear any existing set IP address and restart DHCP negotiation + * afresh (as per RFC2131 3.2.3). + * + * @param netif the netif under DHCP control + */ +static void +dhcp_handle_nak(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_nak(netif=%p) %c%c%"U16_F"\n", + (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); + /* 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 +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 +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 +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))); + + /**add options for support more router by liuHan**/ +#ifdef LWIP_ESP8266 + 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); + +#else + dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*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); +#endif + +#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(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 +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 +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 + && ( netif->dhcp->state == DHCP_REQUESTING || netif->dhcp->state == DHCP_SELECTING ) + ){ + 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 +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 +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 +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 +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 */ + for(n = 0; (n < DNS_MAX_SERVERS) && dhcp_option_given(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n); n++) { + 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); + } +#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 +dhcp_set_struct(struct netif *netif, struct dhcp *dhcp) +{ + LWIP_ASSERT("netif != NULL", netif != NULL); + LWIP_ASSERT("dhcp != NULL", dhcp != NULL); + LWIP_ASSERT("netif already has a struct dhcp set", netif->dhcp == NULL); + + /* clear data structure */ + memset(dhcp, 0, sizeof(struct dhcp)); + /* dhcp_set_state(&dhcp, DHCP_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 +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 +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\n")); + /* 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 */ + 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; + } + ip_set_option(dhcp->pcb, 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 +dhcp_inform(struct netif *netif) +{ + struct dhcp dhcp; + err_t result = ERR_OK; + struct udp_pcb *pcb; + + LWIP_ERROR("netif != NULL", (netif != NULL), return;); + + 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; + ip_set_option(dhcp.pcb, 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)); + + /**add options for support more router by liuHan**/ +#ifdef LWIP_ESP8266 +#if LWIP_NETIF_HOSTNAME + dhcp_option_hostname(&dhcp, netif); +#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); + +#else + dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*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); +#endif + + 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 +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 +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 +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))); + + /**add options for support more router by liuHan**/ +#ifdef LWIP_ESP8266 +#if LWIP_NETIF_HOSTNAME + dhcp_option_hostname(dhcp, netif); +#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); + +#else + dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*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); +#endif + + 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 +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)); + + /**add options for support more router by liuHan**/ +#ifdef LWIP_ESP8266 +#if LWIP_NETIF_HOSTNAME + dhcp_option_hostname(dhcp, netif); +#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); + +#else + dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*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); +#endif + + 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); + + dhcp->p_out->type = PBUF_RAM; + + 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 +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. */ + 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(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)); + } + } + + 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(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 */ + + // 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); + + // 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 +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 0 + dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); + dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr)); +#endif + +#if 0 + dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4); + dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr)); +#endif + +#if LWIP_NETIF_HOSTNAME + dhcp_option_hostname(dhcp, netif); +#endif /* LWIP_NETIF_HOSTNAME */ + /**add options for support more router by liuHan**/ +#ifdef LWIP_ESP8266 + + 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); + +#else + dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*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); +#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 +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 + dhcp_option_hostname(dhcp, netif); +#endif /* LWIP_NETIF_HOSTNAME */ + /**add options for support more router by liuHan**/ +#ifdef LWIP_ESP8266 + 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); + +#else + dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*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); +#endif + +#if 0 + 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 +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); + + /**add options for support more router by liuHan**/ +#ifdef LWIP_ESP8266 +#if LWIP_NETIF_HOSTNAME + dhcp_option_hostname(dhcp, netif); +#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); + +#else + dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*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); +#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_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 +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) { + /**add options for support more router by liuHan**/ +#ifdef LWIP_ESP8266 + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_release: 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 + dhcp_option_hostname(dhcp, netif); +#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); + +#endif + + 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 +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 +dhcp_set_state(struct dhcp *dhcp, u8_t new_state) +{ + if (new_state != dhcp->state) { + dhcp->state = new_state; + dhcp->tries = 0; + dhcp->request_timeout = 0; + } +} + +/* + * Concatenate an option type and length field to the outgoing + * DHCP message. + * + */ +static void +dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len) +{ + LWIP_ASSERT("dhcp_option: dhcp->options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2U + option_len <= DHCP_OPTIONS_LEN); + dhcp->msg_out->options[dhcp->options_out_len++] = option_type; + dhcp->msg_out->options[dhcp->options_out_len++] = option_len; +} +/* + * Concatenate a single byte to the outgoing DHCP message. + * + */ +static void +dhcp_option_byte(struct dhcp *dhcp, u8_t value) +{ + LWIP_ASSERT("dhcp_option_byte: dhcp->options_out_len < DHCP_OPTIONS_LEN", dhcp->options_out_len < DHCP_OPTIONS_LEN); + dhcp->msg_out->options[dhcp->options_out_len++] = value; +} + +static void +dhcp_option_short(struct dhcp *dhcp, u16_t value) +{ + LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2U <= DHCP_OPTIONS_LEN); + dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff00U) >> 8); + dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t) (value & 0x00ffU); +} + +static void +dhcp_option_long(struct dhcp *dhcp, u32_t value) +{ + LWIP_ASSERT("dhcp_option_long: dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 4U <= DHCP_OPTIONS_LEN); + dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff000000UL) >> 24); + dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x00ff0000UL) >> 16); + dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x0000ff00UL) >> 8); + dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x000000ffUL)); +} + +#if LWIP_NETIF_HOSTNAME +static void +dhcp_option_hostname(struct dhcp *dhcp, struct netif *netif) +{ + if (netif->hostname != NULL) { + size_t namelen = strlen(netif->hostname); + if (namelen > 0) { + u8_t len; + const char *p = netif->hostname; + /* Shrink len to available bytes (need 2 bytes for OPTION_HOSTNAME + and 1 byte for trailer) */ + size_t available = DHCP_OPTIONS_LEN - dhcp->options_out_len - 3; + LWIP_ASSERT("DHCP: hostname is too long!", namelen <= available); + len = LWIP_MIN(namelen, available); + dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, len); + while (len--) { + dhcp_option_byte(dhcp, *p++); + } + } + } +} +#endif /* LWIP_NETIF_HOSTNAME */ + +/** + * Extract the DHCP message and the DHCP options. + * + * Extract the DHCP message and the DHCP options, each into a contiguous + * piece of memory. As a DHCP message is variable sized by its options, + * and also allows overriding some fields for options, the easy approach + * is to first unfold the options into a conitguous piece of memory, and + * use that further on. + * + */ +static err_t +dhcp_parse_reply(struct dhcp *dhcp, struct pbuf *p) +{ + u8_t *options; + u16_t offset; + u16_t offset_max; + u16_t options_idx; + u16_t options_idx_max; + struct pbuf *q; + int parse_file_as_options = 0; + int parse_sname_as_options = 0; + + /* clear received options */ + dhcp_clear_all_options(dhcp); + /* check that beginning of dhcp_msg (up to and including chaddr) is in first pbuf */ + if (p->len < DHCP_SNAME_OFS) { + return ERR_BUF; + } + dhcp->msg_in = (struct dhcp_msg *)p->payload; +#if LWIP_DHCP_BOOTP_FILE + /* clear boot file name */ + dhcp->boot_file_name[0] = 0; +#endif /* LWIP_DHCP_BOOTP_FILE */ + + /* parse options */ + + /* start with options field */ + options_idx = DHCP_OPTIONS_OFS; + /* parse options to the end of the received packet */ + options_idx_max = p->tot_len; +again: + q = p; + while((q != NULL) && (options_idx >= q->len)) { + options_idx -= q->len; + options_idx_max -= q->len; + q = q->next; + } + if (q == NULL) { + return ERR_BUF; + } + offset = options_idx; + offset_max = options_idx_max; + options = (u8_t*)q->payload; + /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */ + while((q != NULL) && (options[offset] != DHCP_OPTION_END) && (offset < offset_max)) { + u8_t op = options[offset]; + u8_t len; + u8_t decode_len = 0; + int decode_idx = -1; + u16_t val_offset = offset + 2; + /* len byte might be in the next pbuf */ + if (offset + 1 < q->len) { + len = options[offset + 1]; + } else { + len = (q->next != NULL ? ((u8_t*)q->next->payload)[0] : 0); + } + /* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%"U16_F", q->len=%"U16_F, msg_offset, q->len)); */ + decode_len = len; + switch(op) { + /* case(DHCP_OPTION_END): handled above */ + case(DHCP_OPTION_PAD): + /* special option: no len encoded */ + decode_len = len = 0; + /* will be increased below */ + offset--; + break; + case(DHCP_OPTION_SUBNET_MASK): + LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); + decode_idx = DHCP_OPTION_IDX_SUBNET_MASK; + break; + case(DHCP_OPTION_ROUTER): + decode_len = 4; /* only copy the first given router */ + LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;); + decode_idx = DHCP_OPTION_IDX_ROUTER; + break; + case(DHCP_OPTION_DNS_SERVER): + /* special case: there might be more than one server */ + LWIP_ERROR("len % 4 == 0", len % 4 == 0, return ERR_VAL;); + /* limit number of DNS servers */ + decode_len = LWIP_MIN(len, 4 * DNS_MAX_SERVERS); + LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;); + decode_idx = DHCP_OPTION_IDX_DNS_SERVER; + break; + case(DHCP_OPTION_LEASE_TIME): + LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); + decode_idx = DHCP_OPTION_IDX_LEASE_TIME; + break; + case(DHCP_OPTION_OVERLOAD): + LWIP_ERROR("len == 1", len == 1, return ERR_VAL;); + decode_idx = DHCP_OPTION_IDX_OVERLOAD; + break; + case(DHCP_OPTION_MESSAGE_TYPE): + LWIP_ERROR("len == 1", len == 1, return ERR_VAL;); + decode_idx = DHCP_OPTION_IDX_MSG_TYPE; + break; + case(DHCP_OPTION_SERVER_ID): + LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); + decode_idx = DHCP_OPTION_IDX_SERVER_ID; + break; + case(DHCP_OPTION_T1): + LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); + decode_idx = DHCP_OPTION_IDX_T1; + break; + case(DHCP_OPTION_T2): + LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); + decode_idx = DHCP_OPTION_IDX_T2; + break; + default: + decode_len = 0; + LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", op)); + break; + } + offset += len + 2; + if (decode_len > 0) { + u32_t value = 0; + u16_t copy_len; +decode_next: + LWIP_ASSERT("check decode_idx", decode_idx >= 0 && decode_idx < DHCP_OPTION_IDX_MAX); + if (!dhcp_option_given(dhcp, decode_idx)) { + copy_len = LWIP_MIN(decode_len, 4); + pbuf_copy_partial(q, &value, copy_len, val_offset); + if (decode_len > 4) { + /* decode more than one u32_t */ + LWIP_ERROR("decode_len % 4 == 0", decode_len % 4 == 0, return ERR_VAL;); + dhcp_got_option(dhcp, decode_idx); + dhcp_set_option_value(dhcp, decode_idx, htonl(value)); + decode_len -= 4; + val_offset += 4; + decode_idx++; + goto decode_next; + } else if (decode_len == 4) { + value = ntohl(value); + } else { + LWIP_ERROR("invalid decode_len", decode_len == 1, return ERR_VAL;); + value = ((u8_t*)&value)[0]; + } + dhcp_got_option(dhcp, decode_idx); + dhcp_set_option_value(dhcp, decode_idx, value); + } + } + if (offset >= q->len) { + offset -= q->len; + offset_max -= q->len; + if ((offset < offset_max) && offset_max) { + q = q->next; + LWIP_ASSERT("next pbuf was null", q); + options = (u8_t*)q->payload; + } else { + /* We've run out of bytes, probably no end marker. Don't proceed. */ + break; + } + } + } + /* is this an overloaded message? */ + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_OVERLOAD)) { + u32_t overload = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_OVERLOAD); + dhcp_clear_option(dhcp, DHCP_OPTION_IDX_OVERLOAD); + if (overload == DHCP_OVERLOAD_FILE) { + parse_file_as_options = 1; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded file field\n")); + } else if (overload == DHCP_OVERLOAD_SNAME) { + parse_sname_as_options = 1; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname field\n")); + } else if (overload == DHCP_OVERLOAD_SNAME_FILE) { + parse_sname_as_options = 1; + parse_file_as_options = 1; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname and file field\n")); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("invalid overload option: %d\n", (int)overload)); + } +#if LWIP_DHCP_BOOTP_FILE + if (!parse_file_as_options) { + /* only do this for ACK messages */ + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE) && + (dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE) == DHCP_ACK)) + /* copy bootp file name, don't care for sname (server hostname) */ + pbuf_copy_partial(p, dhcp->boot_file_name, DHCP_FILE_LEN-1, DHCP_FILE_OFS); + /* make sure the string is really NULL-terminated */ + dhcp->boot_file_name[DHCP_FILE_LEN-1] = 0; + } +#endif /* LWIP_DHCP_BOOTP_FILE */ + } + if (parse_file_as_options) { + /* if both are overloaded, parse file first and then sname (RFC 2131 ch. 4.1) */ + parse_file_as_options = 0; + options_idx = DHCP_FILE_OFS; + options_idx_max = DHCP_FILE_OFS + DHCP_FILE_LEN; + goto again; + } else if (parse_sname_as_options) { + parse_sname_as_options = 0; + options_idx = DHCP_SNAME_OFS; + options_idx_max = DHCP_SNAME_OFS + DHCP_SNAME_LEN; + goto again; + } + return ERR_OK; +} + +/** + * If an incoming DHCP message is in response to us, then trigger the state machine + */ +static void +dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port) +{ + SYS_ARCH_DECL_PROTECT(lev); + // add critical for protect dhcp struct + SYS_ARCH_PROTECT(lev); + 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); + SYS_ARCH_UNPROTECT(lev); +} + +/** + * 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))); + + /* reuse transaction identifier in retransmissions */ + if (dhcp->tries == 0) { +#if DHCP_CREATE_RAND_XID && defined(LWIP_RAND) + xid = LWIP_RAND(); +#else /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */ + xid++; +#endif /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */ + } + dhcp->xid = xid; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, + ("transaction id xid(%"X32_F")\n", xid)); + + dhcp->msg_out = (struct dhcp_msg *)dhcp->p_out->payload; + + dhcp->msg_out->op = DHCP_BOOTREQUEST; + /* TODO: make link layer independent */ + dhcp->msg_out->htype = DHCP_HTYPE_ETH; + dhcp->msg_out->hlen = netif->hwaddr_len; + dhcp->msg_out->hops = 0; + dhcp->msg_out->xid = htonl(dhcp->xid); + dhcp->msg_out->secs = 0; + /* we don't need the broadcast flag since we can receive unicast traffic + before being fully configured! */ + dhcp->msg_out->flags = 0; + 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 +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; + } +} + +#endif /* LWIP_DHCP */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/dhcpserver.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/dhcpserver.c new file mode 100644 index 0000000..685da6f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/dhcpserver.c @@ -0,0 +1,1128 @@ +#include "esp_common.h" +#include "lwip/inet.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" +#include "lwip/udp.h" +#include "lwip/mem.h" +#include "lwip/dhcpserver.h" + +#ifndef LWIP_OPEN_SRC +#include "net80211/ieee80211_var.h" +#endif +#include "netif/wlan_lwip_if.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +//////////////////////////////////////////////////////////////////////////////////// +//static const uint8_t xid[4] = {0xad, 0xde, 0x12, 0x23}; +//static u8_t old_xid[4] = {0}; +static const u32_t magic_cookie ICACHE_RODATA_ATTR STORE_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 ip_addr client_address_plus; + +static struct dhcps_lease dhcps_lease; +//static bool dhcps_lease_flag = true; +static list_node *plist = NULL; +static u8_t offer = 0xFF; +static bool renew = false; +#define DHCPS_LEASE_TIME_DEF (120) +u32_t dhcps_lease_time = DHCPS_LEASE_TIME_DEF; //minute +/****************************************************************************** + * 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 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 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 u8_t* add_msg_type(u8_t *optptr, u8_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 u8_t* add_offer_options(u8_t *optptr) +{ + struct ip_addr ipadd; + + ipadd.addr = *( (u32_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; + 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 u8_t* add_end(u8_t *optptr) +{ + + *optptr++ = DHCP_OPTION_END; + return optptr; +} +/////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////// +static void create_msg(struct dhcps_msg *m) +{ + struct ip_addr client; + + client.addr = *( (uint32_t *) &client_address); + + 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); + + memcpy((char *) m->yiaddr, (char *) &client.addr, sizeof(m->yiaddr)); + + memset((char *) m->ciaddr, 0, sizeof(m->ciaddr)); + memset((char *) m->siaddr, 0, sizeof(m->siaddr)); + memset((char *) m->giaddr, 0, sizeof(m->giaddr)); + memset((char *) m->sname, 0, sizeof(m->sname)); + memset((char *) m->file, 0, sizeof(m->file)); + + memset((char *) m->options, 0, sizeof(m->options)); + + u32_t magic_cookie1 = magic_cookie; + memcpy((char *) m->options, &magic_cookie1, sizeof(magic_cookie1)); +} +/////////////////////////////////////////////////////////////////////////////////// +/* + * ����һ��OFFER + * + * @param -- m ָ����Ҫ���͵�DHCP msg���� + */ +/////////////////////////////////////////////////////////////////////////////////// +static void send_offer(struct dhcps_msg *m) +{ + u8_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++]; +#if DHCPS_DEBUG + os_printf("%02x ",data[i]); + if((i+1)%16 == 0){ + os_printf("\n"); + } +#endif + } + + 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 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++]; +#if DHCPS_DEBUG + os_printf("%02x ",data[i]); + if((i+1)%16 == 0){ + os_printf("\n"); + } +#endif + } + + 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 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++]; +#if DHCPS_DEBUG + os_printf("%02x ",data[i]); + if((i+1)%16 == 0){ + os_printf("\n"); + } +#endif + } + + 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 u8_t parse_options(u8_t *optptr, s16_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: (s16_t)*optptr = %d\n", (s16_t)*optptr); +#endif + switch ((s16_t) *optptr) { + + case DHCP_OPTION_MSG_TYPE: //53 + type = *(optptr + 2); + break; + + case DHCP_OPTION_REQ_IPADDR://50 + if( 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 s16_t parse_msg(struct dhcps_msg *m, u16_t len) +{ + if(memcmp((char *)m->options, + &magic_cookie, + sizeof(magic_cookie)) == 0){ +#if DHCPS_DEBUG + os_printf("dhcps: len = %d\n", len); +#endif + /* + * ��¼��ǰ��xid���ﴦ���? + * �˺�ΪDHCP�ͻ����������û�ͳһ��ȡIPʱ�� + */ +// if((old_xid[0] == 0) && +// (old_xid[1] == 0) && +// (old_xid[2] == 0) && +// (old_xid[3] == 0)){ +// /* +// * old_xidδ��¼�κ����? +// * �϶��ǵ�һ��ʹ�� +// */ +// memcpy((char *)old_xid, (char *)m->xid, sizeof(m->xid)); +// }else{ +// /* +// * ������DHCP msg�����xid���ϴμ�¼�IJ�ͬ�� +// * �϶�Ϊ��ͬ��DHCP�ͻ��˷��ͣ���ʱ����Ҫ����Ŀͻ���IP +// * ���� 192.168.4.100(0x6404A8C0) <--> 192.168.4.200(0xC804A8C0) +// * +// */ +// if(memcmp((char *)old_xid, (char *)m->xid, sizeof(m->xid)) != 0){ + /* + * ��¼���ε�xid�ţ�ͬʱ�����IP���� + */ + struct ip_addr addr_tmp; +// memcpy((char *)old_xid, (char *)m->xid, sizeof(m->xid)); + +// { + struct dhcps_pool *pdhcps_pool = NULL; + list_node *pnode = NULL; + list_node *pback_node = NULL; + struct ip_addr first_address; + bool flag = false; + +// POOL_START: + first_address.addr = dhcps_lease.start_ip.addr; + client_address.addr = client_address_plus.addr; + renew = false; +// addr_tmp.addr = htonl(client_address_plus.addr); +// addr_tmp.addr++; +// client_address_plus.addr = htonl(addr_tmp.addr); + if (plist != NULL){ + for (pback_node = plist; pback_node != NULL;pback_node = pback_node->pnext) { + pdhcps_pool = pback_node->pnode; + if (memcmp(pdhcps_pool->mac, m->chaddr, sizeof(pdhcps_pool->mac)) == 0){ +// os_printf("the same device request ip\n"); + if (memcmp(&pdhcps_pool->ip.addr, m->ciaddr, sizeof(pdhcps_pool->ip.addr)) == 0) { + renew = true; + } + client_address.addr = pdhcps_pool->ip.addr; + pdhcps_pool->lease_timer = DHCPS_LEASE_TIMER; + pnode = pback_node; + goto POOL_CHECK; + } else if (pdhcps_pool->ip.addr == client_address_plus.addr){ +// client_address.addr = client_address_plus.addr; +// os_printf("the ip addr has been request\n"); + addr_tmp.addr = htonl(client_address_plus.addr); + addr_tmp.addr++; + client_address_plus.addr = htonl(addr_tmp.addr); + client_address.addr = client_address_plus.addr; + } + + if(flag == false) { // search the fisrt unused ip + if(first_address.addr < pdhcps_pool->ip.addr) { + flag = true; + } else { + addr_tmp.addr = htonl(first_address.addr); + addr_tmp.addr++; + first_address.addr = htonl(addr_tmp.addr); + } + } + } + }else{ + client_address.addr = dhcps_lease.start_ip.addr; + } + + if (client_address_plus.addr > dhcps_lease.end_ip.addr) { + client_address.addr = first_address.addr; + } + if (client_address.addr > dhcps_lease.end_ip.addr) { + client_address_plus.addr = dhcps_lease.start_ip.addr; + pdhcps_pool = NULL; + pnode = NULL; + } else { + pdhcps_pool = (struct dhcps_pool *)os_zalloc(sizeof(struct dhcps_pool)); + pdhcps_pool->ip.addr = client_address.addr; + memcpy(pdhcps_pool->mac, m->chaddr, sizeof(pdhcps_pool->mac)); + pdhcps_pool->lease_timer = DHCPS_LEASE_TIMER; + pnode = (list_node *)os_zalloc(sizeof(list_node )); + pnode->pnode = pdhcps_pool; + pnode->pnext = NULL; + node_insert_to_list(&plist,pnode); + if (client_address.addr == dhcps_lease.end_ip.addr) { + client_address_plus.addr = dhcps_lease.start_ip.addr; + } else { + addr_tmp.addr = htonl(client_address.addr); + addr_tmp.addr++; + client_address_plus.addr = htonl(addr_tmp.addr); + } + } + + POOL_CHECK: + if ((client_address.addr > dhcps_lease.end_ip.addr) || (ip_addr_isany(&client_address))){ + if(pnode != NULL) { + node_remove_from_list(&plist,pnode); + os_free(pnode); + pnode = NULL; + } + + if (pdhcps_pool != NULL) { + os_free(pdhcps_pool); + pdhcps_pool = NULL; + } +// client_address_plus.addr = dhcps_lease.start_ip.addr; + return 4; + } + + s16_t ret = parse_options(&m->options[4], len);; + + if(ret == DHCPS_STATE_RELEASE) { + if(pnode != NULL) { + node_remove_from_list(&plist,pnode); + os_free(pnode); + pnode = NULL; + } + + if (pdhcps_pool != NULL) { + os_free(pdhcps_pool); + pdhcps_pool = NULL; + } + memset(&client_address,0x0,sizeof(client_address)); + } + + if (wifi_softap_set_station_info(m->chaddr, &client_address) == false) { + return 0; + } +// } + +#if DHCPS_DEBUG + os_printf("dhcps: xid changed\n"); + os_printf("dhcps: client_address.addr = %x\n", client_address.addr); +#endif + +// } + +// } + 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 handle_dhcp(void *arg, + struct udp_pcb *pcb, + struct pbuf *p, + struct ip_addr *addr, + u16_t port) +{ + struct dhcps_msg *pmsg_dhcps = NULL; + s16_t tlen; + u16_t i; + u16_t dhcps_msg_cnt=0; + u8_t *p_dhcps_msg = NULL; + u8_t *data; + +#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 DHCPS_DEBUG + os_printf("%02x ",data[i]); + if((i+1)%16 == 0){ + os_printf("\n"); + } +#endif + } + + 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]; +#if DHCPS_DEBUG + os_printf("%02x ",data[i]); + if((i+1)%16 == 0){ + os_printf("\n"); + } +#endif + } + } + + /* + * 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 wifi_softap_init_dhcps_lease(u32_t ip) +{ + u32_t softap_ip = 0,local_ip = 0; + u32_t start_ip = 0; + u32_t end_ip = 0; + 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 ++; + + 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); + } +// os_printf("start_ip = 0x%x, end_ip = 0x%x\n",dhcps_lease.start_ip, dhcps_lease.end_ip); +} +/////////////////////////////////////////////////////////////////////////////////// +void dhcps_start(struct ip_info *info) +{ + struct netif * apnetif = NULL; + apnetif = (struct netif *)wifi_get_netif(SOFTAP_IF); + + 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); + client_address_plus.addr = dhcps_lease.start_ip.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 dhcps_stop(void) +{ + struct netif * apnetif = (struct netif *)wifi_get_netif(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; + pnode = plist; + while (pnode != NULL) { + 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; + } +} + +bool wifi_softap_set_dhcps_lease(struct dhcps_lease *please) +{ + struct ip_info info; + u32_t softap_ip = 0; + u32_t start_ip = 0; + u32_t 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) { + 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; + + 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 wifi_softap_get_dhcps_lease(struct dhcps_lease *please) +{ + u8_t opmode = wifi_get_opmode(); + + if (opmode == STATION_MODE || opmode == NULL_MODE) { + return false; + } + + if (NULL == please) + return false; + if (dhcps_lease.enable == FALSE){ + if (wifi_softap_dhcps_status() == DHCP_STOPPED) + return false; + } else { + } + please->start_ip.addr = dhcps_lease.start_ip.addr; + please->end_ip.addr = dhcps_lease.end_ip.addr; + return true; +} + +static void 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; + os_free(minp->pnode); + minp->pnode = NULL; + os_free(minp); + minp = NULL; +} + +void dhcps_coarse_tmr(void) +{ + u8_t 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; + 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 wifi_softap_set_dhcps_offer_option(u8_t level, void* optarg) +{ + bool offer_flag = true; + u8_t 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 wifi_softap_set_dhcps_lease_time(u32_t minute) +{ + u8_t 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 wifi_softap_reset_dhcps_lease_time(void) +{ + u8_t 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; +} + +u32_t wifi_softap_get_dhcps_lease_time(void) // minute +{ + return dhcps_lease_time; +} diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/dns.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/dns.c new file mode 100644 index 0000000..7da98e7 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/dns.c @@ -0,0 +1,1007 @@ +/** + * @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 +#include + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_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; + +/** + * Initialize the resolver: set up the UDP pcb and configure the default server + * (DNS_SERVER_ADDRESS). + */ +void +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 +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 +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) +{ + if (dns_pcb != NULL) { + LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n")); + dns_check_entries(); + } +} + +#if DNS_LOCAL_HOSTLIST +static void +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 = 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 +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 +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 +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 = 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 +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 +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 * +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 +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; + + 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 + 1 + + SIZEOF_DNS_QUERY, PBUF_RAM); + if (p != NULL) { + u16_t realloc_size; + LWIP_ASSERT("pbuf must be in one piece", p->next == NULL); + /* fill dns header */ + hdr = (struct dns_hdr*)p->payload; + memset(hdr, 0, SIZEOF_DNS_HDR); + hdr->id = htons(id); + 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 */ + realloc_size = (u16_t)((query + SIZEOF_DNS_QUERY) - ((char*)(p->payload))); + LWIP_ASSERT("p->tot_len >= realloc_size", p->tot_len >= realloc_size); + pbuf_realloc(p, realloc_size); + + /* 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 +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 +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 +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* )mem_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); + 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); + +#if 0 + // DYC ADD, not authorized ip, then ignore + u16_t numauthrr = htons(hdr->numauthrr); + if (numauthrr == 0) { + goto responseerr; + } +#endif + + /* 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); + mem_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 hostnamelen length of the hostname + * @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 +dns_enqueue(const char *name, size_t hostnamelen, 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(hostnamelen, 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 +dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found, + void *callback_arg) +{ + u32_t ipaddr; + size_t hostnamelen; + /* 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])) { + return ERR_ARG; + } + hostnamelen = strlen(hostname); + if (hostnamelen >= 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, hostnamelen, found, callback_arg); +} + +#endif /* LWIP_DNS */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/inet_chksum.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/inet_chksum.c new file mode 100644 index 0000000..8bc42c1 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/inet_chksum.c @@ -0,0 +1,545 @@ +/** + * @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 +u16_t lwip_standard_chksum(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(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) + */ + +u16_t +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 + */ + +u16_t +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 + +/** Parts of the pseudo checksum which are common to IPv4 and IPv6 */ +static u16_t +inet_cksum_pseudo_base(struct pbuf *p, u8_t proto, u16_t proto_len, u32_t acc) +{ + struct pbuf *q; + u8_t swapped = 0; + + /* iterate through all pbuf in chain */ + for(q = p; q != NULL; q = q->next) { + LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n", + (void *)q, (void *)q->next)); + acc += LWIP_CHKSUM(q->payload, q->len); + /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/ + /* just executing this next line is probably faster that the if statement needed + to check whether we really need to execute it, and does no harm */ + acc = FOLD_U32T(acc); + if (q->len % 2 != 0) { + swapped = 1 - swapped; + acc = SWAP_BYTES_IN_WORD(acc); + } + /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/ + } + + if (swapped) { + acc = SWAP_BYTES_IN_WORD(acc); + } + + acc += (u32_t)htons((u16_t)proto); + acc += (u32_t)htons(proto_len); + + /* Fold 32-bit sum to 16 bits + calling this twice is 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(struct pbuf *p, u8_t proto, u16_t proto_len, + ip_addr_t *src, ip_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); +} +#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 src source ipv6 address (used for checksum of pseudo header) + * @param dst destination ipv6 address (used for checksum of pseudo header) + * @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) + * @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, + ip6_addr_t *src, 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 */ + +/** Parts of the pseudo checksum which are common to IPv4 and IPv6 */ +static u16_t +inet_cksum_pseudo_partial_base(struct pbuf *p, u8_t proto, u16_t proto_len, + u16_t chksum_len, u32_t acc) +{ + struct pbuf *q; + u8_t swapped = 0; + u16_t chklen; + + /* iterate through all pbuf in chain */ + for(q = p; (q != NULL) && (chksum_len > 0); q = q->next) { + LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n", + (void *)q, (void *)q->next)); + chklen = q->len; + if (chklen > chksum_len) { + chklen = chksum_len; + } + acc += LWIP_CHKSUM(q->payload, chklen); + chksum_len -= chklen; + LWIP_ASSERT("delete me", chksum_len < 0x7fff); + /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/ + /* fold the upper bit down */ + acc = FOLD_U32T(acc); + if (q->len % 2 != 0) { + swapped = 1 - swapped; + acc = SWAP_BYTES_IN_WORD(acc); + } + /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/ + } + + if (swapped) { + acc = SWAP_BYTES_IN_WORD(acc); + } + + acc += (u32_t)htons((u16_t)proto); + acc += (u32_t)htons(proto_len); + + /* Fold 32-bit sum to 16 bits + calling this twice is 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_partial: + * + * 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, u8_t proto, u16_t proto_len, + u16_t chksum_len, ip_addr_t *src, ip_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); +} + +#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 src source ipv6 address (used for checksum of pseudo header) + * @param dst destination ipv6 address (used for checksum of pseudo header) + * @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 + * @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, ip6_addr_t *src, 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 */ + +/* 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/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/init.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/init.c new file mode 100644 index 0000000..b789461 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/init.c @@ -0,0 +1,349 @@ +/** + * @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" +#include "lwip/ip6.h" +#include "lwip/nd6.h" +#include "lwip/mld6.h" +#include "lwip/api.h" + +/* Compile-time sanity checks for configuration errors. + * These can be done independently of LWIP_DEBUG, without penalty. + */ +#ifndef BYTE_ORDER + #error "BYTE_ORDER is not defined, you have to define it in your cc.h" +#endif +#if (!IP_SOF_BROADCAST && IP_SOF_BROADCAST_RECV) + #error "If you want to use broadcast filter per pcb on recv operations, you have to define IP_SOF_BROADCAST=1 in your lwipopts.h" +#endif +#if (!LWIP_UDP && LWIP_UDPLITE) + #error "If you want to use UDP Lite, you have to define LWIP_UDP=1 in your lwipopts.h" +#endif +#if (!LWIP_UDP && LWIP_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 !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_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_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_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) + #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 +#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 + #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 || LWIP_IPV6) && !defined(LWIP_RAND) + #error "When using IGMP or IPv6, LWIP_RAND() needs to be defined to a random-function returning an u32_t random value" +#endif +#if LWIP_TCPIP_CORE_LOCKING_INPUT && !LWIP_TCPIP_CORE_LOCKING + #error "When using LWIP_TCPIP_CORE_LOCKING_INPUT, LWIP_TCPIP_CORE_LOCKING must be enabled, too" +#endif +#if LWIP_TCP && LWIP_NETIF_TX_SINGLE_PBUF && !TCP_OVERSIZE + #error "LWIP_NETIF_TX_SINGLE_PBUF needs TCP_OVERSIZE enabled to create single-pbuf TCP packets" +#endif +#if IP_FRAG && IP_FRAG_USES_STATIC_BUF && LWIP_NETIF_TX_SINGLE_PBUF + #error "LWIP_NETIF_TX_SINGLE_PBUF does not work with IP_FRAG_USES_STATIC_BUF==1 as that creates pbuf queues" +#endif +#if LWIP_NETCONN && LWIP_TCP +#if NETCONN_COPY != TCP_WRITE_FLAG_COPY + #error "NETCONN_COPY != TCP_WRITE_FLAG_COPY" +#endif +#if NETCONN_MORE != TCP_WRITE_FLAG_MORE + #error "NETCONN_MORE != TCP_WRITE_FLAG_MORE" +#endif +#endif /* LWIP_NETCONN && LWIP_TCP */ +#if LWIP_SOCKET +/* Check that the SO_* socket options and SOF_* lwIP-internal flags match */ +#if SO_ACCEPTCONN != SOF_ACCEPTCONN + #error "SO_ACCEPTCONN != SOF_ACCEPTCONN" +#endif +#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 +#if SO_LINGER != SOF_LINGER + #error "WARNING: SO_LINGER != SOF_LINGER" +#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 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 + +#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 !LWIP_DISABLE_MEMP_SANITY_CHECKS +#if LWIP_NETCONN +#if MEMP_MEM_MALLOC +#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 /* MEMP_MEM_MALLOC */ +#endif /* LWIP_NETCONN */ +#endif /* !LWIP_DISABLE_MEMP_SANITY_CHECKS */ + +/* 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_SNDQUEUELOWAT >= TCP_SND_QUEUELEN + #error "lwip_sanity_check: WARNING: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." +#endif +#if !MEMP_MEM_MALLOC && (PBUF_POOL_BUFSIZE <= (PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)) + #error "lwip_sanity_check: WARNING: PBUF_POOL_BUFSIZE does not provide enough space for protocol headers. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." +#endif +//#if !MEMP_MEM_MALLOC && (TCP_WND > (PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - (PBUF_LINK_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 */ + +/** + * 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; + /* Modules initialization */ + stats_init(); +#if !NO_SYS + sys_init(); +#endif /* !NO_SYS */ + mem_init(); + 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_IPV6 + ip6_init(); + nd6_init(); +#if LWIP_IPV6_MLD + mld6_init(); +#endif /* LWIP_IPV6_MLD */ +#endif /* LWIP_IPV6 */ + +#if LWIP_TIMERS + sys_timeouts_init(); +#endif /* LWIP_TIMERS */ +} diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv4/Makefile b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv4/Makefile new file mode 100644 index 0000000..660968b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv4/autoip.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv4/autoip.c new file mode 100644 index 0000000..b44b08b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv4/autoip.c @@ -0,0 +1,532 @@ +/** + * @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 + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#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) + + +/** 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); + + +/** 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 */ + 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; + } + 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/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv4/icmp.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv4/icmp.c new file mode 100644 index 0000000..c24b445 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv4/icmp.c @@ -0,0 +1,342 @@ +/** + * @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 "lwip/stats.h" +#include "lwip/snmp.h" + +#include + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#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; + struct ip_hdr *iphdr; + s16_t hlen; + + ICMP_STATS_INC(icmp.recv); + snmp_inc_icmpinmsgs(); + + iphdr = (struct ip_hdr *)ip_current_header(); + hlen = IPH_HL(iphdr) * 4; + 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). */ + break; + case ICMP_ECHO: +#if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING + { + int accepted = 1; +#if !LWIP_MULTICAST_PING + /* multicast destination address? */ + if (ip_addr_ismulticast(ip_current_dest_addr())) { + accepted = 0; + } +#endif /* LWIP_MULTICAST_PING */ +#if !LWIP_BROADCAST_PING + /* broadcast destination address? */ + if (ip_addr_isbroadcast(ip_current_dest_addr(), 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); +#if 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); + } +#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 + 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 +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 */ + 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; + 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; + + /* 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); + + /* calculate checksum */ + icmphdr->chksum = 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); + pbuf_free(q); +} + +#endif /* LWIP_ICMP */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv4/igmp.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv4/igmp.c new file mode 100644 index 0000000..38e08d7 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv4/igmp.c @@ -0,0 +1,809 @@ +/** + * @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 STORE_ATTR = __FILE__; +#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_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); +static err_t igmp_remove_group(struct igmp_group *group); +static void igmp_timeout( struct igmp_group *group); +static void igmp_start_timer(struct igmp_group *group, u8_t max_time); +static void igmp_delaying_member(struct igmp_group *group, u8_t maxresp); +static err_t igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif); +static void igmp_send(struct igmp_group *group, u8_t type); + + +static struct igmp_group* igmp_group_list; +static ip_addr_t allsystems; +static ip_addr_t allrouters; + + +/** + * Initialize the IGMP module + */ +void +igmp_init(void) +{ + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_init: initializing\n")); + + IP4_ADDR(&allsystems, 224, 0, 0, 1); + IP4_ADDR(&allrouters, 224, 0, 0, 2); +} + +#ifdef LWIP_DEBUG +/** + * Dump global IGMP groups list + */ +void +igmp_dump_group_list() +{ + struct igmp_group *group = igmp_group_list; + + while (group != NULL) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_dump_group_list: [%"U32_F"] ", (u32_t)(group->group_state))); + ip_addr_debug_print(IGMP_DEBUG, &group->group_address); + LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif)); + group = group->next; + } + LWIP_DEBUGF(IGMP_DEBUG, ("\n")); +} +#else +#define igmp_dump_group_list() +#endif /* LWIP_DEBUG */ + +/** + * Start IGMP processing on interface + * + * @param netif network interface on which start IGMP processing + */ +err_t +igmp_start(struct netif *netif) +{ + struct igmp_group* group; + + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %p\n", netif)); + + group = igmp_lookup_group(netif, &allsystems); + + if (group != NULL) { + group->group_state = IGMP_GROUP_IDLE_MEMBER; + group->use++; + + /* Allow the igmp messages at the MAC level */ + if (netif->igmp_mac_filter != NULL) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD ")); + ip_addr_debug_print(IGMP_DEBUG, &allsystems); + LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); + netif->igmp_mac_filter(netif, &allsystems, IGMP_ADD_MAC_FILTER); + } + + return ERR_OK; + } + + return ERR_MEM; +} + +/** + * Stop IGMP processing on interface + * + * @param netif network interface on which stop IGMP processing + */ +err_t +igmp_stop(struct netif *netif) +{ + struct igmp_group *group = igmp_group_list; + struct igmp_group *prev = NULL; + struct igmp_group *next; + + /* look for groups joined on this interface further down the list */ + while (group != NULL) { + next = group->next; + /* is it a group joined on this interface? */ + if (group->netif == netif) { + /* is it the first group of the list? */ + if (group == igmp_group_list) { + igmp_group_list = next; + } + /* is there a "previous" group defined? */ + if (prev != NULL) { + prev->next = next; + } + /* disable the group at the MAC level */ + if (netif->igmp_mac_filter != NULL) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL ")); + ip_addr_debug_print(IGMP_DEBUG, &group->group_address); + LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); + netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER); + } + /* free group */ + memp_free(MEMP_IGMP_GROUP, group); + } else { + /* change the "previous" */ + prev = group; + } + /* move to "next" */ + group = next; + } + return ERR_OK; +} + +/** + * Report IGMP memberships for this interface + * + * @param netif network interface on which report IGMP memberships + */ +void +igmp_report_groups(struct netif *netif) +{ + struct igmp_group *group = igmp_group_list; + + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", netif)); + + while (group != NULL) { + if (group->netif == netif) { + igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR); + } + group = group->next; + } +} + +/** + * Search for a group in the global igmp_group_list + * + * @param ifp the network interface for which to look + * @param addr the group ip address to search for + * @return a struct igmp_group* if the group has been found, + * NULL if the group wasn't found. + */ +struct igmp_group * +igmp_lookfor_group(struct netif *ifp, ip_addr_t *addr) +{ + struct igmp_group *group = igmp_group_list; + + while (group != NULL) { + if ((group->netif == ifp) && (ip_addr_cmp(&(group->group_address), addr))) { + return group; + } + group = group->next; + } + + /* to be clearer, we return NULL here instead of + * 'group' (which is also NULL at this point). + */ + return NULL; +} + +/** + * Search for a specific igmp group and create a new one if not found- + * + * @param ifp the network interface for which to look + * @param addr the group ip address to search + * @return a struct igmp_group*, + * NULL on memory error. + */ +struct igmp_group * +igmp_lookup_group(struct netif *ifp, ip_addr_t *addr) +{ + struct igmp_group *group = igmp_group_list; + + /* Search if the group already exists */ + group = igmp_lookfor_group(ifp, addr); + if (group != NULL) { + /* Group already exists. */ + return group; + } + + /* Group doesn't exist yet, create a new one */ + group = (struct igmp_group *)memp_malloc(MEMP_IGMP_GROUP); + if (group != NULL) { + group->netif = ifp; + ip_addr_set(&(group->group_address), addr); + group->timer = 0; /* Not running */ + group->group_state = IGMP_GROUP_NON_MEMBER; + group->last_reporter_flag = 0; + group->use = 0; + group->next = igmp_group_list; + + igmp_group_list = group; + } + + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to "))); + ip_addr_debug_print(IGMP_DEBUG, addr); + LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", ifp)); + + return group; +} + +/** + * Remove a group in the global igmp_group_list + * + * @param group the group to remove from the global igmp_group_list + * @return ERR_OK if group was removed from the list, an err_t otherwise + */ +static err_t +igmp_remove_group(struct igmp_group *group) +{ + err_t err = ERR_OK; + + /* Is it the first group? */ + if (igmp_group_list == group) { + igmp_group_list = group->next; + } else { + /* look for group further down the list */ + struct igmp_group *tmpGroup; + for (tmpGroup = igmp_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) { + if (tmpGroup->next == group) { + tmpGroup->next = group->next; + break; + } + } + /* Group not found in the global igmp_group_list */ + if (tmpGroup == NULL) + err = ERR_ARG; + } + /* free group */ + memp_free(MEMP_IGMP_GROUP, group); + + return err; +} + +/** + * Called from ip_input() if a new IGMP packet is received. + * + * @param p received igmp packet, p->payload pointing to the 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, ip_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 ")); + ip_addr_debug_print(IGMP_DEBUG, &(ip_current_header()->src)); + LWIP_DEBUGF(IGMP_DEBUG, (" to address ")); + ip_addr_debug_print(IGMP_DEBUG, &(ip_current_header()->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; + } +#ifdef LWIP_RAND + /* ensure the random value is > 0 */ + group->timer = (LWIP_RAND() % max_time); +#endif /* LWIP_RAND */ +} + +/** + * 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/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv4/ip4.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv4/ip4.c new file mode 100644 index 0000000..738a698 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv4/ip4.c @@ -0,0 +1,926 @@ +/** + * @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 + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#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 +#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(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 */ + +/** Global data for both IPv4 and IPv6 */ +struct ip_globals ip_data; + +/** 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; + +#ifdef LWIP_HOOK_IP4_ROUTE + netif = LWIP_HOOK_IP4_ROUTE(dest); + if (netif != NULL) { + return netif; + } +#endif + + /* 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 (!ip_addr_isbroadcast(dest, netif) && netif != netif_default) { + 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; +} + +#if IP_FORWARD +/** + * Determine whether an IP address is in a reserved set of addresses + * that may not be forwarded, or whether datagrams to that destination + * may be forwarded. + * @param p the packet to forward + * @param dest the destination IP address + * @return 1: can forward 0: discard + */ +static int +ip_canforward(struct pbuf *p) +{ + u32_t addr = htonl(ip4_addr_get_u32(ip_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 +ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp) +{ + struct netif *netif; + + PERF_START; + + if (!ip_canforward(p)) { + goto return_noroute; + } + + /* RFC3927 2.7: do not forward link-local addresses */ + if (ip_addr_islinklocal(ip_current_dest_addr())) { + LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not forwarding LLA %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(ip_current_dest_addr()), ip4_addr2_16(ip_current_dest_addr()), + ip4_addr3_16(ip_current_dest_addr()), ip4_addr4_16(ip_current_dest_addr()))); + goto return_noroute; + } + + /* Find network interface where to forward this IP packet to. */ + netif = ip_route(ip_current_dest_addr()); + 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(ip_current_dest_addr()), ip4_addr2_16(ip_current_dest_addr()), + ip4_addr3_16(ip_current_dest_addr()), ip4_addr4_16(ip_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, ("ip_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) { + 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(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, ("ip_forward: forwarding packet to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(ip_current_dest_addr()), ip4_addr2_16(ip_current_dest_addr()), + ip4_addr3_16(ip_current_dest_addr()), ip4_addr4_16(ip_current_dest_addr()))); + + IP_STATS_INC(ip.fw); + IP_STATS_INC(ip.xmit); + snmp_inc_ipforwdatagrams(); + + PERF_STOP("ip_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 + ip_frag(p, netif, ip_current_dest_addr()); +#else /* IP_FRAG */ + /* @todo: send ICMP Destination Unreacheable code 13 "Communication administratively prohibited"? */ +#endif /* IP_FRAG */ + } else { + /* send ICMP Destination Unreacheable code 4: "Fragmentation Needed and DF Set" */ + icmp_dest_unreach(p, ICMP_DUR_FRAG); + } + return; + } + /* transmit pbuf on chosen interface */ + netif->output(netif, p, ip_current_dest_addr()); + 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; + } + +#ifdef LWIP_HOOK_IP4_INPUT + if (LWIP_HOOK_IP4_INPUT(p, inp)) { + /* the packet has been eaten */ + return ERR_OK; + } +#endif + + /* obtain IP header length in number of 32-bit words */ + iphdr_hlen = IPH_HL(iphdr); + /* calculate IP header length in bytes */ + iphdr_hlen *= 4; + /* obtain ip length in bytes */ + iphdr_len = ntohs(IPH_LEN(iphdr)); + + /* 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(*ipX_2_ip(&ip_data.current_iphdr_dest), iphdr->dest); + ip_addr_copy(*ipX_2_ip(&ip_data.current_iphdr_src), iphdr->src); + + /* match packet against an interface, i.e. is this packet for us? */ +#if LWIP_IGMP + if (ip_addr_ismulticast(ip_current_dest_addr())) { + if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, ip_current_dest_addr()))) { + 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(ip_current_dest_addr(), &(netif->ip_addr)) || + /* or broadcast on this interface network address? */ + ip_addr_isbroadcast(ip_current_dest_addr(), 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(ip_current_dest_addr(), &(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(ip_current_src_addr())) +#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ + { if ((ip_addr_isbroadcast(ip_current_src_addr(), inp)) || + (ip_addr_ismulticast(ip_current_src_addr()))) { + /* 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(ip_current_dest_addr(), 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)); + + ip_data.current_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, -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 */ + 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, ip_current_dest_addr()); + break; +#endif /* LWIP_IGMP */ + default: +#if LWIP_ICMP + /* send ICMP destination protocol unreachable unless is was a broadcast */ + if (!ip_addr_isbroadcast(ip_current_dest_addr(), inp) && + !ip_addr_ismulticast(ip_current_dest_addr())) { + pbuf_header(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", IPH_PROTO(iphdr))); + + IP_STATS_INC(ip.proterr); + IP_STATS_INC(ip.drop); + snmp_inc_ipinunknownprotos(); + } + } + + /* @todo: this is not really necessary... */ + ip_data.current_netif = NULL; + ip_data.current_ip4_header = NULL; + ip_data.current_ip_header_tot_len = 0; + ip_addr_set_any(ip_current_src_addr()); + ip_addr_set_any(ip_current_dest_addr()); + + return ERR_OK; +} + +/** + * Sends an IP packet on a network interface. This function constructs + * the IP header and calculates the IP header checksum. If the source + * IP address is NULL, the IP address of the outgoing network + * interface is filled in as source address. + * If the destination IP address is IP_HDRINCL, p is assumed to already + * include an IP header and p->payload points to it instead of the data. + * + * @param p the packet to send (p->payload points to the data, e.g. next + protocol header; if dest == IP_HDRINCL, p already includes an IP + header and p->payload points to that IP header) + * @param src the source IP address to send from (if src == IP_ADDR_ANY, the + * IP address of the netif used to send is used as source address) + * @param dest the destination IP address to send the packet to + * @param ttl the TTL value to be set in the IP header + * @param tos the TOS value to be set in the IP header + * @param proto the PROTOCOL to be set in the IP header + * @param netif the netif on which to send this packet + * @return ERR_OK if the packet was sent OK + * ERR_BUF if p doesn't have enough space for IP/LINK headers + * returns errors returned by netif->output + * + * @note ip_id: RFC791 "some host may be able to simply use + * unique identifiers independent of destination" + */ +err_t +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 */ + 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_VHL_SET(iphdr, 4, ip_hlen / 4); + IPH_TOS_SET(iphdr, tos); +#if CHECKSUM_GEN_IP_INLINE + chk_sum += LWIP_MAKE_U16(tos, iphdr->_v_hl); +#endif /* CHECKSUM_GEN_IP_INLINE */ + IPH_LEN_SET(iphdr, htons(p->tot_len)); +#if CHECKSUM_GEN_IP_INLINE + chk_sum += iphdr->_len; +#endif /* CHECKSUM_GEN_IP_INLINE */ + IPH_OFFSET_SET(iphdr, 0); + IPH_ID_SET(iphdr, htons(ip_id)); +#if CHECKSUM_GEN_IP_INLINE + chk_sum += iphdr->_id; +#endif /* CHECKSUM_GEN_IP_INLINE */ + ++ip_id; + + if (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()")); + 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_SET_HWADDRHINT(netif, addr_hint); + err = ip_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 +ip_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", + 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/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv4/ip4_addr.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv4/ip4_addr.c new file mode 100644 index 0000000..e641ea2 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv4/ip4_addr.c @@ -0,0 +1,434 @@ +/** + * @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 = { IPADDR_ANY }; +const ip_addr_t ip_addr_broadcast = { 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 = 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 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 + */ +#ifdef LWIP_ESP8266 +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); +} + +#else +int +ipaddr_aton(const char *cp, ip_addr_t *addr) +{ + u32_t val; + u8_t base; + char c; + u32_t parts[4]; + u32_t *pp = parts; + + c = *cp; + for (;;) { + /* + * Collect number up to ``.''. + * Values are specified as for C: + * 0x=hex, 0=octal, 1-9=decimal. + */ + if (!isdigit(c)) + return (0); + val = 0; + base = 10; + if (c == '0') { + c = *++cp; + if (c == 'x' || c == 'X') { + base = 16; + c = *++cp; + } else + base = 8; + } + for (;;) { + if (isdigit(c)) { + val = (val * base) + (int)(c - '0'); + c = *++cp; + } else if (base == 16 && isxdigit(c)) { + val = (val << 4) | (int)(c + 10 - (islower(c) ? 'a' : 'A')); + c = *++cp; + } else + break; + } + if (c == '.') { + /* + * Internet format: + * a.b.c.d + * a.b.c (with c treated as 16 bits) + * a.b (with b treated as 24 bits) + */ + if (pp >= parts + 3) { + return (0); + } + *pp++ = val; + c = *++cp; + } else + break; + } + /* + * Check for trailing characters. + */ + if (c != '\0' && !isspace(c)) { + return (0); + } + /* + * Concoct the address according to + * the number of parts specified. + */ + switch (pp - parts + 1) { + + case 0: + return (0); /* initial nondigit */ + + case 1: /* a -- 32 bits */ + break; + + case 2: /* a.b -- 8.24 bits */ + if (val > 0xffffffUL) { + return (0); + } + val |= parts[0] << 24; + break; + + case 3: /* a.b.c -- 8.8.16 bits */ + if (val > 0xffff) { + 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); + } + 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); +} +#endif + +/** + * 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/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv4/ip_frag.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv4/ip_frag.c new file mode 100644 index 0000000..4521085 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv4/ip_frag.c @@ -0,0 +1,867 @@ +/** + * @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 + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +#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); +static int ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev); + +/** + * Reassembly timer base function + * for both NO_SYS == 0 and 1 (!). + * + * Should be called every 1000 msec (defined by IP_TMR_INTERVAL). + */ +void +ip_reass_tmr(void) +{ + struct ip_reassdata *r, *prev = NULL; + + r = reassdatagrams; + while (r != NULL) { + /* Decrement the timer. Once it reaches 0, + * clean up the incomplete fragment assembly */ + if (r->timer > 0) { + r->timer--; + LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer dec %"U16_F"\n",(u16_t)r->timer)); + prev = r; + r = r->next; + } else { + /* reassembly timed out */ + struct ip_reassdata *tmp; + LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer timed out\n")); + tmp = r; + /* get the next pointer before freeing */ + r = r->next; + /* free the helper struct and all enqueued pbufs */ + ip_reass_free_complete_datagram(tmp, prev); + } + } +} + +/** + * Free a datagram (struct ip_reassdata) and all its pbufs. + * Updates the total count of enqueued pbufs (ip_reass_pbufcount), + * SNMP counters and sends an ICMP time exceeded packet. + * + * @param ipr datagram to free + * @param prev the previous datagram in the linked list + * @return the number of pbufs freed + */ +static int +ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev) +{ + u16_t pbufs_freed = 0; + u8_t clen; + struct pbuf *p; + struct ip_reass_helper *iprh; + + LWIP_ASSERT("prev != ipr", prev != ipr); + if (prev != NULL) { + LWIP_ASSERT("prev->next == ipr", prev->next == ipr); + } + + 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* +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; + } + } + 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_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 +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* +ip_frag_alloc_pbuf_custom_ref(void) +{ + return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF); +} + +/** Free a struct pbuf_custom_ref */ +static void +ip_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p) +{ + LWIP_ASSERT("p != NULL", p != NULL); + memp_free(MEMP_FRAG_PBUF, p); +} + +/** Free-callback function to free a 'struct pbuf_custom_ref', called by + * pbuf_free. */ +static void +ipfrag_free_pbuf_custom(struct pbuf *p) +{ + struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref*)p; + LWIP_ASSERT("pcr != NULL", pcr != NULL); + LWIP_ASSERT("pcr == p", (void*)pcr == (void*)p); + if (pcr->original != NULL) { + pbuf_free(pcr->original); + } + ip_frag_free_pbuf_custom_ref(pcr); +} +#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */ +#endif /* IP_FRAG_USES_STATIC_BUF */ + +/** + * Fragment an IP datagram if too large for the netif. + * + * Chop the datagram in MTU sized chunks and send them in order + * by using a fixed size static memory buffer (PBUF_REF) or + * point PBUF_REFs into p (depending on IP_FRAG_USES_STATIC_BUF). + * + * @param p ip packet to send + * @param netif the netif on which to send + * @param dest destination ip address to which to send + * + * @return ERR_OK if sent successfully, err_t otherwise + */ +err_t +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/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/Makefile b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/Makefile new file mode 100644 index 0000000..56d4f02 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/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 = liblwipipv6.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/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/README b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/README new file mode 100644 index 0000000..3620004 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/README @@ -0,0 +1 @@ +IPv6 support in lwIP is very experimental. diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/dhcp6.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/dhcp6.c new file mode 100644 index 0000000..9656c3b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/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_DHCP6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip6_addr.h" +#include "lwip/def.h" + + +#endif /* LWIP_IPV6_DHCP6 */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/ethip6.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/ethip6.c new file mode 100644 index 0000000..ab9783a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/ethip6.c @@ -0,0 +1,193 @@ +/** + * @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 + +#define ETHTYPE_IPV6 0x86DD + +/** The ethernet address */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct eth_addr { + PACK_STRUCT_FIELD(u8_t addr[6]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Ethernet header */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +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) + +/** + * Send an IPv6 packet on the network using netif->linkoutput + * The ethernet header is filled in before sending. + * + * @params netif the lwIP network interface on which to send the packet + * @params p the packet to send, p->payload pointing to the (uninitialized) ethernet header + * @params src the source MAC address to be copied into the ethernet header + * @params dst the destination MAC address to be copied into the ethernet header + * @return ERR_OK if the packet was sent, any other err_t on failure + */ +static err_t +ethip6_send(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct eth_addr *dst) +{ + struct eth_hdr *ethhdr = (struct eth_hdr *)p->payload; + + LWIP_ASSERT("netif->hwaddr_len must be 6 for ethip6!", + (netif->hwaddr_len == 6)); + SMEMCPY(ðhdr->dest, dst, 6); + SMEMCPY(ðhdr->src, src, 6); + ethhdr->type = PP_HTONS(ETHTYPE_IPV6); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("ethip6_send: sending packet %p\n", (void *)p)); + /* send the packet */ + return netif->linkoutput(netif, p); +} + +/** + * Resolve and fill-in Ethernet address header for outgoing IPv6 packet. + * + * For IPv6 multicast, corresponding Ethernet addresses + * are selected and the packet is transmitted on the link. + * + * For unicast addresses, ... + * + * @TODO anycast addresses + * + * @param netif The lwIP network interface which the IP packet will be sent on. + * @param q The pbuf(s) containing the IP packet to be sent. + * @param ip6addr The IP address of the packet destination. + * + * @return + * - ERR_RTE No route to destination (no gateway to external networks), + * or the return type of either etharp_query() or etharp_send_ip(). + */ +err_t +ethip6_output(struct netif *netif, struct pbuf *q, ip6_addr_t *ip6addr) +{ + struct eth_addr dest; + s8_t i; + + /* make room for Ethernet header - should not fail */ + if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) { + /* bail out */ + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, + ("etharp_output: could not allocate room for header.\n")); + return ERR_BUF; + } + + /* multicast destination IP address? */ + if (ip6_addr_ismulticast(ip6addr)) { + /* Hash IP multicast address to MAC address.*/ + dest.addr[0] = 0x33; + dest.addr[1] = 0x33; + dest.addr[2] = ((u8_t *)(&(ip6addr->addr[3])))[0]; + dest.addr[3] = ((u8_t *)(&(ip6addr->addr[3])))[1]; + dest.addr[4] = ((u8_t *)(&(ip6addr->addr[3])))[2]; + dest.addr[5] = ((u8_t *)(&(ip6addr->addr[3])))[3]; + + /* Send out. */ + return ethip6_send(netif, q, (struct eth_addr*)(netif->hwaddr), &dest); + } + + /* We have a unicast destination IP address */ + /* TODO anycast? */ + /* Get next hop record. */ + i = nd6_get_next_hop_entry(ip6addr, netif); + if (i < 0) { + /* failed to get a next hop neighbor record. */ + return ERR_MEM; + } + + /* Now that we have a destination record, send or queue the packet. */ + if (neighbor_cache[i].state == ND6_STALE) { + /* Switch to delay state. */ + neighbor_cache[i].state = ND6_DELAY; + neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME; + } + /* TODO should we send or queue if PROBE? send for now, to let unicast NS pass. */ + if ((neighbor_cache[i].state == ND6_REACHABLE) || + (neighbor_cache[i].state == ND6_DELAY) || + (neighbor_cache[i].state == ND6_PROBE)) { + + /* Send out. */ + SMEMCPY(dest.addr, neighbor_cache[i].lladdr, 6); + return ethip6_send(netif, q, (struct eth_addr*)(netif->hwaddr), &dest); + } + + /* We should queue packet on this interface. */ + pbuf_header(q, -(s16_t)SIZEOF_ETH_HDR); + return nd6_queue_packet(i, q); +} + +#endif /* LWIP_IPV6 && LWIP_ETHERNET */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/icmp6.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/icmp6.c new file mode 100644 index 0000000..7f91d41 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/icmp6.c @@ -0,0 +1,342 @@ +/** + * @file + * + * IPv6 version of ICMP, as per RFC 4443. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#include "lwip/opt.h" + +#if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/icmp6.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/inet_chksum.h" +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/nd6.h" +#include "lwip/mld6.h" +#include "lwip/ip.h" +#include "lwip/stats.h" + +#include + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +#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; + 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 LWIP_ICMP6_CHECKSUM_CHECK + 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 /* LWIP_ICMP6_CHECKSUM_CHECK */ + + 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 = 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; + ((struct icmp6_echo_hdr *)(r->payload))->chksum = ip6_chksum_pseudo(r, + IP6_NEXTH_ICMP6, r->tot_len, reply_src, ip6_current_src_addr()); + + /* 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; + ip6_addr_t *reply_src, *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 = 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; + icmp6hdr->chksum = ip6_chksum_pseudo(q, IP6_NEXTH_ICMP6, q->tot_len, + reply_src, reply_dest); + + 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/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/inet6.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/inet6.c new file mode 100644 index 0000000..bdf4ff4 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/inet6.c @@ -0,0 +1,51 @@ +/** + * @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/inet6.h" + +/** @see ip6_addr.c for implementation of functions. */ + +#endif /* LWIP_IPV6 */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/ip6.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/ip6.c new file mode 100644 index 0000000..d1df3e3 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/ip6.c @@ -0,0 +1,1031 @@ +/** + * @file + * + * IPv6 layer. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + + +#include "lwip/opt.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/netif.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/ip6_frag.h" +#include "lwip/icmp6.h" +#include "lwip/raw.h" +#include "lwip/udp.h" +#include "lwip/tcp_impl.h" +#include "lwip/dhcp6.h" +#include "lwip/nd6.h" +#include "lwip/mld6.h" +#include "lwip/debug.h" +#include "lwip/stats.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#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(struct ip6_addr *src, struct ip6_addr *dest) +{ + struct netif *netif; + s8_t i; + + /* If single netif configuration, fast return. */ + if ((netif_list != NULL) && (netif_list->next == NULL)) { + return netif_list; + } + + /* Special processing for link-local addresses. */ + if (ip6_addr_islinklocal(dest)) { + if (ip6_addr_isany(src)) { + /* Use default netif. */ + return netif_default; + } + + /* Try to find the netif for the source address. */ + for(netif = netif_list; netif != NULL; netif = netif->next) { + 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 */ + return netif_default; + } + + /* See if the destination subnet matches a configured address. */ + for(netif = netif_list; netif != NULL; netif = netif->next) { + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && + ip6_addr_netcmp(dest, netif_ip6_addr(netif, i))) { + return netif; + } + } + } + + /* Get the netif for a suitable router. */ + i = nd6_select_router(dest, NULL); + if (i >= 0) { + if (default_router_list[i].neighbor_entry != NULL) { + if (default_router_list[i].neighbor_entry->netif != NULL) { + return default_router_list[i].neighbor_entry->netif; + } + } + } + + /* try with the netif that matches the source address. */ + if (!ip6_addr_isany(src)) { + for(netif = netif_list; netif != NULL; netif = netif->next) { + 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; + } + } + } + } + + /* no matching netif found, use default netif */ + return netif_default; +} + +/** + * Select the best IPv6 source address for a given destination + * IPv6 address. Loosely follows RFC 3484. "Strong host" behavior + * is assumed. + * + * @param netif the netif on which to send a packet + * @param dest the destination we are trying to reach + * @return the most suitable source address to use, or NULL if no suitable + * source address is found + */ +ip6_addr_t * +ip6_select_source_address(struct netif *netif, ip6_addr_t * dest) +{ + ip6_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_ip6_addr(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_ip6_addr(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_ip6_addr(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_ip6_addr(netif, i); + } + else { + /* Replace src only if we find a prefix match. */ + /* TODO find longest matching prefix. */ + if ((!(ip6_addr_netcmp(src, dest))) && + ip6_addr_netcmp(netif_ip6_addr(netif, i), dest)) { + src = netif_ip6_addr(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_ip6_addr(netif, i); + } + } + + return NULL; +} + +#if LWIP_IPV6_FORWARD +/** + * Forwards an IPv6 packet. It finds an appropriate route for the + * packet, decrements the HL value of the packet, and outputs + * the packet on the appropriate interface. + * + * @param p the packet to forward (p->payload points to IP header) + * @param iphdr the IPv6 header of the input packet + * @param inp the netif on which this packet was received + */ +static void +ip6_forward(struct pbuf *p, struct ip6_hdr *iphdr, struct netif *inp) +{ + struct netif *netif; + + /* do not forward link-local addresses */ + if (ip6_addr_islinklocal(ip6_current_dest_addr())) { + LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not forwarding link-local address.\n")); + IP6_STATS_INC(ip6.rterr); + IP6_STATS_INC(ip6.drop); + return; + } + + /* Find network interface where to forward this IP packet to. */ + netif = ip6_route(IP6_ADDR_ANY, 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; + } + + /* 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", + 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", + 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 */ + ip6_addr_copy(ip_data.current_iphdr_dest.ip6, ip6hdr->dest); + ip6_addr_copy(ip_data.current_iphdr_src.ip6, ip6hdr->src); + + /* 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; + + /* match packet against an interface, i.e. is this packet for us? */ + if (ip6_addr_ismulticast(ip6_current_dest_addr())) { + /* Always joined to multicast if-local and link-local all-nodes group. */ + if (ip6_addr_isallnodes_iflocal(ip6_current_dest_addr()) || + ip6_addr_isallnodes_linklocal(ip6_current_dest_addr())) { + netif = inp; + } +#if LWIP_IPV6_MLD + else if (mld6_lookfor_group(inp, ip6_current_dest_addr())) { + netif = inp; + } +#else /* LWIP_IPV6_MLD */ + else if (ip6_addr_issolicitednode(ip6_current_dest_addr())) { + /* Filter solicited node packets when MLD is not enabled + * (for Neighbor discovery). */ + netif = NULL; + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(inp, i)) && + ip6_addr_cmp_solicitednode(ip6_current_dest_addr(), netif_ip6_addr(inp, i))) { + netif = inp; + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: solicited node packet accepted on interface %c%c\n", + netif->name[0], netif->name[1])); + break; + } + } + } +#endif /* LWIP_IPV6_MLD */ + else { + netif = NULL; + } + } + else { + /* start trying with inp. if that's not acceptable, start walking the + list of configured netifs. + 'first' is used as a boolean to mark whether we started walking the list */ + int first = 1; + netif = inp; + do { + /* interface is up? */ + if (netif_is_up(netif)) { + /* unicast to this interface address? address configured? */ + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && + ip6_addr_cmp(ip6_current_dest_addr(), netif_ip6_addr(netif, i))) { + /* exit outer loop */ + goto netif_found; + } + } + } + if (ip6_addr_islinklocal(ip6_current_dest_addr())) { + /* Do not match link-local addresses to other netifs. */ + netif = NULL; + break; + } + if (first) { + first = 0; + netif = netif_list; + } else { + netif = netif->next; + } + if (netif == inp) { + netif = netif->next; + } + } while(netif != NULL); +netif_found: + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet accepted on interface %c%c\n", + netif ? netif->name[0] : 'X', netif? netif->name[1] : 'X')); + } + + /* "::" packet source address? (used in duplicate address detection) */ + if (ip6_addr_isany(ip6_current_src_addr()) && + (!ip6_addr_issolicitednode(ip6_current_dest_addr()))) { + /* packet source is not valid */ + /* free (drop) packet pbufs */ + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with src ANY_ADDRESS dropped\n")); + pbuf_free(p); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; + } + + /* packet not for us? */ + if (netif == NULL) { + /* packet not for us, route or discard */ + LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_TRACE, ("ip6_input: packet not for us.\n")); +#if LWIP_IPV6_FORWARD + /* non-multicast packet? */ + if (!ip6_addr_ismulticast(ip6_current_dest_addr())) { + /* try to forward IP packet on (other) interfaces */ + ip6_forward(p, ip6hdr, inp); + } +#endif /* LWIP_IPV6_FORWARD */ + pbuf_free(p); + goto ip6_input_cleanup; + } + + /* current netif pointer. */ + ip_data.current_netif = netif; + + /* Save next header type. */ + nexth = IP6H_NEXTH(ip6hdr); + + /* Init header length. */ + hlen = ip_data.current_ip_header_tot_len = IP6_HLEN; + + /* Move to payload. */ + pbuf_header(p, -IP6_HLEN); + + /* Process known option extension headers, if present. */ + while (nexth != IP6_NEXTH_NONE) + { + switch (nexth) { + case IP6_NEXTH_HOPBYHOP: + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Hop-by-Hop options header\n")); + /* Get next header type. */ + nexth = *((u8_t *)p->payload); + + /* Get the header length. */ + hlen = 8 * (1 + *((u8_t *)p->payload + 1)); + ip_data.current_ip_header_tot_len += hlen; + + /* Skip over this header. */ + if (hlen > p->len) { + LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n", + hlen, p->len)); + /* free (drop) packet pbufs */ + pbuf_free(p); + IP6_STATS_INC(ip6.lenerr); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; + } + + pbuf_header(p, -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, -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, -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 & IP6_FRAG_OFFSET_MASK) == 0) && + ((frag_hdr->_fragment_offset & 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, -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(p, ip_data.current_ip_header_tot_len); + + /* send to upper layers */ + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: \n")); + ip6_debug_print(p); + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len)); + +#if LWIP_RAW + /* raw input did not eat the packet? */ + if (raw_input(p, inp) == 0) +#endif /* LWIP_RAW */ + { + switch (nexth) { + case IP6_NEXTH_NONE: + pbuf_free(p); + break; +#if LWIP_UDP + case IP6_NEXTH_UDP: +#if LWIP_UDPLITE + case IP6_NEXTH_UDPLITE: +#endif /* LWIP_UDPLITE */ + /* Point to payload. */ + pbuf_header(p, -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, -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, -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", 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_ip6_header = NULL; + ip_data.current_ip_header_tot_len = 0; + ip6_addr_set_any(&ip_data.current_iphdr_src.ip6); + ip6_addr_set_any(&ip_data.current_iphdr_dest.ip6); + + return ERR_OK; +} + + +/** + * Sends an IPv6 packet on a network interface. This function constructs + * the IPv6 header. If the source IPv6 address is NULL, the IPv6 "ANY" address is + * used as source (usually during network startup). If the source IPv6 address it + * IP6_ADDR_ANY, the most appropriate IPv6 address of the outgoing network + * interface is filled in as source address. If the destination IPv6 address is + * IP_HDRINCL, p is assumed to already include an IPv6 header and p->payload points + * to it instead of the data. + * + * @param p the packet to send (p->payload points to the data, e.g. next + protocol header; if dest == IP_HDRINCL, p already includes an + IPv6 header and p->payload points to that IPv6 header) + * @param src the source IPv6 address to send from (if src == IP6_ADDR_ANY, an + * IP address of the netif is selected and used as source address. + * if src == NULL, IP6_ADDR_ANY is used as source) + * @param dest the destination IPv6 address to send the packet to + * @param hl the Hop Limit value to be set in the IPv6 header + * @param tc the Traffic Class value to be set in the IPv6 header + * @param nexth the Next Header to be set in the IPv6 header + * @param netif the netif on which to send this packet + * @return ERR_OK if the packet was sent OK + * ERR_BUF if p doesn't have enough space for IPv6/LINK headers + * returns errors returned by netif->output + */ +err_t +ip6_output_if(struct pbuf *p, ip6_addr_t *src, 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; + + /* 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); + + /* Should the IPv6 header be generated or is it already included in p? */ + if (dest != IP_HDRINCL) { + /* generate IPv6 header */ + if (pbuf_header(p, IP6_HLEN)) { + LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_output: not enough room for IPv6 header in pbuf\n")); + IP6_STATS_INC(ip6.err); + return ERR_BUF; + } + + ip6hdr = (struct ip6_hdr *)p->payload; + LWIP_ASSERT("check that first pbuf can hold struct ip6_hdr", + (p->len >= sizeof(struct ip6_hdr))); + + IP6H_HOPLIM_SET(ip6hdr, hl); + IP6H_NEXTH_SET(ip6hdr, nexth); + + /* dest cannot be NULL here */ + ip6_addr_copy(ip6hdr->dest, *dest); + + IP6H_VTCFL_SET(ip6hdr, 6, tc, 0); + IP6H_PLEN_SET(ip6hdr, p->tot_len - IP6_HLEN); + + if (src == NULL) { + src = IP6_ADDR_ANY; + } + else if (ip6_addr_isany(src)) { + src = ip6_select_source_address(netif, dest); + if ((src == NULL) || ip6_addr_isany(src)) { + /* No appropriate source address was found for this packet. */ + LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_output: No suitable source address for packet.\n")); + IP6_STATS_INC(ip6.rterr); + return ERR_RTE; + } + } + /* 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], netif->num)); + ip6_debug_print(p); + +#if ENABLE_LOOPBACK + /* TODO implement loopback for v6 + if (ip6_addr_cmp(dest, netif_ip6_addr(0))) { + return netif_loop_output(netif, p, dest); + }*/ +#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()")); + return netif->output_ip6(netif, p, dest); +} + +/** + * Simple interface to ip6_output_if. It finds the outgoing network + * interface and calls upon ip6_output_if to do the actual work. + * + * @param p the packet to send (p->payload points to the data, e.g. next + protocol header; if dest == IP_HDRINCL, p already includes an + IPv6 header and p->payload points to that IPv6 header) + * @param src the source IPv6 address to send from (if src == IP6_ADDR_ANY, an + * IP address of the netif is selected and used as source address. + * if src == NULL, IP6_ADDR_ANY is used as source) + * @param dest the destination IPv6 address to send the packet to + * @param hl the Hop Limit value to be set in the IPv6 header + * @param tc the Traffic Class value to be set in the IPv6 header + * @param nexth the Next Header to be set in the IPv6 header + * + * @return ERR_RTE if no route is found + * see ip_output_if() for more return values + */ +err_t +ip6_output(struct pbuf *p, ip6_addr_t *src, 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; + + /* pbufs passed to IPv6 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 (dest != IP_HDRINCL) { + netif = ip6_route(src, dest); + } else { + /* IP header included in p, read addresses. */ + ip6hdr = (struct ip6_hdr *)p->payload; + ip6_addr_copy(src_addr, ip6hdr->src); + ip6_addr_copy(dest_addr, ip6hdr->dest); + netif = ip6_route(&src_addr, &dest_addr); + } + + if (netif == NULL) { + LWIP_DEBUGF(IP6_DEBUG, ("ip6_output: no route for %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n", + IP6_ADDR_BLOCK1(dest), + IP6_ADDR_BLOCK2(dest), + IP6_ADDR_BLOCK3(dest), + IP6_ADDR_BLOCK4(dest), + IP6_ADDR_BLOCK5(dest), + IP6_ADDR_BLOCK6(dest), + IP6_ADDR_BLOCK7(dest), + IP6_ADDR_BLOCK8(dest))); + IP6_STATS_INC(ip6.rterr); + return ERR_RTE; + } + + return ip6_output_if(p, src, dest, hl, tc, nexth, netif); +} + + +#if LWIP_NETIF_HWADDRHINT +/** Like ip6_output, but takes and addr_hint pointer that is passed on to netif->addr_hint + * before calling ip6_output_if. + * + * @param p the packet to send (p->payload points to the data, e.g. next + protocol header; if dest == IP_HDRINCL, p already includes an + IPv6 header and p->payload points to that IPv6 header) + * @param src the source IPv6 address to send from (if src == IP6_ADDR_ANY, an + * IP address of the netif is selected and used as source address. + * if src == NULL, IP6_ADDR_ANY is used as source) + * @param dest the destination IPv6 address to send the packet to + * @param hl the Hop Limit value to be set in the IPv6 header + * @param tc the Traffic Class value to be set in the IPv6 header + * @param nexth the Next Header to be set in the IPv6 header + * @param addr_hint address hint pointer set to netif->addr_hint before + * calling ip_output_if() + * + * @return ERR_RTE if no route is found + * see ip_output_if() for more return values + */ +err_t +ip6_output_hinted(struct pbuf *p, ip6_addr_t *src, 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; + + /* 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 (dest != IP_HDRINCL) { + netif = ip6_route(src, dest); + } else { + /* IP header included in p, read addresses. */ + ip6hdr = (struct ip6_hdr *)p->payload; + ip6_addr_copy(src_addr, ip6hdr->src); + ip6_addr_copy(dest_addr, ip6hdr->dest); + netif = ip6_route(&src_addr, &dest_addr); + } + + if (netif == NULL) { + LWIP_DEBUGF(IP6_DEBUG, ("ip6_output: no route for %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n", + IP6_ADDR_BLOCK1(dest), + IP6_ADDR_BLOCK2(dest), + IP6_ADDR_BLOCK3(dest), + IP6_ADDR_BLOCK4(dest), + IP6_ADDR_BLOCK5(dest), + IP6_ADDR_BLOCK6(dest), + IP6_ADDR_BLOCK7(dest), + IP6_ADDR_BLOCK8(dest))); + IP6_STATS_INC(ip6.rterr); + return ERR_RTE; + } + + NETIF_SET_HWADDRHINT(netif, addr_hint); + err = ip6_output_if(p, src, dest, hl, tc, nexth, netif); + NETIF_SET_HWADDRHINT(netif, NULL); + + return err; +} +#endif /* LWIP_NETIF_HWADDRHINT*/ + +#if LWIP_IPV6_MLD +/** + * Add a hop-by-hop options header with a router alert option and padding. + * + * Used by MLD when sending a Multicast listener report/done message. + * + * @param p the packet to which we will prepend the options header + * @param nexth the next header protocol number (e.g. IP6_NEXTH_ICMP6) + * @param value the value of the router alert option data (e.g. IP6_ROUTER_ALERT_VALUE_MLD) + * @return ERR_OK if hop-by-hop header was added, ERR_* otherwise + */ +err_t +ip6_options_add_hbh_ra(struct pbuf * p, u8_t nexth, u8_t value) +{ + struct ip6_hbh_hdr * hbh_hdr; + + /* Move pointer to make room for hop-by-hop options header. */ + if (pbuf_header(p, sizeof(struct ip6_hbh_hdr))) { + LWIP_DEBUGF(IP6_DEBUG, ("ip6_options: no space for options header\n")); + IP6_STATS_INC(ip6.err); + return ERR_BUF; + } + + hbh_hdr = (struct ip6_hbh_hdr *)p->payload; + + /* Set fields. */ + hbh_hdr->_nexth = nexth; + hbh_hdr->_hlen = 0; + hbh_hdr->_ra_opt_type = IP6_ROUTER_ALERT_OPTION; + hbh_hdr->_ra_opt_dlen = 2; + hbh_hdr->_ra_opt_data = value; + hbh_hdr->_padn_opt_type = IP6_PADN_ALERT_OPTION; + hbh_hdr->_padn_opt_dlen = 0; + + return ERR_OK; +} +#endif /* LWIP_IPV6_MLD */ + +#if IP6_DEBUG +/* Print an IPv6 header by using LWIP_DEBUGF + * @param p an IPv6 packet, p->payload pointing to the IPv6 header + */ +void +ip6_debug_print(struct pbuf *p) +{ + struct ip6_hdr *ip6hdr = (struct ip6_hdr *)p->payload; + + LWIP_DEBUGF(IP6_DEBUG, ("IPv6 header:\n")); + LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP6_DEBUG, ("| %2"U16_F" | %3"U16_F" | %7"U32_F" | (ver, class, flow)\n", + IP6H_V(ip6hdr), + IP6H_TC(ip6hdr), + IP6H_FL(ip6hdr))); + LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP6_DEBUG, ("| %5"U16_F" | %3"U16_F" | %3"U16_F" | (plen, nexth, hopl)\n", + IP6H_PLEN(ip6hdr), + IP6H_NEXTH(ip6hdr), + IP6H_HOPLIM(ip6hdr))); + LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" | (src)\n", + IP6_ADDR_BLOCK1(&(ip6hdr->src)), + IP6_ADDR_BLOCK2(&(ip6hdr->src)), + IP6_ADDR_BLOCK3(&(ip6hdr->src)), + IP6_ADDR_BLOCK4(&(ip6hdr->src)))); + LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" |\n", + IP6_ADDR_BLOCK5(&(ip6hdr->src)), + IP6_ADDR_BLOCK6(&(ip6hdr->src)), + IP6_ADDR_BLOCK7(&(ip6hdr->src)), + IP6_ADDR_BLOCK8(&(ip6hdr->src)))); + LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" | (dest)\n", + IP6_ADDR_BLOCK1(&(ip6hdr->dest)), + IP6_ADDR_BLOCK2(&(ip6hdr->dest)), + IP6_ADDR_BLOCK3(&(ip6hdr->dest)), + IP6_ADDR_BLOCK4(&(ip6hdr->dest)))); + LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" |\n", + IP6_ADDR_BLOCK5(&(ip6hdr->dest)), + IP6_ADDR_BLOCK6(&(ip6hdr->dest)), + IP6_ADDR_BLOCK7(&(ip6hdr->dest)), + IP6_ADDR_BLOCK8(&(ip6hdr->dest)))); + LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); +} +#endif /* IP6_DEBUG */ + +#endif /* LWIP_IPV6 */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/ip6_addr.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/ip6_addr.c new file mode 100644 index 0000000..65d2798 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/ip6_addr.c @@ -0,0 +1,251 @@ +/** + * @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/ip6_addr.h" +#include "lwip/def.h" + +/* used by IP6_ADDR_ANY in ip6_addr.h */ +const ip6_addr_t ip6_addr_any = { { 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 represenation (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] == ':') { + s++; + /* "::" found, set zeros */ + while (zero_blocks-- > 0) { + if (current_block_index & 0x1) { + addr_index++; + } + else { + if (addr) { + addr->addr[addr_index] = 0; + } + } + current_block_index++; + } + } + } else if (isxdigit(*s)) { + /* add current digit */ + current_block_value = (current_block_value << 4) + + (isdigit(*s) ? *s - '0' : + 10 + (islower(*s) ? *s - 'a' : *s - 'A')); + } else { + /* unexpected digit, space? CRLF? */ + break; + } + } + + if (addr) { + if (current_block_index & 0x1) { + addr->addr[addr_index++] |= current_block_value; + } + else { + addr->addr[addr_index] = current_block_value << 16; + } + } + + /* convert to network byte order. */ + if (addr) { + for (addr_index = 0; addr_index < 4; addr_index++) { + addr->addr[addr_index] = htonl(addr->addr[addr_index]); + } + } + + if (current_block_index != 7) { + return 0; + } + + return 1; +} + +/** + * Convert numeric IPv6 address into ASCII representation. + * returns ptr to static buffer; not reentrant! + * + * @param addr ip6 address in network order to convert + * @return pointer to a global static (!) buffer that holds the ASCII + * represenation 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; + s32_t zero_flag, i; + + i = 0; + zero_flag = 0; /* used to indicate a zero chain for "::' */ + + for (current_block_index = 0; current_block_index < 8; current_block_index++) { + /* get the current 16-bit block */ + current_block_value = htonl(addr->addr[current_block_index >> 1]); + if ((current_block_index & 0x1) == 0) { + current_block_value = current_block_value >> 16; + } + current_block_value &= 0xffff; + + if (current_block_value == 0) { + /* generate empty block "::" */ + if (!zero_flag) { + if (current_block_index > 0) { + zero_flag = 1; + buf[i++] = ':'; + if (i >= buflen) return NULL; + } + } + } + else { + 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; + + zero_flag = 0; + } + } + + buf[i] = 0; + + return buf; +} +#endif /* LWIP_IPV6 */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/ip6_frag.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/ip6_frag.c new file mode 100644 index 0000000..02e4cef --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/ip6_frag.c @@ -0,0 +1,702 @@ +/** + * @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 + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +#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 */ + +#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; + + r = reassdatagrams; + while (r != NULL) { + /* Decrement the timer. Once it reaches 0, + * clean up the incomplete fragment assembly */ + if (r->timer > 0) { + r->timer--; + r = r->next; + } else { + /* reassembly timed out */ + tmp = r; + /* get the next pointer before freeing */ + r = r->next; + /* free the helper struct and all enqueued pbufs */ + ip6_reass_free_complete_datagram(tmp); + } + } +} + +/** + * Free a datagram (struct ip6_reassdata) and all its pbufs. + * Updates the total count of enqueued pbufs (ip6_reass_pbufcount), + * sends an ICMP time exceeded packet. + * + * @param ipr datagram to free + */ +static void +ip6_reass_free_complete_datagram(struct ip6_reassdata *ipr) +{ + struct ip6_reassdata *prev; + u16_t pbufs_freed = 0; + u8_t clen; + struct pbuf *p; + struct ip6_reass_helper *iprh; + +#if LWIP_ICMP6 + iprh = (struct ip6_reass_helper *)ipr->p->payload; + if (iprh->start == 0) { + /* The first fragment was received, send ICMP time exceeded. */ + /* First, de-queue the first pbuf from r->p. */ + p = ipr->p; + ipr->p = iprh->next_pbuf; + /* Then, move back to the original header (we are now pointing to Fragment header). */ + if (pbuf_header(p, (u8_t*)p->payload - (u8_t*)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 != 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 + * @param len the length of the payload (after Fragment Header) + * @return NULL if reassembly is incomplete, pbuf pointing to + * IPv6 Header if reassembly is complete + */ +struct pbuf * +ip6_reass(struct pbuf *p) +{ + struct ip6_reassdata *ipr, *ipr_prev; + struct ip6_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL; + struct ip6_frag_hdr * frag_hdr; + u16_t offset, len; + u8_t clen, valid = 1; + struct pbuf *q; + + IP6_FRAG_STATS_INC(ip6_frag.recv); + + frag_hdr = (struct ip6_frag_hdr *) p->payload; + + clen = pbuf_clen(p); + + offset = ntohs(frag_hdr->_fragment_offset); + + /* Calculate fragment length from IPv6 payload length. + * Adjust for headers before Fragment Header. + * And finally adjust by Fragment Header length. */ + len = ntohs(ip6_current_header()->_plen); + len -= ((u8_t*)p->payload - (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(), &(ipr->iphdr->src)) && + ip6_addr_cmp(ip6_current_dest_addr(), &(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) +#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). */ + ipr->iphdr = (struct ip6_hdr *)ip6_current_header(); + + /* 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) +#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. */ + 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) { + ipr->iphdr = (struct ip6_hdr *)ip6_current_header(); + } + + /* 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 */ + + /* chain together the pbufs contained within the ip6_reassdata list. */ + iprh = (struct ip6_reass_helper*) ipr->p->payload; + while(iprh != NULL) { + + if (iprh->next_pbuf != NULL) { + /* Save next helper struct (will be hidden in next step). */ + iprh_tmp = (struct ip6_reass_helper*) iprh->next_pbuf->payload; + + /* hide the fragment header for every succeding fragment */ + pbuf_header(iprh->next_pbuf, -IP6_FRAG_HLEN); + pbuf_cat(ipr->p, iprh->next_pbuf); + } + else { + iprh_tmp = NULL; + } + + iprh = iprh_tmp; + } + + /* Adjust datagram length by adding header lengths. */ + ipr->datagram_len += ((u8_t*)ipr->p->payload - (u8_t*)ipr->iphdr) + + IP6_FRAG_HLEN + - IP6_HLEN ; + + /* Set payload length in ip header. */ + ipr->iphdr->_plen = htons(ipr->datagram_len); + + /* Get the furst 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. */ + if (pbuf_header(p, (u8_t*)p->payload - (u8_t*)ipr->iphdr)) { + LWIP_ASSERT("ip6_reass: moving p->payload to ip6 header failed\n", 0); + pbuf_free(p); + return NULL; + } + + /* Return the pbuf chain */ + return p; + } + /* the datagram is not (yet?) reassembled completely */ + return NULL; + +nullreturn: + pbuf_free(p); + return NULL; +} + +#endif /* LWIP_IPV6 ^^ LWIP_IPV6_REASS */ + +#if LWIP_IPV6 && LWIP_IPV6_FRAG + +/** Allocate a new struct pbuf_custom_ref */ +static struct pbuf_custom_ref* +ip6_frag_alloc_pbuf_custom_ref(void) +{ + return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF); +} + +/** Free a struct pbuf_custom_ref */ +static void +ip6_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p) +{ + LWIP_ASSERT("p != NULL", p != NULL); + memp_free(MEMP_FRAG_PBUF, p); +} + +/** Free-callback function to free a 'struct pbuf_custom_ref', called by + * pbuf_free. */ +static void +ip6_frag_free_pbuf_custom(struct pbuf *p) +{ + struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref*)p; + LWIP_ASSERT("pcr != NULL", pcr != NULL); + LWIP_ASSERT("pcr == p", (void*)pcr == (void*)p); + if (pcr->original != NULL) { + pbuf_free(pcr->original); + } + ip6_frag_free_pbuf_custom_ref(pcr); +} + +/** + * Fragment an IPv6 datagram if too large for the netif or path MTU. + * + * Chop the datagram in MTU sized chunks and send them in order + * by pointing PBUF_REFs into p + * + * @param p ipv6 packet to send + * @param netif the netif on which to send + * @param dest destination ipv6 address to which to send + * + * @return ERR_OK if sent successfully, err_t otherwise + */ +err_t +ip6_frag(struct pbuf *p, struct netif *netif, ip6_addr_t *dest) +{ + struct ip6_hdr *original_ip6hdr; + struct ip6_hdr *ip6hdr; + struct ip6_frag_hdr * frag_hdr; + struct pbuf *rambuf; + struct pbuf *newpbuf; + static u32_t identification; + u16_t nfb; + u16_t left, cop; + u16_t mtu; + u16_t fragment_offset = 0; + u16_t last; + u16_t poff = IP6_HLEN; + u16_t newpbuflen = 0; + u16_t left_to_copy; + + identification++; + + original_ip6hdr = (struct ip6_hdr *)p->payload; + + mtu = nd6_get_destination_mtu(dest, netif); + + /* TODO we assume there are no options in the unfragmentable part (IPv6 header). */ + left = p->tot_len - IP6_HLEN; + + nfb = (mtu - (IP6_HLEN + IP6_FRAG_HLEN)) & IP6_FRAG_OFFSET_MASK; + + while (left) { + last = (left <= nfb); + + /* Fill this fragment */ + cop = last ? left : nfb; + + /* When not using a static buffer, create a chain of pbufs. + * The first will be a PBUF_RAM holding the link, IPv6, and Fragment header. + * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged, + * but limited to the size of an mtu. + */ + rambuf = pbuf_alloc(PBUF_LINK, IP6_HLEN + IP6_FRAG_HLEN, PBUF_RAM); + if (rambuf == NULL) { + IP6_FRAG_STATS_INC(ip6_frag.memerr); + return ERR_MEM; + } + LWIP_ASSERT("this needs a pbuf in one piece!", + (p->len >= (IP6_HLEN + IP6_FRAG_HLEN))); + SMEMCPY(rambuf->payload, original_ip6hdr, IP6_HLEN); + ip6hdr = (struct ip6_hdr *)rambuf->payload; + frag_hdr = (struct ip6_frag_hdr *)((u8_t*)rambuf->payload + IP6_HLEN); + + /* Can just adjust p directly for needed offset. */ + p->payload = (u8_t *)p->payload + poff; + p->len -= poff; + p->tot_len -= poff; + + left_to_copy = cop; + while (left_to_copy) { + struct pbuf_custom_ref *pcr; + newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len; + /* Is this pbuf already empty? */ + if (!newpbuflen) { + p = p->next; + continue; + } + pcr = ip6_frag_alloc_pbuf_custom_ref(); + if (pcr == NULL) { + pbuf_free(rambuf); + IP6_FRAG_STATS_INC(ip6_frag.memerr); + return ERR_MEM; + } + /* Mirror this pbuf, although we might not need all of it. */ + newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen); + if (newpbuf == NULL) { + ip6_frag_free_pbuf_custom_ref(pcr); + pbuf_free(rambuf); + IP6_FRAG_STATS_INC(ip6_frag.memerr); + return ERR_MEM; + } + pbuf_ref(p); + pcr->original = p; + pcr->pc.custom_free_function = ip6_frag_free_pbuf_custom; + + /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain + * so that it is removed when pbuf_dechain is later called on rambuf. + */ + pbuf_cat(rambuf, newpbuf); + left_to_copy -= newpbuflen; + if (left_to_copy) { + p = p->next; + } + } + poff = newpbuflen; + + /* Set headers */ + frag_hdr->_nexth = original_ip6hdr->_nexth; + frag_hdr->reserved = 0; + frag_hdr->_fragment_offset = htons((fragment_offset & IP6_FRAG_OFFSET_MASK) | (last ? 0 : IP6_FRAG_MORE_FLAG)); + frag_hdr->_identification = htonl(identification); + + IP6H_NEXTH_SET(ip6hdr, IP6_NEXTH_FRAGMENT); + IP6H_PLEN_SET(ip6hdr, cop + IP6_FRAG_HLEN); + + /* No need for separate header pbuf - we allowed room for it in rambuf + * when allocated. + */ + IP6_FRAG_STATS_INC(ip6_frag.xmit); + netif->output_ip6(netif, rambuf, dest); + + /* Unfortunately we can't reuse rambuf - the hardware may still be + * using the buffer. Instead we free it (and the ensuing chain) and + * recreate it next time round the loop. If we're lucky the hardware + * will have already sent the packet, the free will really free, and + * there will be zero memory penalty. + */ + + pbuf_free(rambuf); + left -= cop; + fragment_offset += cop; + } + return ERR_OK; +} + +#endif /* LWIP_IPV6 && LWIP_IPV6_FRAG */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/mld6.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/mld6.c new file mode 100644 index 0000000..86f07ed --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/mld6.c @@ -0,0 +1,584 @@ +/** + * @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 + * + */ + +/* Based on igmp.c implementation of igmp v2 protocol */ + +#include "lwip/opt.h" + +#if LWIP_IPV6 && LWIP_IPV6_MLD /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/mld6.h" +#include "lwip/icmp6.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/ip.h" +#include "lwip/inet_chksum.h" +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/memp.h" +#include "lwip/stats.h" + +#include + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +/* + * MLD constants + */ +#define MLD6_HL 1 +#define MLD6_JOIN_DELAYING_MEMBER_TMR_MS (500) + +#define MLD6_GROUP_NON_MEMBER 0 +#define MLD6_GROUP_DELAYING_MEMBER 1 +#define MLD6_GROUP_IDLE_MEMBER 2 + + +/* The list of joined groups. */ +static struct mld_group* mld_group_list; + + +/* Forward declarations. */ +static struct mld_group * mld6_new_group(struct netif *ifp, ip6_addr_t *addr); +static err_t mld6_free_group(struct mld_group *group); +static void mld6_delayed_report(struct mld_group *group, u16_t maxresp); +static void mld6_send(struct mld_group *group, u8_t type); + + +/** + * Stop MLD processing on interface + * + * @param netif network interface on which stop MLD processing + */ +err_t +mld6_stop(struct netif *netif) +{ + struct mld_group *group = mld_group_list; + struct mld_group *prev = NULL; + struct mld_group *next; + + /* look for groups joined on this interface further down the list */ + while (group != NULL) { + next = group->next; + /* is it a group joined on this interface? */ + if (group->netif == netif) { + /* is it the first group of the list? */ + if (group == mld_group_list) { + mld_group_list = next; + } + /* is there a "previous" group defined? */ + if (prev != NULL) { + prev->next = next; + } + /* disable the group at the MAC level */ + if (netif->mld_mac_filter != NULL) { + netif->mld_mac_filter(netif, &(group->group_address), MLD6_DEL_MAC_FILTER); + } + /* free group */ + memp_free(MEMP_MLD6_GROUP, group); + } else { + /* change the "previous" */ + prev = group; + } + /* move to "next" */ + group = next; + } + return ERR_OK; +} + +/** + * Report MLD memberships for this interface + * + * @param netif network interface on which report MLD memberships + */ +void +mld6_report_groups(struct netif *netif) +{ + struct mld_group *group = mld_group_list; + + while (group != NULL) { + if (group->netif == netif) { + mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS); + } + group = group->next; + } +} + +/** + * Search for a group that is joined on a netif + * + * @param ifp the network interface for which to look + * @param addr the group ipv6 address to search for + * @return a struct mld_group* if the group has been found, + * NULL if the group wasn't found. + */ +struct mld_group * +mld6_lookfor_group(struct netif *ifp, ip6_addr_t *addr) +{ + struct mld_group *group = mld_group_list; + + while (group != NULL) { + if ((group->netif == ifp) && (ip6_addr_cmp(&(group->group_address), addr))) { + return group; + } + group = group->next; + } + + return NULL; +} + + +/** + * create a new group + * + * @param ifp the network interface for which to create + * @param addr the new group ipv6 + * @return a struct mld_group*, + * NULL on memory error. + */ +static struct mld_group * +mld6_new_group(struct netif *ifp, ip6_addr_t *addr) +{ + struct mld_group *group; + + group = (struct mld_group *)memp_malloc(MEMP_MLD6_GROUP); + if (group != NULL) { + group->netif = ifp; + ip6_addr_set(&(group->group_address), addr); + group->timer = 0; /* Not running */ + group->group_state = MLD6_GROUP_IDLE_MEMBER; + group->last_reporter_flag = 0; + group->use = 0; + group->next = mld_group_list; + + mld_group_list = group; + } + + return group; +} + +/** + * Remove a group in the mld_group_list and free + * + * @param group the group to remove + * @return ERR_OK if group was removed from the list, an err_t otherwise + */ +static err_t +mld6_free_group(struct mld_group *group) +{ + err_t err = ERR_OK; + + /* Is it the first group? */ + if (mld_group_list == group) { + mld_group_list = group->next; + } else { + /* look for group further down the list */ + struct mld_group *tmpGroup; + for (tmpGroup = mld_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) { + if (tmpGroup->next == group) { + tmpGroup->next = group->next; + break; + } + } + /* Group not find group */ + if (tmpGroup == NULL) + err = ERR_ARG; + } + /* free group */ + memp_free(MEMP_MLD6_GROUP, group); + + return err; +} + + +/** + * Process an input MLD message. Called by icmp6_input. + * + * @param p the mld packet, p->payload pointing to the icmpv6 header + * @param inp the netif on which this packet was received + */ +void +mld6_input(struct pbuf *p, struct netif *inp) +{ + struct mld_header * mld_hdr; + struct mld_group* group; + + MLD6_STATS_INC(mld6.recv); + + /* Check that mld header fits in packet. */ + if (p->len < sizeof(struct mld_header)) { + /* TODO debug message */ + pbuf_free(p); + MLD6_STATS_INC(mld6.lenerr); + MLD6_STATS_INC(mld6.drop); + return; + } + + mld_hdr = (struct mld_header *)p->payload; + + switch (mld_hdr->type) { + case ICMP6_TYPE_MLQ: /* Multicast listener query. */ + { + /* Is it a general query? */ + if (ip6_addr_isallnodes_linklocal(ip6_current_dest_addr()) && + ip6_addr_isany(&(mld_hdr->multicast_address))) { + MLD6_STATS_INC(mld6.rx_general); + /* Report all groups, except all nodes group, and if-local groups. */ + group = mld_group_list; + while (group != NULL) { + if ((group->netif == inp) && + (!(ip6_addr_ismulticast_iflocal(&(group->group_address)))) && + (!(ip6_addr_isallnodes_linklocal(&(group->group_address))))) { + mld6_delayed_report(group, mld_hdr->max_resp_delay); + } + group = group->next; + } + } + else { + /* Have we joined this group? + * We use IP6 destination address to have a memory aligned copy. + * mld_hdr->multicast_address should be the same. */ + MLD6_STATS_INC(mld6.rx_group); + group = mld6_lookfor_group(inp, ip6_current_dest_addr()); + if (group != NULL) { + /* Schedule a report. */ + mld6_delayed_report(group, mld_hdr->max_resp_delay); + } + } + break; /* ICMP6_TYPE_MLQ */ + } + case ICMP6_TYPE_MLR: /* Multicast listener report. */ + { + /* Have we joined this group? + * We use IP6 destination address to have a memory aligned copy. + * mld_hdr->multicast_address should be the same. */ + MLD6_STATS_INC(mld6.rx_report); + group = mld6_lookfor_group(inp, ip6_current_dest_addr()); + if (group != NULL) { + /* If we are waiting to report, cancel it. */ + if (group->group_state == MLD6_GROUP_DELAYING_MEMBER) { + group->timer = 0; /* stopped */ + group->group_state = MLD6_GROUP_IDLE_MEMBER; + group->last_reporter_flag = 0; + } + } + break; /* ICMP6_TYPE_MLR */ + } + case ICMP6_TYPE_MLD: /* Multicast listener done. */ + { + /* Do nothing, router will query us. */ + break; /* ICMP6_TYPE_MLD */ + } + default: + MLD6_STATS_INC(mld6.proterr); + MLD6_STATS_INC(mld6.drop); + break; + } + + pbuf_free(p); +} + +/** + * 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(ip6_addr_t *srcaddr, ip6_addr_t *groupaddr) +{ + err_t err = ERR_VAL; /* no matching interface */ + struct mld_group *group; + struct netif *netif; + u8_t match; + u8_t i; + + /* loop through netif's */ + netif = netif_list; + while (netif != NULL) { + /* Should we join this interface ? */ + match = 0; + if (ip6_addr_isany(srcaddr)) { + match = 1; + } + else { + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_cmp(srcaddr, netif_ip6_addr(netif, i))) { + match = 1; + break; + } + } + } + if (match) { + /* find group or create a new one if not found */ + group = mld6_lookfor_group(netif, groupaddr); + + if (group == NULL) { + /* Joining a new group. Create a new group entry. */ + group = mld6_new_group(netif, groupaddr); + if (group == NULL) { + return ERR_MEM; + } + + /* Activate this address on the MAC layer. */ + if (netif->mld_mac_filter != NULL) { + netif->mld_mac_filter(netif, groupaddr, MLD6_ADD_MAC_FILTER); + } + + /* Report our membership. */ + MLD6_STATS_INC(mld6.tx_report); + mld6_send(group, ICMP6_TYPE_MLR); + mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS); + } + + /* Increment group use */ + group->use++; + err = ERR_OK; + } + + /* proceed to next network interface */ + netif = netif->next; + } + + return err; +} + +/** + * 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(ip6_addr_t *srcaddr, ip6_addr_t *groupaddr) +{ + err_t err = ERR_VAL; /* no matching interface */ + struct mld_group *group; + struct netif *netif; + u8_t match; + u8_t i; + + /* loop through netif's */ + netif = netif_list; + while (netif != NULL) { + /* Should we leave this interface ? */ + match = 0; + if (ip6_addr_isany(srcaddr)) { + match = 1; + } + else { + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_cmp(srcaddr, netif_ip6_addr(netif, i))) { + match = 1; + break; + } + } + } + if (match) { + /* find group */ + group = mld6_lookfor_group(netif, groupaddr); + + if (group != NULL) { + /* Leave if there is no other use of the group */ + if (group->use <= 1) { + /* If we are the last reporter for this group */ + if (group->last_reporter_flag) { + MLD6_STATS_INC(mld6.tx_leave); + mld6_send(group, ICMP6_TYPE_MLD); + } + + /* Disable the group at the MAC level */ + if (netif->mld_mac_filter != NULL) { + netif->mld_mac_filter(netif, groupaddr, MLD6_DEL_MAC_FILTER); + } + + /* Free the group */ + mld6_free_group(group); + } else { + /* Decrement group use */ + group->use--; + } + /* Leave on this interface */ + err = ERR_OK; + } + } + /* proceed to next network interface */ + netif = netif->next; + } + + return err; +} + + +/** + * Periodic timer for mld processing. Must be called every + * MLD6_TMR_INTERVAL milliseconds (100). + * + * When a delaying member expires, a membership report is sent. + */ +void +mld6_tmr(void) +{ + struct mld_group *group = mld_group_list; + + while (group != NULL) { + if (group->timer > 0) { + group->timer--; + if (group->timer == 0) { + /* If the state is MLD6_GROUP_DELAYING_MEMBER then we send a report for this group */ + if (group->group_state == MLD6_GROUP_DELAYING_MEMBER) { + MLD6_STATS_INC(mld6.tx_report); + mld6_send(group, ICMP6_TYPE_MLR); + group->group_state = MLD6_GROUP_IDLE_MEMBER; + } + } + } + group = group->next; + } +} + +/** + * Schedule a delayed membership report for a group + * + * @param group the mld_group for which "delaying" membership report + * should be sent + * @param maxresp the max resp delay provided in the query + */ +static void +mld6_delayed_report(struct mld_group *group, u16_t maxresp) +{ + /* Convert maxresp from milliseconds to tmr ticks */ + maxresp = maxresp / MLD6_TMR_INTERVAL; + if (maxresp == 0) { + maxresp = 1; + } + +#ifdef LWIP_RAND + /* Randomize maxresp. (if LWIP_RAND is supported) */ + maxresp = (LWIP_RAND() % (maxresp - 1)) + 1; +#endif /* LWIP_RAND */ + + /* Apply timer value if no report has been scheduled already. */ + if ((group->group_state == MLD6_GROUP_IDLE_MEMBER) || + ((group->group_state == MLD6_GROUP_DELAYING_MEMBER) && + ((group->timer == 0) || (maxresp < group->timer)))) { + group->timer = maxresp; + group->group_state = MLD6_GROUP_DELAYING_MEMBER; + } +} + +/** + * Send a MLD message (report or done). + * + * An IPv6 hop-by-hop options header with a router alert option + * is prepended. + * + * @param group the group to report or quit + * @param type ICMP6_TYPE_MLR (report) or ICMP6_TYPE_MLD (done) + */ +static void +mld6_send(struct mld_group *group, u8_t type) +{ + struct mld_header * mld_hdr; + struct pbuf * p; + 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) || (p->len < (sizeof(struct mld_header) + sizeof(struct ip6_hbh_hdr)))) { + /* We couldn't allocate a suitable pbuf. drop it. */ + if (p != NULL) { + pbuf_free(p); + } + MLD6_STATS_INC(mld6.memerr); + return; + } + + /* Move to make room for Hop-by-hop options header. */ + if (pbuf_header(p, -IP6_HBH_HLEN)) { + pbuf_free(p); + MLD6_STATS_INC(mld6.lenerr); + return; + } + + /* Select our source address. */ + if (!ip6_addr_isvalid(netif_ip6_addr_state(group->netif, 0))) { + /* This is a special case, when we are performing duplicate address detection. + * We must join the multicast group, but we don't have a valid address yet. */ + src_addr = IP6_ADDR_ANY; + } else { + /* Use link-local address as source address. */ + src_addr = netif_ip6_addr(group->netif, 0); + } + + /* MLD message header pointer. */ + mld_hdr = (struct mld_header *)p->payload; + + /* Set fields. */ + mld_hdr->type = type; + mld_hdr->code = 0; + mld_hdr->chksum = 0; + mld_hdr->max_resp_delay = 0; + mld_hdr->reserved = 0; + ip6_addr_set(&(mld_hdr->multicast_address), &(group->group_address)); + + mld_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, + src_addr, &(group->group_address)); + + /* Add hop-by-hop headers options: router alert with MLD value. */ + ip6_options_add_hbh_ra(p, IP6_NEXTH_ICMP6, IP6_ROUTER_ALERT_VALUE_MLD); + + /* Send the packet out. */ + MLD6_STATS_INC(mld6.xmit); + ip6_output_if(p, (ip6_addr_isany(src_addr)) ? NULL : src_addr, &(group->group_address), + MLD6_HL, 0, IP6_NEXTH_HOPBYHOP, group->netif); + pbuf_free(p); +} + + + +#endif /* LWIP_IPV6 */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/nd6.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/nd6.c new file mode 100644 index 0000000..b478c00 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/ipv6/nd6.c @@ -0,0 +1,1789 @@ +/** + * @file + * + * Neighbor discovery and stateless address autoconfiguration for IPv6. + * Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862 + * (Address autoconfiguration). + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#include "lwip/opt.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/nd6.h" +#include "lwip/pbuf.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/inet_chksum.h" +#include "lwip/netif.h" +#include "lwip/icmp6.h" +#include "lwip/mld6.h" +#include "lwip/ip.h" +#include "lwip/stats.h" + +#include + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#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(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(ip6_addr_t * ip6addr); +static s8_t nd6_new_destination_cache_entry(void); +static s8_t nd6_is_prefix_in_netif(ip6_addr_t * ip6addr, struct netif * netif); +static s8_t nd6_get_router(ip6_addr_t * router_addr, struct netif * netif); +static s8_t nd6_new_router(ip6_addr_t * router_addr, struct netif * netif); +static s8_t nd6_get_onlink_prefix(ip6_addr_t * prefix, struct netif * netif); +static s8_t nd6_new_onlink_prefix(ip6_addr_t * prefix, struct netif * netif); + +#define ND6_SEND_FLAG_MULTICAST_DEST 0x01 +#define ND6_SEND_FLAG_ALLNODES_DEST 0x02 +static void nd6_send_ns(struct netif * netif, ip6_addr_t * target_addr, u8_t flags); +static void nd6_send_na(struct netif * netif, ip6_addr_t * target_addr, u8_t flags); +#if LWIP_IPV6_SEND_ROUTER_SOLICIT +static void nd6_send_rs(struct netif * netif); +#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ + +#if LWIP_ND6_QUEUEING +static void nd6_free_q(struct nd6_q_entry *q); +#else /* LWIP_ND6_QUEUEING */ +#define nd6_free_q(q) pbuf_free(q) +#endif /* LWIP_ND6_QUEUEING */ +static void nd6_send_q(s8_t i); + + +/** + * Process an incoming neighbor discovery message + * + * @param p the nd packet, p->payload pointing to the icmpv6 header + * @param inp the netif on which this packet was received + */ +void +nd6_input(struct pbuf *p, struct netif *inp) +{ + u8_t msg_type; + s8_t i; + + ND6_STATS_INC(nd6.recv); + + msg_type = *((u8_t *)p->payload); + switch (msg_type) { + case ICMP6_TYPE_NA: /* Neighbor Advertisement. */ + { + struct na_header * na_hdr; + struct lladdr_option * lladdr_opt; + + /* Check that na header fits in packet. */ + if (p->len < (sizeof(struct na_header))) { + /* TODO debug message */ + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + return; + } + + na_hdr = (struct na_header *)p->payload; + + /* Unsolicited NA?*/ + if (ip6_addr_ismulticast(ip6_current_dest_addr())) { + /* This is an unsolicited NA. + * link-layer changed? + * part of DAD mechanism? */ + + /* Check that link-layer address option also fits in packet. */ + if (p->len < (sizeof(struct na_header) + sizeof(struct lladdr_option))) { + /* 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)); + + /* Override ip6_current_dest_addr() so that we have an aligned copy. */ + ip6_addr_set(ip6_current_dest_addr(), &(na_hdr->target_address)); + +#if LWIP_IPV6_DUP_DETECT_ATTEMPTS + /* If the target address matches this netif, it is a DAD response. */ + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_cmp(ip6_current_dest_addr(), netif_ip6_addr(inp, i))) { + /* We are using a duplicate address. */ + netif_ip6_addr_set_state(inp, i, IP6_ADDR_INVALID); + +#if LWIP_IPV6_MLD + /* Leave solicited node multicast group. */ + ip6_addr_set_solicitednode(&multicast_address, netif_ip6_addr(inp, i)->addr[3]); + mld6_leavegroup(netif_ip6_addr(inp, i), &multicast_address); +#endif /* LWIP_IPV6_MLD */ + + + + +#if LWIP_IPV6_AUTOCONFIG + /* Check to see if this address was autoconfigured. */ + if (!ip6_addr_islinklocal(ip6_current_dest_addr())) { + i = nd6_get_onlink_prefix(ip6_current_dest_addr(), inp); + if (i >= 0) { + /* Mark this prefix as duplicate, so that we don't use it + * to generate this address again. */ + prefix_list[i].flags |= ND6_PREFIX_AUTOCONFIG_ADDRESS_DUPLICATE; + } + } +#endif /* LWIP_IPV6_AUTOCONFIG */ + + pbuf_free(p); + return; + } + } +#endif /* LWIP_IPV6_DUP_DETECT_ATTEMPTS */ + + /* This is an unsolicited NA, most likely there was a LLADDR change. */ + i = nd6_find_neighbor_cache_entry(ip6_current_dest_addr()); + if (i >= 0) { + if (na_hdr->flags & ND6_FLAG_OVERRIDE) { + MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); + } + } + } + else { + /* This is a solicited NA. + * neighbor address resolution response? + * neighbor unreachability detection response? */ + + /* Override ip6_current_dest_addr() so that we have an aligned copy. */ + ip6_addr_set(ip6_current_dest_addr(), &(na_hdr->target_address)); + + /* Find the cache entry corresponding to this na. */ + i = nd6_find_neighbor_cache_entry(ip6_current_dest_addr()); + if (i < 0) { + /* We no longer care about this target address. drop it. */ + pbuf_free(p); + return; + } + + /* Update cache entry. */ + neighbor_cache[i].netif = inp; + neighbor_cache[i].counter.reachable_time = reachable_time; + if ((na_hdr->flags & ND6_FLAG_OVERRIDE) || + (neighbor_cache[i].state == ND6_INCOMPLETE)) { + /* Check that link-layer address option also fits in packet. */ + if (p->len < (sizeof(struct na_header) + sizeof(struct lladdr_option))) { + /* 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)); + + MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); + } + neighbor_cache[i].state = ND6_REACHABLE; + + /* Send queued packets, if any. */ + if (neighbor_cache[i].q != NULL) { + nd6_send_q(i); + } + } + + break; /* ICMP6_TYPE_NA */ + } + case ICMP6_TYPE_NS: /* Neighbor solicitation. */ + { + struct ns_header * ns_hdr; + struct lladdr_option * lladdr_opt; + u8_t accepted; + + /* Check that ns header fits in packet. */ + if (p->len < sizeof(struct ns_header)) { + /* TODO debug message */ + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + return; + } + + ns_hdr = (struct ns_header *)p->payload; + + /* Check if there is a link-layer address provided. Only point to it if in this buffer. */ + lladdr_opt = NULL; + if (p->len >= (sizeof(struct ns_header) + sizeof(struct lladdr_option))) { + lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct ns_header)); + } + + /* 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_cmp(&(ns_hdr->target_address), netif_ip6_addr(inp, i))) { + /* Send a NA back so that the sender does not use this address. */ + nd6_send_na(inp, netif_ip6_addr(inp, i), ND6_FLAG_OVERRIDE | ND6_SEND_FLAG_ALLNODES_DEST); + if (ip6_addr_istentative(netif_ip6_addr_state(inp, i))) { + /* We shouldn't use this address either. */ + netif_ip6_addr_set_state(inp, i, IP6_ADDR_INVALID); + } + } + } + } + else { + /* Sender is trying to resolve our address. */ + /* Verify that they included their own link-layer address. */ + if (lladdr_opt == NULL) { + /* Not a valid message. */ + pbuf_free(p); + ND6_STATS_INC(nd6.proterr); + ND6_STATS_INC(nd6.drop); + return; + } + + i = nd6_find_neighbor_cache_entry(ip6_current_src_addr()); + if ( i>= 0) { + /* We already have a record for the solicitor. */ + if (neighbor_cache[i].state == ND6_INCOMPLETE) { + neighbor_cache[i].netif = inp; + MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); + + /* Delay probe in case we get confirmation of reachability from upper layer (TCP). */ + neighbor_cache[i].state = ND6_DELAY; + neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME; + } + } + else + { + /* Add their IPv6 address and link-layer address to neighbor cache. + * We will need it at least to send a unicast NA message, but most + * likely we will also be communicating with this node soon. */ + i = nd6_new_neighbor_cache_entry(); + if (i < 0) { + /* We couldn't assign a cache entry for this neighbor. + * we won't be able to reply. drop it. */ + pbuf_free(p); + ND6_STATS_INC(nd6.memerr); + return; + } + neighbor_cache[i].netif = inp; + MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); + ip6_addr_set(&(neighbor_cache[i].next_hop_address), ip6_current_src_addr()); + + /* Receiving a message does not prove reachability: only in one direction. + * Delay probe in case we get confirmation of reachability from upper layer (TCP). */ + neighbor_cache[i].state = ND6_DELAY; + neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME; + } + + /* Override ip6_current_dest_addr() so that we have an aligned copy. */ + ip6_addr_set(ip6_current_dest_addr(), &(ns_hdr->target_address)); + + /* Send back a NA for us. Allocate the reply pbuf. */ + nd6_send_na(inp, ip6_current_dest_addr(), ND6_FLAG_SOLICITED | ND6_FLAG_OVERRIDE); + } + + break; /* ICMP6_TYPE_NS */ + } + case ICMP6_TYPE_RA: /* Router Advertisement. */ + { + struct ra_header * ra_hdr; + u8_t * buffer; /* Used to copy options. */ + u16_t offset; + + /* Check that RA header fits in packet. */ + if (p->len < sizeof(struct ra_header)) { + /* TODO debug message */ + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + return; + } + + ra_hdr = (struct ra_header *)p->payload; + + /* If we are sending RS messages, stop. */ +#if LWIP_IPV6_SEND_ROUTER_SOLICIT + 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 = ra_hdr->router_lifetime; + + /* Re-set default timer values. */ +#if LWIP_ND6_ALLOW_RA_UPDATES + if (ra_hdr->retrans_timer > 0) { + retrans_timer = ra_hdr->retrans_timer; + } + if (ra_hdr->reachable_time > 0) { + reachable_time = ra_hdr->reachable_time; + } +#endif /* LWIP_ND6_ALLOW_RA_UPDATES */ + + /* TODO set default hop limit... */ + /* ra_hdr->current_hop_limit;*/ + + /* Update flags in local entry (incl. preference). */ + default_router_list[i].flags = ra_hdr->flags; + + /* Offset to options. */ + offset = sizeof(struct ra_header); + + /* Process each option. */ + while ((p->tot_len - offset) > 0) { + if (p->len == p->tot_len) { + /* no need to copy from contiguous pbuf */ + buffer = &((u8_t*)p->payload)[offset]; + } else { + buffer = nd6_ra_buffer; + pbuf_copy_partial(p, buffer, sizeof(struct prefix_option), offset); + } + 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 (mtu_opt->mtu >= 1280) { +#if LWIP_ND6_ALLOW_RA_UPDATES + inp->mtu = ntohl(mtu_opt->mtu); +#endif /* LWIP_ND6_ALLOW_RA_UPDATES */ + } + break; + } + case ND6_OPTION_TYPE_PREFIX_INFO: + { + struct prefix_option * prefix_opt; + prefix_opt = (struct prefix_option *)buffer; + + if (prefix_opt->flags & ND6_PREFIX_FLAG_ON_LINK) { + /* Add to on-link prefix list. */ + + /* Get a memory-aligned copy of the prefix. */ + ip6_addr_set(ip6_current_dest_addr(), &(prefix_opt->prefix)); + + /* find cache entry for this prefix. */ + i = nd6_get_onlink_prefix(ip6_current_dest_addr(), inp); + if (i < 0) { + /* Create a new cache entry. */ + i = nd6_new_onlink_prefix(ip6_current_dest_addr(), inp); + } + if (i >= 0) { + prefix_list[i].invalidation_timer = 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[i].flags |= ND6_PREFIX_AUTOCONFIG_AUTONOMOUS; + } +#endif /* LWIP_IPV6_AUTOCONFIG */ + } + } + + break; + } + case ND6_OPTION_TYPE_ROUTE_INFO: + { + /* TODO implement preferred routes. + struct route_option * route_opt; + route_opt = (struct route_option *)buffer;*/ + + break; + } + default: + /* Unrecognized option, abort. */ + ND6_STATS_INC(nd6.proterr); + break; + } + offset += 8 * ((u16_t)buffer[1]); + } + + break; /* ICMP6_TYPE_RA */ + } + case ICMP6_TYPE_RD: /* Redirect */ + { + struct redirect_header * redir_hdr; + struct lladdr_option * lladdr_opt; + + /* Check that Redir header fits in packet. */ + if (p->len < sizeof(struct redirect_header)) { + /* TODO debug message */ + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + return; + } + + redir_hdr = (struct redirect_header *)p->payload; + + lladdr_opt = NULL; + if (p->len >= (sizeof(struct redirect_header) + sizeof(struct lladdr_option))) { + lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct redirect_header)); + } + + /* Copy original destination address to current source address, to have an aligned copy. */ + ip6_addr_set(ip6_current_src_addr(), &(redir_hdr->destination_address)); + + /* Find dest address in cache */ + i = nd6_find_destination_cache_entry(ip6_current_src_addr()); + if (i < 0) { + /* Destination not in cache, drop packet. */ + pbuf_free(p); + return; + } + + /* Set the new target address. */ + ip6_addr_set(&(destination_cache[i].next_hop_addr), &(redir_hdr->target_address)); + + /* If Link-layer address of other router is given, try to add to neighbor cache. */ + if (lladdr_opt != NULL) { + if (lladdr_opt->type == ND6_OPTION_TYPE_TARGET_LLADDR) { + /* Copy target address to current source address, to have an aligned copy. */ + ip6_addr_set(ip6_current_src_addr(), &(redir_hdr->target_address)); + + i = nd6_find_neighbor_cache_entry(ip6_current_src_addr()); + if (i < 0) { + i = nd6_new_neighbor_cache_entry(); + if (i >= 0) { + neighbor_cache[i].netif = inp; + MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); + ip6_addr_set(&(neighbor_cache[i].next_hop_address), ip6_current_src_addr()); + + /* Receiving a message does not prove reachability: only in one direction. + * Delay probe in case we get confirmation of reachability from upper layer (TCP). */ + neighbor_cache[i].state = ND6_DELAY; + neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME; + } + } + if (i >= 0) { + if (neighbor_cache[i].state == ND6_INCOMPLETE) { + MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); + /* Receiving a message does not prove reachability: only in one direction. + * Delay probe in case we get confirmation of reachability from upper layer (TCP). */ + neighbor_cache[i].state = ND6_DELAY; + neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME; + } + } + } + } + break; /* ICMP6_TYPE_RD */ + } + case ICMP6_TYPE_PTB: /* Packet too big */ + { + struct icmp6_hdr *icmp6hdr; /* Packet too big message */ + struct ip6_hdr * ip6hdr; /* IPv6 header of the packet which caused the error */ + + /* Check that ICMPv6 header + IPv6 header fit in payload */ + if (p->len < (sizeof(struct icmp6_hdr) + IP6_HLEN)) { + /* drop short packets */ + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + return; + } + + icmp6hdr = (struct icmp6_hdr *)p->payload; + ip6hdr = (struct ip6_hdr *)((u8_t*)p->payload + sizeof(struct icmp6_hdr)); + + /* Copy original destination address to current source address, to have an aligned copy. */ + ip6_addr_set(ip6_current_src_addr(), &(ip6hdr->dest)); + + /* Look for entry in destination cache. */ + i = nd6_find_destination_cache_entry(ip6_current_src_addr()); + if (i < 0) { + /* Destination not in cache, drop packet. */ + pbuf_free(p); + return; + } + + /* Change the Path MTU. */ + destination_cache[i].pmtu = icmp6hdr->data; + + 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, j; + 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) { + /* Retries exceeded. */ + nd6_free_neighbor_cache_entry(i); + } + else { + /* Send a NS for this entry. */ + neighbor_cache[i].counter.probes_sent++; + nd6_send_ns(neighbor_cache[i].netif, &(neighbor_cache[i].next_hop_address), ND6_SEND_FLAG_MULTICAST_DEST); + } + break; + case ND6_REACHABLE: + /* Send queued packets, if any are left. Should have been sent already. */ + if (neighbor_cache[i].q != NULL) { + nd6_send_q(i); + } + if (neighbor_cache[i].counter.reachable_time <= ND6_TMR_INTERVAL) { + /* Change to stale state. */ + neighbor_cache[i].state = ND6_STALE; + neighbor_cache[i].counter.stale_time = 0; + } + else { + neighbor_cache[i].counter.reachable_time -= ND6_TMR_INTERVAL; + } + break; + case ND6_STALE: + neighbor_cache[i].counter.stale_time += ND6_TMR_INTERVAL; + break; + case ND6_DELAY: + if (neighbor_cache[i].counter.delay_time <= ND6_TMR_INTERVAL) { + /* Change to PROBE state. */ + neighbor_cache[i].state = ND6_PROBE; + neighbor_cache[i].counter.probes_sent = 0; + } + else { + neighbor_cache[i].counter.delay_time -= ND6_TMR_INTERVAL; + } + break; + case ND6_PROBE: + if (neighbor_cache[i].counter.probes_sent >= LWIP_ND6_MAX_MULTICAST_SOLICIT) { + /* Retries exceeded. */ + nd6_free_neighbor_cache_entry(i); + } + else { + /* Send a NS for this entry. */ + neighbor_cache[i].counter.probes_sent++; + nd6_send_ns(neighbor_cache[i].netif, &(neighbor_cache[i].next_hop_address), 0); + } + break; + case ND6_NO_ENTRY: + default: + /* Do nothing. */ + break; + } + } + + /* Process destination entries. */ + for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { + destination_cache[i].age++; + } + + /* Process router entries. */ + for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { + if (default_router_list[i].neighbor_entry != NULL) { + /* Active entry. */ + if (default_router_list[i].invalidation_timer > 0) { + default_router_list[i].invalidation_timer -= ND6_TMR_INTERVAL / 1000; + } + if (default_router_list[i].invalidation_timer < ND6_TMR_INTERVAL / 1000) { + /* Less than 1 second remainig. 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].invalidation_timer < ND6_TMR_INTERVAL / 1000) { + prefix_list[i].invalidation_timer = 0; + } + if ((prefix_list[i].invalidation_timer > 0) && + (prefix_list[i].netif != NULL)) { + 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)) { + /* 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_ADDRESS_STATE_INVALID) { + /* Generate an address using this prefix and interface ID from link-local address. */ + prefix_list[i].netif->ip6_addr[j].addr[0] = prefix_list[i].prefix.addr[0]; + prefix_list[i].netif->ip6_addr[j].addr[1] = prefix_list[i].prefix.addr[1]; + prefix_list[i].netif->ip6_addr[j].addr[2] = prefix_list[i].netif->ip6_addr[0].addr[2]; + prefix_list[i].netif->ip6_addr[j].addr[3] = prefix_list[i].netif->ip6_addr[0].addr[3]; + + /* Mark it as tentative (DAD will be performed if configured). */ + netif_ip6_addr_set_state(prefix_list[i].netif, j, IP6_ADDR_TENTATIVE); + + /* Mark this prefix with ADDRESS_GENERATED, so that we don't try again. */ + prefix_list[i].flags |= ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED; + + /* Exit loop. */ + break; + } + } + } +#endif /* LWIP_IPV6_AUTOCONFIG */ + } + } + + + /* Process our own addresses, if DAD configured. */ + for (netif = netif_list; netif != NULL; netif = netif->next) { + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { + if (ip6_addr_istentative(netif->ip6_addr_state[i])) { + if ((netif->ip6_addr_state[i] & 0x07) >= LWIP_IPV6_DUP_DETECT_ATTEMPTS) { + /* No NA received in response. Mark address as valid. */ + netif->ip6_addr_state[i] = IP6_ADDR_PREFERRED; + /* TODO implement preferred and valid lifetimes. */ + } + else if (netif->flags & NETIF_FLAG_UP) { +#if LWIP_IPV6_MLD + if ((netif->ip6_addr_state[i] & 0x07) == 0) { + /* Join solicited node multicast group. */ + ip6_addr_set_solicitednode(&multicast_address, netif_ip6_addr(netif, i)->addr[3]); + mld6_joingroup(netif_ip6_addr(netif, i), &multicast_address); + } +#endif /* LWIP_IPV6_MLD */ + /* Send a NS for this address. */ + nd6_send_ns(netif, netif_ip6_addr(netif, i), ND6_SEND_FLAG_MULTICAST_DEST); + (netif->ip6_addr_state[i])++; + /* TODO send max 1 NS per tmr call? enable return*/ + /*return;*/ + } + } + } + } + +#if LWIP_IPV6_SEND_ROUTER_SOLICIT + /* Send router solicitation messages, if necessary. */ + for (netif = netif_list; netif != NULL; netif = netif->next) { + if ((netif->rs_count > 0) && (netif->flags & NETIF_FLAG_UP)) { + nd6_send_rs(netif); + netif->rs_count--; + } + } +#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ + +} + +/** + * Send a neighbor solicitation message + * + * @param netif the netif on which to send the message + * @param target_addr the IPv6 target address for the ND message + * @param flags one of ND6_SEND_FLAG_* + */ +static void +nd6_send_ns(struct netif * netif, ip6_addr_t * target_addr, u8_t flags) +{ + struct ns_header * ns_hdr; + struct lladdr_option * lladdr_opt; + struct pbuf * p; + ip6_addr_t * src_addr; + + if (ip6_addr_isvalid(netif_ip6_addr_state(netif,0))) { + /* Use link-local address as source address. */ + src_addr = netif_ip6_addr(netif, 0); + } else { + src_addr = IP6_ADDR_ANY; + } + + /* Allocate a packet. */ + p = pbuf_alloc(PBUF_IP, sizeof(struct ns_header) + sizeof(struct lladdr_option), PBUF_RAM); + if ((p == NULL) || (p->len < (sizeof(struct ns_header) + sizeof(struct lladdr_option)))) { + /* We couldn't allocate a suitable pbuf for the ns. drop it. */ + if (p != NULL) { + pbuf_free(p); + } + ND6_STATS_INC(nd6.memerr); + return; + } + + /* Set fields. */ + ns_hdr = (struct ns_header *)p->payload; + lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct ns_header)); + + 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); + + lladdr_opt->type = ND6_OPTION_TYPE_SOURCE_LLADDR; + lladdr_opt->length = ((netif->hwaddr_len + 2) >> 3) + (((netif->hwaddr_len + 2) & 0x07) ? 1 : 0); + 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; + } + + ns_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, + target_addr); + + /* Send the packet out. */ + ND6_STATS_INC(nd6.xmit); + ip6_output_if(p, (src_addr == IP6_ADDR_ANY) ? 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, ip6_addr_t * target_addr, u8_t flags) +{ + struct na_header * na_hdr; + struct lladdr_option * lladdr_opt; + struct pbuf * p; + ip6_addr_t * src_addr; + ip6_addr_t * dest_addr; + + /* Use link-local address as source address. */ + /* src_addr = &(netif->ip6_addr[0]); */ + /* Use target address as source address. */ + src_addr = target_addr; + + /* Allocate a packet. */ + p = pbuf_alloc(PBUF_IP, sizeof(struct na_header) + sizeof(struct lladdr_option), PBUF_RAM); + if ((p == NULL) || (p->len < (sizeof(struct na_header) + sizeof(struct lladdr_option)))) { + /* We couldn't allocate a suitable pbuf for the ns. drop it. */ + if (p != NULL) { + pbuf_free(p); + } + 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 = ((netif->hwaddr_len + 2) >> 3) + (((netif->hwaddr_len + 2) & 0x07) ? 1 : 0); + 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(); + } + + na_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, + dest_addr); + + /* 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 void +nd6_send_rs(struct netif * netif) +{ + struct rs_header * rs_hdr; + struct lladdr_option * lladdr_opt; + struct pbuf * p; + ip6_addr_t * src_addr; + u16_t packet_len; + + /* 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_ANY; + } + + /* Generate the all routers target address. */ + ip6_addr_set_allrouters_linklocal(&multicast_address); + + /* Allocate a packet. */ + packet_len = sizeof(struct rs_header); + if (src_addr != IP6_ADDR_ANY) { + packet_len += sizeof(struct lladdr_option); + } + p = pbuf_alloc(PBUF_IP, packet_len, PBUF_RAM); + if ((p == NULL) || (p->len < packet_len)) { + /* We couldn't allocate a suitable pbuf for the ns. drop it. */ + if (p != NULL) { + pbuf_free(p); + } + ND6_STATS_INC(nd6.memerr); + return; + } + + /* 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_ANY) { + /* 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 = ((netif->hwaddr_len + 2) >> 3) + (((netif->hwaddr_len + 2) & 0x07) ? 1 : 0); + SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len); + } + + rs_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, + &multicast_address); + + /* Send the packet out. */ + ND6_STATS_INC(nd6.xmit); + ip6_output_if(p, src_addr, &multicast_address, + LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif); + pbuf_free(p); +} +#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(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; + } + + /* 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(ip6_addr_t * ip6addr) +{ + s8_t i; + for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { + if (ip6_addr_cmp(ip6addr, &(destination_cache[i].destination_addr))) { + return i; + } + } + return -1; +} + +/** + * Create a new destination cache entry. If no unused entry is found, + * will recycle oldest entry. + * + * @return The destination cache entry index that was created, -1 if no + * entry was created + */ +static s8_t +nd6_new_destination_cache_entry(void) +{ + s8_t i, j; + u32_t age; + + /* Find an empty entry. */ + for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { + if (ip6_addr_isany(&(destination_cache[i].destination_addr))) { + return i; + } + } + + /* Find oldest entry. */ + age = 0; + j = LWIP_ND6_NUM_DESTINATIONS - 1; + for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { + if (destination_cache[i].age > age) { + j = i; + } + } + + return j; +} + +/** + * Determine whether an address matches an on-link prefix. + * + * @param ip6addr the IPv6 address to match + * @return 1 if the address is on-link, 0 otherwise + */ +static s8_t +nd6_is_prefix_in_netif(ip6_addr_t * ip6addr, struct netif * netif) +{ + s8_t i; + for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) { + if ((prefix_list[i].netif == netif) && + (prefix_list[i].invalidation_timer > 0) && + ip6_addr_netcmp(ip6addr, &(prefix_list[i].prefix))) { + return 1; + } + } + /* Check to see if address prefix matches a (manually?) configured address. */ + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && + ip6_addr_netcmp(ip6addr, netif_ip6_addr(netif, i))) { + return 1; + } + } + return 0; +} + +/** + * Select a default router for a destination. + * + * @param ip6addr the destination address + * @param netif the netif for the outgoing packet, if known + * @return the default router entry index, or -1 if no suitable + * router is found + */ +s8_t +nd6_select_router(ip6_addr_t * ip6addr, struct netif * netif) +{ + s8_t i; + /* last_router is used for round-robin router selection (as recommended + * in RFC). This is more robust in case one router is not reachable, + * we are not stuck trying to resolve it. */ + static s8_t last_router; + (void)ip6addr; /* TODO match preferred routes!! (must implement ND6_OPTION_TYPE_ROUTE_INFO) */ + + /* TODO: implement default router preference */ + + /* Look for reachable routers. */ + for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { + if (++last_router >= LWIP_ND6_NUM_ROUTERS) { + last_router = 0; + } + if ((default_router_list[i].neighbor_entry != NULL) && + (netif != NULL ? netif == default_router_list[i].neighbor_entry->netif : 1) && + (default_router_list[i].invalidation_timer > 0) && + (default_router_list[i].neighbor_entry->state == ND6_REACHABLE)) { + return i; + } + } + + /* Look for router in other reachability states, but still valid according to timer. */ + for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { + if (++last_router >= LWIP_ND6_NUM_ROUTERS) { + last_router = 0; + } + if ((default_router_list[i].neighbor_entry != NULL) && + (netif != NULL ? netif == default_router_list[i].neighbor_entry->netif : 1) && + (default_router_list[i].invalidation_timer > 0)) { + return i; + } + } + + /* Look for any router for which we have any information at all. */ + for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { + if (++last_router >= LWIP_ND6_NUM_ROUTERS) { + last_router = 0; + } + if (default_router_list[i].neighbor_entry != NULL && + (netif != NULL ? netif == default_router_list[i].neighbor_entry->netif : 1)) { + return i; + } + } + + /* no suitable router found. */ + return -1; +} + +/** + * Find an entry for a default router. + * + * @param router_addr the IPv6 address of the router + * @param netif the netif on which the router is found, if known + * @return the index of the router entry, or -1 if not found + */ +static s8_t +nd6_get_router(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(ip6_addr_t * router_addr, struct netif * netif) +{ + s8_t router_index; + s8_t neighbor_index; + + /* Do we have a neighbor entry for this router? */ + neighbor_index = nd6_find_neighbor_cache_entry(router_addr); + if (neighbor_index < 0) { + /* Create a neighbor entry for this router. */ + neighbor_index = nd6_new_neighbor_cache_entry(); + if (neighbor_index < 0) { + /* Could not create neighbor entry for this router. */ + return -1; + } + ip6_addr_set(&(neighbor_cache[neighbor_index].next_hop_address), router_addr); + neighbor_cache[neighbor_index].netif = netif; + neighbor_cache[neighbor_index].q = NULL; + neighbor_cache[neighbor_index].state = ND6_INCOMPLETE; + neighbor_cache[neighbor_index].counter.probes_sent = 0; + } + + /* Mark neighbor as router. */ + neighbor_cache[neighbor_index].isrouter = 1; + + /* Look for empty entry. */ + for (router_index = 0; router_index < LWIP_ND6_NUM_ROUTERS; router_index++) { + if (default_router_list[router_index].neighbor_entry == NULL) { + default_router_list[router_index].neighbor_entry = &(neighbor_cache[neighbor_index]); + return router_index; + } + } + + /* Could not create a router entry. */ + + /* Mark neighbor entry as not-router. Entry might be useful as neighbor still. */ + neighbor_cache[neighbor_index].isrouter = 0; + + /* router not found. */ + return -1; +} + +/** + * Find the cached entry for an on-link prefix. + * + * @param prefix the IPv6 prefix that is on-link + * @param netif the netif on which the prefix is on-link + * @return the index on the prefix table, or -1 if not found + */ +static s8_t +nd6_get_onlink_prefix(ip6_addr_t * prefix, struct netif * netif) +{ + s8_t i; + + /* Look for prefix in list. */ + for (i = 0; i < LWIP_ND6_NUM_PREFIXES; ++i) { + if ((ip6_addr_netcmp(&(prefix_list[i].prefix), prefix)) && + (prefix_list[i].netif == netif)) { + return i; + } + } + + /* Entry not available. */ + return -1; +} + +/** + * Creates a new entry for an on-link prefix. + * + * @param prefix the IPv6 prefix that is on-link + * @param netif the netif on which the prefix is on-link + * @return the index on the prefix table, or -1 if not created + */ +static s8_t +nd6_new_onlink_prefix(ip6_addr_t * prefix, struct netif * netif) +{ + s8_t i; + + /* Create new entry. */ + for (i = 0; i < LWIP_ND6_NUM_PREFIXES; ++i) { + if ((prefix_list[i].netif == NULL) || + (prefix_list[i].invalidation_timer == 0)) { + /* Found empty prefix entry. */ + prefix_list[i].netif = netif; + ip6_addr_set(&(prefix_list[i].prefix), prefix); + prefix_list[i].flags = 0; + return i; + } + } + + /* Entry not available. */ + return -1; +} + +/** + * Determine the next hop for a destination. Will determine if the + * destination is on-link, else a suitable on-link router is selected. + * + * The last entry index is cached for fast entry search. + * + * @param ip6addr the destination address + * @param netif the netif on which the packet will be sent + * @return the neighbor cache entry for the next hop, ERR_RTE if no + * suitable next hop was found, ERR_MEM if no cache entry + * could be created + */ +s8_t +nd6_get_next_hop_entry(ip6_addr_t * ip6addr, struct netif * netif) +{ + s8_t i; + +#if LWIP_NETIF_HWADDRHINT + if (netif->addr_hint != NULL) { + /* per-pcb cached entry was given */ + u8_t addr_hint = *(netif->addr_hint); + if (addr_hint < LWIP_ND6_NUM_DESTINATIONS) { + nd6_cached_destination_index = addr_hint; + } + } +#endif /* LWIP_NETIF_HWADDRHINT */ + + /* Look for ip6addr in destination cache. */ + if (ip6_addr_cmp(ip6addr, &(destination_cache[nd6_cached_destination_index].destination_addr))) { + /* the cached entry index is the right one! */ + /* do nothing. */ + ND6_STATS_INC(nd6.cachehit); + } else { + /* Search destination cache. */ + i = nd6_find_destination_cache_entry(ip6addr); + if (i >= 0) { + /* found destination entry. make it our new cached index. */ + nd6_cached_destination_index = i; + } + else { + /* Not found. Create a new destination entry. */ + i = nd6_new_destination_cache_entry(); + if (i >= 0) { + /* got new destination entry. make it our new cached index. */ + nd6_cached_destination_index = i; + } else { + /* Could not create a destination cache entry. */ + return ERR_MEM; + } + + /* Copy dest address to destination cache. */ + ip6_addr_set(&(destination_cache[nd6_cached_destination_index].destination_addr), ip6addr); + + /* Now find the next hop. is it a neighbor? */ + if (ip6_addr_islinklocal(ip6addr) || + nd6_is_prefix_in_netif(ip6addr, netif)) { + /* Destination in local link. */ + destination_cache[nd6_cached_destination_index].pmtu = netif->mtu; + ip6_addr_copy(destination_cache[nd6_cached_destination_index].next_hop_addr, destination_cache[nd6_cached_destination_index].destination_addr); + } + else { + /* We need to select a router. */ + i = nd6_select_router(ip6addr, netif); + if (i < 0) { + /* No router found. */ + ip6_addr_set_any(&(destination_cache[nd6_cached_destination_index].destination_addr)); + return ERR_RTE; + } + destination_cache[nd6_cached_destination_index].pmtu = netif->mtu; /* Start with netif mtu, correct through ICMPv6 if necessary */ + ip6_addr_copy(destination_cache[nd6_cached_destination_index].next_hop_addr, default_router_list[i].neighbor_entry->next_hop_address); + } + } + } + +#if LWIP_NETIF_HWADDRHINT + if (netif->addr_hint != NULL) { + /* per-pcb cached entry was given */ + *(netif->addr_hint) = nd6_cached_destination_index; + } +#endif /* LWIP_NETIF_HWADDRHINT */ + + /* Look in neighbor cache for the next-hop address. */ + if (ip6_addr_cmp(&(destination_cache[nd6_cached_destination_index].next_hop_addr), + &(neighbor_cache[nd6_cached_neighbor_index].next_hop_address))) { + /* Cache hit. */ + /* Do nothing. */ + ND6_STATS_INC(nd6.cachehit); + } else { + i = nd6_find_neighbor_cache_entry(&(destination_cache[nd6_cached_destination_index].next_hop_addr)); + if (i >= 0) { + /* Found a matching record, make it new cached entry. */ + nd6_cached_neighbor_index = i; + } + else { + /* Neighbor not in cache. Make a new entry. */ + i = nd6_new_neighbor_cache_entry(); + if (i >= 0) { + /* got new neighbor entry. make it our new cached index. */ + nd6_cached_neighbor_index = i; + } else { + /* Could not create a neighbor cache entry. */ + return ERR_MEM; + } + + /* Initialize fields. */ + ip6_addr_copy(neighbor_cache[i].next_hop_address, + destination_cache[nd6_cached_destination_index].next_hop_addr); + neighbor_cache[i].isrouter = 0; + neighbor_cache[i].netif = netif; + neighbor_cache[i].state = ND6_INCOMPLETE; + neighbor_cache[i].counter.probes_sent = 0; + } + } + + /* Reset this destination's age. */ + destination_cache[nd6_cached_destination_index].age = 0; + + return nd6_cached_neighbor_index; +} + +/** + * Queue a packet for a neighbor. + * + * @param neighbor_index the index in the neighbor cache table + * @param q packet to be queued + * @return ERR_OK if succeeded, ERR_MEM if out of memory + */ +err_t +nd6_queue_packet(s8_t neighbor_index, struct pbuf * q) +{ + err_t result = ERR_MEM; + struct pbuf *p; + int copy_needed = 0; +#if LWIP_ND6_QUEUEING + struct nd6_q_entry *new_entry, *r; +#endif /* LWIP_ND6_QUEUEING */ + + if ((neighbor_index < 0) || (neighbor_index >= LWIP_ND6_NUM_NEIGHBORS)) { + return ERR_ARG; + } + + /* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but + * to copy the whole queue into a new PBUF_RAM (see bug #11400) + * PBUF_ROMs can be left as they are, since ROM must not get changed. */ + p = q; + while (p) { + if(p->type != PBUF_ROM) { + copy_needed = 1; + break; + } + p = p->next; + } + if(copy_needed) { + /* copy the whole packet into new pbufs */ + p = pbuf_alloc(PBUF_LINK, q->tot_len, PBUF_RAM); + while ((p == NULL) && (neighbor_cache[neighbor_index].q != NULL)) { + /* Free oldest packet (as per RFC recommendation) */ +#if LWIP_ND6_QUEUEING + r = neighbor_cache[neighbor_index].q; + neighbor_cache[neighbor_index].q = r->next; + r->next = NULL; + nd6_free_q(r); +#else /* LWIP_ND6_QUEUEING */ + pbuf_free(neighbor_cache[neighbor_index].q); + neighbor_cache[neighbor_index].q = NULL; +#endif /* LWIP_ND6_QUEUEING */ + p = pbuf_alloc(PBUF_LINK, q->tot_len, PBUF_RAM); + } + if(p != NULL) { + if (pbuf_copy(p, q) != ERR_OK) { + pbuf_free(p); + p = NULL; + } + } + } else { + /* referencing the old pbuf is enough */ + p = q; + pbuf_ref(p); + } + /* packet was copied/ref'd? */ + if (p != NULL) { + /* queue packet ... */ +#if LWIP_ND6_QUEUEING + /* allocate a new nd6 queue entry */ + new_entry = (struct nd6_q_entry *)memp_malloc(MEMP_ND6_QUEUE); + if ((new_entry == NULL) && (neighbor_cache[neighbor_index].q != NULL)) { + /* Free oldest packet (as per RFC recommendation) */ + r = neighbor_cache[neighbor_index].q; + neighbor_cache[neighbor_index].q = r->next; + r->next = NULL; + nd6_free_q(r); + new_entry = (struct nd6_q_entry *)memp_malloc(MEMP_ND6_QUEUE); + } + if (new_entry != NULL) { + new_entry->next = NULL; + new_entry->p = p; + if(neighbor_cache[neighbor_index].q != NULL) { + /* queue was already existent, append the new entry to the end */ + r = neighbor_cache[neighbor_index].q; + while (r->next != NULL) { + r = r->next; + } + r->next = new_entry; + } else { + /* queue did not exist, first item in queue */ + neighbor_cache[neighbor_index].q = new_entry; + } + LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: queued packet %p on neighbor entry %"S16_F"\n", (void *)p, (s16_t)neighbor_index)); + result = ERR_OK; + } else { + /* the pool MEMP_ND6_QUEUE is empty */ + pbuf_free(p); + LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: could not queue a copy of packet %p (out of memory)\n", (void *)p)); + /* { result == ERR_MEM } through initialization */ + } +#else /* LWIP_ND6_QUEUEING */ + /* Queue a single packet. If an older packet is already queued, free it as per RFC. */ + if (neighbor_cache[neighbor_index].q != NULL) { + pbuf_free(neighbor_cache[neighbor_index].q); + } + neighbor_cache[neighbor_index].q = p; + LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: queued packet %p on neighbor entry %"S16_F"\n", (void *)p, (s16_t)neighbor_index)); + result = ERR_OK; +#endif /* LWIP_ND6_QUEUEING */ + } else { + LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: could not queue a copy of packet %p (out of memory)\n", (void *)q)); + /* { result == ERR_MEM } through initialization */ + } + + return result; +} + +#if LWIP_ND6_QUEUEING +/** + * Free a complete queue of nd6 q entries + * + * @param q a queue of nd6_q_entry to free + */ +static void +nd6_free_q(struct nd6_q_entry *q) +{ + struct nd6_q_entry *r; + LWIP_ASSERT("q != NULL", q != NULL); + LWIP_ASSERT("q->p != NULL", q->p != NULL); + while (q) { + r = q; + q = q->next; + LWIP_ASSERT("r->p != NULL", (r->p != NULL)); + pbuf_free(r->p); + memp_free(MEMP_ND6_QUEUE, r); + } +} +#endif /* LWIP_ND6_QUEUEING */ + +/** + * Send queued packets for a neighbor + * + * @param i the neighbor to send packets to + */ +static void +nd6_send_q(s8_t i) +{ + struct ip6_hdr *ip6hdr; +#if LWIP_ND6_QUEUEING + struct nd6_q_entry *q; +#endif /* LWIP_ND6_QUEUEING */ + + if ((i < 0) || (i >= LWIP_ND6_NUM_NEIGHBORS)) { + return; + } + +#if LWIP_ND6_QUEUEING + while (neighbor_cache[i].q != NULL) { + /* remember first in queue */ + q = neighbor_cache[i].q; + /* pop first item off the queue */ + neighbor_cache[i].q = q->next; + /* Get ipv6 header. */ + ip6hdr = (struct ip6_hdr *)(q->p->payload); + /* Override ip6_current_dest_addr() so that we have an aligned copy. */ + ip6_addr_set(ip6_current_dest_addr(), &(ip6hdr->dest)); + /* send the queued IPv6 packet */ + (neighbor_cache[i].netif)->output_ip6(neighbor_cache[i].netif, q->p, ip6_current_dest_addr()); + /* free the queued IP packet */ + pbuf_free(q->p); + /* now queue entry can be freed */ + memp_free(MEMP_ND6_QUEUE, q); + } +#else /* LWIP_ND6_QUEUEING */ + if (neighbor_cache[i].q != NULL) { + /* Get ipv6 header. */ + ip6hdr = (struct ip6_hdr *)(neighbor_cache[i].q->payload); + /* Override ip6_current_dest_addr() so that we have an aligned copy. */ + ip6_addr_set(ip6_current_dest_addr(), &(ip6hdr->dest)); + /* send the queued IPv6 packet */ + (neighbor_cache[i].netif)->output_ip6(neighbor_cache[i].netif, neighbor_cache[i].q, ip6_current_dest_addr()); + /* free the queued IP packet */ + pbuf_free(neighbor_cache[i].q); + neighbor_cache[i].q = NULL; + } +#endif /* LWIP_ND6_QUEUEING */ +} + + +/** + * Get the Path MTU for a destination. + * + * @param ip6addr the destination address + * @param netif the netif on which the packet will be sent + * @return the Path MTU, if known, or the netif default MTU + */ +u16_t +nd6_get_destination_mtu(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(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; + } + + /* Set reachability state. */ + neighbor_cache[i].state = ND6_REACHABLE; + neighbor_cache[i].counter.reachable_time = reachable_time; +} +#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ + +#endif /* LWIP_IPV6 */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/mem.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/mem.c new file mode 100644 index 0000000..e51a788 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/mem.c @@ -0,0 +1,664 @@ +/** + * @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 + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +#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) +{ + void *ret; + struct memp_malloc_helper *element; + memp_t poolnr; + mem_size_t required_size = size + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper)); + + for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr = (memp_t)(poolnr + 1)) { +#if MEM_USE_POOLS_TRY_BIGGER_POOL +again: +#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */ + /* is this pool big enough to hold an element of the required size + plus a struct memp_malloc_helper that saves the pool this element came from? */ + if (required_size <= memp_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 */ + ret = (u8_t*)element + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper)); + + 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 */ + 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)); + + /* 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; +}; + +/** 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 */ +u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT]; +#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 ... */ + 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 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 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 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 */ +/** + * 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, count * size); + } + return p; +} + +#endif /* !MEM_LIBC_MALLOC */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/memp.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/memp.c new file mode 100644 index 0000000..24fd91f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/memp.c @@ -0,0 +1,489 @@ +/** + * @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 "lwip/nd6.h" +#include "lwip/ip6_frag.h" +#include "lwip/mld6.h" + +#include + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +#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 STORE_ATTR = { +#define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEM_ALIGN_SIZE(size), +#include "lwip/memp_std.h" +}; + +#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) (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] = { +#define LWIP_MEMPOOL(name,num,size,desc) (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) u8_t memp_memory_ ## name ## _base \ + [((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))]; +#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) 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) + ( (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, using "Floyd's cycle-finding algorithm". + */ +static int +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) "/"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 +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 +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 +memp_overflow_check_all(void) +{ + u16_t i, j; + struct memp *p; + +#if !MEMP_SEPARATE_POOLS + p = (struct memp *)LWIP_MEM_ALIGN(memp_memory); +#endif /* !MEMP_SEPARATE_POOLS */ + for (i = 0; i < MEMP_MAX; ++i) { +#if MEMP_SEPARATE_POOLS + p = (struct memp *)(memp_bases[i]); +#endif /* MEMP_SEPARATE_POOLS */ + 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); + } + } +#if !MEMP_SEPARATE_POOLS + p = (struct memp *)LWIP_MEM_ALIGN(memp_memory); +#endif /* !MEMP_SEPARATE_POOLS */ + for (i = 0; i < MEMP_MAX; ++i) { +#if MEMP_SEPARATE_POOLS + p = (struct memp *)(memp_bases[i]); +#endif /* MEMP_SEPARATE_POOLS */ + 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 +memp_overflow_init(void) +{ + u16_t i, j; + struct memp *p; + u8_t *m; + +#if !MEMP_SEPARATE_POOLS + p = (struct memp *)LWIP_MEM_ALIGN(memp_memory); +#endif /* !MEMP_SEPARATE_POOLS */ + for (i = 0; i < MEMP_MAX; ++i) { +#if MEMP_SEPARATE_POOLS + p = (struct memp *)(memp_bases[i]); +#endif /* MEMP_SEPARATE_POOLS */ + 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; + 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]; + 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 = 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 */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/netif.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/netif.c new file mode 100644 index 0000000..0509b30 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/netif.c @@ -0,0 +1,942 @@ +/** + * @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/ip6_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_IPV6_DHCP6 +#include "lwip/dhcp6.h" +#endif /* LWIP_IPV6_DHCP6 */ +#if LWIP_IPV6_MLD +#include "lwip/mld6.h" +#endif /* LWIP_IPV6_MLD */ + +#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 */ + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +struct netif *netif_list; +struct netif *netif_default; + +static u8_t netif_num; + +#if LWIP_IPV6 +static err_t netif_null_output_ip6(struct netif *netif, struct pbuf *p, ip6_addr_t *ipaddr); +#endif /* LWIP_IPV6 */ + +#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 +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) +{ +#if LWIP_IPV6 + u32_t i; +#endif + + 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); +#if LWIP_IPV6 + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + ip6_addr_set_zero(&netif->ip6_addr[i]); + netif_ip6_addr_set_state(netif, i, IP6_ADDR_INVALID); + } + netif->output_ip6 = netif_null_output_ip6; +#endif /* LWIP_IPV6 */ + netif->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_IPV6_AUTOCONFIG + /* IPv6 address autoconfiguration not enabled by default */ + netif->ip6_autoconfig_enabled = 1; +#endif /* LWIP_IPV6_AUTOCONFIG */ +#if LWIP_IPV6_SEND_ROUTER_SOLICIT + netif->rs_count = LWIP_ND6_MAX_MULTICAST_SOLICIT; +#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ +#if LWIP_IPV6_DHCP6 + /* netif not under DHCPv6 control by default */ + netif->dhcp6 = NULL; +#endif /* LWIP_IPV6_DHCP6 */ +#if LWIP_NETIF_STATUS_CALLBACK + netif->status_callback = NULL; +#endif /* LWIP_NETIF_STATUS_CALLBACK */ +#if LWIP_NETIF_LINK_CALLBACK + netif->link_callback = NULL; +#endif /* LWIP_NETIF_LINK_CALLBACK */ +#if LWIP_IGMP + netif->igmp_mac_filter = NULL; +#endif /* LWIP_IGMP */ +#if LWIP_IPV6 && LWIP_IPV6_MLD + netif->mld_mac_filter = NULL; +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ +#if ENABLE_LOOPBACK + netif->loop_first = NULL; + netif->loop_last = NULL; +#endif /* ENABLE_LOOPBACK */ + + /* remember netif specific state information data */ + netif->state = state; + netif->num = netif_num++; + netif->input = input; + NETIF_SET_HWADDRHINT(netif, NULL); +#if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS + netif->loop_cnt_current = 0; +#endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */ + + 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 LWIP_IPV6 && LWIP_IPV6_MLD + /* stop MLD processing */ + mld6_stop(netif); +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ + if (netif_is_up(netif)) { + /* set netif down before removing (call callback function) */ + netif_set_down(netif); + } + + 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); + } +#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") ); +} + +/** + * 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(ipX_2_ip(&pcb->local_ip), &(netif->ip_addr)) +#if LWIP_AUTOIP + /* connections to link-local addresses must persist (RFC3927 ch. 1.9) */ + && !ip_addr_islinklocal(ipX_2_ip(&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(ipX_2_ip(&lpcb->local_ip)))) && + (ip_addr_cmp(ipX_2_ip(&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(ipX_2_ip(&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 */ +#if LWIP_IPV6 && LWIP_IPV6_MLD + /* send mld memberships */ + mld6_report_groups( netif); +#endif /* LWIP_IPV6 && 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 */ + + } + } +} + +/** + * 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->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 */ + +#if LWIP_NETIF_REMOVE_CALLBACK +/** + * 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 */ + +/** + * 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 */ +#if LWIP_IPV6 && LWIP_IPV6_MLD + /* send mld memberships */ + mld6_report_groups( netif); +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ + } + 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_with_block((tcpip_callback_fn)netif_poll, netif, 0); +#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 */ + +#if LWIP_IPV6 +s8_t +netif_matches_ip6_addr(struct netif * netif, ip6_addr_t * ip6addr) +{ + s8_t i; + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_cmp(netif_ip6_addr(netif, i), ip6addr)) { + return i; + } + } + return -1; +} + +static err_t +netif_null_output_ip6(struct netif *netif, struct pbuf *p, ip6_addr_t *ipaddr) +{ + (void)netif; + (void)p; + (void)ipaddr; + return ERR_IF; +} +#endif /*LWIP_IPV6*/ + +void +netif_create_ip6_linklocal_address(struct netif * netif, u8_t from_mac_48bit) +{ +#if LWIP_IPV6 + u8_t i, addr_index; + + /* Link-local prefix. */ + netif->ip6_addr[0].addr[0] = PP_HTONL(0xfe800000ul); + 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. */ + netif->ip6_addr[0].addr[2] = htonl((((u32_t)(netif->hwaddr[0] ^ 0x02)) << 24) | + ((u32_t)(netif->hwaddr[1]) << 16) | + ((u32_t)(netif->hwaddr[2]) << 8) | + (0xff)); + netif->ip6_addr[0].addr[3] = htonl((0xfeul << 24) | + ((u32_t)(netif->hwaddr[3]) << 16) | + ((u32_t)(netif->hwaddr[4]) << 8) | + (netif->hwaddr[5])); + } + else { + /* Use hwaddr directly as interface ID. */ + netif->ip6_addr[0].addr[2] = 0; + netif->ip6_addr[0].addr[3] = 0; + + addr_index = 3; + for (i = 0; i < 8; i++) { + if (i == 4) { + addr_index--; + } + netif->ip6_addr[0].addr[addr_index] |= ((u32_t)(netif->hwaddr[netif->hwaddr_len - i - 1])) << (8 * (i & 0x03)); + } + } + + ip6_addr_copy(netif->link_local_addr.ip6, netif->ip6_addr[0]); + + /* Set address state. */ +#if LWIP_IPV6_DUP_DETECT_ATTEMPTS + /* Will perform duplicate address detection (DAD). */ + netif->ip6_addr_state[0] = IP6_ADDR_TENTATIVE; +#else + /* Consider address valid. */ + netif->ip6_addr_state[0] = IP6_ADDR_PREFERRED; +#endif /* LWIP_IPV6_AUTOCONFIG */ + +#endif /*LWIP_IPV6*/ +} + +void +netif_create_ip4_linklocal_address(struct netif * netif) +{ +#if LWIP_IPV6 + ip_addr_t linklocal; + ip_addr_t linklocal_mask; + uint32_t addr = 0; + /* Link-local prefix and mask. */ + IP4_ADDR(&linklocal, 169, 254, 0, 0); + IP4_ADDR(&linklocal_mask, 255, 255, 0, 0); + + if (!ip_addr_netcmp(&linklocal, &netif->link_local_addr.ip4, &linklocal_mask) && + !ip_addr_isany(&netif->ip_addr)) { + IP4_ADDR(&netif->link_local_addr.ip4, 169, 254, ip4_addr3(&netif->ip_addr), ip4_addr4(&netif->ip_addr)); + return; + } + + while (!addr || !ip4_addr4(&addr)) + os_get_random((unsigned char *)&addr, sizeof(addr)); + + if (netif->netmask.addr > IP_CLASSB_NET && + !ip_addr_isany(&netif->ip_addr)) { // random host address + IP4_ADDR(&netif->link_local_addr.ip4, 169, 254, ip4_addr3(&netif->ip_addr), ip4_addr4(&addr)); + } else { + IP4_ADDR(&netif->link_local_addr.ip4, 169, 254, ip4_addr3(&addr), ip4_addr4(&addr)); + } +#endif /*LWIP_IPV6*/ +} + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/pbuf.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/pbuf.c new file mode 100644 index 0000000..54a81e2 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/pbuf.c @@ -0,0 +1,1242 @@ +/** + * @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 LWIP_TCP && 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 STORE_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) + +#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_DECL_PROTECT(old_level); + + SYS_ARCH_PROTECT(old_level); + pbuf_free_ooseq_pending = 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; + } + } +} + +#if !NO_SYS +/** + * Just a callback function for tcpip_timeout() 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_DECL_PROTECT(old_level); + SYS_ARCH_PROTECT(old_level); + pbuf_free_ooseq_pending = 1; + SYS_ARCH_UNPROTECT(old_level); +#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 */ + +/** + * 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 = 0; + 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_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN + EP_OFFSET; + break; + case PBUF_IP: + /* add room for IP layer header */ + offset = PBUF_LINK_HLEN + PBUF_IP_HLEN + EP_OFFSET; + break; + 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; + case PBUF_MAC: + offset = EP_OFFSET; + 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. + * 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_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN; + break; + case PBUF_IP: + /* add room for IP layer header */ + offset = PBUF_LINK_HLEN + PBUF_IP_HLEN; + break; + case PBUF_LINK: + /* add room for link layer header */ + offset = PBUF_LINK_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 */ + +/** + * 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) { + 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 + { + /* 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!\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 = strlen(substr); + if (substr_len >= 0xFFFF) { + return 0xFFFF; + } + return pbuf_memfind(p, substr, (u16_t)substr_len, 0); +} diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/raw.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/raw.c new file mode 100644 index 0000000..eeb15df --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/raw.c @@ -0,0 +1,426 @@ +/** + * @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 "lwip/ip6.h" +#include "lwip/ip6_addr.h" + +#include + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_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 +raw_input(struct pbuf *p, struct netif *inp) +{ + struct raw_pcb *pcb, *prev; + struct ip_hdr *iphdr; + s16_t proto; + u8_t eaten = 0; +#if LWIP_IPV6 + struct ip6_hdr *ip6hdr; +#endif /* LWIP_IPV6 */ + + + LWIP_UNUSED_ARG(inp); + + iphdr = (struct ip_hdr *)p->payload; +#if LWIP_IPV6 + if (IPH_V(iphdr) == 6) { + ip6hdr = (struct ip6_hdr *)p->payload; + proto = IP6H_NEXTH(ip6hdr); + } + else +#endif /* LWIP_IPV6 */ + { + 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_PCB_IPVER_INPUT_MATCH(pcb) && + (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip) || + ipX_addr_cmp(PCB_ISIPV6(pcb), &(pcb->local_ip), ipX_current_dest_addr()))) { +#if IP_SOF_BROADCAST_RECV + /* broadcast filter? */ + if ((ip_get_option(pcb, SOF_BROADCAST) || !ip_addr_isbroadcast(ip_current_dest_addr(), inp)) +#if LWIP_IPV6 + && !PCB_ISIPV6(pcb) +#endif /* LWIP_IPV6 */ + ) +#endif /* IP_SOF_BROADCAST_RECV */ + { + /* receive callback function available? */ + if (pcb->recv.ip4 != NULL) { +#ifndef LWIP_NOASSERT + void* old_payload = p->payload; +#endif + /* the receive callback function did not eat the packet? */ + eaten = pcb->recv.ip4(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; +} + +/** + * 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 +raw_bind(struct raw_pcb *pcb, ip_addr_t *ipaddr) +{ + ipX_addr_set_ipaddr(PCB_ISIPV6(pcb), &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 +raw_connect(struct raw_pcb *pcb, ip_addr_t *ipaddr) +{ + ipX_addr_set_ipaddr(PCB_ISIPV6(pcb), &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 +raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg) +{ + /* remember recv() callback and user data */ + pcb->recv.ip4 = 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 +raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr) +{ + err_t err; + struct netif *netif; + ipX_addr_t *src_ip; + struct pbuf *q; /* q will be sent down the stack */ + s16_t header_size; + ipX_addr_t *dst_ip = ip_2_ipX(ipaddr); + + LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n")); + + header_size = ( +#if LWIP_IPV6 + PCB_ISIPV6(pcb) ? IP6_HLEN : +#endif /* LWIP_IPV6 */ + IP_HLEN); + + /* not enough space to add an IP header to first pbuf in given p chain? */ + if (pbuf_header(p, header_size)) { + /* allocate header in new pbuf */ + q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM); + /* new header pbuf could not be allocated? */ + if (q == NULL) { + LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n")); + return ERR_MEM; + } + if (p->tot_len != 0) { + /* chain header q in front of given pbuf p */ + pbuf_chain(q, p); + } + /* { first pbuf q points to header pbuf } */ + LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p)); + } else { + /* first pbuf q equals given pbuf */ + q = p; + if(pbuf_header(q, -header_size)) { + LWIP_ASSERT("Can't restore header we just removed!", 0); + return ERR_MEM; + } + } + + netif = ipX_route(PCB_ISIPV6(pcb), &pcb->local_ip, dst_ip); + if (netif == NULL) { + LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to ")); + ipX_addr_debug_print(PCB_ISIPV6(pcb), RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, dst_ip); + /* free any temporary header pbuf allocated by pbuf_header() */ + if (q != p) { + pbuf_free(q); + } + return ERR_RTE; + } + +#if IP_SOF_BROADCAST +#if LWIP_IPV6 + /* @todo: why does IPv6 not filter broadcast with SOF_BROADCAST enabled? */ + if (!PCB_ISIPV6(pcb)) +#endif /* LWIP_IPV6 */ + { + /* 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 (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip)) { + /* use outgoing network interface IP address as source address */ + src_ip = ipX_netif_get_local_ipX(PCB_ISIPV6(pcb), netif, dst_ip); +#if LWIP_IPV6 + if (src_ip == NULL) { + if (q != p) { + pbuf_free(q); + } + return ERR_RTE; + } +#endif /* LWIP_IPV6 */ + } else { + /* use RAW PCB local IP address as source address */ + src_ip = &pcb->local_ip; + } + + NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint); + err = ipX_output_if(PCB_ISIPV6(pcb), q, ipX_2_ip(src_ip), ipX_2_ip(dst_ip), pcb->ttl, pcb->tos, pcb->protocol, netif); + NETIF_SET_HWADDRHINT(netif, NULL); + + /* did we chain a header earlier? */ + if (q != p) { + /* free the header */ + pbuf_free(q); + } + return err; +} + +/** + * 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, ipX_2_ip(&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 +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 * +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; +} + +#if LWIP_IPV6 +/** + * Create a RAW PCB for IPv6. + * + * @return The RAW PCB which was created. NULL if the PCB data structure + * could not be allocated. + * + * @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_ip6(u8_t proto) +{ + struct raw_pcb *pcb; + pcb = raw_new(proto); + ip_set_v6(pcb, 1); + return pcb; +} +#endif /* LWIP_IPV6 */ + +#endif /* LWIP_RAW */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/snmp/asn1_dec.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/snmp/asn1_dec.c new file mode 100644 index 0000000..1d56582 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/snmp/asn1_dec.c @@ -0,0 +1,657 @@ +/** + * @file + * Abstract Syntax Notation One (ISO 8824, 8825) decoding + * + * @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 + */ + +#include "lwip/opt.h" + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/snmp_asn1.h" + +/** + * Retrieves type field from incoming pbuf chain. + * + * @param p points to a pbuf holding an ASN1 coded type field + * @param ofs points to the offset within the pbuf chain of the ASN1 coded type field + * @param type return ASN1 type + * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode + */ +err_t +snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type) +{ + u16_t plen, base; + u8_t *msg_ptr; + + plen = 0; + while (p != NULL) + { + base = plen; + plen += p->len; + if (ofs < plen) + { + msg_ptr = (u8_t*)p->payload; + msg_ptr += ofs - base; + *type = *msg_ptr; + return ERR_OK; + } + p = p->next; + } + /* p == NULL, ofs >= plen */ + return ERR_ARG; +} + +/** + * Decodes length field from incoming pbuf chain into host length. + * + * @param p points to a pbuf holding an ASN1 coded length + * @param ofs points to the offset within the pbuf chain of the ASN1 coded length + * @param octets_used returns number of octets used by the length code + * @param length return host order length, upto 64k + * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode + */ +err_t +snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length) +{ + u16_t plen, base; + u8_t *msg_ptr; + + plen = 0; + while (p != NULL) + { + base = plen; + plen += p->len; + if (ofs < plen) + { + msg_ptr = (u8_t*)p->payload; + msg_ptr += ofs - base; + + if (*msg_ptr < 0x80) + { + /* primitive definite length format */ + *octets_used = 1; + *length = *msg_ptr; + return ERR_OK; + } + else if (*msg_ptr == 0x80) + { + /* constructed indefinite length format, termination with two zero octets */ + u8_t zeros; + u8_t i; + + *length = 0; + zeros = 0; + while (zeros != 2) + { + i = 2; + while (i > 0) + { + i--; + (*length) += 1; + ofs += 1; + if (ofs >= plen) + { + /* next octet in next pbuf */ + p = p->next; + if (p == NULL) { return ERR_ARG; } + msg_ptr = (u8_t*)p->payload; + plen += p->len; + } + else + { + /* next octet in same pbuf */ + msg_ptr++; + } + if (*msg_ptr == 0) + { + zeros++; + if (zeros == 2) + { + /* stop while (i > 0) */ + i = 0; + } + } + else + { + zeros = 0; + } + } + } + *octets_used = 1; + return ERR_OK; + } + else if (*msg_ptr == 0x81) + { + /* constructed definite length format, one octet */ + ofs += 1; + if (ofs >= plen) + { + /* next octet in next pbuf */ + p = p->next; + if (p == NULL) { return ERR_ARG; } + msg_ptr = (u8_t*)p->payload; + } + else + { + /* next octet in same pbuf */ + msg_ptr++; + } + *length = *msg_ptr; + *octets_used = 2; + return ERR_OK; + } + else if (*msg_ptr == 0x82) + { + u8_t i; + + /* constructed definite length format, two octets */ + i = 2; + while (i > 0) + { + i--; + ofs += 1; + if (ofs >= plen) + { + /* next octet in next pbuf */ + p = p->next; + if (p == NULL) { return ERR_ARG; } + msg_ptr = (u8_t*)p->payload; + plen += p->len; + } + else + { + /* next octet in same pbuf */ + msg_ptr++; + } + if (i == 0) + { + /* least significant length octet */ + *length |= *msg_ptr; + } + else + { + /* most significant length octet */ + *length = (*msg_ptr) << 8; + } + } + *octets_used = 3; + return ERR_OK; + } + else + { + /* constructed definite length format 3..127 octets, this is too big (>64k) */ + /** @todo: do we need to accept inefficient codings with many leading zero's? */ + *octets_used = 1 + ((*msg_ptr) & 0x7f); + return ERR_ARG; + } + } + p = p->next; + } + + /* p == NULL, ofs >= plen */ + return ERR_ARG; +} + +/** + * Decodes positive integer (counter, gauge, timeticks) into u32_t. + * + * @param p points to a pbuf holding an ASN1 coded integer + * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer + * @param len length of the coded integer field + * @param value return host order integer + * @return ERR_OK if successfull, 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 pbuf *p, u16_t ofs, u16_t len, u32_t *value) +{ + u16_t plen, base; + u8_t *msg_ptr; + + plen = 0; + while (p != NULL) + { + base = plen; + plen += p->len; + if (ofs < plen) + { + msg_ptr = (u8_t*)p->payload; + msg_ptr += ofs - base; + if ((len > 0) && (len < 6)) + { + /* start from zero */ + *value = 0; + if (*msg_ptr & 0x80) + { + /* negative, expecting zero sign bit! */ + return ERR_ARG; + } + else + { + /* positive */ + if ((len > 1) && (*msg_ptr == 0)) + { + /* skip leading "sign byte" octet 0x00 */ + len--; + ofs += 1; + if (ofs >= plen) + { + /* next octet in next pbuf */ + p = p->next; + if (p == NULL) { return ERR_ARG; } + msg_ptr = (u8_t*)p->payload; + plen += p->len; + } + else + { + /* next octet in same pbuf */ + msg_ptr++; + } + } + } + /* OR octets with value */ + while (len > 1) + { + len--; + *value |= *msg_ptr; + *value <<= 8; + ofs += 1; + if (ofs >= plen) + { + /* next octet in next pbuf */ + p = p->next; + if (p == NULL) { return ERR_ARG; } + msg_ptr = (u8_t*)p->payload; + plen += p->len; + } + else + { + /* next octet in same pbuf */ + msg_ptr++; + } + } + *value |= *msg_ptr; + return ERR_OK; + } + else + { + return ERR_ARG; + } + } + p = p->next; + } + /* p == NULL, ofs >= plen */ + return ERR_ARG; +} + +/** + * Decodes integer into s32_t. + * + * @param p points to a pbuf holding an ASN1 coded integer + * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer + * @param len length of the coded integer field + * @param value return host order integer + * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode + * + * @note ASN coded integers are _always_ signed! + */ +err_t +snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value) +{ + u16_t plen, base; + u8_t *msg_ptr; +#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; + + plen = 0; + while (p != NULL) + { + base = plen; + plen += p->len; + if (ofs < plen) + { + msg_ptr = (u8_t*)p->payload; + msg_ptr += ofs - base; + if ((len > 0) && (len < 5)) + { + if (*msg_ptr & 0x80) + { + /* negative, start from -1 */ + *value = -1; + sign = 1; + } + else + { + /* positive, start from 0 */ + *value = 0; + sign = 0; + } + /* OR/AND octets with value */ + while (len > 1) + { + len--; + if (sign) + { + *lsb_ptr &= *msg_ptr; + *value <<= 8; + *lsb_ptr |= 255; + } + else + { + *lsb_ptr |= *msg_ptr; + *value <<= 8; + } + ofs += 1; + if (ofs >= plen) + { + /* next octet in next pbuf */ + p = p->next; + if (p == NULL) { return ERR_ARG; } + msg_ptr = (u8_t*)p->payload; + plen += p->len; + } + else + { + /* next octet in same pbuf */ + msg_ptr++; + } + } + if (sign) + { + *lsb_ptr &= *msg_ptr; + } + else + { + *lsb_ptr |= *msg_ptr; + } + return ERR_OK; + } + else + { + return ERR_ARG; + } + } + p = p->next; + } + /* p == NULL, ofs >= plen */ + return ERR_ARG; +} + +/** + * Decodes object identifier from incoming message into array of s32_t. + * + * @param p points to a pbuf holding an ASN1 coded object identifier + * @param ofs points to the offset within the pbuf chain of the ASN1 coded object identifier + * @param len length of the coded object identifier + * @param oid return object identifier struct + * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode + */ +err_t +snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid) +{ + u16_t plen, base; + u8_t *msg_ptr; + s32_t *oid_ptr; + + plen = 0; + while (p != NULL) + { + base = plen; + plen += p->len; + if (ofs < plen) + { + msg_ptr = (u8_t*)p->payload; + msg_ptr += ofs - base; + + oid->len = 0; + oid_ptr = &oid->id[0]; + if (len > 0) + { + /* first compressed octet */ + if (*msg_ptr == 0x2B) + { + /* (most) common case 1.3 (iso.org) */ + *oid_ptr = 1; + oid_ptr++; + *oid_ptr = 3; + oid_ptr++; + } + else if (*msg_ptr < 40) + { + *oid_ptr = 0; + oid_ptr++; + *oid_ptr = *msg_ptr; + oid_ptr++; + } + else if (*msg_ptr < 80) + { + *oid_ptr = 1; + oid_ptr++; + *oid_ptr = (*msg_ptr) - 40; + oid_ptr++; + } + else + { + *oid_ptr = 2; + oid_ptr++; + *oid_ptr = (*msg_ptr) - 80; + oid_ptr++; + } + oid->len = 2; + } + else + { + /* accepting zero length identifiers e.g. for + getnext operation. uncommon but valid */ + return ERR_OK; + } + len--; + if (len > 0) + { + ofs += 1; + if (ofs >= plen) + { + /* next octet in next pbuf */ + p = p->next; + if (p == NULL) { return ERR_ARG; } + msg_ptr = (u8_t*)p->payload; + plen += p->len; + } + else + { + /* next octet in same pbuf */ + msg_ptr++; + } + } + while ((len > 0) && (oid->len < LWIP_SNMP_OBJ_ID_LEN)) + { + /* sub-identifier uses multiple octets */ + if (*msg_ptr & 0x80) + { + s32_t sub_id = 0; + + while ((*msg_ptr & 0x80) && (len > 1)) + { + len--; + sub_id = (sub_id << 7) + (*msg_ptr & ~0x80); + ofs += 1; + if (ofs >= plen) + { + /* next octet in next pbuf */ + p = p->next; + if (p == NULL) { return ERR_ARG; } + msg_ptr = (u8_t*)p->payload; + plen += p->len; + } + else + { + /* next octet in same pbuf */ + msg_ptr++; + } + } + if (!(*msg_ptr & 0x80) && (len > 0)) + { + /* last octet sub-identifier */ + len--; + sub_id = (sub_id << 7) + *msg_ptr; + *oid_ptr = sub_id; + } + } + else + { + /* !(*msg_ptr & 0x80) sub-identifier uses single octet */ + len--; + *oid_ptr = *msg_ptr; + } + if (len > 0) + { + /* remaining oid bytes available ... */ + ofs += 1; + if (ofs >= plen) + { + /* next octet in next pbuf */ + p = p->next; + if (p == NULL) { return ERR_ARG; } + msg_ptr = (u8_t*)p->payload; + plen += p->len; + } + else + { + /* next octet in same pbuf */ + msg_ptr++; + } + } + oid_ptr++; + oid->len++; + } + if (len == 0) + { + /* len == 0, end of oid */ + return ERR_OK; + } + else + { + /* len > 0, oid->len == LWIP_SNMP_OBJ_ID_LEN or malformed encoding */ + return ERR_ARG; + } + + } + p = p->next; + } + /* p == NULL, ofs >= plen */ + return ERR_ARG; +} + +/** + * Decodes (copies) raw data (ip-addresses, octet strings, opaque encoding) + * from incoming message into array. + * + * @param p points to a pbuf holding an ASN1 coded raw data + * @param ofs points to the offset within the pbuf chain of the ASN1 coded raw data + * @param len length of the coded raw data (zero is valid, e.g. empty string!) + * @param raw_len length of the raw return value + * @param raw return raw bytes + * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode + */ +err_t +snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw) +{ + u16_t plen, base; + u8_t *msg_ptr; + + if (len > 0) + { + plen = 0; + while (p != NULL) + { + base = plen; + plen += p->len; + if (ofs < plen) + { + msg_ptr = (u8_t*)p->payload; + msg_ptr += ofs - base; + if (raw_len >= len) + { + while (len > 1) + { + /* copy len - 1 octets */ + len--; + *raw = *msg_ptr; + raw++; + ofs += 1; + if (ofs >= plen) + { + /* next octet in next pbuf */ + p = p->next; + if (p == NULL) { return ERR_ARG; } + msg_ptr = (u8_t*)p->payload; + plen += p->len; + } + else + { + /* next octet in same pbuf */ + msg_ptr++; + } + } + /* copy last octet */ + *raw = *msg_ptr; + return ERR_OK; + } + else + { + /* raw_len < len, not enough dst space */ + return ERR_ARG; + } + } + p = p->next; + } + /* p == NULL, ofs >= plen */ + return ERR_ARG; + } + else + { + /* len == 0, empty string */ + return ERR_OK; + } +} + +#endif /* LWIP_SNMP */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/snmp/asn1_enc.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/snmp/asn1_enc.c new file mode 100644 index 0000000..64dfc5f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/snmp/asn1_enc.c @@ -0,0 +1,611 @@ +/** + * @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 + */ + +#include "lwip/opt.h" + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/snmp_asn1.h" + +/** + * Returns octet count for length. + * + * @param length + * @param octets_needed points to the return value + */ +void +snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed) +{ + if (length < 0x80U) + { + *octets_needed = 1; + } + else if (length < 0x100U) + { + *octets_needed = 2; + } + else + { + *octets_needed = 3; + } +} + +/** + * Returns octet count for an u32_t. + * + * @param value + * @param octets_needed points to the return value + * + * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded + * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value + * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!! + */ +void +snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed) +{ + if (value < 0x80UL) + { + *octets_needed = 1; + } + else if (value < 0x8000UL) + { + *octets_needed = 2; + } + else if (value < 0x800000UL) + { + *octets_needed = 3; + } + else if (value < 0x80000000UL) + { + *octets_needed = 4; + } + else + { + *octets_needed = 5; + } +} + +/** + * Returns octet count for an s32_t. + * + * @param value + * @param octets_needed points to the return value + * + * @note ASN coded integers are _always_ signed. + */ +void +snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed) +{ + if (value < 0) + { + value = ~value; + } + if (value < 0x80L) + { + *octets_needed = 1; + } + else if (value < 0x8000L) + { + *octets_needed = 2; + } + else if (value < 0x800000L) + { + *octets_needed = 3; + } + else + { + *octets_needed = 4; + } +} + +/** + * Returns octet count for an object identifier. + * + * @param ident_len object identifier array length + * @param ident points to object identifier array + * @param octets_needed points to the return value + */ +void +snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed) +{ + s32_t sub_id; + u8_t cnt; + + cnt = 0; + if (ident_len > 1) + { + /* compressed prefix in one octet */ + cnt++; + ident_len -= 2; + ident += 2; + } + while(ident_len > 0) + { + ident_len--; + sub_id = *ident; + + sub_id >>= 7; + cnt++; + while(sub_id > 0) + { + sub_id >>= 7; + cnt++; + } + ident++; + } + *octets_needed = cnt; +} + +/** + * Encodes ASN type field into a pbuf chained ASN1 msg. + * + * @param p points to output pbuf to encode value into + * @param ofs points to the offset within the pbuf chain + * @param type input ASN1 type + * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode + */ +err_t +snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type) +{ + u16_t plen, base; + u8_t *msg_ptr; + + plen = 0; + while (p != NULL) + { + base = plen; + plen += p->len; + if (ofs < plen) + { + msg_ptr = (u8_t*)p->payload; + msg_ptr += ofs - base; + *msg_ptr = type; + return ERR_OK; + } + p = p->next; + } + /* p == NULL, ofs >= plen */ + return ERR_ARG; +} + +/** + * Encodes host order length field into a pbuf chained ASN1 msg. + * + * @param p points to output pbuf to encode length into + * @param ofs points to the offset within the pbuf chain + * @param length is the host order length to be encoded + * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode + */ +err_t +snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length) +{ + u16_t plen, base; + u8_t *msg_ptr; + + plen = 0; + while (p != NULL) + { + base = plen; + plen += p->len; + if (ofs < plen) + { + msg_ptr = (u8_t*)p->payload; + msg_ptr += ofs - base; + + if (length < 0x80) + { + *msg_ptr = (u8_t)length; + return ERR_OK; + } + else if (length < 0x100) + { + *msg_ptr = 0x81; + ofs += 1; + if (ofs >= plen) + { + /* next octet in next pbuf */ + p = p->next; + if (p == NULL) { return ERR_ARG; } + msg_ptr = (u8_t*)p->payload; + } + else + { + /* next octet in same pbuf */ + msg_ptr++; + } + *msg_ptr = (u8_t)length; + return ERR_OK; + } + else + { + u8_t i; + + /* length >= 0x100 && length <= 0xFFFF */ + *msg_ptr = 0x82; + i = 2; + while (i > 0) + { + i--; + ofs += 1; + if (ofs >= plen) + { + /* next octet in next pbuf */ + p = p->next; + if (p == NULL) { return ERR_ARG; } + msg_ptr = (u8_t*)p->payload; + plen += p->len; + } + else + { + /* next octet in same pbuf */ + msg_ptr++; + } + if (i == 0) + { + /* least significant length octet */ + *msg_ptr = (u8_t)length; + } + else + { + /* most significant length octet */ + *msg_ptr = (u8_t)(length >> 8); + } + } + return ERR_OK; + } + } + p = p->next; + } + /* p == NULL, ofs >= plen */ + return ERR_ARG; +} + +/** + * Encodes u32_t (counter, gauge, timeticks) into a pbuf chained ASN1 msg. + * + * @param p points to output pbuf to encode value into + * @param ofs points to the offset within the pbuf chain + * @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 successfull, ERR_ARG if we can't (or won't) encode + * + * @see snmp_asn1_enc_u32t_cnt() + */ +err_t +snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, u32_t value) +{ + u16_t plen, base; + u8_t *msg_ptr; + + plen = 0; + while (p != NULL) + { + base = plen; + plen += p->len; + if (ofs < plen) + { + msg_ptr = (u8_t*)p->payload; + msg_ptr += ofs - base; + + if (octets_needed == 5) + { + /* not enough bits in 'value' add leading 0x00 */ + octets_needed--; + *msg_ptr = 0x00; + ofs += 1; + if (ofs >= plen) + { + /* next octet in next pbuf */ + p = p->next; + if (p == NULL) { return ERR_ARG; } + msg_ptr = (u8_t*)p->payload; + plen += p->len; + } + else + { + /* next octet in same pbuf */ + msg_ptr++; + } + } + while (octets_needed > 1) + { + octets_needed--; + *msg_ptr = (u8_t)(value >> (octets_needed << 3)); + ofs += 1; + if (ofs >= plen) + { + /* next octet in next pbuf */ + p = p->next; + if (p == NULL) { return ERR_ARG; } + msg_ptr = (u8_t*)p->payload; + plen += p->len; + } + else + { + /* next octet in same pbuf */ + msg_ptr++; + } + } + /* (only) one least significant octet */ + *msg_ptr = (u8_t)value; + return ERR_OK; + } + p = p->next; + } + /* p == NULL, ofs >= plen */ + return ERR_ARG; +} + +/** + * Encodes s32_t integer into a pbuf chained ASN1 msg. + * + * @param p points to output pbuf to encode value into + * @param ofs points to the offset within the pbuf chain + * @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 successfull, ERR_ARG if we can't (or won't) encode + * + * @see snmp_asn1_enc_s32t_cnt() + */ +err_t +snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, s32_t value) +{ + u16_t plen, base; + u8_t *msg_ptr; + + plen = 0; + while (p != NULL) + { + base = plen; + plen += p->len; + if (ofs < plen) + { + msg_ptr = (u8_t*)p->payload; + msg_ptr += ofs - base; + + while (octets_needed > 1) + { + octets_needed--; + *msg_ptr = (u8_t)(value >> (octets_needed << 3)); + ofs += 1; + if (ofs >= plen) + { + /* next octet in next pbuf */ + p = p->next; + if (p == NULL) { return ERR_ARG; } + msg_ptr = (u8_t*)p->payload; + plen += p->len; + } + else + { + /* next octet in same pbuf */ + msg_ptr++; + } + } + /* (only) one least significant octet */ + *msg_ptr = (u8_t)value; + return ERR_OK; + } + p = p->next; + } + /* p == NULL, ofs >= plen */ + return ERR_ARG; +} + +/** + * Encodes object identifier into a pbuf chained ASN1 msg. + * + * @param p points to output pbuf to encode oid into + * @param ofs points to the offset within the pbuf chain + * @param ident_len object identifier array length + * @param ident points to object identifier array + * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode + */ +err_t +snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident) +{ + u16_t plen, base; + u8_t *msg_ptr; + + plen = 0; + while (p != NULL) + { + base = plen; + plen += p->len; + if (ofs < plen) + { + msg_ptr = (u8_t*)p->payload; + msg_ptr += ofs - base; + + if (ident_len > 1) + { + if ((ident[0] == 1) && (ident[1] == 3)) + { + /* compressed (most common) prefix .iso.org */ + *msg_ptr = 0x2b; + } + else + { + /* calculate prefix */ + *msg_ptr = (u8_t)((ident[0] * 40) + ident[1]); + } + ofs += 1; + if (ofs >= plen) + { + /* next octet in next pbuf */ + p = p->next; + if (p == NULL) { return ERR_ARG; } + msg_ptr = (u8_t*)p->payload; + plen += p->len; + } + else + { + /* next octet in same pbuf */ + msg_ptr++; + } + ident_len -= 2; + ident += 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 (ident_len > 0) + { + s32_t sub_id; + u8_t shift, tail; + + ident_len--; + sub_id = *ident; + tail = 0; + shift = 28; + while(shift > 0) + { + u8_t code; + + code = (u8_t)(sub_id >> shift); + if ((code != 0) || (tail != 0)) + { + tail = 1; + *msg_ptr = code | 0x80; + ofs += 1; + if (ofs >= plen) + { + /* next octet in next pbuf */ + p = p->next; + if (p == NULL) { return ERR_ARG; } + msg_ptr = (u8_t*)p->payload; + plen += p->len; + } + else + { + /* next octet in same pbuf */ + msg_ptr++; + } + } + shift -= 7; + } + *msg_ptr = (u8_t)sub_id & 0x7F; + if (ident_len > 0) + { + ofs += 1; + if (ofs >= plen) + { + /* next octet in next pbuf */ + p = p->next; + if (p == NULL) { return ERR_ARG; } + msg_ptr = (u8_t*)p->payload; + plen += p->len; + } + else + { + /* next octet in same pbuf */ + msg_ptr++; + } + } + /* proceed to next sub-identifier */ + ident++; + } + return ERR_OK; + } + p = p->next; + } + /* p == NULL, ofs >= plen */ + return ERR_ARG; +} + +/** + * Encodes raw data (octet string, opaque) into a pbuf chained ASN1 msg. + * + * @param p points to output pbuf to encode raw data into + * @param ofs points to the offset within the pbuf chain + * @param raw_len raw data length + * @param raw points raw data + * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode + */ +err_t +snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u16_t raw_len, u8_t *raw) +{ + u16_t plen, base; + u8_t *msg_ptr; + + plen = 0; + while (p != NULL) + { + base = plen; + plen += p->len; + if (ofs < plen) + { + msg_ptr = (u8_t*)p->payload; + msg_ptr += ofs - base; + + while (raw_len > 1) + { + /* copy raw_len - 1 octets */ + raw_len--; + *msg_ptr = *raw; + raw++; + ofs += 1; + if (ofs >= plen) + { + /* next octet in next pbuf */ + p = p->next; + if (p == NULL) { return ERR_ARG; } + msg_ptr = (u8_t*)p->payload; + plen += p->len; + } + else + { + /* next octet in same pbuf */ + msg_ptr++; + } + } + if (raw_len > 0) + { + /* copy last or single octet */ + *msg_ptr = *raw; + } + return ERR_OK; + } + p = p->next; + } + /* p == NULL, ofs >= plen */ + return ERR_ARG; +} + +#endif /* LWIP_SNMP */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/snmp/mib2.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/snmp/mib2.c new file mode 100644 index 0000000..dcd3b62 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/snmp/mib2.c @@ -0,0 +1,4146 @@ +/** + * @file + * Management Information Base II (RFC1213) objects and functions. + * + * @note the object identifiers for this MIB-2 and private MIB tree + * must be kept in sorted ascending order. This to ensure correct getnext operation. + */ + +/* + * 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 + */ + +#include "lwip/opt.h" + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/snmp.h" +#include "lwip/netif.h" +#include "lwip/ip.h" +#include "lwip/ip_frag.h" +#include "lwip/mem.h" +#include "lwip/tcp_impl.h" +#include "lwip/udp.h" +#include "lwip/snmp_asn1.h" +#include "lwip/snmp_structs.h" +#include "lwip/sys.h" +#include "netif/etharp.h" + +/** + * 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 (contact Christiaan Simons)! + * @note don't change this define, use snmp_set_sysobjid() + * + * 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_ENTERPRISE_ID 26381 +#define SNMP_SYSOBJID_LEN 7 +#define SNMP_SYSOBJID {1, 3, 6, 1, 4, 1, SNMP_ENTERPRISE_ID} + +#ifndef SNMP_SYSSERVICES +#define SNMP_SYSSERVICES ((1 << 6) | (1 << 3) | ((IP_FORWARD) << 2)) +#endif + +#ifndef SNMP_GET_SYSUPTIME +#define SNMP_GET_SYSUPTIME(sysuptime) (sysuptime = (sys_now() / 10)) +#endif + +static void system_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +static void system_get_value(struct obj_def *od, u16_t len, void *value); +static u8_t system_set_test(struct obj_def *od, u16_t len, void *value); +static void system_set_value(struct obj_def *od, u16_t len, void *value); +static void interfaces_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +static void interfaces_get_value(struct obj_def *od, u16_t len, void *value); +static void ifentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +static void ifentry_get_value(struct obj_def *od, u16_t len, void *value); +#if !SNMP_SAFE_REQUESTS +static u8_t ifentry_set_test (struct obj_def *od, u16_t len, void *value); +static void ifentry_set_value (struct obj_def *od, u16_t len, void *value); +#endif /* SNMP_SAFE_REQUESTS */ +static void atentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +static void atentry_get_value(struct obj_def *od, u16_t len, void *value); +static void ip_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +static void ip_get_value(struct obj_def *od, u16_t len, void *value); +static u8_t ip_set_test(struct obj_def *od, u16_t len, void *value); +static void ip_addrentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +static void ip_addrentry_get_value(struct obj_def *od, u16_t len, void *value); +static void ip_rteentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +static void ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value); +static void ip_ntomentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +static void ip_ntomentry_get_value(struct obj_def *od, u16_t len, void *value); +static void icmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +static void icmp_get_value(struct obj_def *od, u16_t len, void *value); +#if LWIP_TCP +static void tcp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +static void tcp_get_value(struct obj_def *od, u16_t len, void *value); +#ifdef THIS_SEEMS_UNUSED +static void tcpconnentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +static void tcpconnentry_get_value(struct obj_def *od, u16_t len, void *value); +#endif +#endif +static void udp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +static void udp_get_value(struct obj_def *od, u16_t len, void *value); +static void udpentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +static void udpentry_get_value(struct obj_def *od, u16_t len, void *value); +static void snmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +static void snmp_get_value(struct obj_def *od, u16_t len, void *value); +static u8_t snmp_set_test(struct obj_def *od, u16_t len, void *value); +static void snmp_set_value(struct obj_def *od, u16_t len, void *value); + + +/* snmp .1.3.6.1.2.1.11 */ +const mib_scalar_node snmp_scalar = { + &snmp_get_object_def, + &snmp_get_value, + &snmp_set_test, + &snmp_set_value, + MIB_NODE_SC, + 0 +}; +const s32_t snmp_ids[28] = { + 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30 +}; +struct mib_node* const snmp_nodes[28] = { + (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, + (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, + (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, + (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, + (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, + (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, + (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, + (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, + (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, + (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, + (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, + (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, + (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, + (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar +}; +const struct mib_array_node snmp = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_AR, + 28, + snmp_ids, + snmp_nodes +}; + +/* 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) */ + +/* udp .1.3.6.1.2.1.7 */ +/** index root node for udpTable */ +struct mib_list_rootnode udp_root = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_LR, + 0, + NULL, + NULL, + 0 +}; +const s32_t udpentry_ids[2] = { 1, 2 }; +struct mib_node* const udpentry_nodes[2] = { + (struct mib_node*)&udp_root, (struct mib_node*)&udp_root, +}; +const struct mib_array_node udpentry = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_AR, + 2, + udpentry_ids, + udpentry_nodes +}; + +s32_t udptable_id = 1; +struct mib_node* udptable_node = (struct mib_node*)&udpentry; +struct mib_ram_array_node udptable = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_RA, + 0, + &udptable_id, + &udptable_node +}; + +const mib_scalar_node udp_scalar = { + &udp_get_object_def, + &udp_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_SC, + 0 +}; +const s32_t udp_ids[5] = { 1, 2, 3, 4, 5 }; +struct mib_node* const udp_nodes[5] = { + (struct mib_node*)&udp_scalar, (struct mib_node*)&udp_scalar, + (struct mib_node*)&udp_scalar, (struct mib_node*)&udp_scalar, + (struct mib_node*)&udptable +}; +const struct mib_array_node udp = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_AR, + 5, + udp_ids, + udp_nodes +}; + +/* tcp .1.3.6.1.2.1.6 */ +#if LWIP_TCP +/* only if the TCP protocol is available may implement this group */ +/** index root node for tcpConnTable */ +struct mib_list_rootnode tcpconntree_root = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_LR, + 0, + NULL, + NULL, + 0 +}; +const s32_t tcpconnentry_ids[5] = { 1, 2, 3, 4, 5 }; +struct mib_node* const tcpconnentry_nodes[5] = { + (struct mib_node*)&tcpconntree_root, (struct mib_node*)&tcpconntree_root, + (struct mib_node*)&tcpconntree_root, (struct mib_node*)&tcpconntree_root, + (struct mib_node*)&tcpconntree_root +}; +const struct mib_array_node tcpconnentry = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_AR, + 5, + tcpconnentry_ids, + tcpconnentry_nodes +}; + +s32_t tcpconntable_id = 1; +struct mib_node* tcpconntable_node = (struct mib_node*)&tcpconnentry; +struct mib_ram_array_node tcpconntable = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_RA, +/** @todo update maxlength when inserting / deleting from table + 0 when table is empty, 1 when more than one entry */ + 0, + &tcpconntable_id, + &tcpconntable_node +}; + +const mib_scalar_node tcp_scalar = { + &tcp_get_object_def, + &tcp_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_SC, + 0 +}; +const s32_t tcp_ids[15] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; +struct mib_node* const tcp_nodes[15] = { + (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar, + (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar, + (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar, + (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar, + (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar, + (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar, + (struct mib_node*)&tcpconntable, (struct mib_node*)&tcp_scalar, + (struct mib_node*)&tcp_scalar +}; +const struct mib_array_node tcp = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_AR, + 15, + tcp_ids, + tcp_nodes +}; +#endif + +/* icmp .1.3.6.1.2.1.5 */ +const mib_scalar_node icmp_scalar = { + &icmp_get_object_def, + &icmp_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_SC, + 0 +}; +const s32_t icmp_ids[26] = { 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, 26 }; +struct mib_node* const icmp_nodes[26] = { + (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, + (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, + (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, + (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, + (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, + (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, + (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, + (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, + (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, + (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, + (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, + (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, + (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar +}; +const struct mib_array_node icmp = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_AR, + 26, + icmp_ids, + icmp_nodes +}; + +/** index root node for ipNetToMediaTable */ +struct mib_list_rootnode ipntomtree_root = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_LR, + 0, + NULL, + NULL, + 0 +}; +const s32_t ipntomentry_ids[4] = { 1, 2, 3, 4 }; +struct mib_node* const ipntomentry_nodes[4] = { + (struct mib_node*)&ipntomtree_root, (struct mib_node*)&ipntomtree_root, + (struct mib_node*)&ipntomtree_root, (struct mib_node*)&ipntomtree_root +}; +const struct mib_array_node ipntomentry = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_AR, + 4, + ipntomentry_ids, + ipntomentry_nodes +}; + +s32_t ipntomtable_id = 1; +struct mib_node* ipntomtable_node = (struct mib_node*)&ipntomentry; +struct mib_ram_array_node ipntomtable = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_RA, + 0, + &ipntomtable_id, + &ipntomtable_node +}; + +/** index root node for ipRouteTable */ +struct mib_list_rootnode iprtetree_root = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_LR, + 0, + NULL, + NULL, + 0 +}; +const s32_t iprteentry_ids[13] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 }; +struct mib_node* const iprteentry_nodes[13] = { + (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root, + (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root, + (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root, + (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root, + (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root, + (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root, + (struct mib_node*)&iprtetree_root +}; +const struct mib_array_node iprteentry = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_AR, + 13, + iprteentry_ids, + iprteentry_nodes +}; + +s32_t iprtetable_id = 1; +struct mib_node* iprtetable_node = (struct mib_node*)&iprteentry; +struct mib_ram_array_node iprtetable = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_RA, + 0, + &iprtetable_id, + &iprtetable_node +}; + +/** index root node for ipAddrTable */ +struct mib_list_rootnode ipaddrtree_root = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_LR, + 0, + NULL, + NULL, + 0 +}; +const s32_t ipaddrentry_ids[5] = { 1, 2, 3, 4, 5 }; +struct mib_node* const ipaddrentry_nodes[5] = { + (struct mib_node*)&ipaddrtree_root, + (struct mib_node*)&ipaddrtree_root, + (struct mib_node*)&ipaddrtree_root, + (struct mib_node*)&ipaddrtree_root, + (struct mib_node*)&ipaddrtree_root +}; +const struct mib_array_node ipaddrentry = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_AR, + 5, + ipaddrentry_ids, + ipaddrentry_nodes +}; + +s32_t ipaddrtable_id = 1; +struct mib_node* ipaddrtable_node = (struct mib_node*)&ipaddrentry; +struct mib_ram_array_node ipaddrtable = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_RA, + 0, + &ipaddrtable_id, + &ipaddrtable_node +}; + +/* ip .1.3.6.1.2.1.4 */ +const mib_scalar_node ip_scalar = { + &ip_get_object_def, + &ip_get_value, + &ip_set_test, + &noleafs_set_value, + MIB_NODE_SC, + 0 +}; +const s32_t ip_ids[23] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 }; +struct mib_node* const ip_nodes[23] = { + (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, + (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, + (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, + (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, + (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, + (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, + (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, + (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, + (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, + (struct mib_node*)&ip_scalar, (struct mib_node*)&ipaddrtable, + (struct mib_node*)&iprtetable, (struct mib_node*)&ipntomtable, + (struct mib_node*)&ip_scalar +}; +const struct mib_array_node mib2_ip = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_AR, + 23, + ip_ids, + ip_nodes +}; + +/** index root node for atTable */ +struct mib_list_rootnode arptree_root = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_LR, + 0, + NULL, + NULL, + 0 +}; +const s32_t atentry_ids[3] = { 1, 2, 3 }; +struct mib_node* const atentry_nodes[3] = { + (struct mib_node*)&arptree_root, + (struct mib_node*)&arptree_root, + (struct mib_node*)&arptree_root +}; +const struct mib_array_node atentry = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_AR, + 3, + atentry_ids, + atentry_nodes +}; + +const s32_t attable_id = 1; +struct mib_node* const attable_node = (struct mib_node*)&atentry; +const struct mib_array_node attable = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_AR, + 1, + &attable_id, + &attable_node +}; + +/* at .1.3.6.1.2.1.3 */ +s32_t at_id = 1; +struct mib_node* mib2_at_node = (struct mib_node*)&attable; +struct mib_ram_array_node at = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_RA, + 0, + &at_id, + &mib2_at_node +}; + +/** index root node for ifTable */ +struct mib_list_rootnode iflist_root = { + &ifentry_get_object_def, + &ifentry_get_value, +#if SNMP_SAFE_REQUESTS + &noleafs_set_test, + &noleafs_set_value, +#else /* SNMP_SAFE_REQUESTS */ + &ifentry_set_test, + &ifentry_set_value, +#endif /* SNMP_SAFE_REQUESTS */ + MIB_NODE_LR, + 0, + NULL, + NULL, + 0 +}; +const s32_t ifentry_ids[22] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 }; +struct mib_node* const ifentry_nodes[22] = { + (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, + (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, + (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, + (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, + (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, + (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, + (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, + (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, + (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, + (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, + (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root +}; +const struct mib_array_node ifentry = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_AR, + 22, + ifentry_ids, + ifentry_nodes +}; + +s32_t iftable_id = 1; +struct mib_node* iftable_node = (struct mib_node*)&ifentry; +struct mib_ram_array_node iftable = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_RA, + 0, + &iftable_id, + &iftable_node +}; + +/* interfaces .1.3.6.1.2.1.2 */ +const mib_scalar_node interfaces_scalar = { + &interfaces_get_object_def, + &interfaces_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_SC, + 0 +}; +const s32_t interfaces_ids[2] = { 1, 2 }; +struct mib_node* const interfaces_nodes[2] = { + (struct mib_node*)&interfaces_scalar, (struct mib_node*)&iftable +}; +const struct mib_array_node interfaces = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_AR, + 2, + interfaces_ids, + interfaces_nodes +}; + + +/* 0 1 2 3 4 5 6 */ +/* system .1.3.6.1.2.1.1 */ +const mib_scalar_node sys_tem_scalar = { + &system_get_object_def, + &system_get_value, + &system_set_test, + &system_set_value, + MIB_NODE_SC, + 0 +}; +const s32_t sys_tem_ids[7] = { 1, 2, 3, 4, 5, 6, 7 }; +struct mib_node* const sys_tem_nodes[7] = { + (struct mib_node*)&sys_tem_scalar, (struct mib_node*)&sys_tem_scalar, + (struct mib_node*)&sys_tem_scalar, (struct mib_node*)&sys_tem_scalar, + (struct mib_node*)&sys_tem_scalar, (struct mib_node*)&sys_tem_scalar, + (struct mib_node*)&sys_tem_scalar +}; +/* work around name issue with 'sys_tem', some compiler(s?) seem to reserve 'system' */ +const struct mib_array_node sys_tem = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_AR, + 7, + sys_tem_ids, + sys_tem_nodes +}; + +/* mib-2 .1.3.6.1.2.1 */ +#if LWIP_TCP +#define MIB2_GROUPS 8 +#else +#define MIB2_GROUPS 7 +#endif +const s32_t mib2_ids[MIB2_GROUPS] = +{ + 1, + 2, + 3, + 4, + 5, +#if LWIP_TCP + 6, +#endif + 7, + 11 +}; +struct mib_node* const mib2_nodes[MIB2_GROUPS] = { + (struct mib_node*)&sys_tem, + (struct mib_node*)&interfaces, + (struct mib_node*)&at, + (struct mib_node*)&mib2_ip, + (struct mib_node*)&icmp, +#if LWIP_TCP + (struct mib_node*)&tcp, +#endif + (struct mib_node*)&udp, + (struct mib_node*)&snmp +}; + +const struct mib_array_node mib2 = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_AR, + MIB2_GROUPS, + mib2_ids, + mib2_nodes +}; + +/* mgmt .1.3.6.1.2 */ +const s32_t mgmt_ids[1] = { 1 }; +struct mib_node* const mgmt_nodes[1] = { (struct mib_node*)&mib2 }; +const struct mib_array_node mgmt = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_AR, + 1, + mgmt_ids, + mgmt_nodes +}; + +/* internet .1.3.6.1 */ +#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. */ +s32_t internet_ids[2] = { 2, 4 }; +struct mib_node* const internet_nodes[2] = { (struct mib_node*)&mgmt, (struct mib_node*)&mib_private }; +const struct mib_array_node internet = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_AR, + 2, + internet_ids, + internet_nodes +}; +#else +const s32_t internet_ids[1] = { 2 }; +struct mib_node* const internet_nodes[1] = { (struct mib_node*)&mgmt }; +const struct mib_array_node internet = { + &noleafs_get_object_def, + &noleafs_get_value, + &noleafs_set_test, + &noleafs_set_value, + MIB_NODE_AR, + 1, + internet_ids, + internet_nodes +}; +#endif + +/** mib-2.system.sysObjectID */ +static struct snmp_obj_id sysobjid = {SNMP_SYSOBJID_LEN, SNMP_SYSOBJID}; +/** enterprise ID for generic TRAPs, .iso.org.dod.internet.mgmt.mib-2.snmp */ +static struct snmp_obj_id snmpgrp_id = {7,{1,3,6,1,2,1,11}}; +/** mib-2.system.sysServices */ +static const s32_t sysservices = SNMP_SYSSERVICES; + +/** mib-2.system.sysDescr */ +static const u8_t sysdescr_len_default = 4; +static const u8_t sysdescr_default[] = "lwIP"; +static u8_t* sysdescr_len_ptr = (u8_t*)&sysdescr_len_default; +static u8_t* sysdescr_ptr = (u8_t*)&sysdescr_default[0]; +/** mib-2.system.sysContact */ +static const u8_t syscontact_len_default = 0; +static const u8_t syscontact_default[] = ""; +static u8_t* syscontact_len_ptr = (u8_t*)&syscontact_len_default; +static u8_t* syscontact_ptr = (u8_t*)&syscontact_default[0]; +/** mib-2.system.sysName */ +static const u8_t sysname_len_default = 8; +static const u8_t sysname_default[] = "FQDN-unk"; +static u8_t* sysname_len_ptr = (u8_t*)&sysname_len_default; +static u8_t* sysname_ptr = (u8_t*)&sysname_default[0]; +/** mib-2.system.sysLocation */ +static const u8_t syslocation_len_default = 0; +static const u8_t syslocation_default[] = ""; +static u8_t* syslocation_len_ptr = (u8_t*)&syslocation_len_default; +static u8_t* syslocation_ptr = (u8_t*)&syslocation_default[0]; +/** mib-2.snmp.snmpEnableAuthenTraps */ +static const u8_t snmpenableauthentraps_default = 2; /* disabled */ +static u8_t* snmpenableauthentraps_ptr = (u8_t*)&snmpenableauthentraps_default; + +/** mib-2.interfaces.ifTable.ifEntry.ifSpecific (zeroDotZero) */ +static const struct snmp_obj_id ifspecific = {2, {0, 0}}; +/** mib-2.ip.ipRouteTable.ipRouteEntry.ipRouteInfo (zeroDotZero) */ +static const struct snmp_obj_id iprouteinfo = {2, {0, 0}}; + + + +/* mib-2.system counter(s) */ +static u32_t sysuptime = 0; + +/* mib-2.ip counter(s) */ +static u32_t ipinreceives = 0, + ipinhdrerrors = 0, + ipinaddrerrors = 0, + ipforwdatagrams = 0, + ipinunknownprotos = 0, + ipindiscards = 0, + ipindelivers = 0, + ipoutrequests = 0, + ipoutdiscards = 0, + ipoutnoroutes = 0, + ipreasmreqds = 0, + ipreasmoks = 0, + ipreasmfails = 0, + ipfragoks = 0, + ipfragfails = 0, + ipfragcreates = 0, + iproutingdiscards = 0; +/* mib-2.icmp counter(s) */ +static u32_t icmpinmsgs = 0, + icmpinerrors = 0, + icmpindestunreachs = 0, + icmpintimeexcds = 0, + icmpinparmprobs = 0, + icmpinsrcquenchs = 0, + icmpinredirects = 0, + icmpinechos = 0, + icmpinechoreps = 0, + icmpintimestamps = 0, + icmpintimestampreps = 0, + icmpinaddrmasks = 0, + icmpinaddrmaskreps = 0, + icmpoutmsgs = 0, + icmpouterrors = 0, + icmpoutdestunreachs = 0, + icmpouttimeexcds = 0, + icmpoutparmprobs = 0, + icmpoutsrcquenchs = 0, + icmpoutredirects = 0, + icmpoutechos = 0, + icmpoutechoreps = 0, + icmpouttimestamps = 0, + icmpouttimestampreps = 0, + icmpoutaddrmasks = 0, + icmpoutaddrmaskreps = 0; +/* mib-2.tcp counter(s) */ +static u32_t tcpactiveopens = 0, + tcppassiveopens = 0, + tcpattemptfails = 0, + tcpestabresets = 0, + tcpinsegs = 0, + tcpoutsegs = 0, + tcpretranssegs = 0, + tcpinerrs = 0, + tcpoutrsts = 0; +/* mib-2.udp counter(s) */ +static u32_t udpindatagrams = 0, + udpnoports = 0, + udpinerrors = 0, + udpoutdatagrams = 0; +/* mib-2.snmp counter(s) */ +static u32_t snmpinpkts = 0, + snmpoutpkts = 0, + snmpinbadversions = 0, + snmpinbadcommunitynames = 0, + snmpinbadcommunityuses = 0, + snmpinasnparseerrs = 0, + snmpintoobigs = 0, + snmpinnosuchnames = 0, + snmpinbadvalues = 0, + snmpinreadonlys = 0, + snmpingenerrs = 0, + snmpintotalreqvars = 0, + snmpintotalsetvars = 0, + snmpingetrequests = 0, + snmpingetnexts = 0, + snmpinsetrequests = 0, + snmpingetresponses = 0, + snmpintraps = 0, + snmpouttoobigs = 0, + snmpoutnosuchnames = 0, + snmpoutbadvalues = 0, + snmpoutgenerrs = 0, + snmpoutgetrequests = 0, + snmpoutgetnexts = 0, + snmpoutsetrequests = 0, + snmpoutgetresponses = 0, + snmpouttraps = 0; + + + +/* prototypes of the following functions are in lwip/src/include/lwip/snmp.h */ +/** + * Copy octet string. + * + * @param dst points to destination + * @param src points to source + * @param n number of octets to copy. + */ +static void ocstrncpy(u8_t *dst, u8_t *src, u16_t n) +{ + u16_t i = n; + while (i > 0) { + i--; + *dst++ = *src++; + } +} + +/** + * Copy object identifier (s32_t) array. + * + * @param dst points to destination + * @param src points to source + * @param n number of sub identifiers to copy. + */ +void objectidncpy(s32_t *dst, s32_t *src, u8_t n) +{ + u8_t i = n; + while(i > 0) { + i--; + *dst++ = *src++; + } +} + +/** + * Initializes sysDescr pointers. + * + * @param str if non-NULL then copy str pointer + * @param len points to string length, excluding zero terminator + */ +void snmp_set_sysdesr(u8_t *str, u8_t *len) +{ + if (str != NULL) + { + sysdescr_ptr = str; + sysdescr_len_ptr = len; + } +} + +void snmp_get_sysobjid_ptr(struct snmp_obj_id **oid) +{ + *oid = &sysobjid; +} + +/** + * Initializes sysObjectID value. + * + * @param oid points to stuct snmp_obj_id to copy + */ +void snmp_set_sysobjid(struct snmp_obj_id *oid) +{ + sysobjid = *oid; +} + +/** + * Must be called at regular 10 msec interval from a timer interrupt + * or signal handler depending on your runtime environment. + */ +void snmp_inc_sysuptime(void) +{ + sysuptime++; +} + +void snmp_add_sysuptime(u32_t value) +{ + sysuptime+=value; +} + +void snmp_get_sysuptime(u32_t *value) +{ + SNMP_GET_SYSUPTIME(sysuptime); + *value = sysuptime; +} + +/** + * Initializes sysContact pointers, + * e.g. ptrs to non-volatile memory external to lwIP. + * + * @param ocstr if non-NULL then copy str pointer + * @param ocstrlen points to string length, excluding zero terminator + */ +void snmp_set_syscontact(u8_t *ocstr, u8_t *ocstrlen) +{ + if (ocstr != NULL) + { + syscontact_ptr = ocstr; + syscontact_len_ptr = ocstrlen; + } +} + +/** + * Initializes sysName pointers, + * e.g. ptrs to non-volatile memory external to lwIP. + * + * @param ocstr if non-NULL then copy str pointer + * @param ocstrlen points to string length, excluding zero terminator + */ +void snmp_set_sysname(u8_t *ocstr, u8_t *ocstrlen) +{ + if (ocstr != NULL) + { + sysname_ptr = ocstr; + sysname_len_ptr = ocstrlen; + } +} + +/** + * Initializes sysLocation pointers, + * e.g. ptrs to non-volatile memory external to lwIP. + * + * @param ocstr if non-NULL then copy str pointer + * @param ocstrlen points to string length, excluding zero terminator + */ +void snmp_set_syslocation(u8_t *ocstr, u8_t *ocstrlen) +{ + if (ocstr != NULL) + { + syslocation_ptr = ocstr; + syslocation_len_ptr = ocstrlen; + } +} + + +void snmp_add_ifinoctets(struct netif *ni, u32_t value) +{ + ni->ifinoctets += value; +} + +void snmp_inc_ifinucastpkts(struct netif *ni) +{ + (ni->ifinucastpkts)++; +} + +void snmp_inc_ifinnucastpkts(struct netif *ni) +{ + (ni->ifinnucastpkts)++; +} + +void snmp_inc_ifindiscards(struct netif *ni) +{ + (ni->ifindiscards)++; +} + +void snmp_add_ifoutoctets(struct netif *ni, u32_t value) +{ + ni->ifoutoctets += value; +} + +void snmp_inc_ifoutucastpkts(struct netif *ni) +{ + (ni->ifoutucastpkts)++; +} + +void snmp_inc_ifoutnucastpkts(struct netif *ni) +{ + (ni->ifoutnucastpkts)++; +} + +void snmp_inc_ifoutdiscards(struct netif *ni) +{ + (ni->ifoutdiscards)++; +} + +void snmp_inc_iflist(void) +{ + struct mib_list_node *if_node = NULL; + + snmp_mib_node_insert(&iflist_root, iflist_root.count + 1, &if_node); + /* enable getnext traversal on filled table */ + iftable.maxlength = 1; +} + +void snmp_dec_iflist(void) +{ + snmp_mib_node_delete(&iflist_root, iflist_root.tail); + /* disable getnext traversal on empty table */ + if(iflist_root.count == 0) iftable.maxlength = 0; +} + +/** + * Inserts ARP table indexes (.xIfIndex.xNetAddress) + * into arp table index trees (both atTable and ipNetToMediaTable). + */ +void snmp_insert_arpidx_tree(struct netif *ni, ip_addr_t *ip) +{ + struct mib_list_rootnode *at_rn; + struct mib_list_node *at_node; + s32_t arpidx[5]; + u8_t level, tree; + + LWIP_ASSERT("ni != NULL", ni != NULL); + snmp_netiftoifindex(ni, &arpidx[0]); + snmp_iptooid(ip, &arpidx[1]); + + for (tree = 0; tree < 2; tree++) + { + if (tree == 0) + { + at_rn = &arptree_root; + } + else + { + at_rn = &ipntomtree_root; + } + for (level = 0; level < 5; level++) + { + at_node = NULL; + snmp_mib_node_insert(at_rn, arpidx[level], &at_node); + if ((level != 4) && (at_node != NULL)) + { + if (at_node->nptr == NULL) + { + at_rn = snmp_mib_lrn_alloc(); + at_node->nptr = (struct mib_node*)at_rn; + if (at_rn != NULL) + { + if (level == 3) + { + if (tree == 0) + { + at_rn->get_object_def = atentry_get_object_def; + at_rn->get_value = atentry_get_value; + } + else + { + at_rn->get_object_def = ip_ntomentry_get_object_def; + at_rn->get_value = ip_ntomentry_get_value; + } + at_rn->set_test = noleafs_set_test; + at_rn->set_value = noleafs_set_value; + } + } + else + { + /* at_rn == NULL, malloc failure */ + LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_arpidx_tree() insert failed, mem full")); + break; + } + } + else + { + at_rn = (struct mib_list_rootnode*)at_node->nptr; + } + } + } + } + /* enable getnext traversal on filled tables */ + at.maxlength = 1; + ipntomtable.maxlength = 1; +} + +/** + * Removes ARP table indexes (.xIfIndex.xNetAddress) + * from arp table index trees. + */ +void snmp_delete_arpidx_tree(struct netif *ni, ip_addr_t *ip) +{ + struct mib_list_rootnode *at_rn, *next, *del_rn[5]; + struct mib_list_node *at_n, *del_n[5]; + s32_t arpidx[5]; + u8_t fc, tree, level, del_cnt; + + snmp_netiftoifindex(ni, &arpidx[0]); + snmp_iptooid(ip, &arpidx[1]); + + for (tree = 0; tree < 2; tree++) + { + /* mark nodes for deletion */ + if (tree == 0) + { + at_rn = &arptree_root; + } + else + { + at_rn = &ipntomtree_root; + } + level = 0; + del_cnt = 0; + while ((level < 5) && (at_rn != NULL)) + { + fc = snmp_mib_node_find(at_rn, arpidx[level], &at_n); + if (fc == 0) + { + /* arpidx[level] does not exist */ + del_cnt = 0; + at_rn = NULL; + } + else if (fc == 1) + { + del_rn[del_cnt] = at_rn; + del_n[del_cnt] = at_n; + del_cnt++; + at_rn = (struct mib_list_rootnode*)(at_n->nptr); + } + else if (fc == 2) + { + /* reset delete (2 or more childs) */ + del_cnt = 0; + at_rn = (struct mib_list_rootnode*)(at_n->nptr); + } + level++; + } + /* delete marked index nodes */ + while (del_cnt > 0) + { + del_cnt--; + + at_rn = del_rn[del_cnt]; + at_n = del_n[del_cnt]; + + next = snmp_mib_node_delete(at_rn, at_n); + if (next != NULL) + { + LWIP_ASSERT("next_count == 0",next->count == 0); + snmp_mib_lrn_free(next); + } + } + } + /* disable getnext traversal on empty tables */ + if(arptree_root.count == 0) at.maxlength = 0; + if(ipntomtree_root.count == 0) ipntomtable.maxlength = 0; +} + +void snmp_inc_ipinreceives(void) +{ + ipinreceives++; +} + +void snmp_inc_ipinhdrerrors(void) +{ + ipinhdrerrors++; +} + +void snmp_inc_ipinaddrerrors(void) +{ + ipinaddrerrors++; +} + +void snmp_inc_ipforwdatagrams(void) +{ + ipforwdatagrams++; +} + +void snmp_inc_ipinunknownprotos(void) +{ + ipinunknownprotos++; +} + +void snmp_inc_ipindiscards(void) +{ + ipindiscards++; +} + +void snmp_inc_ipindelivers(void) +{ + ipindelivers++; +} + +void snmp_inc_ipoutrequests(void) +{ + ipoutrequests++; +} + +void snmp_inc_ipoutdiscards(void) +{ + ipoutdiscards++; +} + +void snmp_inc_ipoutnoroutes(void) +{ + ipoutnoroutes++; +} + +void snmp_inc_ipreasmreqds(void) +{ + ipreasmreqds++; +} + +void snmp_inc_ipreasmoks(void) +{ + ipreasmoks++; +} + +void snmp_inc_ipreasmfails(void) +{ + ipreasmfails++; +} + +void snmp_inc_ipfragoks(void) +{ + ipfragoks++; +} + +void snmp_inc_ipfragfails(void) +{ + ipfragfails++; +} + +void snmp_inc_ipfragcreates(void) +{ + ipfragcreates++; +} + +void snmp_inc_iproutingdiscards(void) +{ + iproutingdiscards++; +} + +/** + * Inserts ipAddrTable indexes (.ipAdEntAddr) + * into index tree. + */ +void snmp_insert_ipaddridx_tree(struct netif *ni) +{ + struct mib_list_rootnode *ipa_rn; + struct mib_list_node *ipa_node; + s32_t ipaddridx[4]; + u8_t level; + + LWIP_ASSERT("ni != NULL", ni != NULL); + snmp_iptooid(&ni->ip_addr, &ipaddridx[0]); + + level = 0; + ipa_rn = &ipaddrtree_root; + while (level < 4) + { + ipa_node = NULL; + snmp_mib_node_insert(ipa_rn, ipaddridx[level], &ipa_node); + if ((level != 3) && (ipa_node != NULL)) + { + if (ipa_node->nptr == NULL) + { + ipa_rn = snmp_mib_lrn_alloc(); + ipa_node->nptr = (struct mib_node*)ipa_rn; + if (ipa_rn != NULL) + { + if (level == 2) + { + ipa_rn->get_object_def = ip_addrentry_get_object_def; + ipa_rn->get_value = ip_addrentry_get_value; + ipa_rn->set_test = noleafs_set_test; + ipa_rn->set_value = noleafs_set_value; + } + } + else + { + /* ipa_rn == NULL, malloc failure */ + LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_ipaddridx_tree() insert failed, mem full")); + break; + } + } + else + { + ipa_rn = (struct mib_list_rootnode*)ipa_node->nptr; + } + } + level++; + } + /* enable getnext traversal on filled table */ + ipaddrtable.maxlength = 1; +} + +/** + * Removes ipAddrTable indexes (.ipAdEntAddr) + * from index tree. + */ +void snmp_delete_ipaddridx_tree(struct netif *ni) +{ + struct mib_list_rootnode *ipa_rn, *next, *del_rn[4]; + struct mib_list_node *ipa_n, *del_n[4]; + s32_t ipaddridx[4]; + u8_t fc, level, del_cnt; + + LWIP_ASSERT("ni != NULL", ni != NULL); + snmp_iptooid(&ni->ip_addr, &ipaddridx[0]); + + /* mark nodes for deletion */ + level = 0; + del_cnt = 0; + ipa_rn = &ipaddrtree_root; + while ((level < 4) && (ipa_rn != NULL)) + { + fc = snmp_mib_node_find(ipa_rn, ipaddridx[level], &ipa_n); + if (fc == 0) + { + /* ipaddridx[level] does not exist */ + del_cnt = 0; + ipa_rn = NULL; + } + else if (fc == 1) + { + del_rn[del_cnt] = ipa_rn; + del_n[del_cnt] = ipa_n; + del_cnt++; + ipa_rn = (struct mib_list_rootnode*)(ipa_n->nptr); + } + else if (fc == 2) + { + /* reset delete (2 or more childs) */ + del_cnt = 0; + ipa_rn = (struct mib_list_rootnode*)(ipa_n->nptr); + } + level++; + } + /* delete marked index nodes */ + while (del_cnt > 0) + { + del_cnt--; + + ipa_rn = del_rn[del_cnt]; + ipa_n = del_n[del_cnt]; + + next = snmp_mib_node_delete(ipa_rn, ipa_n); + if (next != NULL) + { + LWIP_ASSERT("next_count == 0",next->count == 0); + snmp_mib_lrn_free(next); + } + } + /* disable getnext traversal on empty table */ + if (ipaddrtree_root.count == 0) ipaddrtable.maxlength = 0; +} + +/** + * Inserts ipRouteTable indexes (.ipRouteDest) + * into index tree. + * + * @param dflt non-zero for the default rte, zero for network rte + * @param ni points to network interface for this rte + * + * @todo record sysuptime for _this_ route when it is installed + * (needed for ipRouteAge) in the netif. + */ +void snmp_insert_iprteidx_tree(u8_t dflt, struct netif *ni) +{ + u8_t insert = 0; + ip_addr_t dst; + + if (dflt != 0) + { + /* the default route 0.0.0.0 */ + ip_addr_set_any(&dst); + insert = 1; + } + else + { + /* route to the network address */ + ip_addr_get_network(&dst, &ni->ip_addr, &ni->netmask); + /* exclude 0.0.0.0 network (reserved for default rte) */ + if (!ip_addr_isany(&dst)) { + insert = 1; + } + } + if (insert) + { + struct mib_list_rootnode *iprte_rn; + struct mib_list_node *iprte_node; + s32_t iprteidx[4]; + u8_t level; + + snmp_iptooid(&dst, &iprteidx[0]); + level = 0; + iprte_rn = &iprtetree_root; + while (level < 4) + { + iprte_node = NULL; + snmp_mib_node_insert(iprte_rn, iprteidx[level], &iprte_node); + if ((level != 3) && (iprte_node != NULL)) + { + if (iprte_node->nptr == NULL) + { + iprte_rn = snmp_mib_lrn_alloc(); + iprte_node->nptr = (struct mib_node*)iprte_rn; + if (iprte_rn != NULL) + { + if (level == 2) + { + iprte_rn->get_object_def = ip_rteentry_get_object_def; + iprte_rn->get_value = ip_rteentry_get_value; + iprte_rn->set_test = noleafs_set_test; + iprte_rn->set_value = noleafs_set_value; + } + } + else + { + /* iprte_rn == NULL, malloc failure */ + LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_iprteidx_tree() insert failed, mem full")); + break; + } + } + else + { + iprte_rn = (struct mib_list_rootnode*)iprte_node->nptr; + } + } + level++; + } + } + /* enable getnext traversal on filled table */ + iprtetable.maxlength = 1; +} + +/** + * Removes ipRouteTable indexes (.ipRouteDest) + * from index tree. + * + * @param dflt non-zero for the default rte, zero for network rte + * @param ni points to network interface for this rte or NULL + * for default route to be removed. + */ +void snmp_delete_iprteidx_tree(u8_t dflt, struct netif *ni) +{ + u8_t del = 0; + ip_addr_t dst; + + if (dflt != 0) + { + /* the default route 0.0.0.0 */ + ip_addr_set_any(&dst); + del = 1; + } + else + { + /* route to the network address */ + ip_addr_get_network(&dst, &ni->ip_addr, &ni->netmask); + /* exclude 0.0.0.0 network (reserved for default rte) */ + if (!ip_addr_isany(&dst)) { + del = 1; + } + } + if (del) + { + struct mib_list_rootnode *iprte_rn, *next, *del_rn[4]; + struct mib_list_node *iprte_n, *del_n[4]; + s32_t iprteidx[4]; + u8_t fc, level, del_cnt; + + snmp_iptooid(&dst, &iprteidx[0]); + /* mark nodes for deletion */ + level = 0; + del_cnt = 0; + iprte_rn = &iprtetree_root; + while ((level < 4) && (iprte_rn != NULL)) + { + fc = snmp_mib_node_find(iprte_rn, iprteidx[level], &iprte_n); + if (fc == 0) + { + /* iprteidx[level] does not exist */ + del_cnt = 0; + iprte_rn = NULL; + } + else if (fc == 1) + { + del_rn[del_cnt] = iprte_rn; + del_n[del_cnt] = iprte_n; + del_cnt++; + iprte_rn = (struct mib_list_rootnode*)(iprte_n->nptr); + } + else if (fc == 2) + { + /* reset delete (2 or more childs) */ + del_cnt = 0; + iprte_rn = (struct mib_list_rootnode*)(iprte_n->nptr); + } + level++; + } + /* delete marked index nodes */ + while (del_cnt > 0) + { + del_cnt--; + + iprte_rn = del_rn[del_cnt]; + iprte_n = del_n[del_cnt]; + + next = snmp_mib_node_delete(iprte_rn, iprte_n); + if (next != NULL) + { + LWIP_ASSERT("next_count == 0",next->count == 0); + snmp_mib_lrn_free(next); + } + } + } + /* disable getnext traversal on empty table */ + if (iprtetree_root.count == 0) iprtetable.maxlength = 0; +} + + +void snmp_inc_icmpinmsgs(void) +{ + icmpinmsgs++; +} + +void snmp_inc_icmpinerrors(void) +{ + icmpinerrors++; +} + +void snmp_inc_icmpindestunreachs(void) +{ + icmpindestunreachs++; +} + +void snmp_inc_icmpintimeexcds(void) +{ + icmpintimeexcds++; +} + +void snmp_inc_icmpinparmprobs(void) +{ + icmpinparmprobs++; +} + +void snmp_inc_icmpinsrcquenchs(void) +{ + icmpinsrcquenchs++; +} + +void snmp_inc_icmpinredirects(void) +{ + icmpinredirects++; +} + +void snmp_inc_icmpinechos(void) +{ + icmpinechos++; +} + +void snmp_inc_icmpinechoreps(void) +{ + icmpinechoreps++; +} + +void snmp_inc_icmpintimestamps(void) +{ + icmpintimestamps++; +} + +void snmp_inc_icmpintimestampreps(void) +{ + icmpintimestampreps++; +} + +void snmp_inc_icmpinaddrmasks(void) +{ + icmpinaddrmasks++; +} + +void snmp_inc_icmpinaddrmaskreps(void) +{ + icmpinaddrmaskreps++; +} + +void snmp_inc_icmpoutmsgs(void) +{ + icmpoutmsgs++; +} + +void snmp_inc_icmpouterrors(void) +{ + icmpouterrors++; +} + +void snmp_inc_icmpoutdestunreachs(void) +{ + icmpoutdestunreachs++; +} + +void snmp_inc_icmpouttimeexcds(void) +{ + icmpouttimeexcds++; +} + +void snmp_inc_icmpoutparmprobs(void) +{ + icmpoutparmprobs++; +} + +void snmp_inc_icmpoutsrcquenchs(void) +{ + icmpoutsrcquenchs++; +} + +void snmp_inc_icmpoutredirects(void) +{ + icmpoutredirects++; +} + +void snmp_inc_icmpoutechos(void) +{ + icmpoutechos++; +} + +void snmp_inc_icmpoutechoreps(void) +{ + icmpoutechoreps++; +} + +void snmp_inc_icmpouttimestamps(void) +{ + icmpouttimestamps++; +} + +void snmp_inc_icmpouttimestampreps(void) +{ + icmpouttimestampreps++; +} + +void snmp_inc_icmpoutaddrmasks(void) +{ + icmpoutaddrmasks++; +} + +void snmp_inc_icmpoutaddrmaskreps(void) +{ + icmpoutaddrmaskreps++; +} + +void snmp_inc_tcpactiveopens(void) +{ + tcpactiveopens++; +} + +void snmp_inc_tcppassiveopens(void) +{ + tcppassiveopens++; +} + +void snmp_inc_tcpattemptfails(void) +{ + tcpattemptfails++; +} + +void snmp_inc_tcpestabresets(void) +{ + tcpestabresets++; +} + +void snmp_inc_tcpinsegs(void) +{ + tcpinsegs++; +} + +void snmp_inc_tcpoutsegs(void) +{ + tcpoutsegs++; +} + +void snmp_inc_tcpretranssegs(void) +{ + tcpretranssegs++; +} + +void snmp_inc_tcpinerrs(void) +{ + tcpinerrs++; +} + +void snmp_inc_tcpoutrsts(void) +{ + tcpoutrsts++; +} + +void snmp_inc_udpindatagrams(void) +{ + udpindatagrams++; +} + +void snmp_inc_udpnoports(void) +{ + udpnoports++; +} + +void snmp_inc_udpinerrors(void) +{ + udpinerrors++; +} + +void snmp_inc_udpoutdatagrams(void) +{ + udpoutdatagrams++; +} + +/** + * Inserts udpTable indexes (.udpLocalAddress.udpLocalPort) + * into index tree. + */ +void snmp_insert_udpidx_tree(struct udp_pcb *pcb) +{ + struct mib_list_rootnode *udp_rn; + struct mib_list_node *udp_node; + s32_t udpidx[5]; + u8_t level; + + LWIP_ASSERT("pcb != NULL", pcb != NULL); + snmp_iptooid(ipX_2_ip(&pcb->local_ip), &udpidx[0]); + udpidx[4] = pcb->local_port; + + udp_rn = &udp_root; + for (level = 0; level < 5; level++) + { + udp_node = NULL; + snmp_mib_node_insert(udp_rn, udpidx[level], &udp_node); + if ((level != 4) && (udp_node != NULL)) + { + if (udp_node->nptr == NULL) + { + udp_rn = snmp_mib_lrn_alloc(); + udp_node->nptr = (struct mib_node*)udp_rn; + if (udp_rn != NULL) + { + if (level == 3) + { + udp_rn->get_object_def = udpentry_get_object_def; + udp_rn->get_value = udpentry_get_value; + udp_rn->set_test = noleafs_set_test; + udp_rn->set_value = noleafs_set_value; + } + } + else + { + /* udp_rn == NULL, malloc failure */ + LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_udpidx_tree() insert failed, mem full")); + break; + } + } + else + { + udp_rn = (struct mib_list_rootnode*)udp_node->nptr; + } + } + } + udptable.maxlength = 1; +} + +/** + * Removes udpTable indexes (.udpLocalAddress.udpLocalPort) + * from index tree. + */ +void snmp_delete_udpidx_tree(struct udp_pcb *pcb) +{ + struct udp_pcb *npcb; + struct mib_list_rootnode *udp_rn, *next, *del_rn[5]; + struct mib_list_node *udp_n, *del_n[5]; + s32_t udpidx[5]; + u8_t bindings, fc, level, del_cnt; + + LWIP_ASSERT("pcb != NULL", pcb != NULL); + snmp_iptooid(ipX_2_ip(&pcb->local_ip), &udpidx[0]); + udpidx[4] = pcb->local_port; + + /* count PCBs for a given binding + (e.g. when reusing ports or for temp output PCBs) */ + bindings = 0; + npcb = udp_pcbs; + while ((npcb != NULL)) + { + if (ipX_addr_cmp(0, &npcb->local_ip, &pcb->local_ip) && + (npcb->local_port == udpidx[4])) + { + bindings++; + } + npcb = npcb->next; + } + if (bindings == 1) + { + /* selectively remove */ + /* mark nodes for deletion */ + level = 0; + del_cnt = 0; + udp_rn = &udp_root; + while ((level < 5) && (udp_rn != NULL)) + { + fc = snmp_mib_node_find(udp_rn, udpidx[level], &udp_n); + if (fc == 0) + { + /* udpidx[level] does not exist */ + del_cnt = 0; + udp_rn = NULL; + } + else if (fc == 1) + { + del_rn[del_cnt] = udp_rn; + del_n[del_cnt] = udp_n; + del_cnt++; + udp_rn = (struct mib_list_rootnode*)(udp_n->nptr); + } + else if (fc == 2) + { + /* reset delete (2 or more childs) */ + del_cnt = 0; + udp_rn = (struct mib_list_rootnode*)(udp_n->nptr); + } + level++; + } + /* delete marked index nodes */ + while (del_cnt > 0) + { + del_cnt--; + + udp_rn = del_rn[del_cnt]; + udp_n = del_n[del_cnt]; + + next = snmp_mib_node_delete(udp_rn, udp_n); + if (next != NULL) + { + LWIP_ASSERT("next_count == 0",next->count == 0); + snmp_mib_lrn_free(next); + } + } + } + /* disable getnext traversal on empty table */ + if (udp_root.count == 0) udptable.maxlength = 0; +} + + +void snmp_inc_snmpinpkts(void) +{ + snmpinpkts++; +} + +void snmp_inc_snmpoutpkts(void) +{ + snmpoutpkts++; +} + +void snmp_inc_snmpinbadversions(void) +{ + snmpinbadversions++; +} + +void snmp_inc_snmpinbadcommunitynames(void) +{ + snmpinbadcommunitynames++; +} + +void snmp_inc_snmpinbadcommunityuses(void) +{ + snmpinbadcommunityuses++; +} + +void snmp_inc_snmpinasnparseerrs(void) +{ + snmpinasnparseerrs++; +} + +void snmp_inc_snmpintoobigs(void) +{ + snmpintoobigs++; +} + +void snmp_inc_snmpinnosuchnames(void) +{ + snmpinnosuchnames++; +} + +void snmp_inc_snmpinbadvalues(void) +{ + snmpinbadvalues++; +} + +void snmp_inc_snmpinreadonlys(void) +{ + snmpinreadonlys++; +} + +void snmp_inc_snmpingenerrs(void) +{ + snmpingenerrs++; +} + +void snmp_add_snmpintotalreqvars(u8_t value) +{ + snmpintotalreqvars += value; +} + +void snmp_add_snmpintotalsetvars(u8_t value) +{ + snmpintotalsetvars += value; +} + +void snmp_inc_snmpingetrequests(void) +{ + snmpingetrequests++; +} + +void snmp_inc_snmpingetnexts(void) +{ + snmpingetnexts++; +} + +void snmp_inc_snmpinsetrequests(void) +{ + snmpinsetrequests++; +} + +void snmp_inc_snmpingetresponses(void) +{ + snmpingetresponses++; +} + +void snmp_inc_snmpintraps(void) +{ + snmpintraps++; +} + +void snmp_inc_snmpouttoobigs(void) +{ + snmpouttoobigs++; +} + +void snmp_inc_snmpoutnosuchnames(void) +{ + snmpoutnosuchnames++; +} + +void snmp_inc_snmpoutbadvalues(void) +{ + snmpoutbadvalues++; +} + +void snmp_inc_snmpoutgenerrs(void) +{ + snmpoutgenerrs++; +} + +void snmp_inc_snmpoutgetrequests(void) +{ + snmpoutgetrequests++; +} + +void snmp_inc_snmpoutgetnexts(void) +{ + snmpoutgetnexts++; +} + +void snmp_inc_snmpoutsetrequests(void) +{ + snmpoutsetrequests++; +} + +void snmp_inc_snmpoutgetresponses(void) +{ + snmpoutgetresponses++; +} + +void snmp_inc_snmpouttraps(void) +{ + snmpouttraps++; +} + +void snmp_get_snmpgrpid_ptr(struct snmp_obj_id **oid) +{ + *oid = &snmpgrp_id; +} + +void snmp_set_snmpenableauthentraps(u8_t *value) +{ + if (value != NULL) + { + snmpenableauthentraps_ptr = value; + } +} + +void snmp_get_snmpenableauthentraps(u8_t *value) +{ + *value = *snmpenableauthentraps_ptr; +} + +void +noleafs_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) +{ + LWIP_UNUSED_ARG(ident_len); + LWIP_UNUSED_ARG(ident); + od->instance = MIB_OBJECT_NONE; +} + +void +noleafs_get_value(struct obj_def *od, u16_t len, void *value) +{ + LWIP_UNUSED_ARG(od); + LWIP_UNUSED_ARG(len); + LWIP_UNUSED_ARG(value); +} + +u8_t +noleafs_set_test(struct obj_def *od, u16_t len, void *value) +{ + LWIP_UNUSED_ARG(od); + LWIP_UNUSED_ARG(len); + LWIP_UNUSED_ARG(value); + /* can't set */ + return 0; +} + +void +noleafs_set_value(struct obj_def *od, u16_t len, void *value) +{ + LWIP_UNUSED_ARG(od); + LWIP_UNUSED_ARG(len); + LWIP_UNUSED_ARG(value); +} + + +/** + * Returns systems object definitions. + * + * @param ident_len the address length (2) + * @param ident points to objectname.0 (object id trailer) + * @param od points to object definition. + */ +static void +system_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) +{ + u8_t id; + + /* return to object name, adding index depth (1) */ + ident_len += 1; + ident -= 1; + if (ident_len == 2) + { + od->id_inst_len = ident_len; + od->id_inst_ptr = ident; + + LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); + id = (u8_t)ident[0]; + LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def system.%"U16_F".0\n",(u16_t)id)); + switch (id) + { + case 1: /* sysDescr */ + od->instance = MIB_OBJECT_SCALAR; + od->access = MIB_OBJECT_READ_ONLY; + od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); + od->v_len = *sysdescr_len_ptr; + break; + case 2: /* sysObjectID */ + od->instance = MIB_OBJECT_SCALAR; + od->access = MIB_OBJECT_READ_ONLY; + od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID); + od->v_len = sysobjid.len * sizeof(s32_t); + break; + case 3: /* sysUpTime */ + od->instance = MIB_OBJECT_SCALAR; + od->access = MIB_OBJECT_READ_ONLY; + od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS); + od->v_len = sizeof(u32_t); + break; + case 4: /* sysContact */ + od->instance = MIB_OBJECT_SCALAR; + od->access = MIB_OBJECT_READ_WRITE; + od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); + od->v_len = *syscontact_len_ptr; + break; + case 5: /* sysName */ + od->instance = MIB_OBJECT_SCALAR; + od->access = MIB_OBJECT_READ_WRITE; + od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); + od->v_len = *sysname_len_ptr; + break; + case 6: /* sysLocation */ + od->instance = MIB_OBJECT_SCALAR; + od->access = MIB_OBJECT_READ_WRITE; + od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); + od->v_len = *syslocation_len_ptr; + break; + case 7: /* sysServices */ + od->instance = MIB_OBJECT_SCALAR; + od->access = MIB_OBJECT_READ_ONLY; + od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); + od->v_len = sizeof(s32_t); + break; + default: + LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_get_object_def: no such object\n")); + od->instance = MIB_OBJECT_NONE; + break; + }; + } + else + { + LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_get_object_def: no scalar\n")); + od->instance = MIB_OBJECT_NONE; + } +} + +/** + * Returns system object value. + * + * @param ident_len the address length (2) + * @param ident points to objectname.0 (object id trailer) + * @param len return value space (in bytes) + * @param value points to (varbind) space to copy value into. + */ +static void +system_get_value(struct obj_def *od, u16_t len, void *value) +{ + u8_t id; + + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; + switch (id) + { + case 1: /* sysDescr */ + ocstrncpy((u8_t*)value, sysdescr_ptr, len); + break; + case 2: /* sysObjectID */ + objectidncpy((s32_t*)value, (s32_t*)sysobjid.id, (u8_t)(len / sizeof(s32_t))); + break; + case 3: /* sysUpTime */ + { + snmp_get_sysuptime((u32_t*)value); + } + break; + case 4: /* sysContact */ + ocstrncpy((u8_t*)value, syscontact_ptr, len); + break; + case 5: /* sysName */ + ocstrncpy((u8_t*)value, sysname_ptr, len); + break; + case 6: /* sysLocation */ + ocstrncpy((u8_t*)value, syslocation_ptr, len); + break; + case 7: /* sysServices */ + { + s32_t *sint_ptr = (s32_t*)value; + *sint_ptr = sysservices; + } + break; + }; +} + +static u8_t +system_set_test(struct obj_def *od, u16_t len, void *value) +{ + u8_t id, set_ok; + + LWIP_UNUSED_ARG(value); + set_ok = 0; + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; + switch (id) + { + case 4: /* sysContact */ + if ((syscontact_ptr != syscontact_default) && + (len <= 255)) + { + set_ok = 1; + } + break; + case 5: /* sysName */ + if ((sysname_ptr != sysname_default) && + (len <= 255)) + { + set_ok = 1; + } + break; + case 6: /* sysLocation */ + if ((syslocation_ptr != syslocation_default) && + (len <= 255)) + { + set_ok = 1; + } + break; + }; + return set_ok; +} + +static void +system_set_value(struct obj_def *od, u16_t len, void *value) +{ + u8_t id; + + LWIP_ASSERT("invalid len", len <= 0xff); + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; + switch (id) + { + case 4: /* sysContact */ + ocstrncpy(syscontact_ptr, (u8_t*)value, len); + *syscontact_len_ptr = (u8_t)len; + break; + case 5: /* sysName */ + ocstrncpy(sysname_ptr, (u8_t*)value, len); + *sysname_len_ptr = (u8_t)len; + break; + case 6: /* sysLocation */ + ocstrncpy(syslocation_ptr, (u8_t*)value, len); + *syslocation_len_ptr = (u8_t)len; + break; + }; +} + +/** + * Returns interfaces.ifnumber object definition. + * + * @param ident_len the address length (2) + * @param ident points to objectname.index + * @param od points to object definition. + */ +static void +interfaces_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) +{ + /* return to object name, adding index depth (1) */ + ident_len += 1; + ident -= 1; + if (ident_len == 2) + { + od->id_inst_len = ident_len; + od->id_inst_ptr = ident; + + od->instance = MIB_OBJECT_SCALAR; + od->access = MIB_OBJECT_READ_ONLY; + od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); + od->v_len = sizeof(s32_t); + } + else + { + LWIP_DEBUGF(SNMP_MIB_DEBUG,("interfaces_get_object_def: no scalar\n")); + od->instance = MIB_OBJECT_NONE; + } +} + +/** + * Returns interfaces.ifnumber object value. + * + * @param ident_len the address length (2) + * @param ident points to objectname.0 (object id trailer) + * @param len return value space (in bytes) + * @param value points to (varbind) space to copy value into. + */ +static void +interfaces_get_value(struct obj_def *od, u16_t len, void *value) +{ + LWIP_UNUSED_ARG(len); + if (od->id_inst_ptr[0] == 1) + { + s32_t *sint_ptr = (s32_t*)value; + *sint_ptr = iflist_root.count; + } +} + +/** + * Returns ifentry object definitions. + * + * @param ident_len the address length (2) + * @param ident points to objectname.index + * @param od points to object definition. + */ +static void +ifentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) +{ + u8_t id; + + /* return to object name, adding index depth (1) */ + ident_len += 1; + ident -= 1; + if (ident_len == 2) + { + od->id_inst_len = ident_len; + od->id_inst_ptr = ident; + + LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); + id = (u8_t)ident[0]; + LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def ifentry.%"U16_F"\n",(u16_t)id)); + switch (id) + { + case 1: /* ifIndex */ + case 3: /* ifType */ + case 4: /* ifMtu */ + case 8: /* ifOperStatus */ + od->instance = MIB_OBJECT_TAB; + od->access = MIB_OBJECT_READ_ONLY; + od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); + od->v_len = sizeof(s32_t); + break; + case 2: /* ifDescr */ + od->instance = MIB_OBJECT_TAB; + od->access = MIB_OBJECT_READ_ONLY; + od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); + /** @todo this should be some sort of sizeof(struct netif.name) */ + od->v_len = 2; + break; + case 5: /* ifSpeed */ + case 21: /* ifOutQLen */ + od->instance = MIB_OBJECT_TAB; + od->access = MIB_OBJECT_READ_ONLY; + od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE); + od->v_len = sizeof(u32_t); + break; + case 6: /* ifPhysAddress */ + { + struct netif *netif; + + snmp_ifindextonetif(ident[1], &netif); + od->instance = MIB_OBJECT_TAB; + od->access = MIB_OBJECT_READ_ONLY; + od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); + od->v_len = netif->hwaddr_len; + } + break; + case 7: /* ifAdminStatus */ + od->instance = MIB_OBJECT_TAB; + od->access = MIB_OBJECT_READ_WRITE; + od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); + od->v_len = sizeof(s32_t); + break; + case 9: /* ifLastChange */ + od->instance = MIB_OBJECT_TAB; + od->access = MIB_OBJECT_READ_ONLY; + od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS); + od->v_len = sizeof(u32_t); + break; + case 10: /* ifInOctets */ + case 11: /* ifInUcastPkts */ + case 12: /* ifInNUcastPkts */ + case 13: /* ifInDiscarts */ + case 14: /* ifInErrors */ + case 15: /* ifInUnkownProtos */ + case 16: /* ifOutOctets */ + case 17: /* ifOutUcastPkts */ + case 18: /* ifOutNUcastPkts */ + case 19: /* ifOutDiscarts */ + case 20: /* ifOutErrors */ + od->instance = MIB_OBJECT_TAB; + od->access = MIB_OBJECT_READ_ONLY; + od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER); + od->v_len = sizeof(u32_t); + break; + case 22: /* ifSpecific */ + /** @note returning zeroDotZero (0.0) no media specific MIB support */ + od->instance = MIB_OBJECT_TAB; + od->access = MIB_OBJECT_READ_ONLY; + od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID); + od->v_len = ifspecific.len * sizeof(s32_t); + break; + default: + LWIP_DEBUGF(SNMP_MIB_DEBUG,("ifentry_get_object_def: no such object\n")); + od->instance = MIB_OBJECT_NONE; + break; + }; + } + else + { + LWIP_DEBUGF(SNMP_MIB_DEBUG,("ifentry_get_object_def: no scalar\n")); + od->instance = MIB_OBJECT_NONE; + } +} + +/** + * Returns ifentry object value. + * + * @param ident_len the address length (2) + * @param ident points to objectname.0 (object id trailer) + * @param len return value space (in bytes) + * @param value points to (varbind) space to copy value into. + */ +static void +ifentry_get_value(struct obj_def *od, u16_t len, void *value) +{ + struct netif *netif; + u8_t id; + + snmp_ifindextonetif(od->id_inst_ptr[1], &netif); + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; + switch (id) + { + case 1: /* ifIndex */ + { + s32_t *sint_ptr = (s32_t*)value; + *sint_ptr = od->id_inst_ptr[1]; + } + break; + case 2: /* ifDescr */ + ocstrncpy((u8_t*)value, (u8_t*)netif->name, len); + break; + case 3: /* ifType */ + { + s32_t *sint_ptr = (s32_t*)value; + *sint_ptr = netif->link_type; + } + break; + case 4: /* ifMtu */ + { + s32_t *sint_ptr = (s32_t*)value; + *sint_ptr = netif->mtu; + } + break; + case 5: /* ifSpeed */ + { + u32_t *uint_ptr = (u32_t*)value; + *uint_ptr = netif->link_speed; + } + break; + case 6: /* ifPhysAddress */ + ocstrncpy((u8_t*)value, netif->hwaddr, len); + break; + case 7: /* ifAdminStatus */ + { + s32_t *sint_ptr = (s32_t*)value; + if (netif_is_up(netif)) + { + if (netif_is_link_up(netif)) + { + *sint_ptr = 1; /* up */ + } + else + { + *sint_ptr = 7; /* lowerLayerDown */ + } + } + else + { + *sint_ptr = 2; /* down */ + } + } + break; + case 8: /* ifOperStatus */ + { + s32_t *sint_ptr = (s32_t*)value; + if (netif_is_up(netif)) + { + *sint_ptr = 1; + } + else + { + *sint_ptr = 2; + } + } + break; + case 9: /* ifLastChange */ + { + u32_t *uint_ptr = (u32_t*)value; + *uint_ptr = netif->ts; + } + break; + case 10: /* ifInOctets */ + { + u32_t *uint_ptr = (u32_t*)value; + *uint_ptr = netif->ifinoctets; + } + break; + case 11: /* ifInUcastPkts */ + { + u32_t *uint_ptr = (u32_t*)value; + *uint_ptr = netif->ifinucastpkts; + } + break; + case 12: /* ifInNUcastPkts */ + { + u32_t *uint_ptr = (u32_t*)value; + *uint_ptr = netif->ifinnucastpkts; + } + break; + case 13: /* ifInDiscarts */ + { + u32_t *uint_ptr = (u32_t*)value; + *uint_ptr = netif->ifindiscards; + } + break; + case 14: /* ifInErrors */ + case 15: /* ifInUnkownProtos */ + /** @todo add these counters! */ + { + u32_t *uint_ptr = (u32_t*)value; + *uint_ptr = 0; + } + break; + case 16: /* ifOutOctets */ + { + u32_t *uint_ptr = (u32_t*)value; + *uint_ptr = netif->ifoutoctets; + } + break; + case 17: /* ifOutUcastPkts */ + { + u32_t *uint_ptr = (u32_t*)value; + *uint_ptr = netif->ifoutucastpkts; + } + break; + case 18: /* ifOutNUcastPkts */ + { + u32_t *uint_ptr = (u32_t*)value; + *uint_ptr = netif->ifoutnucastpkts; + } + break; + case 19: /* ifOutDiscarts */ + { + u32_t *uint_ptr = (u32_t*)value; + *uint_ptr = netif->ifoutdiscards; + } + break; + case 20: /* ifOutErrors */ + /** @todo add this counter! */ + { + u32_t *uint_ptr = (u32_t*)value; + *uint_ptr = 0; + } + break; + case 21: /* ifOutQLen */ + /** @todo figure out if this must be 0 (no queue) or 1? */ + { + u32_t *uint_ptr = (u32_t*)value; + *uint_ptr = 0; + } + break; + case 22: /* ifSpecific */ + objectidncpy((s32_t*)value, (s32_t*)ifspecific.id, (u8_t)(len / sizeof(s32_t))); + break; + }; +} + +#if !SNMP_SAFE_REQUESTS +static u8_t +ifentry_set_test(struct obj_def *od, u16_t len, void *value) +{ + struct netif *netif; + u8_t id, set_ok; + LWIP_UNUSED_ARG(len); + + set_ok = 0; + snmp_ifindextonetif(od->id_inst_ptr[1], &netif); + id = (u8_t)od->id_inst_ptr[0]; + switch (id) + { + case 7: /* ifAdminStatus */ + { + s32_t *sint_ptr = (s32_t*)value; + if (*sint_ptr == 1 || *sint_ptr == 2) + set_ok = 1; + } + break; + } + return set_ok; +} + +static void +ifentry_set_value(struct obj_def *od, u16_t len, void *value) +{ + struct netif *netif; + u8_t id; + LWIP_UNUSED_ARG(len); + + snmp_ifindextonetif(od->id_inst_ptr[1], &netif); + id = (u8_t)od->id_inst_ptr[0]; + switch (id) + { + case 7: /* ifAdminStatus */ + { + s32_t *sint_ptr = (s32_t*)value; + if (*sint_ptr == 1) + { + netif_set_up(netif); + } + else if (*sint_ptr == 2) + { + netif_set_down(netif); + } + } + break; + } +} +#endif /* SNMP_SAFE_REQUESTS */ + +/** + * Returns atentry object definitions. + * + * @param ident_len the address length (6) + * @param ident points to objectname.atifindex.atnetaddress + * @param od points to object definition. + */ +static void +atentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) +{ + /* return to object name, adding index depth (5) */ + ident_len += 5; + ident -= 5; + + if (ident_len == 6) + { + od->id_inst_len = ident_len; + od->id_inst_ptr = ident; + + switch (ident[0]) + { + case 1: /* atIfIndex */ + od->instance = MIB_OBJECT_TAB; + od->access = MIB_OBJECT_READ_WRITE; + od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); + od->v_len = sizeof(s32_t); + break; + case 2: /* atPhysAddress */ + od->instance = MIB_OBJECT_TAB; + od->access = MIB_OBJECT_READ_WRITE; + od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); + od->v_len = 6; /** @todo try to use netif::hwaddr_len */ + break; + case 3: /* atNetAddress */ + od->instance = MIB_OBJECT_TAB; + od->access = MIB_OBJECT_READ_WRITE; + od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR); + od->v_len = 4; + break; + default: + LWIP_DEBUGF(SNMP_MIB_DEBUG,("atentry_get_object_def: no such object\n")); + od->instance = MIB_OBJECT_NONE; + break; + } + } + else + { + LWIP_DEBUGF(SNMP_MIB_DEBUG,("atentry_get_object_def: no scalar\n")); + od->instance = MIB_OBJECT_NONE; + } +} + +static void +atentry_get_value(struct obj_def *od, u16_t len, void *value) +{ +#if LWIP_ARP + u8_t id; + struct eth_addr* ethaddr_ret; + ip_addr_t* ipaddr_ret; +#endif /* LWIP_ARP */ + ip_addr_t ip; + struct netif *netif; + + LWIP_UNUSED_ARG(len); + LWIP_UNUSED_ARG(value);/* if !LWIP_ARP */ + + snmp_ifindextonetif(od->id_inst_ptr[1], &netif); + snmp_oidtoip(&od->id_inst_ptr[2], &ip); + +#if LWIP_ARP /** @todo implement a netif_find_addr */ + if (etharp_find_addr(netif, &ip, ðaddr_ret, &ipaddr_ret) > -1) + { + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; + switch (id) + { + case 1: /* atIfIndex */ + { + s32_t *sint_ptr = (s32_t*)value; + *sint_ptr = od->id_inst_ptr[1]; + } + break; + case 2: /* atPhysAddress */ + { + struct eth_addr *dst = (struct eth_addr*)value; + + *dst = *ethaddr_ret; + } + break; + case 3: /* atNetAddress */ + { + ip_addr_t *dst = (ip_addr_t*)value; + + *dst = *ipaddr_ret; + } + break; + } + } +#endif /* LWIP_ARP */ +} + +static void +ip_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) +{ + u8_t id; + + /* return to object name, adding index depth (1) */ + ident_len += 1; + ident -= 1; + if (ident_len == 2) + { + od->id_inst_len = ident_len; + od->id_inst_ptr = ident; + + LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); + id = (u8_t)ident[0]; + LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def ip.%"U16_F".0\n",(u16_t)id)); + switch (id) + { + case 1: /* ipForwarding */ + case 2: /* ipDefaultTTL */ + od->instance = MIB_OBJECT_SCALAR; + od->access = MIB_OBJECT_READ_WRITE; + od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); + od->v_len = sizeof(s32_t); + break; + case 3: /* ipInReceives */ + case 4: /* ipInHdrErrors */ + case 5: /* ipInAddrErrors */ + case 6: /* ipForwDatagrams */ + case 7: /* ipInUnknownProtos */ + case 8: /* ipInDiscards */ + case 9: /* ipInDelivers */ + case 10: /* ipOutRequests */ + case 11: /* ipOutDiscards */ + case 12: /* ipOutNoRoutes */ + case 14: /* ipReasmReqds */ + case 15: /* ipReasmOKs */ + case 16: /* ipReasmFails */ + case 17: /* ipFragOKs */ + case 18: /* ipFragFails */ + case 19: /* ipFragCreates */ + case 23: /* ipRoutingDiscards */ + od->instance = MIB_OBJECT_SCALAR; + od->access = MIB_OBJECT_READ_ONLY; + od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER); + od->v_len = sizeof(u32_t); + break; + case 13: /* ipReasmTimeout */ + od->instance = MIB_OBJECT_SCALAR; + od->access = MIB_OBJECT_READ_ONLY; + od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); + od->v_len = sizeof(s32_t); + break; + default: + LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_get_object_def: no such object\n")); + od->instance = MIB_OBJECT_NONE; + break; + }; + } + else + { + LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_get_object_def: no scalar\n")); + od->instance = MIB_OBJECT_NONE; + } +} + +static void +ip_get_value(struct obj_def *od, u16_t len, void *value) +{ + u8_t id; + + LWIP_UNUSED_ARG(len); + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; + switch (id) + { + case 1: /* ipForwarding */ + { + s32_t *sint_ptr = (s32_t*)value; +#if IP_FORWARD + /* forwarding */ + *sint_ptr = 1; +#else + /* not-forwarding */ + *sint_ptr = 2; +#endif + } + break; + case 2: /* ipDefaultTTL */ + { + s32_t *sint_ptr = (s32_t*)value; + *sint_ptr = IP_DEFAULT_TTL; + } + break; + case 3: /* ipInReceives */ + { + u32_t *uint_ptr = (u32_t*)value; + *uint_ptr = ipinreceives; + } + break; + case 4: /* ipInHdrErrors */ + { + u32_t *uint_ptr = (u32_t*)value; + *uint_ptr = ipinhdrerrors; + } + break; + case 5: /* ipInAddrErrors */ + { + u32_t *uint_ptr = (u32_t*)value; + *uint_ptr = ipinaddrerrors; + } + break; + case 6: /* ipForwDatagrams */ + { + u32_t *uint_ptr = (u32_t*)value; + *uint_ptr = ipforwdatagrams; + } + break; + case 7: /* ipInUnknownProtos */ + { + u32_t *uint_ptr = (u32_t*)value; + *uint_ptr = ipinunknownprotos; + } + break; + case 8: /* ipInDiscards */ + { + u32_t *uint_ptr = (u32_t*)value; + *uint_ptr = ipindiscards; + } + break; + case 9: /* ipInDelivers */ + { + u32_t *uint_ptr = (u32_t*)value; + *uint_ptr = ipindelivers; + } + break; + case 10: /* ipOutRequests */ + { + u32_t *uint_ptr = (u32_t*)value; + *uint_ptr = ipoutrequests; + } + break; + case 11: /* ipOutDiscards */ + { + u32_t *uint_ptr = (u32_t*)value; + *uint_ptr = ipoutdiscards; + } + break; + case 12: /* ipOutNoRoutes */ + { + u32_t *uint_ptr = (u32_t*)value; + *uint_ptr = ipoutnoroutes; + } + break; + case 13: /* ipReasmTimeout */ + { + s32_t *sint_ptr = (s32_t*)value; +#if IP_REASSEMBLY + *sint_ptr = IP_REASS_MAXAGE; +#else + *sint_ptr = 0; +#endif + } + break; + case 14: /* ipReasmReqds */ + { + u32_t *uint_ptr = (u32_t*)value; + *uint_ptr = ipreasmreqds; + } + break; + case 15: /* ipReasmOKs */ + { + u32_t *uint_ptr = (u32_t*)value; + *uint_ptr = ipreasmoks; + } + break; + case 16: /* ipReasmFails */ + { + u32_t *uint_ptr = (u32_t*)value; + *uint_ptr = ipreasmfails; + } + break; + case 17: /* ipFragOKs */ + { + u32_t *uint_ptr = (u32_t*)value; + *uint_ptr = ipfragoks; + } + break; + case 18: /* ipFragFails */ + { + u32_t *uint_ptr = (u32_t*)value; + *uint_ptr = ipfragfails; + } + break; + case 19: /* ipFragCreates */ + { + u32_t *uint_ptr = (u32_t*)value; + *uint_ptr = ipfragcreates; + } + break; + case 23: /* ipRoutingDiscards */ + /** @todo can lwIP discard routes at all?? hardwire this to 0?? */ + { + u32_t *uint_ptr = (u32_t*)value; + *uint_ptr = iproutingdiscards; + } + break; + }; +} + +/** + * Test ip object value before setting. + * + * @param od is the object definition + * @param len return value space (in bytes) + * @param value points to (varbind) space to copy value from. + * + * @note we allow set if the value matches the hardwired value, + * otherwise return badvalue. + */ +static u8_t +ip_set_test(struct obj_def *od, u16_t len, void *value) +{ + u8_t id, set_ok; + s32_t *sint_ptr = (s32_t*)value; + + LWIP_UNUSED_ARG(len); + set_ok = 0; + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; + switch (id) + { + case 1: /* ipForwarding */ +#if IP_FORWARD + /* forwarding */ + if (*sint_ptr == 1) +#else + /* not-forwarding */ + if (*sint_ptr == 2) +#endif + { + set_ok = 1; + } + break; + case 2: /* ipDefaultTTL */ + if (*sint_ptr == IP_DEFAULT_TTL) + { + set_ok = 1; + } + break; + }; + return set_ok; +} + +static void +ip_addrentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) +{ + /* return to object name, adding index depth (4) */ + ident_len += 4; + ident -= 4; + + if (ident_len == 5) + { + u8_t id; + + od->id_inst_len = ident_len; + od->id_inst_ptr = ident; + + LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); + id = (u8_t)ident[0]; + switch (id) + { + case 1: /* ipAdEntAddr */ + case 3: /* ipAdEntNetMask */ + od->instance = MIB_OBJECT_TAB; + od->access = MIB_OBJECT_READ_ONLY; + od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR); + od->v_len = 4; + break; + case 2: /* ipAdEntIfIndex */ + case 4: /* ipAdEntBcastAddr */ + case 5: /* ipAdEntReasmMaxSize */ + od->instance = MIB_OBJECT_TAB; + od->access = MIB_OBJECT_READ_ONLY; + od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); + od->v_len = sizeof(s32_t); + break; + default: + LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_addrentry_get_object_def: no such object\n")); + od->instance = MIB_OBJECT_NONE; + break; + } + } + else + { + LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_addrentry_get_object_def: no scalar\n")); + od->instance = MIB_OBJECT_NONE; + } +} + +static void +ip_addrentry_get_value(struct obj_def *od, u16_t len, void *value) +{ + u8_t id; + u16_t ifidx; + ip_addr_t ip; + struct netif *netif = netif_list; + + LWIP_UNUSED_ARG(len); + snmp_oidtoip(&od->id_inst_ptr[1], &ip); + ifidx = 0; + while ((netif != NULL) && !ip_addr_cmp(&ip, &netif->ip_addr)) + { + netif = netif->next; + ifidx++; + } + + if (netif != NULL) + { + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; + switch (id) + { + case 1: /* ipAdEntAddr */ + { + ip_addr_t *dst = (ip_addr_t*)value; + *dst = netif->ip_addr; + } + break; + case 2: /* ipAdEntIfIndex */ + { + s32_t *sint_ptr = (s32_t*)value; + *sint_ptr = ifidx + 1; + } + break; + case 3: /* ipAdEntNetMask */ + { + ip_addr_t *dst = (ip_addr_t*)value; + *dst = netif->netmask; + } + break; + case 4: /* ipAdEntBcastAddr */ + { + s32_t *sint_ptr = (s32_t*)value; + + /* lwIP oddity, there's no broadcast + address in the netif we can rely on */ + *sint_ptr = IPADDR_BROADCAST & 1; + } + break; + case 5: /* ipAdEntReasmMaxSize */ + { + s32_t *sint_ptr = (s32_t*)value; +#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... + */ + *sint_ptr = (IP_HLEN + ((IP_REASS_MAX_PBUFS/2) * + (PBUF_POOL_BUFSIZE - 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 */ + *sint_ptr = 0; +#endif + } + break; + } + } +} + +/** + * @note + * lwIP IP routing is currently using the network addresses in netif_list. + * if no suitable network IP is found in netif_list, the default_netif is used. + */ +static void +ip_rteentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) +{ + u8_t id; + + /* return to object name, adding index depth (4) */ + ident_len += 4; + ident -= 4; + + if (ident_len == 5) + { + od->id_inst_len = ident_len; + od->id_inst_ptr = ident; + + LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); + id = (u8_t)ident[0]; + switch (id) + { + case 1: /* ipRouteDest */ + case 7: /* ipRouteNextHop */ + case 11: /* ipRouteMask */ + od->instance = MIB_OBJECT_TAB; + od->access = MIB_OBJECT_READ_WRITE; + od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR); + od->v_len = 4; + break; + case 2: /* ipRouteIfIndex */ + case 3: /* ipRouteMetric1 */ + case 4: /* ipRouteMetric2 */ + case 5: /* ipRouteMetric3 */ + case 6: /* ipRouteMetric4 */ + case 8: /* ipRouteType */ + case 10: /* ipRouteAge */ + case 12: /* ipRouteMetric5 */ + od->instance = MIB_OBJECT_TAB; + od->access = MIB_OBJECT_READ_WRITE; + od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); + od->v_len = sizeof(s32_t); + break; + case 9: /* ipRouteProto */ + od->instance = MIB_OBJECT_TAB; + od->access = MIB_OBJECT_READ_ONLY; + od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); + od->v_len = sizeof(s32_t); + break; + case 13: /* ipRouteInfo */ + /** @note returning zeroDotZero (0.0) no routing protocol specific MIB */ + od->instance = MIB_OBJECT_TAB; + od->access = MIB_OBJECT_READ_ONLY; + od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID); + od->v_len = iprouteinfo.len * sizeof(s32_t); + break; + default: + LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_rteentry_get_object_def: no such object\n")); + od->instance = MIB_OBJECT_NONE; + break; + } + } + else + { + LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_rteentry_get_object_def: no scalar\n")); + od->instance = MIB_OBJECT_NONE; + } +} + +static void +ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value) +{ + struct netif *netif; + ip_addr_t dest; + s32_t *ident; + u8_t id; + + ident = od->id_inst_ptr; + snmp_oidtoip(&ident[1], &dest); + + if (ip_addr_isany(&dest)) + { + /* ip_route() uses default netif for default route */ + netif = netif_default; + } + else + { + /* not using ip_route(), need exact match! */ + netif = netif_list; + while ((netif != NULL) && + !ip_addr_netcmp(&dest, &(netif->ip_addr), &(netif->netmask)) ) + { + netif = netif->next; + } + } + if (netif != NULL) + { + LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); + id = (u8_t)ident[0]; + switch (id) + { + case 1: /* ipRouteDest */ + { + ip_addr_t *dst = (ip_addr_t*)value; + + if (ip_addr_isany(&dest)) + { + /* default rte has 0.0.0.0 dest */ + ip_addr_set_zero(dst); + } + else + { + /* netifs have netaddress dest */ + ip_addr_get_network(dst, &netif->ip_addr, &netif->netmask); + } + } + break; + case 2: /* ipRouteIfIndex */ + { + s32_t *sint_ptr = (s32_t*)value; + + snmp_netiftoifindex(netif, sint_ptr); + } + break; + case 3: /* ipRouteMetric1 */ + { + s32_t *sint_ptr = (s32_t*)value; + + if (ip_addr_isany(&dest)) + { + /* default rte has metric 1 */ + *sint_ptr = 1; + } + else + { + /* other rtes have metric 0 */ + *sint_ptr = 0; + } + } + break; + case 4: /* ipRouteMetric2 */ + case 5: /* ipRouteMetric3 */ + case 6: /* ipRouteMetric4 */ + case 12: /* ipRouteMetric5 */ + { + s32_t *sint_ptr = (s32_t*)value; + /* not used */ + *sint_ptr = -1; + } + break; + case 7: /* ipRouteNextHop */ + { + ip_addr_t *dst = (ip_addr_t*)value; + + if (ip_addr_isany(&dest)) + { + /* default rte: gateway */ + *dst = netif->gw; + } + else + { + /* other rtes: netif ip_addr */ + *dst = netif->ip_addr; + } + } + break; + case 8: /* ipRouteType */ + { + s32_t *sint_ptr = (s32_t*)value; + + if (ip_addr_isany(&dest)) + { + /* default rte is indirect */ + *sint_ptr = 4; + } + else + { + /* other rtes are direct */ + *sint_ptr = 3; + } + } + break; + case 9: /* ipRouteProto */ + { + s32_t *sint_ptr = (s32_t*)value; + /* locally defined routes */ + *sint_ptr = 2; + } + break; + case 10: /* ipRouteAge */ + { + s32_t *sint_ptr = (s32_t*)value; + /** @todo (sysuptime - timestamp last change) / 100 + @see snmp_insert_iprteidx_tree() */ + *sint_ptr = 0; + } + break; + case 11: /* ipRouteMask */ + { + ip_addr_t *dst = (ip_addr_t*)value; + + if (ip_addr_isany(&dest)) + { + /* default rte use 0.0.0.0 mask */ + ip_addr_set_zero(dst); + } + else + { + /* other rtes use netmask */ + *dst = netif->netmask; + } + } + break; + case 13: /* ipRouteInfo */ + objectidncpy((s32_t*)value, (s32_t*)iprouteinfo.id, (u8_t)(len / sizeof(s32_t))); + break; + } + } +} + +static void +ip_ntomentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) +{ + /* return to object name, adding index depth (5) */ + ident_len += 5; + ident -= 5; + + if (ident_len == 6) + { + u8_t id; + + od->id_inst_len = ident_len; + od->id_inst_ptr = ident; + + LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); + id = (u8_t)ident[0]; + switch (id) + { + case 1: /* ipNetToMediaIfIndex */ + case 4: /* ipNetToMediaType */ + od->instance = MIB_OBJECT_TAB; + od->access = MIB_OBJECT_READ_WRITE; + od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); + od->v_len = sizeof(s32_t); + break; + case 2: /* ipNetToMediaPhysAddress */ + od->instance = MIB_OBJECT_TAB; + od->access = MIB_OBJECT_READ_WRITE; + od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); + od->v_len = 6; /** @todo try to use netif::hwaddr_len */ + break; + case 3: /* ipNetToMediaNetAddress */ + od->instance = MIB_OBJECT_TAB; + od->access = MIB_OBJECT_READ_WRITE; + od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR); + od->v_len = 4; + break; + default: + LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_ntomentry_get_object_def: no such object\n")); + od->instance = MIB_OBJECT_NONE; + break; + } + } + else + { + LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_ntomentry_get_object_def: no scalar\n")); + od->instance = MIB_OBJECT_NONE; + } +} + +static void +ip_ntomentry_get_value(struct obj_def *od, u16_t len, void *value) +{ +#if LWIP_ARP + u8_t id; + struct eth_addr* ethaddr_ret; + ip_addr_t* ipaddr_ret; +#endif /* LWIP_ARP */ + ip_addr_t ip; + struct netif *netif; + + LWIP_UNUSED_ARG(len); + LWIP_UNUSED_ARG(value);/* if !LWIP_ARP */ + + snmp_ifindextonetif(od->id_inst_ptr[1], &netif); + snmp_oidtoip(&od->id_inst_ptr[2], &ip); + +#if LWIP_ARP /** @todo implement a netif_find_addr */ + if (etharp_find_addr(netif, &ip, ðaddr_ret, &ipaddr_ret) > -1) + { + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; + switch (id) + { + case 1: /* ipNetToMediaIfIndex */ + { + s32_t *sint_ptr = (s32_t*)value; + *sint_ptr = od->id_inst_ptr[1]; + } + break; + case 2: /* ipNetToMediaPhysAddress */ + { + struct eth_addr *dst = (struct eth_addr*)value; + + *dst = *ethaddr_ret; + } + break; + case 3: /* ipNetToMediaNetAddress */ + { + ip_addr_t *dst = (ip_addr_t*)value; + + *dst = *ipaddr_ret; + } + break; + case 4: /* ipNetToMediaType */ + { + s32_t *sint_ptr = (s32_t*)value; + /* dynamic (?) */ + *sint_ptr = 3; + } + break; + } + } +#endif /* LWIP_ARP */ +} + +static void +icmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) +{ + /* return to object name, adding index depth (1) */ + ident_len += 1; + ident -= 1; + if ((ident_len == 2) && + (ident[0] > 0) && (ident[0] < 27)) + { + od->id_inst_len = ident_len; + od->id_inst_ptr = ident; + + od->instance = MIB_OBJECT_SCALAR; + od->access = MIB_OBJECT_READ_ONLY; + od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER); + od->v_len = sizeof(u32_t); + } + else + { + LWIP_DEBUGF(SNMP_MIB_DEBUG,("icmp_get_object_def: no scalar\n")); + od->instance = MIB_OBJECT_NONE; + } +} + +static void +icmp_get_value(struct obj_def *od, u16_t len, void *value) +{ + u32_t *uint_ptr = (u32_t*)value; + u8_t id; + + LWIP_UNUSED_ARG(len); + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; + switch (id) + { + case 1: /* icmpInMsgs */ + *uint_ptr = icmpinmsgs; + break; + case 2: /* icmpInErrors */ + *uint_ptr = icmpinerrors; + break; + case 3: /* icmpInDestUnreachs */ + *uint_ptr = icmpindestunreachs; + break; + case 4: /* icmpInTimeExcds */ + *uint_ptr = icmpintimeexcds; + break; + case 5: /* icmpInParmProbs */ + *uint_ptr = icmpinparmprobs; + break; + case 6: /* icmpInSrcQuenchs */ + *uint_ptr = icmpinsrcquenchs; + break; + case 7: /* icmpInRedirects */ + *uint_ptr = icmpinredirects; + break; + case 8: /* icmpInEchos */ + *uint_ptr = icmpinechos; + break; + case 9: /* icmpInEchoReps */ + *uint_ptr = icmpinechoreps; + break; + case 10: /* icmpInTimestamps */ + *uint_ptr = icmpintimestamps; + break; + case 11: /* icmpInTimestampReps */ + *uint_ptr = icmpintimestampreps; + break; + case 12: /* icmpInAddrMasks */ + *uint_ptr = icmpinaddrmasks; + break; + case 13: /* icmpInAddrMaskReps */ + *uint_ptr = icmpinaddrmaskreps; + break; + case 14: /* icmpOutMsgs */ + *uint_ptr = icmpoutmsgs; + break; + case 15: /* icmpOutErrors */ + *uint_ptr = icmpouterrors; + break; + case 16: /* icmpOutDestUnreachs */ + *uint_ptr = icmpoutdestunreachs; + break; + case 17: /* icmpOutTimeExcds */ + *uint_ptr = icmpouttimeexcds; + break; + case 18: /* icmpOutParmProbs */ + *uint_ptr = icmpoutparmprobs; + break; + case 19: /* icmpOutSrcQuenchs */ + *uint_ptr = icmpoutsrcquenchs; + break; + case 20: /* icmpOutRedirects */ + *uint_ptr = icmpoutredirects; + break; + case 21: /* icmpOutEchos */ + *uint_ptr = icmpoutechos; + break; + case 22: /* icmpOutEchoReps */ + *uint_ptr = icmpoutechoreps; + break; + case 23: /* icmpOutTimestamps */ + *uint_ptr = icmpouttimestamps; + break; + case 24: /* icmpOutTimestampReps */ + *uint_ptr = icmpouttimestampreps; + break; + case 25: /* icmpOutAddrMasks */ + *uint_ptr = icmpoutaddrmasks; + break; + case 26: /* icmpOutAddrMaskReps */ + *uint_ptr = icmpoutaddrmaskreps; + break; + } +} + +#if LWIP_TCP +/** @todo tcp grp */ +static void +tcp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) +{ + u8_t id; + + /* return to object name, adding index depth (1) */ + ident_len += 1; + ident -= 1; + if (ident_len == 2) + { + od->id_inst_len = ident_len; + od->id_inst_ptr = ident; + + LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); + id = (u8_t)ident[0]; + LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def tcp.%"U16_F".0\n",(u16_t)id)); + + switch (id) + { + case 1: /* tcpRtoAlgorithm */ + case 2: /* tcpRtoMin */ + case 3: /* tcpRtoMax */ + case 4: /* tcpMaxConn */ + od->instance = MIB_OBJECT_SCALAR; + od->access = MIB_OBJECT_READ_ONLY; + od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); + od->v_len = sizeof(s32_t); + break; + case 5: /* tcpActiveOpens */ + case 6: /* tcpPassiveOpens */ + case 7: /* tcpAttemptFails */ + case 8: /* tcpEstabResets */ + case 10: /* tcpInSegs */ + case 11: /* tcpOutSegs */ + case 12: /* tcpRetransSegs */ + case 14: /* tcpInErrs */ + case 15: /* tcpOutRsts */ + od->instance = MIB_OBJECT_SCALAR; + od->access = MIB_OBJECT_READ_ONLY; + od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER); + od->v_len = sizeof(u32_t); + break; + case 9: /* tcpCurrEstab */ + od->instance = MIB_OBJECT_TAB; + od->access = MIB_OBJECT_READ_ONLY; + od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE); + od->v_len = sizeof(u32_t); + break; + default: + LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcp_get_object_def: no such object\n")); + od->instance = MIB_OBJECT_NONE; + break; + }; + } + else + { + LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcp_get_object_def: no scalar\n")); + od->instance = MIB_OBJECT_NONE; + } +} + +static void +tcp_get_value(struct obj_def *od, u16_t len, void *value) +{ + u32_t *uint_ptr = (u32_t*)value; + s32_t *sint_ptr = (s32_t*)value; + u8_t id; + + LWIP_UNUSED_ARG(len); + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; + switch (id) + { + case 1: /* tcpRtoAlgorithm, vanj(4) */ + *sint_ptr = 4; + break; + case 2: /* tcpRtoMin */ + /* @todo not the actual value, a guess, + needs to be calculated */ + *sint_ptr = 1000; + break; + case 3: /* tcpRtoMax */ + /* @todo not the actual value, a guess, + needs to be calculated */ + *sint_ptr = 60000; + break; + case 4: /* tcpMaxConn */ + *sint_ptr = MEMP_NUM_TCP_PCB; + break; + case 5: /* tcpActiveOpens */ + *uint_ptr = tcpactiveopens; + break; + case 6: /* tcpPassiveOpens */ + *uint_ptr = tcppassiveopens; + break; + case 7: /* tcpAttemptFails */ + *uint_ptr = tcpattemptfails; + break; + case 8: /* tcpEstabResets */ + *uint_ptr = tcpestabresets; + break; + 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; + } + break; + case 10: /* tcpInSegs */ + *uint_ptr = tcpinsegs; + break; + case 11: /* tcpOutSegs */ + *uint_ptr = tcpoutsegs; + break; + case 12: /* tcpRetransSegs */ + *uint_ptr = tcpretranssegs; + break; + case 14: /* tcpInErrs */ + *uint_ptr = tcpinerrs; + break; + case 15: /* tcpOutRsts */ + *uint_ptr = tcpoutrsts; + break; + } +} +#ifdef THIS_SEEMS_UNUSED +static void +tcpconnentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) +{ + /* return to object name, adding index depth (10) */ + ident_len += 10; + ident -= 10; + + if (ident_len == 11) + { + u8_t id; + + od->id_inst_len = ident_len; + od->id_inst_ptr = ident; + + id = ident[0]; + LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def tcp.%"U16_F".0\n",(u16_t)id)); + + switch (id) + { + case 1: /* tcpConnState */ + od->instance = MIB_OBJECT_TAB; + od->access = MIB_OBJECT_READ_WRITE; + od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); + od->v_len = sizeof(s32_t); + break; + case 2: /* tcpConnLocalAddress */ + case 4: /* tcpConnRemAddress */ + od->instance = MIB_OBJECT_TAB; + od->access = MIB_OBJECT_READ_ONLY; + od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR); + od->v_len = 4; + break; + case 3: /* tcpConnLocalPort */ + case 5: /* tcpConnRemPort */ + od->instance = MIB_OBJECT_TAB; + od->access = MIB_OBJECT_READ_ONLY; + od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); + od->v_len = sizeof(s32_t); + break; + default: + LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcpconnentry_get_object_def: no such object\n")); + od->instance = MIB_OBJECT_NONE; + break; + }; + } + else + { + LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcpconnentry_get_object_def: no such object\n")); + od->instance = MIB_OBJECT_NONE; + } +} + +static void +tcpconnentry_get_value(struct obj_def *od, u16_t len, void *value) +{ + ip_addr_t lip, rip; + u16_t lport, rport; + s32_t *ident; + + ident = od->id_inst_ptr; + snmp_oidtoip(&ident[1], &lip); + lport = ident[5]; + snmp_oidtoip(&ident[6], &rip); + rport = ident[10]; + + /** @todo find matching PCB */ +} +#endif /* if 0 */ +#endif + +static void +udp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) +{ + /* return to object name, adding index depth (1) */ + ident_len += 1; + ident -= 1; + if ((ident_len == 2) && + (ident[0] > 0) && (ident[0] < 6)) + { + od->id_inst_len = ident_len; + od->id_inst_ptr = ident; + + od->instance = MIB_OBJECT_SCALAR; + od->access = MIB_OBJECT_READ_ONLY; + od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER); + od->v_len = sizeof(u32_t); + } + else + { + LWIP_DEBUGF(SNMP_MIB_DEBUG,("udp_get_object_def: no scalar\n")); + od->instance = MIB_OBJECT_NONE; + } +} + +static void +udp_get_value(struct obj_def *od, u16_t len, void *value) +{ + u32_t *uint_ptr = (u32_t*)value; + u8_t id; + + LWIP_UNUSED_ARG(len); + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; + switch (id) + { + case 1: /* udpInDatagrams */ + *uint_ptr = udpindatagrams; + break; + case 2: /* udpNoPorts */ + *uint_ptr = udpnoports; + break; + case 3: /* udpInErrors */ + *uint_ptr = udpinerrors; + break; + case 4: /* udpOutDatagrams */ + *uint_ptr = udpoutdatagrams; + break; + } +} + +static void +udpentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) +{ + /* return to object name, adding index depth (5) */ + ident_len += 5; + ident -= 5; + + if (ident_len == 6) + { + od->id_inst_len = ident_len; + od->id_inst_ptr = ident; + + switch (ident[0]) + { + case 1: /* udpLocalAddress */ + od->instance = MIB_OBJECT_TAB; + od->access = MIB_OBJECT_READ_ONLY; + od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR); + od->v_len = 4; + break; + case 2: /* udpLocalPort */ + od->instance = MIB_OBJECT_TAB; + od->access = MIB_OBJECT_READ_ONLY; + od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); + od->v_len = sizeof(s32_t); + break; + default: + LWIP_DEBUGF(SNMP_MIB_DEBUG,("udpentry_get_object_def: no such object\n")); + od->instance = MIB_OBJECT_NONE; + break; + } + } + else + { + LWIP_DEBUGF(SNMP_MIB_DEBUG,("udpentry_get_object_def: no scalar\n")); + od->instance = MIB_OBJECT_NONE; + } +} + +static void +udpentry_get_value(struct obj_def *od, u16_t len, void *value) +{ + u8_t id; + struct udp_pcb *pcb; + ipX_addr_t ip; + u16_t port; + + LWIP_UNUSED_ARG(len); + snmp_oidtoip(&od->id_inst_ptr[1], (ip_addr_t*)&ip); + LWIP_ASSERT("invalid port", (od->id_inst_ptr[5] >= 0) && (od->id_inst_ptr[5] <= 0xffff)); + port = (u16_t)od->id_inst_ptr[5]; + + pcb = udp_pcbs; + while ((pcb != NULL) && + !(ipX_addr_cmp(0, &pcb->local_ip, &ip) && + (pcb->local_port == port))) + { + pcb = pcb->next; + } + + if (pcb != NULL) + { + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; + switch (id) + { + case 1: /* udpLocalAddress */ + { + ipX_addr_t *dst = (ipX_addr_t*)value; + ipX_addr_copy(0, *dst, pcb->local_ip); + } + break; + case 2: /* udpLocalPort */ + { + s32_t *sint_ptr = (s32_t*)value; + *sint_ptr = pcb->local_port; + } + break; + } + } +} + +static void +snmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) +{ + /* return to object name, adding index depth (1) */ + ident_len += 1; + ident -= 1; + if (ident_len == 2) + { + u8_t id; + + od->id_inst_len = ident_len; + od->id_inst_ptr = ident; + + LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); + id = (u8_t)ident[0]; + switch (id) + { + case 1: /* snmpInPkts */ + case 2: /* snmpOutPkts */ + case 3: /* snmpInBadVersions */ + case 4: /* snmpInBadCommunityNames */ + case 5: /* snmpInBadCommunityUses */ + case 6: /* snmpInASNParseErrs */ + case 8: /* snmpInTooBigs */ + case 9: /* snmpInNoSuchNames */ + case 10: /* snmpInBadValues */ + case 11: /* snmpInReadOnlys */ + case 12: /* snmpInGenErrs */ + case 13: /* snmpInTotalReqVars */ + case 14: /* snmpInTotalSetVars */ + case 15: /* snmpInGetRequests */ + case 16: /* snmpInGetNexts */ + case 17: /* snmpInSetRequests */ + case 18: /* snmpInGetResponses */ + case 19: /* snmpInTraps */ + case 20: /* snmpOutTooBigs */ + case 21: /* snmpOutNoSuchNames */ + case 22: /* snmpOutBadValues */ + case 24: /* snmpOutGenErrs */ + case 25: /* snmpOutGetRequests */ + case 26: /* snmpOutGetNexts */ + case 27: /* snmpOutSetRequests */ + case 28: /* snmpOutGetResponses */ + case 29: /* snmpOutTraps */ + od->instance = MIB_OBJECT_SCALAR; + od->access = MIB_OBJECT_READ_ONLY; + od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER); + od->v_len = sizeof(u32_t); + break; + case 30: /* snmpEnableAuthenTraps */ + od->instance = MIB_OBJECT_SCALAR; + od->access = MIB_OBJECT_READ_WRITE; + od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); + od->v_len = sizeof(s32_t); + break; + default: + LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_get_object_def: no such object\n")); + od->instance = MIB_OBJECT_NONE; + break; + }; + } + else + { + LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_get_object_def: no scalar\n")); + od->instance = MIB_OBJECT_NONE; + } +} + +static void +snmp_get_value(struct obj_def *od, u16_t len, void *value) +{ + u32_t *uint_ptr = (u32_t*)value; + u8_t id; + + LWIP_UNUSED_ARG(len); + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; + switch (id) + { + case 1: /* snmpInPkts */ + *uint_ptr = snmpinpkts; + break; + case 2: /* snmpOutPkts */ + *uint_ptr = snmpoutpkts; + break; + case 3: /* snmpInBadVersions */ + *uint_ptr = snmpinbadversions; + break; + case 4: /* snmpInBadCommunityNames */ + *uint_ptr = snmpinbadcommunitynames; + break; + case 5: /* snmpInBadCommunityUses */ + *uint_ptr = snmpinbadcommunityuses; + break; + case 6: /* snmpInASNParseErrs */ + *uint_ptr = snmpinasnparseerrs; + break; + case 8: /* snmpInTooBigs */ + *uint_ptr = snmpintoobigs; + break; + case 9: /* snmpInNoSuchNames */ + *uint_ptr = snmpinnosuchnames; + break; + case 10: /* snmpInBadValues */ + *uint_ptr = snmpinbadvalues; + break; + case 11: /* snmpInReadOnlys */ + *uint_ptr = snmpinreadonlys; + break; + case 12: /* snmpInGenErrs */ + *uint_ptr = snmpingenerrs; + break; + case 13: /* snmpInTotalReqVars */ + *uint_ptr = snmpintotalreqvars; + break; + case 14: /* snmpInTotalSetVars */ + *uint_ptr = snmpintotalsetvars; + break; + case 15: /* snmpInGetRequests */ + *uint_ptr = snmpingetrequests; + break; + case 16: /* snmpInGetNexts */ + *uint_ptr = snmpingetnexts; + break; + case 17: /* snmpInSetRequests */ + *uint_ptr = snmpinsetrequests; + break; + case 18: /* snmpInGetResponses */ + *uint_ptr = snmpingetresponses; + break; + case 19: /* snmpInTraps */ + *uint_ptr = snmpintraps; + break; + case 20: /* snmpOutTooBigs */ + *uint_ptr = snmpouttoobigs; + break; + case 21: /* snmpOutNoSuchNames */ + *uint_ptr = snmpoutnosuchnames; + break; + case 22: /* snmpOutBadValues */ + *uint_ptr = snmpoutbadvalues; + break; + case 24: /* snmpOutGenErrs */ + *uint_ptr = snmpoutgenerrs; + break; + case 25: /* snmpOutGetRequests */ + *uint_ptr = snmpoutgetrequests; + break; + case 26: /* snmpOutGetNexts */ + *uint_ptr = snmpoutgetnexts; + break; + case 27: /* snmpOutSetRequests */ + *uint_ptr = snmpoutsetrequests; + break; + case 28: /* snmpOutGetResponses */ + *uint_ptr = snmpoutgetresponses; + break; + case 29: /* snmpOutTraps */ + *uint_ptr = snmpouttraps; + break; + case 30: /* snmpEnableAuthenTraps */ + *uint_ptr = *snmpenableauthentraps_ptr; + break; + }; +} + +/** + * Test snmp object value before setting. + * + * @param od is the object definition + * @param len return value space (in bytes) + * @param value points to (varbind) space to copy value from. + */ +static u8_t +snmp_set_test(struct obj_def *od, u16_t len, void *value) +{ + u8_t id, set_ok; + + LWIP_UNUSED_ARG(len); + set_ok = 0; + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; + if (id == 30) + { + /* snmpEnableAuthenTraps */ + s32_t *sint_ptr = (s32_t*)value; + + if (snmpenableauthentraps_ptr != &snmpenableauthentraps_default) + { + /* we should have writable non-volatile mem here */ + if ((*sint_ptr == 1) || (*sint_ptr == 2)) + { + set_ok = 1; + } + } + else + { + /* const or hardwired value */ + if (*sint_ptr == snmpenableauthentraps_default) + { + set_ok = 1; + } + } + } + return set_ok; +} + +static void +snmp_set_value(struct obj_def *od, u16_t len, void *value) +{ + u8_t id; + + LWIP_UNUSED_ARG(len); + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; + if (id == 30) + { + /* snmpEnableAuthenTraps */ + /* @todo @fixme: which kind of pointer is 'value'? s32_t or u8_t??? */ + u8_t *ptr = (u8_t*)value; + *snmpenableauthentraps_ptr = *ptr; + } +} + +#endif /* LWIP_SNMP */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/snmp/mib_structs.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/snmp/mib_structs.c new file mode 100644 index 0000000..36b9103 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/snmp/mib_structs.c @@ -0,0 +1,1178 @@ +/** + * @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 + */ + +#include "lwip/opt.h" + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/snmp_structs.h" +#include "lwip/memp.h" +#include "lwip/netif.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +/** .iso.org.dod.internet address prefix, @see snmp_iso_*() */ +const s32_t prefix[4] = {1, 3, 6, 1}; + +#define NODE_STACK_SIZE (LWIP_SNMP_OBJ_ID_LEN) +/** node stack entry (old news?) */ +struct nse +{ + /** right child */ + struct mib_node* r_ptr; + /** right child identifier */ + s32_t r_id; + /** right child next level */ + u8_t r_nl; +}; +static u8_t node_stack_cnt; +static struct nse node_stack[NODE_STACK_SIZE]; + +/** + * Pushes nse struct onto stack. + */ +static void +push_node(struct nse* node) +{ + LWIP_ASSERT("node_stack_cnt < NODE_STACK_SIZE",node_stack_cnt < NODE_STACK_SIZE); + LWIP_DEBUGF(SNMP_MIB_DEBUG,("push_node() node=%p id=%"S32_F"\n",(void*)(node->r_ptr),node->r_id)); + if (node_stack_cnt < NODE_STACK_SIZE) + { + node_stack[node_stack_cnt] = *node; + node_stack_cnt++; + } +} + +/** + * Pops nse struct from stack. + */ +static void +pop_node(struct nse* node) +{ + if (node_stack_cnt > 0) + { + node_stack_cnt--; + *node = node_stack[node_stack_cnt]; + } + LWIP_DEBUGF(SNMP_MIB_DEBUG,("pop_node() node=%p id=%"S32_F"\n",(void *)(node->r_ptr),node->r_id)); +} + +/** + * Conversion from ifIndex to lwIP netif + * @param ifindex is a s32_t object sub-identifier + * @param netif points to returned netif struct pointer + */ +void +snmp_ifindextonetif(s32_t ifindex, struct netif **netif) +{ + struct netif *nif = netif_list; + s32_t i, ifidx; + + ifidx = ifindex - 1; + i = 0; + while ((nif != NULL) && (i < ifidx)) + { + nif = nif->next; + i++; + } + *netif = nif; +} + +/** + * Conversion from lwIP netif to ifIndex + * @param netif points to a netif struct + * @param ifidx points to s32_t object sub-identifier + */ +void +snmp_netiftoifindex(struct netif *netif, s32_t *ifidx) +{ + struct netif *nif = netif_list; + u16_t i; + + i = 0; + while ((nif != NULL) && (nif != netif)) + { + nif = nif->next; + i++; + } + *ifidx = i+1; +} + +/** + * Conversion from oid to lwIP ip_addr + * @param ident points to s32_t ident[4] input + * @param ip points to output struct + */ +void +snmp_oidtoip(s32_t *ident, ip_addr_t *ip) +{ + IP4_ADDR(ip, ident[0], ident[1], ident[2], ident[3]); +} + +/** + * Conversion from lwIP ip_addr to oid + * @param ip points to input struct + * @param ident points to s32_t ident[4] output + */ +void +snmp_iptooid(ip_addr_t *ip, s32_t *ident) +{ + ident[0] = ip4_addr1(ip); + ident[1] = ip4_addr2(ip); + ident[2] = ip4_addr3(ip); + ident[3] = ip4_addr4(ip); +} + +struct mib_list_node * +snmp_mib_ln_alloc(s32_t id) +{ + struct mib_list_node *ln; + + ln = (struct mib_list_node *)memp_malloc(MEMP_SNMP_NODE); + if (ln != NULL) + { + ln->prev = NULL; + ln->next = NULL; + ln->objid = id; + ln->nptr = NULL; + } + return ln; +} + +void +snmp_mib_ln_free(struct mib_list_node *ln) +{ + memp_free(MEMP_SNMP_NODE, ln); +} + +struct mib_list_rootnode * +snmp_mib_lrn_alloc(void) +{ + struct mib_list_rootnode *lrn; + + lrn = (struct mib_list_rootnode*)memp_malloc(MEMP_SNMP_ROOTNODE); + if (lrn != NULL) + { + lrn->get_object_def = noleafs_get_object_def; + lrn->get_value = noleafs_get_value; + lrn->set_test = noleafs_set_test; + lrn->set_value = noleafs_set_value; + lrn->node_type = MIB_NODE_LR; + lrn->maxlength = 0; + lrn->head = NULL; + lrn->tail = NULL; + lrn->count = 0; + } + return lrn; +} + +void +snmp_mib_lrn_free(struct mib_list_rootnode *lrn) +{ + memp_free(MEMP_SNMP_ROOTNODE, lrn); +} + +/** + * Inserts node in idx list in a sorted + * (ascending order) fashion and + * allocates the node if needed. + * + * @param rn points to the root node + * @param objid is the object sub identifier + * @param insn points to a pointer to the inserted node + * used for constructing the tree. + * @return -1 if failed, 1 if inserted, 2 if present. + */ +s8_t +snmp_mib_node_insert(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **insn) +{ + struct mib_list_node *nn; + s8_t insert; + + LWIP_ASSERT("rn != NULL",rn != NULL); + + /* -1 = malloc failure, 0 = not inserted, 1 = inserted, 2 = was present */ + insert = 0; + if (rn->head == NULL) + { + /* empty list, add first node */ + LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc empty list objid==%"S32_F"\n",objid)); + nn = snmp_mib_ln_alloc(objid); + if (nn != NULL) + { + rn->head = nn; + rn->tail = nn; + *insn = nn; + insert = 1; + } + else + { + insert = -1; + } + } + else + { + struct mib_list_node *n; + /* at least one node is present */ + n = rn->head; + while ((n != NULL) && (insert == 0)) + { + if (n->objid == objid) + { + /* node is already there */ + LWIP_DEBUGF(SNMP_MIB_DEBUG,("node already there objid==%"S32_F"\n",objid)); + *insn = n; + insert = 2; + } + else if (n->objid < objid) + { + if (n->next == NULL) + { + /* alloc and insert at the tail */ + LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc ins tail objid==%"S32_F"\n",objid)); + nn = snmp_mib_ln_alloc(objid); + if (nn != NULL) + { + nn->next = NULL; + nn->prev = n; + n->next = nn; + rn->tail = nn; + *insn = nn; + insert = 1; + } + else + { + /* insertion failure */ + insert = -1; + } + } + else + { + /* there's more to explore: traverse list */ + LWIP_DEBUGF(SNMP_MIB_DEBUG,("traverse list\n")); + n = n->next; + } + } + else + { + /* n->objid > objid */ + /* alloc and insert between n->prev and n */ + LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc ins n->prev, objid==%"S32_F", n\n",objid)); + nn = snmp_mib_ln_alloc(objid); + if (nn != NULL) + { + if (n->prev == NULL) + { + /* insert at the head */ + nn->next = n; + nn->prev = NULL; + rn->head = nn; + n->prev = nn; + } + else + { + /* insert in the middle */ + nn->next = n; + nn->prev = n->prev; + n->prev->next = nn; + n->prev = nn; + } + *insn = nn; + insert = 1; + } + else + { + /* insertion failure */ + insert = -1; + } + } + } + } + if (insert == 1) + { + rn->count += 1; + } + LWIP_ASSERT("insert != 0",insert != 0); + return insert; +} + +/** + * Finds node in idx list and returns deletion mark. + * + * @param rn points to the root node + * @param objid is the object sub identifier + * @param fn returns pointer to found node + * @return 0 if not found, 1 if deletable, + * 2 can't delete (2 or more children), 3 not a list_node + */ +s8_t +snmp_mib_node_find(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **fn) +{ + s8_t fc; + struct mib_list_node *n; + + LWIP_ASSERT("rn != NULL",rn != NULL); + n = rn->head; + while ((n != NULL) && (n->objid != objid)) + { + n = n->next; + } + if (n == NULL) + { + fc = 0; + } + else if (n->nptr == NULL) + { + /* leaf, can delete node */ + fc = 1; + } + else + { + struct mib_list_rootnode *r; + + if (n->nptr->node_type == MIB_NODE_LR) + { + r = (struct mib_list_rootnode *)n->nptr; + if (r->count > 1) + { + /* can't delete node */ + fc = 2; + } + else + { + /* count <= 1, can delete node */ + fc = 1; + } + } + else + { + /* other node type */ + fc = 3; + } + } + *fn = n; + return fc; +} + +/** + * Removes node from idx list + * if it has a single child left. + * + * @param rn points to the root node + * @param n points to the node to delete + * @return the nptr to be freed by caller + */ +struct mib_list_rootnode * +snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n) +{ + struct mib_list_rootnode *next; + + LWIP_ASSERT("rn != NULL",rn != NULL); + LWIP_ASSERT("n != NULL",n != NULL); + + /* caller must remove this sub-tree */ + next = (struct mib_list_rootnode*)(n->nptr); + rn->count -= 1; + + if (n == rn->head) + { + rn->head = n->next; + if (n->next != NULL) + { + /* not last node, new list begin */ + n->next->prev = NULL; + } + } + else if (n == rn->tail) + { + rn->tail = n->prev; + if (n->prev != NULL) + { + /* not last node, new list end */ + n->prev->next = NULL; + } + } + else + { + /* node must be in the middle */ + n->prev->next = n->next; + n->next->prev = n->prev; + } + LWIP_DEBUGF(SNMP_MIB_DEBUG,("free list objid==%"S32_F"\n",n->objid)); + snmp_mib_ln_free(n); + if (rn->count == 0) + { + rn->head = NULL; + rn->tail = NULL; + } + return next; +} + + + +/** + * Searches tree for the supplied (scalar?) object identifier. + * + * @param node points to the root of the tree ('.internet') + * @param ident_len the length of the supplied object identifier + * @param ident points to the array of sub identifiers + * @param np points to the found object instance (return) + * @return pointer to the requested parent (!) node if success, NULL otherwise + */ +struct mib_node * +snmp_search_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_name_ptr *np) +{ + u8_t node_type, ext_level; + + ext_level = 0; + LWIP_DEBUGF(SNMP_MIB_DEBUG,("node==%p *ident==%"S32_F"\n",(void*)node,*ident)); + while (node != NULL) + { + node_type = node->node_type; + if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA)) + { + struct mib_array_node *an; + u16_t i; + + if (ident_len > 0) + { + /* array node (internal ROM or RAM, fixed length) */ + an = (struct mib_array_node *)node; + i = 0; + while ((i < an->maxlength) && (an->objid[i] != *ident)) + { + i++; + } + if (i < an->maxlength) + { + /* found it, if available proceed to child, otherwise inspect leaf */ + LWIP_DEBUGF(SNMP_MIB_DEBUG,("an->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,an->objid[i],*ident)); + if (an->nptr[i] == NULL) + { + /* a scalar leaf OR table, + inspect remaining instance number / table index */ + np->ident_len = ident_len; + np->ident = ident; + return (struct mib_node*)an; + } + else + { + /* follow next child pointer */ + ident++; + ident_len--; + node = an->nptr[i]; + } + } + else + { + /* search failed, identifier mismatch (nosuchname) */ + LWIP_DEBUGF(SNMP_MIB_DEBUG,("an search failed *ident==%"S32_F"\n",*ident)); + return NULL; + } + } + else + { + /* search failed, short object identifier (nosuchname) */ + LWIP_DEBUGF(SNMP_MIB_DEBUG,("an search failed, short object identifier\n")); + return NULL; + } + } + else if(node_type == MIB_NODE_LR) + { + struct mib_list_rootnode *lrn; + struct mib_list_node *ln; + + if (ident_len > 0) + { + /* list root node (internal 'RAM', variable length) */ + lrn = (struct mib_list_rootnode *)node; + ln = lrn->head; + /* iterate over list, head to tail */ + while ((ln != NULL) && (ln->objid != *ident)) + { + ln = ln->next; + } + if (ln != NULL) + { + /* found it, proceed to child */; + LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln->objid==%"S32_F" *ident==%"S32_F"\n",ln->objid,*ident)); + if (ln->nptr == NULL) + { + np->ident_len = ident_len; + np->ident = ident; + return (struct mib_node*)lrn; + } + else + { + /* follow next child pointer */ + ident_len--; + ident++; + node = ln->nptr; + } + } + else + { + /* search failed */ + LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln search failed *ident==%"S32_F"\n",*ident)); + return NULL; + } + } + else + { + /* search failed, short object identifier (nosuchname) */ + LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln search failed, short object identifier\n")); + return NULL; + } + } + else if(node_type == MIB_NODE_EX) + { + struct mib_external_node *en; + u16_t i, len; + + if (ident_len > 0) + { + /* external node (addressing and access via functions) */ + en = (struct mib_external_node *)node; + + i = 0; + len = en->level_length(en->addr_inf,ext_level); + while ((i < len) && (en->ident_cmp(en->addr_inf,ext_level,i,*ident) != 0)) + { + i++; + } + if (i < len) + { + s32_t debug_id; + + en->get_objid(en->addr_inf,ext_level,i,&debug_id); + LWIP_DEBUGF(SNMP_MIB_DEBUG,("en->objid==%"S32_F" *ident==%"S32_F"\n",debug_id,*ident)); + if ((ext_level + 1) == en->tree_levels) + { + np->ident_len = ident_len; + np->ident = ident; + return (struct mib_node*)en; + } + else + { + /* found it, proceed to child */ + ident_len--; + ident++; + ext_level++; + } + } + else + { + /* search failed */ + LWIP_DEBUGF(SNMP_MIB_DEBUG,("en search failed *ident==%"S32_F"\n",*ident)); + return NULL; + } + } + else + { + /* search failed, short object identifier (nosuchname) */ + LWIP_DEBUGF(SNMP_MIB_DEBUG,("en search failed, short object identifier\n")); + return NULL; + } + } + else if (node_type == MIB_NODE_SC) + { + mib_scalar_node *sn; + + sn = (mib_scalar_node *)node; + if ((ident_len == 1) && (*ident == 0)) + { + np->ident_len = ident_len; + np->ident = ident; + return (struct mib_node*)sn; + } + else + { + /* search failed, short object identifier (nosuchname) */ + LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed, invalid object identifier length\n")); + return NULL; + } + } + else + { + /* unknown node_type */ + LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed node_type %"U16_F" unkown\n",(u16_t)node_type)); + return NULL; + } + } + /* done, found nothing */ + LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed node==%p\n",(void*)node)); + return NULL; +} + +/** + * Test table for presence of at least one table entry. + */ +static u8_t +empty_table(struct mib_node *node) +{ + u8_t node_type; + u8_t empty = 0; + + if (node != NULL) + { + node_type = node->node_type; + if (node_type == MIB_NODE_LR) + { + struct mib_list_rootnode *lrn; + lrn = (struct mib_list_rootnode *)node; + if ((lrn->count == 0) || (lrn->head == NULL)) + { + empty = 1; + } + } + else if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA)) + { + struct mib_array_node *an; + an = (struct mib_array_node *)node; + if ((an->maxlength == 0) || (an->nptr == NULL)) + { + empty = 1; + } + } + else if (node_type == MIB_NODE_EX) + { + struct mib_external_node *en; + en = (struct mib_external_node *)node; + if (en->tree_levels == 0) + { + empty = 1; + } + } + } + return empty; +} + +/** + * Tree expansion. + */ +struct mib_node * +snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret) +{ + u8_t node_type, ext_level, climb_tree; + + ext_level = 0; + /* reset node stack */ + node_stack_cnt = 0; + while (node != NULL) + { + climb_tree = 0; + node_type = node->node_type; + if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA)) + { + struct mib_array_node *an; + u16_t i; + + /* array node (internal ROM or RAM, fixed length) */ + an = (struct mib_array_node *)node; + if (ident_len > 0) + { + i = 0; + while ((i < an->maxlength) && (an->objid[i] < *ident)) + { + i++; + } + if (i < an->maxlength) + { + LWIP_DEBUGF(SNMP_MIB_DEBUG,("an->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,an->objid[i],*ident)); + /* add identifier to oidret */ + oidret->id[oidret->len] = an->objid[i]; + (oidret->len)++; + + if (an->nptr[i] == NULL) + { + LWIP_DEBUGF(SNMP_MIB_DEBUG,("leaf node\n")); + /* leaf node (e.g. in a fixed size table) */ + if (an->objid[i] > *ident) + { + return (struct mib_node*)an; + } + else if ((i + 1) < an->maxlength) + { + /* an->objid[i] == *ident */ + (oidret->len)--; + oidret->id[oidret->len] = an->objid[i + 1]; + (oidret->len)++; + return (struct mib_node*)an; + } + else + { + /* (i + 1) == an->maxlength */ + (oidret->len)--; + climb_tree = 1; + } + } + else + { + u8_t j; + struct nse cur_node; + + LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n")); + /* non-leaf, store right child ptr and id */ + LWIP_ASSERT("i < 0xff", i < 0xff); + j = (u8_t)i + 1; + while ((j < an->maxlength) && (empty_table(an->nptr[j]))) + { + j++; + } + if (j < an->maxlength) + { + cur_node.r_ptr = an->nptr[j]; + cur_node.r_id = an->objid[j]; + cur_node.r_nl = 0; + } + else + { + cur_node.r_ptr = NULL; + } + push_node(&cur_node); + if (an->objid[i] == *ident) + { + ident_len--; + ident++; + } + else + { + /* an->objid[i] < *ident */ + ident_len = 0; + } + /* follow next child pointer */ + node = an->nptr[i]; + } + } + else + { + /* i == an->maxlength */ + climb_tree = 1; + } + } + else + { + u8_t j; + /* ident_len == 0, complete with leftmost '.thing' */ + j = 0; + while ((j < an->maxlength) && empty_table(an->nptr[j])) + { + j++; + } + if (j < an->maxlength) + { + LWIP_DEBUGF(SNMP_MIB_DEBUG,("left an->objid[j]==%"S32_F"\n",an->objid[j])); + oidret->id[oidret->len] = an->objid[j]; + (oidret->len)++; + if (an->nptr[j] == NULL) + { + /* leaf node */ + return (struct mib_node*)an; + } + else + { + /* no leaf, continue */ + node = an->nptr[j]; + } + } + else + { + /* j == an->maxlength */ + climb_tree = 1; + } + } + } + else if(node_type == MIB_NODE_LR) + { + struct mib_list_rootnode *lrn; + struct mib_list_node *ln; + + /* list root node (internal 'RAM', variable length) */ + lrn = (struct mib_list_rootnode *)node; + if (ident_len > 0) + { + ln = lrn->head; + /* iterate over list, head to tail */ + while ((ln != NULL) && (ln->objid < *ident)) + { + ln = ln->next; + } + if (ln != NULL) + { + LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln->objid==%"S32_F" *ident==%"S32_F"\n",ln->objid,*ident)); + oidret->id[oidret->len] = ln->objid; + (oidret->len)++; + if (ln->nptr == NULL) + { + /* leaf node */ + if (ln->objid > *ident) + { + return (struct mib_node*)lrn; + } + else if (ln->next != NULL) + { + /* ln->objid == *ident */ + (oidret->len)--; + oidret->id[oidret->len] = ln->next->objid; + (oidret->len)++; + return (struct mib_node*)lrn; + } + else + { + /* ln->next == NULL */ + (oidret->len)--; + climb_tree = 1; + } + } + else + { + struct mib_list_node *jn; + struct nse cur_node; + + /* non-leaf, store right child ptr and id */ + jn = ln->next; + while ((jn != NULL) && empty_table(jn->nptr)) + { + jn = jn->next; + } + if (jn != NULL) + { + cur_node.r_ptr = jn->nptr; + cur_node.r_id = jn->objid; + cur_node.r_nl = 0; + } + else + { + cur_node.r_ptr = NULL; + } + push_node(&cur_node); + if (ln->objid == *ident) + { + ident_len--; + ident++; + } + else + { + /* ln->objid < *ident */ + ident_len = 0; + } + /* follow next child pointer */ + node = ln->nptr; + } + + } + else + { + /* ln == NULL */ + climb_tree = 1; + } + } + else + { + struct mib_list_node *jn; + /* ident_len == 0, complete with leftmost '.thing' */ + jn = lrn->head; + while ((jn != NULL) && empty_table(jn->nptr)) + { + jn = jn->next; + } + if (jn != NULL) + { + LWIP_DEBUGF(SNMP_MIB_DEBUG,("left jn->objid==%"S32_F"\n",jn->objid)); + oidret->id[oidret->len] = jn->objid; + (oidret->len)++; + if (jn->nptr == NULL) + { + /* leaf node */ + LWIP_DEBUGF(SNMP_MIB_DEBUG,("jn->nptr == NULL\n")); + return (struct mib_node*)lrn; + } + else + { + /* no leaf, continue */ + node = jn->nptr; + } + } + else + { + /* jn == NULL */ + climb_tree = 1; + } + } + } + else if(node_type == MIB_NODE_EX) + { + struct mib_external_node *en; + s32_t ex_id; + + /* external node (addressing and access via functions) */ + en = (struct mib_external_node *)node; + if (ident_len > 0) + { + u16_t i, len; + + i = 0; + len = en->level_length(en->addr_inf,ext_level); + while ((i < len) && (en->ident_cmp(en->addr_inf,ext_level,i,*ident) < 0)) + { + i++; + } + if (i < len) + { + /* add identifier to oidret */ + en->get_objid(en->addr_inf,ext_level,i,&ex_id); + LWIP_DEBUGF(SNMP_MIB_DEBUG,("en->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,ex_id,*ident)); + oidret->id[oidret->len] = ex_id; + (oidret->len)++; + + if ((ext_level + 1) == en->tree_levels) + { + LWIP_DEBUGF(SNMP_MIB_DEBUG,("leaf node\n")); + /* leaf node */ + if (ex_id > *ident) + { + return (struct mib_node*)en; + } + else if ((i + 1) < len) + { + /* ex_id == *ident */ + en->get_objid(en->addr_inf,ext_level,i + 1,&ex_id); + (oidret->len)--; + oidret->id[oidret->len] = ex_id; + (oidret->len)++; + return (struct mib_node*)en; + } + else + { + /* (i + 1) == len */ + (oidret->len)--; + climb_tree = 1; + } + } + else + { + u8_t j; + struct nse cur_node; + + LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n")); + /* non-leaf, store right child ptr and id */ + LWIP_ASSERT("i < 0xff", i < 0xff); + j = (u8_t)i + 1; + if (j < len) + { + /* right node is the current external node */ + cur_node.r_ptr = node; + en->get_objid(en->addr_inf,ext_level,j,&cur_node.r_id); + cur_node.r_nl = ext_level + 1; + } + else + { + cur_node.r_ptr = NULL; + } + push_node(&cur_node); + if (en->ident_cmp(en->addr_inf,ext_level,i,*ident) == 0) + { + ident_len--; + ident++; + } + else + { + /* external id < *ident */ + ident_len = 0; + } + /* proceed to child */ + ext_level++; + } + } + else + { + /* i == len (en->level_len()) */ + climb_tree = 1; + } + } + else + { + /* ident_len == 0, complete with leftmost '.thing' */ + en->get_objid(en->addr_inf,ext_level,0,&ex_id); + LWIP_DEBUGF(SNMP_MIB_DEBUG,("left en->objid==%"S32_F"\n",ex_id)); + oidret->id[oidret->len] = ex_id; + (oidret->len)++; + if ((ext_level + 1) == en->tree_levels) + { + /* leaf node */ + LWIP_DEBUGF(SNMP_MIB_DEBUG,("(ext_level + 1) == en->tree_levels\n")); + return (struct mib_node*)en; + } + else + { + /* no leaf, proceed to child */ + ext_level++; + } + } + } + else if(node_type == MIB_NODE_SC) + { + mib_scalar_node *sn; + + /* scalar node */ + sn = (mib_scalar_node *)node; + if (ident_len > 0) + { + /* at .0 */ + climb_tree = 1; + } + else + { + /* ident_len == 0, complete object identifier */ + oidret->id[oidret->len] = 0; + (oidret->len)++; + /* leaf node */ + LWIP_DEBUGF(SNMP_MIB_DEBUG,("completed scalar leaf\n")); + return (struct mib_node*)sn; + } + } + else + { + /* unknown/unhandled node_type */ + LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed node_type %"U16_F" unkown\n",(u16_t)node_type)); + return NULL; + } + + if (climb_tree) + { + struct nse child; + + /* find right child ptr */ + child.r_ptr = NULL; + child.r_id = 0; + child.r_nl = 0; + while ((node_stack_cnt > 0) && (child.r_ptr == NULL)) + { + pop_node(&child); + /* trim returned oid */ + (oidret->len)--; + } + if (child.r_ptr != NULL) + { + /* incoming ident is useless beyond this point */ + ident_len = 0; + oidret->id[oidret->len] = child.r_id; + oidret->len++; + node = child.r_ptr; + ext_level = child.r_nl; + } + else + { + /* tree ends here ... */ + LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed, tree ends here\n")); + return NULL; + } + } + } + /* done, found nothing */ + LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed node==%p\n",(void*)node)); + return NULL; +} + +/** + * Test object identifier for the iso.org.dod.internet prefix. + * + * @param ident_len the length of the supplied object identifier + * @param ident points to the array of sub identifiers + * @return 1 if it matches, 0 otherwise + */ +u8_t +snmp_iso_prefix_tst(u8_t ident_len, s32_t *ident) +{ + if ((ident_len > 3) && + (ident[0] == 1) && (ident[1] == 3) && + (ident[2] == 6) && (ident[3] == 1)) + { + return 1; + } + else + { + return 0; + } +} + +/** + * Expands object identifier to the iso.org.dod.internet + * prefix for use in getnext operation. + * + * @param ident_len the length of the supplied object identifier + * @param ident points to the array of sub identifiers + * @param oidret points to returned expanded object identifier + * @return 1 if it matches, 0 otherwise + * + * @note ident_len 0 is allowed, expanding to the first known object id!! + */ +u8_t +snmp_iso_prefix_expand(u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret) +{ + const s32_t *prefix_ptr; + s32_t *ret_ptr; + u8_t i; + + i = 0; + prefix_ptr = &prefix[0]; + ret_ptr = &oidret->id[0]; + ident_len = ((ident_len < 4)?ident_len:4); + while ((i < ident_len) && ((*ident) <= (*prefix_ptr))) + { + *ret_ptr++ = *prefix_ptr++; + ident++; + i++; + } + if (i == ident_len) + { + /* match, complete missing bits */ + while (i < 4) + { + *ret_ptr++ = *prefix_ptr++; + i++; + } + oidret->len = i; + return 1; + } + else + { + /* i != ident_len */ + return 0; + } +} + +#endif /* LWIP_SNMP */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/snmp/msg_in.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/snmp/msg_in.c new file mode 100644 index 0000000..f60893b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/snmp/msg_in.c @@ -0,0 +1,1457 @@ +/** + * @file + * SNMP input message processing (RFC1157). + */ + +/* + * 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 + */ + +#include "lwip/opt.h" + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/snmp.h" +#include "lwip/snmp_asn1.h" +#include "lwip/snmp_msg.h" +#include "lwip/snmp_structs.h" +#include "lwip/ip_addr.h" +#include "lwip/memp.h" +#include "lwip/udp.h" +#include "lwip/stats.h" + +#include + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +/* public (non-static) constants */ +/** SNMP v1 == 0 */ +const s32_t snmp_version = 0; +/** default SNMP community string */ +const char snmp_publiccommunity[7] = "public"; + +/* statically allocated buffers for SNMP_CONCURRENT_REQUESTS */ +struct snmp_msg_pstat msg_input_list[SNMP_CONCURRENT_REQUESTS]; +/* UDP Protocol Control Block */ +struct udp_pcb *snmp1_pcb; + +static void snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port); +static err_t snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat); +static err_t snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat); + + +/** + * Starts SNMP Agent. + * Allocates UDP pcb and binds it to IP_ADDR_ANY port 161. + */ +void +snmp_init(void) +{ + struct snmp_msg_pstat *msg_ps; + u8_t i; + + snmp1_pcb = udp_new(); + if (snmp1_pcb != NULL) + { + udp_recv(snmp1_pcb, snmp_recv, (void *)SNMP_IN_PORT); + udp_bind(snmp1_pcb, IP_ADDR_ANY, SNMP_IN_PORT); + } + msg_ps = &msg_input_list[0]; + for (i=0; istate = SNMP_MSG_EMPTY; + msg_ps->error_index = 0; + msg_ps->error_status = SNMP_ES_NOERROR; + msg_ps++; + } + trap_msg.pcb = snmp1_pcb; + +#ifdef SNMP_PRIVATE_MIB_INIT + /* If defined, this must be a function-like define to initialize the + * private MIB after the stack has been initialized. + * The private MIB can also be initialized in tcpip_callback (or after + * the stack is initialized), this define is only for convenience. */ + SNMP_PRIVATE_MIB_INIT(); +#endif /* SNMP_PRIVATE_MIB_INIT */ + + /* The coldstart trap will only be output + if our outgoing interface is up & configured */ + snmp_coldstart_trap(); +} + +static void +snmp_error_response(struct snmp_msg_pstat *msg_ps, u8_t error) +{ + /* move names back from outvb to invb */ + int v; + struct snmp_varbind *vbi = msg_ps->invb.head; + struct snmp_varbind *vbo = msg_ps->outvb.head; + for (v=0; vvb_idx; v++) { + vbi->ident_len = vbo->ident_len; + vbo->ident_len = 0; + vbi->ident = vbo->ident; + vbo->ident = NULL; + vbi = vbi->next; + vbo = vbo->next; + } + /* free outvb */ + snmp_varbind_list_free(&msg_ps->outvb); + /* we send invb back */ + msg_ps->outvb = msg_ps->invb; + msg_ps->invb.head = NULL; + msg_ps->invb.tail = NULL; + msg_ps->invb.count = 0; + msg_ps->error_status = error; + /* error index must be 0 for error too big */ + msg_ps->error_index = (error != SNMP_ES_TOOBIG) ? (1 + msg_ps->vb_idx) : 0; + snmp_send_response(msg_ps); + snmp_varbind_list_free(&msg_ps->outvb); + msg_ps->state = SNMP_MSG_EMPTY; +} + +static void +snmp_ok_response(struct snmp_msg_pstat *msg_ps) +{ + err_t err_ret; + + err_ret = snmp_send_response(msg_ps); + if (err_ret == ERR_MEM) + { + /* serious memory problem, can't return tooBig */ + } + else + { + LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event = %"S32_F"\n",msg_ps->error_status)); + } + /* free varbinds (if available) */ + snmp_varbind_list_free(&msg_ps->invb); + snmp_varbind_list_free(&msg_ps->outvb); + msg_ps->state = SNMP_MSG_EMPTY; +} + +/** + * Service an internal or external event for SNMP GET. + * + * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1) + * @param msg_ps points to the assosicated message process state + */ +static void +snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps) +{ + LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_get_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state)); + + if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF) + { + struct mib_external_node *en; + struct snmp_name_ptr np; + + /* get_object_def() answer*/ + en = msg_ps->ext_mib_node; + np = msg_ps->ext_name_ptr; + + /* translate answer into a known lifeform */ + en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def); + if ((msg_ps->ext_object_def.instance != MIB_OBJECT_NONE) && + (msg_ps->ext_object_def.access & MIB_ACCESS_READ)) + { + msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE; + en->get_value_q(request_id, &msg_ps->ext_object_def); + } + else + { + en->get_object_def_pc(request_id, np.ident_len, np.ident); + /* search failed, object id points to unknown object (nosuchname) */ + snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); + } + } + else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE) + { + struct mib_external_node *en; + struct snmp_varbind *vb; + + /* get_value() answer */ + en = msg_ps->ext_mib_node; + + /* allocate output varbind */ + vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND); + if (vb != NULL) + { + vb->next = NULL; + vb->prev = NULL; + + /* move name from invb to outvb */ + vb->ident = msg_ps->vb_ptr->ident; + vb->ident_len = msg_ps->vb_ptr->ident_len; + /* ensure this memory is refereced once only */ + msg_ps->vb_ptr->ident = NULL; + msg_ps->vb_ptr->ident_len = 0; + + vb->value_type = msg_ps->ext_object_def.asn_type; + LWIP_ASSERT("invalid length", msg_ps->ext_object_def.v_len <= 0xff); + vb->value_len = (u8_t)msg_ps->ext_object_def.v_len; + if (vb->value_len > 0) + { + LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", vb->value_len <= SNMP_MAX_VALUE_SIZE); + vb->value = memp_malloc(MEMP_SNMP_VALUE); + if (vb->value != NULL) + { + en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value); + snmp_varbind_tail_add(&msg_ps->outvb, vb); + /* search again (if vb_idx < msg_ps->invb.count) */ + msg_ps->state = SNMP_MSG_SEARCH_OBJ; + msg_ps->vb_idx += 1; + } + else + { + en->get_value_pc(request_id, &msg_ps->ext_object_def); + LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no variable space\n")); + msg_ps->vb_ptr->ident = vb->ident; + msg_ps->vb_ptr->ident_len = vb->ident_len; + memp_free(MEMP_SNMP_VARBIND, vb); + snmp_error_response(msg_ps,SNMP_ES_TOOBIG); + } + } + else + { + /* vb->value_len == 0, empty value (e.g. empty string) */ + en->get_value_a(request_id, &msg_ps->ext_object_def, 0, NULL); + vb->value = NULL; + snmp_varbind_tail_add(&msg_ps->outvb, vb); + /* search again (if vb_idx < msg_ps->invb.count) */ + msg_ps->state = SNMP_MSG_SEARCH_OBJ; + msg_ps->vb_idx += 1; + } + } + else + { + en->get_value_pc(request_id, &msg_ps->ext_object_def); + LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no outvb space\n")); + snmp_error_response(msg_ps,SNMP_ES_TOOBIG); + } + } + + while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && + (msg_ps->vb_idx < msg_ps->invb.count)) + { + struct mib_node *mn; + struct snmp_name_ptr np; + + if (msg_ps->vb_idx == 0) + { + msg_ps->vb_ptr = msg_ps->invb.head; + } + else + { + msg_ps->vb_ptr = msg_ps->vb_ptr->next; + } + /** test object identifier for .iso.org.dod.internet prefix */ + if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident)) + { + mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4, + msg_ps->vb_ptr->ident + 4, &np); + if (mn != NULL) + { + if (mn->node_type == MIB_NODE_EX) + { + /* external object */ + struct mib_external_node *en = (struct mib_external_node*)mn; + + msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF; + /* save en && args in msg_ps!! */ + msg_ps->ext_mib_node = en; + msg_ps->ext_name_ptr = np; + + en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident); + } + else + { + /* internal object */ + struct obj_def object_def; + + msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF; + mn->get_object_def(np.ident_len, np.ident, &object_def); + if ((object_def.instance != MIB_OBJECT_NONE) && + (object_def.access & MIB_ACCESS_READ)) + { + mn = mn; + } + else + { + /* search failed, object id points to unknown object (nosuchname) */ + mn = NULL; + } + if (mn != NULL) + { + struct snmp_varbind *vb; + + msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE; + /* allocate output varbind */ + vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND); + if (vb != NULL) + { + vb->next = NULL; + vb->prev = NULL; + + /* move name from invb to outvb */ + vb->ident = msg_ps->vb_ptr->ident; + vb->ident_len = msg_ps->vb_ptr->ident_len; + /* ensure this memory is refereced once only */ + msg_ps->vb_ptr->ident = NULL; + msg_ps->vb_ptr->ident_len = 0; + + vb->value_type = object_def.asn_type; + LWIP_ASSERT("invalid length", object_def.v_len <= 0xff); + vb->value_len = (u8_t)object_def.v_len; + if (vb->value_len > 0) + { + LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", + vb->value_len <= SNMP_MAX_VALUE_SIZE); + vb->value = memp_malloc(MEMP_SNMP_VALUE); + if (vb->value != NULL) + { + mn->get_value(&object_def, vb->value_len, vb->value); + snmp_varbind_tail_add(&msg_ps->outvb, vb); + msg_ps->state = SNMP_MSG_SEARCH_OBJ; + msg_ps->vb_idx += 1; + } + else + { + LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate variable space\n")); + msg_ps->vb_ptr->ident = vb->ident; + msg_ps->vb_ptr->ident_len = vb->ident_len; + vb->ident = NULL; + vb->ident_len = 0; + memp_free(MEMP_SNMP_VARBIND, vb); + snmp_error_response(msg_ps,SNMP_ES_TOOBIG); + } + } + else + { + /* vb->value_len == 0, empty value (e.g. empty string) */ + vb->value = NULL; + snmp_varbind_tail_add(&msg_ps->outvb, vb); + msg_ps->state = SNMP_MSG_SEARCH_OBJ; + msg_ps->vb_idx += 1; + } + } + else + { + LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate outvb space\n")); + snmp_error_response(msg_ps,SNMP_ES_TOOBIG); + } + } + } + } + } + else + { + mn = NULL; + } + if (mn == NULL) + { + /* mn == NULL, noSuchName */ + snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); + } + } + if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && + (msg_ps->vb_idx == msg_ps->invb.count)) + { + snmp_ok_response(msg_ps); + } +} + +/** + * Service an internal or external event for SNMP GETNEXT. + * + * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1) + * @param msg_ps points to the assosicated message process state + */ +static void +snmp_msg_getnext_event(u8_t request_id, struct snmp_msg_pstat *msg_ps) +{ + LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state)); + + if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF) + { + struct mib_external_node *en; + + /* get_object_def() answer*/ + en = msg_ps->ext_mib_node; + + /* translate answer into a known lifeform */ + en->get_object_def_a(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1], &msg_ps->ext_object_def); + if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE) + { + msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE; + en->get_value_q(request_id, &msg_ps->ext_object_def); + } + else + { + en->get_object_def_pc(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1]); + /* search failed, object id points to unknown object (nosuchname) */ + snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); + } + } + else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE) + { + struct mib_external_node *en; + struct snmp_varbind *vb; + + /* get_value() answer */ + en = msg_ps->ext_mib_node; + + LWIP_ASSERT("invalid length", msg_ps->ext_object_def.v_len <= 0xff); + vb = snmp_varbind_alloc(&msg_ps->ext_oid, + msg_ps->ext_object_def.asn_type, + (u8_t)msg_ps->ext_object_def.v_len); + if (vb != NULL) + { + en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value); + snmp_varbind_tail_add(&msg_ps->outvb, vb); + msg_ps->state = SNMP_MSG_SEARCH_OBJ; + msg_ps->vb_idx += 1; + } + else + { + en->get_value_pc(request_id, &msg_ps->ext_object_def); + LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: couldn't allocate outvb space\n")); + snmp_error_response(msg_ps,SNMP_ES_TOOBIG); + } + } + + while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && + (msg_ps->vb_idx < msg_ps->invb.count)) + { + struct mib_node *mn; + struct snmp_obj_id oid; + + if (msg_ps->vb_idx == 0) + { + msg_ps->vb_ptr = msg_ps->invb.head; + } + else + { + msg_ps->vb_ptr = msg_ps->vb_ptr->next; + } + if (snmp_iso_prefix_expand(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident, &oid)) + { + if (msg_ps->vb_ptr->ident_len > 3) + { + /* can offset ident_len and ident */ + mn = snmp_expand_tree((struct mib_node*)&internet, + msg_ps->vb_ptr->ident_len - 4, + msg_ps->vb_ptr->ident + 4, &oid); + } + else + { + /* can't offset ident_len -4, ident + 4 */ + mn = snmp_expand_tree((struct mib_node*)&internet, 0, NULL, &oid); + } + } + else + { + mn = NULL; + } + if (mn != NULL) + { + if (mn->node_type == MIB_NODE_EX) + { + /* external object */ + struct mib_external_node *en = (struct mib_external_node*)mn; + + msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF; + /* save en && args in msg_ps!! */ + msg_ps->ext_mib_node = en; + msg_ps->ext_oid = oid; + + en->get_object_def_q(en->addr_inf, request_id, 1, &oid.id[oid.len - 1]); + } + else + { + /* internal object */ + struct obj_def object_def; + struct snmp_varbind *vb; + + msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF; + mn->get_object_def(1, &oid.id[oid.len - 1], &object_def); + + LWIP_ASSERT("invalid length", object_def.v_len <= 0xff); + vb = snmp_varbind_alloc(&oid, object_def.asn_type, (u8_t)object_def.v_len); + if (vb != NULL) + { + msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE; + mn->get_value(&object_def, object_def.v_len, vb->value); + snmp_varbind_tail_add(&msg_ps->outvb, vb); + msg_ps->state = SNMP_MSG_SEARCH_OBJ; + msg_ps->vb_idx += 1; + } + else + { + LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv couldn't allocate outvb space\n")); + snmp_error_response(msg_ps,SNMP_ES_TOOBIG); + } + } + } + if (mn == NULL) + { + /* mn == NULL, noSuchName */ + snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); + } + } + if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && + (msg_ps->vb_idx == msg_ps->invb.count)) + { + snmp_ok_response(msg_ps); + } +} + +/** + * Service an internal or external event for SNMP SET. + * + * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1) + * @param msg_ps points to the assosicated message process state + */ +static void +snmp_msg_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps) +{ + LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_set_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state)); + + if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF) + { + struct mib_external_node *en; + struct snmp_name_ptr np; + + /* get_object_def() answer*/ + en = msg_ps->ext_mib_node; + np = msg_ps->ext_name_ptr; + + /* translate answer into a known lifeform */ + en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def); + if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE) + { + msg_ps->state = SNMP_MSG_EXTERNAL_SET_TEST; + en->set_test_q(request_id, &msg_ps->ext_object_def); + } + else + { + en->get_object_def_pc(request_id, np.ident_len, np.ident); + /* search failed, object id points to unknown object (nosuchname) */ + snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); + } + } + else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_TEST) + { + struct mib_external_node *en; + + /* set_test() answer*/ + en = msg_ps->ext_mib_node; + + if (msg_ps->ext_object_def.access & MIB_ACCESS_WRITE) + { + if ((msg_ps->ext_object_def.asn_type == msg_ps->vb_ptr->value_type) && + (en->set_test_a(request_id,&msg_ps->ext_object_def, + msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0)) + { + msg_ps->state = SNMP_MSG_SEARCH_OBJ; + msg_ps->vb_idx += 1; + } + else + { + en->set_test_pc(request_id,&msg_ps->ext_object_def); + /* bad value */ + snmp_error_response(msg_ps,SNMP_ES_BADVALUE); + } + } + else + { + en->set_test_pc(request_id,&msg_ps->ext_object_def); + /* object not available for set */ + snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); + } + } + else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF_S) + { + struct mib_external_node *en; + struct snmp_name_ptr np; + + /* get_object_def() answer*/ + en = msg_ps->ext_mib_node; + np = msg_ps->ext_name_ptr; + + /* translate answer into a known lifeform */ + en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def); + if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE) + { + msg_ps->state = SNMP_MSG_EXTERNAL_SET_VALUE; + en->set_value_q(request_id, &msg_ps->ext_object_def, + msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value); + } + else + { + en->get_object_def_pc(request_id, np.ident_len, np.ident); + /* set_value failed, object has disappeared for some odd reason?? */ + snmp_error_response(msg_ps,SNMP_ES_GENERROR); + } + } + else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_VALUE) + { + struct mib_external_node *en; + + /** set_value_a() */ + en = msg_ps->ext_mib_node; + en->set_value_a(request_id, &msg_ps->ext_object_def, + msg_ps->vb_ptr->value_len, msg_ps->vb_ptr->value); + + /** @todo use set_value_pc() if toobig */ + msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE; + msg_ps->vb_idx += 1; + } + + /* test all values before setting */ + while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && + (msg_ps->vb_idx < msg_ps->invb.count)) + { + struct mib_node *mn; + struct snmp_name_ptr np; + + if (msg_ps->vb_idx == 0) + { + msg_ps->vb_ptr = msg_ps->invb.head; + } + else + { + msg_ps->vb_ptr = msg_ps->vb_ptr->next; + } + /** test object identifier for .iso.org.dod.internet prefix */ + if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident)) + { + mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4, + msg_ps->vb_ptr->ident + 4, &np); + if (mn != NULL) + { + if (mn->node_type == MIB_NODE_EX) + { + /* external object */ + struct mib_external_node *en = (struct mib_external_node*)mn; + + msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF; + /* save en && args in msg_ps!! */ + msg_ps->ext_mib_node = en; + msg_ps->ext_name_ptr = np; + + en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident); + } + else + { + /* internal object */ + struct obj_def object_def; + + msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF; + mn->get_object_def(np.ident_len, np.ident, &object_def); + if (object_def.instance != MIB_OBJECT_NONE) + { + mn = mn; + } + else + { + /* search failed, object id points to unknown object (nosuchname) */ + mn = NULL; + } + if (mn != NULL) + { + msg_ps->state = SNMP_MSG_INTERNAL_SET_TEST; + + if (object_def.access & MIB_ACCESS_WRITE) + { + if ((object_def.asn_type == msg_ps->vb_ptr->value_type) && + (mn->set_test(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0)) + { + msg_ps->state = SNMP_MSG_SEARCH_OBJ; + msg_ps->vb_idx += 1; + } + else + { + /* bad value */ + snmp_error_response(msg_ps,SNMP_ES_BADVALUE); + } + } + else + { + /* object not available for set */ + snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); + } + } + } + } + } + else + { + mn = NULL; + } + if (mn == NULL) + { + /* mn == NULL, noSuchName */ + snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); + } + } + + if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && + (msg_ps->vb_idx == msg_ps->invb.count)) + { + msg_ps->vb_idx = 0; + msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE; + } + + /* set all values "atomically" (be as "atomic" as possible) */ + while ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) && + (msg_ps->vb_idx < msg_ps->invb.count)) + { + struct mib_node *mn; + struct snmp_name_ptr np; + + if (msg_ps->vb_idx == 0) + { + msg_ps->vb_ptr = msg_ps->invb.head; + } + else + { + msg_ps->vb_ptr = msg_ps->vb_ptr->next; + } + /* skip iso prefix test, was done previously while settesting() */ + mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4, + msg_ps->vb_ptr->ident + 4, &np); + /* check if object is still available + (e.g. external hot-plug thingy present?) */ + if (mn != NULL) + { + if (mn->node_type == MIB_NODE_EX) + { + /* external object */ + struct mib_external_node *en = (struct mib_external_node*)mn; + + msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF_S; + /* save en && args in msg_ps!! */ + msg_ps->ext_mib_node = en; + msg_ps->ext_name_ptr = np; + + en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident); + } + else + { + /* internal object */ + struct obj_def object_def; + + msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF_S; + mn->get_object_def(np.ident_len, np.ident, &object_def); + msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE; + mn->set_value(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value); + msg_ps->vb_idx += 1; + } + } + } + if ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) && + (msg_ps->vb_idx == msg_ps->invb.count)) + { + /* simply echo the input if we can set it + @todo do we need to return the actual value? + e.g. if value is silently modified or behaves sticky? */ + msg_ps->outvb = msg_ps->invb; + msg_ps->invb.head = NULL; + msg_ps->invb.tail = NULL; + msg_ps->invb.count = 0; + snmp_ok_response(msg_ps); + } +} + + +/** + * Handle one internal or external event. + * Called for one async event. (recv external/private answer) + * + * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1) + */ +void +snmp_msg_event(u8_t request_id) +{ + struct snmp_msg_pstat *msg_ps; + + if (request_id < SNMP_CONCURRENT_REQUESTS) + { + msg_ps = &msg_input_list[request_id]; + if (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ) + { + snmp_msg_getnext_event(request_id, msg_ps); + } + else if (msg_ps->rt == SNMP_ASN1_PDU_GET_REQ) + { + snmp_msg_get_event(request_id, msg_ps); + } + else if(msg_ps->rt == SNMP_ASN1_PDU_SET_REQ) + { + snmp_msg_set_event(request_id, msg_ps); + } + } +} + + +/* lwIP UDP receive callback function */ +static void +snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port) +{ + struct snmp_msg_pstat *msg_ps; + u8_t req_idx; + err_t err_ret; + u16_t payload_len = p->tot_len; + u16_t payload_ofs = 0; + u16_t varbind_ofs = 0; + + /* suppress unused argument warning */ + LWIP_UNUSED_ARG(arg); + + /* traverse input message process list, look for SNMP_MSG_EMPTY */ + msg_ps = &msg_input_list[0]; + req_idx = 0; + while ((req_idx < SNMP_CONCURRENT_REQUESTS) && (msg_ps->state != SNMP_MSG_EMPTY)) + { + req_idx++; + msg_ps++; + } + if (req_idx == SNMP_CONCURRENT_REQUESTS) + { + /* exceeding number of concurrent requests */ + pbuf_free(p); + return; + } + + /* accepting request */ + snmp_inc_snmpinpkts(); + /* record used 'protocol control block' */ + msg_ps->pcb = pcb; + /* source address (network order) */ + msg_ps->sip = *addr; + /* source port (host order (lwIP oddity)) */ + msg_ps->sp = port; + + /* check total length, version, community, pdu type */ + err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps); + /* Only accept requests and requests without error (be robust) */ + /* Reject response and trap headers or error requests as input! */ + if ((err_ret != ERR_OK) || + ((msg_ps->rt != SNMP_ASN1_PDU_GET_REQ) && + (msg_ps->rt != SNMP_ASN1_PDU_GET_NEXT_REQ) && + (msg_ps->rt != SNMP_ASN1_PDU_SET_REQ)) || + ((msg_ps->error_status != SNMP_ES_NOERROR) || + (msg_ps->error_index != 0)) ) + { + /* header check failed drop request silently, do not return error! */ + pbuf_free(p); + LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n")); + return; + } + LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv ok, community %s\n", msg_ps->community)); + + /* Builds a list of variable bindings. Copy the varbinds from the pbuf + chain to glue them when these are divided over two or more pbuf's. */ + err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps); + /* we've decoded the incoming message, release input msg now */ + pbuf_free(p); + if ((err_ret != ERR_OK) || (msg_ps->invb.count == 0)) + { + /* varbind-list decode failed, or varbind list empty. + drop request silently, do not return error! + (errors are only returned for a specific varbind failure) */ + LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed\n")); + return; + } + + msg_ps->error_status = SNMP_ES_NOERROR; + msg_ps->error_index = 0; + /* find object for each variable binding */ + msg_ps->state = SNMP_MSG_SEARCH_OBJ; + /* first variable binding from list to inspect */ + msg_ps->vb_idx = 0; + + LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count)); + + /* handle input event and as much objects as possible in one go */ + snmp_msg_event(req_idx); +} + +/** + * Checks and decodes incoming SNMP message header, logs header errors. + * + * @param p points to pbuf chain of SNMP message (UDP payload) + * @param ofs points to first octet of SNMP message + * @param pdu_len the length of the UDP payload + * @param ofs_ret returns the ofset of the variable bindings + * @param m_stat points to the current message request state return + * @return + * - ERR_OK SNMP header is sane and accepted + * - ERR_ARG SNMP header is either malformed or rejected + */ +static err_t +snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat) +{ + err_t derr; + u16_t len, ofs_base; + u8_t len_octets; + u8_t type; + s32_t version; + + ofs_base = ofs; + snmp_asn1_dec_type(p, ofs, &type); + derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); + if ((derr != ERR_OK) || + (pdu_len != (1 + len_octets + len)) || + (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ))) + { + snmp_inc_snmpinasnparseerrs(); + return ERR_ARG; + } + ofs += (1 + len_octets); + snmp_asn1_dec_type(p, ofs, &type); + derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); + if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG))) + { + /* can't decode or no integer (version) */ + snmp_inc_snmpinasnparseerrs(); + return ERR_ARG; + } + derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &version); + if (derr != ERR_OK) + { + /* can't decode */ + snmp_inc_snmpinasnparseerrs(); + return ERR_ARG; + } + if (version != 0) + { + /* not version 1 */ + snmp_inc_snmpinbadversions(); + return ERR_ARG; + } + ofs += (1 + len_octets + len); + snmp_asn1_dec_type(p, ofs, &type); + derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); + if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR))) + { + /* can't decode or no octet string (community) */ + snmp_inc_snmpinasnparseerrs(); + return ERR_ARG; + } + derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, SNMP_COMMUNITY_STR_LEN, m_stat->community); + if (derr != ERR_OK) + { + snmp_inc_snmpinasnparseerrs(); + return ERR_ARG; + } + /* add zero terminator */ + len = ((len < (SNMP_COMMUNITY_STR_LEN))?(len):(SNMP_COMMUNITY_STR_LEN)); + m_stat->community[len] = 0; + m_stat->com_strlen = (u8_t)len; + if (strncmp(snmp_publiccommunity, (const char*)m_stat->community, SNMP_COMMUNITY_STR_LEN) != 0) + { + /** @todo: move this if we need to check more names */ + snmp_inc_snmpinbadcommunitynames(); + snmp_authfail_trap(); + return ERR_ARG; + } + ofs += (1 + len_octets + len); + snmp_asn1_dec_type(p, ofs, &type); + derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); + if (derr != ERR_OK) + { + snmp_inc_snmpinasnparseerrs(); + return ERR_ARG; + } + switch(type) + { + case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_REQ): + /* GetRequest PDU */ + snmp_inc_snmpingetrequests(); + derr = ERR_OK; + break; + case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_NEXT_REQ): + /* GetNextRequest PDU */ + snmp_inc_snmpingetnexts(); + derr = ERR_OK; + break; + case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP): + /* GetResponse PDU */ + snmp_inc_snmpingetresponses(); + derr = ERR_ARG; + break; + case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_SET_REQ): + /* SetRequest PDU */ + snmp_inc_snmpinsetrequests(); + derr = ERR_OK; + break; + case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP): + /* Trap PDU */ + snmp_inc_snmpintraps(); + derr = ERR_ARG; + break; + default: + snmp_inc_snmpinasnparseerrs(); + derr = ERR_ARG; + break; + } + if (derr != ERR_OK) + { + /* unsupported input PDU for this agent (no parse error) */ + return ERR_ARG; + } + m_stat->rt = type & 0x1F; + ofs += (1 + len_octets); + if (len != (pdu_len - (ofs - ofs_base))) + { + /* decoded PDU length does not equal actual payload length */ + snmp_inc_snmpinasnparseerrs(); + return ERR_ARG; + } + snmp_asn1_dec_type(p, ofs, &type); + derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); + if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG))) + { + /* can't decode or no integer (request ID) */ + snmp_inc_snmpinasnparseerrs(); + return ERR_ARG; + } + derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->rid); + if (derr != ERR_OK) + { + /* can't decode */ + snmp_inc_snmpinasnparseerrs(); + return ERR_ARG; + } + ofs += (1 + len_octets + len); + snmp_asn1_dec_type(p, ofs, &type); + derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); + if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG))) + { + /* can't decode or no integer (error-status) */ + snmp_inc_snmpinasnparseerrs(); + return ERR_ARG; + } + /* must be noError (0) for incoming requests. + log errors for mib-2 completeness and for debug purposes */ + derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_status); + if (derr != ERR_OK) + { + /* can't decode */ + snmp_inc_snmpinasnparseerrs(); + return ERR_ARG; + } + switch (m_stat->error_status) + { + case SNMP_ES_TOOBIG: + snmp_inc_snmpintoobigs(); + break; + case SNMP_ES_NOSUCHNAME: + snmp_inc_snmpinnosuchnames(); + break; + case SNMP_ES_BADVALUE: + snmp_inc_snmpinbadvalues(); + break; + case SNMP_ES_READONLY: + snmp_inc_snmpinreadonlys(); + break; + case SNMP_ES_GENERROR: + snmp_inc_snmpingenerrs(); + break; + } + ofs += (1 + len_octets + len); + snmp_asn1_dec_type(p, ofs, &type); + derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); + if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG))) + { + /* can't decode or no integer (error-index) */ + snmp_inc_snmpinasnparseerrs(); + return ERR_ARG; + } + /* must be 0 for incoming requests. + decode anyway to catch bad integers (and dirty tricks) */ + derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_index); + if (derr != ERR_OK) + { + /* can't decode */ + snmp_inc_snmpinasnparseerrs(); + return ERR_ARG; + } + ofs += (1 + len_octets + len); + *ofs_ret = ofs; + return ERR_OK; +} + +static err_t +snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat) +{ + err_t derr; + u16_t len, vb_len; + u8_t len_octets; + u8_t type; + + /* variable binding list */ + snmp_asn1_dec_type(p, ofs, &type); + derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &vb_len); + if ((derr != ERR_OK) || + (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ))) + { + snmp_inc_snmpinasnparseerrs(); + return ERR_ARG; + } + ofs += (1 + len_octets); + + /* start with empty list */ + m_stat->invb.count = 0; + m_stat->invb.head = NULL; + m_stat->invb.tail = NULL; + + while (vb_len > 0) + { + struct snmp_obj_id oid, oid_value; + struct snmp_varbind *vb; + + snmp_asn1_dec_type(p, ofs, &type); + derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); + if ((derr != ERR_OK) || + (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)) || + (len == 0) || (len > vb_len)) + { + snmp_inc_snmpinasnparseerrs(); + /* free varbinds (if available) */ + snmp_varbind_list_free(&m_stat->invb); + return ERR_ARG; + } + ofs += (1 + len_octets); + vb_len -= (1 + len_octets); + + snmp_asn1_dec_type(p, ofs, &type); + derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); + if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID))) + { + /* can't decode object name length */ + snmp_inc_snmpinasnparseerrs(); + /* free varbinds (if available) */ + snmp_varbind_list_free(&m_stat->invb); + return ERR_ARG; + } + derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid); + if (derr != ERR_OK) + { + /* can't decode object name */ + snmp_inc_snmpinasnparseerrs(); + /* free varbinds (if available) */ + snmp_varbind_list_free(&m_stat->invb); + return ERR_ARG; + } + ofs += (1 + len_octets + len); + vb_len -= (1 + len_octets + len); + + snmp_asn1_dec_type(p, ofs, &type); + derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); + if (derr != ERR_OK) + { + /* can't decode object value length */ + snmp_inc_snmpinasnparseerrs(); + /* free varbinds (if available) */ + snmp_varbind_list_free(&m_stat->invb); + return ERR_ARG; + } + + switch (type) + { + case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG): + vb = snmp_varbind_alloc(&oid, type, sizeof(s32_t)); + if (vb != NULL) + { + s32_t *vptr = (s32_t*)vb->value; + + derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, vptr); + snmp_varbind_tail_add(&m_stat->invb, vb); + } + else + { + derr = ERR_ARG; + } + break; + case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER): + case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE): + case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS): + vb = snmp_varbind_alloc(&oid, type, sizeof(u32_t)); + if (vb != NULL) + { + u32_t *vptr = (u32_t*)vb->value; + + derr = snmp_asn1_dec_u32t(p, ofs + 1 + len_octets, len, vptr); + snmp_varbind_tail_add(&m_stat->invb, vb); + } + else + { + derr = ERR_ARG; + } + break; + case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR): + case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE): + LWIP_ASSERT("invalid length", len <= 0xff); + vb = snmp_varbind_alloc(&oid, type, (u8_t)len); + if (vb != NULL) + { + derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, (u8_t*)vb->value); + snmp_varbind_tail_add(&m_stat->invb, vb); + } + else + { + derr = ERR_ARG; + } + break; + case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL): + vb = snmp_varbind_alloc(&oid, type, 0); + if (vb != NULL) + { + snmp_varbind_tail_add(&m_stat->invb, vb); + derr = ERR_OK; + } + else + { + derr = ERR_ARG; + } + break; + case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID): + derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid_value); + if (derr == ERR_OK) + { + vb = snmp_varbind_alloc(&oid, type, oid_value.len * sizeof(s32_t)); + if (vb != NULL) + { + u8_t i = oid_value.len; + s32_t *vptr = (s32_t*)vb->value; + + while(i > 0) + { + i--; + vptr[i] = oid_value.id[i]; + } + snmp_varbind_tail_add(&m_stat->invb, vb); + derr = ERR_OK; + } + else + { + derr = ERR_ARG; + } + } + break; + case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR): + if (len == 4) + { + /* must be exactly 4 octets! */ + vb = snmp_varbind_alloc(&oid, type, 4); + if (vb != NULL) + { + derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, (u8_t*)vb->value); + snmp_varbind_tail_add(&m_stat->invb, vb); + } + else + { + derr = ERR_ARG; + } + } + else + { + derr = ERR_ARG; + } + break; + default: + derr = ERR_ARG; + break; + } + if (derr != ERR_OK) + { + snmp_inc_snmpinasnparseerrs(); + /* free varbinds (if available) */ + snmp_varbind_list_free(&m_stat->invb); + return ERR_ARG; + } + ofs += (1 + len_octets + len); + vb_len -= (1 + len_octets + len); + } + + if (m_stat->rt == SNMP_ASN1_PDU_SET_REQ) + { + snmp_add_snmpintotalsetvars(m_stat->invb.count); + } + else + { + snmp_add_snmpintotalreqvars(m_stat->invb.count); + } + + *ofs_ret = ofs; + return ERR_OK; +} + +struct snmp_varbind* +snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len) +{ + struct snmp_varbind *vb; + + vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND); + if (vb != NULL) + { + u8_t i; + + vb->next = NULL; + vb->prev = NULL; + i = oid->len; + vb->ident_len = i; + if (i > 0) + { + LWIP_ASSERT("SNMP_MAX_TREE_DEPTH is configured too low", i <= SNMP_MAX_TREE_DEPTH); + /* allocate array of s32_t for our object identifier */ + vb->ident = (s32_t*)memp_malloc(MEMP_SNMP_VALUE); + if (vb->ident == NULL) + { + LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_varbind_alloc: couldn't allocate ident value space\n")); + memp_free(MEMP_SNMP_VARBIND, vb); + return NULL; + } + while(i > 0) + { + i--; + vb->ident[i] = oid->id[i]; + } + } + else + { + /* i == 0, pass zero length object identifier */ + vb->ident = NULL; + } + vb->value_type = type; + vb->value_len = len; + if (len > 0) + { + LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", vb->value_len <= SNMP_MAX_VALUE_SIZE); + /* allocate raw bytes for our object value */ + vb->value = memp_malloc(MEMP_SNMP_VALUE); + if (vb->value == NULL) + { + LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_varbind_alloc: couldn't allocate value space\n")); + if (vb->ident != NULL) + { + memp_free(MEMP_SNMP_VALUE, vb->ident); + } + memp_free(MEMP_SNMP_VARBIND, vb); + return NULL; + } + } + else + { + /* ASN1_NUL type, or zero length ASN1_OC_STR */ + vb->value = NULL; + } + } + else + { + LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_varbind_alloc: couldn't allocate varbind space\n")); + } + return vb; +} + +void +snmp_varbind_free(struct snmp_varbind *vb) +{ + if (vb->value != NULL ) + { + memp_free(MEMP_SNMP_VALUE, vb->value); + } + if (vb->ident != NULL ) + { + memp_free(MEMP_SNMP_VALUE, vb->ident); + } + memp_free(MEMP_SNMP_VARBIND, vb); +} + +void +snmp_varbind_list_free(struct snmp_varbind_root *root) +{ + struct snmp_varbind *vb, *prev; + + vb = root->tail; + while ( vb != NULL ) + { + prev = vb->prev; + snmp_varbind_free(vb); + vb = prev; + } + root->count = 0; + root->head = NULL; + root->tail = NULL; +} + +void +snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb) +{ + if (root->count == 0) + { + /* add first varbind to list */ + root->head = vb; + root->tail = vb; + } + else + { + /* add nth varbind to list tail */ + root->tail->next = vb; + vb->prev = root->tail; + root->tail = vb; + } + root->count += 1; +} + +struct snmp_varbind* +snmp_varbind_tail_remove(struct snmp_varbind_root *root) +{ + struct snmp_varbind* vb; + + if (root->count > 0) + { + /* remove tail varbind */ + vb = root->tail; + root->tail = vb->prev; + vb->prev->next = NULL; + root->count -= 1; + } + else + { + /* nothing to remove */ + vb = NULL; + } + return vb; +} + +#endif /* LWIP_SNMP */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/snmp/msg_out.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/snmp/msg_out.c new file mode 100644 index 0000000..3099753 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/snmp/msg_out.c @@ -0,0 +1,682 @@ +/** + * @file + * SNMP output message processing (RFC1157). + * + * Output responses and traps are build in two passes: + * + * Pass 0: iterate over the output message backwards to determine encoding lengths + * Pass 1: the actual forward encoding of internal form into ASN1 + * + * The single-pass encoding method described by Comer & Stevens + * requires extra buffer space and copying for reversal of the packet. + * The buffer requirement can be prohibitively large for big payloads + * (>= 484) therefore we use the two encoding passes. + */ + +/* + * 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 + */ + +#include "lwip/opt.h" + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/udp.h" +#include "lwip/netif.h" +#include "lwip/snmp.h" +#include "lwip/snmp_asn1.h" +#include "lwip/snmp_msg.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +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; +}; +struct snmp_trap_dst trap_dst[SNMP_TRAP_DESTINATIONS]; + +/** TRAP message structure */ +struct snmp_msg_trap trap_msg; + +static u16_t snmp_resp_header_sum(struct snmp_msg_pstat *m_stat, u16_t vb_len); +static u16_t snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len); +static u16_t snmp_varbind_list_sum(struct snmp_varbind_root *root); + +static u16_t snmp_resp_header_enc(struct snmp_msg_pstat *m_stat, struct pbuf *p); +static u16_t snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p); +static u16_t snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs); + +/** + * 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; + } +} + +/** + * 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, ip_addr_t *dst) +{ + if (dst_idx < SNMP_TRAP_DESTINATIONS) + { + ip_addr_set(&trap_dst[dst_idx].dip, dst); + } +} + +/** + * Sends a 'getresponse' message to the request originator. + * + * @param m_stat points to the current message request state source + * @return ERR_OK when success, ERR_MEM if we're out of memory + * + * @note the caller is responsible for filling in outvb in the m_stat + * and provide error-status and index (except for tooBig errors) ... + */ +err_t +snmp_send_response(struct snmp_msg_pstat *m_stat) +{ + struct snmp_varbind_root emptyvb = {NULL, NULL, 0, 0, 0}; + struct pbuf *p; + u16_t tot_len; + err_t err; + + /* pass 0, calculate length fields */ + tot_len = snmp_varbind_list_sum(&m_stat->outvb); + tot_len = snmp_resp_header_sum(m_stat, tot_len); + + /* try allocating pbuf(s) for complete response */ + p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL); + if (p == NULL) + { + LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() tooBig\n")); + + /* can't construct reply, return error-status tooBig */ + m_stat->error_status = SNMP_ES_TOOBIG; + m_stat->error_index = 0; + /* pass 0, recalculate lengths, for empty varbind-list */ + tot_len = snmp_varbind_list_sum(&emptyvb); + tot_len = snmp_resp_header_sum(m_stat, tot_len); + /* retry allocation once for header and empty varbind-list */ + p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL); + } + if (p != NULL) + { + /* first pbuf alloc try or retry alloc success */ + u16_t ofs; + + LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() p != NULL\n")); + + /* pass 1, size error, encode packet ino the pbuf(s) */ + ofs = snmp_resp_header_enc(m_stat, p); + snmp_varbind_list_enc(&m_stat->outvb, p, ofs); + + switch (m_stat->error_status) + { + case SNMP_ES_TOOBIG: + snmp_inc_snmpouttoobigs(); + break; + case SNMP_ES_NOSUCHNAME: + snmp_inc_snmpoutnosuchnames(); + break; + case SNMP_ES_BADVALUE: + snmp_inc_snmpoutbadvalues(); + break; + case SNMP_ES_GENERROR: + snmp_inc_snmpoutgenerrs(); + break; + } + snmp_inc_snmpoutgetresponses(); + snmp_inc_snmpoutpkts(); + + /** @todo do we need separate rx and tx pcbs for threaded case? */ + /** connect to the originating source */ + udp_connect(m_stat->pcb, &m_stat->sip, m_stat->sp); + err = udp_send(m_stat->pcb, p); + if (err == ERR_MEM) + { + /** @todo release some memory, retry and return tooBig? tooMuchHassle? */ + err = ERR_MEM; + } + else + { + err = ERR_OK; + } + /** disassociate remote address and port with this pcb */ + udp_disconnect(m_stat->pcb); + + pbuf_free(p); + LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() done\n")); + return err; + } + else + { + /* first pbuf alloc try or retry alloc failed + very low on memory, couldn't return tooBig */ + return ERR_MEM; + } +} + + +/** + * Sends an generic or enterprise specific trap message. + * + * @param generic_trap is the trap code + * @param eoid points to enterprise object identifier + * @param specific_trap used for enterprise traps when generic_trap == 6 + * @return ERR_OK when success, ERR_MEM if we're out of memory + * + * @note the caller is responsible for filling in outvb in the trap_msg + * @note the use of the enterpise 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(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap) +{ + struct snmp_trap_dst *td; + struct netif *dst_if; + ip_addr_t dst_ip; + struct pbuf *p; + u16_t i,tot_len; + err_t err = ERR_OK; + + for (i=0, td = &trap_dst[0]; ienable != 0) && !ip_addr_isany(&td->dip)) + { + /* network order trap destination */ + ip_addr_copy(trap_msg.dip, td->dip); + /* lookup current source address for this dst */ + dst_if = ip_route(&td->dip); + if (dst_if != NULL) { + ip_addr_copy(dst_ip, dst_if->ip_addr); + /* @todo: what about IPv6? */ + trap_msg.sip_raw[0] = ip4_addr1(&dst_ip); + trap_msg.sip_raw[1] = ip4_addr2(&dst_ip); + trap_msg.sip_raw[2] = ip4_addr3(&dst_ip); + trap_msg.sip_raw[3] = ip4_addr4(&dst_ip); + trap_msg.gen_trap = generic_trap; + trap_msg.spc_trap = specific_trap; + if (generic_trap == SNMP_GENTRAP_ENTERPRISESPC) + { + /* enterprise-Specific trap */ + trap_msg.enterprise = eoid; + } + else + { + /* generic (MIB-II) trap */ + snmp_get_snmpgrpid_ptr(&trap_msg.enterprise); + } + snmp_get_sysuptime(&trap_msg.ts); + + /* pass 0, calculate length fields */ + tot_len = snmp_varbind_list_sum(&trap_msg.outvb); + tot_len = snmp_trap_header_sum(&trap_msg, tot_len); + + /* allocate pbuf(s) */ + p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL); + if (p != NULL) + { + u16_t ofs; + + /* pass 1, encode packet ino the pbuf(s) */ + ofs = snmp_trap_header_enc(&trap_msg, p); + snmp_varbind_list_enc(&trap_msg.outvb, p, ofs); + + snmp_inc_snmpouttraps(); + snmp_inc_snmpoutpkts(); + + /** send to the TRAP destination */ + udp_sendto(trap_msg.pcb, p, &trap_msg.dip, SNMP_TRAP_PORT); + + pbuf_free(p); + } else { + err = ERR_MEM; + } + } else { + /* routing error */ + err = ERR_RTE; + } + } + } + return err; +} + +void +snmp_coldstart_trap(void) +{ + trap_msg.outvb.head = NULL; + trap_msg.outvb.tail = NULL; + trap_msg.outvb.count = 0; + snmp_send_trap(SNMP_GENTRAP_COLDSTART, NULL, 0); +} + +void +snmp_authfail_trap(void) +{ + u8_t enable; + snmp_get_snmpenableauthentraps(&enable); + if (enable == 1) + { + trap_msg.outvb.head = NULL; + trap_msg.outvb.tail = NULL; + trap_msg.outvb.count = 0; + snmp_send_trap(SNMP_GENTRAP_AUTHFAIL, NULL, 0); + } +} + +/** + * Sums response header field lengths from tail to head and + * returns resp_header_lengths for second encoding pass. + * + * @param vb_len varbind-list length + * @param rhl points to returned header lengths + * @return the required lenght for encoding the response header + */ +static u16_t +snmp_resp_header_sum(struct snmp_msg_pstat *m_stat, u16_t vb_len) +{ + u16_t tot_len; + struct snmp_resp_header_lengths *rhl; + + rhl = &m_stat->rhl; + tot_len = vb_len; + snmp_asn1_enc_s32t_cnt(m_stat->error_index, &rhl->erridxlen); + snmp_asn1_enc_length_cnt(rhl->erridxlen, &rhl->erridxlenlen); + tot_len += 1 + rhl->erridxlenlen + rhl->erridxlen; + + snmp_asn1_enc_s32t_cnt(m_stat->error_status, &rhl->errstatlen); + snmp_asn1_enc_length_cnt(rhl->errstatlen, &rhl->errstatlenlen); + tot_len += 1 + rhl->errstatlenlen + rhl->errstatlen; + + snmp_asn1_enc_s32t_cnt(m_stat->rid, &rhl->ridlen); + snmp_asn1_enc_length_cnt(rhl->ridlen, &rhl->ridlenlen); + tot_len += 1 + rhl->ridlenlen + rhl->ridlen; + + rhl->pdulen = tot_len; + snmp_asn1_enc_length_cnt(rhl->pdulen, &rhl->pdulenlen); + tot_len += 1 + rhl->pdulenlen; + + rhl->comlen = m_stat->com_strlen; + snmp_asn1_enc_length_cnt(rhl->comlen, &rhl->comlenlen); + tot_len += 1 + rhl->comlenlen + rhl->comlen; + + snmp_asn1_enc_s32t_cnt(snmp_version, &rhl->verlen); + snmp_asn1_enc_length_cnt(rhl->verlen, &rhl->verlenlen); + tot_len += 1 + rhl->verlen + rhl->verlenlen; + + rhl->seqlen = tot_len; + snmp_asn1_enc_length_cnt(rhl->seqlen, &rhl->seqlenlen); + tot_len += 1 + rhl->seqlenlen; + + return tot_len; +} + +/** + * Sums trap header field lengths from tail to head and + * returns trap_header_lengths for second encoding pass. + * + * @param vb_len varbind-list length + * @param thl points to returned header lengths + * @return the required lenght for encoding the trap header + */ +static u16_t +snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len) +{ + u16_t tot_len; + struct snmp_trap_header_lengths *thl; + + thl = &m_trap->thl; + tot_len = vb_len; + + snmp_asn1_enc_u32t_cnt(m_trap->ts, &thl->tslen); + snmp_asn1_enc_length_cnt(thl->tslen, &thl->tslenlen); + tot_len += 1 + thl->tslen + thl->tslenlen; + + snmp_asn1_enc_s32t_cnt(m_trap->spc_trap, &thl->strplen); + snmp_asn1_enc_length_cnt(thl->strplen, &thl->strplenlen); + tot_len += 1 + thl->strplen + thl->strplenlen; + + snmp_asn1_enc_s32t_cnt(m_trap->gen_trap, &thl->gtrplen); + snmp_asn1_enc_length_cnt(thl->gtrplen, &thl->gtrplenlen); + tot_len += 1 + thl->gtrplen + thl->gtrplenlen; + + thl->aaddrlen = 4; + snmp_asn1_enc_length_cnt(thl->aaddrlen, &thl->aaddrlenlen); + tot_len += 1 + thl->aaddrlen + thl->aaddrlenlen; + + snmp_asn1_enc_oid_cnt(m_trap->enterprise->len, &m_trap->enterprise->id[0], &thl->eidlen); + snmp_asn1_enc_length_cnt(thl->eidlen, &thl->eidlenlen); + tot_len += 1 + thl->eidlen + thl->eidlenlen; + + thl->pdulen = tot_len; + snmp_asn1_enc_length_cnt(thl->pdulen, &thl->pdulenlen); + tot_len += 1 + thl->pdulenlen; + + thl->comlen = sizeof(snmp_publiccommunity) - 1; + snmp_asn1_enc_length_cnt(thl->comlen, &thl->comlenlen); + tot_len += 1 + thl->comlenlen + thl->comlen; + + snmp_asn1_enc_s32t_cnt(snmp_version, &thl->verlen); + snmp_asn1_enc_length_cnt(thl->verlen, &thl->verlenlen); + tot_len += 1 + thl->verlen + thl->verlenlen; + + thl->seqlen = tot_len; + snmp_asn1_enc_length_cnt(thl->seqlen, &thl->seqlenlen); + tot_len += 1 + thl->seqlenlen; + + return tot_len; +} + +/** + * Sums varbind lengths from tail to head and + * annotates lengths in varbind for second encoding pass. + * + * @param root points to the root of the variable binding list + * @return the required lenght for encoding the variable bindings + */ +static u16_t +snmp_varbind_list_sum(struct snmp_varbind_root *root) +{ + struct snmp_varbind *vb; + u32_t *uint_ptr; + s32_t *sint_ptr; + u16_t tot_len; + + tot_len = 0; + vb = root->tail; + while ( vb != NULL ) + { + /* encoded value lenght depends on type */ + switch (vb->value_type) + { + case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG): + sint_ptr = (s32_t*)vb->value; + snmp_asn1_enc_s32t_cnt(*sint_ptr, &vb->vlen); + break; + case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER): + case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE): + case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS): + uint_ptr = (u32_t*)vb->value; + snmp_asn1_enc_u32t_cnt(*uint_ptr, &vb->vlen); + break; + case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR): + case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL): + case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR): + case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE): + vb->vlen = vb->value_len; + break; + case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID): + sint_ptr = (s32_t*)vb->value; + snmp_asn1_enc_oid_cnt(vb->value_len / sizeof(s32_t), sint_ptr, &vb->vlen); + break; + default: + /* unsupported type */ + vb->vlen = 0; + break; + }; + /* encoding length of value length field */ + snmp_asn1_enc_length_cnt(vb->vlen, &vb->vlenlen); + snmp_asn1_enc_oid_cnt(vb->ident_len, vb->ident, &vb->olen); + snmp_asn1_enc_length_cnt(vb->olen, &vb->olenlen); + + vb->seqlen = 1 + vb->vlenlen + vb->vlen; + vb->seqlen += 1 + vb->olenlen + vb->olen; + snmp_asn1_enc_length_cnt(vb->seqlen, &vb->seqlenlen); + + /* varbind seq */ + tot_len += 1 + vb->seqlenlen + vb->seqlen; + + vb = vb->prev; + } + + /* varbind-list seq */ + root->seqlen = tot_len; + snmp_asn1_enc_length_cnt(root->seqlen, &root->seqlenlen); + tot_len += 1 + root->seqlenlen; + + return tot_len; +} + +/** + * Encodes response header from head to tail. + */ +static u16_t +snmp_resp_header_enc(struct snmp_msg_pstat *m_stat, struct pbuf *p) +{ + u16_t ofs; + + ofs = 0; + snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)); + ofs += 1; + snmp_asn1_enc_length(p, ofs, m_stat->rhl.seqlen); + ofs += m_stat->rhl.seqlenlen; + + snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); + ofs += 1; + snmp_asn1_enc_length(p, ofs, m_stat->rhl.verlen); + ofs += m_stat->rhl.verlenlen; + snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.verlen, snmp_version); + ofs += m_stat->rhl.verlen; + + snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR)); + ofs += 1; + snmp_asn1_enc_length(p, ofs, m_stat->rhl.comlen); + ofs += m_stat->rhl.comlenlen; + snmp_asn1_enc_raw(p, ofs, m_stat->rhl.comlen, m_stat->community); + ofs += m_stat->rhl.comlen; + + snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP)); + ofs += 1; + snmp_asn1_enc_length(p, ofs, m_stat->rhl.pdulen); + ofs += m_stat->rhl.pdulenlen; + + snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); + ofs += 1; + snmp_asn1_enc_length(p, ofs, m_stat->rhl.ridlen); + ofs += m_stat->rhl.ridlenlen; + snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.ridlen, m_stat->rid); + ofs += m_stat->rhl.ridlen; + + snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); + ofs += 1; + snmp_asn1_enc_length(p, ofs, m_stat->rhl.errstatlen); + ofs += m_stat->rhl.errstatlenlen; + snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.errstatlen, m_stat->error_status); + ofs += m_stat->rhl.errstatlen; + + snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); + ofs += 1; + snmp_asn1_enc_length(p, ofs, m_stat->rhl.erridxlen); + ofs += m_stat->rhl.erridxlenlen; + snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.erridxlen, m_stat->error_index); + ofs += m_stat->rhl.erridxlen; + + return ofs; +} + +/** + * Encodes trap header from head to tail. + */ +static u16_t +snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p) +{ + u16_t ofs; + + ofs = 0; + snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)); + ofs += 1; + snmp_asn1_enc_length(p, ofs, m_trap->thl.seqlen); + ofs += m_trap->thl.seqlenlen; + + snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); + ofs += 1; + snmp_asn1_enc_length(p, ofs, m_trap->thl.verlen); + ofs += m_trap->thl.verlenlen; + snmp_asn1_enc_s32t(p, ofs, m_trap->thl.verlen, snmp_version); + ofs += m_trap->thl.verlen; + + snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR)); + ofs += 1; + snmp_asn1_enc_length(p, ofs, m_trap->thl.comlen); + ofs += m_trap->thl.comlenlen; + snmp_asn1_enc_raw(p, ofs, m_trap->thl.comlen, (u8_t *)&snmp_publiccommunity[0]); + ofs += m_trap->thl.comlen; + + snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP)); + ofs += 1; + snmp_asn1_enc_length(p, ofs, m_trap->thl.pdulen); + ofs += m_trap->thl.pdulenlen; + + snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID)); + ofs += 1; + snmp_asn1_enc_length(p, ofs, m_trap->thl.eidlen); + ofs += m_trap->thl.eidlenlen; + snmp_asn1_enc_oid(p, ofs, m_trap->enterprise->len, &m_trap->enterprise->id[0]); + ofs += m_trap->thl.eidlen; + + snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR)); + ofs += 1; + snmp_asn1_enc_length(p, ofs, m_trap->thl.aaddrlen); + ofs += m_trap->thl.aaddrlenlen; + snmp_asn1_enc_raw(p, ofs, m_trap->thl.aaddrlen, &m_trap->sip_raw[0]); + ofs += m_trap->thl.aaddrlen; + + snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); + ofs += 1; + snmp_asn1_enc_length(p, ofs, m_trap->thl.gtrplen); + ofs += m_trap->thl.gtrplenlen; + snmp_asn1_enc_u32t(p, ofs, m_trap->thl.gtrplen, m_trap->gen_trap); + ofs += m_trap->thl.gtrplen; + + snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); + ofs += 1; + snmp_asn1_enc_length(p, ofs, m_trap->thl.strplen); + ofs += m_trap->thl.strplenlen; + snmp_asn1_enc_u32t(p, ofs, m_trap->thl.strplen, m_trap->spc_trap); + ofs += m_trap->thl.strplen; + + snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS)); + ofs += 1; + snmp_asn1_enc_length(p, ofs, m_trap->thl.tslen); + ofs += m_trap->thl.tslenlen; + snmp_asn1_enc_u32t(p, ofs, m_trap->thl.tslen, m_trap->ts); + ofs += m_trap->thl.tslen; + + return ofs; +} + +/** + * Encodes varbind list from head to tail. + */ +static u16_t +snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs) +{ + struct snmp_varbind *vb; + s32_t *sint_ptr; + u32_t *uint_ptr; + u8_t *raw_ptr; + + snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)); + ofs += 1; + snmp_asn1_enc_length(p, ofs, root->seqlen); + ofs += root->seqlenlen; + + vb = root->head; + while ( vb != NULL ) + { + snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)); + ofs += 1; + snmp_asn1_enc_length(p, ofs, vb->seqlen); + ofs += vb->seqlenlen; + + snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID)); + ofs += 1; + snmp_asn1_enc_length(p, ofs, vb->olen); + ofs += vb->olenlen; + snmp_asn1_enc_oid(p, ofs, vb->ident_len, &vb->ident[0]); + ofs += vb->olen; + + snmp_asn1_enc_type(p, ofs, vb->value_type); + ofs += 1; + snmp_asn1_enc_length(p, ofs, vb->vlen); + ofs += vb->vlenlen; + + switch (vb->value_type) + { + case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG): + sint_ptr = (s32_t*)vb->value; + snmp_asn1_enc_s32t(p, ofs, vb->vlen, *sint_ptr); + break; + case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER): + case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE): + case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS): + uint_ptr = (u32_t*)vb->value; + snmp_asn1_enc_u32t(p, ofs, vb->vlen, *uint_ptr); + break; + case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR): + case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR): + case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE): + raw_ptr = (u8_t*)vb->value; + snmp_asn1_enc_raw(p, ofs, vb->vlen, raw_ptr); + break; + case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL): + break; + case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID): + sint_ptr = (s32_t*)vb->value; + snmp_asn1_enc_oid(p, ofs, vb->value_len / sizeof(s32_t), sint_ptr); + break; + default: + /* unsupported type */ + break; + }; + ofs += vb->vlen; + vb = vb->next; + } + return ofs; +} + +#endif /* LWIP_SNMP */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/stats.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/stats.c new file mode 100644 index 0000000..cc47084 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/stats.c @@ -0,0 +1,186 @@ +/** + * @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 + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +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, 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 +void +stats_display_igmp(struct stats_igmp *igmp, const char *name) +{ + LWIP_PLATFORM_DIAG(("\n%s\n\t", name)); + LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", igmp->xmit)); + LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", igmp->recv)); + LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", igmp->drop)); + LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", igmp->chkerr)); + LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", igmp->lenerr)); + LWIP_PLATFORM_DIAG(("memerr: %"STAT_COUNTER_F"\n\t", igmp->memerr)); + LWIP_PLATFORM_DIAG(("proterr: %"STAT_COUNTER_F"\n\t", igmp->proterr)); + LWIP_PLATFORM_DIAG(("rx_v1: %"STAT_COUNTER_F"\n\t", igmp->rx_v1)); + LWIP_PLATFORM_DIAG(("rx_group: %"STAT_COUNTER_F"\n\t", igmp->rx_group)); + LWIP_PLATFORM_DIAG(("rx_general: %"STAT_COUNTER_F"\n\t", igmp->rx_general)); + LWIP_PLATFORM_DIAG(("rx_report: %"STAT_COUNTER_F"\n\t", igmp->rx_report)); + LWIP_PLATFORM_DIAG(("tx_join: %"STAT_COUNTER_F"\n\t", igmp->tx_join)); + LWIP_PLATFORM_DIAG(("tx_leave: %"STAT_COUNTER_F"\n\t", igmp->tx_leave)); + LWIP_PLATFORM_DIAG(("tx_report: %"STAT_COUNTER_F"\n\t", igmp->tx_report)); +} +#endif /* IGMP_STATS */ + +#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) +{ + 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(); + 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/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/sys.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/sys.c new file mode 100644 index 0000000..f177737 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/sys.c @@ -0,0 +1,68 @@ +/** + * @file + * lwIP Operating System abstraction + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#include "lwip/sys.h" + +/* Most of the functions defined in sys.h must be implemented in the + * architecture-dependent file sys_arch.c */ + +#if !NO_SYS + +#ifndef sys_msleep +/** + * Sleep for some ms. Timeouts are NOT processed while sleeping. + * + * @param ms number of milliseconds to sleep + */ +void +sys_msleep(u32_t ms) +{ + if (ms > 0) { + sys_sem_t delaysem; + err_t err = sys_sem_new(&delaysem, 0); + if (err == ERR_OK) { + sys_arch_sem_wait(&delaysem, ms); + sys_sem_free(&delaysem); + } + } +} +#endif /* sys_msleep */ + +#endif /* !NO_SYS */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/tcp.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/tcp.c new file mode 100644 index 0000000..2896742 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/tcp.c @@ -0,0 +1,1945 @@ +/** + * @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 "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/nd6.h" + +#include + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#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) (((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 */ + +#ifdef LWIP_DEBUG +const char tcp_state_str_rodata[][12] ICACHE_RODATA_ATTR STORE_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 + +/* last local TCP port */ +#ifdef LWIP_ESP8266 +static s16_t tcp_port = TCP_LOCAL_PORT_RANGE_START; +#else +static u16_t tcp_port = TCP_LOCAL_PORT_RANGE_START; +#endif + +/* Incremented every coarse grained timer shot (typically every 500 ms). */ +u32_t tcp_ticks; +const u8_t tcp_backoff[13] ICACHE_RODATA_ATTR STORE_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 STORE_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 STORE_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; + +u8_t tcp_active_pcbs_changed; + +/** Timer counter to handle calling slow-timer from tcp_tmr() */ +static u8_t tcp_timer; +static u8_t tcp_timer_ctr; +static u16_t tcp_new_port(void); + +/** + * Initialize this module. + */ +void +tcp_init(void) +{ +#if LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) + tcp_port = TCP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND()); +#endif /* LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) */ +} + +/** + * Called periodically to dispatch TCP timers. + */ +void +tcp_tmr(void) +{ + /* Call tcp_fasttmr() every 250 ms */ + tcp_fasttmr(); + + if (++tcp_timer & 1) { + /* Call tcp_tmr() every 500 ms, i.e., every other timer + tcp_tmr() is called. */ + tcp_slowtmr(); + } +} + +static char LwipForceClose = 0; +//Open this func to customer +/** + * set if lwip_close will use 4-handshake to close a tcp connection, + * + * @param req 1 , send rst pkt directly, when call lwip_close(),rather than 4-handshake. + * then all buffed PCB memory resource will be freed immediately + * 0, send Fin flag pkt other than rst pkt + * @return + */ +void lwip_force_close_set(char req) +{ + if(req == 0) + LwipForceClose = 0; + else + LwipForceClose = 1; +} + + +/** + * Closes the TX side of a connection held by the PCB. + * For tcp_close(), a RST is sent if the application didn't receive all data + * (tcp_recved() not called for all data passed to recv callback). + * + * Listening pcbs are freed and may not be referenced any more. + * Connection pcbs are freed if not yet connected and may not be referenced + * any more. If a connection is established (at least SYN received or in + * a closing state), the connection is closed, and put in a closing state. + * The pcb is then automatically freed in tcp_slowtmr(). It is therefore + * unsafe to reference it. + * + * @param pcb the tcp_pcb to close + * @return ERR_OK if connection has been closed + * another err_t if closing failed and pcb is not freed + */ +static err_t +tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data) +{ + err_t err; + + if (rst_on_unacked_data && ((pcb->state == ESTABLISHED) || (pcb->state == CLOSE_WAIT))) { + if ((pcb->refused_data != NULL) || (pcb->rcv_wnd != TCP_WND)) { + /* 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, PCB_ISIPV6(pcb)); + + 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 */ + memp_free(MEMP_TCP_PCB, pcb); + } + return ERR_OK; + } + } + + switch (pcb->state) { + case CLOSED: + /* Closing a pcb in the CLOSED state might seem erroneous, + * however, it is in this state once allocated and as yet unused + * and the user needs some way to free it should the need arise. + * Calling tcp_close() with a pcb that has already been closed, (i.e. twice) + * or for a pcb that has been used and then entered the CLOSED state + * is erroneous, but this should never happen as the pcb has in those cases + * been freed, and so any remaining handles are bogus. */ + err = ERR_OK; + if (pcb->local_port != 0) { + TCP_RMV(&tcp_bound_pcbs, pcb); + } + memp_free(MEMP_TCP_PCB, pcb); + pcb = NULL; + break; + case LISTEN: + err = ERR_OK; + tcp_pcb_remove(&tcp_listen_pcbs.pcbs, pcb); + memp_free(MEMP_TCP_PCB_LISTEN, pcb); + pcb = NULL; + break; + case SYN_SENT: + err = ERR_OK; + TCP_PCB_REMOVE_ACTIVE(pcb); + memp_free(MEMP_TCP_PCB, pcb); + pcb = NULL; + snmp_inc_tcpattemptfails(); + break; + case SYN_RCVD: + err = tcp_send_fin(pcb); + if (err == ERR_OK) { + snmp_inc_tcpattemptfails(); + pcb->state = 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; + } + 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); + } + 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 + */ +err_t +tcp_close(struct tcp_pcb *pcb) +{ +#if TCP_DEBUG + 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 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, 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 = reset && (pcb->state != CLOSED); + seqno = pcb->snd_nxt; + ackno = pcb->rcv_nxt; +#if LWIP_CALLBACK_API + errf = pcb->errf; +#endif /* LWIP_CALLBACK_API */ + errf_arg = pcb->callback_arg; + 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 */ + if (send_rst) { + LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n")); + tcp_rst(seqno, ackno, &pcb->local_ip, &pcb->remote_ip, pcb->local_port, pcb->remote_port, PCB_ISIPV6(pcb)); + } + memp_free(MEMP_TCP_PCB, pcb); + TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT); + } +} + +/** + * 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_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, 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_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; + } + } + + /* 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_PCB_IPVER_EQ(pcb, cpcb) && + (ipX_addr_isany(PCB_ISIPV6(pcb), &cpcb->local_ip) || + ipX_addr_isany(PCB_ISIPV6(pcb), ip_2_ipX(ipaddr)) || + ipX_addr_cmp(PCB_ISIPV6(pcb), &cpcb->local_ip, ip_2_ipX(ipaddr)))) { + return ERR_USE; + } + } + } + } + } + + if (!ipX_addr_isany(PCB_ISIPV6(pcb), ip_2_ipX(ipaddr))) { + ipX_addr_set(PCB_ISIPV6(pcb), &pcb->local_ip, ip_2_ipX(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. + * + * @param pcb the original tcp_pcb + * @param backlog the incoming connections queue limit + * @return tcp_pcb used for listening, consumes less memory. + * + * @note The original tcp_pcb is freed. This function therefore has to be + * called like this: + * tpcb = tcp_listen(tpcb); + */ +struct tcp_pcb * +tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) +{ + struct tcp_pcb_listen *lpcb; + + LWIP_UNUSED_ARG(backlog); + LWIP_ERROR("tcp_listen: pcb already connected", pcb->state == CLOSED, return NULL); + + /* already listening? */ + if (pcb->state == LISTEN) { + return pcb; + } +#if SO_REUSE + if (ip_get_option(pcb, SOF_REUSEADDR)) { + /* Since SOF_REUSEADDR allows reusing a local address before the pcb's usage + is declared (listen-/connection-pcb), we have to make sure now that + this port is only used once for every local IP. */ + for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { + if ((lpcb->local_port == pcb->local_port) && + IP_PCB_IPVER_EQ(pcb, lpcb)) { + if (ipX_addr_cmp(PCB_ISIPV6(pcb), &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; + ip_set_option(lpcb, SOF_ACCEPTCONN); + lpcb->ttl = pcb->ttl; + lpcb->tos = pcb->tos; +#if LWIP_IPV6 + PCB_ISIPV6(lpcb) = PCB_ISIPV6(pcb); + lpcb->accept_any_ip_version = 0; +#endif /* LWIP_IPV6 */ + ipX_addr_copy(PCB_ISIPV6(pcb), 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); + return (struct tcp_pcb *)lpcb; +} + +#if LWIP_IPV6 +/** + * Same as tcp_listen_with_backlog, but allows to accept IPv4 and IPv6 + * connections, if the pcb's local address is set to ANY. + */ +struct tcp_pcb * +tcp_listen_dual_with_backlog(struct tcp_pcb *pcb, u8_t backlog) +{ + struct tcp_pcb *lpcb; + + lpcb = tcp_listen_with_backlog(pcb, backlog); + if ((lpcb != NULL) && + ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip)) { + /* The default behavior is to accept connections on either + * IPv4 or IPv6, if not bound. */ + /* @see NETCONN_FLAG_IPV6_V6ONLY for changing this behavior */ + ((struct tcp_pcb_listen*)lpcb)->accept_any_ip_version = 1; + } + return lpcb; +} +#endif /* LWIP_IPV6 */ + +/** + * 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; + + /* pcb->state LISTEN not allowed here */ + LWIP_ASSERT("don't call tcp_recved for listen-pcbs", + pcb->state != LISTEN); + 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: received %"U16_F" bytes, wnd %"U16_F" (%"U16_F").\n", + len, pcb->rcv_wnd, TCP_WND - 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: +#ifdef LWIP_ESP8266 + tcp_port = system_get_time(); + if (tcp_port < 0) + tcp_port = os_random() - tcp_port; + tcp_port %= TCP_LOCAL_PORT_RANGE_START; +#else + if (tcp_port++ == TCP_LOCAL_PORT_RANGE_END) { + tcp_port = TCP_LOCAL_PORT_RANGE_START; + } +#endif + /* 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; +} + +/** + * 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 (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 connect from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN); + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port)); + if (ipaddr != NULL) { + ipX_addr_set(PCB_ISIPV6(pcb), &pcb->remote_ip, ip_2_ipX(ipaddr)); + } else { + return ERR_VAL; + } + pcb->remote_port = port; + + /* check if we have a route to the remote host */ + if (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip)) { + /* no local IP address set, yet. */ + struct netif *netif; + ipX_addr_t *local_ip; + ipX_route_get_local_ipX(PCB_ISIPV6(pcb), &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. */ + ipX_addr_copy(PCB_ISIPV6(pcb), 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; + } + } +#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_PCB_IPVER_EQ(cpcb, pcb) && + ipX_addr_cmp(PCB_ISIPV6(pcb), &cpcb->local_ip, &pcb->local_ip) && + ipX_addr_cmp(PCB_ISIPV6(pcb), &cpcb->remote_ip, ip_2_ipX(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, &pcb->local_ip, &pcb->remote_ip, PCB_ISIPV6(pcb)); +#endif /* TCP_CALCULATE_EFF_SEND_MSS */ + pcb->cwnd = 1; + pcb->ssthresh = pcb->mss * 10; +#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); + 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; + ++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. */ + 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); + } + + /* 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 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 ")); + ipX_addr_debug_print(PCB_ISIPV6(pcb), 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) + { + 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_err_fn err_fn; + void *err_arg; + tcp_pcb_purge(pcb); + /* Remove PCB from tcp_active_pcbs list. */ + if (prev != NULL) { + LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs); + prev->next = pcb->next; + } else { + /* This PCB was the first. */ + LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb); + tcp_active_pcbs = pcb->next; + } + + if (pcb_reset) { + tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, + pcb->local_port, pcb->remote_port, PCB_ISIPV6(pcb)); + } + + err_fn = pcb->errf; + err_arg = pcb->callback_arg; + pcb2 = pcb; + pcb = pcb->next; + memp_free(MEMP_TCP_PCB, pcb2); + + tcp_active_pcbs_changed = 0; + TCP_EVENT_ERR(err_fn, err_arg, ERR_ABRT); + if (tcp_active_pcbs_changed) { + goto tcp_slowtmr_start; + } + } else { + /* get the 'next' element now and work with 'prev' below (in case of abort) */ + prev = pcb; + pcb = pcb->next; + + /* We check if we should poll the connection. */ + ++prev->polltmr; + if (prev->polltmr >= prev->pollinterval) { + prev->polltmr = 0; + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n")); + tcp_active_pcbs_changed = 0; + TCP_EVENT_POLL(prev, err); + if (tcp_active_pcbs_changed) { + goto tcp_slowtmr_start; + } + /* if err == ERR_ABRT, 'prev' is already deallocated */ + if (err == ERR_OK) { + tcp_output(prev); + } + } + } + } + + + /* Steps through all of the TIME-WAIT PCBs. */ + prev = NULL; + pcb = tcp_tw_pcbs; + while (pcb != NULL) { + LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); + pcb_remove = 0; + + /* Check if this PCB has stayed long enough in TIME-WAIT */ + if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) { + ++pcb_remove; + } + + + + /* If the PCB should be removed, do it. */ + if (pcb_remove) { + struct tcp_pcb *pcb2; + tcp_pcb_purge(pcb); + /* Remove PCB from tcp_tw_pcbs list. */ + if (prev != NULL) { + LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs); + prev->next = pcb->next; + } else { + /* This PCB was the first. */ + LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb); + tcp_tw_pcbs = pcb->next; + } + pcb2 = pcb; + pcb = pcb->next; + memp_free(MEMP_TCP_PCB, pcb2); + } else { + prev = pcb; + pcb = pcb->next; + } + } +} + +/** + * Is called every TCP_FAST_INTERVAL (250 ms) and process data previously + * "refused" by upper layer (application) and sends delayed ACKs. + * + * Automatically called from tcp_tmr(). + */ +void +tcp_fasttmr(void) +{ + struct tcp_pcb *pcb; + + ++tcp_timer_ctr; + +tcp_fasttmr_start: + pcb = tcp_active_pcbs; + + while(pcb != NULL) { + if (pcb->last_timer != tcp_timer_ctr) { + struct tcp_pcb *next; + pcb->last_timer = tcp_timer_ctr; + /* send delayed ACKs */ + if (pcb->flags & TF_ACK_DELAY) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n")); + tcp_ack_now(pcb); + tcp_output(pcb); + pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); + } + + next = pcb->next; + + /* If there is data which was previously "refused" by upper layer */ + if (pcb->refused_data != NULL) { + tcp_active_pcbs_changed = 0; + tcp_process_refused_data(pcb); + if (tcp_active_pcbs_changed) { + /* application callback has changed the pcb list: restart the loop */ + goto tcp_fasttmr_start; + } + } + pcb = next; + } + } +} + +/** Pass pcb->refused_data to the recv callback */ +err_t +tcp_process_refused_data(struct tcp_pcb *pcb) +{ + 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; + 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, refused_data, ERR_OK, err); + if (err == ERR_OK) { + /* did refused_data include a FIN? */ + if (refused_flags & PBUF_FLAG_TCP_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) { + 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) */ + pcb->refused_data = refused_data; + } + 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 = 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 +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); + } +} + +#ifdef LWIP_ESP8266 +/** + * Kills the oldest connection that is in FIN_WAIT_2 state. + * Called from tcp_alloc() if no more connections are available. + */ +static void tcp_kill_finwait2(void) +{ + struct tcp_pcb *pcb, *inactive; + u32_t inactivity; + /* 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; + } + } + } + if (inactive != NULL) { + tcp_pcb_remove(&tcp_active_pcbs, inactive); + memp_free(MEMP_TCP_PCB, inactive); + } +} + +/** + * Kills the oldest connection that is in LAST_ACK state. + * Called from tcp_alloc() if no more connections are available. + */ +static void tcp_kill_lastack(void) +{ + struct tcp_pcb *pcb, *inactive; + u32_t inactivity; + /* 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; + } + } + } + if (inactive != NULL) { + tcp_pcb_remove(&tcp_active_pcbs, inactive); + memp_free(MEMP_TCP_PCB, inactive); + } +} +#endif +/** + * Allocate a new tcp_pcb structure. + * + * @param prio priority for the new pcb + * @return a new tcp_pcb that initially is in state CLOSED + */ +struct tcp_pcb * +tcp_alloc(u8_t prio) +{ + struct tcp_pcb *pcb; + u32_t iss; + +#ifdef LWIP_ESP8266 + /*Kills the oldest connection that is in TIME_WAIT state.*/ + uint8 time_wait_num = 0; + for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { + time_wait_num ++; + } + + if (time_wait_num >= MEMP_NUM_TCP_PCB) + tcp_kill_timewait(); + + /*Kills the oldest connection that is in FIN_WAIT_2 state.*/ + time_wait_num = 0; + for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next){ + //if (pcb->state == FIN_WAIT_2) + if (pcb->state == FIN_WAIT_2 || pcb->state == FIN_WAIT_1) + time_wait_num ++; + } + + if (time_wait_num >= MEMP_NUM_TCP_PCB) + tcp_kill_finwait2(); + + /*Kills the oldest connection that is in LAST_ACK state.*/ + time_wait_num = 0; + for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next){ + if (pcb->state == LAST_ACK) + time_wait_num ++; + } + + if (time_wait_num >= MEMP_NUM_TCP_PCB) + tcp_kill_lastack(); +#endif + + 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 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) { + memset(pcb, 0, sizeof(struct tcp_pcb)); + pcb->prio = prio; + pcb->snd_buf = TCP_SND_BUF; + pcb->snd_queuelen = 0; + pcb->rcv_wnd = TCP_WND; + pcb->rcv_ann_wnd = TCP_WND; + pcb->tos = 0; + 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 = (TCP_MSS > 536) ? 536 : TCP_MSS; + pcb->rto = 3000 / TCP_SLOW_INTERVAL; + pcb->sa = 0; + pcb->sv = 3000 / TCP_SLOW_INTERVAL; + pcb->rtime = -1; + pcb->cwnd = 1; + iss = tcp_next_iss(); + pcb->snd_wl2 = iss; + pcb->snd_nxt = iss; + pcb->lastack = iss; + pcb->snd_lbb = iss; + pcb->tmr = tcp_ticks; + pcb->last_timer = tcp_timer_ctr; + + 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); +} + +#if LWIP_IPV6 +/** + * Creates a new TCP-over-IPv6 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(). + * + * @return a new tcp_pcb that initially is in state CLOSED + */ +struct tcp_pcb * +tcp_new_ip6(void) +{ + struct tcp_pcb * pcb; + pcb = tcp_alloc(TCP_PRIO_NORMAL); + ip_set_v6(pcb, 1); + return pcb; +} +#endif /* LWIP_IPV6 */ + +/** + * 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. */ + pcb->callback_arg = arg; +} +#if LWIP_CALLBACK_API + +/** + * 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) +{ + LWIP_ASSERT("invalid socket state for recv callback", pcb->state != LISTEN); + pcb->recv = recv; +} + +/** + * 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) +{ + LWIP_ASSERT("invalid socket state for sent callback", pcb->state != LISTEN); + pcb->sent = sent; +} + +/** + * Used to specify the function that should be called when a fatal error + * has occured on the connection. + * + * @param pcb tcp_pcb to set the err callback + * @param err callback function to call for this pcb when a fatal error + * has occured on the connection + */ +void +tcp_err(struct tcp_pcb *pcb, tcp_err_fn err) +{ + LWIP_ASSERT("invalid socket state for err callback", pcb->state != LISTEN); + pcb->errf = err; +} + +/** + * 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) +{ + /* This function is allowed to be called for both listen pcbs and + connection pcbs. */ + 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. + * + */ +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")); + +#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_PCB_IPVER_EQ(pcb, lpcb) && + (ipX_addr_isany(PCB_ISIPV6(lpcb), &lpcb->local_ip) || + ipX_addr_cmp(PCB_ISIPV6(lpcb), &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; + + iss += tcp_ticks; /* XXX */ + 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_impl(u16_t sendmss, ipX_addr_t *dest +#if LWIP_IPV6 + , ipX_addr_t *src, u8_t isipv6 +#endif /* LWIP_IPV6 */ + ) +{ + u16_t mss_s; + struct netif *outif; + s16_t mtu; + + outif = ipX_route(isipv6, src, dest); +#if LWIP_IPV6 + if (isipv6) { + /* First look in destination cache, to see if there is a Path MTU. */ + mtu = nd6_get_destination_mtu(ipX_2_ip6(dest), outif); + } else +#endif /* LWIP_IPV6 */ + { + if (outif == NULL) { + return sendmss; + } + mtu = outif->mtu; + } + + if (mtu != 0) { + mss_s = mtu - IP_HLEN - TCP_HLEN; +#if LWIP_IPV6 + /* for IPv6, substract the difference in header size */ + mss_s -= (IP6_HLEN - IP_HLEN); +#endif /* LWIP_IPV6 */ + /* 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/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/tcp_in.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/tcp_in.c new file mode 100644 index 0000000..32e3e9b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/tcp_in.c @@ -0,0 +1,1669 @@ +/** + * @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" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/inet_chksum.h" +#if LWIP_ND6_TCP_REACHABILITY_HINTS +#include "lwip/nd6.h" +#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_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; +static struct tcp_hdr *tcphdr; +static u32_t seqno, ackno; +static u8_t flags; +static u16_t tcplen; + +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 err_t tcp_listen_input(struct tcp_pcb_listen *pcb); +static err_t 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; + err_t err; +#if CHECKSUM_CHECK_TCP + u16_t chksum; +#endif /* CHECKSUM_CHECK_TCP */ + + PERF_START; + + TCP_STATS_INC(tcp.recv); + snmp_inc_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 < 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); + goto dropped; + } + + /* Don't even process incoming broadcasts/multicasts. */ + if ((!ip_current_is_v6() && ip_addr_isbroadcast(ip_current_dest_addr(), inp)) || + ipX_addr_ismulticast(ip_current_is_v6(), ipX_current_dest_addr())) { + TCP_STATS_INC(tcp.proterr); + goto dropped; + } + +#if CHECKSUM_CHECK_TCP + /* Verify TCP checksum. */ + chksum = ipX_chksum_pseudo(ip_current_is_v6(), p, IP_PROTO_TCP, p->tot_len, + ipX_current_src_addr(), ipX_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 */ + + /* Move the payload pointer in the pbuf so that it points to the + TCP data instead of the TCP header. */ + hdrlen = TCPH_HDRLEN(tcphdr); + if(pbuf_header(p, -(hdrlen * 4))){ + /* drop short packets */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet\n")); + TCP_STATS_INC(tcp.lenerr); + goto dropped; + } + + /* Convert fields in TCP header to host byte order. */ + tcphdr->src = ntohs(tcphdr->src); + tcphdr->dest = ntohs(tcphdr->dest); + seqno = tcphdr->seqno = ntohl(tcphdr->seqno); + ackno = tcphdr->ackno = ntohl(tcphdr->ackno); + tcphdr->wnd = ntohs(tcphdr->wnd); + + flags = TCPH_FLAGS(tcphdr); + tcplen = p->tot_len + ((flags & (TCP_FIN | TCP_SYN)) ? 1 : 0); + + /* Demultiplex an incoming segment. First, we check if it is destined + for an active connection. */ + prev = NULL; + + + for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED); + LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); + LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN); + if (pcb->remote_port == tcphdr->src && + pcb->local_port == tcphdr->dest && + IP_PCB_IPVER_INPUT_MATCH(pcb) && + ipX_addr_cmp(ip_current_is_v6(), &pcb->remote_ip, ipX_current_src_addr()) && + ipX_addr_cmp(ip_current_is_v6(),&pcb->local_ip, ipX_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; + } + 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_PCB_IPVER_INPUT_MATCH(pcb) && + ipX_addr_cmp(ip_current_is_v6(), &pcb->remote_ip, ipX_current_src_addr()) && + ipX_addr_cmp(ip_current_is_v6(),&pcb->local_ip, ipX_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 LWIP_IPV6 + if (lpcb->accept_any_ip_version) { + /* found an ANY-match */ +#if SO_REUSE + lpcb_any = lpcb; + lpcb_prev = prev; +#else /* SO_REUSE */ + break; +#endif /* SO_REUSE */ + } else +#endif /* LWIP_IPV6 */ + if (IP_PCB_IPVER_INPUT_MATCH(lpcb)) { + if (ipX_addr_cmp(ip_current_is_v6(), &lpcb->local_ip, ipX_current_dest_addr())) { + /* found an exact match */ + break; + } else if (ipX_addr_isany(ip_current_is_v6(), &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; + } + + 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) { +//DYC add here +#if TCP_QUEUE_OOSEQ + extern char RxNodeNum(void); +//os_printf("rxnod_num:%u\n",RxNodeNum()); +//os_printf("ooseq_en\n"); + if(RxNodeNum() <= 2) + { +extern void pbuf_free_ooseq(void); +//os_printf("free_ooseq\n"); + pbuf_free_ooseq(); +//os_printf("rxnod_num2:%u\n",RxNodeNum()); + } +#endif /* TCP_QUEUE_OOSEQ */ + /* 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 (flags & TCP_PSH) { + p->flags |= PBUF_FLAG_PUSH; + } + + /* If there is data which was previously "refused" by upper layer */ + if (pcb->refused_data != NULL) { + if ((tcp_process_refused_data(pcb) == ERR_ABRT) || + ((pcb->refused_data != NULL) && (tcplen > 0))) { + /* pcb has been aborted or refused data is still refused and the new + segment contains data */ + TCP_STATS_INC(tcp.drop); + snmp_inc_tcpinerrs(); + goto aborted; + } + } + tcp_input_pcb = pcb; + err = tcp_process(pcb); + /* A return value of ERR_ABRT means that tcp_abort() was called + and that the pcb has been freed. If so, we don't do anything. */ + if (err != ERR_ABRT) { + if (recv_flags & TF_RESET) { + /* TF_RESET means that the connection was reset by the other + end. We then call the error callback to inform the + application that the connection is dead before we + deallocate the PCB. */ + TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_RST); + tcp_pcb_remove(&tcp_active_pcbs, pcb); + memp_free(MEMP_TCP_PCB, pcb); + } else 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); + 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; + } + + /* 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) { + 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) { + 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, ipX_current_dest_addr(), + ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6()); + } + pbuf_free(p); + } + + LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane()); + PERF_STOP("tcp_input"); + return; +dropped: + TCP_STATS_INC(tcp.drop); + snmp_inc_tcpinerrs(); + pbuf_free(p); +} + +/** + * Called by tcp_input() when a segment arrives for a listening + * connection (from tcp_input()). + * + * @param pcb the tcp_pcb_listen for which a segment arrived + * @return ERR_OK if the segment was processed + * another err_t on error + * + * @note the return value is not (yet?) used in tcp_input() + * @note the segment which arrived is saved in global variables, therefore only the pcb + * involved is passed as a parameter to this function + */ +static err_t +tcp_listen_input(struct tcp_pcb_listen *pcb) +{ + struct tcp_pcb *npcb; + err_t rc; + + if (flags & TCP_RST) { + /* An incoming RST should be ignored. Return. */ + return ERR_OK; + } + + /* 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, ipX_current_dest_addr(), + ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6()); + } 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 ERR_ABRT; + } +#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) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n")); + TCP_STATS_INC(tcp.memerr); + return ERR_MEM; + } +#if TCP_LISTEN_BACKLOG + pcb->accepts_pending++; +#endif /* TCP_LISTEN_BACKLOG */ + /* Set up the new PCB. */ +#if LWIP_IPV6 + PCB_ISIPV6(npcb) = ip_current_is_v6(); +#endif /* LWIP_IPV6 */ + ipX_addr_copy(ip_current_is_v6(), npcb->local_ip, *ipX_current_dest_addr()); + ipX_addr_copy(ip_current_is_v6(), npcb->remote_ip, *ipX_current_src_addr()); + npcb->local_port = pcb->local_port; + npcb->remote_port = tcphdr->src; + npcb->state = SYN_RCVD; + npcb->rcv_nxt = seqno + 1; + npcb->rcv_ann_right_edge = npcb->rcv_nxt; + npcb->snd_wnd = tcphdr->wnd; + npcb->snd_wnd_max = 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_ACTIVE(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->local_ip, + &npcb->remote_ip, PCB_ISIPV6(npcb)); +#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 + */ +static err_t +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 ERR_OK; + } + /* - 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, ipX_current_dest_addr(), + ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6()); + return ERR_OK; + } + } 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; + 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_wnd_max = 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->local_ip, &pcb->remote_ip, + PCB_ISIPV6(pcb)); +#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; + 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 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, ipX_current_dest_addr(), + ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6()); + } + 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, ipX_current_dest_addr(), + ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6()); + } + } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) { + /* Looks like another copy of the SYN - retransmit our SYN-ACK */ + tcp_rexmit(pcb); + } + break; + case CLOSE_WAIT: + /* FALLTHROUGH */ + case ESTABLISHED: + tcp_receive(pcb); + if (recv_flags & TF_GOT_FIN) { /* passive close */ + tcp_ack_now(pcb); + pcb->state = CLOSE_WAIT; + } + break; + case FIN_WAIT_1: + tcp_receive(pcb); + if (recv_flags & TF_GOT_FIN) { + if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) { + LWIP_DEBUGF(TCP_DEBUG, + ("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); + tcp_ack_now(pcb); + tcp_pcb_purge(pcb); + TCP_RMV_ACTIVE(pcb); + pcb->state = TIME_WAIT; + TCP_REG(&tcp_tw_pcbs, pcb); + } else { + tcp_ack_now(pcb); + pcb->state = CLOSING; + } + } else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) { + pcb->state = FIN_WAIT_2; + } + break; + case FIN_WAIT_2: + tcp_receive(pcb); + if (recv_flags & TF_GOT_FIN) { + LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: FIN_WAIT_2 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); + tcp_ack_now(pcb); + tcp_pcb_purge(pcb); + TCP_RMV_ACTIVE(pcb); + pcb->state = TIME_WAIT; + TCP_REG(&tcp_tw_pcbs, pcb); + } + break; + case CLOSING: + tcp_receive(pcb); + if (flags & TCP_ACK && ackno == pcb->snd_nxt) { + LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); + tcp_pcb_purge(pcb); + TCP_RMV_ACTIVE(pcb); + pcb->state = TIME_WAIT; + TCP_REG(&tcp_tw_pcbs, pcb); + } + break; + case LAST_ACK: + tcp_receive(pcb); + if (flags & TCP_ACK && ackno == pcb->snd_nxt) { + LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: LAST_ACK %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); + /* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */ + recv_flags |= TF_CLOSED; + } + break; + default: + break; + } + return ERR_OK; +} + +#if TCP_QUEUE_OOSEQ +/** + * Insert segment into the list (segments covered with new one will be deleted) + * + * Called from tcp_receive() + */ +static void +tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next) +{ + struct tcp_seg *old_seg; + + if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) { + /* received segment overlaps all following segments */ + tcp_segs_free(next); + next = NULL; + } + else { + /* delete some following segments + oos queue may have segments with FIN flag */ + while (next && + TCP_SEQ_GEQ((seqno + cseg->len), + (next->tcphdr->seqno + next->len))) { + /* cseg with FIN already processed */ + if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) { + TCPH_SET_FLAG(cseg->tcphdr, TCP_FIN); + } + old_seg = next; + next = next->next; + tcp_seg_free(old_seg); + } + if (next && + TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) { + /* We need to trim the incoming segment. */ + cseg->len = (u16_t)(next->tcphdr->seqno - seqno); + pbuf_realloc(cseg->p, cseg->len); + } + } + cseg->next = next; +} +#endif /* TCP_QUEUE_OOSEQ */ + +/** + * Called by tcp_process. Checks if the given segment is an ACK for outstanding + * data, and if so frees the memory of the buffered data. Next, 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 + * it has been removed from the buffer. + * + * If the incoming segment constitutes an ACK for a segment that was used for RTT + * estimation, the RTT is estimated here as well. + * + * Called from tcp_process(). + */ +static void +tcp_receive(struct tcp_pcb *pcb) +{ + struct tcp_seg *next; +#if TCP_QUEUE_OOSEQ + struct tcp_seg *prev, *cseg; +#endif /* TCP_QUEUE_OOSEQ */ + struct pbuf *p; + s32_t off; + s16_t m; + u32_t right_wnd_edge; + u16_t new_tot_len; + int found_dupack = 0; +#if TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS + u32_t ooseq_blen; + u16_t ooseq_qlen; +#endif /* TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS */ + + LWIP_ASSERT("tcp_receive: wrong state", pcb->state >= ESTABLISHED); + + if (flags & TCP_ACK) { + right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2; + + /* Update window. */ + if (TCP_SEQ_LT(pcb->snd_wl1, seqno) || + (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) || + (pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) { + pcb->snd_wnd = tcphdr->wnd; + /* keep track of the biggest window announced by the remote host to calculate + the maximum segment size */ + if (pcb->snd_wnd_max < tcphdr->wnd) { + pcb->snd_wnd_max = tcphdr->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 %"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) + * + * 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)) { + 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 ((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 ((u16_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; + + /* 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. */ + while (pcb->unacked != NULL && + TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) + + TCP_TCPLEN(pcb->unacked), ackno)) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unacked\n", + ntohl(pcb->unacked->tcphdr->seqno), + ntohl(pcb->unacked->tcphdr->seqno) + + TCP_TCPLEN(pcb->unacked))); + + next = pcb->unacked; + pcb->unacked = pcb->unacked->next; + + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"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); + tcp_seg_free(next); + + 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; + +#if LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS + if (PCB_ISIPV6(pcb)) { + /* Inform neighbor reachability of forward progress. */ + nd6_reachability_hint(ip6_current_src_addr()); + } +#endif /* LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS*/ + } 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. */ + while (pcb->unsent != NULL && + TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) + + TCP_TCPLEN(pcb->unsent), pcb->snd_nxt)) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n", + ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) + + TCP_TCPLEN(pcb->unsent))); + + next = pcb->unsent; + pcb->unsent = pcb->unsent->next; +#if TCP_OVERSIZE + if (pcb->unsent == NULL) { + pcb->unsent_oversize = 0; + } +#endif /* TCP_OVERSIZE */ + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"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); + 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)) { + /* 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, 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, 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, chapeter 3.9, "SEGMENT ARRIVES" in states CLOSE-WAIT, CLOSING, + LAST-ACK and TIME-WAIT: "Ignore the segment text.") */ + if ((tcplen > 0) && (pcb->state < CLOSE_WAIT)) { + /* This code basically does three things: + + +) If the incoming segment contains data that is the next + in-sequence data, this data is passed to the application. This + might involve trimming the first edge of the data. The rcv_nxt + variable and the advertised window are adjusted. + + +) If the incoming segment has data that is above the next + sequence number expected (->rcv_nxt), the segment is placed on + the ->ooseq queue. This is done by finding the appropriate + place in the ->ooseq queue (which is ordered by sequence + number) and trim the segment in both ends if needed. An + immediate ACK is sent to indicate that we received an + out-of-sequence segment. + + +) Finally, we check if the first segment on the ->ooseq queue + now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If + rcv_nxt > ooseq->seqno, we must trim the first edge of the + segment on ->ooseq before we adjust rcv_nxt. The data in the + segments that are now on sequence are chained onto the + incoming segment so that we only need to call the application + once. + */ + + /* First, we check if we must trim the first edge. We have to do + this if the sequence number of the incoming segment is less + than rcv_nxt, and the sequence number plus the length of the + segment is larger than rcv_nxt. */ + /* if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){ + if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/ + if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)){ + /* Trimming the first edge is done by pushing the payload + pointer in the pbuf downwards. This is somewhat tricky since + we do not want to discard the full contents of the pbuf up to + the new starting point of the data since we have to keep the + TCP header which is present in the first pbuf in the chain. + + What is done is really quite a nasty hack: the first pbuf in + the pbuf chain is pointed to by inseg.p. Since we need to be + able to deallocate the whole pbuf, we cannot change this + inseg.p pointer to point to any of the later pbufs in the + chain. Instead, we point the ->payload pointer in the first + pbuf to data in one of the later pbufs. We also set the + inseg.data pointer to point to the right place. This way, the + ->p pointer will still point to the first pbuf, but the + ->p->payload pointer will point to data in another pbuf. + + After we are done with adjusting the pbuf pointers we must + adjust the ->data pointer in the seg and the segment + length.*/ + + off = pcb->rcv_nxt - seqno; + p = inseg.p; + LWIP_ASSERT("inseg.p != NULL", inseg.p); + LWIP_ASSERT("insane offset!", (off < 0x7fff)); + if (inseg.p->len < off) { + LWIP_ASSERT("pbuf too short!", (((s32_t)inseg.p->tot_len) >= off)); + new_tot_len = (u16_t)(inseg.p->tot_len - off); + while (p->len < off) { + off -= p->len; + /* KJM following line changed (with addition of new_tot_len var) + to fix bug #9076 + inseg.p->tot_len -= p->len; */ + p->tot_len = new_tot_len; + p->len = 0; + p = p->next; + } + if(pbuf_header(p, (s16_t)-off)) { + /* Do we need to cope with this failing? Assert for now */ + LWIP_ASSERT("pbuf_header failed", 0); + } + } else { + if(pbuf_header(inseg.p, (s16_t)-off)) { + /* Do we need to cope with this failing? Assert for now */ + LWIP_ASSERT("pbuf_header failed", 0); + } + } + inseg.len -= (u16_t)(pcb->rcv_nxt - seqno); + inseg.tcphdr->seqno = seqno = pcb->rcv_nxt; + } + else { + if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){ + /* the whole segment is < rcv_nxt */ + /* must be a duplicate of a packet that has already been correctly handled */ + + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", seqno)); + tcp_ack_now(pcb); + } + } + + /* The sequence number must be within the window (above rcv_nxt + and below rcv_nxt + rcv_wnd) in order to be further + processed. */ + if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, + pcb->rcv_nxt + pcb->rcv_wnd - 1)){ + if (pcb->rcv_nxt == seqno) { + /* The incoming segment is the next in sequence. We check if + we have to trim the end of the segment and update rcv_nxt + and pass the data to the application. */ + tcplen = TCP_TCPLEN(&inseg); + + if (tcplen > pcb->rcv_wnd) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, + ("tcp_receive: other end overran receive window" + "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n", + seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd)); + if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { + /* Must remove the FIN from the header as we're trimming + * that byte of sequence-space from the packet */ + TCPH_FLAGS_SET(inseg.tcphdr, TCPH_FLAGS(inseg.tcphdr) &~ 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); + +#if LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS + if (PCB_ISIPV6(pcb)) { + /* 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 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; + } + } +#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 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/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/tcp_out.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/tcp_out.c new file mode 100644 index 0000000..778976c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/tcp_out.c @@ -0,0 +1,1504 @@ +/** + * @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/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/inet_chksum.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/inet_chksum.h" +#if LWIP_TCP_TIMESTAMPS +#include "lwip/sys.h" +#endif + +#include + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_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 * +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); + 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 | 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 * +tcp_pbuf_prealloc(pbuf_layer layer, u16_t length, u16_t max_length, + u16_t *oversize, struct tcp_pcb *pcb, u8_t apiflags, + u8_t first_seg) +{ + struct pbuf *p; + u16_t alloc = length; + +#if LWIP_NETIF_TX_SINGLE_PBUF + LWIP_UNUSED_ARG(max_length); + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(apiflags); + LWIP_UNUSED_ARG(first_seg); + /* always create MSS-sized pbufs */ + alloc = max_length; +#else /* LWIP_NETIF_TX_SINGLE_PBUF */ + if (length < max_length) { + /* Should we allocate an oversized pbuf, or just the minimum + * length required? If tcp_write is going to be called again + * before this segment is transmitted, we want the oversized + * buffer. If the segment will be transmitted immediately, we can + * save memory by allocating only length. We use a simple + * heuristic based on the following information: + * + * Did the user set TCP_WRITE_FLAG_MORE? + * + * Will the Nagle algorithm defer transmission of this segment? + */ + if ((apiflags & TCP_WRITE_FLAG_MORE) || + (!(pcb->flags & TF_NODELAY) && + (!first_seg || + pcb->unsent != NULL || + pcb->unacked != NULL))) { + alloc = LWIP_MIN(max_length, LWIP_MEM_ALIGN_SIZE(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 +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 | 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 : + * - 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; + /* don't allocate segments bigger than half the maximum window we ever received */ + u16_t mss_local = LWIP_MIN(pcb->mss, pcb->snd_wnd_max/2); + +#if LWIP_NETIF_TX_SINGLE_PBUF + /* Always copy to try to create single pbufs for TX */ + apiflags |= TCP_WRITE_FLAG_COPY; +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + + LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, data=%p, len=%"U16_F", apiflags=%"U16_F")\n", + (void *)pcb, arg, len, (u16_t)apiflags)); + LWIP_ERROR("tcp_write: arg == NULL (programmer violates API)", + arg != NULL, return ERR_ARG;); + + err = tcp_write_checks(pcb, len); + if (err != ERR_OK) { + return err; + } + queuelen = pcb->snd_queuelen; + +#if LWIP_TCP_TIMESTAMPS + if ((pcb->flags & TF_TIMESTAMP)) { + optflags = TF_SEG_OPTS_TS; + optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS); + } +#endif /* LWIP_TCP_TIMESTAMPS */ + + + /* + * TCP segmentation is done in three phases with increasing complexity: + * + * 1. Copy data directly into an oversized pbuf. + * 2. Chain a new pbuf to the end of pcb->unsent. + * 3. Create new segments. + * + * We may run out of memory at any point. In that case we must + * return ERR_MEM and not change anything in pcb. Therefore, all + * changes are recorded in local variables and committed at the end + * of the function. Some pcb fields are maintained in local copies: + * + * queuelen = pcb->snd_queuelen + * oversize = pcb->unsent_oversize + * + * These variables are set consistently by the phases: + * + * seg points to the last segment tampered with. + * + * pos records progress as data is segmented. + */ + + /* Find the tail of the unsent queue. */ + if (pcb->unsent != NULL) { + u16_t space; + u16_t unsent_optlen; + + /* @todo: this could be sped up by keeping last_unsent in the pcb */ + for (last_unsent = pcb->unsent; last_unsent->next != NULL; + last_unsent = last_unsent->next); + + /* Usable space at the end of the last unsent segment */ + unsent_optlen = LWIP_TCP_OPT_LENGTH(last_unsent->flags); + space = mss_local - (last_unsent->len + unsent_optlen); + + /* + * Phase 1: Copy data directly into an oversized pbuf. + * + * The number of bytes copied is recorded in the oversize_used + * variable. The actual copying is done at the bottom of the + * function. + */ +#if TCP_OVERSIZE +#if TCP_OVERSIZE_DBGCHECK + /* check that pcb->unsent_oversize matches last_unsent->unsent_oversize */ + LWIP_ASSERT("unsent_oversize mismatch (pcb vs. last_unsent)", + pcb->unsent_oversize == last_unsent->oversize_left); +#endif /* TCP_OVERSIZE_DBGCHECK */ + oversize = pcb->unsent_oversize; + if (oversize > 0) { + LWIP_ASSERT("inconsistent oversize vs. space", oversize_used <= space); + seg = last_unsent; + oversize_used = oversize < len ? oversize : len; + pos += oversize_used; + oversize -= oversize_used; + space -= oversize_used; + } + /* now we are either finished or oversize is zero */ + LWIP_ASSERT("inconsistend oversize vs. len", (oversize == 0) || (pos == len)); +#endif /* TCP_OVERSIZE */ + + /* + * Phase 2: Chain a new pbuf to the end of pcb->unsent. + * + * We don't extend segments containing SYN/FIN flags or options + * (len==0). The new pbuf is kept in concat_p and pbuf_cat'ed at + * the end. + */ + if ((pos < len) && (space > 0) && (last_unsent->len > 0)) { + u16_t seglen = space < len - pos ? space : len - pos; + seg = last_unsent; + + /* Create a pbuf with a copy or reference to seglen bytes. We + * can use PBUF_RAW here since the data appears in the middle of + * a segment. A header will never be prepended. */ + if (apiflags & TCP_WRITE_FLAG_COPY) { + /* Data is copied */ + if ((concat_p = tcp_pbuf_prealloc(PBUF_RAW, seglen, space, &oversize, pcb, apiflags, 1)) == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, + ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n", + seglen)); + goto memerr; + } +#if TCP_OVERSIZE_DBGCHECK + last_unsent->oversize_left += oversize; +#endif /* TCP_OVERSIZE_DBGCHECK */ + TCP_DATA_COPY2(concat_p->payload, (u8_t*)arg + pos, seglen, &concat_chksum, &concat_chksum_swapped); +#if TCP_CHECKSUM_ON_COPY + concat_chksummed += seglen; +#endif /* TCP_CHECKSUM_ON_COPY */ + } else { + /* Data is not copied */ + if ((concat_p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, + ("tcp_write: could not allocate memory for zero-copy pbuf\n")); + goto memerr; + } +#if TCP_CHECKSUM_ON_COPY + /* calculate the checksum of nocopy-data */ + tcp_seg_add_chksum(~inet_chksum((u8_t*)arg + pos, seglen), seglen, + &concat_chksum, &concat_chksum_swapped); + concat_chksummed += seglen; +#endif /* TCP_CHECKSUM_ON_COPY */ + /* reference the non-volatile payload data */ + concat_p->payload = (u8_t*)arg + pos; + } + + pos += seglen; + queuelen += pbuf_clen(concat_p); + } + } else { +#if TCP_OVERSIZE + LWIP_ASSERT("unsent_oversize mismatch (pcb->unsent is NULL)", + pcb->unsent_oversize == 0); +#endif /* TCP_OVERSIZE */ + } + + /* + * Phase 3: Create new segments. + * + * The new segments are chained together in the local 'queue' + * variable, ready to be appended to pcb->unsent. + */ + while (pos < len) { + struct pbuf *p; + u16_t left = len - pos; + u16_t max_len = mss_local - optlen; + u16_t seglen = left > max_len ? max_len : left; +#if TCP_CHECKSUM_ON_COPY + u16_t chksum = 0; + u8_t chksum_swapped = 0; +#endif /* TCP_CHECKSUM_ON_COPY */ + + if (apiflags & TCP_WRITE_FLAG_COPY) { + /* If copy is set, memory should be allocated and data copied + * into pbuf */ + if ((p = tcp_pbuf_prealloc(PBUF_TRANSPORT, seglen + optlen, mss_local, &oversize, pcb, apiflags, queue == NULL)) == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 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 + LWIP_ASSERT("last_unsent->oversize_left >= oversize_used", + last_unsent->oversize_left >= oversize_used); + last_unsent->oversize_left -= oversize_used; +#endif /* TCP_OVERSIZE_DBGCHECK */ + } + pcb->unsent_oversize = oversize; +#endif /* TCP_OVERSIZE */ + + /* + * Phase 2: concat_p can be concatenated onto last_unsent->p + */ + if (concat_p != NULL) { + LWIP_ASSERT("tcp_write: cannot concatenate when pcb->unsent is empty", + (last_unsent != NULL)); + pbuf_cat(last_unsent->p, concat_p); + last_unsent->len += concat_p->tot_len; +#if TCP_CHECKSUM_ON_COPY + if (concat_chksummed) { + 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 +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; + u8_t optlen = 0; +#if LWIP_TCP_TIMESTAMPS || CHECKSUM_GEN_TCP + struct tcp_hdr *tcphdr; +#endif /* LWIP_TCP_TIMESTAMPS || CHECKSUM_GEN_TCP */ + +#if LWIP_TCP_TIMESTAMPS + if (pcb->flags & TF_TIMESTAMP) { + optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS); + } +#endif + + p = tcp_output_alloc_header(pcb, optlen, 0, htonl(pcb->snd_nxt)); + if (p == NULL) { + 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)); + /* 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 = ipX_chksum_pseudo(PCB_ISIPV6(pcb), p, IP_PROTO_TCP, p->tot_len, + &pcb->local_ip, &pcb->remote_ip); +#endif +#if LWIP_NETIF_HWADDRHINT + ipX_output_hinted(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, + IP_PROTO_TCP, &pcb->addr_hint); +#else /* LWIP_NETIF_HWADDRHINT*/ + ipX_output(PCB_ISIPV6(pcb), 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 +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 */ + + /* pcb->state LISTEN not allowed here */ + LWIP_ASSERT("don't call tcp_output for listen-pcbs", + pcb->state != LISTEN); + + /* First, check if we are invoked by the TCP input processing + code. If so, we do not output anything. Instead, we rely on the + input processing code to call us when input processing is done + with. */ + if (tcp_input_pcb == pcb) { + return ERR_OK; + } + + wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd); + + seg = pcb->unsent; + + /* If the TF_ACK_NOW flag is set and no data will be sent (either + * because the ->unsent queue is empty or because the window does + * not allow it), construct an empty ACK segment and send it. + * + * If data is to be sent, we will just piggyback the ACK (see below). + */ + if (pcb->flags & TF_ACK_NOW && + (seg == NULL || + ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) { + return tcp_send_empty_ack(pcb); + } + + /* useg should point to last segment on unacked queue */ + useg = pcb->unacked; + if (useg != NULL) { + for (; useg->next != NULL; useg = useg->next); + } + +#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); + pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); + } + +#if TCP_OVERSIZE_DBGCHECK + seg->oversize_left = 0; +#endif /* TCP_OVERSIZE_DBGCHECK */ + tcp_output_segment(seg, pcb); + snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg); + if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) { + pcb->snd_nxt = snd_nxt; + } + /* put segment on unacknowledged list if length > 0 */ + if (TCP_TCPLEN(seg) > 0) { + seg->next = NULL; + /* unacked list is empty? */ + if (pcb->unacked == NULL) { + pcb->unacked = seg; + useg = seg; + /* unacked list is not empty? */ + } else { + /* In the case of fast retransmit, the packet should not go to the tail + * of the unacked queue, but rather somewhere before it. We need to check for + * this case. -STJ Jul 27, 2004 */ + if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))) { + /* add segment to before tail of unacked list, keeping the list sorted */ + struct tcp_seg **cur_seg = &(pcb->unacked); + while (*cur_seg && + TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) { + cur_seg = &((*cur_seg)->next ); + } + seg->next = (*cur_seg); + (*cur_seg) = seg; + } else { + /* add segment to tail of unacked list */ + useg->next = seg; + useg = useg->next; + } + } + /* do not queue empty segments on the unacked list */ + } else { + tcp_seg_free(seg); + } + seg = pcb->unsent; + } +#if TCP_OVERSIZE + if (pcb->unsent == NULL) { + /* last unsent has been removed, reset unsent_oversize */ + pcb->unsent_oversize = 0; + } +#endif /* TCP_OVERSIZE */ + + pcb->flags &= ~TF_NAGLEMEMERR; + return ERR_OK; +} + +/** + * Called by tcp_output() to actually send a TCP segment over IP. + * + * @param seg the tcp_seg to send + * @param pcb the tcp_pcb for the TCP connection used to send the segment + */ +static void +tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) +{ + u16_t len; + 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 */ + 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, PCB_ISIPV6(pcb)); +#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 + + /* Set retransmission timer running if it is not currently enabled + This must be set before checking the route. */ + if (pcb->rtime == -1) { + pcb->rtime = 0; + } + + /* If we don't have a local IP address, we get one by + calling ip_route(). */ + if (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip)) { + struct netif *netif; + ipX_addr_t *local_ip; + ipX_route_get_local_ipX(PCB_ISIPV6(pcb), &pcb->local_ip, &pcb->remote_ip, netif, local_ip); + if ((netif == NULL) || (local_ip == NULL)) { + return; + } + ipX_addr_copy(PCB_ISIPV6(pcb), pcb->local_ip, *local_ip); + } + + 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 TCP_CHECKSUM_ON_COPY + { + u32_t acc; +#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK + u16_t chksum_slow = ipX_chksum_pseudo(PCB_ISIPV6(pcb), 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 = ipX_chksum_pseudo_partial(PCB_ISIPV6(pcb), 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) { + 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 */ +#if CHECKSUM_GEN_TCP + seg->tcphdr->chksum = ipX_chksum_pseudo(PCB_ISIPV6(pcb), seg->p, IP_PROTO_TCP, + seg->p->tot_len, &pcb->local_ip, &pcb->remote_ip); +#endif /* CHECKSUM_GEN_TCP */ +#endif /* TCP_CHECKSUM_ON_COPY */ + TCP_STATS_INC(tcp.xmit); + +#if LWIP_NETIF_HWADDRHINT + ipX_output_hinted(PCB_ISIPV6(pcb), seg->p, &pcb->local_ip, &pcb->remote_ip, + pcb->ttl, pcb->tos, IP_PROTO_TCP, &pcb->addr_hint); +#else /* LWIP_NETIF_HWADDRHINT*/ + ipX_output(PCB_ISIPV6(pcb), 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_impl(u32_t seqno, u32_t ackno, + ipX_addr_t *local_ip, ipX_addr_t *remote_ip, + u16_t local_port, u16_t remote_port +#if LWIP_IPV6 + , u8_t isipv6 +#endif /* LWIP_IPV6 */ + ) +{ + 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; + + TCP_STATS_INC(tcp.xmit); + snmp_inc_tcpoutrsts(); + +#if CHECKSUM_GEN_TCP + tcphdr->chksum = ipX_chksum_pseudo(isipv6, 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 */ + ipX_output(isipv6, 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; + + 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; + /* unsent queue is the concatenated queue (of unacked, unsent) */ + pcb->unsent = pcb->unacked; + /* unacked queue is now empty */ + pcb->unacked = NULL; + /* 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; +#if TCP_OVERSIZE + if (seg->next == NULL) { + /* the retransmitted segment is last in unsent, so reset unsent_oversize */ + pcb->unsent_oversize = 0; + } +#endif /* TCP_OVERSIZE */ + + ++pcb->nrtx; + + /* Don't take any rtt measurements after retransmitting. */ + pcb->rttest = 0; + + /* Do the actual retransmission. */ + 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; +#if CHECKSUM_GEN_TCP + struct tcp_hdr *tcphdr; +#endif /* CHECKSUM_GEN_TCP */ + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to ")); + ipX_addr_debug_print(PCB_ISIPV6(pcb), 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, 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; + } +#if CHECKSUM_GEN_TCP + tcphdr = (struct tcp_hdr *)p->payload; + + tcphdr->chksum = ipX_chksum_pseudo(PCB_ISIPV6(pcb), 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 */ +#if LWIP_NETIF_HWADDRHINT + ipX_output_hinted(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, + pcb->ttl, 0, IP_PROTO_TCP, &pcb->addr_hint); +#else /* LWIP_NETIF_HWADDRHINT*/ + ipX_output(PCB_ISIPV6(pcb), 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 len; + u8_t is_fin; + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: sending ZERO WINDOW probe to ")); + ipX_addr_debug_print(PCB_ISIPV6(pcb), 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, pcb->keep_cnt_sent)); + + seg = pcb->unacked; + + if(seg == NULL) { + seg = pcb->unsent; + } + 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 */ + 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); + } + +#if CHECKSUM_GEN_TCP + tcphdr->chksum = ipX_chksum_pseudo(PCB_ISIPV6(pcb), p, IP_PROTO_TCP, p->tot_len, + &pcb->local_ip, &pcb->remote_ip); +#endif + TCP_STATS_INC(tcp.xmit); + + /* Send output to IP */ +#if LWIP_NETIF_HWADDRHINT + ipX_output_hinted(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, + 0, IP_PROTO_TCP, &pcb->addr_hint); +#else /* LWIP_NETIF_HWADDRHINT*/ + ipX_output(PCB_ISIPV6(pcb), 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/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/timers.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/timers.c new file mode 100644 index 0000000..315ebf5 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/timers.c @@ -0,0 +1,561 @@ +/** + * @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" +#include "lwip/nd6.h" +#include "lwip/ip6_frag.h" +#include "lwip/mld6.h" +#include "lwip/sys.h" +#include "lwip/pbuf.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +/** The one and only timeout list */ +static struct sys_timeo *next_timeout; +#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 +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 */ + +#if IP_REASSEMBLY +/** + * Timer callback function that calls ip_reass_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void +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 +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 */ + +#if LWIP_IPV6 +/** + * Timer callback function that calls nd6_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void +nd6_timer(void *arg) +{ + LWIP_UNUSED_ARG(arg); + LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: nd6_tmr()\n")); + nd6_tmr(); + sys_timeout(ND6_TMR_INTERVAL, nd6_timer, NULL); +} + +#if LWIP_IPV6_REASS +/** + * Timer callback function that calls ip6_reass_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void +ip6_reass_timer(void *arg) +{ + LWIP_UNUSED_ARG(arg); + LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: ip6_reass_tmr()\n")); + ip6_reass_tmr(); + sys_timeout(IP6_REASS_TMR_INTERVAL, ip6_reass_timer, NULL); +} +#endif /* LWIP_IPV6_REASS */ + +#if LWIP_IPV6_MLD +/** + * Timer callback function that calls mld6_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void +mld6_timer(void *arg) +{ + LWIP_UNUSED_ARG(arg); + LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: mld6_tmr()\n")); + mld6_tmr(); + sys_timeout(MLD6_TMR_INTERVAL, mld6_timer, NULL); +} +#endif /* LWIP_IPV6_MLD */ +#endif /* LWIP_IPV6 */ + +/** 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_IPV6 + sys_timeout(ND6_TMR_INTERVAL, nd6_timer, NULL); +#if LWIP_IPV6_REASS + sys_timeout(IP6_REASS_TMR_INTERVAL, ip6_reass_timer, NULL); +#endif /* LWIP_IPV6_REASS */ +#if LWIP_IPV6_MLD + sys_timeout(MLD6_TMR_INTERVAL, mld6_timer, NULL); +#endif /* LWIP_IPV6_MLD */ +#endif /* LWIP_IPV6 */ + +#if NO_SYS + /* Initialise timestamp for sys_check_timeouts */ + timeouts_last_time = sys_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 */ + +u32_t LwipTimOutLim = 0; // For light sleep. time out. limit is 3000ms +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; + + +if(msecs < LwipTimOutLim) + msecs = LwipTimOutLim; + + 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 + +/** 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) +{ + 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 + { +#if PBUF_POOL_FREE_OOSEQ + PBUF_CHECK_FREE_OOSEQ(); +#endif /* PBUF_POOL_FREE_OOSEQ */ + had_one = 0; + tmptimeout = next_timeout; + if (tmptimeout && (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 = sys_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/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/udp.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/udp.c new file mode 100644 index 0000000..90ca8d9 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/core/udp.c @@ -0,0 +1,1164 @@ +/** + * @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/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/inet_chksum.h" +#include "lwip/netif.h" +#include "lwip/icmp.h" +#include "lwip/icmp6.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "arch/perf.h" +#include "lwip/dhcp.h" + +#include + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +#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) (((port) & ~UDP_LOCAL_PORT_RANGE_START) + UDP_LOCAL_PORT_RANGE_START) +#endif + +/* last local UDP port */ +static u16_t udp_port = UDP_LOCAL_PORT_RANGE_START; + +/* The list of UDP PCBs */ +/* exported in udp.h (was static) */ +struct udp_pcb *udp_pcbs; + +/** + * Initialize this module. + */ +void +udp_init(void) +{ +#if LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) + udp_port = UDP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND()); +#endif /* LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) */ +} + +/** + * Allocate a new local UDP port. + * + * @return a new (free) local UDP port number + */ +static u16_t +udp_new_port(void) +{ + u16_t n = 0; + struct udp_pcb *pcb; + +again: + if (udp_port++ == UDP_LOCAL_PORT_RANGE_END) { + udp_port = UDP_LOCAL_PORT_RANGE_START; + } + /* Check all PCBs. */ + for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { + if (pcb->local_port == udp_port) { + if (++n > (UDP_LOCAL_PORT_RANGE_END - UDP_LOCAL_PORT_RANGE_START)) { + return 0; + } + goto again; + } + } + return udp_port; +#if 0 + struct udp_pcb *ipcb = udp_pcbs; + while ((ipcb != NULL) && (udp_port != UDP_LOCAL_PORT_RANGE_END)) { + if (ipcb->local_port == udp_port) { + /* port is already used by another udp_pcb */ + udp_port++; + /* restart scanning all udp pcbs */ + ipcb = udp_pcbs; + } else { + /* go on with next udp pcb */ + ipcb = ipcb->next; + } + } + if (ipcb != NULL) { + return 0; + } + return udp_port; +#endif +} + +/** + * 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 local_match; + u8_t broadcast; + u8_t for_us; + + 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); + snmp_inc_udpinerrors(); + pbuf_free(p); + goto end; + } + + udphdr = (struct udp_hdr *)p->payload; + + /* is broadcast packet ? */ +#if LWIP_IPV6 + broadcast = !ip_current_is_v6() && ip_addr_isbroadcast(ip_current_dest_addr(), inp); +#else /* LWIP_IPV6 */ + broadcast = ip_addr_isbroadcast(ip_current_dest_addr(), inp); +#endif /* LWIP_IPV6 */ + + 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 (")); + ipX_addr_debug_print(ip_current_is_v6(), UDP_DEBUG, ipX_current_dest_addr()); + LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", ntohs(udphdr->dest))); + ipX_addr_debug_print(ip_current_is_v6(), UDP_DEBUG, ipX_current_src_addr()); + LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", 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 + (no need to check for IPv6 since the dhcp struct always uses IPv4) */ + if (ipX_addr_isany(0, &inp->dhcp->pcb->remote_ip) || + ip_addr_cmp(ipX_2_ip(&(inp->dhcp->pcb->remote_ip)), ip_current_src_addr())) { + pcb = inp->dhcp->pcb; + } + } + } else if (dest == DHCP_SERVER_PORT) { + if (src == DHCP_CLIENT_PORT) { + if ( inp->dhcps_pcb != NULL ) { + if (ipX_addr_isany(0, &inp->dhcps_pcb->local_ip) || + ip_addr_cmp(ipX_2_ip(&(inp->dhcps_pcb->local_ip)), ip_current_src_addr())) { + 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 (")); + ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG, &pcb->local_ip); + LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", pcb->local_port)); + ipX_addr_debug_print(PCB_ISIPV6(pcb), 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) { + if ( +#if LWIP_IPV6 + ((PCB_ISIPV6(pcb) && (ip_current_is_v6()) && + (ip6_addr_isany(ipX_2_ip6(&pcb->local_ip)) || +#if LWIP_IPV6_MLD + ip6_addr_ismulticast(ip6_current_dest_addr()) || +#endif /* LWIP_IPV6_MLD */ + ip6_addr_cmp(ipX_2_ip6(&pcb->local_ip), ip6_current_dest_addr()))) || + (!PCB_ISIPV6(pcb) && + (ip_current_header() != NULL) && +#else /* LWIP_IPV6 */ + (( +#endif /* LWIP_IPV6 */ + ((!broadcast && ipX_addr_isany(0, &pcb->local_ip)) || + ip_addr_cmp(ipX_2_ip(&pcb->local_ip), ip_current_dest_addr()) || +#if LWIP_IGMP + ip_addr_ismulticast(ip_current_dest_addr()) || +#endif /* LWIP_IGMP */ +#if IP_SOF_BROADCAST_RECV + (broadcast && ip_get_option(pcb, SOF_BROADCAST) && + (ipX_addr_isany(0, &pcb->local_ip) || + ip_addr_netcmp(ipX_2_ip(&pcb->local_ip), ip_current_dest_addr(), &inp->netmask))))))) { +#else /* IP_SOF_BROADCAST_RECV */ + (broadcast && + (ipX_addr_isany(0, &pcb->local_ip) || + ip_addr_netcmp(ipX_2_ip(&pcb->local_ip), ip_current_dest_addr(), &inp->netmask))))))) { +#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_PCB_IPVER_INPUT_MATCH(pcb) && + (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->remote_ip) || + ipX_addr_cmp(PCB_ISIPV6(pcb), &pcb->remote_ip, ipX_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_matches_ip6_addr(inp, ip6_current_dest_addr()); + } else +#endif /* LWIP_IPV6 */ + { + for_us = ip_addr_cmp(&inp->ip_addr, ip_current_dest_addr()); + } + } + if (for_us) { + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n")); +#if CHECKSUM_CHECK_UDP +#if LWIP_UDPLITE + if (ip_current_header_proto() == IP_PROTO_UDPLITE) { + /* Do the UDP Lite checksum */ + u16_t chklen = ntohs(udphdr->len); + if (chklen < sizeof(struct udp_hdr)) { + if (chklen == 0) { + /* For UDP-Lite, checksum length of 0 means checksum + over the complete packet (See RFC 3828 chap. 3.1) */ + chklen = p->tot_len; + } else { + /* At least the UDP-Lite header must be covered by the + checksum! (Again, see RFC 3828 chap. 3.1) */ + goto chkerr; + } + } + if (ipX_chksum_pseudo_partial(ip_current_is_v6(), p, IP_PROTO_UDPLITE, + p->tot_len, chklen, + ipX_current_src_addr(), ipX_current_dest_addr()) != 0) { + goto chkerr; + } + } else +#endif /* LWIP_UDPLITE */ + { + if (udphdr->chksum != 0) { + if (ipX_chksum_pseudo(ip_current_is_v6(), p, IP_PROTO_UDP, p->tot_len, + ipX_current_src_addr(), + ipX_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); + snmp_inc_udpinerrors(); + pbuf_free(p); + goto end; + } + if (pcb != NULL) { + snmp_inc_udpindatagrams(); +#if SO_REUSE && SO_REUSE_RXTOALL + if ((broadcast || +#if LWIP_IPV6 + ip6_addr_ismulticast(ip6_current_dest_addr()) || +#endif /* LWIP_IPV6 */ + ip_addr_ismulticast(ip_current_dest_addr())) && + ip_get_option(pcb, SOF_REUSEADDR)) { + /* 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) && +#if LWIP_IPV6 + ((PCB_ISIPV6(mpcb) && + (ip6_addr_ismulticast(ip6_current_dest_addr()) || + ip6_addr_cmp(ipX_2_ip6(&mpcb->local_ip), ip6_current_dest_addr()))) || + (!PCB_ISIPV6(mpcb) && +#else /* LWIP_IPV6 */ + (( +#endif /* LWIP_IPV6 */ + ((!broadcast && ipX_addr_isany(0, &mpcb->local_ip)) || + ip_addr_cmp(ipX_2_ip(&mpcb->local_ip), ip_current_dest_addr()) || +#if LWIP_IGMP + ip_addr_ismulticast(ip_current_dest_addr()) || +#endif /* LWIP_IGMP */ +#if IP_SOF_BROADCAST_RECV + (broadcast && ip_get_option(mpcb, 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.ip4 != NULL) { + struct pbuf *q; + /* for that, move payload to IP header again */ + if (p_header_changed == 0) { + pbuf_header(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); +#if LWIP_IPV6 + if (PCB_ISIPV6(mpcb)) { + mpcb->recv.ip6(mpcb->recv_arg, mpcb, q, ip6_current_src_addr(), src); + } + else +#endif /* LWIP_IPV6 */ + { + mpcb->recv.ip4(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.ip4 != NULL) { + /* now the recv function is responsible for freeing p */ +#if LWIP_IPV6 + if (PCB_ISIPV6(pcb)) { + pcb->recv.ip6(pcb->recv_arg, pcb, p, ip6_current_src_addr(), src); + } + else +#endif /* LWIP_IPV6 */ + { + pcb->recv.ip4(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 && +#if LWIP_IPV6 + !ip6_addr_ismulticast(ip6_current_dest_addr()) && +#endif /* LWIP_IPV6 */ + !ip_addr_ismulticast(ip_current_dest_addr())) { + /* move payload pointer back to ip header */ + pbuf_header(p, ip_current_header_tot_len() + UDP_HLEN); + icmp_port_unreach(ip_current_is_v6(), p); + } +#endif /* LWIP_ICMP || LWIP_ICMP6 */ + UDP_STATS_INC(udp.proterr); + UDP_STATS_INC(udp.drop); + snmp_inc_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); + snmp_inc_udpinerrors(); + pbuf_free(p); + PERF_STOP("udp_input"); +#endif /* CHECKSUM_CHECK_UDP */ +} + +/** + * 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 +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, ipX_2_ip(&pcb->remote_ip), pcb->remote_port); +} + +#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP +/** 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) +{ + /* send to the packet using remote ip and port stored in the pcb */ + return udp_sendto_chksum(pcb, p, ipX_2_ip(&pcb->remote_ip), pcb->remote_port, + have_chksum, chksum); +} +#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ + +/** + * 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, + 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); +} + +/** Same as udp_sendto(), but with checksum */ +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) +{ +#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ + struct netif *netif; + ipX_addr_t *dst_ip_route = ip_2_ipX(dst_ip); + + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n")); + +#if LWIP_IPV6 || LWIP_IGMP + if (ipX_addr_ismulticast(PCB_ISIPV6(pcb), dst_ip_route)) { + /* For multicast, find a netif based on source address. */ +#if LWIP_IPV6 + if (PCB_ISIPV6(pcb)) { + dst_ip_route = &pcb->local_ip; + } else +#endif /* LWIP_IPV6 */ + { +#if LWIP_IGMP + dst_ip_route = ip_2_ipX(&pcb->multicast_ip); +#endif /* LWIP_IGMP */ + } + } +#endif /* LWIP_IPV6 || LWIP_IGMP */ + + /* find the outgoing network interface for this packet */ + netif = ipX_route(PCB_ISIPV6(pcb), &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 ")); + ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ip_2_ipX(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 */ +} + +/** + * 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, + 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, 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 */ + struct udp_hdr *udphdr; + ip_addr_t *src_ip; + err_t err; + struct pbuf *q; /* q will be sent down the stack */ + u8_t ip_proto; + +#if IP_SOF_BROADCAST + /* broadcast filter? */ + if (!ip_get_option(pcb, SOF_BROADCAST) && +#if LWIP_IPV6 + !PCB_ISIPV6(pcb) && +#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 /* 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, ipX_2_ip(&pcb->local_ip), pcb->local_port); + if (err != ERR_OK) { + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: forced port bind failed\n")); + return err; + } + } + + /* not enough space to add an UDP header to first pbuf in given p chain? */ + if (pbuf_header(p, UDP_HLEN)) { + /* allocate header in a separate new pbuf */ + q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM); + /* new header pbuf could not be allocated? */ + if (q == NULL) { + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: could not allocate header\n")); + return ERR_MEM; + } + if (p->tot_len != 0) { + /* chain header q in front of given pbuf p (only if p contains data) */ + pbuf_chain(q, p); + } + /* first pbuf q points to header pbuf */ + LWIP_DEBUGF(UDP_DEBUG, + ("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p)); + } else { + /* adding space for header within p succeeded */ + /* first pbuf q equals given pbuf */ + q = p; + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header in given pbuf %p\n", (void *)p)); + } + LWIP_ASSERT("check that first pbuf can hold struct udp_hdr", + (q->len >= sizeof(struct udp_hdr))); + /* q now represents the packet to be sent */ + udphdr = (struct udp_hdr *)q->payload; + udphdr->src = htons(pcb->local_port); + udphdr->dest = htons(dst_port); + /* in UDP, 0 checksum means 'no checksum' */ + udphdr->chksum = 0x0000; + + /* Multicast Loop? */ +#if LWIP_IGMP + if (((pcb->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) && +#if LWIP_IPV6 + ( +#if LWIP_IPV6_MLD + (PCB_ISIPV6(pcb) && + ip6_addr_ismulticast(ip_2_ip6(dst_ip))) || +#endif /* LWIP_IPV6_MLD */ + (!PCB_ISIPV6(pcb) && +#else /* LWIP_IPV6 */ + (( +#endif /* LWIP_IPV6 */ + ip_addr_ismulticast(dst_ip)))) { + q->flags |= PBUF_FLAG_MCASTLOOP; + } +#endif /* LWIP_IGMP */ + + + /* PCB local address is IP_ANY_ADDR? */ +#if LWIP_IPV6 + if (PCB_ISIPV6(pcb)) { + if (ip6_addr_isany(ipX_2_ip6(&pcb->local_ip))) { + src_ip = ip6_2_ip(ip6_select_source_address(netif, ip_2_ip6(dst_ip))); + if (src_ip == NULL) { + /* No suitable source address was found. */ + if (q != p) { + /* free the header pbuf */ + pbuf_free(q); + /* p is still referenced by the caller, and will live on */ + } + return ERR_RTE; + } + } else { + /* use UDP PCB local IPv6 address as source address, if still valid. */ + if (netif_matches_ip6_addr(netif, ipX_2_ip6(&pcb->local_ip)) < 0) { + /* Address isn't valid anymore. */ + if (q != p) { + /* free the header pbuf */ + pbuf_free(q); + /* p is still referenced by the caller, and will live on */ + } + return ERR_RTE; + } + src_ip = ipX_2_ip(&pcb->local_ip); + } + } + else +#endif /* LWIP_IPV6 */ + if (ip_addr_isany(ipX_2_ip(&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(ipX_2_ip(&(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 = ipX_2_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 +#if LWIP_CHECKSUM_ON_COPY + if (have_chksum) { + chklen = UDP_HLEN; + } +#endif /* LWIP_CHECKSUM_ON_COPY */ + udphdr->chksum = ipX_chksum_pseudo_partial(PCB_ISIPV6(pcb), q, IP_PROTO_UDPLITE, + q->tot_len, chklen, ip_2_ipX(src_ip), ip_2_ipX(dst_ip)); +#if LWIP_CHECKSUM_ON_COPY + if (have_chksum) { + u32_t acc; + acc = udphdr->chksum + (u16_t)~(chksum); + udphdr->chksum = FOLD_U32T(acc); + } +#endif /* LWIP_CHECKSUM_ON_COPY */ + + /* chksum zero must become 0xffff, as zero means 'no checksum' */ + if (udphdr->chksum == 0x0000) { + udphdr->chksum = 0xffff; + } +#endif /* CHECKSUM_GEN_UDP */ + + ip_proto = IP_PROTO_UDPLITE; + } else +#endif /* LWIP_UDPLITE */ + { /* UDP */ + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %"U16_F"\n", q->tot_len)); + udphdr->len = htons(q->tot_len); + /* calculate checksum */ +#if CHECKSUM_GEN_UDP + /* Checksum is mandatory over IPv6. */ + if (PCB_ISIPV6(pcb) || (pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) { + u16_t udpchksum; +#if LWIP_CHECKSUM_ON_COPY + if (have_chksum) { + u32_t acc; + udpchksum = ipX_chksum_pseudo_partial(PCB_ISIPV6(pcb), q, IP_PROTO_UDP, + q->tot_len, UDP_HLEN, ip_2_ipX(src_ip), ip_2_ipX(dst_ip)); + acc = udpchksum + (u16_t)~(chksum); + udpchksum = FOLD_U32T(acc); + } else +#endif /* LWIP_CHECKSUM_ON_COPY */ + { + udpchksum = ipX_chksum_pseudo(PCB_ISIPV6(pcb), q, IP_PROTO_UDP, q->tot_len, + ip_2_ipX(src_ip), ip_2_ipX(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; + } + + 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 = ipX_output_if(PCB_ISIPV6(pcb), q, src_ip, dst_ip, pcb->ttl, pcb->tos, ip_proto, netif); + NETIF_SET_HWADDRHINT(netif, NULL); + + /* 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 +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 = ")); + ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG | LWIP_DBG_TRACE, ip_2_ipX(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 (!ip_get_option(pcb, SOF_REUSEADDR) && + !ip_get_option(ipcb, SOF_REUSEADDR)) { +#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_PCB_IPVER_EQ(pcb, ipcb) && + /* IP address matches, or one is IP_ADDR_ANY? */ + (ipX_addr_isany(PCB_ISIPV6(ipcb), &(ipcb->local_ip)) || + ipX_addr_isany(PCB_ISIPV6(ipcb), ip_2_ipX(ipaddr)) || + ipX_addr_cmp(PCB_ISIPV6(ipcb), &(ipcb->local_ip), ip_2_ipX(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; + } + } + } + + ipX_addr_set_ipaddr(PCB_ISIPV6(pcb), &pcb->local_ip, ipaddr); + + /* 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; + } + } + 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 ")); + ipX_addr_debug_print(PCB_ISIPV6(pcb), 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; +} + +/** + * 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, ip_addr_t *ipaddr, u16_t port) +{ + struct udp_pcb *ipcb; + + if (pcb->local_port == 0) { + err_t err = udp_bind(pcb, ipX_2_ip(&pcb->local_ip), pcb->local_port); + if (err != ERR_OK) { + return err; + } + } + + ipX_addr_set_ipaddr(PCB_ISIPV6(pcb), &pcb->remote_ip, ipaddr); + pcb->remote_port = port; + pcb->flags |= UDP_FLAGS_CONNECTED; +/** TODO: this functionality belongs in upper layers */ +#ifdef LWIP_UDP_TODO +#if LWIP_IPV6 + if (!PCB_ISIPV6(pcb)) +#endif /* LWIP_IPV6 */ + { + /* Nail down local IP for netconn_addr()/getsockname() */ + if (ip_addr_isany(ipX_2_ip(&pcb->local_ip)) && !ip_addr_isany(ipX_2_ip(&pcb->remote_ip))) { + struct netif *netif; + + if ((netif = ip_route(ipX_2_ip(&pcb->remote_ip))) == NULL) { + LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", + ip4_addr_get_u32(ipX_2_ip(&pcb->remote_ip)))); + 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! */ + ipX_addr_copy(0, pcb->local_ip, netif->ip_addr); + } else if (ip_addr_isany(ipX_2_ip(&pcb->remote_ip))) { + ipX_addr_set_any(0, &pcb->local_ip); + } + } +#endif + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_connect: connected to ")); + ipX_addr_debug_print(PCB_ISIPV6(pcb), 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; +} + +/** + * Disconnect a UDP PCB + * + * @param pcb the udp pcb to disconnect. + */ +void +udp_disconnect(struct udp_pcb *pcb) +{ + /* reset remote address association */ + ipX_addr_set_any(PCB_ISIPV6(pcb), &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 +udp_recv(struct udp_pcb *pcb, udp_recv_fn recv, void *recv_arg) +{ + /* remember recv() callback and user data */ + pcb->recv.ip4 = 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 +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 * +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; + } + return pcb; +} + +#if LWIP_IPV6 +/** + * Create a UDP PCB for IPv6. + * + * @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_ip6(void) +{ + struct udp_pcb *pcb; + pcb = udp_new(); + ip_set_v6(pcb, 1); + return pcb; +} +#endif /* LWIP_IPV6 */ + +#if UDP_DEBUG +/** + * Print UDP header information for debug purposes. + * + * @param udphdr pointer to the udp header in memory. + */ +void +udp_debug_print(struct udp_hdr *udphdr) +{ + LWIP_DEBUGF(UDP_DEBUG, ("UDP header:\n")); + LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(UDP_DEBUG, ("| %5"U16_F" | %5"U16_F" | (src port, dest port)\n", + ntohs(udphdr->src), ntohs(udphdr->dest))); + LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(UDP_DEBUG, ("| %5"U16_F" | 0x%04"X16_F" | (len, chksum)\n", + ntohs(udphdr->len), ntohs(udphdr->chksum))); + LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); +} +#endif /* UDP_DEBUG */ + +#endif /* LWIP_UDP */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/FILES b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/FILES new file mode 100644 index 0000000..099dbf3 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/FILES @@ -0,0 +1,29 @@ +This directory contains generic network interface device drivers that +do not contain any hardware or architecture specific code. The files +are: + +etharp.c + Implements the ARP (Address Resolution Protocol) over + Ethernet. The code in this file should be used together with + Ethernet device drivers. Note that this module has been + largely made Ethernet independent so you should be able to + adapt this for other link layers (such as Firewire). + +ethernetif.c + An example of how an Ethernet device driver could look. This + file can be used as a "skeleton" for developing new Ethernet + network device drivers. It uses the etharp.c ARP code. + +loopif.c + A "loopback" network interface driver. It requires configuration + through the define LWIP_LOOPIF_MULTITHREADING (see opt.h). + +slipif.c + A generic implementation of the SLIP (Serial Line IP) + protocol. It requires a sio (serial I/O) module to work. + +ppp/ Point-to-Point Protocol stack + The PPP stack has been ported from ucip (http://ucip.sourceforge.net). + It matches quite well to pppd 2.3.1 (http://ppp.samba.org), although + compared to that, it has some modifications for embedded systems and + the source code has been reordered a bit. \ No newline at end of file diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/Makefile b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/Makefile new file mode 100644 index 0000000..9e5e810 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/etharp.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/etharp.c new file mode 100644 index 0000000..5a17c66 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/etharp.c @@ -0,0 +1,1433 @@ +/** + * @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" +#include "lwip/ip6.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 STORE_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}}; + +/** The 24-bit IANA multicast OUI is 01-00-5e: */ +#define LL_MULTICAST_ADDR_0 0x01 +#define LL_MULTICAST_ADDR_1 0x00 +#define LL_MULTICAST_ADDR_2 0x5e + +#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 +#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 */ + ip_addr_t ipaddr; + struct netif *netif; + struct eth_addr ethaddr; + u8_t state; + u8_t ctime; +}; + +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 + + +#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 */ + 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_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; + 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 + && (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) { + /* 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 +etharp_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, ("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 && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { + 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 */ + ip_addr_copy(arp_table[i].ipaddr, *ipaddr); + } + arp_table[i].ctime = 0; + return (err_t)i; +} + +/** + * Send an IP packet on the network using netif->linkoutput + * The ethernet header is filled in before sending. + * + * @params netif the lwIP network interface on which to send the packet + * @params p the packet to send, p->payload pointing to the (uninitialized) ethernet header + * @params src the source MAC address to be copied into the ethernet header + * @params dst the destination MAC address to be copied into the ethernet header + * @return ERR_OK if the packet was sent, any other err_t on failure + */ +static err_t +etharp_send_ip(struct netif *netif, struct pbuf *p, struct eth_addr *src, 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 +etharp_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, ("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), + 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, ("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); + /* 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 +#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 */ + snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr); + + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i)); + /* update address */ + ETHADDR32_COPY(&arp_table[i].ethaddr, ethaddr); + /* reset time stamp */ + arp_table[i].ctime = 0; + /* this is where we will send out queued packets! */ +#if ARP_QUEUEING + while (arp_table[i].q != NULL) { + struct pbuf *p; + /* remember remainder of queue */ + struct etharp_q_entry *q = arp_table[i].q; + /* pop first item off the queue */ + arp_table[i].q = q->next; + /* get the packet pointer */ + p = q->p; + /* now queue entry can be freed */ + memp_free(MEMP_ARP_QUEUE, q); +#else /* ARP_QUEUEING */ + if (arp_table[i].q != NULL) { + struct pbuf *p = arp_table[i].q; + arp_table[i].q = NULL; +#endif /* ARP_QUEUEING */ + /* send the queued IP packet */ + etharp_send_ip(netif, p, (struct eth_addr*)(netif->hwaddr), ethaddr); + /* free the queued IP packet */ + pbuf_free(p); + } + return ERR_OK; +} + +#if ETHARP_SUPPORT_STATIC_ENTRIES +/** Add a new static entry to the ARP table. If an entry exists for the + * specified IP address, this entry is overwritten. + * If packets are queued for the specified IP address, they are sent out. + * + * @param ipaddr IP address for the new static entry + * @param ethaddr ethernet address for the new static entry + * @return @see return values of etharp_add_static_entry + */ +err_t +etharp_add_static_entry(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 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(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 = etharp_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_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, 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 = etharp_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 +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 == PP_HTONS(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. */ + etharp_update_arp_entry(netif, &iphdr_src, &(ethhdr->src), ETHARP_FLAG_FIND_ONLY); +} +#endif /* ETHARP_TRUST_IP_MAC */ + +/** + * Responds to ARP requests to us. Upon ARP replies to us, add entry to cache + * send out queued IP packets. Updates cache with snooped address pairs. + * + * Should be called for incoming ARP packets. The pbuf in the argument + * is freed by this function. + * + * @param netif The lwIP network interface on which the ARP packet pbuf arrived. + * @param ethaddr Ethernet address of netif. + * @param p The ARP packet that arrived on netif. Is freed by this function. + * + * @return NULL + * + * @see pbuf_free() + */ +static void +etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p) +{ + struct etharp_hdr *hdr; + struct eth_hdr *ethhdr; + /* these are aligned properly, whereas the ARP header fields might not be */ + ip_addr_t sipaddr, dipaddr; + u8_t for_us; +#if LWIP_AUTOIP + const u8_t * ethdst_hwaddr; +#endif /* LWIP_AUTOIP */ + + LWIP_ERROR("netif != NULL", (netif != NULL), return;); + + /* drop short ARP packets: we have to check for p->len instead of p->tot_len here + since a struct etharp_hdr is pointed to p->payload, so it musn't be chained! */ + if (p->len < SIZEOF_ETHARP_PACKET) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, + ("etharp_arp_input: packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len, + (s16_t)SIZEOF_ETHARP_PACKET)); + ETHARP_STATS_INC(etharp.lenerr); + ETHARP_STATS_INC(etharp.drop); + pbuf_free(p); + return; + } + + ethhdr = (struct eth_hdr *)p->payload; + hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR); +#if ETHARP_SUPPORT_VLAN + if (ethhdr->type == PP_HTONS(ETHTYPE_VLAN)) { + hdr = (struct etharp_hdr *)(((u8_t*)ethhdr) + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR); + } +#endif /* ETHARP_SUPPORT_VLAN */ + + /* RFC 826 "Packet Reception": */ + if ((hdr->hwtype != PP_HTONS(HWTYPE_ETHERNET)) || + (hdr->hwlen != ETHARP_HWADDR_LEN) || + (hdr->protolen != sizeof(ip_addr_t)) || + (hdr->proto != PP_HTONS(ETHTYPE_IP))) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, + ("etharp_arp_input: packet dropped, wrong hw type, hwlen, proto, protolen or ethernet type (%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F")\n", + hdr->hwtype, hdr->hwlen, hdr->proto, 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 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 */ + 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 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 */ + + /* return ARP reply */ + netif->linkoutput(netif, p); + /* 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 +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; + struct eth_addr mcastaddr; + ip_addr_t *dst_addr = ipaddr; + + LWIP_ASSERT("netif != NULL", netif != NULL); + LWIP_ASSERT("q != NULL", q != NULL); + LWIP_ASSERT("ipaddr != NULL", ipaddr != NULL); + + /* make room for Ethernet header - should not fail */ + if (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; + } + + /* 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] = LL_MULTICAST_ADDR_0; + mcastaddr.addr[1] = LL_MULTICAST_ADDR_1; + mcastaddr.addr[2] = LL_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 (!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 */ + dst_addr = &(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(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) && + (ip_addr_cmp(dst_addr, &arp_table[i].ipaddr))) { + /* found an existing, stable entry */ + ETHARP_SET_HINT(netif, i); + return etharp_output_to_arp_index(netif, q, i); + } + } + /* no stable entry found, use the (slower) query function: + queue on destination Ethernet address belonging to ipaddr */ + return etharp_query(netif, dst_addr, q); + } + + /* continuation for multicast/broadcast destinations */ + /* obtain source Ethernet address of the given interface */ + /* send packet directly on the link */ + return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr), dest); +} + +/** + * Send an ARP request for the given IP address and/or queue a packet. + * + * If the IP address was not yet in the cache, a pending ARP cache entry + * is added and an ARP request is sent for the given address. The packet + * is queued on this entry. + * + * If the IP address was already pending in the cache, a new ARP request + * is sent for the given address. The packet is queued on this entry. + * + * If the IP address was already stable in the cache, and a packet is + * given, it is directly sent and no ARP request is sent out. + * + * If the IP address was already stable in the cache, and no packet is + * given, an ARP request is sent out. + * + * @param netif The lwIP network interface on which ipaddr + * must be queried for. + * @param ipaddr The IP address to be resolved. + * @param q If non-NULL, a pbuf that must be delivered to the IP address. + * q is not freed by this function. + * + * @note q must only be ONE packet, not a packet queue! + * + * @return + * - ERR_BUF Could not make room for Ethernet header. + * - ERR_MEM Hardware address unknown, and no more ARP entries available + * to query for address or queue the packet. + * - ERR_MEM Could not queue packet due to memory shortage. + * - ERR_RTE No route to destination (no gateway to external networks). + * - ERR_ARG Non-unicast address given, those will not appear in ARP cache. + * + */ +err_t +etharp_query(struct netif *netif, 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 = etharp_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) { + 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; + int entry_q_number = 1; + while (r->next != NULL) { + entry_q_number ++; + r = r->next; + } +#ifdef LWIP_ESP8266 + if(entry_q_number >= ARP_ENTRY_QUEUE_SIZE) { + 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); + /* free the queued IP packet */ + pbuf_free(p); + } +#endif /* LWIP_ESP8266 */ + r->next = new_entry; + } else { + /* queue did not exist, first item in queue */ + arp_table[i].q = new_entry; + } + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); + result = ERR_OK; + } else { + /* the pool MEMP_ARP_QUEUE is empty */ + pbuf_free(p); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); + result = ERR_MEM; + } +#else /* ARP_QUEUEING */ + /* always queue one packet per ARP request only, freeing a previously queued packet */ + if (arp_table[i].q != NULL) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: dropped previously queued packet %p for ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); + pbuf_free(arp_table[i].q); + } + arp_table[i].q = p; + result = ERR_OK; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); +#endif /* ARP_QUEUEING */ + } else { + ETHARP_STATS_INC(etharp.memerr); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); + result = ERR_MEM; + } + } + return result; +} + +/** + * Send a raw ARP packet (opcode and all addresses can be modified) + * + * @param netif the lwip network interface on which to send the ARP packet + * @param ethsrc_addr the source MAC address for the ethernet header + * @param ethdst_addr the destination MAC address for the ethernet header + * @param hwsrc_addr the source MAC address for the ARP protocol header + * @param ipsrc_addr the source IP address for the ARP protocol header + * @param hwdst_addr the destination MAC address for the ARP protocol header + * @param ipdst_addr the destination IP address for the ARP protocol header + * @param opcode the type of the ARP packet + * @return ERR_OK if the ARP packet has been sent + * ERR_MEM if the ARP packet couldn't be allocated + * any other err_t on failure + */ +#if !LWIP_AUTOIP +static +#endif /* LWIP_AUTOIP */ +err_t +etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr, + const struct eth_addr *ethdst_addr, + const struct eth_addr *hwsrc_addr, const 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 */ + + LWIP_ASSERT("netif != NULL", netif != NULL); + + /* 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; +#if LWIP_ARP || ETHARP_SUPPORT_VLAN + 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); + 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 */ + ETHARP_STATS_INC(etharp.proterr); + ETHARP_STATS_INC(etharp.drop); + goto free_and_return; + } +#if defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) /* if not, allow all VLANs */ +#ifdef 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(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) */ + type = vlan->tpid; + ip_hdr_offset = SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR; + } +#endif /* ETHARP_SUPPORT_VLAN */ + +#if LWIP_ARP_FILTER_NETIF + netif = LWIP_ARP_FILTER_NETIF_FN(p, netif, htons(type)); +#endif /* LWIP_ARP_FILTER_NETIF*/ + + if (ethhdr->dest.addr[0] & 1) { + /* this might be a multicast or broadcast packet */ + if (ethhdr->dest.addr[0] == LL_MULTICAST_ADDR_0) { + if ((ethhdr->dest.addr[1] == LL_MULTICAST_ADDR_1) && + (ethhdr->dest.addr[2] == LL_MULTICAST_ADDR_2)) { + /* mark the pbuf as link-layer multicast */ + p->flags |= PBUF_FLAG_LLMCAST; + } + } else if (eth_addr_cmp(ðhdr->dest, ðbroadcast)) { + /* mark the pbuf as link-layer broadcast */ + p->flags |= PBUF_FLAG_LLBCAST; + } + } + + 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 */ + +#if LWIP_IPV6 + case PP_HTONS(ETHTYPE_IPV6): /* IPv6 */ + /* skip Ethernet header */ + if(pbuf_header(p, -(s16_t)SIZEOF_ETH_HDR)) { + LWIP_ASSERT("Can't move over header in packet", 0); + goto free_and_return; + } else { + /* pass to IPv6 layer */ + ip6_input(p, netif); + } + break; +#endif /* LWIP_IPV6 */ + + 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/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ethernetif.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ethernetif.c new file mode 100644 index 0000000..3e76a4f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ethernetif.c @@ -0,0 +1,274 @@ +/** + * @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 + * + */ + +#include "lwip/opt.h" + +#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 "netif/etharp.h" +#include "netif/ppp_oe.h" + +#include "esp_common.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +/* Define those to better describe your network interface. */ +#define IFNAME0 'e' +#define IFNAME1 'n' + +char *hostname; +bool default_hostname = 1; + +/** + * 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) +{ + /* set MAC hardware address length */ + netif->hwaddr_len = ETHARP_HWADDR_LEN; + + /* 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_IGMP + netif->flags |= NETIF_FLAG_IGMP; +#endif + /* 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 availale 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; + err_t err = ERR_OK; +// initiate transfer(); + +#if ETH_PAD_SIZE + pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ +#endif + + struct pbuf *tmp; + 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); + tmp = q->next; + + err = ieee80211_output_pbuf(netif, q); + if (err == ERR_MEM) { + err = ERR_OK; + } + q->next = tmp; + break; + } + +// signal that packet should be sent(); + +#if ETH_PAD_SIZE + pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ +#endif + + LINK_STATS_INC(link.xmit); + + return err; +} + +/** + * 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 + */ +void +ethernetif_input(struct netif *netif, struct pbuf *p) +{ + struct ethernetif *ethernetif; + struct eth_hdr *ethhdr; + + if(p == NULL) + goto _exit; + + if(p->payload == NULL) { + pbuf_free(p); + goto _exit; + } + + if(netif == NULL) { + goto _exit; + } + + if (!(netif->flags & NETIF_FLAG_LINK_UP)) { + pbuf_free(p); + p = NULL; + goto _exit; + } + + ethernetif = netif->state; + + /* points to packet payload, which starts with an Ethernet header */ + ethhdr = p->payload; + + switch (htons(ethhdr->type)) { + /* IP or ARP packet? */ + case ETHTYPE_IP: + case ETHTYPE_IPV6: + case ETHTYPE_ARP: +#if PPPOE_SUPPORT + /* PPPoE packet? */ + case ETHTYPE_PPPOEDISC: + case ETHTYPE_PPPOE: +#endif /* PPPOE_SUPPORT */ + /* full packet send to tcpip_thread to process */ + if (netif->input(p, netif)!=ERR_OK) + { LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); + pbuf_free(p); + p = NULL; + } + break; + + default: + pbuf_free(p); + p = NULL; + break; + } +_exit: +; +} + +/** + * 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) +{ + LWIP_ASSERT("netif != NULL", (netif != NULL)); + + u8_t mac[NETIF_MAX_HWADDR_LEN]; + + /* set MAC hardware address */ + if ((struct netif *)wifi_get_netif(STATION_IF) == netif) { + wifi_get_macaddr(STATION_IF, mac); + } else { + wifi_get_macaddr(SOFTAP_IF, mac); + } + memcpy(netif->hwaddr, mac, NETIF_MAX_HWADDR_LEN); + +#if LWIP_NETIF_HOSTNAME + if ((struct netif *)wifi_get_netif(STATION_IF) == netif) { + if (default_hostname == 1) { + wifi_station_set_default_hostname(netif->hwaddr); + } + + /* Initialize interface hostname */ + netif->hostname = hostname; + } else { + netif->hostname = NULL; + } +#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. + */ + NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS); + + 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; + + extern void wifi_station_dhcpc_event(void); + netif->dhcp_event = wifi_station_dhcpc_event; + + /* initialize the hardware */ + low_level_init(netif); + + return ERR_OK; +} diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/auth.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/auth.c new file mode 100644 index 0000000..00aea8a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/auth.c @@ -0,0 +1,1334 @@ +/***************************************************************************** +* auth.c - Network Authentication and Phase Control program file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* Copyright (c) 1997 by Global Election Systems Inc. All rights reserved. +* +* 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-12-08 Guy Lancaster , Global Election Systems Inc. +* Ported from public pppd code. +*****************************************************************************/ +/* + * auth.c - PPP authentication and phase control. + * + * Copyright (c) 1993 The Australian National 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 the Australian National 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "ppp_impl.h" +#include "pppdebug.h" + +#include "fsm.h" +#include "lcp.h" +#include "pap.h" +#include "chap.h" +#include "auth.h" +#include "ipcp.h" + +#if CBCP_SUPPORT +#include "cbcp.h" +#endif /* CBCP_SUPPORT */ + +#include "lwip/inet.h" + +#include + +#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 PAP_SUPPORT || CHAP_SUPPORT +/* The name by which the peer authenticated itself to us. */ +static char peer_authname[MAXNAMELEN]; +#endif /* PAP_SUPPORT || CHAP_SUPPORT */ + +/* Records which authentication operations haven't completed yet. */ +static int auth_pending[NUM_PPP]; + +/* Set if we have successfully called plogin() */ +static int logged_in; + +/* Set if we have run the /etc/ppp/auth-up script. */ +static int did_authup; /* @todo, we don't need this in lwip*/ + +/* List of addresses which the peer may use. */ +static struct wordlist *addresses[NUM_PPP]; + +#if 0 /* UNUSED */ +/* Wordlist giving addresses which the peer may use + without authenticating itself. */ +static struct wordlist *noauth_addrs; + +/* Extra options to apply, from the secrets file entry for the peer. */ +static struct wordlist *extra_options; +#endif /* UNUSED */ + +/* Number of network protocols which we have opened. */ +static int num_np_open; + +/* Number of network protocols which have come up. */ +static int num_np_up; + +#if PAP_SUPPORT || CHAP_SUPPORT +/* Set if we got the contents of passwd[] from the pap-secrets file. */ +static int passwd_from_file; +#endif /* PAP_SUPPORT || CHAP_SUPPORT */ + +#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) __P((struct ppp_idle *)) = NULL; + +/* Hook for a plugin to say whether we can possibly authenticate any peer */ +int (*pap_check_hook) __P((void)) = NULL; + +/* Hook for a plugin to check the PAP user and password */ +int (*pap_auth_hook) __P((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) __P((void)) = NULL; + +/* Hook for a plugin to get the PAP password for authenticating us */ +int (*pap_passwd_hook) __P((char *user, char *passwd)) = NULL; + +/* + * This is used to ensure that we don't start an auth-up/down + * script while one is already running. + */ +enum script_state { + s_down, + s_up +}; + +static enum script_state auth_state = s_down; +static enum script_state auth_script_state = s_down; +static pid_t auth_script_pid = 0; + +/* + * Option variables. + * lwip: some of these are present in the ppp_settings structure + */ +bool uselogin = 0; /* Use /etc/passwd for checking PAP */ +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 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 */ +char remote_name[MAXNAMELEN]; /* Peer's name for authentication */ + +#endif /* UNUSED */ + +/* Bits in auth_pending[] */ +#define PAP_WITHPEER 1 +#define PAP_PEER 2 +#define CHAP_WITHPEER 4 +#define CHAP_PEER 8 + +/* @todo, move this somewhere */ +/* Used for storing a sequence of words. Usually malloced. */ +struct wordlist { + struct wordlist *next; + char word[1]; +}; + + +extern char *crypt (const char *, const char *); + +/* Prototypes for procedures local to this file. */ + +static void network_phase (int); +static void check_idle (void *); +static void connect_time_expired (void *); +#if 0 +static int plogin (char *, char *, char **, int *); +#endif +static void plogout (void); +static int null_login (int); +static int get_pap_passwd (int, char *, char *); +static int have_pap_secret (void); +static int have_chap_secret (char *, char *, u32_t); +static int ip_addr_check (u32_t, struct wordlist *); + +#if 0 /* PAP_SUPPORT || CHAP_SUPPORT */ +static int scan_authfile (FILE *, char *, char *, char *, + struct wordlist **, struct wordlist **, + char *); +static void free_wordlist (struct wordlist *); +static void auth_script (char *); +static void auth_script_done (void *); +static void set_allowed_addrs (int unit, struct wordlist *addrs); +static int some_ip_ok (struct wordlist *); +static int setupapfile (char **); +static int privgroup (char **); +static int set_noauth_addr (char **); +static void check_access (FILE *, char *); +#endif /* 0 */ /* PAP_SUPPORT || CHAP_SUPPORT */ + +#if 0 /* UNUSED */ +/* + * Authentication-related options. + */ +option_t auth_options[] = { + { "require-pap", o_bool, &lcp_wantoptions[0].neg_upap, + "Require PAP authentication from peer", 1, &auth_required }, + { "+pap", o_bool, &lcp_wantoptions[0].neg_upap, + "Require PAP authentication from peer", 1, &auth_required }, + { "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", 1 }, + { "require-chap", o_bool, &lcp_wantoptions[0].neg_chap, + "Require CHAP authentication from peer", 1, &auth_required }, + { "+chap", o_bool, &lcp_wantoptions[0].neg_chap, + "Require CHAP authentication from peer", 1, &auth_required }, + { "refuse-chap", o_bool, &refuse_chap, + "Don't agree to auth to peer with CHAP", 1 }, + { "-chap", o_bool, &refuse_chap, + "Don't allow CHAP authentication with peer", 1 }, + { "name", o_string, our_name, + "Set local name for authentication", + OPT_PRIV|OPT_STATIC, NULL, MAXNAMELEN }, + { "user", o_string, user, + "Set name for auth with peer", OPT_STATIC, NULL, MAXNAMELEN }, + { "usehostname", o_bool, &usehostname, + "Must use hostname for authentication", 1 }, + { "remotename", o_string, remote_name, + "Set remote name for authentication", OPT_STATIC, + &explicit_remote, MAXNAMELEN }, + { "auth", o_bool, &auth_required, + "Require authentication from peer", 1 }, + { "noauth", o_bool, &auth_required, + "Don't require peer to authenticate", OPT_PRIV, &allow_any_ip }, + { "login", o_bool, &uselogin, + "Use system password database for PAP", 1 }, + { "papcrypt", o_bool, &cryptpap, + "PAP passwords are encrypted", 1 }, + { "+ua", o_special, (void *)setupapfile, + "Get PAP user and password from file" }, + { "password", o_string, passwd, + "Password for authenticating us to the peer", OPT_STATIC, + NULL, MAXSECRETLEN }, + { "privgroup", o_special, (void *)privgroup, + "Allow group members to use privileged options", OPT_PRIV }, + { "allow-ip", o_special, (void *)set_noauth_addr, + "Set IP address(es) which can be used without authentication", + OPT_PRIV }, + { NULL } +}; +#endif /* UNUSED */ +#if 0 /* UNUSED */ +/* + * setupapfile - specifies UPAP info for authenticating with peer. + */ +static int +setupapfile(char **argv) +{ + FILE * ufile; + int l; + + lcp_allowoptions[0].neg_upap = 1; + + /* open user info file */ + seteuid(getuid()); + ufile = fopen(*argv, "r"); + seteuid(0); + if (ufile == NULL) { + option_error("unable to open user login data file %s", *argv); + return 0; + } + check_access(ufile, *argv); + + /* get username */ + if (fgets(user, MAXNAMELEN - 1, ufile) == NULL + || fgets(passwd, MAXSECRETLEN - 1, ufile) == NULL){ + option_error("unable to read user login data file %s", *argv); + return 0; + } + fclose(ufile); + + /* get rid of newlines */ + l = os_strlen(user); + if (l > 0 && user[l-1] == '\n') + user[l-1] = 0; + l = os_strlen(passwd); + if (l > 0 && passwd[l-1] == '\n') + passwd[l-1] = 0; + + return (1); +} +#endif /* UNUSED */ + +#if 0 /* UNUSED */ +/* + * privgroup - allow members of the group to have privileged access. + */ +static int +privgroup(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; +} +#endif + +#if 0 /* UNUSED */ +/* + * 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(char **argv) +{ + char *addr = *argv; + int l = os_strlen(addr); + struct wordlist *wp; + + wp = (struct wordlist *) malloc(sizeof(struct wordlist) + l + 1); + if (wp == NULL) + novm("allow-ip argument"); + wp->word = (char *) (wp + 1); + wp->next = noauth_addrs; + BCOPY(addr, wp->word, l); + noauth_addrs = wp; + return 1; +} +#endif /* UNUSED */ + +/* + * An Open on LCP has requested a change from Dead to Establish phase. + * Do what's necessary to bring the physical layer up. + */ +void +link_required(int unit) +{ + LWIP_UNUSED_ARG(unit); + + AUTHDEBUG(LOG_INFO, ("link_required: %d\n", unit)); +} + +/* + * LCP has terminated the link; go to the Dead phase and take the + * physical layer down. + */ +void +link_terminated(int unit) +{ + AUTHDEBUG(LOG_INFO, ("link_terminated: %d\n", unit)); + if (lcp_phase[unit] == PHASE_DEAD) { + return; + } + if (logged_in) { + plogout(); + } + lcp_phase[unit] = PHASE_DEAD; + AUTHDEBUG(LOG_NOTICE, ("Connection terminated.\n")); + pppLinkTerminated(unit); +} + +/* + * LCP has gone down; it will either die or try to re-establish. + */ +void +link_down(int unit) +{ + int i; + struct protent *protp; + + AUTHDEBUG(LOG_INFO, ("link_down: %d\n", unit)); + + if (did_authup) { + /* XXX Do link down processing. */ + did_authup = 0; + } + for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) { + if (!protp->enabled_flag) { + continue; + } + if (protp->protocol != PPP_LCP && protp->lowerdown != NULL) { + (*protp->lowerdown)(unit); + } + if (protp->protocol < 0xC000 && protp->close != NULL) { + (*protp->close)(unit, "LCP down"); + } + } + num_np_open = 0; /* number of network protocols we have opened */ + num_np_up = 0; /* Number of network protocols which have come up */ + + if (lcp_phase[unit] != PHASE_DEAD) { + lcp_phase[unit] = PHASE_TERMINATE; + } + pppLinkDown(unit); +} + +/* + * The link is established. + * Proceed to the Dead, Authenticate or Network phase as appropriate. + */ +void +link_established(int unit) +{ + int auth; + int i; + struct protent *protp; + lcp_options *wo = &lcp_wantoptions[unit]; + lcp_options *go = &lcp_gotoptions[unit]; +#if PAP_SUPPORT || CHAP_SUPPORT + lcp_options *ho = &lcp_hisoptions[unit]; +#endif /* PAP_SUPPORT || CHAP_SUPPORT */ + + AUTHDEBUG(LOG_INFO, ("link_established: unit %d; Lowering up all protocols...\n", unit)); + /* + * Tell higher-level protocols that LCP is up. + */ + for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) { + if (protp->protocol != PPP_LCP && protp->enabled_flag && protp->lowerup != NULL) { + (*protp->lowerup)(unit); + } + } + if (ppp_settings.auth_required && !(go->neg_chap || go->neg_upap)) { + /* + * We wanted the peer to authenticate itself, and it refused: + * 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 (!wo->neg_upap || !null_login(unit)) { + AUTHDEBUG(LOG_WARNING, ("peer refused to authenticate\n")); + lcp_close(unit, "peer refused to authenticate"); + return; + } + } + + lcp_phase[unit] = PHASE_AUTHENTICATE; + auth = 0; +#if CHAP_SUPPORT + if (go->neg_chap) { + ChapAuthPeer(unit, ppp_settings.our_name, go->chap_mdtype); + auth |= CHAP_PEER; + } +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT && CHAP_SUPPORT + else +#endif /* PAP_SUPPORT && CHAP_SUPPORT */ +#if PAP_SUPPORT + if (go->neg_upap) { + upap_authpeer(unit); + auth |= PAP_PEER; + } +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + if (ho->neg_chap) { + ChapAuthWithPeer(unit, ppp_settings.user, ho->chap_mdtype); + auth |= CHAP_WITHPEER; + } +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT && CHAP_SUPPORT + else +#endif /* PAP_SUPPORT && CHAP_SUPPORT */ +#if PAP_SUPPORT + if (ho->neg_upap) { + if (ppp_settings.passwd[0] == 0) { + passwd_from_file = 1; + if (!get_pap_passwd(unit, ppp_settings.user, ppp_settings.passwd)) { + AUTHDEBUG(LOG_ERR, ("No secret found for PAP login\n")); + } + } + upap_authwithpeer(unit, ppp_settings.user, ppp_settings.passwd); + auth |= PAP_WITHPEER; + } +#endif /* PAP_SUPPORT */ + auth_pending[unit] = auth; + + if (!auth) { + network_phase(unit); + } +} + +/* + * Proceed to the network phase. + */ +static void +network_phase(int unit) +{ + int i; + struct protent *protp; + lcp_options *go = &lcp_gotoptions[unit]; + + /* + * If the peer had to authenticate, run the auth-up script now. + */ + if ((go->neg_chap || go->neg_upap) && !did_authup) { + /* XXX Do setup for peer authentication. */ + did_authup = 1; + } + +#if CBCP_SUPPORT + /* + * If we negotiated callback, do it now. + */ + if (go->neg_cbcp) { + lcp_phase[unit] = PHASE_CALLBACK; + (*cbcp_protent.open)(unit); + return; + } +#endif /* CBCP_SUPPORT */ + + lcp_phase[unit] = PHASE_NETWORK; + for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) { + if (protp->protocol < 0xC000 && protp->enabled_flag && protp->open != NULL) { + (*protp->open)(unit); + if (protp->protocol != PPP_CCP) { + ++num_np_open; + } + } + } + + if (num_np_open == 0) { + /* nothing to do */ + lcp_close(0, "No network protocols running"); + } +} +/* @todo: add void start_networks(void) here (pppd 2.3.11) */ + +/* + * The peer has failed to authenticate himself using `protocol'. + */ +void +auth_peer_fail(int unit, u16_t protocol) +{ + LWIP_UNUSED_ARG(protocol); + + AUTHDEBUG(LOG_INFO, ("auth_peer_fail: %d proto=%X\n", unit, protocol)); + /* + * Authentication failure: take the link down + */ + lcp_close(unit, "Authentication failed"); +} + + +#if PAP_SUPPORT || CHAP_SUPPORT +/* + * The peer has been successfully authenticated using `protocol'. + */ +void +auth_peer_success(int unit, u16_t protocol, char *name, int namelen) +{ + int pbit; + + AUTHDEBUG(LOG_INFO, ("auth_peer_success: %d proto=%X\n", unit, protocol)); + switch (protocol) { + case PPP_CHAP: + pbit = CHAP_PEER; + break; + case PPP_PAP: + pbit = PAP_PEER; + break; + default: + AUTHDEBUG(LOG_WARNING, ("auth_peer_success: unknown protocol %x\n", protocol)); + return; + } + + /* + * Save the authenticated name of the peer for later. + */ + if (namelen > (int)sizeof(peer_authname) - 1) { + namelen = sizeof(peer_authname) - 1; + } + BCOPY(name, peer_authname, namelen); + peer_authname[namelen] = 0; + + /* + * If there is no more authentication still to be done, + * proceed to the network (or callback) phase. + */ + if ((auth_pending[unit] &= ~pbit) == 0) { + network_phase(unit); + } +} + +/* + * We have failed to authenticate ourselves to the peer using `protocol'. + */ +void +auth_withpeer_fail(int unit, u16_t protocol) +{ + int errCode = PPPERR_AUTHFAIL; + + LWIP_UNUSED_ARG(protocol); + + AUTHDEBUG(LOG_INFO, ("auth_withpeer_fail: %d proto=%X\n", unit, protocol)); + if (passwd_from_file) { + BZERO(ppp_settings.passwd, MAXSECRETLEN); + } + + /* + * We've failed to authenticate ourselves to our peer. + * He'll probably take the link down, and there's not much + * we can do except wait for that. + */ + pppIOCtl(unit, PPPCTLS_ERRCODE, &errCode); + lcp_close(unit, "Failed to authenticate ourselves to peer"); +} + +/* + * We have successfully authenticated ourselves with the peer using `protocol'. + */ +void +auth_withpeer_success(int unit, u16_t protocol) +{ + int pbit; + + AUTHDEBUG(LOG_INFO, ("auth_withpeer_success: %d proto=%X\n", unit, protocol)); + switch (protocol) { + case PPP_CHAP: + pbit = CHAP_WITHPEER; + break; + case PPP_PAP: + if (passwd_from_file) { + BZERO(ppp_settings.passwd, MAXSECRETLEN); + } + pbit = PAP_WITHPEER; + break; + default: + AUTHDEBUG(LOG_WARNING, ("auth_peer_success: unknown protocol %x\n", protocol)); + pbit = 0; + } + + /* + * If there is no more authentication still being done, + * proceed to the network (or callback) phase. + */ + if ((auth_pending[unit] &= ~pbit) == 0) { + network_phase(unit); + } +} +#endif /* PAP_SUPPORT || CHAP_SUPPORT */ + + +/* + * np_up - a network protocol has come up. + */ +void +np_up(int unit, u16_t proto) +{ + LWIP_UNUSED_ARG(unit); + LWIP_UNUSED_ARG(proto); + + AUTHDEBUG(LOG_INFO, ("np_up: %d proto=%X\n", unit, proto)); + if (num_np_up == 0) { + AUTHDEBUG(LOG_INFO, ("np_up: maxconnect=%d idle_time_limit=%d\n",ppp_settings.maxconnect,ppp_settings.idle_time_limit)); + /* + * At this point we consider that the link has come up successfully. + */ + if (ppp_settings.idle_time_limit > 0) { + TIMEOUT(check_idle, NULL, ppp_settings.idle_time_limit); + } + + /* + * Set a timeout to close the connection once the maximum + * connect time has expired. + */ + if (ppp_settings.maxconnect > 0) { + TIMEOUT(connect_time_expired, 0, ppp_settings.maxconnect); + } + } + ++num_np_up; +} + +/* + * np_down - a network protocol has gone down. + */ +void +np_down(int unit, u16_t proto) +{ + LWIP_UNUSED_ARG(unit); + LWIP_UNUSED_ARG(proto); + + AUTHDEBUG(LOG_INFO, ("np_down: %d proto=%X\n", unit, proto)); + if (--num_np_up == 0 && ppp_settings.idle_time_limit > 0) { + UNTIMEOUT(check_idle, NULL); + } +} + +/* + * np_finished - a network protocol has finished using the link. + */ +void +np_finished(int unit, u16_t proto) +{ + LWIP_UNUSED_ARG(unit); + LWIP_UNUSED_ARG(proto); + + AUTHDEBUG(LOG_INFO, ("np_finished: %d proto=%X\n", unit, proto)); + if (--num_np_open <= 0) { + /* no further use for the link: shut up shop. */ + lcp_close(0, "No network protocols running"); + } +} + +/* + * check_idle - check whether the link has been idle for long + * enough that we can shut it down. + */ +static void +check_idle(void *arg) +{ + struct ppp_idle idle; + u_short itime; + + LWIP_UNUSED_ARG(arg); + if (!get_idle_time(0, &idle)) { + return; + } + itime = LWIP_MIN(idle.xmit_idle, idle.recv_idle); + if (itime >= ppp_settings.idle_time_limit) { + /* link is idle: shut it down. */ + AUTHDEBUG(LOG_INFO, ("Terminating connection due to lack of activity.\n")); + lcp_close(0, "Link inactive"); + } else { + TIMEOUT(check_idle, NULL, ppp_settings.idle_time_limit - itime); + } +} + +/* + * connect_time_expired - log a message and close the connection. + */ +static void +connect_time_expired(void *arg) +{ + LWIP_UNUSED_ARG(arg); + + AUTHDEBUG(LOG_INFO, ("Connect time expired\n")); + lcp_close(0, "Connect time expired"); /* Close connection */ +} + +#if 0 /* UNUSED */ +/* + * auth_check_options - called to check authentication options. + */ +void +auth_check_options(void) +{ + lcp_options *wo = &lcp_wantoptions[0]; + int can_auth; + ipcp_options *ipwo = &ipcp_wantoptions[0]; + u32_t remote; + + /* Default our_name to hostname, and user to our_name */ + if (ppp_settings.our_name[0] == 0 || ppp_settings.usehostname) { + strcpy(ppp_settings.our_name, ppp_settings.hostname); + } + + if (ppp_settings.user[0] == 0) { + strcpy(ppp_settings.user, ppp_settings.our_name); + } + + /* If authentication is required, ask peer for CHAP or PAP. */ + if (ppp_settings.auth_required && !wo->neg_chap && !wo->neg_upap) { + wo->neg_chap = 1; + wo->neg_upap = 1; + } + + /* + * Check whether we have appropriate secrets to use + * to authenticate the peer. + */ + can_auth = wo->neg_upap && have_pap_secret(); + if (!can_auth && wo->neg_chap) { + remote = ipwo->accept_remote? 0: ipwo->hisaddr; + can_auth = have_chap_secret(ppp_settings.remote_name, ppp_settings.our_name, remote); + } + + if (ppp_settings.auth_required && !can_auth) { + ppp_panic("No auth secret"); + } +} +#endif /* 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(int unit) +{ + lcp_options *go = &lcp_gotoptions[unit]; + lcp_options *ao = &lcp_allowoptions[0]; + ipcp_options *ipwo = &ipcp_wantoptions[0]; + u32_t remote; + + AUTHDEBUG(LOG_INFO, ("auth_reset: %d\n", unit)); + ao->neg_upap = !ppp_settings.refuse_pap && (ppp_settings.passwd[0] != 0 || get_pap_passwd(unit, NULL, NULL)); + ao->neg_chap = !ppp_settings.refuse_chap && ppp_settings.passwd[0] != 0 /*have_chap_secret(ppp_settings.user, ppp_settings.remote_name, (u32_t)0)*/; + + if (go->neg_upap && !have_pap_secret()) { + go->neg_upap = 0; + } + if (go->neg_chap) { + remote = ipwo->accept_remote? 0: ipwo->hisaddr; + if (!have_chap_secret(ppp_settings.remote_name, ppp_settings.our_name, remote)) { + go->neg_chap = 0; + } + } +} + +#if PAP_SUPPORT +/* + * 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. + */ +u_char +check_passwd( int unit, char *auser, int userlen, char *apasswd, int passwdlen, char **msg, int *msglen) +{ +#if 1 /* XXX Assume all entries OK. */ + LWIP_UNUSED_ARG(unit); + LWIP_UNUSED_ARG(auser); + LWIP_UNUSED_ARG(userlen); + LWIP_UNUSED_ARG(apasswd); + LWIP_UNUSED_ARG(passwdlen); + LWIP_UNUSED_ARG(msglen); + *msg = (char *) 0; + return UPAP_AUTHACK; /* XXX Assume all entries OK. */ +#else + u_char ret = 0; + struct wordlist *addrs = NULL; + char passwd[256], user[256]; + char secret[MAXWORDLEN]; + static u_short attempts = 0; + + /* + * Make copies of apasswd and auser, then null-terminate them. + */ + BCOPY(apasswd, passwd, passwdlen); + passwd[passwdlen] = '\0'; + BCOPY(auser, user, userlen); + user[userlen] = '\0'; + *msg = (char *) 0; + + /* XXX Validate user name and password. */ + ret = UPAP_AUTHACK; /* XXX Assume all entries OK. */ + + if (ret == UPAP_AUTHNAK) { + if (*msg == (char *) 0) { + *msg = "Login incorrect"; + } + *msglen = os_strlen(*msg); + /* + * 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) { + AUTHDEBUG(LOG_WARNING, ("%d LOGIN FAILURES BY %s\n", attempts, user)); + /*ppp_panic("Excess Bad Logins");*/ + } + if (attempts > 3) { + /* @todo: this was sleep(), i.e. seconds, not milliseconds + * I don't think we really need this in lwIP - we would block tcpip_thread! + */ + /*sys_msleep((attempts - 3) * 5);*/ + } + if (addrs != NULL) { + free_wordlist(addrs); + } + } else { + attempts = 0; /* Reset count */ + if (*msg == (char *) 0) { + *msg = "Login ok"; + } + *msglen = os_strlen(*msg); + set_allowed_addrs(unit, addrs); + } + + BZERO(passwd, sizeof(passwd)); + BZERO(secret, sizeof(secret)); + + return ret; +#endif +} +#endif /* PAP_SUPPORT */ + +#if 0 /* UNUSED */ +/* + * This function is needed for PAM. + */ + +#ifdef USE_PAM + +/* lwip does not support PAM*/ + +#endif /* USE_PAM */ + +#endif /* UNUSED */ + + +#if 0 /* UNUSED */ +/* + * plogin - Check the user name and password against the system + * password database, and login the user if OK. + * + * returns: + * UPAP_AUTHNAK: Login failed. + * UPAP_AUTHACK: Login succeeded. + * In either case, msg points to an appropriate message. + */ +static int +plogin(char *user, char *passwd, char **msg, int *msglen) +{ + + LWIP_UNUSED_ARG(user); + LWIP_UNUSED_ARG(passwd); + LWIP_UNUSED_ARG(msg); + LWIP_UNUSED_ARG(msglen); + + + /* The new lines are here align the file when + * compared against the pppd 2.3.11 code */ + + + + + + + + + + + + + + + + + /* XXX Fail until we decide that we want to support logins. */ + return (UPAP_AUTHNAK); +} +#endif + + + +/* + * plogout - Logout the user. + */ +static void +plogout(void) +{ + logged_in = 0; +} + +/* + * 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(int unit) +{ + LWIP_UNUSED_ARG(unit); + /* XXX Fail until we decide that we want to support logins. */ + return 0; +} + + +/* + * 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. + */ +static int +get_pap_passwd(int unit, char *user, char *passwd) +{ + LWIP_UNUSED_ARG(unit); +/* normally we would reject PAP if no password is provided, + but this causes problems with some providers (like CHT in Taiwan) + who incorrectly request PAP and expect a bogus/empty password, so + always provide a default user/passwd of "none"/"none" + + @todo: This should be configured by the user, instead of being hardcoded here! +*/ + if(user) { + strcpy(user, "none"); + } + if(passwd) { + strcpy(passwd, "none"); + } + 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(void) +{ + /* XXX Fail until we set up our passwords. */ + return 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(char *client, char *server, u32_t remote) +{ + LWIP_UNUSED_ARG(client); + LWIP_UNUSED_ARG(server); + LWIP_UNUSED_ARG(remote); + + /* XXX Fail until we set up our passwords. */ + return 0; +} +#if CHAP_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(int unit, char *client, char *server, char *secret, int *secret_len, int save_addrs) +{ +#if 1 + int len; + struct wordlist *addrs; + + LWIP_UNUSED_ARG(unit); + LWIP_UNUSED_ARG(server); + LWIP_UNUSED_ARG(save_addrs); + + addrs = NULL; + + if(!client || !client[0] || os_strcmp(client, ppp_settings.user)) { + return 0; + } + + len = (int)os_strlen(ppp_settings.passwd); + if (len > MAXSECRETLEN) { + AUTHDEBUG(LOG_ERR, ("Secret for %s on %s is too long\n", client, server)); + len = MAXSECRETLEN; + } + + BCOPY(ppp_settings.passwd, secret, len); + *secret_len = len; + + return 1; +#else + int ret = 0, len; + struct wordlist *addrs; + char secbuf[MAXWORDLEN]; + + addrs = NULL; + secbuf[0] = 0; + + /* XXX Find secret. */ + if (ret < 0) { + return 0; + } + + if (save_addrs) { + set_allowed_addrs(unit, addrs); + } + + len = os_strlen(secbuf); + if (len > MAXSECRETLEN) { + AUTHDEBUG(LOG_ERR, ("Secret for %s on %s is too long\n", client, server)); + len = MAXSECRETLEN; + } + + BCOPY(secbuf, secret, len); + BZERO(secbuf, sizeof(secbuf)); + *secret_len = len; + + return 1; +#endif +} +#endif /* CHAP_SUPPORT */ + + +#if 0 /* PAP_SUPPORT || CHAP_SUPPORT */ +/* + * set_allowed_addrs() - set the list of allowed addresses. + */ +static void +set_allowed_addrs(int unit, struct wordlist *addrs) +{ + if (addresses[unit] != NULL) { + free_wordlist(addresses[unit]); + } + addresses[unit] = addrs; + +#if 0 + /* + * If there's only one authorized address we might as well + * ask our peer for that one right away + */ + if (addrs != NULL && addrs->next == NULL) { + char *p = addrs->word; + struct ipcp_options *wo = &ipcp_wantoptions[unit]; + u32_t a; + struct hostent *hp; + + if (wo->hisaddr == 0 && *p != '!' && *p != '-' && strchr(p, '/') == NULL) { + hp = gethostbyname(p); + if (hp != NULL && hp->h_addrtype == AF_INET) { + a = *(u32_t *)hp->h_addr; + } else { + a = inet_addr(p); + } + if (a != (u32_t) -1) { + wo->hisaddr = a; + } + } + } +#endif +} +#endif /* 0 */ /* PAP_SUPPORT || CHAP_SUPPORT */ + +/* + * 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(int unit, u32_t addr) +{ + return ip_addr_check(addr, addresses[unit]); +} + +static int /* @todo: integrate this funtion into auth_ip_addr()*/ +ip_addr_check(u32_t addr, struct wordlist *addrs) +{ + /* don't allow loopback or multicast address */ + if (bad_ip_adrs(addr)) { + return 0; + } + + if (addrs == NULL) { + return !ppp_settings.auth_required; /* no addresses authorized */ + } + + /* XXX All other addresses allowed. */ + return 1; +} + +/* + * 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(u32_t addr) +{ + addr = ntohl(addr); + return (addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET + || IN_MULTICAST(addr) || IN_BADCLASS(addr); +} + +#if 0 /* UNUSED */ /* PAP_SUPPORT || CHAP_SUPPORT */ +/* + * some_ip_ok - check a wordlist to see if it authorizes any + * IP address(es). + */ +static int +some_ip_ok(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; +} + +/* + * check_access - complain if a secret file has too-liberal permissions. + */ +static void +check_access(FILE *f, char *filename) +{ + struct stat sbuf; + + if (fstat(fileno(f), &sbuf) < 0) { + warn("cannot stat secret file %s: %m", filename); + } else if ((sbuf.st_mode & (S_IRWXG | S_IRWXO)) != 0) { + 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. + */ +static int +scan_authfile(FILE *f, char *client, char *server, char *secret, struct wordlist **addrs, struct wordlist **opts, char *filename) +{ + /* We do not (currently) need this in lwip */ + return 0; /* dummy */ +} +/* + * free_wordlist - release memory allocated for a wordlist. + */ +static void +free_wordlist(struct wordlist *wp) +{ + struct wordlist *next; + + while (wp != NULL) { + next = wp->next; + free(wp); + wp = next; + } +} + +/* + * auth_script_done - called when the auth-up or auth-down script + * has finished. + */ +static void +auth_script_done(void *arg) +{ + auth_script_pid = 0; + switch (auth_script_state) { + case s_up: + if (auth_state == s_down) { + auth_script_state = s_down; + auth_script(_PATH_AUTHDOWN); + } + break; + case s_down: + if (auth_state == s_up) { + auth_script_state = s_up; + auth_script(_PATH_AUTHUP); + } + break; + } +} + +/* + * auth_script - execute a script with arguments + * interface-name peer-name real-user tty speed + */ +static void +auth_script(char *script) +{ + char strspeed[32]; + struct passwd *pw; + char struid[32]; + char *user_name; + char *argv[8]; + + if ((pw = getpwuid(getuid())) != NULL && pw->pw_name != NULL) + user_name = pw->pw_name; + else { + slprintf(struid, sizeof(struid), "%d", getuid()); + user_name = struid; + } + slprintf(strspeed, sizeof(strspeed), "%d", baud_rate); + + argv[0] = script; + argv[1] = ifname; + argv[2] = peer_authname; + argv[3] = user_name; + argv[4] = devnam; + argv[5] = strspeed; + argv[6] = NULL; + + auth_script_pid = run_program(script, argv, 0, auth_script_done, NULL); +} +#endif /* 0 */ /* PAP_SUPPORT || CHAP_SUPPORT */ +#endif /* PPP_SUPPORT */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/auth.h b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/auth.h new file mode 100644 index 0000000..a8069ec --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/auth.h @@ -0,0 +1,111 @@ +/***************************************************************************** +* auth.h - PPP Authentication and phase control header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions 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. +* 97-12-04 Guy Lancaster , Global Election Systems Inc. +* Original derived from BSD pppd.h. +*****************************************************************************/ +/* + * pppd.h - PPP daemon global declarations. + * + * 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#ifndef AUTH_H +#define AUTH_H + +/*********************** +*** PUBLIC FUNCTIONS *** +***********************/ + +/* we are starting to use the link */ +void link_required (int); + +/* we are finished with the link */ +void link_terminated (int); + +/* the LCP layer has left the Opened state */ +void link_down (int); + +/* the link is up; authenticate now */ +void link_established (int); + +/* a network protocol has come up */ +void np_up (int, u16_t); + +/* a network protocol has gone down */ +void np_down (int, u16_t); + +/* a network protocol no longer needs link */ +void np_finished (int, u16_t); + +/* peer failed to authenticate itself */ +void auth_peer_fail (int, u16_t); + +/* peer successfully authenticated itself */ +void auth_peer_success (int, u16_t, char *, int); + +/* we failed to authenticate ourselves */ +void auth_withpeer_fail (int, u16_t); + +/* we successfully authenticated ourselves */ +void auth_withpeer_success (int, u16_t); + +/* check authentication options supplied */ +void auth_check_options (void); + +/* check what secrets we have */ +void auth_reset (int); + +/* Check peer-supplied username/password */ +u_char check_passwd (int, char *, int, char *, int, char **, int *); + +/* get "secret" for chap */ +int get_secret (int, char *, char *, char *, int *, int); + +/* check if IP address is authorized */ +int auth_ip_addr (int, u32_t); + +/* check if IP address is unreasonable */ +int bad_ip_adrs (u32_t); + +#endif /* AUTH_H */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/chap.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/chap.c new file mode 100644 index 0000000..76e57db --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/chap.c @@ -0,0 +1,908 @@ +/*** WARNING - THIS HAS NEVER BEEN FINISHED ***/ +/***************************************************************************** +* chap.c - Network Challenge Handshake Authentication 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-12-04 Guy Lancaster , Global Election Systems Inc. +* Original based on BSD chap.c. +*****************************************************************************/ +/* + * chap.c - Challenge Handshake Authentication Protocol. + * + * Copyright (c) 1993 The Australian National 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 the Australian National 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Copyright (c) 1991 Gregory M. Christy. + * 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 Gregory M. Christy. The name of the author 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. + */ + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#if CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "ppp_impl.h" +#include "pppdebug.h" + +#include "magic.h" +#include "randm.h" +#include "auth.h" +#include "md5.h" +#include "chap.h" +#include "chpms.h" + +#include + +#if 0 /* UNUSED */ +/* + * Command-line options. + */ +static option_t chap_option_list[] = { + { "chap-restart", o_int, &chap[0].timeouttime, + "Set timeout for CHAP" }, + { "chap-max-challenge", o_int, &chap[0].max_transmits, + "Set max #xmits for challenge" }, + { "chap-interval", o_int, &chap[0].chal_interval, + "Set interval for rechallenge" }, +#ifdef MSLANMAN + { "ms-lanman", o_bool, &ms_lanman, + "Use LanMan passwd when using MS-CHAP", 1 }, +#endif + { NULL } +}; +#endif /* UNUSED */ + +/* + * Protocol entry points. + */ +static void ChapInit (int); +static void ChapLowerUp (int); +static void ChapLowerDown (int); +static void ChapInput (int, u_char *, int); +static void ChapProtocolReject (int); +#if PPP_ADDITIONAL_CALLBACKS +static int ChapPrintPkt (u_char *, int, void (*) (void *, char *, ...), void *); +#endif + +struct protent chap_protent = { + PPP_CHAP, + ChapInit, + ChapInput, + ChapProtocolReject, + ChapLowerUp, + ChapLowerDown, + NULL, + NULL, +#if PPP_ADDITIONAL_CALLBACKS + ChapPrintPkt, + NULL, +#endif /* PPP_ADDITIONAL_CALLBACKS */ + 1, + "CHAP", +#if PPP_ADDITIONAL_CALLBACKS + NULL, + NULL, + NULL +#endif /* PPP_ADDITIONAL_CALLBACKS */ +}; + +chap_state chap[NUM_PPP]; /* CHAP state; one for each unit */ + +static void ChapChallengeTimeout (void *); +static void ChapResponseTimeout (void *); +static void ChapReceiveChallenge (chap_state *, u_char *, u_char, int); +static void ChapRechallenge (void *); +static void ChapReceiveResponse (chap_state *, u_char *, int, int); +static void ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len); +static void ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len); +static void ChapSendStatus (chap_state *, int); +static void ChapSendChallenge (chap_state *); +static void ChapSendResponse (chap_state *); +static void ChapGenChallenge (chap_state *); + +/* + * ChapInit - Initialize a CHAP unit. + */ +static void +ChapInit(int unit) +{ + chap_state *cstate = &chap[unit]; + + BZERO(cstate, sizeof(*cstate)); + cstate->unit = unit; + cstate->clientstate = CHAPCS_INITIAL; + cstate->serverstate = CHAPSS_INITIAL; + cstate->timeouttime = CHAP_DEFTIMEOUT; + cstate->max_transmits = CHAP_DEFTRANSMITS; + /* random number generator is initialized in magic_init */ +} + + +/* + * ChapAuthWithPeer - Authenticate us with our peer (start client). + * + */ +void +ChapAuthWithPeer(int unit, char *our_name, u_char digest) +{ + chap_state *cstate = &chap[unit]; + + cstate->resp_name = our_name; + cstate->resp_type = digest; + + if (cstate->clientstate == CHAPCS_INITIAL || + cstate->clientstate == CHAPCS_PENDING) { + /* lower layer isn't up - wait until later */ + cstate->clientstate = CHAPCS_PENDING; + return; + } + + /* + * We get here as a result of LCP coming up. + * So even if CHAP was open before, we will + * have to re-authenticate ourselves. + */ + cstate->clientstate = CHAPCS_LISTEN; +} + + +/* + * ChapAuthPeer - Authenticate our peer (start server). + */ +void +ChapAuthPeer(int unit, char *our_name, u_char digest) +{ + chap_state *cstate = &chap[unit]; + + cstate->chal_name = our_name; + cstate->chal_type = digest; + + if (cstate->serverstate == CHAPSS_INITIAL || + cstate->serverstate == CHAPSS_PENDING) { + /* lower layer isn't up - wait until later */ + cstate->serverstate = CHAPSS_PENDING; + return; + } + + ChapGenChallenge(cstate); + ChapSendChallenge(cstate); /* crank it up dude! */ + cstate->serverstate = CHAPSS_INITIAL_CHAL; +} + + +/* + * ChapChallengeTimeout - Timeout expired on sending challenge. + */ +static void +ChapChallengeTimeout(void *arg) +{ + chap_state *cstate = (chap_state *) arg; + + /* if we aren't sending challenges, don't worry. then again we */ + /* probably shouldn't be here either */ + if (cstate->serverstate != CHAPSS_INITIAL_CHAL && + cstate->serverstate != CHAPSS_RECHALLENGE) { + return; + } + + if (cstate->chal_transmits >= cstate->max_transmits) { + /* give up on peer */ + CHAPDEBUG(LOG_ERR, ("Peer failed to respond to CHAP challenge\n")); + cstate->serverstate = CHAPSS_BADAUTH; + auth_peer_fail(cstate->unit, PPP_CHAP); + return; + } + + ChapSendChallenge(cstate); /* Re-send challenge */ +} + + +/* + * ChapResponseTimeout - Timeout expired on sending response. + */ +static void +ChapResponseTimeout(void *arg) +{ + chap_state *cstate = (chap_state *) arg; + + /* if we aren't sending a response, don't worry. */ + if (cstate->clientstate != CHAPCS_RESPONSE) { + return; + } + + ChapSendResponse(cstate); /* re-send response */ +} + + +/* + * ChapRechallenge - Time to challenge the peer again. + */ +static void +ChapRechallenge(void *arg) +{ + chap_state *cstate = (chap_state *) arg; + + /* if we aren't sending a response, don't worry. */ + if (cstate->serverstate != CHAPSS_OPEN) { + return; + } + + ChapGenChallenge(cstate); + ChapSendChallenge(cstate); + cstate->serverstate = CHAPSS_RECHALLENGE; +} + + +/* + * ChapLowerUp - The lower layer is up. + * + * Start up if we have pending requests. + */ +static void +ChapLowerUp(int unit) +{ + chap_state *cstate = &chap[unit]; + + if (cstate->clientstate == CHAPCS_INITIAL) { + cstate->clientstate = CHAPCS_CLOSED; + } else if (cstate->clientstate == CHAPCS_PENDING) { + cstate->clientstate = CHAPCS_LISTEN; + } + + if (cstate->serverstate == CHAPSS_INITIAL) { + cstate->serverstate = CHAPSS_CLOSED; + } else if (cstate->serverstate == CHAPSS_PENDING) { + ChapGenChallenge(cstate); + ChapSendChallenge(cstate); + cstate->serverstate = CHAPSS_INITIAL_CHAL; + } +} + + +/* + * ChapLowerDown - The lower layer is down. + * + * Cancel all timeouts. + */ +static void +ChapLowerDown(int unit) +{ + chap_state *cstate = &chap[unit]; + + /* Timeout(s) pending? Cancel if so. */ + if (cstate->serverstate == CHAPSS_INITIAL_CHAL || + cstate->serverstate == CHAPSS_RECHALLENGE) { + UNTIMEOUT(ChapChallengeTimeout, cstate); + } else if (cstate->serverstate == CHAPSS_OPEN + && cstate->chal_interval != 0) { + UNTIMEOUT(ChapRechallenge, cstate); + } + if (cstate->clientstate == CHAPCS_RESPONSE) { + UNTIMEOUT(ChapResponseTimeout, cstate); + } + cstate->clientstate = CHAPCS_INITIAL; + cstate->serverstate = CHAPSS_INITIAL; +} + + +/* + * ChapProtocolReject - Peer doesn't grok CHAP. + */ +static void +ChapProtocolReject(int unit) +{ + chap_state *cstate = &chap[unit]; + + if (cstate->serverstate != CHAPSS_INITIAL && + cstate->serverstate != CHAPSS_CLOSED) { + auth_peer_fail(unit, PPP_CHAP); + } + if (cstate->clientstate != CHAPCS_INITIAL && + cstate->clientstate != CHAPCS_CLOSED) { + auth_withpeer_fail(unit, PPP_CHAP); /* lwip: just sets the PPP error code on this unit to PPPERR_AUTHFAIL */ + } + ChapLowerDown(unit); /* shutdown chap */ +} + + +/* + * ChapInput - Input CHAP packet. + */ +static void +ChapInput(int unit, u_char *inpacket, int packet_len) +{ + chap_state *cstate = &chap[unit]; + u_char *inp; + u_char code, id; + int len; + + /* + * Parse header (code, id and length). + * If packet too short, drop it. + */ + inp = inpacket; + if (packet_len < CHAP_HEADERLEN) { + CHAPDEBUG(LOG_INFO, ("ChapInput: rcvd short header.\n")); + return; + } + GETCHAR(code, inp); + GETCHAR(id, inp); + GETSHORT(len, inp); + if (len < CHAP_HEADERLEN) { + CHAPDEBUG(LOG_INFO, ("ChapInput: rcvd illegal length.\n")); + return; + } + if (len > packet_len) { + CHAPDEBUG(LOG_INFO, ("ChapInput: rcvd short packet.\n")); + return; + } + len -= CHAP_HEADERLEN; + + /* + * Action depends on code (as in fact it usually does :-). + */ + switch (code) { + case CHAP_CHALLENGE: + ChapReceiveChallenge(cstate, inp, id, len); + break; + + case CHAP_RESPONSE: + ChapReceiveResponse(cstate, inp, id, len); + break; + + case CHAP_FAILURE: + ChapReceiveFailure(cstate, inp, id, len); + break; + + case CHAP_SUCCESS: + ChapReceiveSuccess(cstate, inp, id, len); + break; + + default: /* Need code reject? */ + CHAPDEBUG(LOG_WARNING, ("Unknown CHAP code (%d) received.\n", code)); + break; + } +} + + +/* + * ChapReceiveChallenge - Receive Challenge and send Response. + */ +static void +ChapReceiveChallenge(chap_state *cstate, u_char *inp, u_char id, int len) +{ + int rchallenge_len; + u_char *rchallenge; + int secret_len; + char secret[MAXSECRETLEN]; + char rhostname[256]; + MD5_CTX mdContext; + u_char hash[MD5_SIGNATURE_SIZE]; + + CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: Rcvd id %d.\n", id)); + if (cstate->clientstate == CHAPCS_CLOSED || + cstate->clientstate == CHAPCS_PENDING) { + CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: in state %d\n", + cstate->clientstate)); + return; + } + + if (len < 2) { + CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: rcvd short packet.\n")); + return; + } + + GETCHAR(rchallenge_len, inp); + len -= sizeof (u_char) + rchallenge_len; /* now name field length */ + if (len < 0) { + CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: rcvd short packet.\n")); + return; + } + rchallenge = inp; + INCPTR(rchallenge_len, inp); + + if (len >= (int)sizeof(rhostname)) { + len = sizeof(rhostname) - 1; + } + BCOPY(inp, rhostname, len); + rhostname[len] = '\000'; + + CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: received name field '%s'\n", + rhostname)); + + /* Microsoft doesn't send their name back in the PPP packet */ + if (ppp_settings.remote_name[0] != 0 && (ppp_settings.explicit_remote || rhostname[0] == 0)) { + strncpy(rhostname, ppp_settings.remote_name, sizeof(rhostname)); + rhostname[sizeof(rhostname) - 1] = 0; + CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: using '%s' as remote name\n", + rhostname)); + } + + /* get secret for authenticating ourselves with the specified host */ + if (!get_secret(cstate->unit, cstate->resp_name, rhostname, + secret, &secret_len, 0)) { + secret_len = 0; /* assume null secret if can't find one */ + CHAPDEBUG(LOG_WARNING, ("No CHAP secret found for authenticating us to %s\n", + rhostname)); + } + + /* cancel response send timeout if necessary */ + if (cstate->clientstate == CHAPCS_RESPONSE) { + UNTIMEOUT(ChapResponseTimeout, cstate); + } + + cstate->resp_id = id; + cstate->resp_transmits = 0; + + /* generate MD based on negotiated type */ + switch (cstate->resp_type) { + + case CHAP_DIGEST_MD5: + MD5Init(&mdContext); + MD5Update(&mdContext, &cstate->resp_id, 1); + MD5Update(&mdContext, (u_char*)secret, secret_len); + MD5Update(&mdContext, rchallenge, rchallenge_len); + MD5Final(hash, &mdContext); + BCOPY(hash, cstate->response, MD5_SIGNATURE_SIZE); + cstate->resp_length = MD5_SIGNATURE_SIZE; + break; + +#if MSCHAP_SUPPORT + case CHAP_MICROSOFT: + ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len); + break; +#endif + + default: + CHAPDEBUG(LOG_INFO, ("unknown digest type %d\n", cstate->resp_type)); + return; + } + + BZERO(secret, sizeof(secret)); + ChapSendResponse(cstate); +} + + +/* + * ChapReceiveResponse - Receive and process response. + */ +static void +ChapReceiveResponse(chap_state *cstate, u_char *inp, int id, int len) +{ + u_char *remmd, remmd_len; + int secret_len, old_state; + int code; + char rhostname[256]; + MD5_CTX mdContext; + char secret[MAXSECRETLEN]; + u_char hash[MD5_SIGNATURE_SIZE]; + + CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: Rcvd id %d.\n", id)); + + if (cstate->serverstate == CHAPSS_CLOSED || + cstate->serverstate == CHAPSS_PENDING) { + CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: in state %d\n", + cstate->serverstate)); + return; + } + + if (id != cstate->chal_id) { + return; /* doesn't match ID of last challenge */ + } + + /* + * If we have received a duplicate or bogus Response, + * we have to send the same answer (Success/Failure) + * as we did for the first Response we saw. + */ + if (cstate->serverstate == CHAPSS_OPEN) { + ChapSendStatus(cstate, CHAP_SUCCESS); + return; + } + if (cstate->serverstate == CHAPSS_BADAUTH) { + ChapSendStatus(cstate, CHAP_FAILURE); + return; + } + + if (len < 2) { + CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: rcvd short packet.\n")); + return; + } + GETCHAR(remmd_len, inp); /* get length of MD */ + remmd = inp; /* get pointer to MD */ + INCPTR(remmd_len, inp); + + len -= sizeof (u_char) + remmd_len; + if (len < 0) { + CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: rcvd short packet.\n")); + return; + } + + UNTIMEOUT(ChapChallengeTimeout, cstate); + + if (len >= (int)sizeof(rhostname)) { + len = sizeof(rhostname) - 1; + } + BCOPY(inp, rhostname, len); + rhostname[len] = '\000'; + + CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: received name field: %s\n", + rhostname)); + + /* + * Get secret for authenticating them with us, + * do the hash ourselves, and compare the result. + */ + code = CHAP_FAILURE; + if (!get_secret(cstate->unit, rhostname, cstate->chal_name, + secret, &secret_len, 1)) { + CHAPDEBUG(LOG_WARNING, ("No CHAP secret found for authenticating %s\n", + rhostname)); + } else { + /* generate MD based on negotiated type */ + switch (cstate->chal_type) { + + case CHAP_DIGEST_MD5: /* only MD5 is defined for now */ + if (remmd_len != MD5_SIGNATURE_SIZE) { + break; /* it's not even the right length */ + } + MD5Init(&mdContext); + MD5Update(&mdContext, &cstate->chal_id, 1); + MD5Update(&mdContext, (u_char*)secret, secret_len); + MD5Update(&mdContext, cstate->challenge, cstate->chal_len); + MD5Final(hash, &mdContext); + + /* compare local and remote MDs and send the appropriate status */ + if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0) { + code = CHAP_SUCCESS; /* they are the same! */ + } + break; + + default: + CHAPDEBUG(LOG_INFO, ("unknown digest type %d\n", cstate->chal_type)); + } + } + + BZERO(secret, sizeof(secret)); + ChapSendStatus(cstate, code); + + if (code == CHAP_SUCCESS) { + old_state = cstate->serverstate; + cstate->serverstate = CHAPSS_OPEN; + if (old_state == CHAPSS_INITIAL_CHAL) { + auth_peer_success(cstate->unit, PPP_CHAP, rhostname, len); + } + if (cstate->chal_interval != 0) { + TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval); + } + } else { + CHAPDEBUG(LOG_ERR, ("CHAP peer authentication failed\n")); + cstate->serverstate = CHAPSS_BADAUTH; + auth_peer_fail(cstate->unit, PPP_CHAP); + } +} + +/* + * ChapReceiveSuccess - Receive Success + */ +static void +ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len) +{ + LWIP_UNUSED_ARG(id); + LWIP_UNUSED_ARG(inp); + + CHAPDEBUG(LOG_INFO, ("ChapReceiveSuccess: Rcvd id %d.\n", id)); + + if (cstate->clientstate == CHAPCS_OPEN) { + /* presumably an answer to a duplicate response */ + return; + } + + if (cstate->clientstate != CHAPCS_RESPONSE) { + /* don't know what this is */ + CHAPDEBUG(LOG_INFO, ("ChapReceiveSuccess: in state %d\n", + cstate->clientstate)); + return; + } + + UNTIMEOUT(ChapResponseTimeout, cstate); + + /* + * Print message. + */ + if (len > 0) { + PRINTMSG(inp, len); + } + + cstate->clientstate = CHAPCS_OPEN; + + auth_withpeer_success(cstate->unit, PPP_CHAP); +} + + +/* + * ChapReceiveFailure - Receive failure. + */ +static void +ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len) +{ + LWIP_UNUSED_ARG(id); + LWIP_UNUSED_ARG(inp); + + CHAPDEBUG(LOG_INFO, ("ChapReceiveFailure: Rcvd id %d.\n", id)); + + if (cstate->clientstate != CHAPCS_RESPONSE) { + /* don't know what this is */ + CHAPDEBUG(LOG_INFO, ("ChapReceiveFailure: in state %d\n", + cstate->clientstate)); + return; + } + + UNTIMEOUT(ChapResponseTimeout, cstate); + + /* + * Print message. + */ + if (len > 0) { + PRINTMSG(inp, len); + } + + CHAPDEBUG(LOG_ERR, ("CHAP authentication failed\n")); + auth_withpeer_fail(cstate->unit, PPP_CHAP); /* lwip: just sets the PPP error code on this unit to PPPERR_AUTHFAIL */ +} + + +/* + * ChapSendChallenge - Send an Authenticate challenge. + */ +static void +ChapSendChallenge(chap_state *cstate) +{ + u_char *outp; + int chal_len, name_len; + int outlen; + + chal_len = cstate->chal_len; + name_len = (int)os_strlen(cstate->chal_name); + outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len; + outp = outpacket_buf[cstate->unit]; + + MAKEHEADER(outp, PPP_CHAP); /* paste in a CHAP header */ + + PUTCHAR(CHAP_CHALLENGE, outp); + PUTCHAR(cstate->chal_id, outp); + PUTSHORT(outlen, outp); + + PUTCHAR(chal_len, outp); /* put length of challenge */ + BCOPY(cstate->challenge, outp, chal_len); + INCPTR(chal_len, outp); + + BCOPY(cstate->chal_name, outp, name_len); /* append hostname */ + + pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN); + + CHAPDEBUG(LOG_INFO, ("ChapSendChallenge: Sent id %d.\n", cstate->chal_id)); + + TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime); + ++cstate->chal_transmits; +} + + +/* + * ChapSendStatus - Send a status response (ack or nak). + */ +static void +ChapSendStatus(chap_state *cstate, int code) +{ + u_char *outp; + int outlen, msglen; + char msg[256]; /* @todo: this can be a char*, no strcpy needed */ + + if (code == CHAP_SUCCESS) { + strcpy(msg, "Welcome!"); + } else { + strcpy(msg, "I don't like you. Go 'way."); + } + msglen = (int)os_strlen(msg); + + outlen = CHAP_HEADERLEN + msglen; + outp = outpacket_buf[cstate->unit]; + + MAKEHEADER(outp, PPP_CHAP); /* paste in a header */ + + PUTCHAR(code, outp); + PUTCHAR(cstate->chal_id, outp); + PUTSHORT(outlen, outp); + BCOPY(msg, outp, msglen); + pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN); + + CHAPDEBUG(LOG_INFO, ("ChapSendStatus: Sent code %d, id %d.\n", code, + cstate->chal_id)); +} + +/* + * ChapGenChallenge is used to generate a pseudo-random challenge string of + * a pseudo-random length between min_len and max_len. The challenge + * string and its length are stored in *cstate, and various other fields of + * *cstate are initialized. + */ + +static void +ChapGenChallenge(chap_state *cstate) +{ + int chal_len; + u_char *ptr = cstate->challenge; + int i; + + /* pick a random challenge length between MIN_CHALLENGE_LENGTH and + MAX_CHALLENGE_LENGTH */ + chal_len = (unsigned) + ((((magic() >> 16) * + (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) >> 16) + + MIN_CHALLENGE_LENGTH); + LWIP_ASSERT("chal_len <= 0xff", chal_len <= 0xffff); + cstate->chal_len = (u_char)chal_len; + cstate->chal_id = ++cstate->id; + cstate->chal_transmits = 0; + + /* generate a random string */ + for (i = 0; i < chal_len; i++ ) { + *ptr++ = (char) (magic() & 0xff); + } +} + +/* + * ChapSendResponse - send a response packet with values as specified + * in *cstate. + */ +/* ARGSUSED */ +static void +ChapSendResponse(chap_state *cstate) +{ + u_char *outp; + int outlen, md_len, name_len; + + md_len = cstate->resp_length; + name_len = (int)os_strlen(cstate->resp_name); + outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len; + outp = outpacket_buf[cstate->unit]; + + MAKEHEADER(outp, PPP_CHAP); + + PUTCHAR(CHAP_RESPONSE, outp); /* we are a response */ + PUTCHAR(cstate->resp_id, outp); /* copy id from challenge packet */ + PUTSHORT(outlen, outp); /* packet length */ + + PUTCHAR(md_len, outp); /* length of MD */ + BCOPY(cstate->response, outp, md_len); /* copy MD to buffer */ + INCPTR(md_len, outp); + + BCOPY(cstate->resp_name, outp, name_len); /* append our name */ + + /* send the packet */ + pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN); + + cstate->clientstate = CHAPCS_RESPONSE; + TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime); + ++cstate->resp_transmits; +} + +#if PPP_ADDITIONAL_CALLBACKS +static char *ChapCodenames[] = { + "Challenge", "Response", "Success", "Failure" +}; +/* + * ChapPrintPkt - print the contents of a CHAP packet. + */ +static int +ChapPrintPkt( u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg) +{ + int code, id, len; + int clen, nlen; + u_char x; + + if (plen < CHAP_HEADERLEN) { + return 0; + } + GETCHAR(code, p); + GETCHAR(id, p); + GETSHORT(len, p); + if (len < CHAP_HEADERLEN || len > plen) { + return 0; + } + + if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *)) { + printer(arg, " %s", ChapCodenames[code-1]); + } else { + printer(arg, " code=0x%x", code); + } + printer(arg, " id=0x%x", id); + len -= CHAP_HEADERLEN; + 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 = %.*Z", nlen, p); + break; + case CHAP_FAILURE: + case CHAP_SUCCESS: + printer(arg, " %.*Z", len, p); + break; + default: + for (clen = len; clen > 0; --clen) { + GETCHAR(x, p); + printer(arg, " %.2x", x); + } + } + + return len + CHAP_HEADERLEN; +} +#endif /* PPP_ADDITIONAL_CALLBACKS */ + +#endif /* CHAP_SUPPORT */ + +#endif /* PPP_SUPPORT */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/chap.h b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/chap.h new file mode 100644 index 0000000..fedcab8 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/chap.h @@ -0,0 +1,150 @@ +/***************************************************************************** +* chap.h - Network Challenge Handshake Authentication Protocol header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions 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. +* 97-12-03 Guy Lancaster , Global Election Systems Inc. +* Original built from BSD network code. +******************************************************************************/ +/* + * chap.h - Challenge Handshake Authentication Protocol definitions. + * + * Copyright (c) 1993 The Australian National 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 the Australian National 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Copyright (c) 1991 Gregory M. Christy + * 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 author. + * + * 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. + * + * $Id: chap.h,v 1.6 2010/01/24 13:19:34 goldsimon Exp $ + */ + +#ifndef CHAP_H +#define CHAP_H + +/* Code + ID + length */ +#define CHAP_HEADERLEN 4 + +/* + * CHAP codes. + */ + +#define CHAP_DIGEST_MD5 5 /* use MD5 algorithm */ +#define MD5_SIGNATURE_SIZE 16 /* 16 bytes in a MD5 message digest */ +#define CHAP_MICROSOFT 0x80 /* use Microsoft-compatible alg. */ +#define MS_CHAP_RESPONSE_LEN 49 /* Response length for MS-CHAP */ + +#define CHAP_CHALLENGE 1 +#define CHAP_RESPONSE 2 +#define CHAP_SUCCESS 3 +#define CHAP_FAILURE 4 + +/* + * Challenge lengths (for challenges we send) and other limits. + */ +#define MIN_CHALLENGE_LENGTH 32 +#define MAX_CHALLENGE_LENGTH 64 +#define MAX_RESPONSE_LENGTH 64 /* sufficient for MD5 or MS-CHAP */ + +/* + * Each interface is described by a chap structure. + */ + +typedef struct chap_state { + int unit; /* Interface unit number */ + int clientstate; /* Client state */ + int serverstate; /* Server state */ + u_char challenge[MAX_CHALLENGE_LENGTH]; /* last challenge string sent */ + u_char chal_len; /* challenge length */ + u_char chal_id; /* ID of last challenge */ + u_char chal_type; /* hash algorithm for challenges */ + u_char id; /* Current id */ + char *chal_name; /* Our name to use with challenge */ + int chal_interval; /* Time until we challenge peer again */ + int timeouttime; /* Timeout time in seconds */ + int max_transmits; /* Maximum # of challenge transmissions */ + int chal_transmits; /* Number of transmissions of challenge */ + int resp_transmits; /* Number of transmissions of response */ + u_char response[MAX_RESPONSE_LENGTH]; /* Response to send */ + u_char resp_length; /* length of response */ + u_char resp_id; /* ID for response messages */ + u_char resp_type; /* hash algorithm for responses */ + char *resp_name; /* Our name to send with response */ +} chap_state; + + +/* + * Client (peer) states. + */ +#define CHAPCS_INITIAL 0 /* Lower layer down, not opened */ +#define CHAPCS_CLOSED 1 /* Lower layer up, not opened */ +#define CHAPCS_PENDING 2 /* Auth us to peer when lower up */ +#define CHAPCS_LISTEN 3 /* Listening for a challenge */ +#define CHAPCS_RESPONSE 4 /* Sent response, waiting for status */ +#define CHAPCS_OPEN 5 /* We've received Success */ + +/* + * Server (authenticator) states. + */ +#define CHAPSS_INITIAL 0 /* Lower layer down, not opened */ +#define CHAPSS_CLOSED 1 /* Lower layer up, not opened */ +#define CHAPSS_PENDING 2 /* Auth peer when lower up */ +#define CHAPSS_INITIAL_CHAL 3 /* We've sent the first challenge */ +#define CHAPSS_OPEN 4 /* We've sent a Success msg */ +#define CHAPSS_RECHALLENGE 5 /* We've sent another challenge */ +#define CHAPSS_BADAUTH 6 /* We've sent a Failure msg */ + +extern chap_state chap[]; + +void ChapAuthWithPeer (int, char *, u_char); +void ChapAuthPeer (int, char *, u_char); + +extern struct protent chap_protent; + +#endif /* CHAP_H */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/chpms.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/chpms.c new file mode 100644 index 0000000..81a887b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/chpms.c @@ -0,0 +1,396 @@ +/*** WARNING - THIS CODE HAS NOT BEEN FINISHED! ***/ +/*** The original PPPD code is written in a way to require either the UNIX DES + encryption functions encrypt(3) and setkey(3) or the DES library libdes. + Since both is not included in lwIP, MSCHAP currently does not work! */ +/***************************************************************************** +* chpms.c - Network MicroSoft Challenge Handshake Authentication Protocol program file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* Copyright (c) 1997 by Global Election Systems Inc. All rights reserved. +* +* 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-12-08 Guy Lancaster , Global Election Systems Inc. +* Original based on BSD chap_ms.c. +*****************************************************************************/ +/* + * chap_ms.c - Microsoft MS-CHAP compatible implementation. + * + * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited. + * http://www.strataware.com/ + * + * 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 Eric Rosenquist. The name of the author 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. + */ + +/* + * 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 + */ + +#define USE_CRYPT + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#if MSCHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "ppp_impl.h" +#include "pppdebug.h" + +#include "md4.h" +#ifndef USE_CRYPT +#include "des.h" +#endif +#include "chap.h" +#include "chpms.h" + +#include + + +/*************************/ +/*** LOCAL DEFINITIONS ***/ +/*************************/ + + +/************************/ +/*** LOCAL DATA TYPES ***/ +/************************/ +typedef struct { + u_char LANManResp[24]; + u_char NTResp[24]; + u_char UseNT; /* If 1, ignore the LANMan response field */ +} MS_ChapResponse; +/* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse), + in case this struct gets padded. */ + + + +/***********************************/ +/*** LOCAL FUNCTION DECLARATIONS ***/ +/***********************************/ + +/* XXX Don't know what to do with these. */ +extern void setkey(const char *); +extern void encrypt(char *, int); + +static void DesEncrypt (u_char *, u_char *, u_char *); +static void MakeKey (u_char *, u_char *); + +#ifdef USE_CRYPT +static void Expand (u_char *, u_char *); +static void Collapse (u_char *, u_char *); +#endif + +static void ChallengeResponse( + u_char *challenge, /* IN 8 octets */ + u_char *pwHash, /* IN 16 octets */ + u_char *response /* OUT 24 octets */ +); +static void ChapMS_NT( + char *rchallenge, + int rchallenge_len, + char *secret, + int secret_len, + MS_ChapResponse *response +); +static u_char Get7Bits( + u_char *input, + int startBit +); + +static void +ChallengeResponse( u_char *challenge, /* IN 8 octets */ + u_char *pwHash, /* IN 16 octets */ + u_char *response /* OUT 24 octets */) +{ + u_char ZPasswordHash[21]; + + BZERO(ZPasswordHash, sizeof(ZPasswordHash)); + BCOPY(pwHash, ZPasswordHash, 16); + +#if 0 + log_packet(ZPasswordHash, sizeof(ZPasswordHash), "ChallengeResponse - ZPasswordHash", LOG_DEBUG); +#endif + + DesEncrypt(challenge, ZPasswordHash + 0, response + 0); + DesEncrypt(challenge, ZPasswordHash + 7, response + 8); + DesEncrypt(challenge, ZPasswordHash + 14, response + 16); + +#if 0 + log_packet(response, 24, "ChallengeResponse - response", LOG_DEBUG); +#endif +} + + +#ifdef USE_CRYPT +static void +DesEncrypt( u_char *clear, /* IN 8 octets */ + u_char *key, /* IN 7 octets */ + u_char *cipher /* OUT 8 octets */) +{ + u_char des_key[8]; + u_char crypt_key[66]; + u_char des_input[66]; + + MakeKey(key, des_key); + + Expand(des_key, crypt_key); + setkey((char*)crypt_key); + +#if 0 + CHAPDEBUG(LOG_INFO, ("DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n", + clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7])); +#endif + + Expand(clear, des_input); + encrypt((char*)des_input, 0); + Collapse(des_input, cipher); + +#if 0 + CHAPDEBUG(LOG_INFO, ("DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n", + cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7])); +#endif +} + +#else /* USE_CRYPT */ + +static void +DesEncrypt( u_char *clear, /* IN 8 octets */ + u_char *key, /* IN 7 octets */ + u_char *cipher /* OUT 8 octets */) +{ + des_cblock des_key; + des_key_schedule key_schedule; + + MakeKey(key, des_key); + + des_set_key(&des_key, key_schedule); + +#if 0 + CHAPDEBUG(LOG_INFO, ("DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n", + clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7])); +#endif + + des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1); + +#if 0 + CHAPDEBUG(LOG_INFO, ("DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n", + cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7])); +#endif +} + +#endif /* USE_CRYPT */ + + +static u_char +Get7Bits( u_char *input, int startBit) +{ + register unsigned int word; + + word = (unsigned)input[startBit / 8] << 8; + word |= (unsigned)input[startBit / 8 + 1]; + + word >>= 15 - (startBit % 8 + 7); + + return word & 0xFE; +} + +#ifdef USE_CRYPT + +/* in == 8-byte string (expanded version of the 56-bit key) + * out == 64-byte string where each byte is either 1 or 0 + * Note that the low-order "bit" is always ignored by by setkey() + */ +static void +Expand(u_char *in, u_char *out) +{ + int j, c; + int i; + + for(i = 0; i < 64; in++){ + c = *in; + for(j = 7; j >= 0; j--) { + *out++ = (c >> j) & 01; + } + i += 8; + } +} + +/* The inverse of Expand + */ +static void +Collapse(u_char *in, u_char *out) +{ + int j; + int i; + unsigned int c; + + for (i = 0; i < 64; i += 8, out++) { + c = 0; + for (j = 7; j >= 0; j--, in++) { + c |= *in << j; + } + *out = c & 0xff; + } +} +#endif + +static void +MakeKey( u_char *key, /* IN 56 bit DES key missing parity bits */ + u_char *des_key /* OUT 64 bit DES key with parity bits added */) +{ + des_key[0] = Get7Bits(key, 0); + des_key[1] = Get7Bits(key, 7); + des_key[2] = Get7Bits(key, 14); + des_key[3] = Get7Bits(key, 21); + des_key[4] = Get7Bits(key, 28); + des_key[5] = Get7Bits(key, 35); + des_key[6] = Get7Bits(key, 42); + des_key[7] = Get7Bits(key, 49); + +#ifndef USE_CRYPT + des_set_odd_parity((des_cblock *)des_key); +#endif + +#if 0 + CHAPDEBUG(LOG_INFO, ("MakeKey: 56-bit input : %02X%02X%02X%02X%02X%02X%02X\n", + key[0], key[1], key[2], key[3], key[4], key[5], key[6])); + CHAPDEBUG(LOG_INFO, ("MakeKey: 64-bit output: %02X%02X%02X%02X%02X%02X%02X%02X\n", + des_key[0], des_key[1], des_key[2], des_key[3], des_key[4], des_key[5], des_key[6], des_key[7])); +#endif +} + +static void +ChapMS_NT( char *rchallenge, + int rchallenge_len, + char *secret, + int secret_len, + MS_ChapResponse *response) +{ + int i; + MDstruct md4Context; + u_char unicodePassword[MAX_NT_PASSWORD * 2]; + static int low_byte_first = -1; + + LWIP_UNUSED_ARG(rchallenge_len); + + /* Initialize the Unicode version of the secret (== password). */ + /* This implicitly supports 8-bit ISO8859/1 characters. */ + BZERO(unicodePassword, sizeof(unicodePassword)); + for (i = 0; i < secret_len; i++) { + unicodePassword[i * 2] = (u_char)secret[i]; + } + MDbegin(&md4Context); + MDupdate(&md4Context, unicodePassword, secret_len * 2 * 8); /* Unicode is 2 bytes/char, *8 for bit count */ + + if (low_byte_first == -1) { + low_byte_first = (PP_HTONS((unsigned short int)1) != 1); + } + if (low_byte_first == 0) { + /* @todo: arg type - u_long* or u_int* ? */ + MDreverse((unsigned int*)&md4Context); /* sfb 961105 */ + } + + MDupdate(&md4Context, NULL, 0); /* Tell MD4 we're done */ + + ChallengeResponse((u_char*)rchallenge, (u_char*)md4Context.buffer, response->NTResp); +} + +#ifdef MSLANMAN +static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */ + +static void +ChapMS_LANMan( char *rchallenge, + int rchallenge_len, + char *secret, + int secret_len, + MS_ChapResponse *response) +{ + int i; + u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */ + u_char PasswordHash[16]; + + /* LANMan password is case insensitive */ + BZERO(UcasePassword, sizeof(UcasePassword)); + for (i = 0; i < secret_len; i++) { + UcasePassword[i] = (u_char)toupper(secret[i]); + } + DesEncrypt( StdText, UcasePassword + 0, PasswordHash + 0 ); + DesEncrypt( StdText, UcasePassword + 7, PasswordHash + 8 ); + ChallengeResponse(rchallenge, PasswordHash, response->LANManResp); +} +#endif + +void +ChapMS( chap_state *cstate, char *rchallenge, int rchallenge_len, char *secret, int secret_len) +{ + MS_ChapResponse response; +#ifdef MSLANMAN + extern int ms_lanman; +#endif + +#if 0 + CHAPDEBUG(LOG_INFO, ("ChapMS: secret is '%.*s'\n", secret_len, secret)); +#endif + BZERO(&response, sizeof(response)); + + /* Calculate both always */ + ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response); + +#ifdef MSLANMAN + ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response); + + /* prefered method is set by option */ + response.UseNT = !ms_lanman; +#else + response.UseNT = 1; +#endif + + BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN); + cstate->resp_length = MS_CHAP_RESPONSE_LEN; +} + +#endif /* MSCHAP_SUPPORT */ + +#endif /* PPP_SUPPORT */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/chpms.h b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/chpms.h new file mode 100644 index 0000000..df070fb --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/chpms.h @@ -0,0 +1,64 @@ +/***************************************************************************** +* chpms.h - Network Microsoft Challenge Handshake Protocol header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions 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-01-30 Guy Lancaster , Global Election Systems Inc. +* Original built from BSD network code. +******************************************************************************/ +/* + * chap.h - Challenge Handshake Authentication Protocol definitions. + * + * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited. + * http://www.strataware.com/ + * + * 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 Eric Rosenquist. The name of the author 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. + * + * $Id: chpms.h,v 1.5 2007/12/19 20:47:23 fbernon Exp $ + */ + +#ifndef CHPMS_H +#define CHPMS_H + +#define MAX_NT_PASSWORD 256 /* Maximum number of (Unicode) chars in an NT password */ + +void ChapMS (chap_state *, char *, int, char *, int); + +#endif /* CHPMS_H */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/fsm.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/fsm.c new file mode 100644 index 0000000..1f74686 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/fsm.c @@ -0,0 +1,890 @@ +/***************************************************************************** +* fsm.c - Network Control Protocol Finite State Machine 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-12-01 Guy Lancaster , Global Election Systems Inc. +* Original based on BSD fsm.c. +*****************************************************************************/ +/* + * fsm.c - {Link, IP} Control Protocol Finite State Machine. + * + * 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * TODO: + * Randomize fsm id on link/init. + * Deal with variable outgoing MTU. + */ + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "ppp_impl.h" +#include "pppdebug.h" + +#include "fsm.h" + +#include + +#if PPP_DEBUG +static const char *ppperr_strerr[] = { + "LS_INITIAL", /* LS_INITIAL 0 */ + "LS_STARTING", /* LS_STARTING 1 */ + "LS_CLOSED", /* LS_CLOSED 2 */ + "LS_STOPPED", /* LS_STOPPED 3 */ + "LS_CLOSING", /* LS_CLOSING 4 */ + "LS_STOPPING", /* LS_STOPPING 5 */ + "LS_REQSENT", /* LS_REQSENT 6 */ + "LS_ACKRCVD", /* LS_ACKRCVD 7 */ + "LS_ACKSENT", /* LS_ACKSENT 8 */ + "LS_OPENED" /* LS_OPENED 9 */ +}; +#endif /* PPP_DEBUG */ + +static void fsm_timeout (void *); +static void fsm_rconfreq (fsm *, u_char, u_char *, int); +static void fsm_rconfack (fsm *, int, u_char *, int); +static void fsm_rconfnakrej (fsm *, int, int, u_char *, int); +static void fsm_rtermreq (fsm *, int, u_char *, int); +static void fsm_rtermack (fsm *); +static void fsm_rcoderej (fsm *, u_char *, int); +static void fsm_sconfreq (fsm *, int); + +#define PROTO_NAME(f) ((f)->callbacks->proto_name) + +int peer_mru[NUM_PPP]; + + +/* + * fsm_init - Initialize fsm. + * + * Initialize fsm state. + */ +void +fsm_init(fsm *f) +{ + f->state = LS_INITIAL; + f->flags = 0; + f->id = 0; /* XXX Start with random id? */ + f->timeouttime = FSM_DEFTIMEOUT; + f->maxconfreqtransmits = FSM_DEFMAXCONFREQS; + f->maxtermtransmits = FSM_DEFMAXTERMREQS; + f->maxnakloops = FSM_DEFMAXNAKLOOPS; + f->term_reason_len = 0; +} + + +/* + * fsm_lowerup - The lower layer is up. + */ +void +fsm_lowerup(fsm *f) +{ + int oldState = f->state; + + LWIP_UNUSED_ARG(oldState); + + switch( f->state ) { + case LS_INITIAL: + f->state = LS_CLOSED; + break; + + case LS_STARTING: + if( f->flags & OPT_SILENT ) { + f->state = LS_STOPPED; + } else { + /* Send an initial configure-request */ + fsm_sconfreq(f, 0); + f->state = LS_REQSENT; + } + break; + + default: + FSMDEBUG(LOG_INFO, ("%s: Up event in state %d (%s)!\n", + PROTO_NAME(f), f->state, ppperr_strerr[f->state])); + } + + FSMDEBUG(LOG_INFO, ("%s: lowerup state %d (%s) -> %d (%s)\n", + PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state])); +} + + +/* + * fsm_lowerdown - The lower layer is down. + * + * Cancel all timeouts and inform upper layers. + */ +void +fsm_lowerdown(fsm *f) +{ + int oldState = f->state; + + LWIP_UNUSED_ARG(oldState); + + switch( f->state ) { + case LS_CLOSED: + f->state = LS_INITIAL; + break; + + case LS_STOPPED: + f->state = LS_STARTING; + if( f->callbacks->starting ) { + (*f->callbacks->starting)(f); + } + break; + + case LS_CLOSING: + f->state = LS_INITIAL; + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + break; + + case LS_STOPPING: + case LS_REQSENT: + case LS_ACKRCVD: + case LS_ACKSENT: + f->state = LS_STARTING; + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + break; + + case LS_OPENED: + if( f->callbacks->down ) { + (*f->callbacks->down)(f); + } + f->state = LS_STARTING; + break; + + default: + FSMDEBUG(LOG_INFO, ("%s: Down event in state %d (%s)!\n", + PROTO_NAME(f), f->state, ppperr_strerr[f->state])); + } + + FSMDEBUG(LOG_INFO, ("%s: lowerdown state %d (%s) -> %d (%s)\n", + PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state])); +} + + +/* + * fsm_open - Link is allowed to come up. + */ +void +fsm_open(fsm *f) +{ + int oldState = f->state; + + LWIP_UNUSED_ARG(oldState); + + switch( f->state ) { + case LS_INITIAL: + f->state = LS_STARTING; + if( f->callbacks->starting ) { + (*f->callbacks->starting)(f); + } + break; + + case LS_CLOSED: + if( f->flags & OPT_SILENT ) { + f->state = LS_STOPPED; + } else { + /* Send an initial configure-request */ + fsm_sconfreq(f, 0); + f->state = LS_REQSENT; + } + break; + + case LS_CLOSING: + f->state = LS_STOPPING; + /* fall through */ + case LS_STOPPED: + case LS_OPENED: + if( f->flags & OPT_RESTART ) { + fsm_lowerdown(f); + fsm_lowerup(f); + } + break; + } + + FSMDEBUG(LOG_INFO, ("%s: open state %d (%s) -> %d (%s)\n", + PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state])); +} + +#if 0 /* backport pppd 2.4.4b1; */ +/* + * 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) +{ + /* @todo */ +} +#endif + +/* + * fsm_close - Start closing connection. + * + * Cancel timeouts and either initiate close or possibly go directly to + * the LS_CLOSED state. + */ +void +fsm_close(fsm *f, char *reason) +{ + int oldState = f->state; + + LWIP_UNUSED_ARG(oldState); + + f->term_reason = reason; + f->term_reason_len = (reason == NULL ? 0 : (int)os_strlen(reason)); + switch( f->state ) { + case LS_STARTING: + f->state = LS_INITIAL; + break; + case LS_STOPPED: + f->state = LS_CLOSED; + break; + case LS_STOPPING: + f->state = LS_CLOSING; + break; + + case LS_REQSENT: + case LS_ACKRCVD: + case LS_ACKSENT: + case LS_OPENED: + if( f->state != LS_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, send Terminate-Request */ + f->retransmits = f->maxtermtransmits; + fsm_sdata(f, TERMREQ, f->reqid = ++f->id, + (u_char *) f->term_reason, f->term_reason_len); + TIMEOUT(fsm_timeout, f, f->timeouttime); + --f->retransmits; + + f->state = LS_CLOSING; + break; + } + + FSMDEBUG(LOG_INFO, ("%s: close reason=%s state %d (%s) -> %d (%s)\n", + PROTO_NAME(f), reason, oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state])); +} + + +/* + * fsm_timeout - Timeout expired. + */ +static void +fsm_timeout(void *arg) +{ + fsm *f = (fsm *) arg; + + switch (f->state) { + case LS_CLOSING: + case LS_STOPPING: + if( f->retransmits <= 0 ) { + FSMDEBUG(LOG_WARNING, ("%s: timeout sending Terminate-Request state=%d (%s)\n", + PROTO_NAME(f), f->state, ppperr_strerr[f->state])); + /* + * We've waited for an ack long enough. Peer probably heard us. + */ + f->state = (f->state == LS_CLOSING)? LS_CLOSED: LS_STOPPED; + if( f->callbacks->finished ) { + (*f->callbacks->finished)(f); + } + } else { + FSMDEBUG(LOG_WARNING, ("%s: timeout resending Terminate-Requests state=%d (%s)\n", + PROTO_NAME(f), f->state, ppperr_strerr[f->state])); + /* Send Terminate-Request */ + fsm_sdata(f, TERMREQ, f->reqid = ++f->id, + (u_char *) f->term_reason, f->term_reason_len); + TIMEOUT(fsm_timeout, f, f->timeouttime); + --f->retransmits; + } + break; + + case LS_REQSENT: + case LS_ACKRCVD: + case LS_ACKSENT: + if (f->retransmits <= 0) { + FSMDEBUG(LOG_WARNING, ("%s: timeout sending Config-Requests state=%d (%s)\n", + PROTO_NAME(f), f->state, ppperr_strerr[f->state])); + f->state = LS_STOPPED; + if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished ) { + (*f->callbacks->finished)(f); + } + } else { + FSMDEBUG(LOG_WARNING, ("%s: timeout resending Config-Request state=%d (%s)\n", + PROTO_NAME(f), f->state, ppperr_strerr[f->state])); + /* Retransmit the configure-request */ + if (f->callbacks->retransmit) { + (*f->callbacks->retransmit)(f); + } + fsm_sconfreq(f, 1); /* Re-send Configure-Request */ + if( f->state == LS_ACKRCVD ) { + f->state = LS_REQSENT; + } + } + break; + + default: + FSMDEBUG(LOG_INFO, ("%s: UNHANDLED timeout event in state %d (%s)!\n", + PROTO_NAME(f), f->state, ppperr_strerr[f->state])); + } +} + + +/* + * fsm_input - Input packet. + */ +void +fsm_input(fsm *f, u_char *inpacket, int l) +{ + u_char *inp = inpacket; + u_char code, id; + int len; + + /* + * Parse header (code, id and length). + * If packet too short, drop it. + */ + if (l < HEADERLEN) { + FSMDEBUG(LOG_WARNING, ("fsm_input(%x): Rcvd short header.\n", + f->protocol)); + return; + } + GETCHAR(code, inp); + GETCHAR(id, inp); + GETSHORT(len, inp); + if (len < HEADERLEN) { + FSMDEBUG(LOG_INFO, ("fsm_input(%x): Rcvd illegal length.\n", + f->protocol)); + return; + } + if (len > l) { + FSMDEBUG(LOG_INFO, ("fsm_input(%x): Rcvd short packet.\n", + f->protocol)); + return; + } + len -= HEADERLEN; /* subtract header length */ + + if( f->state == LS_INITIAL || f->state == LS_STARTING ) { + FSMDEBUG(LOG_INFO, ("fsm_input(%x): Rcvd packet in state %d (%s).\n", + f->protocol, f->state, ppperr_strerr[f->state])); + return; + } + FSMDEBUG(LOG_INFO, ("fsm_input(%s):%d,%d,%d\n", PROTO_NAME(f), code, id, l)); + /* + * 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: + FSMDEBUG(LOG_INFO, ("fsm_input(%s): default: \n", PROTO_NAME(f))); + 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; + + FSMDEBUG(LOG_INFO, ("fsm_rconfreq(%s): Rcvd id %d state=%d (%s)\n", + PROTO_NAME(f), id, f->state, ppperr_strerr[f->state])); + switch( f->state ) { + case LS_CLOSED: + /* Go away, we're closed */ + fsm_sdata(f, TERMACK, id, NULL, 0); + return; + case LS_CLOSING: + case LS_STOPPING: + return; + + case LS_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 */ + break; + + case LS_STOPPED: + /* Negotiation started by our peer */ + fsm_sconfreq(f, 0); /* Send initial Configure-Request */ + f->state = LS_REQSENT; + 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, (u_char)code, id, inp, len); + + if (code == CONFACK) { + if (f->state == LS_ACKRCVD) { + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + f->state = LS_OPENED; + if (f->callbacks->up) { + (*f->callbacks->up)(f); /* Inform upper layers */ + } + } else { + f->state = LS_ACKSENT; + } + f->nakloops = 0; + } else { + /* we sent CONFACK or CONFREJ */ + if (f->state != LS_ACKRCVD) { + f->state = LS_REQSENT; + } + if( code == CONFNAK ) { + ++f->nakloops; + } + } +} + + +/* + * fsm_rconfack - Receive Configure-Ack. + */ +static void +fsm_rconfack(fsm *f, int id, u_char *inp, int len) +{ + FSMDEBUG(LOG_INFO, ("fsm_rconfack(%s): Rcvd id %d state=%d (%s)\n", + PROTO_NAME(f), id, f->state, ppperr_strerr[f->state])); + + 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 */ + FSMDEBUG(LOG_INFO, ("%s: received bad Ack (length %d)\n", + PROTO_NAME(f), len)); + return; + } + f->seen_ack = 1; + + switch (f->state) { + case LS_CLOSED: + case LS_STOPPED: + fsm_sdata(f, TERMACK, (u_char)id, NULL, 0); + break; + + case LS_REQSENT: + f->state = LS_ACKRCVD; + f->retransmits = f->maxconfreqtransmits; + break; + + case LS_ACKRCVD: + /* Huh? an extra valid Ack? oh well... */ + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + fsm_sconfreq(f, 0); + f->state = LS_REQSENT; + break; + + case LS_ACKSENT: + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + f->state = LS_OPENED; + f->retransmits = f->maxconfreqtransmits; + if (f->callbacks->up) { + (*f->callbacks->up)(f); /* Inform upper layers */ + } + break; + + case LS_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 = LS_REQSENT; + 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 (*proc) (fsm *, u_char *, int); + int ret; + + FSMDEBUG(LOG_INFO, ("fsm_rconfnakrej(%s): Rcvd id %d state=%d (%s)\n", + PROTO_NAME(f), id, f->state, ppperr_strerr[f->state])); + + if (id != f->reqid || f->seen_ack) { /* Expected id? */ + return; /* Nope, toss... */ + } + proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci; + if (!proc || !((ret = proc(f, inp, len)))) { + /* Nak/reject is bad - ignore it */ + FSMDEBUG(LOG_INFO, ("%s: received bad %s (length %d)\n", + PROTO_NAME(f), (code==CONFNAK? "Nak": "reject"), len)); + return; + } + f->seen_ack = 1; + + switch (f->state) { + case LS_CLOSED: + case LS_STOPPED: + fsm_sdata(f, TERMACK, (u_char)id, NULL, 0); + break; + + case LS_REQSENT: + case LS_ACKSENT: + /* They didn't agree to what we wanted - try another request */ + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + if (ret < 0) { + f->state = LS_STOPPED; /* kludge for stopping CCP */ + } else { + fsm_sconfreq(f, 0); /* Send Configure-Request */ + } + break; + + case LS_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 = LS_REQSENT; + break; + + case LS_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 = LS_REQSENT; + break; + } +} + + +/* + * fsm_rtermreq - Receive Terminate-Req. + */ +static void +fsm_rtermreq(fsm *f, int id, u_char *p, int len) +{ + LWIP_UNUSED_ARG(p); + + FSMDEBUG(LOG_INFO, ("fsm_rtermreq(%s): Rcvd id %d state=%d (%s)\n", + PROTO_NAME(f), id, f->state, ppperr_strerr[f->state])); + + switch (f->state) { + case LS_ACKRCVD: + case LS_ACKSENT: + f->state = LS_REQSENT; /* Start over but keep trying */ + break; + + case LS_OPENED: + if (len > 0) { + FSMDEBUG(LOG_INFO, ("%s terminated by peer (%p)\n", PROTO_NAME(f), p)); + } else { + FSMDEBUG(LOG_INFO, ("%s terminated by peer\n", PROTO_NAME(f))); + } + if (f->callbacks->down) { + (*f->callbacks->down)(f); /* Inform upper layers */ + } + f->retransmits = 0; + f->state = LS_STOPPING; + TIMEOUT(fsm_timeout, f, f->timeouttime); + break; + } + + fsm_sdata(f, TERMACK, (u_char)id, NULL, 0); +} + + +/* + * fsm_rtermack - Receive Terminate-Ack. + */ +static void +fsm_rtermack(fsm *f) +{ + FSMDEBUG(LOG_INFO, ("fsm_rtermack(%s): state=%d (%s)\n", + PROTO_NAME(f), f->state, ppperr_strerr[f->state])); + + switch (f->state) { + case LS_CLOSING: + UNTIMEOUT(fsm_timeout, f); + f->state = LS_CLOSED; + if( f->callbacks->finished ) { + (*f->callbacks->finished)(f); + } + break; + + case LS_STOPPING: + UNTIMEOUT(fsm_timeout, f); + f->state = LS_STOPPED; + if( f->callbacks->finished ) { + (*f->callbacks->finished)(f); + } + break; + + case LS_ACKRCVD: + f->state = LS_REQSENT; + break; + + case LS_OPENED: + if (f->callbacks->down) { + (*f->callbacks->down)(f); /* Inform upper layers */ + } + fsm_sconfreq(f, 0); + break; + default: + FSMDEBUG(LOG_INFO, ("fsm_rtermack(%s): UNHANDLED state=%d (%s)!!!\n", + PROTO_NAME(f), f->state, ppperr_strerr[f->state])); + } +} + + +/* + * fsm_rcoderej - Receive an Code-Reject. + */ +static void +fsm_rcoderej(fsm *f, u_char *inp, int len) +{ + u_char code, id; + + FSMDEBUG(LOG_INFO, ("fsm_rcoderej(%s): state=%d (%s)\n", + PROTO_NAME(f), f->state, ppperr_strerr[f->state])); + + if (len < HEADERLEN) { + FSMDEBUG(LOG_INFO, ("fsm_rcoderej: Rcvd short Code-Reject packet!\n")); + return; + } + GETCHAR(code, inp); + GETCHAR(id, inp); + FSMDEBUG(LOG_WARNING, ("%s: Rcvd Code-Reject for code %d, id %d\n", + PROTO_NAME(f), code, id)); + + if( f->state == LS_ACKRCVD ) { + f->state = LS_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 LS_CLOSING: + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + /* fall through */ + case LS_CLOSED: + f->state = LS_CLOSED; + if( f->callbacks->finished ) { + (*f->callbacks->finished)(f); + } + break; + + case LS_STOPPING: + case LS_REQSENT: + case LS_ACKRCVD: + case LS_ACKSENT: + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + /* fall through */ + case LS_STOPPED: + f->state = LS_STOPPED; + if( f->callbacks->finished ) { + (*f->callbacks->finished)(f); + } + break; + + case LS_OPENED: + if( f->callbacks->down ) { + (*f->callbacks->down)(f); + } + /* Init restart counter, send Terminate-Request */ + f->retransmits = f->maxtermtransmits; + fsm_sdata(f, TERMREQ, f->reqid = ++f->id, + (u_char *) f->term_reason, f->term_reason_len); + TIMEOUT(fsm_timeout, f, f->timeouttime); + --f->retransmits; + + f->state = LS_STOPPING; + break; + + default: + FSMDEBUG(LOG_INFO, ("%s: Protocol-reject event in state %d (%s)!\n", + PROTO_NAME(f), f->state, ppperr_strerr[f->state])); + } +} + + +/* + * fsm_sconfreq - Send a Configure-Request. + */ +static void +fsm_sconfreq(fsm *f, int retransmit) +{ + u_char *outp; + int cilen; + + if( f->state != LS_REQSENT && f->state != LS_ACKRCVD && f->state != LS_ACKSENT ) { + /* Not currently negotiating - reset options */ + if( f->callbacks->resetci ) { + (*f->callbacks->resetci)(f); + } + f->nakloops = 0; + } + + if( !retransmit ) { + /* New request - reset retransmission counter, use new ID */ + f->retransmits = f->maxconfreqtransmits; + f->reqid = ++f->id; + } + + f->seen_ack = 0; + + /* + * Make up the request packet + */ + outp = outpacket_buf[f->unit] + PPP_HDRLEN + HEADERLEN; + if( f->callbacks->cilen && f->callbacks->addci ) { + cilen = (*f->callbacks->cilen)(f); + if( cilen > peer_mru[f->unit] - (int)HEADERLEN ) { + cilen = peer_mru[f->unit] - HEADERLEN; + } + if (f->callbacks->addci) { + (*f->callbacks->addci)(f, outp, &cilen); + } + } else { + cilen = 0; + } + + /* send the request to our peer */ + fsm_sdata(f, CONFREQ, f->reqid, outp, cilen); + + /* start the retransmit timer */ + --f->retransmits; + TIMEOUT(fsm_timeout, f, f->timeouttime); + + FSMDEBUG(LOG_INFO, ("%s: sending Configure-Request, id %d\n", + PROTO_NAME(f), f->reqid)); +} + + +/* + * 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, u_char *data, int datalen) +{ + u_char *outp; + int outlen; + + /* Adjust length to be smaller than MTU */ + outp = outpacket_buf[f->unit]; + if (datalen > peer_mru[f->unit] - (int)HEADERLEN) { + datalen = peer_mru[f->unit] - HEADERLEN; + } + if (datalen && data != outp + PPP_HDRLEN + HEADERLEN) { + BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen); + } + outlen = datalen + HEADERLEN; + MAKEHEADER(outp, f->protocol); + PUTCHAR(code, outp); + PUTCHAR(id, outp); + PUTSHORT(outlen, outp); + pppWrite(f->unit, outpacket_buf[f->unit], outlen + PPP_HDRLEN); + FSMDEBUG(LOG_INFO, ("fsm_sdata(%s): Sent code %d,%d,%d.\n", + PROTO_NAME(f), code, id, outlen)); +} + +#endif /* PPP_SUPPORT */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/fsm.h b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/fsm.h new file mode 100644 index 0000000..8d41b5f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/fsm.h @@ -0,0 +1,157 @@ +/***************************************************************************** +* fsm.h - Network Control Protocol Finite State Machine header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* 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 based on BSD code. +*****************************************************************************/ +/* + * fsm.h - {Link, IP} Control Protocol Finite State Machine 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: fsm.h,v 1.5 2009/12/31 17:08:08 goldsimon Exp $ + */ + +#ifndef FSM_H +#define FSM_H + +/* + * LCP Packet header = Code, id, length. + */ +#define HEADERLEN (sizeof (u_char) + sizeof (u_char) + sizeof (u_short)) + + +/* + * 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 { + int unit; /* Interface unit number */ + u_short protocol; /* Data Link Layer Protocol field value */ + int state; /* State */ + int flags; /* Contains option bits */ + u_char id; /* Current id */ + u_char reqid; /* Current request id */ + u_char seen_ack; /* Have received valid Ack/Nak/Rej to Req */ + int timeouttime; /* Timeout time in milliseconds */ + int maxconfreqtransmits; /* Maximum Configure-Request transmissions */ + int retransmits; /* Number of retransmissions left */ + int maxtermtransmits; /* Maximum Terminate-Request transmissions */ + int nakloops; /* Number of nak loops since last ack */ + int maxnakloops; /* Maximum number of nak loops tolerated */ + struct fsm_callbacks* callbacks; /* Callback routines */ + char* term_reason; /* Reason for closing protocol */ + int term_reason_len; /* Length of term_reason */ +} fsm; + + +typedef struct fsm_callbacks { + void (*resetci)(fsm*); /* Reset our Configuration Information */ + int (*cilen)(fsm*); /* Length of our Configuration Information */ + void (*addci)(fsm*, u_char*, int*); /* Add our Configuration Information */ + int (*ackci)(fsm*, u_char*, int); /* ACK our Configuration Information */ + int (*nakci)(fsm*, u_char*, int); /* NAK our Configuration Information */ + int (*rejci)(fsm*, u_char*, int); /* Reject our Configuration Information */ + int (*reqci)(fsm*, u_char*, int*, int); /* Request peer's Configuration Information */ + void (*up)(fsm*); /* Called when fsm reaches LS_OPENED state */ + void (*down)(fsm*); /* Called when fsm leaves LS_OPENED state */ + void (*starting)(fsm*); /* Called when we want the lower layer */ + void (*finished)(fsm*); /* Called when we don't want the lower layer */ + void (*protreject)(int); /* Called when Protocol-Reject received */ + void (*retransmit)(fsm*); /* Retransmission is necessary */ + int (*extcode)(fsm*, int, u_char, u_char*, int); /* Called when unknown code received */ + char *proto_name; /* String name for protocol (for messages) */ +} fsm_callbacks; + + +/* + * Link states. + */ +#define LS_INITIAL 0 /* Down, hasn't been opened */ +#define LS_STARTING 1 /* Down, been opened */ +#define LS_CLOSED 2 /* Up, hasn't been opened */ +#define LS_STOPPED 3 /* Open, waiting for down event */ +#define LS_CLOSING 4 /* Terminating the connection, not open */ +#define LS_STOPPING 5 /* Terminating, but open */ +#define LS_REQSENT 6 /* We've sent a Config Request */ +#define LS_ACKRCVD 7 /* We've received a Config Ack */ +#define LS_ACKSENT 8 /* We've sent a Config Ack */ +#define LS_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 */ + + +/* + * Prototypes + */ +void fsm_init (fsm*); +void fsm_lowerup (fsm*); +void fsm_lowerdown (fsm*); +void fsm_open (fsm*); +void fsm_close (fsm*, char*); +void fsm_input (fsm*, u_char*, int); +void fsm_protreject (fsm*); +void fsm_sdata (fsm*, u_char, u_char, u_char*, int); + + +/* + * Variables + */ +extern int peer_mru[]; /* currently negotiated peer MRU (per unit) */ + +#endif /* FSM_H */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/ipcp.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/ipcp.c new file mode 100644 index 0000000..f0ab2e0 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/ipcp.c @@ -0,0 +1,1411 @@ +/** In contrast to pppd 2.3.1, DNS support has been added, proxy-ARP and + dial-on-demand has been stripped. */ +/***************************************************************************** +* ipcp.c - Network PPP IP Control 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-12-08 Guy Lancaster , Global Election Systems Inc. +* Original. +*****************************************************************************/ +/* + * ipcp.c - PPP IP Control Protocol. + * + * 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "ppp_impl.h" +#include "pppdebug.h" + +#include "auth.h" +#include "fsm.h" +#include "vj.h" +#include "ipcp.h" + +#include "lwip/inet.h" + +#include + +/* #define OLD_CI_ADDRS 1 */ /* Support deprecated address negotiation. */ + +/* global vars */ +ipcp_options ipcp_wantoptions[NUM_PPP]; /* Options that we want to request */ +ipcp_options ipcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */ +ipcp_options ipcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */ +ipcp_options ipcp_hisoptions[NUM_PPP]; /* Options that we ack'd */ + +/* local vars */ +static int default_route_set[NUM_PPP]; /* Have set up a default route */ +static int cis_received[NUM_PPP]; /* # Conf-Reqs received */ + + +/* + * Callbacks for fsm code. (CI = Configuration Information) + */ +static void ipcp_resetci (fsm *); /* Reset our CI */ +static int ipcp_cilen (fsm *); /* Return length of our CI */ +static void ipcp_addci (fsm *, u_char *, int *); /* Add our CI */ +static int ipcp_ackci (fsm *, u_char *, int); /* Peer ack'd our CI */ +static int ipcp_nakci (fsm *, u_char *, int); /* Peer nak'd our CI */ +static int ipcp_rejci (fsm *, u_char *, int); /* Peer rej'd our CI */ +static int ipcp_reqci (fsm *, u_char *, int *, int); /* Rcv CI */ +static void ipcp_up (fsm *); /* We're UP */ +static void ipcp_down (fsm *); /* We're DOWN */ +#if PPP_ADDITIONAL_CALLBACKS +static void ipcp_script (fsm *, char *); /* Run an up/down script */ +#endif +static void ipcp_finished (fsm *); /* Don't need lower layer */ + + +fsm ipcp_fsm[NUM_PPP]; /* IPCP fsm structure */ + + +static 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 LS_OPENED state */ + ipcp_down, /* Called when fsm leaves LS_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 */ +}; + +/* + * Protocol entry points from main code. + */ +static void ipcp_init (int); +static void ipcp_open (int); +static void ipcp_close (int, char *); +static void ipcp_lowerup (int); +static void ipcp_lowerdown (int); +static void ipcp_input (int, u_char *, int); +static void ipcp_protrej (int); + + +struct protent ipcp_protent = { + PPP_IPCP, + ipcp_init, + ipcp_input, + ipcp_protrej, + ipcp_lowerup, + ipcp_lowerdown, + ipcp_open, + ipcp_close, +#if PPP_ADDITIONAL_CALLBACKS + ipcp_printpkt, + NULL, +#endif /* PPP_ADDITIONAL_CALLBACKS */ + 1, + "IPCP", +#if PPP_ADDITIONAL_CALLBACKS + ip_check_options, + NULL, + ip_active_pkt +#endif /* PPP_ADDITIONAL_CALLBACKS */ +}; + +static void ipcp_clear_addrs (int); + +/* + * 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") + + +/* + * ipcp_init - Initialize IPCP. + */ +static void +ipcp_init(int unit) +{ + fsm *f = &ipcp_fsm[unit]; + ipcp_options *wo = &ipcp_wantoptions[unit]; + ipcp_options *ao = &ipcp_allowoptions[unit]; + + f->unit = unit; + f->protocol = PPP_IPCP; + f->callbacks = &ipcp_callbacks; + fsm_init(&ipcp_fsm[unit]); + + memset(wo, 0, sizeof(*wo)); + memset(ao, 0, sizeof(*ao)); + + wo->neg_addr = 1; + wo->ouraddr = 0; +#if VJ_SUPPORT + wo->neg_vj = 1; +#else /* VJ_SUPPORT */ + wo->neg_vj = 0; +#endif /* VJ_SUPPORT */ + wo->vj_protocol = IPCP_VJ_COMP; + wo->maxslotindex = MAX_SLOTS - 1; + wo->cflag = 0; + wo->default_route = 1; + + ao->neg_addr = 1; +#if VJ_SUPPORT + ao->neg_vj = 1; +#else /* VJ_SUPPORT */ + ao->neg_vj = 0; +#endif /* VJ_SUPPORT */ + ao->maxslotindex = MAX_SLOTS - 1; + ao->cflag = 1; + ao->default_route = 1; +} + + +/* + * ipcp_open - IPCP is allowed to come up. + */ +static void +ipcp_open(int unit) +{ + fsm_open(&ipcp_fsm[unit]); +} + + +/* + * ipcp_close - Take IPCP down. + */ +static void +ipcp_close(int unit, char *reason) +{ + fsm_close(&ipcp_fsm[unit], reason); +} + + +/* + * ipcp_lowerup - The lower layer is up. + */ +static void +ipcp_lowerup(int unit) +{ + fsm_lowerup(&ipcp_fsm[unit]); +} + + +/* + * ipcp_lowerdown - The lower layer is down. + */ +static void +ipcp_lowerdown(int unit) +{ + fsm_lowerdown(&ipcp_fsm[unit]); +} + + +/* + * ipcp_input - Input IPCP packet. + */ +static void +ipcp_input(int unit, u_char *p, int len) +{ + fsm_input(&ipcp_fsm[unit], 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(int unit) +{ + fsm_lowerdown(&ipcp_fsm[unit]); +} + + +/* + * ipcp_resetci - Reset our CI. + */ +static void +ipcp_resetci(fsm *f) +{ + ipcp_options *wo = &ipcp_wantoptions[f->unit]; + + wo->req_addr = wo->neg_addr && ipcp_allowoptions[f->unit].neg_addr; + if (wo->ouraddr == 0) { + wo->accept_local = 1; + } + if (wo->hisaddr == 0) { + wo->accept_remote = 1; + } + /* Request DNS addresses from the peer */ + wo->req_dns1 = ppp_settings.usepeerdns; + wo->req_dns2 = ppp_settings.usepeerdns; + ipcp_gotoptions[f->unit] = *wo; + cis_received[f->unit] = 0; +} + + +/* + * ipcp_cilen - Return length of our CI. + */ +static int +ipcp_cilen(fsm *f) +{ + ipcp_options *go = &ipcp_gotoptions[f->unit]; + ipcp_options *wo = &ipcp_wantoptions[f->unit]; + ipcp_options *ho = &ipcp_hisoptions[f->unit]; + +#define LENCIVJ(neg, old) (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0) +#define LENCIADDR(neg, old) (neg ? (old? CILEN_ADDRS : CILEN_ADDR) : 0) +#define LENCIDNS(neg) (neg ? (CILEN_ADDR) : 0) + + /* + * First see if we want to change our options to the old + * forms because we have received old forms from the peer. + */ + if (wo->neg_addr && !go->neg_addr && !go->old_addrs) { + /* use the old style of address negotiation */ + go->neg_addr = 1; + go->old_addrs = 1; + } + if (wo->neg_vj && !go->neg_vj && !go->old_vj) { + /* try an older style of VJ negotiation */ + if (cis_received[f->unit] == 0) { + /* keep trying the new style until we see some CI from the peer */ + go->neg_vj = 1; + } else { + /* 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; + } + } + } + + return (LENCIADDR(go->neg_addr, go->old_addrs) + + LENCIVJ(go->neg_vj, go->old_vj) + + LENCIDNS(go->req_dns1) + + LENCIDNS(go->req_dns2)); +} + + +/* + * ipcp_addci - Add our desired CIs to a packet. + */ +static void +ipcp_addci(fsm *f, u_char *ucp, int *lenp) +{ + ipcp_options *go = &ipcp_gotoptions[f->unit]; + int len = *lenp; + +#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; \ + } \ + } + +#define ADDCIADDR(opt, neg, old, val1, val2) \ + if (neg) { \ + int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \ + if (len >= addrlen) { \ + u32_t l; \ + PUTCHAR(opt, ucp); \ + PUTCHAR(addrlen, ucp); \ + l = ntohl(val1); \ + PUTLONG(l, ucp); \ + if (old) { \ + l = ntohl(val2); \ + PUTLONG(l, ucp); \ + } \ + len -= addrlen; \ + } else { \ + neg = 0; \ + } \ + } + +#define ADDCIDNS(opt, neg, addr) \ + if (neg) { \ + if (len >= CILEN_ADDR) { \ + u32_t l; \ + PUTCHAR(opt, ucp); \ + PUTCHAR(CILEN_ADDR, ucp); \ + l = ntohl(addr); \ + PUTLONG(l, ucp); \ + len -= CILEN_ADDR; \ + } else { \ + neg = 0; \ + } \ + } + + ADDCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr, + go->old_addrs, go->ouraddr, go->hisaddr); + + ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj, + go->maxslotindex, go->cflag); + + ADDCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]); + + ADDCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]); + + *lenp -= len; +} + + +/* + * ipcp_ackci - Ack our CIs. + * + * Returns: + * 0 - Ack was bad. + * 1 - Ack was good. + */ +static int +ipcp_ackci(fsm *f, u_char *p, int len) +{ + ipcp_options *go = &ipcp_gotoptions[f->unit]; + u_short cilen, citype, cishort; + u32_t cilong; + u_char cimaxslotindex, cicflag; + + /* + * 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 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; \ + } \ + } \ + } + +#define ACKCIADDR(opt, neg, old, val1, val2) \ + if (neg) { \ + int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \ + u32_t l; \ + if ((len -= addrlen) < 0) { \ + goto bad; \ + } \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != addrlen || \ + citype != opt) { \ + goto bad; \ + } \ + GETLONG(l, p); \ + cilong = htonl(l); \ + if (val1 != cilong) { \ + goto bad; \ + } \ + if (old) { \ + GETLONG(l, p); \ + cilong = htonl(l); \ + if (val2 != cilong) { \ + goto bad; \ + } \ + } \ + } + +#define ACKCIDNS(opt, neg, addr) \ + if (neg) { \ + u32_t l; \ + if ((len -= CILEN_ADDR) < 0) { \ + goto bad; \ + } \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != CILEN_ADDR || \ + citype != opt) { \ + goto bad; \ + } \ + GETLONG(l, p); \ + cilong = htonl(l); \ + if (addr != cilong) { \ + goto bad; \ + } \ + } + + ACKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr, + go->old_addrs, go->ouraddr, go->hisaddr); + + ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj, + go->maxslotindex, go->cflag); + + ACKCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]); + + ACKCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]); + + /* + * If there are any remaining CIs, then this packet is bad. + */ + if (len != 0) { + goto bad; + } + return (1); + +bad: + IPCPDEBUG(LOG_INFO, ("ipcp_ackci: received bad Ack!\n")); + 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 LS_OPENED state. + * + * Returns: + * 0 - Nak was bad. + * 1 - Nak was good. + */ +static int +ipcp_nakci(fsm *f, u_char *p, int len) +{ + ipcp_options *go = &ipcp_gotoptions[f->unit]; + u_char cimaxslotindex, cicflag; + u_char citype, cilen, *next; + u_short cishort; + u32_t ciaddr1, ciaddr2, l, cidnsaddr; + 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 NAKCIADDR(opt, neg, old, code) \ + if (go->neg && \ + len >= (cilen = (old? CILEN_ADDRS: CILEN_ADDR)) && \ + p[1] == cilen && \ + p[0] == opt) { \ + len -= cilen; \ + INCPTR(2, p); \ + GETLONG(l, p); \ + ciaddr1 = htonl(l); \ + if (old) { \ + GETLONG(l, p); \ + ciaddr2 = htonl(l); \ + no.old_addrs = 1; \ + } else { \ + ciaddr2 = 0; \ + } \ + no.neg = 1; \ + code \ + } + +#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 \ + } + +#define NAKCIDNS(opt, neg, code) \ + if (go->neg && \ + ((cilen = p[1]) == CILEN_ADDR) && \ + len >= cilen && \ + p[0] == opt) { \ + len -= cilen; \ + INCPTR(2, p); \ + GETLONG(l, p); \ + cidnsaddr = htonl(l); \ + no.neg = 1; \ + code \ + } + + /* + * Accept the peer's idea of {our,his} address, if different + * from our idea, only if the accept_{local,remote} flag is set. + */ + NAKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr, go->old_addrs, + if (go->accept_local && ciaddr1) { /* Do we know our address? */ + try.ouraddr = ciaddr1; + IPCPDEBUG(LOG_INFO, ("local IP address %s\n", + inet_ntoa(ciaddr1))); + } + if (go->accept_remote && ciaddr2) { /* Does he know his? */ + try.hisaddr = ciaddr2; + IPCPDEBUG(LOG_INFO, ("remote IP address %s\n", + inet_ntoa(ciaddr2))); + } + ); + + /* + * 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 (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; + } + } + ); + + NAKCIDNS(CI_MS_DNS1, req_dns1, + try.dnsaddr[0] = cidnsaddr; + IPCPDEBUG(LOG_INFO, ("primary DNS address %s\n", inet_ntoa(cidnsaddr))); + ); + + NAKCIDNS(CI_MS_DNS2, req_dns2, + try.dnsaddr[1] = cidnsaddr; + IPCPDEBUG(LOG_INFO, ("secondary DNS address %s\n", inet_ntoa(cidnsaddr))); + ); + + /* + * 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. + */ + while (len > CILEN_VOID) { + GETCHAR(citype, p); + GETCHAR(cilen, p); + if( (len -= cilen) < 0 ) { + goto bad; + } + next = p + cilen - 2; + + switch (citype) { + case CI_COMPRESSTYPE: + if (go->neg_vj || no.neg_vj || + (cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) { + goto bad; + } + no.neg_vj = 1; + break; + case CI_ADDRS: + if ((go->neg_addr && go->old_addrs) || no.old_addrs + || cilen != CILEN_ADDRS) { + goto bad; + } + try.neg_addr = 1; + try.old_addrs = 1; + GETLONG(l, p); + ciaddr1 = htonl(l); + if (ciaddr1 && go->accept_local) { + try.ouraddr = ciaddr1; + } + GETLONG(l, p); + ciaddr2 = htonl(l); + if (ciaddr2 && go->accept_remote) { + try.hisaddr = ciaddr2; + } + no.old_addrs = 1; + break; + case CI_ADDR: + if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR) { + goto bad; + } + try.old_addrs = 0; + GETLONG(l, p); + ciaddr1 = htonl(l); + if (ciaddr1 && go->accept_local) { + try.ouraddr = ciaddr1; + } + if (try.ouraddr != 0) { + try.neg_addr = 1; + } + no.neg_addr = 1; + break; + } + 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 != LS_OPENED) { + *go = try; + } + + return 1; + +bad: + IPCPDEBUG(LOG_INFO, ("ipcp_nakci: received bad Nak!\n")); + return 0; +} + + +/* + * ipcp_rejci - Reject some of our CIs. + */ +static int +ipcp_rejci(fsm *f, u_char *p, int len) +{ + ipcp_options *go = &ipcp_gotoptions[f->unit]; + u_char cimaxslotindex, ciflag, cilen; + u_short cishort; + 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 REJCIADDR(opt, neg, old, val1, val2) \ + if (go->neg && \ + len >= (cilen = old? CILEN_ADDRS: CILEN_ADDR) && \ + p[1] == cilen && \ + p[0] == opt) { \ + u32_t l; \ + len -= cilen; \ + INCPTR(2, p); \ + GETLONG(l, p); \ + cilong = htonl(l); \ + /* Check rejected value. */ \ + if (cilong != val1) { \ + goto bad; \ + } \ + if (old) { \ + GETLONG(l, p); \ + cilong = htonl(l); \ + /* Check rejected value. */ \ + if (cilong != val2) { \ + goto bad; \ + } \ + } \ + try.neg = 0; \ + } + +#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; \ + } + +#define REJCIDNS(opt, neg, dnsaddr) \ + if (go->neg && \ + ((cilen = p[1]) == CILEN_ADDR) && \ + len >= cilen && \ + p[0] == opt) { \ + u32_t l; \ + len -= cilen; \ + INCPTR(2, p); \ + GETLONG(l, p); \ + cilong = htonl(l); \ + /* Check rejected value. */ \ + if (cilong != dnsaddr) { \ + goto bad; \ + } \ + try.neg = 0; \ + } + + REJCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr, + go->old_addrs, go->ouraddr, go->hisaddr); + + REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj, + go->maxslotindex, go->cflag); + + REJCIDNS(CI_MS_DNS1, req_dns1, go->dnsaddr[0]); + + REJCIDNS(CI_MS_DNS2, req_dns2, go->dnsaddr[1]); + + /* + * If there are any remaining CIs, then this packet is bad. + */ + if (len != 0) { + goto bad; + } + /* + * Now we can update state. + */ + if (f->state != LS_OPENED) { + *go = try; + } + return 1; + +bad: + IPCPDEBUG(LOG_INFO, ("ipcp_rejci: received bad Reject!\n")); + return 0; +} + + +/* + * ipcp_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. + */ +static int +ipcp_reqci(fsm *f, u_char *inp/* Requested CIs */,int *len/* Length of requested CIs */,int reject_if_disagree) +{ + ipcp_options *wo = &ipcp_wantoptions[f->unit]; + ipcp_options *ho = &ipcp_hisoptions[f->unit]; + ipcp_options *ao = &ipcp_allowoptions[f->unit]; +#ifdef OLD_CI_ADDRS + ipcp_options *go = &ipcp_gotoptions[f->unit]; +#endif + u_char *cip, *next; /* Pointer to current and next CIs */ + u_short cilen, citype; /* Parsed len, type */ + u_short cishort; /* Parsed short value */ + u32_t tl, ciaddr1; /* Parsed address values */ +#ifdef OLD_CI_ADDRS + u32_t ciaddr2; /* Parsed address values */ +#endif + 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 */ + u_char maxslotindex, cflag; + int d; + + cis_received[f->unit] = 1; + + /* + * 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(LOG_INFO, ("ipcp_reqci: bad CI length!\n")); + orc = CONFREJ; /* Reject bad CI */ + cilen = (u_short)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 */ +#ifdef OLD_CI_ADDRS /* Need to save space... */ + case CI_ADDRS: + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: received ADDRS\n")); + if (!ao->neg_addr || + cilen != CILEN_ADDRS) { /* Check CI length */ + orc = CONFREJ; /* Reject CI */ + break; + } + + /* + * If he has no address, or if we both have his address but + * disagree about it, then NAK it with our idea. + * In particular, if we don't know his address, but he does, + * then accept it. + */ + GETLONG(tl, p); /* Parse source address (his) */ + ciaddr1 = htonl(tl); + IPCPDEBUG(LOG_INFO, ("his addr %s\n", inet_ntoa(ciaddr1))); + if (ciaddr1 != wo->hisaddr + && (ciaddr1 == 0 || !wo->accept_remote)) { + orc = CONFNAK; + if (!reject_if_disagree) { + DECPTR(sizeof(u32_t), p); + tl = ntohl(wo->hisaddr); + PUTLONG(tl, p); + } + } else if (ciaddr1 == 0 && wo->hisaddr == 0) { + /* + * If neither we nor he knows his address, reject the option. + */ + orc = CONFREJ; + wo->req_addr = 0; /* don't NAK with 0.0.0.0 later */ + break; + } + + /* + * If he doesn't know our address, or if we both have our address + * but disagree about it, then NAK it with our idea. + */ + GETLONG(tl, p); /* Parse desination address (ours) */ + ciaddr2 = htonl(tl); + IPCPDEBUG(LOG_INFO, ("our addr %s\n", inet_ntoa(ciaddr2))); + if (ciaddr2 != wo->ouraddr) { + if (ciaddr2 == 0 || !wo->accept_local) { + orc = CONFNAK; + if (!reject_if_disagree) { + DECPTR(sizeof(u32_t), p); + tl = ntohl(wo->ouraddr); + PUTLONG(tl, p); + } + } else { + go->ouraddr = ciaddr2; /* accept peer's idea */ + } + } + + ho->neg_addr = 1; + ho->old_addrs = 1; + ho->hisaddr = ciaddr1; + ho->ouraddr = ciaddr2; + break; +#endif + + case CI_ADDR: + if (!ao->neg_addr) { + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Reject ADDR not allowed\n")); + orc = CONFREJ; /* Reject CI */ + break; + } else if (cilen != CILEN_ADDR) { /* Check CI length */ + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Reject ADDR bad len\n")); + orc = CONFREJ; /* Reject CI */ + break; + } + + /* + * If he has no address, or if we both have his address but + * disagree about it, then NAK it with our idea. + * In particular, if we don't know his address, but he does, + * then accept it. + */ + GETLONG(tl, p); /* Parse source address (his) */ + ciaddr1 = htonl(tl); + if (ciaddr1 != wo->hisaddr + && (ciaddr1 == 0 || !wo->accept_remote)) { + orc = CONFNAK; + if (!reject_if_disagree) { + DECPTR(sizeof(u32_t), p); + tl = ntohl(wo->hisaddr); + PUTLONG(tl, p); + } + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Nak ADDR %s\n", inet_ntoa(ciaddr1))); + } else if (ciaddr1 == 0 && wo->hisaddr == 0) { + /* + * Don't ACK an address of 0.0.0.0 - reject it instead. + */ + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Reject ADDR %s\n", inet_ntoa(ciaddr1))); + orc = CONFREJ; + wo->req_addr = 0; /* don't NAK with 0.0.0.0 later */ + break; + } + + ho->neg_addr = 1; + ho->hisaddr = ciaddr1; + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: ADDR %s\n", inet_ntoa(ciaddr1))); + break; + + 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 */ + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Rejecting DNS%d Request\n", d+1)); + orc = CONFREJ; /* Reject CI */ + break; + } + GETLONG(tl, p); + if (htonl(tl) != ao->dnsaddr[d]) { + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Naking DNS%d Request %s\n", + d+1, inet_ntoa(tl))); + DECPTR(sizeof(u32_t), p); + tl = ntohl(ao->dnsaddr[d]); + PUTLONG(tl, p); + orc = CONFNAK; + } + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: received DNS%d Request\n", d+1)); + break; + + case CI_MS_WINS1: + case CI_MS_WINS2: + /* Microsoft primary or secondary WINS request */ + d = citype == CI_MS_WINS2; + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: received WINS%d Request\n", d+1)); + + /* If we do not have a DNS address then we cannot send it */ + if (ao->winsaddr[d] == 0 || + cilen != CILEN_ADDR) { /* Check CI length */ + orc = CONFREJ; /* Reject CI */ + break; + } + GETLONG(tl, p); + if (htonl(tl) != ao->winsaddr[d]) { + DECPTR(sizeof(u32_t), p); + tl = ntohl(ao->winsaddr[d]); + PUTLONG(tl, p); + orc = CONFNAK; + } + break; + + case CI_COMPRESSTYPE: + if (!ao->neg_vj) { + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Rejecting COMPRESSTYPE not allowed\n")); + orc = CONFREJ; + break; + } else if (cilen != CILEN_VJ && cilen != CILEN_COMPRESS) { + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Rejecting COMPRESSTYPE len=%d\n", cilen)); + orc = CONFREJ; + break; + } + GETSHORT(cishort, p); + + if (!(cishort == IPCP_VJ_COMP || + (cishort == IPCP_VJ_COMP_OLD && cilen == CILEN_COMPRESS))) { + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Rejecting COMPRESSTYPE %d\n", cishort)); + orc = CONFREJ; + break; + } + + ho->neg_vj = 1; + ho->vj_protocol = cishort; + if (cilen == CILEN_VJ) { + GETCHAR(maxslotindex, p); + if (maxslotindex > ao->maxslotindex) { + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Naking VJ max slot %d\n", maxslotindex)); + orc = CONFNAK; + if (!reject_if_disagree) { + DECPTR(1, p); + PUTCHAR(ao->maxslotindex, p); + } + } + GETCHAR(cflag, p); + if (cflag && !ao->cflag) { + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Naking VJ cflag %d\n", 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_SLOTS - 1; + ho->cflag = 1; + } + IPCPDEBUG(LOG_INFO, ( + "ipcp_reqci: received COMPRESSTYPE p=%d old=%d maxslot=%d cflag=%d\n", + ho->vj_protocol, ho->old_vj, ho->maxslotindex, ho->cflag)); + break; + + default: + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Rejecting unknown CI type %d\n", 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? */ + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Rejecting too many naks\n")); + 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) { + BCOPY(cip, ucp, 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 && + wo->req_addr && !reject_if_disagree) { + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Requesting peer address\n")); + if (rc == CONFACK) { + rc = CONFNAK; + ucp = inp; /* reset pointer */ + wo->req_addr = 0; /* don't ask again */ + } + PUTCHAR(CI_ADDR, ucp); + PUTCHAR(CILEN_ADDR, ucp); + tl = ntohl(wo->hisaddr); + PUTLONG(tl, ucp); + } + + *len = (int)(ucp - inp); /* Compute output length */ + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: returning Configure-%s\n", CODENAME(rc))); + return (rc); /* Return final code */ +} + + +#if 0 +/* + * ip_check_options - check that any IP-related options are OK, + * and assign appropriate defaults. + */ +static void +ip_check_options(u_long localAddr) +{ + ipcp_options *wo = &ipcp_wantoptions[0]; + + /* + * Load our default IP address but allow the remote host to give us + * a new address. + */ + if (wo->ouraddr == 0 && !ppp_settings.disable_defaultip) { + wo->accept_local = 1; /* don't insist on this default value */ + wo->ouraddr = htonl(localAddr); + } +} +#endif + + +/* + * ipcp_up - IPCP has come UP. + * + * Configure the IP network interface appropriately and bring it up. + */ +static void +ipcp_up(fsm *f) +{ + u32_t mask; + ipcp_options *ho = &ipcp_hisoptions[f->unit]; + ipcp_options *go = &ipcp_gotoptions[f->unit]; + ipcp_options *wo = &ipcp_wantoptions[f->unit]; + + np_up(f->unit, PPP_IP); + IPCPDEBUG(LOG_INFO, ("ipcp: up\n")); + + /* + * We must have a non-zero IP address for both ends of the link. + */ + if (!ho->neg_addr) { + ho->hisaddr = wo->hisaddr; + } + + if (ho->hisaddr == 0) { + IPCPDEBUG(LOG_ERR, ("Could not determine remote IP address\n")); + ipcp_close(f->unit, "Could not determine remote IP address"); + return; + } + if (go->ouraddr == 0) { + IPCPDEBUG(LOG_ERR, ("Could not determine local IP address\n")); + ipcp_close(f->unit, "Could not determine local IP address"); + return; + } + + if (ppp_settings.usepeerdns && (go->dnsaddr[0] || go->dnsaddr[1])) { + /*pppGotDNSAddrs(go->dnsaddr[0], go->dnsaddr[1]);*/ + } + + /* + * Check that the peer is allowed to use the IP address it wants. + */ + if (!auth_ip_addr(f->unit, ho->hisaddr)) { + IPCPDEBUG(LOG_ERR, ("Peer is not authorized to use remote address %s\n", + inet_ntoa(ho->hisaddr))); + ipcp_close(f->unit, "Unauthorized remote IP address"); + return; + } + + /* set tcp compression */ + sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->maxslotindex); + + /* + * Set IP addresses and (if specified) netmask. + */ + mask = GetMask(go->ouraddr); + + if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask, go->dnsaddr[0], go->dnsaddr[1])) { + IPCPDEBUG(LOG_WARNING, ("sifaddr failed\n")); + ipcp_close(f->unit, "Interface configuration failed"); + return; + } + + /* bring the interface up for IP */ + if (!sifup(f->unit)) { + IPCPDEBUG(LOG_WARNING, ("sifup failed\n")); + ipcp_close(f->unit, "Interface configuration failed"); + return; + } + + sifnpmode(f->unit, PPP_IP, NPMODE_PASS); + + /* assign a default route through the interface if required */ + if (ipcp_wantoptions[f->unit].default_route) { + if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr)) { + default_route_set[f->unit] = 1; + } + } + + IPCPDEBUG(LOG_NOTICE, ("local IP address %s\n", inet_ntoa(go->ouraddr))); + IPCPDEBUG(LOG_NOTICE, ("remote IP address %s\n", inet_ntoa(ho->hisaddr))); + if (go->dnsaddr[0]) { + IPCPDEBUG(LOG_NOTICE, ("primary DNS address %s\n", inet_ntoa(go->dnsaddr[0]))); + } + if (go->dnsaddr[1]) { + IPCPDEBUG(LOG_NOTICE, ("secondary DNS address %s\n", inet_ntoa(go->dnsaddr[1]))); + } +} + + +/* + * 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) +{ + IPCPDEBUG(LOG_INFO, ("ipcp: down\n")); + np_down(f->unit, PPP_IP); + sifvjcomp(f->unit, 0, 0, 0); + + sifdown(f->unit); + ipcp_clear_addrs(f->unit); +} + + +/* + * ipcp_clear_addrs() - clear the interface addresses, routes, etc. + */ +static void +ipcp_clear_addrs(int unit) +{ + u32_t ouraddr, hisaddr; + + ouraddr = ipcp_gotoptions[unit].ouraddr; + hisaddr = ipcp_hisoptions[unit].hisaddr; + if (default_route_set[unit]) { + cifdefaultroute(unit, ouraddr, hisaddr); + default_route_set[unit] = 0; + } + cifaddr(unit, ouraddr, hisaddr); +} + + +/* + * ipcp_finished - possibly shut down the lower layers. + */ +static void +ipcp_finished(fsm *f) +{ + np_finished(f->unit, PPP_IP); +} + +#if PPP_ADDITIONAL_CALLBACKS +static int +ipcp_printpkt(u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg) +{ + LWIP_UNUSED_ARG(p); + LWIP_UNUSED_ARG(plen); + LWIP_UNUSED_ARG(printer); + LWIP_UNUSED_ARG(arg); + return 0; +} + +/* + * 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 +#define IPPROTO_TCP 6 +#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(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 /* PPP_ADDITIONAL_CALLBACKS */ + +#endif /* PPP_SUPPORT */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/ipcp.h b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/ipcp.h new file mode 100644 index 0000000..de03f46 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/ipcp.h @@ -0,0 +1,106 @@ +/***************************************************************************** +* ipcp.h - PPP IP NCP: Internet Protocol Network Control 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-12-04 Guy Lancaster , Global Election Systems Inc. +* Original derived from BSD codes. +*****************************************************************************/ +/* + * ipcp.h - IP Control 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: ipcp.h,v 1.4 2010/01/18 20:49:43 goldsimon Exp $ + */ + +#ifndef IPCP_H +#define IPCP_H + +/* + * Options. + */ +#define CI_ADDRS 1 /* IP Addresses */ +#define CI_COMPRESSTYPE 2 /* Compression Type */ +#define CI_ADDR 3 + +#define CI_MS_DNS1 129 /* Primary DNS value */ +#define CI_MS_WINS1 128 /* Primary WINS value */ +#define CI_MS_DNS2 131 /* Secondary DNS value */ +#define CI_MS_WINS2 130 /* Secondary WINS value */ + +#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 */ + +typedef struct ipcp_options { + u_int neg_addr : 1; /* Negotiate IP Address? */ + u_int old_addrs : 1; /* Use old (IP-Addresses) option? */ + u_int req_addr : 1; /* Ask peer to send IP address? */ + u_int default_route : 1; /* Assign default route through interface? */ + u_int proxy_arp : 1; /* Make proxy ARP entry for peer? */ + u_int neg_vj : 1; /* Van Jacobson Compression? */ + u_int old_vj : 1; /* use old (short) form of VJ option? */ + u_int accept_local : 1; /* accept peer's value for ouraddr */ + u_int accept_remote : 1; /* accept peer's value for hisaddr */ + u_int req_dns1 : 1; /* Ask peer to send primary DNS address? */ + u_int req_dns2 : 1; /* Ask peer to send secondary DNS address? */ + u_short vj_protocol; /* protocol value to use in VJ option */ + u_char maxslotindex; /* VJ slots - 1. */ + u_char cflag; /* VJ slot compression flag. */ + u32_t ouraddr, hisaddr; /* Addresses in NETWORK BYTE ORDER */ + u32_t dnsaddr[2]; /* Primary and secondary MS DNS entries */ + u32_t winsaddr[2]; /* Primary and secondary MS WINS entries */ +} ipcp_options; + +extern fsm ipcp_fsm[]; +extern ipcp_options ipcp_wantoptions[]; +extern ipcp_options ipcp_gotoptions[]; +extern ipcp_options ipcp_allowoptions[]; +extern ipcp_options ipcp_hisoptions[]; + +extern struct protent ipcp_protent; + +#endif /* IPCP_H */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/lcp.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/lcp.c new file mode 100644 index 0000000..54f758a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/lcp.c @@ -0,0 +1,2066 @@ +/***************************************************************************** +* lcp.c - Network Link Control 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-12-01 Guy Lancaster , Global Election Systems Inc. +* Original. +*****************************************************************************/ + +/* + * lcp.c - PPP Link Control Protocol. + * + * 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "ppp_impl.h" +#include "pppdebug.h" + +#include "fsm.h" +#include "chap.h" +#include "magic.h" +#include "auth.h" +#include "lcp.h" + +#include + +#if PPPOE_SUPPORT +#include "netif/ppp_oe.h" +#else +#define PPPOE_MAXMTU PPP_MAXMRU +#endif + +#if 0 /* UNUSED */ +/* + * LCP-related command-line options. + */ +int lcp_echo_interval = 0; /* Interval between LCP echo-requests */ +int lcp_echo_fails = 0; /* Tolerance to unanswered echo-requests */ +bool lax_recv = 0; /* accept control chars in asyncmap */ + +static int setescape (char **); + +static option_t lcp_option_list[] = { + /* LCP options */ + /* list stripped for simplicity */ + {NULL} +}; +#endif /* UNUSED */ + +/* options */ +LinkPhase lcp_phase[NUM_PPP]; /* Phase of link session (RFC 1661) */ +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 */ + +/* global vars */ +static fsm lcp_fsm[NUM_PPP]; /* LCP fsm structure (global)*/ +lcp_options lcp_wantoptions[NUM_PPP]; /* Options that we want to request */ +lcp_options lcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */ +lcp_options lcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */ +lcp_options lcp_hisoptions[NUM_PPP]; /* Options that we ack'd */ +ext_accm xmit_accm[NUM_PPP]; /* extended transmit ACCM */ + +static u32_t lcp_echos_pending = 0; /* Number of outstanding echo msgs */ +static u32_t lcp_echo_number = 0; /* ID number of next echo frame */ +static u32_t lcp_echo_timer_running = 0; /* TRUE if a timer is running */ + +/* @todo: do we really need such a large buffer? The typical 1500 bytes seem too much. */ +static u_char nak_buffer[PPP_MRU]; /* where we construct a nak packet */ + +/* + * Callbacks for fsm code. (CI = Configuration Information) + */ +static void lcp_resetci (fsm*); /* Reset our CI */ +static int lcp_cilen (fsm*); /* Return length of our CI */ +static void lcp_addci (fsm*, u_char*, int*); /* Add our CI to pkt */ +static int lcp_ackci (fsm*, u_char*, int); /* Peer ack'd our CI */ +static int lcp_nakci (fsm*, u_char*, int); /* Peer nak'd our CI */ +static int lcp_rejci (fsm*, u_char*, int); /* Peer rej'd our CI */ +static int lcp_reqci (fsm*, u_char*, int*, int); /* Rcv peer CI */ +static void lcp_up (fsm*); /* We're UP */ +static void lcp_down (fsm*); /* 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*, int, u_char, u_char*, int); +static void lcp_rprotrej (fsm*, u_char*, int); + +/* + * routines to send LCP echos to peer + */ + +static void lcp_echo_lowerup (int); +static void lcp_echo_lowerdown (int); +static void LcpEchoTimeout (void*); +static void lcp_received_echo_reply (fsm*, int, u_char*, int); +static void LcpSendEchoRequest (fsm*); +static void LcpLinkFailure (fsm*); +static void LcpEchoCheck (fsm*); + +static 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 LS_OPENED state */ + lcp_down, /* Called when fsm leaves LS_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_input (int, u_char *, int); +static void lcp_protrej (int); + +struct protent lcp_protent = { + PPP_LCP, + lcp_init, + lcp_input, + lcp_protrej, + lcp_lowerup, + lcp_lowerdown, + lcp_open, + lcp_close, +#if PPP_ADDITIONAL_CALLBACKS + lcp_printpkt, + NULL, +#endif /* PPP_ADDITIONAL_CALLBACKS */ + 1, + "LCP", +#if PPP_ADDITIONAL_CALLBACKS + NULL, + NULL, + NULL +#endif /* PPP_ADDITIONAL_CALLBACKS */ +}; + +int lcp_loopbackfail = DEFLOOPBACKFAIL; + +/* + * Length of each type of configuration option (in octets) + */ +#define CILEN_VOID 2 +#define CILEN_CHAR 3 +#define CILEN_SHORT 4 /* CILEN_VOID + sizeof(short) */ +#define CILEN_CHAP 5 /* CILEN_VOID + sizeof(short) + 1 */ +#define CILEN_LONG 6 /* CILEN_VOID + sizeof(long) */ +#define CILEN_LQR 8 /* CILEN_VOID + sizeof(short) + sizeof(long) */ +#define CILEN_CBCP 3 + +#define CODENAME(x) ((x) == CONFACK ? "ACK" : (x) == CONFNAK ? "NAK" : "REJ") + +#if 0 /* UNUSED */ +/* + * setescape - add chars to the set we escape on transmission. + */ +static int +setescape(argv) + char **argv; +{ + int n, ret; + char *p, *endp; + + p = *argv; + ret = 1; + while (*p) { + n = strtol(p, &endp, 16); + if (p == endp) { + option_error("escape parameter contains invalid hex number '%s'", p); + return 0; + } + p = endp; + if (n < 0 || n == 0x5E || n > 0xFF) { + option_error("can't escape character 0x%x", n); + ret = 0; + } else + xmit_accm[0][n >> 5] |= 1 << (n & 0x1F); + while (*p == ',' || *p == ' ') + ++p; + } + return ret; +} +#endif /* UNUSED */ + +/* + * lcp_init - Initialize LCP. + */ +void +lcp_init(int unit) +{ + fsm *f = &lcp_fsm[unit]; + lcp_options *wo = &lcp_wantoptions[unit]; + lcp_options *ao = &lcp_allowoptions[unit]; + + f->unit = unit; + f->protocol = PPP_LCP; + f->callbacks = &lcp_callbacks; + + fsm_init(f); + + wo->passive = 0; + wo->silent = 0; + wo->restart = 0; /* Set to 1 in kernels or multi-line implementations */ + wo->neg_mru = 1; + wo->mru = PPP_DEFMRU; + wo->neg_asyncmap = 1; + wo->asyncmap = 0x00000000l; /* Assume don't need to escape any ctl chars. */ + wo->neg_chap = 0; /* Set to 1 on server */ + wo->neg_upap = 0; /* Set to 1 on server */ + wo->chap_mdtype = CHAP_DIGEST_MD5; + wo->neg_magicnumber = 1; + wo->neg_pcompression = 1; + wo->neg_accompression = 1; + wo->neg_lqr = 0; /* no LQR implementation yet */ + wo->neg_cbcp = 0; + + ao->neg_mru = 1; + ao->mru = PPP_MAXMRU; + ao->neg_asyncmap = 1; + ao->asyncmap = 0x00000000l; /* Assume don't need to escape any ctl chars. */ + ao->neg_chap = (CHAP_SUPPORT != 0); + ao->chap_mdtype = CHAP_DIGEST_MD5; + ao->neg_upap = (PAP_SUPPORT != 0); + ao->neg_magicnumber = 1; + ao->neg_pcompression = 1; + ao->neg_accompression = 1; + ao->neg_lqr = 0; /* no LQR implementation yet */ + ao->neg_cbcp = (CBCP_SUPPORT != 0); + + /* + * Set transmit escape for the flag and escape characters plus anything + * set for the allowable options. + */ + memset(xmit_accm[unit], 0, sizeof(xmit_accm[0])); + xmit_accm[unit][15] = 0x60; + xmit_accm[unit][0] = (u_char)((ao->asyncmap & 0xFF)); + xmit_accm[unit][1] = (u_char)((ao->asyncmap >> 8) & 0xFF); + xmit_accm[unit][2] = (u_char)((ao->asyncmap >> 16) & 0xFF); + xmit_accm[unit][3] = (u_char)((ao->asyncmap >> 24) & 0xFF); + LCPDEBUG(LOG_INFO, ("lcp_init: xmit_accm=%X %X %X %X\n", + xmit_accm[unit][0], + xmit_accm[unit][1], + xmit_accm[unit][2], + xmit_accm[unit][3])); + + lcp_phase[unit] = PHASE_INITIALIZE; +} + + +/* + * lcp_open - LCP is allowed to come up. + */ +void +lcp_open(int unit) +{ + fsm *f = &lcp_fsm[unit]; + lcp_options *wo = &lcp_wantoptions[unit]; + + f->flags = 0; + if (wo->passive) { + f->flags |= OPT_PASSIVE; + } + if (wo->silent) { + f->flags |= OPT_SILENT; + } + fsm_open(f); + + lcp_phase[unit] = PHASE_ESTABLISH; +} + + +/* + * lcp_close - Take LCP down. + */ +void +lcp_close(int unit, char *reason) +{ + fsm *f = &lcp_fsm[unit]; + + if (lcp_phase[unit] != PHASE_DEAD) { + lcp_phase[unit] = PHASE_TERMINATE; + } + if (f->state == LS_STOPPED && f->flags & (OPT_PASSIVE|OPT_SILENT)) { + /* + * This action is not strictly according to the FSM in RFC1548, + * but it does mean that the program terminates if you do an + * lcp_close() in passive/silent mode when a connection hasn't + * been established. + */ + f->state = LS_CLOSED; + lcp_finished(f); + } else { + fsm_close(f, reason); + } +} + + +/* + * lcp_lowerup - The lower layer is up. + */ +void +lcp_lowerup(int unit) +{ + lcp_options *wo = &lcp_wantoptions[unit]; + + /* + * 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. + */ + ppp_set_xaccm(unit, &xmit_accm[unit]); + ppp_send_config(unit, PPP_MRU, 0xffffffffl, 0, 0); + ppp_recv_config(unit, PPP_MRU, 0x00000000l, + wo->neg_pcompression, wo->neg_accompression); + peer_mru[unit] = PPP_MRU; + lcp_allowoptions[unit].asyncmap = (u_long)xmit_accm[unit][0] + | ((u_long)xmit_accm[unit][1] << 8) + | ((u_long)xmit_accm[unit][2] << 16) + | ((u_long)xmit_accm[unit][3] << 24); + LCPDEBUG(LOG_INFO, ("lcp_lowerup: asyncmap=%X %X %X %X\n", + xmit_accm[unit][3], + xmit_accm[unit][2], + xmit_accm[unit][1], + xmit_accm[unit][0])); + + fsm_lowerup(&lcp_fsm[unit]); +} + + +/* + * lcp_lowerdown - The lower layer is down. + */ +void +lcp_lowerdown(int unit) +{ + fsm_lowerdown(&lcp_fsm[unit]); +} + + +/* + * lcp_input - Input LCP packet. + */ +static void +lcp_input(int unit, u_char *p, int len) +{ + fsm *f = &lcp_fsm[unit]; + + fsm_input(f, p, len); +} + + +/* + * lcp_extcode - Handle a LCP-specific code. + */ +static int +lcp_extcode(fsm *f, int code, u_char id, u_char *inp, int len) +{ + u_char *magp; + + switch( code ){ + case PROTREJ: + lcp_rprotrej(f, inp, len); + break; + + case ECHOREQ: + if (f->state != LS_OPENED) { + break; + } + LCPDEBUG(LOG_INFO, ("lcp: Echo-Request, Rcvd id %d\n", id)); + magp = inp; + PUTLONG(lcp_gotoptions[f->unit].magicnumber, magp); + fsm_sdata(f, ECHOREP, id, inp, len); + break; + + case ECHOREP: + lcp_received_echo_reply(f, id, inp, len); + break; + + case DISCREQ: + 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; + struct protent *protp; + u_short prot; + + if (len < (int)sizeof (u_short)) { + LCPDEBUG(LOG_INFO, ("lcp_rprotrej: Rcvd short Protocol-Reject packet!\n")); + return; + } + + GETSHORT(prot, inp); + + LCPDEBUG(LOG_INFO, ("lcp_rprotrej: Rcvd Protocol-Reject packet for %x!\n", prot)); + + /* + * Protocol-Reject packets received in any state other than the LCP + * LS_OPENED state SHOULD be silently discarded. + */ + if( f->state != LS_OPENED ) { + LCPDEBUG(LOG_INFO, ("Protocol-Reject discarded: LCP in state %d\n", f->state)); + return; + } + + /* + * Upcall the proper Protocol-Reject routine. + */ + for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) { + if (protp->protocol == prot && protp->enabled_flag) { + (*protp->protrej)(f->unit); + return; + } + } + + LCPDEBUG(LOG_WARNING, ("Protocol-Reject for unsupported protocol 0x%x\n", prot)); +} + + +/* + * lcp_protrej - A Protocol-Reject was received. + */ +static void +lcp_protrej(int unit) +{ + LWIP_UNUSED_ARG(unit); + /* + * Can't reject LCP! + */ + LCPDEBUG(LOG_WARNING, ("lcp_protrej: Received Protocol-Reject for LCP!\n")); + fsm_protreject(&lcp_fsm[unit]); +} + + +/* + * lcp_sprotrej - Send a Protocol-Reject for some protocol. + */ +void +lcp_sprotrej(int unit, u_char *p, int len) +{ + /* + * Send back the protocol and the information field of the + * rejected packet. We only get here if LCP is in the LS_OPENED state. + */ + + fsm_sdata(&lcp_fsm[unit], PROTREJ, ++lcp_fsm[unit].id, p, len); +} + + +/* + * lcp_resetci - Reset our CI. + */ +static void +lcp_resetci(fsm *f) +{ + lcp_wantoptions[f->unit].magicnumber = magic(); + lcp_wantoptions[f->unit].numloops = 0; + lcp_gotoptions[f->unit] = lcp_wantoptions[f->unit]; + peer_mru[f->unit] = PPP_MRU; + auth_reset(f->unit); +} + + +/* + * lcp_cilen - Return length of our CI. + */ +static int +lcp_cilen(fsm *f) +{ + lcp_options *go = &lcp_gotoptions[f->unit]; + +#define LENCIVOID(neg) ((neg) ? CILEN_VOID : 0) +#define LENCICHAP(neg) ((neg) ? CILEN_CHAP : 0) +#define LENCISHORT(neg) ((neg) ? CILEN_SHORT : 0) +#define LENCILONG(neg) ((neg) ? CILEN_LONG : 0) +#define LENCILQR(neg) ((neg) ? CILEN_LQR: 0) +#define LENCICBCP(neg) ((neg) ? CILEN_CBCP: 0) + /* + * NB: we only ask for one of CHAP and UPAP, even if we will + * accept either. + */ + return (LENCISHORT(go->neg_mru && go->mru != PPP_DEFMRU) + + LENCILONG(go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl) + + LENCICHAP(go->neg_chap) + + LENCISHORT(!go->neg_chap && go->neg_upap) + + LENCILQR(go->neg_lqr) + + LENCICBCP(go->neg_cbcp) + + LENCILONG(go->neg_magicnumber) + + LENCIVOID(go->neg_pcompression) + + LENCIVOID(go->neg_accompression)); +} + + +/* + * lcp_addci - Add our desired CIs to a packet. + */ +static void +lcp_addci(fsm *f, u_char *ucp, int *lenp) +{ + lcp_options *go = &lcp_gotoptions[f->unit]; + u_char *start_ucp = ucp; + +#define ADDCIVOID(opt, neg) \ + if (neg) { \ + LCPDEBUG(LOG_INFO, ("lcp_addci: opt=%d\n", opt)); \ + PUTCHAR(opt, ucp); \ + PUTCHAR(CILEN_VOID, ucp); \ + } +#define ADDCISHORT(opt, neg, val) \ + if (neg) { \ + LCPDEBUG(LOG_INFO, ("lcp_addci: INT opt=%d %X\n", opt, val)); \ + PUTCHAR(opt, ucp); \ + PUTCHAR(CILEN_SHORT, ucp); \ + PUTSHORT(val, ucp); \ + } +#define ADDCICHAP(opt, neg, val, digest) \ + if (neg) { \ + LCPDEBUG(LOG_INFO, ("lcp_addci: CHAP opt=%d %X\n", opt, val)); \ + PUTCHAR(opt, ucp); \ + PUTCHAR(CILEN_CHAP, ucp); \ + PUTSHORT(val, ucp); \ + PUTCHAR(digest, ucp); \ + } +#define ADDCILONG(opt, neg, val) \ + if (neg) { \ + LCPDEBUG(LOG_INFO, ("lcp_addci: L opt=%d %lX\n", opt, val)); \ + PUTCHAR(opt, ucp); \ + PUTCHAR(CILEN_LONG, ucp); \ + PUTLONG(val, ucp); \ + } +#define ADDCILQR(opt, neg, val) \ + if (neg) { \ + LCPDEBUG(LOG_INFO, ("lcp_addci: LQR opt=%d %lX\n", opt, val)); \ + PUTCHAR(opt, ucp); \ + PUTCHAR(CILEN_LQR, ucp); \ + PUTSHORT(PPP_LQR, ucp); \ + PUTLONG(val, ucp); \ + } +#define ADDCICHAR(opt, neg, val) \ + if (neg) { \ + LCPDEBUG(LOG_INFO, ("lcp_addci: CHAR opt=%d %X '%z'\n", opt, val, val)); \ + PUTCHAR(opt, ucp); \ + PUTCHAR(CILEN_CHAR, ucp); \ + PUTCHAR(val, ucp); \ + } + + ADDCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru); + ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl, go->asyncmap); + ADDCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype); + ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP); + ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period); + 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); + + if (ucp - start_ucp != *lenp) { + /* this should never happen, because peer_mtu should be 1500 */ + LCPDEBUG(LOG_ERR, ("Bug in lcp_addci: wrong length\n")); + } +} + + +/* + * 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) +{ + lcp_options *go = &lcp_gotoptions[f->unit]; + 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; \ + } +#define ACKCICHAP(opt, neg, val, digest) \ + 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 != val) \ + goto bad; \ + GETCHAR(cichar, p); \ + if (cichar != digest) \ + goto bad; \ + } +#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; \ + } +#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; \ + } + + ACKCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru); + ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl, go->asyncmap); + ACKCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype); + ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP); + ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period); + 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); + + /* + * If there are any remaining CIs, then this packet is bad. + */ + if (len != 0) { + goto bad; + } + LCPDEBUG(LOG_INFO, ("lcp_acki: Ack\n")); + return (1); +bad: + LCPDEBUG(LOG_WARNING, ("lcp_acki: received bad Ack!\n")); + 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 LS_OPENED state. + * + * Returns: + * 0 - Nak was bad. + * 1 - Nak was good. + */ +static int +lcp_nakci(fsm *f, u_char *p, int len) +{ + lcp_options *go = &lcp_gotoptions[f->unit]; + lcp_options *wo = &lcp_wantoptions[f->unit]; + 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, code) \ + if (go->neg && \ + len >= CILEN_VOID && \ + p[1] == CILEN_VOID && \ + p[0] == opt) { \ + len -= CILEN_VOID; \ + INCPTR(CILEN_VOID, p); \ + no.neg = 1; \ + code \ + } +#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 \ + } +#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 \ + } +#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 \ + } + + /* + * 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 != 0xFFFFFFFFl) { + 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 ((go->neg_chap || go->neg_upap) + && len >= CILEN_SHORT + && p[0] == CI_AUTHTYPE && p[1] >= CILEN_SHORT && p[1] <= len) { + cilen = p[1]; + len -= cilen; + no.neg_chap = go->neg_chap; + no.neg_upap = go->neg_upap; + INCPTR(2, p); + GETSHORT(cishort, p); + if (cishort == PPP_PAP && cilen == CILEN_SHORT) { + /* + * If we were asking for CHAP, they obviously don't want to do it. + * If we weren't asking for CHAP, then we were asking for PAP, + * in which case this Nak is bad. + */ + if (!go->neg_chap) { + goto bad; + } + try.neg_chap = 0; + + } else if (cishort == PPP_CHAP && cilen == CILEN_CHAP) { + GETCHAR(cichar, p); + if (go->neg_chap) { + /* + * We were asking for CHAP/MD5; they must want a different + * algorithm. If they can't do MD5, we'll have to stop + * asking for CHAP. + */ + if (cichar != go->chap_mdtype) { + try.neg_chap = 0; + } + } else { + /* + * Stop asking for PAP if we were asking for it. + */ + try.neg_upap = 0; + } + + } else { + /* + * We don't recognize what they're suggesting. + * Stop asking for what we were asking for. + */ + if (go->neg_chap) { + try.neg_chap = 0; + } else { + try.neg_upap = 0; + } + p += cilen - CILEN_SHORT; + } + } + + /* + * 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; + } + ); + + /* + * Only implementing CBCP...not the rest of the callback options + */ + NAKCICHAR(CI_CALLBACK, neg_cbcp, + try.neg_cbcp = 0; + ); + + /* + * 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, + try.neg_pcompression = 0; + ); + NAKCIVOID(CI_ACCOMPRESSION, neg_accompression, + try.neg_accompression = 0; + ); + + /* + * 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.mru = cishort; + } + break; + case CI_ASYNCMAP: + if ((go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl) + || no.neg_asyncmap || cilen != CILEN_LONG) { + goto bad; + } + break; + case CI_AUTHTYPE: + if (go->neg_chap || no.neg_chap || go->neg_upap || no.neg_upap) { + 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; + case CI_QUALITY: + if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR) { + goto bad; + } + 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 != LS_OPENED) { + if (looped_back) { + if (++try.numloops >= lcp_loopbackfail) { + LCPDEBUG(LOG_NOTICE, ("Serial line is looped back.\n")); + lcp_close(f->unit, "Loopback detected"); + } + } else { + try.numloops = 0; + } + *go = try; + } + + return 1; + +bad: + LCPDEBUG(LOG_WARNING, ("lcp_nakci: received bad Nak!\n")); + 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 LS_OPENED state. + * + * Returns: + * 0 - Reject was bad. + * 1 - Reject was good. + */ +static int +lcp_rejci(fsm *f, u_char *p, int len) +{ + lcp_options *go = &lcp_gotoptions[f->unit]; + 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; \ + LCPDEBUG(LOG_INFO, ("lcp_rejci: void opt %d rejected\n", opt)); \ + } +#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; \ + LCPDEBUG(LOG_INFO, ("lcp_rejci: short opt %d rejected\n", opt)); \ + } +#define REJCICHAP(opt, neg, val, digest) \ + 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 != val || cichar != digest) { \ + goto bad; \ + } \ + try.neg = 0; \ + try.neg_upap = 0; \ + LCPDEBUG(LOG_INFO, ("lcp_rejci: chap opt %d rejected\n", opt)); \ + } +#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; \ + LCPDEBUG(LOG_INFO, ("lcp_rejci: long opt %d rejected\n", opt)); \ + } +#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; \ + LCPDEBUG(LOG_INFO, ("lcp_rejci: LQR opt %d rejected\n", opt)); \ + } +#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; \ + LCPDEBUG(LOG_INFO, ("lcp_rejci: Callback opt %d rejected\n", opt)); \ + } + + REJCISHORT(CI_MRU, neg_mru, go->mru); + REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap); + REJCICHAP(CI_AUTHTYPE, neg_chap, PPP_CHAP, go->chap_mdtype); + if (!go->neg_chap) { + REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP); + } + REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period); + REJCICBCP(CI_CALLBACK, neg_cbcp, CBCP_OPT); + REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber); + REJCIVOID(CI_PCOMPRESSION, neg_pcompression); + REJCIVOID(CI_ACCOMPRESSION, neg_accompression); + + /* + * If there are any remaining CIs, then this packet is bad. + */ + if (len != 0) { + goto bad; + } + /* + * Now we can update state. + */ + if (f->state != LS_OPENED) { + *go = try; + } + return 1; + +bad: + LCPDEBUG(LOG_WARNING, ("lcp_rejci: received bad Reject!\n")); + 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. + */ +static int +lcp_reqci(fsm *f, + u_char *inp, /* Requested CIs */ + int *lenp, /* Length of requested CIs */ + int reject_if_disagree) +{ + lcp_options *go = &lcp_gotoptions[f->unit]; + lcp_options *ho = &lcp_hisoptions[f->unit]; + lcp_options *ao = &lcp_allowoptions[f->unit]; + u_char *cip, *next; /* Pointer to current and next CIs */ + int cilen, citype; /* Parsed len, type */ + u_char cichar; /* Parsed 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 */ + u_char *nakp; /* Pointer to next char in Nak frame */ + int l = *lenp; /* Length left */ +#if TRACELCP > 0 + char traceBuf[80]; + size_t traceNdx = 0; +#endif + + /* + * Reset all his options. + */ + BZERO(ho, sizeof(*ho)); + + /* + * Process all his options. + */ + next = inp; + nakp = nak_buffer; + 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(LOG_WARNING, ("lcp_reqci: bad CI length!\n")); + 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? */ + LCPDEBUG(LOG_INFO, ("lcp_reqci: Reject MRU - not allowed\n")); + orc = CONFREJ; /* Reject CI */ + break; + } else if (cilen != CILEN_SHORT) { /* Check CI length */ + LCPDEBUG(LOG_INFO, ("lcp_reqci: Reject MRU - bad length\n")); + 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) { + LCPDEBUG(LOG_INFO, ("lcp_reqci: Nak - MRU too small\n")); + orc = CONFNAK; /* Nak CI */ + PUTCHAR(CI_MRU, nakp); + PUTCHAR(CILEN_SHORT, nakp); + PUTSHORT(PPP_MINMRU, nakp); /* Give him a hint */ + break; + } + ho->neg_mru = 1; /* Remember he sent MRU */ + ho->mru = cishort; /* And remember value */ +#if TRACELCP > 0 + snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " MRU %d", cishort); + traceNdx = strlen(traceBuf); +#endif + break; + + case CI_ASYNCMAP: + if (!ao->neg_asyncmap) { + LCPDEBUG(LOG_INFO, ("lcp_reqci: Reject ASYNCMAP not allowed\n")); + orc = CONFREJ; + break; + } else if (cilen != CILEN_LONG) { + LCPDEBUG(LOG_INFO, ("lcp_reqci: Reject ASYNCMAP bad length\n")); + 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) { + LCPDEBUG(LOG_INFO, ("lcp_reqci: Nak ASYNCMAP %lX missing %lX\n", + cilong, ao->asyncmap)); + orc = CONFNAK; + PUTCHAR(CI_ASYNCMAP, nakp); + PUTCHAR(CILEN_LONG, nakp); + PUTLONG(ao->asyncmap | cilong, nakp); + break; + } + ho->neg_asyncmap = 1; + ho->asyncmap = cilong; +#if TRACELCP > 0 + snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " ASYNCMAP=%lX", cilong); + traceNdx = strlen(traceBuf); +#endif + break; + + case CI_AUTHTYPE: + if (cilen < CILEN_SHORT) { + LCPDEBUG(LOG_INFO, ("lcp_reqci: Reject AUTHTYPE missing arg\n")); + orc = CONFREJ; + break; + } else if (!(ao->neg_upap || ao->neg_chap)) { + /* + * Reject the option if we're not willing to authenticate. + */ + LCPDEBUG(LOG_INFO, ("lcp_reqci: Reject AUTHTYPE not allowed\n")); + orc = CONFREJ; + break; + } + GETSHORT(cishort, p); + + /* + * Authtype must be UPAP or CHAP. + * + * Note: if both ao->neg_upap and ao->neg_chap are set, + * and the peer sends a Configure-Request with two + * authenticate-protocol requests, one for CHAP and one + * for UPAP, then we will reject the second request. + * Whether we end up doing CHAP or UPAP depends then on + * the ordering of the CIs in the peer's Configure-Request. + */ + + if (cishort == PPP_PAP) { + if (ho->neg_chap) { /* we've already accepted CHAP */ + LCPDEBUG(LOG_WARNING, ("lcp_reqci: Reject AUTHTYPE PAP already accepted\n")); + orc = CONFREJ; + break; + } else if (cilen != CILEN_SHORT) { + LCPDEBUG(LOG_WARNING, ("lcp_reqci: Reject AUTHTYPE PAP bad len\n")); + orc = CONFREJ; + break; + } + if (!ao->neg_upap) { /* we don't want to do PAP */ + LCPDEBUG(LOG_WARNING, ("lcp_reqci: Nak AUTHTYPE PAP not allowed\n")); + orc = CONFNAK; /* NAK it and suggest CHAP */ + PUTCHAR(CI_AUTHTYPE, nakp); + PUTCHAR(CILEN_CHAP, nakp); + PUTSHORT(PPP_CHAP, nakp); + PUTCHAR(ao->chap_mdtype, nakp); + break; + } + ho->neg_upap = 1; +#if TRACELCP > 0 + snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " PAP (%X)", cishort); + traceNdx = strlen(traceBuf); +#endif + break; + } + if (cishort == PPP_CHAP) { + if (ho->neg_upap) { /* we've already accepted PAP */ + LCPDEBUG(LOG_WARNING, ("lcp_reqci: Reject AUTHTYPE CHAP accepted PAP\n")); + orc = CONFREJ; + break; + } else if (cilen != CILEN_CHAP) { + LCPDEBUG(LOG_WARNING, ("lcp_reqci: Reject AUTHTYPE CHAP bad len\n")); + orc = CONFREJ; + break; + } + if (!ao->neg_chap) { /* we don't want to do CHAP */ + LCPDEBUG(LOG_WARNING, ("lcp_reqci: Nak AUTHTYPE CHAP not allowed\n")); + orc = CONFNAK; /* NAK it and suggest PAP */ + PUTCHAR(CI_AUTHTYPE, nakp); + PUTCHAR(CILEN_SHORT, nakp); + PUTSHORT(PPP_PAP, nakp); + break; + } + GETCHAR(cichar, p); /* get digest type*/ + if (cichar != CHAP_DIGEST_MD5 +#if MSCHAP_SUPPORT + && cichar != CHAP_MICROSOFT +#endif + ) { + LCPDEBUG(LOG_WARNING, ("lcp_reqci: Nak AUTHTYPE CHAP digest=%d\n", (int)cichar)); + orc = CONFNAK; + PUTCHAR(CI_AUTHTYPE, nakp); + PUTCHAR(CILEN_CHAP, nakp); + PUTSHORT(PPP_CHAP, nakp); + PUTCHAR(ao->chap_mdtype, nakp); + break; + } +#if TRACELCP > 0 + snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CHAP %X,%d", cishort, (int)cichar); + traceNdx = strlen(traceBuf); +#endif + ho->chap_mdtype = cichar; /* save md type */ + ho->neg_chap = 1; + break; + } + + /* + * 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.) + */ + orc = CONFNAK; + PUTCHAR(CI_AUTHTYPE, nakp); + if (ao->neg_chap) { + LCPDEBUG(LOG_WARNING, ("lcp_reqci: Nak AUTHTYPE %d req CHAP\n", cishort)); + PUTCHAR(CILEN_CHAP, nakp); + PUTSHORT(PPP_CHAP, nakp); + PUTCHAR(ao->chap_mdtype, nakp); + } else { + LCPDEBUG(LOG_WARNING, ("lcp_reqci: Nak AUTHTYPE %d req PAP\n", cishort)); + PUTCHAR(CILEN_SHORT, nakp); + PUTSHORT(PPP_PAP, nakp); + } + break; + + case CI_QUALITY: + GETSHORT(cishort, p); + GETLONG(cilong, p); +#if TRACELCP > 0 + snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " QUALITY (%x %x)", cishort, (unsigned int) cilong); + traceNdx = strlen(traceBuf); +#endif + + if (!ao->neg_lqr || + cilen != CILEN_LQR) { + orc = CONFREJ; + break; + } + + /* + * 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, nakp); + PUTCHAR(CILEN_LQR, nakp); + PUTSHORT(PPP_LQR, nakp); + PUTLONG(ao->lqr_period, nakp); + break; + } + break; + + case CI_MAGICNUMBER: + if (!(ao->neg_magicnumber || go->neg_magicnumber) || + cilen != CILEN_LONG) { + orc = CONFREJ; + break; + } + GETLONG(cilong, p); +#if TRACELCP > 0 + snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " MAGICNUMBER (%lX)", cilong); + traceNdx = strlen(traceBuf); +#endif + + /* + * 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, nakp); + PUTCHAR(CILEN_LONG, nakp); + PUTLONG(cilong, nakp); + break; + } + ho->neg_magicnumber = 1; + ho->magicnumber = cilong; + break; + + + case CI_PCOMPRESSION: +#if TRACELCP > 0 + snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " PCOMPRESSION"); + traceNdx = strlen(traceBuf); +#endif + if (!ao->neg_pcompression || + cilen != CILEN_VOID) { + orc = CONFREJ; + break; + } + ho->neg_pcompression = 1; + break; + + case CI_ACCOMPRESSION: +#if TRACELCP > 0 + snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " ACCOMPRESSION"); + traceNdx = strlen(traceBuf); +#endif + if (!ao->neg_accompression || + cilen != CILEN_VOID) { + orc = CONFREJ; + break; + } + ho->neg_accompression = 1; + break; + + case CI_MRRU: +#if TRACELCP > 0 + snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_MRRU"); + traceNdx = strlen(traceBuf); +#endif + orc = CONFREJ; + break; + + case CI_SSNHF: +#if TRACELCP > 0 + snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_SSNHF"); + traceNdx = strlen(traceBuf); +#endif + orc = CONFREJ; + break; + + case CI_EPDISC: +#if TRACELCP > 0 + snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_EPDISC"); + traceNdx = strlen(traceBuf); +#endif + orc = CONFREJ; + break; + + default: +#if TRACELCP + snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " unknown %d", citype); + traceNdx = strlen(traceBuf); +#endif + orc = CONFREJ; + break; + } + + endswitch: +#if TRACELCP + if (traceNdx >= 80 - 32) { + LCPDEBUG(LOG_INFO, ("lcp_reqci: rcvd%s\n", traceBuf)); + traceNdx = 0; + } +#endif + 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? */ + BCOPY(cip, rejp, 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 *nakp. + * At present there are no cases where we want to ask the + * peer to negotiate an option. + */ + + switch (rc) { + case CONFACK: + *lenp = (int)(next - inp); + break; + case CONFNAK: + /* + * Copy the Nak'd options from the nak_buffer to the caller's buffer. + */ + *lenp = (int)(nakp - nak_buffer); + BCOPY(nak_buffer, inp, *lenp); + break; + case CONFREJ: + *lenp = (int)(rejp - inp); + break; + } + +#if TRACELCP > 0 + if (traceNdx > 0) { + LCPDEBUG(LOG_INFO, ("lcp_reqci: %s\n", traceBuf)); + } +#endif + LCPDEBUG(LOG_INFO, ("lcp_reqci: returning CONF%s.\n", CODENAME(rc))); + return (rc); /* Return final code */ +} + + +/* + * lcp_up - LCP has come UP. + */ +static void +lcp_up(fsm *f) +{ + lcp_options *wo = &lcp_wantoptions[f->unit]; + lcp_options *ho = &lcp_hisoptions[f->unit]; + lcp_options *go = &lcp_gotoptions[f->unit]; + lcp_options *ao = &lcp_allowoptions[f->unit]; + + 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. + */ + ppp_send_config(f->unit, LWIP_MIN(ao->mru, (ho->neg_mru? ho->mru: PPP_MRU)), + (ho->neg_asyncmap? ho->asyncmap: 0xffffffffl), + ho->neg_pcompression, ho->neg_accompression); + /* + * If the asyncmap hasn't been negotiated, we really should + * set the receive asyncmap to ffffffff, but we set it to 0 + * for backwards contemptibility. + */ + ppp_recv_config(f->unit, (go->neg_mru? LWIP_MAX(wo->mru, go->mru): PPP_MRU), + (go->neg_asyncmap? go->asyncmap: 0x00000000), + go->neg_pcompression, go->neg_accompression); + + if (ho->neg_mru) { + peer_mru[f->unit] = ho->mru; + } + + lcp_echo_lowerup(f->unit); /* Enable echo messages */ + + link_established(f->unit); /* The link is up; authenticate now */ +} + + +/* + * lcp_down - LCP has gone DOWN. + * + * Alert other protocols. + */ +static void +lcp_down(fsm *f) +{ + lcp_options *go = &lcp_gotoptions[f->unit]; + + lcp_echo_lowerdown(f->unit); + + link_down(f->unit); + + ppp_send_config(f->unit, PPP_MRU, 0xffffffffl, 0, 0); + ppp_recv_config(f->unit, PPP_MRU, + (go->neg_asyncmap? go->asyncmap: 0x00000000), + go->neg_pcompression, go->neg_accompression); + peer_mru[f->unit] = PPP_MRU; +} + + +/* + * lcp_starting - LCP needs the lower layer up. + */ +static void +lcp_starting(fsm *f) +{ + link_required(f->unit); /* lwip: currently does nothing */ +} + + +/* + * lcp_finished - LCP has finished with the lower layer. + */ +static void +lcp_finished(fsm *f) +{ + link_terminated(f->unit); /* we are finished with the link */ +} + + +#if PPP_ADDITIONAL_CALLBACKS +/* + * print_string - print a readable representation of a string using + * printer. + */ +static void +print_string( char *p, int len, void (*printer) (void *, 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", c); + } + } + } + printer(arg, "\""); +} + + +/* + * lcp_printpkt - print the contents of an LCP packet. + */ +static char *lcp_codenames[] = { + "ConfReq", "ConfAck", "ConfNak", "ConfRej", + "TermReq", "TermAck", "CodeRej", "ProtRej", + "EchoReq", "EchoRep", "DiscReq" +}; + +static int +lcp_printpkt( u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg) +{ + int code, id, len, olen; + 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 <= sizeof(lcp_codenames) / sizeof(char *)) { + 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%lx", cilong); + } + break; + case CI_AUTHTYPE: + if (olen >= CILEN_SHORT) { + p += 2; + printer(arg, "auth "); + GETSHORT(cishort, p); + switch (cishort) { + case PPP_PAP: + printer(arg, "pap"); + break; + case PPP_CHAP: + printer(arg, "chap"); + break; + default: + printer(arg, "0x%x", cishort); + } + } + break; + 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; + case CI_CALLBACK: + if (olen >= CILEN_CHAR) { + p += 2; + printer(arg, "callback "); + GETSHORT(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; + } + 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, " "); + print_string((char*)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); + p += 4; + len -= 4; + } + break; + } + + /* print the rest of the bytes in the packet */ + for (; len > 0; --len) { + GETCHAR(code, p); + printer(arg, " %.2x", code); + } + + return (int)(p - pstart); +} +#endif /* PPP_ADDITIONAL_CALLBACKS */ + +/* + * Time to shut down the link because there is nothing out there. + */ +static void +LcpLinkFailure (fsm *f) +{ + if (f->state == LS_OPENED) { + LCPDEBUG(LOG_INFO, ("No response to %d echo-requests\n", lcp_echos_pending)); + LCPDEBUG(LOG_NOTICE, ("Serial link appears to be disconnected.\n")); + lcp_close(f->unit, "Peer not responding"); + } +} + +/* + * Timer expired for the LCP echo requests from this process. + */ +static void +LcpEchoCheck (fsm *f) +{ + LcpSendEchoRequest (f); + + /* + * Start the timer for the next interval. + */ + LWIP_ASSERT("lcp_echo_timer_running == 0", lcp_echo_timer_running == 0); + + TIMEOUT (LcpEchoTimeout, f, lcp_echo_interval); + lcp_echo_timer_running = 1; +} + +/* + * LcpEchoTimeout - Timer expired on the LCP echo + */ +static void +LcpEchoTimeout (void *arg) +{ + if (lcp_echo_timer_running != 0) { + 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) +{ + u32_t magic; + + LWIP_UNUSED_ARG(id); + + /* Check the magic number - don't count replies from ourselves. */ + if (len < 4) { + LCPDEBUG(LOG_WARNING, ("lcp: received short Echo-Reply, length %d\n", len)); + return; + } + GETLONG(magic, inp); + if (lcp_gotoptions[f->unit].neg_magicnumber && magic == lcp_gotoptions[f->unit].magicnumber) { + LCPDEBUG(LOG_WARNING, ("appear to have received our own echo-reply!\n")); + return; + } + + /* Reset the number of outstanding echo frames */ + lcp_echos_pending = 0; +} + +/* + * LcpSendEchoRequest - Send an echo request frame to the peer + */ +static void +LcpSendEchoRequest (fsm *f) +{ + u32_t lcp_magic; + u_char pkt[4], *pktp; + + /* + * Detect the failure of the peer at this point. + */ + if (lcp_echo_fails != 0) { + if (lcp_echos_pending >= lcp_echo_fails) { + LcpLinkFailure(f); + lcp_echos_pending = 0; + } + } + + /* + * Make and send the echo request frame. + */ + if (f->state == LS_OPENED) { + lcp_magic = lcp_gotoptions[f->unit].magicnumber; + pktp = pkt; + PUTLONG(lcp_magic, pktp); + fsm_sdata(f, ECHOREQ, (u_char)(lcp_echo_number++ & 0xFF), pkt, (int)(pktp - pkt)); + ++lcp_echos_pending; + } +} + +/* + * lcp_echo_lowerup - Start the timer for the LCP frame + */ + +static void +lcp_echo_lowerup (int unit) +{ + fsm *f = &lcp_fsm[unit]; + + /* Clear the parameters for generating echo frames */ + lcp_echos_pending = 0; + lcp_echo_number = 0; + lcp_echo_timer_running = 0; + + /* If a timeout interval is specified then start the timer */ + if (lcp_echo_interval != 0) { + LcpEchoCheck (f); + } +} + +/* + * lcp_echo_lowerdown - Stop the timer for the LCP frame + */ + +static void +lcp_echo_lowerdown (int unit) +{ + fsm *f = &lcp_fsm[unit]; + + if (lcp_echo_timer_running != 0) { + UNTIMEOUT (LcpEchoTimeout, f); + lcp_echo_timer_running = 0; + } +} + +#endif /* PPP_SUPPORT */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/lcp.h b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/lcp.h new file mode 100644 index 0000000..b9201ee --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/lcp.h @@ -0,0 +1,151 @@ +/***************************************************************************** +* lcp.h - Network Link Control 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. +*****************************************************************************/ +/* + * lcp.h - Link Control 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: lcp.h,v 1.4 2010/01/18 20:49:43 goldsimon Exp $ + */ + +#ifndef LCP_H +#define LCP_H +/* + * Options. + */ +#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_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 */ + +/* + * 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 CBCP_OPT 6 /* Use callback control protocol */ + +/* + * The state of options is described by an lcp_options structure. + */ +typedef struct lcp_options { + u_int passive : 1; /* Don't die if we don't get a response */ + u_int silent : 1; /* Wait for the other end to start first */ + u_int restart : 1; /* Restart vs. exit after close */ + u_int neg_mru : 1; /* Negotiate the MRU? */ + u_int neg_asyncmap : 1; /* Negotiate the async map? */ + u_int neg_upap : 1; /* Ask for UPAP authentication? */ + u_int neg_chap : 1; /* Ask for CHAP authentication? */ + u_int neg_magicnumber : 1; /* Ask for magic number? */ + u_int neg_pcompression : 1; /* HDLC Protocol Field Compression? */ + u_int neg_accompression : 1; /* HDLC Address/Control Field Compression? */ + u_int neg_lqr : 1; /* Negotiate use of Link Quality Reports */ + u_int neg_cbcp : 1; /* Negotiate use of CBCP */ +#ifdef PPP_MULTILINK + u_int neg_mrru : 1; /* Negotiate multilink MRRU */ + u_int neg_ssnhf : 1; /* Negotiate short sequence numbers */ + u_int neg_endpoint : 1; /* Negotiate endpoint discriminator */ +#endif + u_short mru; /* Value of MRU */ +#ifdef PPP_MULTILINK + u_short mrru; /* Value of MRRU, and multilink enable */ +#endif + u_char chap_mdtype; /* which MD type (hashing algorithm) */ + u32_t asyncmap; /* Value of async map */ + u32_t magicnumber; + int numloops; /* Number of loops during magic number neg. */ + u32_t lqr_period; /* Reporting period for LQR 1/100ths second */ +#ifdef PPP_MULTILINK + struct epdisc endpoint; /* endpoint discriminator */ +#endif +} lcp_options; + +/* + * Values for phase from BSD pppd.h based on RFC 1661. + */ +typedef enum { + PHASE_DEAD = 0, + PHASE_INITIALIZE, + PHASE_ESTABLISH, + PHASE_AUTHENTICATE, + PHASE_CALLBACK, + PHASE_NETWORK, + PHASE_TERMINATE +} LinkPhase; + + + +extern LinkPhase lcp_phase[NUM_PPP]; /* Phase of link session (RFC 1661) */ +extern lcp_options lcp_wantoptions[]; +extern lcp_options lcp_gotoptions[]; +extern lcp_options lcp_allowoptions[]; +extern lcp_options lcp_hisoptions[]; +extern ext_accm xmit_accm[]; + + +void lcp_init (int); +void lcp_open (int); +void lcp_close (int, char *); +void lcp_lowerup (int); +void lcp_lowerdown(int); +void lcp_sprotrej (int, u_char *, int); /* send protocol reject */ + +extern struct protent lcp_protent; + +/* Default number of times we receive our magic number from the peer + before deciding the link is looped-back. */ +#define DEFLOOPBACKFAIL 10 + +#endif /* LCP_H */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/magic.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/magic.c new file mode 100644 index 0000000..3732a42 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/magic.c @@ -0,0 +1,80 @@ +/***************************************************************************** +* magic.c - Network Random Number Generator 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-12-04 Guy Lancaster , Global Election Systems Inc. +* Original based on BSD magic.c. +*****************************************************************************/ +/* + * magic.c - PPP Magic Number routines. + * + * 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "lwip/opt.h" + +#if PPP_SUPPORT + +#include "ppp_impl.h" +#include "randm.h" +#include "magic.h" + + +/* + * magicInit - Initialize the magic number generator. + * + * Since we use another random number generator that has its own + * initialization, we do nothing here. + */ +void magicInit() +{ + return; +} + +/* + * magic - Returns the next magic number. + */ +u32_t magic() +{ + return avRandom(); +} + +#endif /* PPP_SUPPORT */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/magic.h b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/magic.h new file mode 100644 index 0000000..eba70d2 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/magic.h @@ -0,0 +1,63 @@ +/***************************************************************************** +* magic.h - Network Random Number Generator 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-12-04 Guy Lancaster , Global Election Systems Inc. +* Original derived from BSD codes. +*****************************************************************************/ +/* + * magic.h - PPP Magic Number 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: magic.h,v 1.3 2010/01/18 20:49:43 goldsimon Exp $ + */ + +#ifndef MAGIC_H +#define MAGIC_H + +/* Initialize the magic number generator */ +void magicInit(void); + +/* Returns the next magic number */ +u32_t magic(void); + +#endif /* MAGIC_H */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/md5.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/md5.c new file mode 100644 index 0000000..dc3cc75 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/md5.c @@ -0,0 +1,320 @@ +/* + *********************************************************************** + ** md5.c -- the source code for MD5 routines ** + ** RSA Data Security, Inc. MD5 Message-Digest Algorithm ** + ** Created: 2/17/90 RLR ** + ** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. ** + *********************************************************************** + */ + +/* + *********************************************************************** + ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** + ** ** + ** License to copy and use this software is granted provided that ** + ** it is identified as the "RSA Data Security, Inc. MD5 Message- ** + ** Digest Algorithm" in all material mentioning or referencing this ** + ** software or this function. ** + ** ** + ** License is also granted to make and use derivative works ** + ** provided that such works are identified as "derived from the RSA ** + ** Data Security, Inc. MD5 Message-Digest Algorithm" in all ** + ** material mentioning or referencing the derived work. ** + ** ** + ** RSA Data Security, Inc. makes no representations concerning ** + ** either the merchantability of this software or the suitability ** + ** of this software for any particular purpose. It is provided "as ** + ** is" without express or implied warranty of any kind. ** + ** ** + ** These notices must be retained in any copies of any part of this ** + ** documentation and/or software. ** + *********************************************************************** + */ + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#if CHAP_SUPPORT || MD5_SUPPORT + +#include "ppp_impl.h" +#include "pppdebug.h" + +#include "md5.h" + +#include + +/* + *********************************************************************** + ** Message-digest routines: ** + ** To form the message digest for a message M ** + ** (1) Initialize a context buffer mdContext using MD5Init ** + ** (2) Call MD5Update on mdContext and M ** + ** (3) Call MD5Final on mdContext ** + ** The message digest is now in mdContext->digest[0...15] ** + *********************************************************************** + */ + +/* forward declaration */ +static void Transform (u32_t *buf, u32_t *in); + +static unsigned char PADDING[64] = { + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* F, G, H and I are basic MD5 functions */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */ +/* Rotation is separate from addition to prevent recomputation */ +#define FF(a, b, c, d, x, s, ac) \ + {(a) += F ((b), (c), (d)) + (x) + (u32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) \ + {(a) += G ((b), (c), (d)) + (x) + (u32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) \ + {(a) += H ((b), (c), (d)) + (x) + (u32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) \ + {(a) += I ((b), (c), (d)) + (x) + (u32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +#ifdef __STDC__ +#define UL(x) x##UL +#else +#ifdef WIN32 +#define UL(x) x##UL +#else +#define UL(x) x +#endif +#endif + +/* The routine MD5Init initializes the message-digest context + mdContext. All fields are set to zero. + */ +void +MD5Init (MD5_CTX *mdContext) +{ + mdContext->i[0] = mdContext->i[1] = (u32_t)0; + + /* Load magic initialization constants. */ + mdContext->buf[0] = (u32_t)0x67452301UL; + mdContext->buf[1] = (u32_t)0xefcdab89UL; + mdContext->buf[2] = (u32_t)0x98badcfeUL; + mdContext->buf[3] = (u32_t)0x10325476UL; +} + +/* The routine MD5Update updates the message-digest context to + account for the presence of each of the characters inBuf[0..inLen-1] + in the message whose digest is being computed. + */ +void +MD5Update(MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen) +{ + u32_t in[16]; + int mdi; + unsigned int i, ii; + +#if 0 + PPPDEBUG(LOG_INFO, ("MD5Update: %u:%.*H\n", inLen, LWIP_MIN(inLen, 20) * 2, inBuf)); + PPPDEBUG(LOG_INFO, ("MD5Update: %u:%s\n", inLen, inBuf)); +#endif + + /* compute number of bytes mod 64 */ + mdi = (int)((mdContext->i[0] >> 3) & 0x3F); + + /* update number of bits */ + if ((mdContext->i[0] + ((u32_t)inLen << 3)) < mdContext->i[0]) { + mdContext->i[1]++; + } + mdContext->i[0] += ((u32_t)inLen << 3); + mdContext->i[1] += ((u32_t)inLen >> 29); + + while (inLen--) { + /* add new character to buffer, increment mdi */ + mdContext->in[mdi++] = *inBuf++; + + /* transform if necessary */ + if (mdi == 0x40) { + for (i = 0, ii = 0; i < 16; i++, ii += 4) { + in[i] = (((u32_t)mdContext->in[ii+3]) << 24) | + (((u32_t)mdContext->in[ii+2]) << 16) | + (((u32_t)mdContext->in[ii+1]) << 8) | + ((u32_t)mdContext->in[ii]); + } + Transform (mdContext->buf, in); + mdi = 0; + } + } +} + +/* The routine MD5Final terminates the message-digest computation and + ends with the desired message digest in mdContext->digest[0...15]. + */ +void +MD5Final (unsigned char hash[], MD5_CTX *mdContext) +{ + u32_t in[16]; + int mdi; + unsigned int i, ii; + unsigned int padLen; + + /* save number of bits */ + in[14] = mdContext->i[0]; + in[15] = mdContext->i[1]; + + /* compute number of bytes mod 64 */ + mdi = (int)((mdContext->i[0] >> 3) & 0x3F); + + /* pad out to 56 mod 64 */ + padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi); + MD5Update (mdContext, PADDING, padLen); + + /* append length in bits and transform */ + for (i = 0, ii = 0; i < 14; i++, ii += 4) { + in[i] = (((u32_t)mdContext->in[ii+3]) << 24) | + (((u32_t)mdContext->in[ii+2]) << 16) | + (((u32_t)mdContext->in[ii+1]) << 8) | + ((u32_t)mdContext->in[ii]); + } + Transform (mdContext->buf, in); + + /* store buffer in digest */ + for (i = 0, ii = 0; i < 4; i++, ii += 4) { + mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF); + mdContext->digest[ii+1] = + (unsigned char)((mdContext->buf[i] >> 8) & 0xFF); + mdContext->digest[ii+2] = + (unsigned char)((mdContext->buf[i] >> 16) & 0xFF); + mdContext->digest[ii+3] = + (unsigned char)((mdContext->buf[i] >> 24) & 0xFF); + } + SMEMCPY(hash, mdContext->digest, 16); +} + +/* Basic MD5 step. Transforms buf based on in. + */ +static void +Transform (u32_t *buf, u32_t *in) +{ + u32_t a = buf[0], b = buf[1], c = buf[2], d = buf[3]; + + /* Round 1 */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 + FF ( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */ + FF ( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */ + FF ( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */ + FF ( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */ + FF ( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */ + FF ( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */ + FF ( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */ + FF ( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */ + FF ( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */ + FF ( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */ + FF ( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */ + FF ( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */ + FF ( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */ + FF ( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */ + FF ( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */ + FF ( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */ + + /* Round 2 */ +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 + GG ( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */ + GG ( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */ + GG ( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */ + GG ( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */ + GG ( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */ + GG ( d, a, b, c, in[10], S22, UL( 38016083)); /* 22 */ + GG ( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */ + GG ( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */ + GG ( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */ + GG ( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */ + GG ( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */ + GG ( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */ + GG ( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */ + GG ( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */ + GG ( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */ + GG ( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */ + + /* Round 3 */ +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 + HH ( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */ + HH ( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */ + HH ( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */ + HH ( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */ + HH ( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */ + HH ( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */ + HH ( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */ + HH ( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */ + HH ( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */ + HH ( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */ + HH ( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */ + HH ( b, c, d, a, in[ 6], S34, UL( 76029189)); /* 44 */ + HH ( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */ + HH ( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */ + HH ( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */ + HH ( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */ + + /* Round 4 */ +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + II ( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */ + II ( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */ + II ( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */ + II ( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */ + II ( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */ + II ( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */ + II ( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */ + II ( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */ + II ( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */ + II ( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */ + II ( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */ + II ( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */ + II ( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */ + II ( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */ + II ( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */ + II ( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */ + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +#endif /* CHAP_SUPPORT || MD5_SUPPORT */ + +#endif /* PPP_SUPPORT */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/md5.h b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/md5.h new file mode 100644 index 0000000..e129533 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/md5.h @@ -0,0 +1,55 @@ +/* + *********************************************************************** + ** md5.h -- header file for implementation of MD5 ** + ** RSA Data Security, Inc. MD5 Message-Digest Algorithm ** + ** Created: 2/17/90 RLR ** + ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version ** + ** Revised (for MD5): RLR 4/27/91 ** + ** -- G modified to have y&~z instead of y&z ** + ** -- FF, GG, HH modified to add in last register done ** + ** -- Access pattern: round 2 works mod 5, round 3 works mod 3 ** + ** -- distinct additive constant for each step ** + ** -- round 4 added, working mod 7 ** + *********************************************************************** + */ + +/* + *********************************************************************** + ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** + ** ** + ** License to copy and use this software is granted provided that ** + ** it is identified as the "RSA Data Security, Inc. MD5 Message- ** + ** Digest Algorithm" in all material mentioning or referencing this ** + ** software or this function. ** + ** ** + ** License is also granted to make and use derivative works ** + ** provided that such works are identified as "derived from the RSA ** + ** Data Security, Inc. MD5 Message-Digest Algorithm" in all ** + ** material mentioning or referencing the derived work. ** + ** ** + ** RSA Data Security, Inc. makes no representations concerning ** + ** either the merchantability of this software or the suitability ** + ** of this software for any particular purpose. It is provided "as ** + ** is" without express or implied warranty of any kind. ** + ** ** + ** These notices must be retained in any copies of any part of this ** + ** documentation and/or software. ** + *********************************************************************** + */ + +#ifndef MD5_H +#define MD5_H + +/* Data structure for MD5 (Message-Digest) computation */ +typedef struct { + u32_t i[2]; /* number of _bits_ handled mod 2^64 */ + u32_t buf[4]; /* scratch buffer */ + unsigned char in[64]; /* input buffer */ + unsigned char digest[16]; /* actual digest after MD5Final call */ +} MD5_CTX; + +void MD5Init ( MD5_CTX *mdContext); +void MD5Update( MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen); +void MD5Final ( unsigned char hash[], MD5_CTX *mdContext); + +#endif /* MD5_H */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/pap.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/pap.c new file mode 100644 index 0000000..e1452d2 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/pap.c @@ -0,0 +1,628 @@ +/***************************************************************************** +* pap.c - Network Password Authentication 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-12-12 Guy Lancaster , Global Election Systems Inc. +* Original. +*****************************************************************************/ +/* + * upap.c - User/Password Authentication Protocol. + * + * 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#if PAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "ppp_impl.h" +#include "pppdebug.h" + +#include "auth.h" +#include "pap.h" + +#include + +#if 0 /* UNUSED */ +static bool hide_password = 1; + +/* + * Command-line options. + */ +static option_t pap_option_list[] = { + { "hide-password", o_bool, &hide_password, + "Don't output passwords to log", 1 }, + { "show-password", o_bool, &hide_password, + "Show password string in debug log messages", 0 }, + { "pap-restart", o_int, &upap[0].us_timeouttime, + "Set retransmit timeout for PAP" }, + { "pap-max-authreq", o_int, &upap[0].us_maxtransmits, + "Set max number of transmissions for auth-reqs" }, + { "pap-timeout", o_int, &upap[0].us_reqtimeout, + "Set time limit for peer PAP authentication" }, + { NULL } +}; +#endif + +/* + * Protocol entry points. + */ +static void upap_init (int); +static void upap_lowerup (int); +static void upap_lowerdown (int); +static void upap_input (int, u_char *, int); +static void upap_protrej (int); +#if PPP_ADDITIONAL_CALLBACKS +static int upap_printpkt (u_char *, int, void (*)(void *, char *, ...), void *); +#endif /* PPP_ADDITIONAL_CALLBACKS */ + +struct protent pap_protent = { + PPP_PAP, + upap_init, + upap_input, + upap_protrej, + upap_lowerup, + upap_lowerdown, + NULL, + NULL, +#if PPP_ADDITIONAL_CALLBACKS + upap_printpkt, + NULL, +#endif /* PPP_ADDITIONAL_CALLBACKS */ + 1, + "PAP", +#if PPP_ADDITIONAL_CALLBACKS + NULL, + NULL, + NULL +#endif /* PPP_ADDITIONAL_CALLBACKS */ +}; + +upap_state upap[NUM_PPP]; /* UPAP state; one for each unit */ + +static void upap_timeout (void *); +static void upap_reqtimeout(void *); +static void upap_rauthreq (upap_state *, u_char *, u_char, int); +static void upap_rauthack (upap_state *, u_char *, int, int); +static void upap_rauthnak (upap_state *, u_char *, int, int); +static void upap_sauthreq (upap_state *); +static void upap_sresp (upap_state *, u_char, u_char, char *, int); + + +/* + * upap_init - Initialize a UPAP unit. + */ +static void +upap_init(int unit) +{ + upap_state *u = &upap[unit]; + + UPAPDEBUG(LOG_INFO, ("upap_init: %d\n", unit)); + u->us_unit = unit; + u->us_user = NULL; + u->us_userlen = 0; + u->us_passwd = NULL; + u->us_passwdlen = 0; + u->us_clientstate = UPAPCS_INITIAL; + u->us_serverstate = UPAPSS_INITIAL; + u->us_id = 0; + u->us_timeouttime = UPAP_DEFTIMEOUT; + u->us_maxtransmits = 10; + u->us_reqtimeout = UPAP_DEFREQTIME; +} + +/* + * upap_authwithpeer - Authenticate us with our peer (start client). + * + * Set new state and send authenticate's. + */ +void +upap_authwithpeer(int unit, char *user, char *password) +{ + upap_state *u = &upap[unit]; + + UPAPDEBUG(LOG_INFO, ("upap_authwithpeer: %d user=%s password=%s s=%d\n", + unit, user, password, u->us_clientstate)); + + /* Save the username and password we're given */ + u->us_user = user; + u->us_userlen = (int)os_strlen(user); + u->us_passwd = password; + u->us_passwdlen = (int)os_strlen(password); + + u->us_transmits = 0; + + /* Lower layer up yet? */ + if (u->us_clientstate == UPAPCS_INITIAL || + u->us_clientstate == UPAPCS_PENDING) { + u->us_clientstate = UPAPCS_PENDING; + return; + } + + upap_sauthreq(u); /* Start protocol */ +} + + +/* + * upap_authpeer - Authenticate our peer (start server). + * + * Set new state. + */ +void +upap_authpeer(int unit) +{ + upap_state *u = &upap[unit]; + + /* Lower layer up yet? */ + if (u->us_serverstate == UPAPSS_INITIAL || + u->us_serverstate == UPAPSS_PENDING) { + u->us_serverstate = UPAPSS_PENDING; + return; + } + + u->us_serverstate = UPAPSS_LISTEN; + if (u->us_reqtimeout > 0) { + TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout); + } +} + +/* + * upap_timeout - Retransmission timer for sending auth-reqs expired. + */ +static void +upap_timeout(void *arg) +{ + upap_state *u = (upap_state *) arg; + + UPAPDEBUG(LOG_INFO, ("upap_timeout: %d timeout %d expired s=%d\n", + u->us_unit, u->us_timeouttime, u->us_clientstate)); + + if (u->us_clientstate != UPAPCS_AUTHREQ) { + UPAPDEBUG(LOG_INFO, ("upap_timeout: not in AUTHREQ state!\n")); + return; + } + + if (u->us_transmits >= u->us_maxtransmits) { + /* give up in disgust */ + UPAPDEBUG(LOG_ERR, ("No response to PAP authenticate-requests\n")); + u->us_clientstate = UPAPCS_BADAUTH; + auth_withpeer_fail(u->us_unit, PPP_PAP); + return; + } + + upap_sauthreq(u); /* Send Authenticate-Request and set upap timeout*/ +} + + +/* + * upap_reqtimeout - Give up waiting for the peer to send an auth-req. + */ +static void +upap_reqtimeout(void *arg) +{ + upap_state *u = (upap_state *) arg; + + if (u->us_serverstate != UPAPSS_LISTEN) { + return; /* huh?? */ + } + + auth_peer_fail(u->us_unit, PPP_PAP); + u->us_serverstate = UPAPSS_BADAUTH; +} + + +/* + * upap_lowerup - The lower layer is up. + * + * Start authenticating if pending. + */ +static void +upap_lowerup(int unit) +{ + upap_state *u = &upap[unit]; + + UPAPDEBUG(LOG_INFO, ("upap_lowerup: init %d clientstate s=%d\n", unit, u->us_clientstate)); + + if (u->us_clientstate == UPAPCS_INITIAL) { + u->us_clientstate = UPAPCS_CLOSED; + } else if (u->us_clientstate == UPAPCS_PENDING) { + upap_sauthreq(u); /* send an auth-request */ + /* now client state is UPAPCS__AUTHREQ */ + } + + if (u->us_serverstate == UPAPSS_INITIAL) { + u->us_serverstate = UPAPSS_CLOSED; + } else if (u->us_serverstate == UPAPSS_PENDING) { + u->us_serverstate = UPAPSS_LISTEN; + if (u->us_reqtimeout > 0) { + TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout); + } + } +} + + +/* + * upap_lowerdown - The lower layer is down. + * + * Cancel all timeouts. + */ +static void +upap_lowerdown(int unit) +{ + upap_state *u = &upap[unit]; + + UPAPDEBUG(LOG_INFO, ("upap_lowerdown: %d s=%d\n", unit, u->us_clientstate)); + + if (u->us_clientstate == UPAPCS_AUTHREQ) { /* Timeout pending? */ + UNTIMEOUT(upap_timeout, u); /* Cancel timeout */ + } + if (u->us_serverstate == UPAPSS_LISTEN && u->us_reqtimeout > 0) { + UNTIMEOUT(upap_reqtimeout, u); + } + + u->us_clientstate = UPAPCS_INITIAL; + u->us_serverstate = UPAPSS_INITIAL; +} + + +/* + * upap_protrej - Peer doesn't speak this protocol. + * + * This shouldn't happen. In any case, pretend lower layer went down. + */ +static void +upap_protrej(int unit) +{ + upap_state *u = &upap[unit]; + + if (u->us_clientstate == UPAPCS_AUTHREQ) { + UPAPDEBUG(LOG_ERR, ("PAP authentication failed due to protocol-reject\n")); + auth_withpeer_fail(unit, PPP_PAP); + } + if (u->us_serverstate == UPAPSS_LISTEN) { + UPAPDEBUG(LOG_ERR, ("PAP authentication of peer failed (protocol-reject)\n")); + auth_peer_fail(unit, PPP_PAP); + } + upap_lowerdown(unit); +} + + +/* + * upap_input - Input UPAP packet. + */ +static void +upap_input(int unit, u_char *inpacket, int l) +{ + upap_state *u = &upap[unit]; + 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 < (int)UPAP_HEADERLEN) { + UPAPDEBUG(LOG_INFO, ("pap_input: rcvd short header.\n")); + return; + } + GETCHAR(code, inp); + GETCHAR(id, inp); + GETSHORT(len, inp); + if (len < (int)UPAP_HEADERLEN) { + UPAPDEBUG(LOG_INFO, ("pap_input: rcvd illegal length.\n")); + return; + } + if (len > l) { + UPAPDEBUG(LOG_INFO, ("pap_input: rcvd short packet.\n")); + return; + } + len -= UPAP_HEADERLEN; + + /* + * Action depends on code. + */ + switch (code) { + case UPAP_AUTHREQ: + upap_rauthreq(u, inp, id, len); + break; + + case UPAP_AUTHACK: + upap_rauthack(u, inp, id, len); + break; + + case UPAP_AUTHNAK: + upap_rauthnak(u, inp, id, len); + break; + + default: /* XXX Need code reject */ + UPAPDEBUG(LOG_INFO, ("pap_input: UNHANDLED default: code: %d, id: %d, len: %d.\n", code, id, len)); + break; + } +} + + +/* + * upap_rauth - Receive Authenticate. + */ +static void +upap_rauthreq(upap_state *u, u_char *inp, u_char id, int len) +{ + u_char ruserlen, rpasswdlen; + char *ruser, *rpasswd; + u_char retcode; + char *msg; + int msglen; + + UPAPDEBUG(LOG_INFO, ("pap_rauth: Rcvd id %d.\n", id)); + + if (u->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 (u->us_serverstate == UPAPSS_OPEN) { + upap_sresp(u, UPAP_AUTHACK, id, "", 0); /* return auth-ack */ + return; + } + if (u->us_serverstate == UPAPSS_BADAUTH) { + upap_sresp(u, UPAP_AUTHNAK, id, "", 0); /* return auth-nak */ + return; + } + + /* + * Parse user/passwd. + */ + if (len < (int)sizeof (u_char)) { + UPAPDEBUG(LOG_INFO, ("pap_rauth: rcvd short packet.\n")); + return; + } + GETCHAR(ruserlen, inp); + len -= sizeof (u_char) + ruserlen + sizeof (u_char); + if (len < 0) { + UPAPDEBUG(LOG_INFO, ("pap_rauth: rcvd short packet.\n")); + return; + } + ruser = (char *) inp; + INCPTR(ruserlen, inp); + GETCHAR(rpasswdlen, inp); + if (len < rpasswdlen) { + UPAPDEBUG(LOG_INFO, ("pap_rauth: rcvd short packet.\n")); + return; + } + rpasswd = (char *) inp; + + /* + * Check the username and password given. + */ + retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd, rpasswdlen, &msg, &msglen); + /* lwip: currently retcode is always UPAP_AUTHACK */ + BZERO(rpasswd, rpasswdlen); + + upap_sresp(u, retcode, id, msg, msglen); + + if (retcode == UPAP_AUTHACK) { + u->us_serverstate = UPAPSS_OPEN; + auth_peer_success(u->us_unit, PPP_PAP, ruser, ruserlen); + } else { + u->us_serverstate = UPAPSS_BADAUTH; + auth_peer_fail(u->us_unit, PPP_PAP); + } + + if (u->us_reqtimeout > 0) { + UNTIMEOUT(upap_reqtimeout, u); + } +} + + +/* + * upap_rauthack - Receive Authenticate-Ack. + */ +static void +upap_rauthack(upap_state *u, u_char *inp, int id, int len) +{ + u_char msglen; + char *msg; + + LWIP_UNUSED_ARG(id); + + UPAPDEBUG(LOG_INFO, ("pap_rauthack: Rcvd id %d s=%d\n", id, u->us_clientstate)); + + if (u->us_clientstate != UPAPCS_AUTHREQ) { /* XXX */ + UPAPDEBUG(LOG_INFO, ("pap_rauthack: us_clientstate != UPAPCS_AUTHREQ\n")); + return; + } + + /* + * Parse message. + */ + if (len < (int)sizeof (u_char)) { + UPAPDEBUG(LOG_INFO, ("pap_rauthack: ignoring missing msg-length.\n")); + } else { + GETCHAR(msglen, inp); + if (msglen > 0) { + len -= sizeof (u_char); + if (len < msglen) { + UPAPDEBUG(LOG_INFO, ("pap_rauthack: rcvd short packet.\n")); + return; + } + msg = (char *) inp; + PRINTMSG(msg, msglen); + } + } + UNTIMEOUT(upap_timeout, u); /* Cancel timeout */ + u->us_clientstate = UPAPCS_OPEN; + + auth_withpeer_success(u->us_unit, PPP_PAP); +} + + +/* + * upap_rauthnak - Receive Authenticate-Nak. + */ +static void +upap_rauthnak(upap_state *u, u_char *inp, int id, int len) +{ + u_char msglen; + char *msg; + + LWIP_UNUSED_ARG(id); + + UPAPDEBUG(LOG_INFO, ("pap_rauthnak: Rcvd id %d s=%d\n", id, u->us_clientstate)); + + if (u->us_clientstate != UPAPCS_AUTHREQ) { /* XXX */ + return; + } + + /* + * Parse message. + */ + if (len < sizeof (u_char)) { + UPAPDEBUG(LOG_INFO, ("pap_rauthnak: ignoring missing msg-length.\n")); + } else { + GETCHAR(msglen, inp); + if(msglen > 0) { + len -= sizeof (u_char); + if (len < msglen) { + UPAPDEBUG(LOG_INFO, ("pap_rauthnak: rcvd short packet.\n")); + return; + } + msg = (char *) inp; + PRINTMSG(msg, msglen); + } + } + + u->us_clientstate = UPAPCS_BADAUTH; + + UPAPDEBUG(LOG_ERR, ("PAP authentication failed\n")); + auth_withpeer_fail(u->us_unit, PPP_PAP); +} + + +/* + * upap_sauthreq - Send an Authenticate-Request. + */ +static void +upap_sauthreq(upap_state *u) +{ + u_char *outp; + int outlen; + + outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) + + u->us_userlen + u->us_passwdlen; + outp = outpacket_buf[u->us_unit]; + + MAKEHEADER(outp, PPP_PAP); + + PUTCHAR(UPAP_AUTHREQ, outp); + PUTCHAR(++u->us_id, outp); + PUTSHORT(outlen, outp); + PUTCHAR(u->us_userlen, outp); + BCOPY(u->us_user, outp, u->us_userlen); + INCPTR(u->us_userlen, outp); + PUTCHAR(u->us_passwdlen, outp); + BCOPY(u->us_passwd, outp, u->us_passwdlen); + + pppWrite(u->us_unit, outpacket_buf[u->us_unit], outlen + PPP_HDRLEN); + + UPAPDEBUG(LOG_INFO, ("pap_sauth: Sent id %d\n", u->us_id)); + + TIMEOUT(upap_timeout, u, u->us_timeouttime); + ++u->us_transmits; + u->us_clientstate = UPAPCS_AUTHREQ; +} + + +/* + * upap_sresp - Send a response (ack or nak). + */ +static void +upap_sresp(upap_state *u, u_char code, u_char id, char *msg, int msglen) +{ + u_char *outp; + int outlen; + + outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen; + outp = outpacket_buf[u->us_unit]; + MAKEHEADER(outp, PPP_PAP); + + PUTCHAR(code, outp); + PUTCHAR(id, outp); + PUTSHORT(outlen, outp); + PUTCHAR(msglen, outp); + BCOPY(msg, outp, msglen); + pppWrite(u->us_unit, outpacket_buf[u->us_unit], outlen + PPP_HDRLEN); + + UPAPDEBUG(LOG_INFO, ("pap_sresp: Sent code %d, id %d s=%d\n", code, id, u->us_clientstate)); +} + +#if PPP_ADDITIONAL_CALLBACKS +static char *upap_codenames[] = { + "AuthReq", "AuthAck", "AuthNak" +}; + +/* + * upap_printpkt - print the contents of a PAP packet. + */ +static int upap_printpkt( + u_char *p, + int plen, + void (*printer) (void *, char *, ...), + void *arg +) +{ + LWIP_UNUSED_ARG(p); + LWIP_UNUSED_ARG(plen); + LWIP_UNUSED_ARG(printer); + LWIP_UNUSED_ARG(arg); + return 0; +} +#endif /* PPP_ADDITIONAL_CALLBACKS */ + +#endif /* PAP_SUPPORT */ + +#endif /* PPP_SUPPORT */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/pap.h b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/pap.h new file mode 100644 index 0000000..c99a204 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/pap.h @@ -0,0 +1,118 @@ +/***************************************************************************** +* pap.h - PPP Password Authentication 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-12-04 Guy Lancaster , Global Election Systems Inc. +* Original derived from BSD codes. +*****************************************************************************/ +/* + * upap.h - User/Password Authentication 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef PAP_H +#define PAP_H + +#if PAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +/* + * Packet header = Code, id, length. + */ +#define UPAP_HEADERLEN (sizeof (u_char) + sizeof (u_char) + sizeof (u_short)) + + +/* + * UPAP codes. + */ +#define UPAP_AUTHREQ 1 /* Authenticate-Request */ +#define UPAP_AUTHACK 2 /* Authenticate-Ack */ +#define UPAP_AUTHNAK 3 /* Authenticate-Nak */ + +/* + * Each interface is described by upap structure. + */ +typedef struct upap_state { + int us_unit; /* Interface unit number */ + const char *us_user; /* User */ + int us_userlen; /* User length */ + const char *us_passwd; /* Password */ + int us_passwdlen; /* Password length */ + int us_clientstate; /* Client state */ + int us_serverstate; /* Server state */ + u_char us_id; /* Current id */ + int us_timeouttime; /* Timeout (seconds) for auth-req retrans. */ + int us_transmits; /* Number of auth-reqs sent */ + int us_maxtransmits; /* Maximum number of auth-reqs to send */ + int us_reqtimeout; /* Time to wait for auth-req from peer */ +} upap_state; + +/* + * 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 */ + + +extern upap_state upap[]; + +void upap_authwithpeer (int, char *, char *); +void upap_authpeer (int); + +extern struct protent pap_protent; + +#endif /* PAP_SUPPORT */ + +#endif /* PAP_H */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/ppp.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/ppp.c new file mode 100644 index 0000000..2a34657 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/ppp.c @@ -0,0 +1,2052 @@ +/***************************************************************************** +* 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. + */ + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "ppp_impl.h" +#include "lwip/ip.h" /* for ip_input() */ + +#include "pppdebug.h" + +#include "randm.h" +#include "fsm.h" +#if PAP_SUPPORT +#include "pap.h" +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT +#include "chap.h" +#endif /* CHAP_SUPPORT */ +#include "ipcp.h" +#include "lcp.h" +#include "magic.h" +#include "auth.h" +#if VJ_SUPPORT +#include "vj.h" +#endif /* VJ_SUPPORT */ +#if PPPOE_SUPPORT +#include "netif/ppp_oe.h" +#endif /* PPPOE_SUPPORT */ + +#include "lwip/tcpip.h" +#include "lwip/api.h" +#include "lwip/snmp.h" + +#include + +/*************************/ +/*** LOCAL DEFINITIONS ***/ +/*************************/ + +/** PPP_INPROC_MULTITHREADED==1 call pppInput using tcpip_callback(). + * Set this to 0 if pppInProc is called inside tcpip_thread or with NO_SYS==1. + * Default is 1 for NO_SYS==0 (multithreaded) and 0 for NO_SYS==1 (single-threaded). + */ +#ifndef PPP_INPROC_MULTITHREADED +#define PPP_INPROC_MULTITHREADED (NO_SYS==0) +#endif + +/** PPP_INPROC_OWNTHREAD==1: start a dedicated RX thread per PPP session. + * Default is 0: call pppos_input() for received raw characters, charcater + * reception is up to the port */ +#ifndef PPP_INPROC_OWNTHREAD +#define PPP_INPROC_OWNTHREAD PPP_INPROC_MULTITHREADED +#endif + +#if PPP_INPROC_OWNTHREAD && !PPP_INPROC_MULTITHREADED + #error "PPP_INPROC_OWNTHREAD needs PPP_INPROC_MULTITHREADED==1" +#endif + +/* + * 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]) + +/* PPP packet parser states. Current state indicates operation yet to be + * completed. */ +typedef 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. */ +} PPPDevStates; + +#define ESCAPE_P(accm, c) ((accm)[(c) >> 3] & pppACCMMask[c & 0x07]) + +/************************/ +/*** LOCAL DATA TYPES ***/ +/************************/ + +/** RX buffer size: this may be configured smaller! */ +#ifndef PPPOS_RX_BUFSIZE +#define PPPOS_RX_BUFSIZE (PPP_MRU + PPP_HDRLEN) +#endif + +typedef struct PPPControlRx_s { + /** unit number / ppp descriptor */ + int pd; + /** the rx file descriptor */ + sio_fd_t fd; + /** receive buffer - encoded data is stored here */ +#if PPP_INPROC_OWNTHREAD + u_char rxbuf[PPPOS_RX_BUFSIZE]; +#endif /* PPP_INPROC_OWNTHREAD */ + + /* The input packet. */ + struct pbuf *inHead, *inTail; + +#if PPPOS_SUPPORT + u16_t inProtocol; /* The input protocol code. */ + u16_t inFCS; /* Input Frame Check Sequence value. */ +#endif /* PPPOS_SUPPORT */ + PPPDevStates inState; /* The input process state. */ + char inEscaped; /* Escape next character. */ + ext_accm inACCM; /* Async-Ctl-Char-Map for input. */ +} PPPControlRx; + +/* + * PPP interface control block. + */ +typedef struct PPPControl_s { + PPPControlRx rx; + char openFlag; /* True when in use. */ +#if PPPOE_SUPPORT + struct netif *ethif; + struct pppoe_softc *pppoe_sc; +#endif /* PPPOE_SUPPORT */ + int if_up; /* True when the interface is up. */ + int errCode; /* Code indicating why interface is down. */ +#if PPPOS_SUPPORT + sio_fd_t fd; /* File device ID of port. */ +#endif /* PPPOS_SUPPORT */ + u16_t mtu; /* Peer's mru */ + int pcomp; /* Does peer accept protocol compression? */ + int accomp; /* Does peer accept addr/ctl compression? */ + u_long lastXMit; /* Time of last transmission. */ + ext_accm outACCM; /* Async-Ctl-Char-Map for output. */ +#if PPPOS_SUPPORT && VJ_SUPPORT + int vjEnabled; /* Flag indicating VJ compression enabled. */ + struct vjcompress vjComp; /* Van Jacobson compression header. */ +#endif /* PPPOS_SUPPORT && VJ_SUPPORT */ + + struct netif netif; + + struct ppp_addrs addrs; + + void (*linkStatusCB)(void *ctx, int errCode, void *arg); + void *linkStatusCtx; + +} PPPControl; + + +/* + * Ioctl definitions. + */ + +struct npioctl { + int protocol; /* PPP procotol, e.g. PPP_IP */ + enum NPmode mode; +}; + + + +/***********************************/ +/*** LOCAL FUNCTION DECLARATIONS ***/ +/***********************************/ +#if PPPOS_SUPPORT +#if PPP_INPROC_OWNTHREAD +static void pppInputThread(void *arg); +#endif /* PPP_INPROC_OWNTHREAD */ +static void pppDrop(PPPControlRx *pcrx); +static void pppInProc(PPPControlRx *pcrx, u_char *s, int l); +static void pppFreeCurrentInputPacket(PPPControlRx *pcrx); +#endif /* PPPOS_SUPPORT */ + + +/******************************/ +/*** PUBLIC DATA STRUCTURES ***/ +/******************************/ +static PPPControl pppControl[NUM_PPP]; /* The PPP interface control blocks. */ + +/* + * PPP Data Link Layer "protocol" table. + * One entry per supported protocol. + * The last entry must be NULL. + */ +struct protent *ppp_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 */ + &ipcp_protent, +#if CCP_SUPPORT + &ccp_protent, +#endif /* CCP_SUPPORT */ + NULL +}; + + +/* + * Buffers for outgoing packets. This must be accessed only from the appropriate + * PPP task so that it doesn't need to be protected to avoid collisions. + */ +u_char outpacket_buf[NUM_PPP][PPP_MRU+PPP_HDRLEN]; + + +/*****************************/ +/*** LOCAL DATA STRUCTURES ***/ +/*****************************/ + +#if PPPOS_SUPPORT +/* + * FCS lookup table as calculated by genfcstab. + * @todo: smaller, slower implementation for lower memory footprint? + */ +static const 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 +}; + +/* PPP's Asynchronous-Control-Character-Map. The mask array is used + * to select the specific bit for a character. */ +static u_char pppACCMMask[] = { + 0x01, + 0x02, + 0x04, + 0x08, + 0x10, + 0x20, + 0x40, + 0x80 +}; + +#if PPP_INPROC_OWNTHREAD +/** Wake up the task blocked in reading from serial line (if any) */ +static void +pppRecvWakeup(int pd) +{ + PPPDEBUG(LOG_DEBUG, ("pppRecvWakeup: unit %d\n", pd)); + if (pppControl[pd].openFlag != 0) { + sio_read_abort(pppControl[pd].fd); + } +} +#endif /* PPP_INPROC_OWNTHREAD */ +#endif /* PPPOS_SUPPORT */ + +void +pppLinkTerminated(int pd) +{ + PPPDEBUG(LOG_DEBUG, ("pppLinkTerminated: unit %d\n", pd)); + +#if PPPOE_SUPPORT + if (pppControl[pd].ethif) { + pppoe_disconnect(pppControl[pd].pppoe_sc); + } else +#endif /* PPPOE_SUPPORT */ + { +#if PPPOS_SUPPORT + PPPControl* pc; +#if PPP_INPROC_OWNTHREAD + pppRecvWakeup(pd); +#endif /* PPP_INPROC_OWNTHREAD */ + pc = &pppControl[pd]; + + PPPDEBUG(LOG_DEBUG, ("pppLinkTerminated: unit %d: linkStatusCB=%p errCode=%d\n", pd, pc->linkStatusCB, pc->errCode)); + if (pc->linkStatusCB) { + pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL); + } + + pc->openFlag = 0;/**/ +#endif /* PPPOS_SUPPORT */ + } + PPPDEBUG(LOG_DEBUG, ("pppLinkTerminated: finished.\n")); +} + +void +pppLinkDown(int pd) +{ + PPPDEBUG(LOG_DEBUG, ("pppLinkDown: unit %d\n", pd)); + +#if PPPOE_SUPPORT + if (pppControl[pd].ethif) { + pppoe_disconnect(pppControl[pd].pppoe_sc); + } else +#endif /* PPPOE_SUPPORT */ + { +#if PPPOS_SUPPORT && PPP_INPROC_OWNTHREAD + pppRecvWakeup(pd); +#endif /* PPPOS_SUPPORT && PPP_INPROC_OWNTHREAD*/ + } +} + +/** Initiate LCP open request */ +static void +pppStart(int pd) +{ + PPPDEBUG(LOG_DEBUG, ("pppStart: unit %d\n", pd)); + lcp_lowerup(pd); + lcp_open(pd); /* Start protocol */ + PPPDEBUG(LOG_DEBUG, ("pppStart: finished\n")); +} + +/** LCP close request */ +static void +pppStop(int pd) +{ + PPPDEBUG(LOG_DEBUG, ("pppStop: unit %d\n", pd)); + lcp_close(pd, "User request"); +} + +/** Called when carrier/link is lost */ +static void +pppHup(int pd) +{ + PPPDEBUG(LOG_DEBUG, ("pppHupCB: unit %d\n", pd)); + lcp_lowerdown(pd); + link_terminated(pd); +} + +/***********************************/ +/*** PUBLIC FUNCTION DEFINITIONS ***/ +/***********************************/ +/* Initialize the PPP subsystem. */ + +struct ppp_settings ppp_settings; + +void +pppInit(void) +{ + struct protent *protp; + int i, j; + + memset(&ppp_settings, 0, sizeof(ppp_settings)); + ppp_settings.usepeerdns = 1; + pppSetAuth(PPPAUTHTYPE_NONE, NULL, NULL); + + magicInit(); + + for (i = 0; i < NUM_PPP; i++) { + /* Initialize each protocol to the standard option set. */ + for (j = 0; (protp = ppp_protocols[j]) != NULL; ++j) { + (*protp->init)(i); + } + } +} + +void +pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd) +{ + switch(authType) { + case PPPAUTHTYPE_NONE: + default: +#ifdef LWIP_PPP_STRICT_PAP_REJECT + ppp_settings.refuse_pap = 1; +#else /* LWIP_PPP_STRICT_PAP_REJECT */ + /* some providers request pap and accept an empty login/pw */ + ppp_settings.refuse_pap = 0; +#endif /* LWIP_PPP_STRICT_PAP_REJECT */ + ppp_settings.refuse_chap = 1; + break; + + case PPPAUTHTYPE_ANY: + /* 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. + * + */ + ppp_settings.refuse_pap = 0; + ppp_settings.refuse_chap = 0; + break; + + case PPPAUTHTYPE_PAP: + ppp_settings.refuse_pap = 0; + ppp_settings.refuse_chap = 1; + break; + + case PPPAUTHTYPE_CHAP: + ppp_settings.refuse_pap = 1; + ppp_settings.refuse_chap = 0; + break; + } + + if(user) { + strncpy(ppp_settings.user, user, sizeof(ppp_settings.user)-1); + ppp_settings.user[sizeof(ppp_settings.user)-1] = '\0'; + } else { + ppp_settings.user[0] = '\0'; + } + + if(passwd) { + strncpy(ppp_settings.passwd, passwd, sizeof(ppp_settings.passwd)-1); + ppp_settings.passwd[sizeof(ppp_settings.passwd)-1] = '\0'; + } else { + ppp_settings.passwd[0] = '\0'; + } +} + +#if PPPOS_SUPPORT +/** Open a new PPP connection using the given I/O device. + * This initializes the PPP control block but does not + * attempt to negotiate the LCP session. If this port + * connects to a modem, the modem connection must be + * established before calling this. + * Return a new PPP connection descriptor on success or + * an error code (negative) on failure. + * + * pppOpen() is directly defined to this function. + */ +int +pppOverSerialOpen(sio_fd_t fd, pppLinkStatusCB_fn linkStatusCB, void *linkStatusCtx) +{ + PPPControl *pc; + int pd; + + if (linkStatusCB == NULL) { + /* PPP is single-threaded: without a callback, + * there is no way to know when the link is up. */ + return PPPERR_PARAM; + } + + /* Find a free PPP session descriptor. */ + for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++); + + if (pd >= NUM_PPP) { + pd = PPPERR_OPEN; + } else { + pc = &pppControl[pd]; + /* input pbuf left over from last session? */ + pppFreeCurrentInputPacket(&pc->rx); + /* @todo: is this correct or do I overwrite something? */ + memset(pc, 0, sizeof(PPPControl)); + pc->rx.pd = pd; + pc->rx.fd = fd; + + pc->openFlag = 1; + pc->fd = fd; + +#if VJ_SUPPORT + vj_compress_init(&pc->vjComp); +#endif /* VJ_SUPPORT */ + + /* + * Default the in and out accm so that escape and flag characters + * are always escaped. + */ + pc->rx.inACCM[15] = 0x60; /* no need to protect since RX is not running */ + pc->outACCM[15] = 0x60; + + pc->linkStatusCB = linkStatusCB; + pc->linkStatusCtx = linkStatusCtx; + + /* + * Start the connection and handle incoming events (packet or timeout). + */ + PPPDEBUG(LOG_INFO, ("pppOverSerialOpen: unit %d: Connecting\n", pd)); + pppStart(pd); +#if PPP_INPROC_OWNTHREAD + sys_thread_new(PPP_THREAD_NAME, pppInputThread, (void*)&pc->rx, PPP_THREAD_STACKSIZE, PPP_THREAD_PRIO); +#endif /* PPP_INPROC_OWNTHREAD */ + } + + return pd; +} +#endif /* PPPOS_SUPPORT */ + +#if PPPOE_SUPPORT +static void pppOverEthernetLinkStatusCB(int pd, int up); + +void +pppOverEthernetClose(int pd) +{ + PPPControl* pc = &pppControl[pd]; + + /* *TJL* There's no lcp_deinit */ + lcp_close(pd, NULL); + + pppoe_destroy(&pc->netif); +} + +int pppOverEthernetOpen(struct netif *ethif, const char *service_name, const char *concentrator_name, + pppLinkStatusCB_fn linkStatusCB, void *linkStatusCtx) +{ + PPPControl *pc; + int pd; + + LWIP_UNUSED_ARG(service_name); + LWIP_UNUSED_ARG(concentrator_name); + + if (linkStatusCB == NULL) { + /* PPP is single-threaded: without a callback, + * there is no way to know when the link is up. */ + return PPPERR_PARAM; + } + + /* Find a free PPP session descriptor. Critical region? */ + for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++); + if (pd >= NUM_PPP) { + pd = PPPERR_OPEN; + } else { + pc = &pppControl[pd]; + memset(pc, 0, sizeof(PPPControl)); + pc->openFlag = 1; + pc->ethif = ethif; + + pc->linkStatusCB = linkStatusCB; + pc->linkStatusCtx = linkStatusCtx; + + lcp_wantoptions[pd].mru = PPPOE_MAXMTU; + lcp_wantoptions[pd].neg_asyncmap = 0; + lcp_wantoptions[pd].neg_pcompression = 0; + lcp_wantoptions[pd].neg_accompression = 0; + + lcp_allowoptions[pd].mru = PPPOE_MAXMTU; + lcp_allowoptions[pd].neg_asyncmap = 0; + lcp_allowoptions[pd].neg_pcompression = 0; + lcp_allowoptions[pd].neg_accompression = 0; + + if(pppoe_create(ethif, pd, pppOverEthernetLinkStatusCB, &pc->pppoe_sc) != ERR_OK) { + pc->openFlag = 0; + return PPPERR_OPEN; + } + + pppoe_connect(pc->pppoe_sc); + } + + return pd; +} +#endif /* PPPOE_SUPPORT */ + + +/* Close a PPP connection and release the descriptor. + * Any outstanding packets in the queues are dropped. + * Return 0 on success, an error code on failure. */ +int +pppClose(int pd) +{ + PPPControl *pc = &pppControl[pd]; + int st = 0; + + PPPDEBUG(LOG_DEBUG, ("pppClose() called\n")); + + /* Disconnect */ +#if PPPOE_SUPPORT + if(pc->ethif) { + PPPDEBUG(LOG_DEBUG, ("pppClose: unit %d kill_link -> pppStop\n", pd)); + pc->errCode = PPPERR_USER; + /* This will leave us at PHASE_DEAD. */ + pppStop(pd); + } else +#endif /* PPPOE_SUPPORT */ + { +#if PPPOS_SUPPORT + PPPDEBUG(LOG_DEBUG, ("pppClose: unit %d kill_link -> pppStop\n", pd)); + pc->errCode = PPPERR_USER; + /* This will leave us at PHASE_DEAD. */ + pppStop(pd); +#if PPP_INPROC_OWNTHREAD + pppRecvWakeup(pd); +#endif /* PPP_INPROC_OWNTHREAD */ +#endif /* PPPOS_SUPPORT */ + } + + return st; +} + +/* This function is called when carrier is lost on the PPP channel. */ +void +pppSigHUP(int pd) +{ + PPPDEBUG(LOG_DEBUG, ("pppSigHUP: unit %d sig_hup -> pppHupCB\n", pd)); + pppHup(pd); +} + +#if PPPOS_SUPPORT +static void +nPut(PPPControl *pc, struct pbuf *nb) +{ + struct pbuf *b; + int c; + + for(b = nb; b != NULL; b = b->next) { + if((c = sio_write(pc->fd, b->payload, b->len)) != b->len) { + PPPDEBUG(LOG_WARNING, + ("PPP nPut: incomplete sio_write(fd:%"SZT_F", len:%d, c: 0x%"X8_F") c = %d\n", (size_t)pc->fd, b->len, c, c)); + LINK_STATS_INC(link.err); + pc->lastXMit = 0; /* prepend PPP_FLAG to next packet */ + snmp_inc_ifoutdiscards(&pc->netif); + pbuf_free(nb); + return; + } + } + + snmp_add_ifoutoctets(&pc->netif, nb->tot_len); + snmp_inc_ifoutucastpkts(&pc->netif); + pbuf_free(nb); + LINK_STATS_INC(link.xmit); +} + +/* + * pppAppend - append given character to end of given pbuf. If outACCM + * is not NULL and the character needs to be escaped, do so. + * If pbuf is full, append another. + * Return the current pbuf. + */ +static struct pbuf * +pppAppend(u_char c, struct pbuf *nb, ext_accm *outACCM) +{ + struct pbuf *tb = nb; + + /* 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? */ + /* Note: We assume no packet header. */ + if (nb && (PBUF_POOL_BUFSIZE - nb->len) < 2) { + tb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL); + if (tb) { + nb->next = tb; + } else { + LINK_STATS_INC(link.memerr); + } + nb = tb; + } + + if (nb) { + if (outACCM && ESCAPE_P(*outACCM, c)) { + *((u_char*)nb->payload + nb->len++) = PPP_ESCAPE; + *((u_char*)nb->payload + nb->len++) = c ^ PPP_TRANS; + } else { + *((u_char*)nb->payload + nb->len++) = c; + } + } + + return tb; +} +#endif /* PPPOS_SUPPORT */ + +#if PPPOE_SUPPORT +static err_t +pppifOutputOverEthernet(int pd, struct pbuf *p) +{ + PPPControl *pc = &pppControl[pd]; + struct pbuf *pb; + u_short protocol = PPP_IP; + int i=0; + u16_t tot_len; + + /* @todo: try to use pbuf_header() here! */ + pb = pbuf_alloc(PBUF_LINK, PPPOE_HDRLEN + sizeof(protocol), PBUF_RAM); + if(!pb) { + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.proterr); + snmp_inc_ifoutdiscards(&pc->netif); + return ERR_MEM; + } + + pbuf_header(pb, -(s16_t)PPPOE_HDRLEN); + + pc->lastXMit = sys_jiffies(); + + if (!pc->pcomp || protocol > 0xFF) { + *((u_char*)pb->payload + i++) = (protocol >> 8) & 0xFF; + } + *((u_char*)pb->payload + i) = protocol & 0xFF; + + pbuf_chain(pb, p); + tot_len = pb->tot_len; + + if(pppoe_xmit(pc->pppoe_sc, pb) != ERR_OK) { + LINK_STATS_INC(link.err); + snmp_inc_ifoutdiscards(&pc->netif); + return PPPERR_DEVICE; + } + + snmp_add_ifoutoctets(&pc->netif, tot_len); + snmp_inc_ifoutucastpkts(&pc->netif); + LINK_STATS_INC(link.xmit); + return ERR_OK; +} +#endif /* PPPOE_SUPPORT */ + +/* Send a packet on the given connection. */ +static err_t +pppifOutput(struct netif *netif, struct pbuf *pb, ip_addr_t *ipaddr) +{ + int pd = (int)(size_t)netif->state; + PPPControl *pc = &pppControl[pd]; +#if PPPOS_SUPPORT + u_short protocol = PPP_IP; + u_int fcsOut = PPP_INITFCS; + struct pbuf *headMB = NULL, *tailMB = NULL, *p; + u_char c; +#endif /* PPPOS_SUPPORT */ + + LWIP_UNUSED_ARG(ipaddr); + + /* Validate parameters. */ + /* We let any protocol value go through - it can't hurt us + * and the peer will just drop it if it's not accepting it. */ + if (pd < 0 || pd >= NUM_PPP || !pc->openFlag || !pb) { + PPPDEBUG(LOG_WARNING, ("pppifOutput[%d]: bad parms prot=%d pb=%p\n", + pd, PPP_IP, pb)); + LINK_STATS_INC(link.opterr); + LINK_STATS_INC(link.drop); + snmp_inc_ifoutdiscards(netif); + return ERR_ARG; + } + + /* Check that the link is up. */ + if (lcp_phase[pd] == PHASE_DEAD) { + PPPDEBUG(LOG_ERR, ("pppifOutput[%d]: link not up\n", pd)); + LINK_STATS_INC(link.rterr); + LINK_STATS_INC(link.drop); + snmp_inc_ifoutdiscards(netif); + return ERR_RTE; + } + +#if PPPOE_SUPPORT + if(pc->ethif) { + return pppifOutputOverEthernet(pd, pb); + } +#endif /* PPPOE_SUPPORT */ + +#if PPPOS_SUPPORT + /* Grab an output buffer. */ + headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL); + if (headMB == NULL) { + PPPDEBUG(LOG_WARNING, ("pppifOutput[%d]: first alloc fail\n", pd)); + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + snmp_inc_ifoutdiscards(netif); + return ERR_MEM; + } + +#if VJ_SUPPORT + /* + * Attempt Van Jacobson header compression if VJ is configured and + * this is an IP packet. + */ + if (protocol == PPP_IP && pc->vjEnabled) { + switch (vj_compress_tcp(&pc->vjComp, pb)) { + case TYPE_IP: + /* No change... + protocol = PPP_IP_PROTOCOL; */ + break; + case TYPE_COMPRESSED_TCP: + protocol = PPP_VJC_COMP; + break; + case TYPE_UNCOMPRESSED_TCP: + protocol = PPP_VJC_UNCOMP; + break; + default: + PPPDEBUG(LOG_WARNING, ("pppifOutput[%d]: bad IP packet\n", pd)); + LINK_STATS_INC(link.proterr); + LINK_STATS_INC(link.drop); + snmp_inc_ifoutdiscards(netif); + pbuf_free(headMB); + return ERR_VAL; + } + } +#endif /* VJ_SUPPORT */ + + tailMB = headMB; + + /* Build the PPP header. */ + if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG) { + tailMB = pppAppend(PPP_FLAG, tailMB, NULL); + } + + pc->lastXMit = sys_jiffies(); + if (!pc->accomp) { + fcsOut = PPP_FCS(fcsOut, PPP_ALLSTATIONS); + tailMB = pppAppend(PPP_ALLSTATIONS, tailMB, &pc->outACCM); + fcsOut = PPP_FCS(fcsOut, PPP_UI); + tailMB = pppAppend(PPP_UI, tailMB, &pc->outACCM); + } + if (!pc->pcomp || protocol > 0xFF) { + c = (protocol >> 8) & 0xFF; + fcsOut = PPP_FCS(fcsOut, c); + tailMB = pppAppend(c, tailMB, &pc->outACCM); + } + c = protocol & 0xFF; + fcsOut = PPP_FCS(fcsOut, c); + tailMB = pppAppend(c, tailMB, &pc->outACCM); + + /* Load packet. */ + for(p = pb; p; p = p->next) { + int n; + u_char *sPtr; + + sPtr = (u_char*)p->payload; + n = p->len; + while (n-- > 0) { + c = *sPtr++; + + /* Update FCS before checking for special characters. */ + fcsOut = PPP_FCS(fcsOut, c); + + /* Copy to output buffer escaping special characters. */ + tailMB = pppAppend(c, tailMB, &pc->outACCM); + } + } + + /* Add FCS and trailing flag. */ + c = ~fcsOut & 0xFF; + tailMB = pppAppend(c, tailMB, &pc->outACCM); + c = (~fcsOut >> 8) & 0xFF; + tailMB = pppAppend(c, tailMB, &pc->outACCM); + tailMB = pppAppend(PPP_FLAG, tailMB, NULL); + + /* If we failed to complete the packet, throw it away. */ + if (!tailMB) { + PPPDEBUG(LOG_WARNING, + ("pppifOutput[%d]: Alloc err - dropping proto=%d\n", + pd, protocol)); + pbuf_free(headMB); + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + snmp_inc_ifoutdiscards(netif); + return ERR_MEM; + } + + /* Send it. */ + PPPDEBUG(LOG_INFO, ("pppifOutput[%d]: proto=0x%"X16_F"\n", pd, protocol)); + + nPut(pc, headMB); +#endif /* PPPOS_SUPPORT */ + + return ERR_OK; +} + +/* Get and set parameters for the given connection. + * Return 0 on success, an error code on failure. */ +int +pppIOCtl(int pd, int cmd, void *arg) +{ + PPPControl *pc = &pppControl[pd]; + int st = 0; + + if (pd < 0 || pd >= NUM_PPP) { + st = PPPERR_PARAM; + } else { + switch(cmd) { + case PPPCTLG_UPSTATUS: /* Get the PPP up status. */ + if (arg) { + *(int *)arg = (int)(pc->if_up); + } else { + st = PPPERR_PARAM; + } + break; + case PPPCTLS_ERRCODE: /* Set the PPP error code. */ + if (arg) { + pc->errCode = *(int *)arg; + } else { + st = PPPERR_PARAM; + } + break; + case PPPCTLG_ERRCODE: /* Get the PPP error code. */ + if (arg) { + *(int *)arg = (int)(pc->errCode); + } else { + st = PPPERR_PARAM; + } + break; +#if PPPOS_SUPPORT + case PPPCTLG_FD: /* Get the fd associated with the ppp */ + if (arg) { + *(sio_fd_t *)arg = pc->fd; + } else { + st = PPPERR_PARAM; + } + break; +#endif /* PPPOS_SUPPORT */ + default: + st = PPPERR_PARAM; + break; + } + } + + return st; +} + +/* + * Return the Maximum Transmission Unit for the given PPP connection. + */ +u_short +pppMTU(int pd) +{ + PPPControl *pc = &pppControl[pd]; + u_short st; + + /* Validate parameters. */ + if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) { + st = 0; + } else { + st = pc->mtu; + } + + return st; +} + +#if PPPOE_SUPPORT +int +pppWriteOverEthernet(int pd, const u_char *s, int n) +{ + PPPControl *pc = &pppControl[pd]; + struct pbuf *pb; + + /* skip address & flags */ + s += 2; + n -= 2; + + LWIP_ASSERT("PPPOE_HDRLEN + n <= 0xffff", PPPOE_HDRLEN + n <= 0xffff); + pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HDRLEN + n), PBUF_RAM); + if(!pb) { + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.proterr); + snmp_inc_ifoutdiscards(&pc->netif); + return PPPERR_ALLOC; + } + + pbuf_header(pb, -(s16_t)PPPOE_HDRLEN); + + pc->lastXMit = sys_jiffies(); + + MEMCPY(pb->payload, s, n); + + if(pppoe_xmit(pc->pppoe_sc, pb) != ERR_OK) { + LINK_STATS_INC(link.err); + snmp_inc_ifoutdiscards(&pc->netif); + return PPPERR_DEVICE; + } + + snmp_add_ifoutoctets(&pc->netif, (u16_t)n); + snmp_inc_ifoutucastpkts(&pc->netif); + LINK_STATS_INC(link.xmit); + return PPPERR_NONE; +} +#endif /* PPPOE_SUPPORT */ + +/* + * Write n characters to a ppp link. + * RETURN: >= 0 Number of characters written + * -1 Failed to write to device + */ +int +pppWrite(int pd, const u_char *s, int n) +{ + PPPControl *pc = &pppControl[pd]; +#if PPPOS_SUPPORT + u_char c; + u_int fcsOut; + struct pbuf *headMB, *tailMB; +#endif /* PPPOS_SUPPORT */ + +#if PPPOE_SUPPORT + if(pc->ethif) { + return pppWriteOverEthernet(pd, s, n); + } +#endif /* PPPOE_SUPPORT */ + +#if PPPOS_SUPPORT + headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL); + if (headMB == NULL) { + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.proterr); + snmp_inc_ifoutdiscards(&pc->netif); + return PPPERR_ALLOC; + } + + tailMB = headMB; + + /* If the link has been idle, we'll send a fresh flag character to + * flush any noise. */ + if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG) { + tailMB = pppAppend(PPP_FLAG, tailMB, NULL); + } + pc->lastXMit = sys_jiffies(); + + fcsOut = PPP_INITFCS; + /* Load output buffer. */ + while (n-- > 0) { + c = *s++; + + /* Update FCS before checking for special characters. */ + fcsOut = PPP_FCS(fcsOut, c); + + /* Copy to output buffer escaping special characters. */ + tailMB = pppAppend(c, tailMB, &pc->outACCM); + } + + /* Add FCS and trailing flag. */ + c = ~fcsOut & 0xFF; + tailMB = pppAppend(c, tailMB, &pc->outACCM); + c = (~fcsOut >> 8) & 0xFF; + tailMB = pppAppend(c, tailMB, &pc->outACCM); + tailMB = pppAppend(PPP_FLAG, tailMB, NULL); + + /* If we failed to complete the packet, throw it away. + * Otherwise send it. */ + if (!tailMB) { + PPPDEBUG(LOG_WARNING, + ("pppWrite[%d]: Alloc err - dropping pbuf len=%d\n", pd, headMB->len)); + /*"pppWrite[%d]: Alloc err - dropping %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */ + pbuf_free(headMB); + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.proterr); + snmp_inc_ifoutdiscards(&pc->netif); + return PPPERR_ALLOC; + } + + PPPDEBUG(LOG_INFO, ("pppWrite[%d]: len=%d\n", pd, headMB->len)); + /* "pppWrite[%d]: %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */ + nPut(pc, headMB); +#endif /* PPPOS_SUPPORT */ + + return PPPERR_NONE; +} + +/* + * ppp_send_config - configure the transmit characteristics of + * the ppp interface. + */ +void +ppp_send_config( int unit, u16_t mtu, u32_t asyncmap, int pcomp, int accomp) +{ + PPPControl *pc = &pppControl[unit]; + int i; + + pc->mtu = mtu; + pc->pcomp = pcomp; + pc->accomp = accomp; + + /* Load the ACCM bits for the 32 control codes. */ + for (i = 0; i < 32/8; i++) { + pc->outACCM[i] = (u_char)((asyncmap >> (8 * i)) & 0xFF); + } + PPPDEBUG(LOG_INFO, ("ppp_send_config[%d]: outACCM=%X %X %X %X\n", + unit, + pc->outACCM[0], pc->outACCM[1], pc->outACCM[2], pc->outACCM[3])); +} + + +/* + * ppp_set_xaccm - set the extended transmit ACCM for the interface. + */ +void +ppp_set_xaccm(int unit, ext_accm *accm) +{ + SMEMCPY(pppControl[unit].outACCM, accm, sizeof(ext_accm)); + PPPDEBUG(LOG_INFO, ("ppp_set_xaccm[%d]: outACCM=%X %X %X %X\n", + unit, + pppControl[unit].outACCM[0], + pppControl[unit].outACCM[1], + pppControl[unit].outACCM[2], + pppControl[unit].outACCM[3])); +} + + +/* + * ppp_recv_config - configure the receive-side characteristics of + * the ppp interface. + */ +void +ppp_recv_config( int unit, int mru, u32_t asyncmap, int pcomp, int accomp) +{ + PPPControl *pc = &pppControl[unit]; + int i; + SYS_ARCH_DECL_PROTECT(lev); + + LWIP_UNUSED_ARG(accomp); + LWIP_UNUSED_ARG(pcomp); + LWIP_UNUSED_ARG(mru); + + /* Load the ACCM bits for the 32 control codes. */ + SYS_ARCH_PROTECT(lev); + for (i = 0; i < 32 / 8; i++) { + /* @todo: does this work? ext_accm has been modified from pppd! */ + pc->rx.inACCM[i] = (u_char)(asyncmap >> (i * 8)); + } + SYS_ARCH_UNPROTECT(lev); + PPPDEBUG(LOG_INFO, ("ppp_recv_config[%d]: inACCM=%X %X %X %X\n", + unit, + pc->rx.inACCM[0], pc->rx.inACCM[1], pc->rx.inACCM[2], pc->rx.inACCM[3])); +} + +#if 0 +/* + * ccp_test - ask kernel whether a given compression method + * is acceptable for use. Returns 1 if the method and parameters + * are OK, 0 if the method is known but the parameters are not OK + * (e.g. code size should be reduced), or -1 if the method is unknown. + */ +int +ccp_test( int unit, int opt_len, int for_transmit, u_char *opt_ptr) +{ + return 0; /* XXX Currently no compression. */ +} + +/* + * ccp_flags_set - inform kernel about the current state of CCP. + */ +void +ccp_flags_set(int unit, int isopen, int isup) +{ + /* XXX */ +} + +/* + * 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(int unit) +{ + /* XXX */ + return 0; +} +#endif + +/* + * get_idle_time - return how long the link has been idle. + */ +int +get_idle_time(int u, struct ppp_idle *ip) +{ + /* XXX */ + LWIP_UNUSED_ARG(u); + LWIP_UNUSED_ARG(ip); + + return 0; +} + + +/* + * 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 +GetMask(u32_t addr) +{ + u32_t mask, nmask; + + addr = htonl(addr); + if (IP_CLASSA(addr)) { /* determine network mask for address class */ + nmask = IP_CLASSA_NET; + } else if (IP_CLASSB(addr)) { + nmask = IP_CLASSB_NET; + } else { + nmask = IP_CLASSC_NET; + } + + /* class D nets are disallowed by bad_ip_adrs */ + mask = PP_HTONL(0xffffff00UL) | htonl(nmask); + + /* XXX + * Scan through the system's network interfaces. + * Get each netmask and OR them into our mask. + */ + + return mask; +} + +/* + * sifvjcomp - config tcp header compression + */ +int +sifvjcomp(int pd, int vjcomp, u8_t cidcomp, u8_t maxcid) +{ +#if PPPOS_SUPPORT && VJ_SUPPORT + PPPControl *pc = &pppControl[pd]; + + pc->vjEnabled = vjcomp; + pc->vjComp.compressSlot = cidcomp; + pc->vjComp.maxSlotIndex = maxcid; + PPPDEBUG(LOG_INFO, ("sifvjcomp: VJ compress enable=%d slot=%d max slot=%d\n", + vjcomp, cidcomp, maxcid)); +#else /* PPPOS_SUPPORT && VJ_SUPPORT */ + LWIP_UNUSED_ARG(pd); + LWIP_UNUSED_ARG(vjcomp); + LWIP_UNUSED_ARG(cidcomp); + LWIP_UNUSED_ARG(maxcid); +#endif /* PPPOS_SUPPORT && VJ_SUPPORT */ + + return 0; +} + +/* + * pppifNetifInit - netif init callback + */ +static err_t +pppifNetifInit(struct netif *netif) +{ + netif->name[0] = 'p'; + netif->name[1] = 'p'; + netif->output = pppifOutput; + netif->mtu = pppMTU((int)(size_t)netif->state); + netif->flags = NETIF_FLAG_POINTTOPOINT | NETIF_FLAG_LINK_UP; +#if LWIP_NETIF_HOSTNAME + /* @todo: Initialize interface hostname */ + /* netif_set_hostname(netif, "lwip"); */ +#endif /* LWIP_NETIF_HOSTNAME */ + return ERR_OK; +} + + +/* + * sifup - Config the interface up and enable IP packets to pass. + */ +int +sifup(int pd) +{ + PPPControl *pc = &pppControl[pd]; + int st = 1; + + if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) { + st = 0; + PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd)); + } else { + netif_remove(&pc->netif); + if (netif_add(&pc->netif, &pc->addrs.our_ipaddr, &pc->addrs.netmask, + &pc->addrs.his_ipaddr, (void *)(size_t)pd, pppifNetifInit, ip_input)) { + netif_set_up(&pc->netif); + pc->if_up = 1; + pc->errCode = PPPERR_NONE; + + PPPDEBUG(LOG_DEBUG, ("sifup: unit %d: linkStatusCB=%p errCode=%d\n", pd, pc->linkStatusCB, pc->errCode)); + if (pc->linkStatusCB) { + pc->linkStatusCB(pc->linkStatusCtx, pc->errCode, &pc->addrs); + } + } else { + st = 0; + PPPDEBUG(LOG_ERR, ("sifup[%d]: netif_add failed\n", pd)); + } + } + + return st; +} + +/* + * sifnpmode - Set the mode for handling packets for a given NP. + */ +int +sifnpmode(int u, int proto, enum NPmode mode) +{ + LWIP_UNUSED_ARG(u); + LWIP_UNUSED_ARG(proto); + LWIP_UNUSED_ARG(mode); + return 0; +} + +/* + * sifdown - Config the interface down and disable IP. + */ +int +sifdown(int pd) +{ + PPPControl *pc = &pppControl[pd]; + int st = 1; + + if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) { + st = 0; + PPPDEBUG(LOG_WARNING, ("sifdown[%d]: bad parms\n", pd)); + } else { + pc->if_up = 0; + /* make sure the netif status callback is called */ + netif_set_down(&pc->netif); + netif_remove(&pc->netif); + PPPDEBUG(LOG_DEBUG, ("sifdown: unit %d: linkStatusCB=%p errCode=%d\n", pd, pc->linkStatusCB, pc->errCode)); + if (pc->linkStatusCB) { + pc->linkStatusCB(pc->linkStatusCtx, PPPERR_CONNECT, NULL); + } + } + return st; +} + +/** + * sifaddr - Config the interface IP addresses and netmask. + * @param pd Interface unit ??? + * @param o Our IP address ??? + * @param h His IP address ??? + * @param m IP subnet mask ??? + * @param ns1 Primary DNS + * @param ns2 Secondary DNS + */ +int +sifaddr( int pd, u32_t o, u32_t h, u32_t m, u32_t ns1, u32_t ns2) +{ + PPPControl *pc = &pppControl[pd]; + int st = 1; + + if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) { + st = 0; + PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd)); + } else { + SMEMCPY(&pc->addrs.our_ipaddr, &o, sizeof(o)); + SMEMCPY(&pc->addrs.his_ipaddr, &h, sizeof(h)); + SMEMCPY(&pc->addrs.netmask, &m, sizeof(m)); + SMEMCPY(&pc->addrs.dns1, &ns1, sizeof(ns1)); + SMEMCPY(&pc->addrs.dns2, &ns2, sizeof(ns2)); + } + return st; +} + +/** + * cifaddr - Clear the interface IP addresses, and delete routes + * through the interface if possible. + * @param pd Interface unit ??? + * @param o Our IP address ??? + * @param h IP broadcast address ??? + */ +int +cifaddr( int pd, u32_t o, u32_t h) +{ + PPPControl *pc = &pppControl[pd]; + int st = 1; + + LWIP_UNUSED_ARG(o); + LWIP_UNUSED_ARG(h); + if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) { + st = 0; + PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd)); + } else { + IP4_ADDR(&pc->addrs.our_ipaddr, 0,0,0,0); + IP4_ADDR(&pc->addrs.his_ipaddr, 0,0,0,0); + IP4_ADDR(&pc->addrs.netmask, 255,255,255,0); + IP4_ADDR(&pc->addrs.dns1, 0,0,0,0); + IP4_ADDR(&pc->addrs.dns2, 0,0,0,0); + } + return st; +} + +/* + * sifdefaultroute - assign a default route through the address given. + */ +int +sifdefaultroute(int pd, u32_t l, u32_t g) +{ + PPPControl *pc = &pppControl[pd]; + int st = 1; + + LWIP_UNUSED_ARG(l); + LWIP_UNUSED_ARG(g); + + if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) { + st = 0; + PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd)); + } else { + netif_set_default(&pc->netif); + } + + /* TODO: check how PPP handled the netMask, previously not set by ipSetDefault */ + + return st; +} + +/* + * cifdefaultroute - delete a default route through the address given. + */ +int +cifdefaultroute(int pd, u32_t l, u32_t g) +{ + PPPControl *pc = &pppControl[pd]; + int st = 1; + + LWIP_UNUSED_ARG(l); + LWIP_UNUSED_ARG(g); + + if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) { + st = 0; + PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd)); + } else { + netif_set_default(NULL); + } + + return st; +} + +/**********************************/ +/*** LOCAL FUNCTION DEFINITIONS ***/ +/**********************************/ + +#if PPPOS_SUPPORT && PPP_INPROC_OWNTHREAD +/* The main PPP process function. This implements the state machine according + * to section 4 of RFC 1661: The Point-To-Point Protocol. */ +static void +pppInputThread(void *arg) +{ + int count; + PPPControlRx *pcrx = arg; + + while (lcp_phase[pcrx->pd] != PHASE_DEAD) { + count = sio_read(pcrx->fd, pcrx->rxbuf, PPPOS_RX_BUFSIZE); + if(count > 0) { + pppInProc(pcrx, pcrx->rxbuf, count); + } else { + /* nothing received, give other tasks a chance to run */ + sys_msleep(1); + } + } +} +#endif /* PPPOS_SUPPORT && PPP_INPROC_OWNTHREAD */ + +#if PPPOE_SUPPORT + +void +pppOverEthernetInitFailed(int pd) +{ + PPPControl* pc; + + pppHup(pd); + pppStop(pd); + + pc = &pppControl[pd]; + pppoe_destroy(&pc->netif); + pc->openFlag = 0; + + if(pc->linkStatusCB) { + pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL); + } +} + +static void +pppOverEthernetLinkStatusCB(int pd, int up) +{ + if(up) { + PPPDEBUG(LOG_INFO, ("pppOverEthernetLinkStatusCB: unit %d: Connecting\n", pd)); + pppStart(pd); + } else { + pppOverEthernetInitFailed(pd); + } +} +#endif /* PPPOE_SUPPORT */ + +struct pbuf * +pppSingleBuf(struct pbuf *p) +{ + struct pbuf *q, *b; + u_char *pl; + + if(p->tot_len == p->len) { + return p; + } + + q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); + if(!q) { + PPPDEBUG(LOG_ERR, + ("pppSingleBuf: unable to alloc new buf (%d)\n", p->tot_len)); + return p; /* live dangerously */ + } + + for(b = p, pl = q->payload; b != NULL; b = b->next) { + MEMCPY(pl, b->payload, b->len); + pl += b->len; + } + + pbuf_free(p); + + return q; +} + +/** Input helper struct, must be packed since it is stored to pbuf->payload, + * which might be unaligned. + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct pppInputHeader { + PACK_STRUCT_FIELD(int unit); + PACK_STRUCT_FIELD(u16_t proto); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* + * Pass the processed input packet to the appropriate handler. + * This function and all handlers run in the context of the tcpip_thread + */ +static void +pppInput(void *arg) +{ + struct pbuf *nb = (struct pbuf *)arg; + u16_t protocol; + int pd; + + pd = ((struct pppInputHeader *)nb->payload)->unit; + protocol = ((struct pppInputHeader *)nb->payload)->proto; + + if(pbuf_header(nb, -(int)sizeof(struct pppInputHeader))) { + LWIP_ASSERT("pbuf_header failed\n", 0); + goto drop; + } + + LINK_STATS_INC(link.recv); + snmp_inc_ifinucastpkts(&pppControl[pd].netif); + snmp_add_ifinoctets(&pppControl[pd].netif, nb->tot_len); + + /* + * Toss all non-LCP packets unless LCP is OPEN. + * Until we get past the authentication phase, toss all packets + * except LCP, LQR and authentication packets. + */ + if((lcp_phase[pd] <= PHASE_AUTHENTICATE) && (protocol != PPP_LCP)) { + if(!((protocol == PPP_LQR) || (protocol == PPP_PAP) || (protocol == PPP_CHAP)) || + (lcp_phase[pd] != PHASE_AUTHENTICATE)) { + PPPDEBUG(LOG_INFO, ("pppInput: discarding proto 0x%"X16_F" in phase %d\n", protocol, lcp_phase[pd])); + goto drop; + } + } + + switch(protocol) { + case PPP_VJC_COMP: /* VJ compressed TCP */ +#if PPPOS_SUPPORT && VJ_SUPPORT + PPPDEBUG(LOG_INFO, ("pppInput[%d]: vj_comp in pbuf len=%d\n", pd, nb->len)); + /* + * Clip off the VJ header and prepend the rebuilt TCP/IP header and + * pass the result to IP. + */ + if ((vj_uncompress_tcp(&nb, &pppControl[pd].vjComp) >= 0) && (pppControl[pd].netif.input)) { + pppControl[pd].netif.input(nb, &pppControl[pd].netif); + return; + } + /* Something's wrong so drop it. */ + PPPDEBUG(LOG_WARNING, ("pppInput[%d]: Dropping VJ compressed\n", pd)); +#else /* PPPOS_SUPPORT && VJ_SUPPORT */ + /* No handler for this protocol so drop the packet. */ + PPPDEBUG(LOG_INFO, ("pppInput[%d]: drop VJ Comp in %d:%s\n", pd, nb->len, nb->payload)); +#endif /* PPPOS_SUPPORT && VJ_SUPPORT */ + break; + + case PPP_VJC_UNCOMP: /* VJ uncompressed TCP */ +#if PPPOS_SUPPORT && VJ_SUPPORT + PPPDEBUG(LOG_INFO, ("pppInput[%d]: vj_un in pbuf len=%d\n", pd, nb->len)); + /* + * Process the TCP/IP header for VJ header compression and then pass + * the packet to IP. + */ + if ((vj_uncompress_uncomp(nb, &pppControl[pd].vjComp) >= 0) && pppControl[pd].netif.input) { + pppControl[pd].netif.input(nb, &pppControl[pd].netif); + return; + } + /* Something's wrong so drop it. */ + PPPDEBUG(LOG_WARNING, ("pppInput[%d]: Dropping VJ uncompressed\n", pd)); +#else /* PPPOS_SUPPORT && VJ_SUPPORT */ + /* No handler for this protocol so drop the packet. */ + PPPDEBUG(LOG_INFO, + ("pppInput[%d]: drop VJ UnComp in %d:.*H\n", + pd, nb->len, LWIP_MIN(nb->len * 2, 40), nb->payload)); +#endif /* PPPOS_SUPPORT && VJ_SUPPORT */ + break; + + case PPP_IP: /* Internet Protocol */ + PPPDEBUG(LOG_INFO, ("pppInput[%d]: ip in pbuf len=%d\n", pd, nb->len)); + if (pppControl[pd].netif.input) { + pppControl[pd].netif.input(nb, &pppControl[pd].netif); + return; + } + break; + + default: { + struct protent *protp; + int i; + + /* + * Upcall the proper protocol input routine. + */ + for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) { + if (protp->protocol == protocol && protp->enabled_flag) { + PPPDEBUG(LOG_INFO, ("pppInput[%d]: %s len=%d\n", pd, protp->name, nb->len)); + nb = pppSingleBuf(nb); + (*protp->input)(pd, nb->payload, nb->len); + PPPDEBUG(LOG_DETAIL, ("pppInput[%d]: packet processed\n", pd)); + goto out; + } + } + + /* No handler for this protocol so reject the packet. */ + PPPDEBUG(LOG_INFO, ("pppInput[%d]: rejecting unsupported proto 0x%"X16_F" len=%d\n", pd, protocol, nb->len)); + if (pbuf_header(nb, sizeof(protocol))) { + LWIP_ASSERT("pbuf_header failed\n", 0); + goto drop; + } +#if BYTE_ORDER == LITTLE_ENDIAN + protocol = htons(protocol); +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + SMEMCPY(nb->payload, &protocol, sizeof(protocol)); + lcp_sprotrej(pd, nb->payload, nb->len); + } + break; + } + +drop: + LINK_STATS_INC(link.drop); + snmp_inc_ifindiscards(&pppControl[pd].netif); + +out: + pbuf_free(nb); + return; +} + +#if PPPOS_SUPPORT +/* + * Drop the input packet. + */ +static void +pppFreeCurrentInputPacket(PPPControlRx *pcrx) +{ + if (pcrx->inHead != NULL) { + if (pcrx->inTail && (pcrx->inTail != pcrx->inHead)) { + pbuf_free(pcrx->inTail); + } + pbuf_free(pcrx->inHead); + pcrx->inHead = NULL; + } + pcrx->inTail = NULL; +} + +/* + * Drop the input packet and increase error counters. + */ +static void +pppDrop(PPPControlRx *pcrx) +{ + if (pcrx->inHead != NULL) { +#if 0 + PPPDEBUG(LOG_INFO, ("pppDrop: %d:%.*H\n", pcrx->inHead->len, min(60, pcrx->inHead->len * 2), pcrx->inHead->payload)); +#endif + PPPDEBUG(LOG_INFO, ("pppDrop: pbuf len=%d, addr %p\n", pcrx->inHead->len, (void*)pcrx->inHead)); + } + pppFreeCurrentInputPacket(pcrx); +#if VJ_SUPPORT + vj_uncompress_err(&pppControl[pcrx->pd].vjComp); +#endif /* VJ_SUPPORT */ + + LINK_STATS_INC(link.drop); + snmp_inc_ifindiscards(&pppControl[pcrx->pd].netif); +} + +#if !PPP_INPROC_OWNTHREAD +/** Pass received raw characters to PPPoS to be decoded. This function is + * thread-safe and can be called from a dedicated RX-thread or from a main-loop. + * + * @param pd PPP descriptor index, returned by pppOpen() + * @param data received data + * @param len length of received data + */ +void +pppos_input(int pd, u_char* data, int len) +{ + pppInProc(&pppControl[pd].rx, data, len); +} +#endif + +/** + * Process a received octet string. + */ +static void +pppInProc(PPPControlRx *pcrx, u_char *s, int l) +{ + struct pbuf *nextNBuf; + u_char curChar; + u_char escaped; + SYS_ARCH_DECL_PROTECT(lev); + + PPPDEBUG(LOG_DEBUG, ("pppInProc[%d]: got %d bytes\n", pcrx->pd, l)); + while (l-- > 0) { + curChar = *s++; + + SYS_ARCH_PROTECT(lev); + escaped = ESCAPE_P(pcrx->inACCM, curChar); + SYS_ARCH_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 (curChar == PPP_ESCAPE) { + pcrx->inEscaped = 1; + /* Check for the flag character. */ + } else if (curChar == PPP_FLAG) { + /* If this is just an extra flag character, ignore it. */ + if (pcrx->inState <= PDADDRESS) { + /* ignore it */; + /* If we haven't received the packet header, drop what has come in. */ + } else if (pcrx->inState < PDDATA) { + PPPDEBUG(LOG_WARNING, + ("pppInProc[%d]: Dropping incomplete packet %d\n", + pcrx->pd, pcrx->inState)); + LINK_STATS_INC(link.lenerr); + pppDrop(pcrx); + /* If the fcs is invalid, drop the packet. */ + } else if (pcrx->inFCS != PPP_GOODFCS) { + PPPDEBUG(LOG_INFO, + ("pppInProc[%d]: Dropping bad fcs 0x%"X16_F" proto=0x%"X16_F"\n", + pcrx->pd, pcrx->inFCS, pcrx->inProtocol)); + /* Note: If you get lots of these, check for UART frame errors or try different baud rate */ + LINK_STATS_INC(link.chkerr); + pppDrop(pcrx); + /* Otherwise it's a good packet so pass it on. */ + } else { + struct pbuf *inp; + /* Trim off the checksum. */ + if(pcrx->inTail->len > 2) { + pcrx->inTail->len -= 2; + + pcrx->inTail->tot_len = pcrx->inTail->len; + if (pcrx->inTail != pcrx->inHead) { + pbuf_cat(pcrx->inHead, pcrx->inTail); + } + } else { + pcrx->inTail->tot_len = pcrx->inTail->len; + if (pcrx->inTail != pcrx->inHead) { + pbuf_cat(pcrx->inHead, pcrx->inTail); + } + + pbuf_realloc(pcrx->inHead, pcrx->inHead->tot_len - 2); + } + + /* Dispatch the packet thereby consuming it. */ + inp = pcrx->inHead; + /* Packet consumed, release our references. */ + pcrx->inHead = NULL; + pcrx->inTail = NULL; +#if PPP_INPROC_MULTITHREADED + if(tcpip_callback_with_block(pppInput, inp, 0) != ERR_OK) { + PPPDEBUG(LOG_ERR, ("pppInProc[%d]: tcpip_callback() failed, dropping packet\n", pcrx->pd)); + pbuf_free(inp); + LINK_STATS_INC(link.drop); + snmp_inc_ifindiscards(&pppControl[pcrx->pd].netif); + } +#else /* PPP_INPROC_MULTITHREADED */ + pppInput(inp); +#endif /* PPP_INPROC_MULTITHREADED */ + } + + /* Prepare for a new packet. */ + pcrx->inFCS = PPP_INITFCS; + pcrx->inState = PDADDRESS; + pcrx->inEscaped = 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, + ("pppInProc[%d]: Dropping ACCM char <%d>\n", pcrx->pd, curChar)); + } + /* Process other characters. */ + } else { + /* Unencode escaped characters. */ + if (pcrx->inEscaped) { + pcrx->inEscaped = 0; + curChar ^= PPP_TRANS; + } + + /* Process character relative to current state. */ + switch(pcrx->inState) { + case PDIDLE: /* Idle state - waiting. */ + /* Drop the character if it's not 0xff + * we would have processed a flag character above. */ + if (curChar != PPP_ALLSTATIONS) { + break; + } + + /* Fall through */ + case PDSTART: /* Process start flag. */ + /* Prepare for a new packet. */ + pcrx->inFCS = PPP_INITFCS; + + /* Fall through */ + case PDADDRESS: /* Process address field. */ + if (curChar == PPP_ALLSTATIONS) { + pcrx->inState = PDCONTROL; + 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 (curChar == PPP_UI) { + pcrx->inState = PDPROTOCOL1; + break; + } +#if 0 + else { + PPPDEBUG(LOG_WARNING, + ("pppInProc[%d]: Invalid control <%d>\n", pcrx->pd, curChar)); + pcrx->inState = PDSTART; + } +#endif + case PDPROTOCOL1: /* Process protocol field 1. */ + /* If the lower bit is set, this is the end of the protocol + * field. */ + if (curChar & 1) { + pcrx->inProtocol = curChar; + pcrx->inState = PDDATA; + } else { + pcrx->inProtocol = (u_int)curChar << 8; + pcrx->inState = PDPROTOCOL2; + } + break; + case PDPROTOCOL2: /* Process protocol field 2. */ + pcrx->inProtocol |= curChar; + pcrx->inState = PDDATA; + break; + case PDDATA: /* Process data byte. */ + /* Make space to receive processed data. */ + if (pcrx->inTail == NULL || pcrx->inTail->len == PBUF_POOL_BUFSIZE) { + if (pcrx->inTail != NULL) { + pcrx->inTail->tot_len = pcrx->inTail->len; + if (pcrx->inTail != pcrx->inHead) { + pbuf_cat(pcrx->inHead, pcrx->inTail); + /* give up the inTail reference now */ + pcrx->inTail = NULL; + } + } + /* If we haven't started a packet, we need a packet header. */ + nextNBuf = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL); + if (nextNBuf == 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, ("pppInProc[%d]: NO FREE MBUFS!\n", pcrx->pd)); + LINK_STATS_INC(link.memerr); + pppDrop(pcrx); + pcrx->inState = PDSTART; /* Wait for flag sequence. */ + break; + } + if (pcrx->inHead == NULL) { + struct pppInputHeader *pih = nextNBuf->payload; + + pih->unit = pcrx->pd; + pih->proto = pcrx->inProtocol; + + nextNBuf->len += sizeof(*pih); + + pcrx->inHead = nextNBuf; + } + pcrx->inTail = nextNBuf; + } + /* Load character into buffer. */ + ((u_char*)pcrx->inTail->payload)[pcrx->inTail->len++] = curChar; + break; + } + + /* update the frame check sequence number. */ + pcrx->inFCS = PPP_FCS(pcrx->inFCS, curChar); + } + } /* while (l-- > 0), all bytes processed */ + + avRandomize(); +} +#endif /* PPPOS_SUPPORT */ + +#if PPPOE_SUPPORT +void +pppInProcOverEthernet(int pd, struct pbuf *pb) +{ + struct pppInputHeader *pih; + u16_t inProtocol; + + if(pb->len < sizeof(inProtocol)) { + PPPDEBUG(LOG_ERR, ("pppInProcOverEthernet: too small for protocol field\n")); + goto drop; + } + + inProtocol = (((u8_t *)pb->payload)[0] << 8) | ((u8_t*)pb->payload)[1]; + + /* make room for pppInputHeader - should not fail */ + if (pbuf_header(pb, sizeof(*pih) - sizeof(inProtocol)) != 0) { + PPPDEBUG(LOG_ERR, ("pppInProcOverEthernet: could not allocate room for header\n")); + goto drop; + } + + pih = pb->payload; + + pih->unit = pd; + pih->proto = inProtocol; + + /* Dispatch the packet thereby consuming it. */ + pppInput(pb); + return; + +drop: + LINK_STATS_INC(link.drop); + snmp_inc_ifindiscards(&pppControl[pd].netif); + pbuf_free(pb); + return; +} +#endif /* PPPOE_SUPPORT */ + +#if LWIP_NETIF_STATUS_CALLBACK +/** Set the status callback of a PPP's netif + * + * @param pd The PPP descriptor returned by pppOpen() + * @param status_callback pointer to the status callback function + * + * @see netif_set_status_callback + */ +void +ppp_set_netif_statuscallback(int pd, netif_status_callback_fn status_callback) +{ + netif_set_status_callback(&pppControl[pd].netif, status_callback); +} +#endif /* LWIP_NETIF_STATUS_CALLBACK */ + +#if LWIP_NETIF_LINK_CALLBACK +/** Set the link callback of a PPP's netif + * + * @param pd The PPP descriptor returned by pppOpen() + * @param link_callback pointer to the link callback function + * + * @see netif_set_link_callback + */ +void +ppp_set_netif_linkcallback(int pd, netif_status_callback_fn link_callback) +{ + netif_set_link_callback(&pppControl[pd].netif, link_callback); +} +#endif /* LWIP_NETIF_LINK_CALLBACK */ + +#endif /* PPP_SUPPORT */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/ppp.h b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/ppp.h new file mode 100644 index 0000000..08d6e62 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/ppp.h @@ -0,0 +1,201 @@ +/***************************************************************************** +* 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 PPP_H +#define PPP_H + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/def.h" +#include "lwip/sio.h" +#include "lwip/stats.h" +#include "lwip/mem.h" +#include "lwip/netif.h" +#include "lwip/sys.h" +#include "lwip/timers.h" + + +#ifndef __u_char_defined + +/* Type definitions for BSD code. */ +typedef unsigned long u_long; +typedef unsigned int u_int; +typedef unsigned short u_short; +typedef unsigned char u_char; + +#endif + + +/************************* +*** PUBLIC DEFINITIONS *** +*************************/ + +/* 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. */ + +/* + * PPP IOCTL commands. + */ +/* + * Get the up status - 0 for down, non-zero for up. The argument must + * point to an int. + */ +#define PPPCTLG_UPSTATUS 100 /* Get the up status - 0 down else up */ +#define PPPCTLS_ERRCODE 101 /* Set the error code */ +#define PPPCTLG_ERRCODE 102 /* Get the error code */ +#define PPPCTLG_FD 103 /* Get the fd associated with the ppp */ + +/************************ +*** PUBLIC DATA TYPES *** +************************/ + +struct ppp_addrs { + ip_addr_t our_ipaddr, his_ipaddr, netmask, dns1, dns2; +}; + + +/*********************** +*** PUBLIC FUNCTIONS *** +***********************/ + +/* Initialize the PPP subsystem. */ +void pppInit(void); + +/* 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. + * + */ +enum pppAuthType { + PPPAUTHTYPE_NONE, + PPPAUTHTYPE_ANY, + PPPAUTHTYPE_PAP, + PPPAUTHTYPE_CHAP +}; + +void pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd); + +/* Link status callback function prototype */ +typedef void (*pppLinkStatusCB_fn)(void *ctx, int errCode, void *arg); + +#if PPPOS_SUPPORT +/* + * Open a new PPP connection using the given serial I/O device. + * This initializes the PPP control block but does not + * attempt to negotiate the LCP session. + * Return a new PPP connection descriptor on success or + * an error code (negative) on failure. + */ +int pppOverSerialOpen(sio_fd_t fd, pppLinkStatusCB_fn linkStatusCB, void *linkStatusCtx); +#endif /* PPPOS_SUPPORT */ + +#if PPPOE_SUPPORT +/* + * Open a new PPP Over Ethernet (PPPOE) connection. + */ +int pppOverEthernetOpen(struct netif *ethif, const char *service_name, const char *concentrator_name, + pppLinkStatusCB_fn linkStatusCB, void *linkStatusCtx); +#endif /* PPPOE_SUPPORT */ + +/* for source code compatibility */ +#define pppOpen(fd,cb,ls) pppOverSerialOpen(fd,cb,ls) + +/* + * Close a PPP connection and release the descriptor. + * Any outstanding packets in the queues are dropped. + * Return 0 on success, an error code on failure. + */ +int pppClose(int pd); + +/* + * Indicate to the PPP process that the line has disconnected. + */ +void pppSigHUP(int pd); + +/* + * Get and set parameters for the given connection. + * Return 0 on success, an error code on failure. + */ +int pppIOCtl(int pd, int cmd, void *arg); + +/* + * Return the Maximum Transmission Unit for the given PPP connection. + */ +u_short pppMTU(int pd); + +#if PPPOS_SUPPORT && !PPP_INPROC_OWNTHREAD +/* + * PPP over Serial: this is the input function to be called for received data. + * If PPP_INPROC_OWNTHREAD==1, a seperate input thread using the blocking + * sio_read() is used, so this is deactivated. + */ +void pppos_input(int pd, u_char* data, int len); +#endif /* PPPOS_SUPPORT && !PPP_INPROC_OWNTHREAD */ + + +#if LWIP_NETIF_STATUS_CALLBACK +/* Set an lwIP-style status-callback for the selected PPP device */ +void ppp_set_netif_statuscallback(int pd, netif_status_callback_fn status_callback); +#endif /* LWIP_NETIF_STATUS_CALLBACK */ +#if LWIP_NETIF_LINK_CALLBACK +/* Set an lwIP-style link-callback for the selected PPP device */ +void ppp_set_netif_linkcallback(int pd, netif_status_callback_fn link_callback); +#endif /* LWIP_NETIF_LINK_CALLBACK */ + +#endif /* PPP_SUPPORT */ + +#endif /* PPP_H */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/ppp_impl.h b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/ppp_impl.h new file mode 100644 index 0000000..89aea60 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/ppp_impl.h @@ -0,0 +1,363 @@ +/***************************************************************************** +* 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 PPP_IMPL_H +#define PPP_IMPL_H + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "ppp.h" +#include "lwip/def.h" +#include "lwip/sio.h" +#include "lwip/stats.h" +#include "lwip/mem.h" +#include "lwip/netif.h" +#include "lwip/sys.h" +#include "lwip/timers.h" + +/** Some defines for code we skip compared to the original pppd. + * These are just here to minimise the use of the ugly "#if 0". */ +#define PPP_ADDITIONAL_CALLBACKS 0 + +/** Some error checks to test for unsupported code */ +#if CBCP_SUPPORT +#error "CBCP is not supported in lwIP PPP" +#endif +#if CCP_SUPPORT +#error "CCP is not supported in lwIP PPP" +#endif + +/* + * pppd.h - PPP daemon global declarations. + * + * 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + */ +/* + * ppp_defs.h - PPP definitions. + * + * 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. + */ + +#define TIMEOUT(f, a, t) do { sys_untimeout((f), (a)); sys_timeout((t)*1000, (f), (a)); } while(0) +#define UNTIMEOUT(f, a) sys_untimeout((f), (a)) + + +/* + * Constants and structures defined by the internet system, + * Per RFC 790, September 1981, and numerous additions. + */ + +/* + * The basic PPP frame. + */ +#define PPP_HDRLEN 4 /* octets for standard ppp header */ +#define PPP_FCSLEN 2 /* octets for FCS */ + + +/* + * 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 */ +#define PPP_AT 0x29 /* AppleTalk Protocol */ +#define PPP_VJC_COMP 0x2d /* VJ compressed TCP */ +#define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */ +#define PPP_COMP 0xfd /* compressed packet */ +#define PPP_IPCP 0x8021 /* IP Control Protocol */ +#define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */ +#define PPP_CCP 0x80fd /* Compression Control Protocol */ +#define PPP_LCP 0xc021 /* Link Control Protocol */ +#define PPP_PAP 0xc023 /* Password Authentication Protocol */ +#define PPP_LQR 0xc025 /* Link Quality Report protocol */ +#define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */ +#define PPP_CBCP 0xc029 /* Callback Control Protocol */ + +/* + * Values for FCS calculations. + */ +#define PPP_INITFCS 0xffff /* Initial FCS value */ +#define PPP_GOODFCS 0xf0b8 /* Good final FCS value */ +#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff]) + +/* + * Extended asyncmap - allows any character to be escaped. + */ +typedef u_char ext_accm[32]; + +/* + * 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. */ +}; + +/* + * 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); (cp)++; (s) <<= 8; \ + (s) |= *(cp); (cp)++; \ +} +#define PUTSHORT(s, cp) { \ + *(cp)++ = (u_char) ((s) >> 8); \ + *(cp)++ = (u_char) (s & 0xff); \ +} + +#define GETLONG(l, cp) { \ + (l) = *(cp); (cp)++; (l) <<= 8; \ + (l) |= *(cp); (cp)++; (l) <<= 8; \ + (l) |= *(cp); (cp)++; (l) <<= 8; \ + (l) |= *(cp); (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)) + +#define BCMP(s0, s1, l) memcmp((u_char *)(s0), (u_char *)(s1), (l)) +#define BCOPY(s, d, l) MEMCPY((d), (s), (l)) +#define BZERO(s, n) memset(s, 0, n) + +#if PPP_DEBUG +#define PRINTMSG(m, l) { m[l] = '\0'; LWIP_DEBUGF(LOG_INFO, ("Remote message: %s\n", m)); } +#else /* PPP_DEBUG */ +#define PRINTMSG(m, l) +#endif /* PPP_DEBUG */ + +/* + * MAKEHEADER - Add PPP Header fields to a packet. + */ +#define MAKEHEADER(p, t) { \ + PUTCHAR(PPP_ALLSTATIONS, p); \ + PUTCHAR(PPP_UI, p); \ + PUTSHORT(t, p); } + +/************************ +*** PUBLIC DATA TYPES *** +************************/ + +/* + * 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) (int unit); + /* Process a received packet */ + void (*input) (int unit, u_char *pkt, int len); + /* Process a received protocol-reject */ + void (*protrej) (int unit); + /* Lower layer has come up */ + void (*lowerup) (int unit); + /* Lower layer has gone down */ + void (*lowerdown) (int unit); + /* Open the protocol */ + void (*open) (int unit); + /* Close the protocol */ + void (*close) (int unit, char *reason); +#if PPP_ADDITIONAL_CALLBACKS + /* Print a packet in readable form */ + int (*printpkt) (u_char *pkt, int len, + void (*printer) (void *, char *, ...), + void *arg); + /* Process a received data packet */ + void (*datainput) (int unit, u_char *pkt, int len); +#endif /* PPP_ADDITIONAL_CALLBACKS */ + int enabled_flag; /* 0 if protocol is disabled */ + char *name; /* Text name of protocol */ +#if PPP_ADDITIONAL_CALLBACKS + /* Check requested options, assign defaults */ + void (*check_options) (u_long); + /* 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 /* PPP_ADDITIONAL_CALLBACKS */ +}; + +/* + * The following structure records the time in seconds since + * the last NP packet was sent or received. + */ +struct ppp_idle { + u_short xmit_idle; /* seconds since last NP packet sent */ + u_short recv_idle; /* seconds since last NP packet received */ +}; + +struct ppp_settings { + + u_int disable_defaultip : 1; /* Don't use hostname for default IP addrs */ + u_int auth_required : 1; /* Peer is required to authenticate */ + u_int explicit_remote : 1; /* remote_name specified with remotename opt */ + u_int refuse_pap : 1; /* Don't wanna auth. ourselves with PAP */ + u_int refuse_chap : 1; /* Don't wanna auth. ourselves with CHAP */ + u_int usehostname : 1; /* Use hostname for our_name */ + u_int usepeerdns : 1; /* Ask peer for DNS adds */ + + u_short idle_time_limit; /* Shut down link if idle for this long */ + int maxconnect; /* Maximum connect time (seconds) */ + + char user [MAXNAMELEN + 1]; /* Username for PAP */ + char passwd [MAXSECRETLEN + 1]; /* Password for PAP, secret for CHAP */ + char our_name [MAXNAMELEN + 1]; /* Our name for authentication purposes */ + char remote_name[MAXNAMELEN + 1]; /* Peer's name for authentication */ +}; + +/***************************** +*** PUBLIC DATA STRUCTURES *** +*****************************/ + +/* Buffers for outgoing packets. */ +extern u_char outpacket_buf[NUM_PPP][PPP_MRU+PPP_HDRLEN]; + +extern struct ppp_settings ppp_settings; + +extern struct protent *ppp_protocols[]; /* Table of pointers to supported protocols */ + + +/*********************** +*** PUBLIC FUNCTIONS *** +***********************/ + +/* + * Write n characters to a ppp link. + * RETURN: >= 0 Number of characters written, -1 Failed to write to device. + */ +int pppWrite(int pd, const u_char *s, int n); + +void pppInProcOverEthernet(int pd, struct pbuf *pb); + +struct pbuf *pppSingleBuf(struct pbuf *p); + +void pppLinkTerminated(int pd); + +void pppLinkDown(int pd); + +/* Configure i/f transmit parameters */ +void ppp_send_config (int, u16_t, u32_t, int, int); +/* Set extended transmit ACCM */ +void ppp_set_xaccm (int, ext_accm *); +/* Configure i/f receive parameters */ +void ppp_recv_config (int, int, u32_t, int, int); +/* Find out how long link has been idle */ +int get_idle_time (int, struct ppp_idle *); + +/* Configure VJ TCP header compression */ +int sifvjcomp (int, int, u8_t, u8_t); +/* Configure i/f down (for IP) */ +int sifup (int); +/* Set mode for handling packets for proto */ +int sifnpmode (int u, int proto, enum NPmode mode); +/* Configure i/f down (for IP) */ +int sifdown (int); +/* Configure IP addresses for i/f */ +int sifaddr (int, u32_t, u32_t, u32_t, u32_t, u32_t); +/* Reset i/f IP addresses */ +int cifaddr (int, u32_t, u32_t); +/* Create default route through i/f */ +int sifdefaultroute (int, u32_t, u32_t); +/* Delete default route through i/f */ +int cifdefaultroute (int, u32_t, u32_t); + +/* Get appropriate netmask for address */ +u32_t GetMask (u32_t); + +#endif /* PPP_SUPPORT */ + +#endif /* PPP_IMPL_H */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/ppp_oe.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/ppp_oe.c new file mode 100644 index 0000000..fdf52ae --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/ppp_oe.c @@ -0,0 +1,1132 @@ +/***************************************************************************** +* ppp_oe.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 "lwip/opt.h" + +#if PPPOE_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "netif/ppp_oe.h" + +#include "ppp_impl.h" +#include "pppdebug.h" + +#include "lwip/timers.h" +#include "lwip/memp.h" + +#include +#include + + +/* 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 + +#ifndef PPPOE_ERRORSTRING_LEN +#define PPPOE_ERRORSTRING_LEN 64 +#endif +static char pppoe_error_tmp[PPPOE_ERRORSTRING_LEN]; + + +/* input routines */ +static void pppoe_dispatch_disc_pkt(struct netif *, struct pbuf *); + +/* management routines */ +static int pppoe_do_disconnect(struct pppoe_softc *); +static void pppoe_abort_connect(struct pppoe_softc *); +static void pppoe_clear_softc(struct pppoe_softc *, const char *); + +/* 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 struct pppoe_softc * pppoe_find_softc_by_session(u_int, struct netif *); +static struct pppoe_softc * pppoe_find_softc_by_hunique(u8_t *, size_t, struct netif *); + +/** linked list of created pppoe interfaces */ +static struct pppoe_softc *pppoe_softc_list; + +err_t +pppoe_create(struct netif *ethif, int pd, void (*linkStatusCB)(int pd, int up), struct pppoe_softc **scptr) +{ + struct pppoe_softc *sc; + + sc = (struct pppoe_softc *)memp_malloc(MEMP_PPPOE_IF); + if (sc == NULL) { + *scptr = NULL; + return ERR_MEM; + } + memset(sc, 0, sizeof(struct pppoe_softc)); + + /* changed to real address later */ + MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); + + sc->sc_pd = pd; + sc->sc_linkStatusCB = linkStatusCB; + sc->sc_ethif = ethif; + + /* put the new interface at the head of the list */ + sc->next = pppoe_softc_list; + pppoe_softc_list = sc; + + *scptr = sc; + + return ERR_OK; +} + +err_t +pppoe_destroy(struct netif *ifp) +{ + struct pppoe_softc *sc, *prev = NULL; + + for (sc = pppoe_softc_list; sc != NULL; prev = sc, sc = sc->next) { + if (sc->sc_ethif == ifp) { + break; + } + } + + if(!(sc && (sc->sc_ethif == ifp))) { + return ERR_IF; + } + + sys_untimeout(pppoe_timeout, sc); + if (prev == NULL) { + /* remove sc from the head of the list */ + pppoe_softc_list = sc->next; + } else { + /* remove sc from the list */ + prev->next = sc->next; + } + +#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 */ + memp_free(MEMP_PPPOE_IF, sc); + + return ERR_OK; +} + +/* + * Find the interface handling the specified session. + * Note: O(number of sessions open), this is a client-side only, mean + * and lean implementation, so number of open sessions typically should + * be 1. + */ +static struct pppoe_softc * +pppoe_find_softc_by_session(u_int session, struct netif *rcvif) +{ + struct pppoe_softc *sc; + + if (session == 0) { + return NULL; + } + + for (sc = pppoe_softc_list; sc != NULL; sc = sc->next) { + if (sc->sc_state == PPPOE_STATE_SESSION + && sc->sc_session == session) { + if (sc->sc_ethif == rcvif) { + return sc; + } else { + return NULL; + } + } + } + return NULL; +} + +/* Check host unique token passed and return appropriate softc pointer, + * or NULL if token is bogus. */ +static struct pppoe_softc * +pppoe_find_softc_by_hunique(u8_t *token, size_t len, struct netif *rcvif) +{ + struct pppoe_softc *sc, *t; + + if (pppoe_softc_list == NULL) { + return NULL; + } + + if (len != sizeof sc) { + return NULL; + } + MEMCPY(&t, token, len); + + for (sc = pppoe_softc_list; sc != NULL; sc = sc->next) { + if (sc == t) { + break; + } + } + + if (sc == NULL) { + PPPDEBUG(LOG_DEBUG, ("pppoe: alien host unique tag, no session found\n")); + return NULL; + } + + /* should be safe to access *sc now */ + if (sc->sc_state < PPPOE_STATE_PADI_SENT || sc->sc_state >= PPPOE_STATE_SESSION) { + printf("%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) { + printf("%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; +} + +static void +pppoe_linkstatus_up(struct pppoe_softc *sc) +{ + sc->sc_linkStatusCB(sc->sc_pd, 1); +} + +/* analyze and handle a single received packet while not in session state */ +static void +pppoe_dispatch_disc_pkt(struct netif *netif, struct pbuf *pb) +{ + u16_t tag, len; + u16_t session, plen; + struct pppoe_softc *sc; + const char *err_msg; + char devname[6]; + 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, errortag; + struct eth_hdr *ethhdr; + + pb = pppSingleBuf(pb); + + strcpy(devname, "pppoe"); /* as long as we don't know which instance */ + err_msg = NULL; + errortag = 0; + 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 < PPPOE_HEADERLEN) { + printf("pppoe: packet too short: %d\n", pb->len); + goto done; + } + + ph = (struct pppoehdr *) (ethhdr + 1); + if (ph->vertype != PPPOE_VERTYPE) { + printf("pppoe: unknown version/type packet: 0x%x\n", ph->vertype); + goto done; + } + session = ntohs(ph->session); + plen = ntohs(ph->plen); + off += sizeof(*ph); + + if (plen + off > pb->len) { + printf("pppoe: packet content does not fit: data available = %d, packet size = %u\n", + pb->len - off, plen); + goto done; + } + if(pb->tot_len == pb->len) { + pb->tot_len = pb->len = (u16_t)off + plen; /* ignore trailing garbage */ + } + tag = 0; + len = 0; + sc = NULL; + while (off + sizeof(pt) <= pb->len) { + MEMCPY(&pt, (u8_t*)pb->payload + off, sizeof(pt)); + tag = ntohs(pt.tag); + len = ntohs(pt.len); + if (off + sizeof(pt) + len > pb->len) { + printf("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); + if (sc != NULL) { + snprintf(devname, sizeof(devname), "%c%c%"U16_F, sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num); + } + break; + case PPPOE_TAG_ACCOOKIE: + if (ac_cookie == NULL) { + ac_cookie = (u8_t*)pb->payload + off + sizeof(pt); + ac_cookie_len = len; + } + break; + case PPPOE_TAG_SNAME_ERR: + err_msg = "SERVICE NAME ERROR"; + errortag = 1; + break; + case PPPOE_TAG_ACSYS_ERR: + err_msg = "AC SYSTEM ERROR"; + errortag = 1; + break; + case PPPOE_TAG_GENERIC_ERR: + err_msg = "GENERIC ERROR"; + errortag = 1; + break; + } + if (err_msg) { + if (errortag && len) { + u16_t error_len = LWIP_MIN(len, sizeof(pppoe_error_tmp)-1); + strncpy(pppoe_error_tmp, (char*)pb->payload + off + sizeof(pt), error_len); + pppoe_error_tmp[error_len-1] = '\0'; + printf("%s: %s: %s\n", devname, err_msg, pppoe_error_tmp); + } else { + printf("%s: %s\n", devname, err_msg); + } + if (errortag) { + goto done; + } + } + 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) { + /* printf("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 */ + printf("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)) { + printf("pppoe: received PADR but could not find request for it\n"); + } + goto done; + } + if (sc->sc_state != PPPOE_STATE_PADO_SENT) { + printf("%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; + pppoe_linkstatus_up(sc); /* 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) { + printf("pppoe: received PADO but could not find request for it\n"); + } + goto done; + } + if (sc->sc_state != PPPOE_STATE_PADI_SENT) { + printf("%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; + pppoe_linkstatus_up(sc); /* notify upper layers */ + break; + case PPPOE_CODE_PADT: + if (sc == NULL) { + goto done; + } + pppoe_clear_softc(sc, "received PADT"); + break; + default: + if(sc) { + printf("%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 { + printf("pppoe: unknown code (0x%"X16_F") session = 0x%"X16_F"\n", (u16_t)ph->code, session); + } + break; + } + +done: + pbuf_free(pb); + return; +} + +void +pppoe_disc_input(struct netif *netif, struct pbuf *p) +{ + /* avoid error messages if there is not a single pppoe instance */ + if (pppoe_softc_list != NULL) { + pppoe_dispatch_disc_pkt(netif, p); + } else { + pbuf_free(p); + } +} + +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, -(int)sizeof(struct eth_hdr)) != 0) { + /* bail out */ + PPPDEBUG(LOG_ERR, ("pppoe_data_input: pbuf_header failed\n")); + LINK_STATS_INC(link.lenerr); + goto drop; + } + + pb = pppSingleBuf (pb); + + if (pb->len <= PPPOE_HEADERLEN) { + printf("pppoe (data): dropping too short packet: %d bytes\n", pb->len); + goto drop; + } + + if (pb->len < sizeof(*ph)) { + printf("pppoe_data_input: could not get PPPoE header\n"); + goto drop; + } + ph = (struct pppoehdr *)pb->payload; + + if (ph->vertype != PPPOE_VERTYPE) { + printf("pppoe (data): unknown version/type packet: 0x%x\n", ph->vertype); + goto drop; + } + if (ph->code != 0) { + goto drop; + } + + session = ntohs(ph->session); + sc = pppoe_find_softc_by_session(session, netif); + if (sc == NULL) { +#ifdef PPPOE_TERM_UNKNOWN_SESSIONS + printf("pppoe: input for unknown session 0x%x, sending PADT\n", session); + pppoe_send_padt(netif, session, shost); +#endif + goto drop; + } + + plen = ntohs(ph->plen); + + if (pbuf_header(pb, -(int)(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->len < plen) { + goto drop; + } + + pppInProcOverEthernet(sc->sc_pd, pb); + + return; + +drop: + pbuf_free(pb); +} + +static err_t +pppoe_output(struct pppoe_softc *sc, struct pbuf *pb) +{ + struct eth_hdr *ethhdr; + u16_t etype; + err_t res; + + if (!sc->sc_ethif) { + pbuf_free(pb); + return ERR_IF; + } + + ethhdr = (struct eth_hdr *)pb->payload; + etype = sc->sc_state == PPPOE_STATE_SESSION ? ETHTYPE_PPPOE : ETHTYPE_PPPOEDISC; + ethhdr->type = htons(etype); + MEMCPY(ethhdr->dest.addr, sc->sc_dest.addr, sizeof(ethhdr->dest.addr)); + MEMCPY(ethhdr->src.addr, ((struct eth_addr *)sc->sc_ethif->hwaddr)->addr, sizeof(ethhdr->src.addr)); + + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F" (%x) state=%d, session=0x%x output -> %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F", len=%d\n", + sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, etype, + sc->sc_state, sc->sc_session, + sc->sc_dest.addr[0], sc->sc_dest.addr[1], sc->sc_dest.addr[2], sc->sc_dest.addr[3], sc->sc_dest.addr[4], sc->sc_dest.addr[5], + pb->tot_len)); + + res = sc->sc_ethif->linkoutput(sc->sc_ethif, pb); + + pbuf_free(pb); + + return res; +} + +static err_t +pppoe_send_padi(struct pppoe_softc *sc) +{ + struct pbuf *pb; + u8_t *p; + int len; +#ifdef PPPOE_TODO + int l1 = 0, l2 = 0; /* XXX: gcc */ +#endif /* PPPOE_TODO */ + + if (sc->sc_state >PPPOE_STATE_PADI_SENT) { + PPPDEBUG(LOG_ERR, ("ERROR: pppoe_send_padi in state %d", sc->sc_state)); + } + + /* calculate length of frame (excluding ethernet header + pppoe header) */ + len = 2 + 2 + 2 + 2 + sizeof sc; /* service name tag is required, host unique is send too */ +#ifdef PPPOE_TODO + if (sc->sc_service_name != NULL) { + l1 = (int)strlen(sc->sc_service_name); + len += l1; + } + if (sc->sc_concentrator_name != NULL) { + l2 = (int)strlen(sc->sc_concentrator_name); + len += 2 + 2 + l2; + } +#endif /* PPPOE_TODO */ + LWIP_ASSERT("sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff", + sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff); + + /* allocate a buffer */ + pb = pbuf_alloc(PBUF_LINK, (u16_t)(sizeof(struct eth_hdr) + 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 + sizeof (struct eth_hdr); + /* 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) +{ + int retry_wait, 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. + */ + + /* initialize for quick retry mode */ + retry_wait = PPPOE_DISC_TIMEOUT * (1 + sc->sc_padi_retried); + + sc->sc_padi_retried++; + if (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; + } + } + 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; + case PPPOE_STATE_CLOSING: + pppoe_do_disconnect(sc); + break; + default: + return; /* all done, work in peace */ + } +} + +/* Start a connection (i.e. initiate discovery phase) */ +int +pppoe_connect(struct pppoe_softc *sc) +{ + int err; + + if (sc->sc_state != PPPOE_STATE_INITIAL) { + return EBUSY; + } + +#ifdef PPPOE_SERVER + /* wait PADI if IFF_PASSIVE */ + if ((sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE)) { + return 0; + } +#endif + /* save state, in case we fail to send PADI */ + sc->sc_state = PPPOE_STATE_PADI_SENT; + sc->sc_padr_retried = 0; + err = pppoe_send_padi(sc); + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to send PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); + sys_timeout(PPPOE_DISC_TIMEOUT, pppoe_timeout, sc); + return err; +} + +/* disconnect */ +void +pppoe_disconnect(struct pppoe_softc *sc) +{ + if (sc->sc_state < PPPOE_STATE_SESSION) { + return; + } + /* + * Do not call pppoe_disconnect here, the upper layer state + * machine gets confused by this. We must return from this + * function and defer disconnecting to the timeout handler. + */ + sc->sc_state = PPPOE_STATE_CLOSING; + sys_timeout(20, pppoe_timeout, sc); +} + +static int +pppoe_do_disconnect(struct pppoe_softc *sc) +{ + int err; + + if (sc->sc_state < PPPOE_STATE_SESSION) { + err = EBUSY; + } else { + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": disconnecting\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); + err = pppoe_send_padt(sc->sc_ethif, sc->sc_session, (const u8_t *)&sc->sc_dest); + } + + /* cleanup softc */ + sc->sc_state = PPPOE_STATE_INITIAL; + MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); + sc->sc_ac_cookie_len = 0; +#ifdef PPPOE_SERVER + if (sc->sc_hunique) { + mem_free(sc->sc_hunique); + sc->sc_hunique = NULL; + } + sc->sc_hunique_len = 0; +#endif + sc->sc_session = 0; + + sc->sc_linkStatusCB(sc->sc_pd, 0); /* notify upper layers */ + + return err; +} + +/* Connection attempt aborted */ +static void +pppoe_abort_connect(struct pppoe_softc *sc) +{ + printf("%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_CLOSING; + + sc->sc_linkStatusCB(sc->sc_pd, 0); /* notify upper layers */ + + /* clear connection state */ + MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); + sc->sc_state = PPPOE_STATE_INITIAL; +} + +/* Send a PADR packet */ +static err_t +pppoe_send_padr(struct pppoe_softc *sc) +{ + struct pbuf *pb; + u8_t *p; + size_t len; +#ifdef PPPOE_TODO + size_t l1 = 0; /* XXX: gcc */ +#endif /* PPPOE_TODO */ + + if (sc->sc_state != PPPOE_STATE_PADR_SENT) { + return ERR_CONN; + } + + len = 2 + 2 + 2 + 2 + sizeof(sc); /* service name, host unique */ +#ifdef PPPOE_TODO + if (sc->sc_service_name != NULL) { /* service name tag maybe empty */ + l1 = strlen(sc->sc_service_name); + len += l1; + } +#endif /* PPPOE_TODO */ + if (sc->sc_ac_cookie_len > 0) { + len += 2 + 2 + sc->sc_ac_cookie_len; /* AC cookie */ + } + LWIP_ASSERT("sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff", + sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff); + pb = pbuf_alloc(PBUF_LINK, (u16_t)(sizeof(struct eth_hdr) + 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 + sizeof (struct eth_hdr); + 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, sizeof(struct eth_hdr) + PPPOE_HEADERLEN, PBUF_RAM); + if (!pb) { + return ERR_MEM; + } + LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); + + ethhdr = (struct eth_hdr *)pb->payload; + ethhdr->type = PP_HTONS(ETHTYPE_PPPOEDISC); + MEMCPY(ethhdr->dest.addr, dest, sizeof(ethhdr->dest.addr)); + MEMCPY(ethhdr->src.addr, ((struct eth_addr *)outgoing_if->hwaddr)->addr, sizeof(ethhdr->src.addr)); + + p = (u8_t*)(ethhdr + 1); + PPPOE_ADD_HEADER(p, PPPOE_CODE_PADT, session, 0); + + res = outgoing_if->linkoutput(outgoing_if, pb); + + pbuf_free(pb); + + return res; +} + +#ifdef PPPOE_SERVER +static err_t +pppoe_send_pado(struct pppoe_softc *sc) +{ + struct pbuf *pb; + u8_t *p; + size_t len; + + if (sc->sc_state != PPPOE_STATE_PADO_SENT) { + return ERR_CONN; + } + + /* calc length */ + len = 0; + /* include ac_cookie */ + len += 2 + 2 + sizeof(sc); + /* include hunique */ + len += 2 + 2 + sc->sc_hunique_len; + pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + 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 + sizeof (struct eth_hdr); + PPPOE_ADD_HEADER(p, PPPOE_CODE_PADO, 0, len); + PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE); + PPPOE_ADD_16(p, sizeof(sc)); + MEMCPY(p, &sc, sizeof(sc)); + p += sizeof(sc); + PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE); + PPPOE_ADD_16(p, sc->sc_hunique_len); + MEMCPY(p, sc->sc_hunique, sc->sc_hunique_len); + return pppoe_output(sc, pb); +} + +static err_t +pppoe_send_pads(struct pppoe_softc *sc) +{ + struct pbuf *pb; + u8_t *p; + size_t len, l1 = 0; /* XXX: gcc */ + + if (sc->sc_state != PPPOE_STATE_PADO_SENT) { + return ERR_CONN; + } + + sc->sc_session = mono_time.tv_sec % 0xff + 1; + /* calc length */ + len = 0; + /* include hunique */ + len += 2 + 2 + 2 + 2 + sc->sc_hunique_len; /* service name, host unique*/ + if (sc->sc_service_name != NULL) { /* service name tag maybe empty */ + l1 = strlen(sc->sc_service_name); + len += l1; + } + pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + 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 + sizeof (struct eth_hdr); + 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 + +err_t +pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb) +{ + u8_t *p; + size_t len; + + /* are we ready to process data yet? */ + if (sc->sc_state < PPPOE_STATE_SESSION) { + /*sppp_flush(&sc->sc_sppp.pp_if);*/ + pbuf_free(pb); + return ERR_CONN; + } + + len = pb->tot_len; + + /* make room for Ethernet header - should not fail */ + if (pbuf_header(pb, sizeof(struct eth_hdr) + PPPOE_HEADERLEN) != 0) { + /* bail out */ + PPPDEBUG(LOG_ERR, ("pppoe: %c%c%"U16_F": pppoe_xmit: could not allocate room for 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 + sizeof(struct eth_hdr); + 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); + printf("%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 + +static void +pppoe_clear_softc(struct pppoe_softc *sc, const char *message) +{ + LWIP_UNUSED_ARG(message); + + /* stop timer */ + sys_untimeout(pppoe_timeout, sc); + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": session 0x%x terminated, %s\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, sc->sc_session, message)); + + /* fix our state */ + sc->sc_state = PPPOE_STATE_INITIAL; + + /* notify upper layers */ + sc->sc_linkStatusCB(sc->sc_pd, 0); + + /* clean up softc */ + MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); + sc->sc_ac_cookie_len = 0; + sc->sc_session = 0; +} + +#endif /* PPPOE_SUPPORT */ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/pppdebug.h b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/pppdebug.h new file mode 100644 index 0000000..8134997 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/pppdebug.h @@ -0,0 +1,73 @@ +/***************************************************************************** +* 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. +* +***************************************************************************** +*/ +#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) + + +#define TRACELCP PPP_DEBUG + +#if PPP_DEBUG + +#define AUTHDEBUG(a, b) LWIP_DEBUGF(a, b) +#define IPCPDEBUG(a, b) LWIP_DEBUGF(a, b) +#define UPAPDEBUG(a, b) LWIP_DEBUGF(a, b) +#define LCPDEBUG(a, b) LWIP_DEBUGF(a, b) +#define FSMDEBUG(a, b) LWIP_DEBUGF(a, b) +#define CHAPDEBUG(a, b) LWIP_DEBUGF(a, b) +#define PPPDEBUG(a, b) LWIP_DEBUGF(a, b) + +#else /* PPP_DEBUG */ + +#define AUTHDEBUG(a, b) +#define IPCPDEBUG(a, b) +#define UPAPDEBUG(a, b) +#define LCPDEBUG(a, b) +#define FSMDEBUG(a, b) +#define CHAPDEBUG(a, b) +#define PPPDEBUG(a, b) + +#endif /* PPP_DEBUG */ + +#endif /* PPPDEBUG_H */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/randm.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/randm.c new file mode 100644 index 0000000..b736091 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/randm.c @@ -0,0 +1,249 @@ +/***************************************************************************** +* 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 "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "md5.h" +#include "randm.h" + +#include "ppp_impl.h" +#include "pppdebug.h" + +#include + +#if MD5_SUPPORT /* this module depends on MD5 */ +#define RANDPOOLSZ 16 /* Bytes stored in the pool of randomness. */ + +/*****************************/ +/*** LOCAL DATA STRUCTURES ***/ +/*****************************/ +static char randPool[RANDPOOLSZ]; /* Pool of randomness. */ +static long randCount = 0; /* Pseudo-random incrementer */ + + +/***********************************/ +/*** PUBLIC FUNCTION DEFINITIONS ***/ +/***********************************/ +/* + * Initialize the random number generator. + * + * Since this is to be called on power up, we don't have much + * system randomess to work with. Here all we use is the + * real-time clock. We'll accumulate more randomness as soon + * as things start happening. + */ +void +avRandomInit() +{ + avChurnRand(NULL, 0); +} + +/* + * 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 + */ +void +avChurnRand(char *randData, u32_t randLen) +{ + MD5_CTX md5; + + /* LWIP_DEBUGF(LOG_INFO, ("churnRand: %u@%P\n", randLen, randData)); */ + MD5Init(&md5); + MD5Update(&md5, (u_char *)randPool, sizeof(randPool)); + if (randData) { + MD5Update(&md5, (u_char *)randData, randLen); + } else { + struct { + /* INCLUDE fields for any system sources of randomness */ + char foobar; + } sysData; + + /* Load sysData fields here. */ + MD5Update(&md5, (u_char *)&sysData, sizeof(sysData)); + } + MD5Final((u_char *)randPool, &md5); +/* LWIP_DEBUGF(LOG_INFO, ("churnRand: -> 0\n")); */ +} + +/* + * Use the random pool to generate random data. This degrades to pseudo + * random when used faster than randomness is supplied using churnRand(). + * Note: It's important that there be sufficient randomness in 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 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 + * randCount each time? Probably there is a weakness but I wish that + * it was documented. + */ +void +avGenRand(char *buf, u32_t bufLen) +{ + MD5_CTX md5; + u_char tmp[16]; + u32_t n; + + while (bufLen > 0) { + n = LWIP_MIN(bufLen, RANDPOOLSZ); + MD5Init(&md5); + MD5Update(&md5, (u_char *)randPool, sizeof(randPool)); + MD5Update(&md5, (u_char *)&randCount, sizeof(randCount)); + MD5Final(tmp, &md5); + randCount++; + MEMCPY(buf, tmp, n); + buf += n; + bufLen -= n; + } +} + +/* + * Return a new random number. + */ +u32_t +avRandom() +{ + u32_t newRand; + + avGenRand((char *)&newRand, sizeof(newRand)); + + return newRand; +} + +#else /* MD5_SUPPORT */ + +/*****************************/ +/*** LOCAL DATA STRUCTURES ***/ +/*****************************/ +static int avRandomized = 0; /* Set when truely randomized. */ +static u32_t avRandomSeed = 0; /* 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 +avRandomInit() +{ +#if 0 + /* Get a pointer into the last 4 bytes of clockBuf. */ + u32_t *lptr1 = (u32_t *)((char *)&clockBuf[3]); + + /* + * Initialize our seed using the real-time clock, the idle + * counter, the millisecond timer, and the hardware timer + * tick counter. The real-time clock and the hardware + * tick counter are the best sources of randomness but + * since the tick counter is only 16 bit (and truncated + * at that), the idle counter and millisecond timer + * (which may be small values) are added to help + * randomize the lower 16 bits of the seed. + */ + readClk(); + avRandomSeed += *(u32_t *)clockBuf + *lptr1 + OSIdleCtr + + ppp_mtime() + ((u32_t)TM1 << 16) + TM1; +#else + avRandomSeed += sys_jiffies(); /* XXX */ +#endif + + /* Initialize the Borland random number generator. */ + srand((unsigned)avRandomSeed); +} + +/* + * 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 +avRandomize(void) +{ + static u32_t last_jiffies; + + if (!avRandomized) { + avRandomized = !0; + avRandomInit(); + /* The initialization function also updates the seed. */ + } else { + /* avRandomSeed += (avRandomSeed << 16) + TM1; */ + avRandomSeed += (sys_jiffies() - last_jiffies); /* XXX */ + } + last_jiffies = sys_jiffies(); +} + +/* + * 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 +avRandom() +{ + return ((((u32_t)rand() << 16) + rand()) + avRandomSeed); +} + +#endif /* MD5_SUPPORT */ + +#endif /* PPP_SUPPORT */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/randm.h b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/randm.h new file mode 100644 index 0000000..a0984b0 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/randm.h @@ -0,0 +1,81 @@ +/***************************************************************************** +* 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. +*****************************************************************************/ + +#ifndef RANDM_H +#define RANDM_H + +/*********************** +*** PUBLIC FUNCTIONS *** +***********************/ +/* + * Initialize the random number generator. + */ +void avRandomInit(void); + +/* + * 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. + */ +void avChurnRand(char *randData, u32_t randLen); + +/* + * Randomize our random seed value. To be called for truely random events + * such as user operations and network traffic. + */ +#if MD5_SUPPORT +#define avRandomize() avChurnRand(NULL, 0) +#else /* MD5_SUPPORT */ +void avRandomize(void); +#endif /* MD5_SUPPORT */ + +/* + * Use the random pool to generate random data. This degrades to pseudo + * random when used faster than randomness is supplied using 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 avGenRand(char *buf, u32_t bufLen); + +/* + * Return a new random number. + */ +u32_t avRandom(void); + + +#endif /* RANDM_H */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/readme.txt b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/readme.txt new file mode 100644 index 0000000..5be41b9 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/readme.txt @@ -0,0 +1,21 @@ +About the PPP code: + +The PPP code is not our "own" code - we just copied it from pppd (http://ppp.samba.org/) and adapted it to lwIP. +Unfortunately, not many here know their way around it too well. Back in 2009, we took the effort to see which +version of pppd our code relates to and we're pretty much on 2.3.11 with some bugs from 2.4.x backported. + +Aside from simple code adaptions, there are some files that are different, however: +- chpms.c/.h are named chap_ms.c/.h in the original pppd 2.3.11 sources +- pap.c/.h are named upap.c/.h in the original pppd 2.3.11 sources +- randm.c is a random generator not included in the original pppd +- magic.c does not use the C library's random functions, but uses randm.c instead +- vj.c/.h is an implementation of the Van Jacobson header compression algorithm adapted to lwIP pbufs, + probably copied from one of the vjcompress.c files from pppd. +- ppp.c, ppp.h and ppp_impl.h contain the adaption from pppd to lwIP. This is the "OS"-dependent part like there + is an implementation for linux, xBSD etc. in the pppd sources. +- ppp_oe.c is Marc Boucher's implementation based on NetBSD's if_pppoe.c + +There is of course potential for bugs in it, but when analyzing of reporting bugs, it is strongly encouraged to +compare the code in question to pppd 2.3.11 (our basis) and newer versions (perhaps it's already fixed?) and to +share this knowledge with us when reporting a bug. + diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/vj.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/vj.c new file mode 100644 index 0000000..40fdad1 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/vj.c @@ -0,0 +1,652 @@ +/* + * 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 "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "ppp_impl.h" +#include "pppdebug.h" + +#include "vj.h" + +#include + +#if VJ_SUPPORT + +#if LINK_STATS +#define INCR(counter) ++comp->stats.counter +#else +#define INCR(counter) +#endif + +void +vj_compress_init(struct vjcompress *comp) +{ + register u_char i; + register 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 ((u_short)(n) >= 256) { \ + *cp++ = 0; \ + cp[1] = (u_char)(n); \ + cp[0] = (u_char)((n) >> 8); \ + cp += 2; \ + } else { \ + *cp++ = (u_char)(n); \ + } \ +} +#define ENCODEZ(n) { \ + if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \ + *cp++ = 0; \ + cp[1] = (u_char)(n); \ + cp[0] = (u_char)((n) >> 8); \ + cp += 2; \ + } else { \ + *cp++ = (u_char)(n); \ + } \ +} + +#define DECODEL(f) { \ + if (*cp == 0) {\ + u32_t tmp = ntohl(f) + ((cp[1] << 8) | cp[2]); \ + (f) = htonl(tmp); \ + cp += 3; \ + } else { \ + u32_t tmp = ntohl(f) + (u32_t)*cp++; \ + (f) = htonl(tmp); \ + } \ +} + +#define DECODES(f) { \ + if (*cp == 0) {\ + u_short tmp = ntohs(f) + (((u_short)cp[1] << 8) | cp[2]); \ + (f) = htons(tmp); \ + cp += 3; \ + } else { \ + u_short tmp = ntohs(f) + (u_short)*cp++; \ + (f) = htons(tmp); \ + } \ +} + +#define DECODEU(f) { \ + if (*cp == 0) {\ + (f) = htons(((u_short)cp[1] << 8) | cp[2]); \ + cp += 3; \ + } else { \ + (f) = htons((u_short)*cp++); \ + } \ +} + +/* + * 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. + */ +u_int +vj_compress_tcp(struct vjcompress *comp, struct pbuf *pb) +{ + register struct ip_hdr *ip = (struct ip_hdr *)pb->payload; + register struct cstate *cs = comp->last_cs->cs_next; + register u_short hlen = IPH_HL(ip); + register struct tcp_hdr *oth; + register struct tcp_hdr *th; + register u_short deltaS, deltaA; + register u_long deltaL; + register u_int changes = 0; + u_char new_seq[16]; + register u_char *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)) || pb->tot_len < 40) { + return (TYPE_IP); + } + th = (struct tcp_hdr *)&((long *)ip)[hlen]; + if ((TCPH_FLAGS(th) & (TCP_SYN|TCP_FIN|TCP_RST|TCP_ACK)) != TCP_ACK) { + return (TYPE_IP); + } + /* + * 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 (!ip_addr_cmp(&ip->src, &cs->cs_ip.src) + || !ip_addr_cmp(&ip->dest, &cs->cs_ip.dest) + || *(long *)th != ((long *)&cs->cs_ip)[IPH_HL(&cs->cs_ip)]) { + /* + * 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. + */ + register struct cstate *lcs; + register struct cstate *lastcs = comp->last_cs; + + do { + lcs = cs; cs = cs->cs_next; + INCR(vjs_searches); + if (ip_addr_cmp(&ip->src, &cs->cs_ip.src) + && ip_addr_cmp(&ip->dest, &cs->cs_ip.dest) + && *(long *)th == ((long *)&cs->cs_ip)[IPH_HL(&cs->cs_ip)]) { + 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; + hlen += TCPH_HDRLEN(th); + hlen <<= 2; + /* Check that the IP/TCP headers are contained in the first buffer. */ + if (hlen > pb->len) { + return (TYPE_IP); + } + 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 *)&((long *)&cs->cs_ip)[hlen]; + deltaS = hlen; + hlen += TCPH_HDRLEN(th); + hlen <<= 2; + /* Check that the IP/TCP headers are contained in the first buffer. */ + if (hlen > pb->len) { + PPPDEBUG(LOG_INFO, ("vj_compress_tcp: header len %d spans buffers\n", hlen)); + return (TYPE_IP); + } + + /* + * 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 (((u_short *)ip)[0] != ((u_short *)&cs->cs_ip)[0] + || ((u_short *)ip)[3] != ((u_short *)&cs->cs_ip)[3] + || ((u_short *)ip)[4] != ((u_short *)&cs->cs_ip)[4] + || TCPH_HDRLEN(th) != TCPH_HDRLEN(oth) + || (deltaS > 5 && BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) + || (TCPH_HDRLEN(th) > 5 && BCMP(th + 1, oth + 1, (TCPH_HDRLEN(th) - 5) << 2))) { + goto uncompressed; + } + + /* + * Figure out which of the changing fields changed. The + * receiver expects changes in the order: urgent, window, + * ack, seq (the order minimizes the number of temporaries + * needed in this section of code). + */ + if (TCPH_FLAGS(th) & TCP_URG) { + deltaS = ntohs(th->urgp); + ENCODEZ(deltaS); + changes |= NEW_U; + } else if (th->urgp != oth->urgp) { + /* argh! URG not set but urp changed -- a sensible + * implementation should never do this but RFC793 + * doesn't prohibit the change so we have to deal + * with it. */ + goto uncompressed; + } + + if ((deltaS = (u_short)(ntohs(th->wnd) - ntohs(oth->wnd))) != 0) { + ENCODE(deltaS); + changes |= NEW_W; + } + + if ((deltaL = ntohl(th->ackno) - ntohl(oth->ackno)) != 0) { + if (deltaL > 0xffff) { + goto uncompressed; + } + deltaA = (u_short)deltaL; + ENCODE(deltaA); + changes |= NEW_A; + } + + if ((deltaL = ntohl(th->seqno) - ntohl(oth->seqno)) != 0) { + if (deltaL > 0xffff) { + goto uncompressed; + } + deltaS = (u_short)deltaL; + ENCODE(deltaS); + changes |= NEW_S; + } + + switch(changes) { + case 0: + /* + * Nothing changed. If this packet contains data and the + * last one didn't, this is probably a data packet following + * an ack (normal on an interactive connection) and we send + * it compressed. Otherwise it's probably a retransmit, + * retransmitted ack or window probe. Send it uncompressed + * in case the other side missed the compressed version. + */ + if (IPH_LEN(ip) != IPH_LEN(&cs->cs_ip) && + ntohs(IPH_LEN(&cs->cs_ip)) == hlen) { + break; + } + + /* (fall through) */ + + case SPECIAL_I: + case SPECIAL_D: + /* + * actual changes match one of our special case encodings -- + * send packet uncompressed. + */ + goto uncompressed; + + case NEW_S|NEW_A: + if (deltaS == deltaA && deltaS == ntohs(IPH_LEN(&cs->cs_ip)) - hlen) { + /* special case for echoed terminal traffic */ + changes = SPECIAL_I; + cp = new_seq; + } + break; + + case NEW_S: + if (deltaS == ntohs(IPH_LEN(&cs->cs_ip)) - hlen) { + /* special case for data xfer */ + changes = SPECIAL_D; + cp = new_seq; + } + break; + } + + deltaS = (u_short)(ntohs(IPH_ID(ip)) - ntohs(IPH_ID(&cs->cs_ip))); + if (deltaS != 1) { + ENCODEZ(deltaS); + changes |= NEW_I; + } + if (TCPH_FLAGS(th) & TCP_PSH) { + changes |= TCP_PUSH_BIT; + } + /* + * Grab the cksum before we overwrite it below. Then update our + * state with this packet's header. + */ + deltaA = ntohs(th->chksum); + BCOPY(ip, &cs->cs_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 = (u_short)(cp - new_seq); + if (!comp->compressSlot || comp->last_xmit != cs->cs_id) { + comp->last_xmit = cs->cs_id; + hlen -= deltaS + 4; + if(pbuf_header(pb, -hlen)){ + /* Can we cope with this failing? Just assert for now */ + LWIP_ASSERT("pbuf_header failed\n", 0); + } + cp = (u_char *)pb->payload; + *cp++ = (u_char)(changes | NEW_C); + *cp++ = cs->cs_id; + } else { + hlen -= deltaS + 3; + if(pbuf_header(pb, -hlen)) { + /* Can we cope with this failing? Just assert for now */ + LWIP_ASSERT("pbuf_header failed\n", 0); + } + cp = (u_char *)pb->payload; + *cp++ = (u_char)changes; + } + *cp++ = (u_char)(deltaA >> 8); + *cp++ = (u_char)deltaA; + BCOPY(new_seq, cp, 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: + BCOPY(ip, &cs->cs_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) +{ + register u_int hlen; + register struct cstate *cs; + register 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); + BCOPY(ip, &cs->cs_ip, hlen); + cs->cs_hlen = (u_short)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) +{ + u_char *cp; + struct tcp_hdr *th; + struct cstate *cs; + u_short *bp; + struct pbuf *n0 = *nb; + u32_t tmp; + u_int vjlen, hlen, changes; + + INCR(vjs_compressedin); + cp = (u_char *)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 *)&((u_char *)&cs->cs_ip)[hlen]; + th->chksum = htons((*cp << 8) | cp[1]); + cp += 2; + if (changes & TCP_PUSH_BIT) { + TCPH_SET_FLAG(th, TCP_PSH); + } else { + TCPH_UNSET_FLAG(th, TCP_PSH); + } + + switch (changes & SPECIALS_MASK) { + case SPECIAL_I: + { + register u32_t i = ntohs(IPH_LEN(&cs->cs_ip)) - cs->cs_hlen; + /* some compilers can't nest inline assembler.. */ + tmp = ntohl(th->ackno) + i; + th->ackno = htonl(tmp); + tmp = ntohl(th->seqno) + i; + th->seqno = htonl(tmp); + } + break; + + case SPECIAL_D: + /* some compilers can't nest inline assembler.. */ + tmp = ntohl(th->seqno) + ntohs(IPH_LEN(&cs->cs_ip)) - cs->cs_hlen; + th->seqno = htonl(tmp); + break; + + default: + if (changes & NEW_U) { + TCPH_SET_FLAG(th, TCP_URG); + DECODEU(th->urgp); + } else { + TCPH_UNSET_FLAG(th, TCP_URG); + } + if (changes & NEW_W) { + DECODES(th->wnd); + } + if (changes & NEW_A) { + DECODEL(th->ackno); + } + if (changes & NEW_S) { + DECODEL(th->seqno); + } + break; + } + if (changes & NEW_I) { + DECODES(cs->cs_ip._id); + } else { + IPH_ID_SET(&cs->cs_ip, ntohs(IPH_ID(&cs->cs_ip)) + 1); + IPH_ID_SET(&cs->cs_ip, htons(IPH_ID(&cs->cs_ip))); + } + + /* + * At this point, cp points to the first byte of data in the + * packet. Fill in the IP total length and update the IP + * header checksum. + */ + vjlen = (u_short)(cp - (u_char*)n0->payload); + if (n0->len < vjlen) { + /* + * We must have dropped some characters (crc should detect + * this but the old slip framing won't) + */ + PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: head buffer %d too short %d\n", + n0->len, vjlen)); + goto bad; + } + +#if BYTE_ORDER == LITTLE_ENDIAN + tmp = n0->tot_len - vjlen + cs->cs_hlen; + IPH_LEN_SET(&cs->cs_ip, htons((u_short)tmp)); +#else + IPH_LEN_SET(&cs->cs_ip, htons(n0->tot_len - vjlen + cs->cs_hlen)); +#endif + + /* recompute the ip header checksum */ + bp = (u_short *) &cs->cs_ip; + IPH_CHKSUM_SET(&cs->cs_ip, 0); + for (tmp = 0; hlen > 0; hlen -= 2) { + tmp += *bp++; + } + tmp = (tmp & 0xffff) + (tmp >> 16); + tmp = (tmp & 0xffff) + (tmp >> 16); + IPH_CHKSUM_SET(&cs->cs_ip, (u_short)(~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; + + np = pbuf_alloc(PBUF_RAW, n0->len + cs->cs_hlen, PBUF_POOL); + if(!np) { + PPPDEBUG(LOG_WARNING, ("vj_uncompress_tcp: realign failed\n")); + goto bad; + } + + if(pbuf_header(np, -cs->cs_hlen)) { + /* Can we cope with this failing? Just assert for now */ + LWIP_ASSERT("pbuf_header failed\n", 0); + goto bad; + } + + bufptr = 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, 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 /* VJ_SUPPORT */ + +#endif /* PPP_SUPPORT */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/vj.h b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/vj.h new file mode 100644 index 0000000..fad1213 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/ppp/vj.h @@ -0,0 +1,156 @@ +/* + * 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. + */ + +#ifndef VJ_H +#define VJ_H + +#include "lwip/ip.h" +#include "lwip/tcp_impl.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) */ + u_short cs_hlen; /* size of hdr (receive only) */ + u_char cs_id; /* connection # associated with this state */ + u_char 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 { + unsigned long vjs_packets; /* outbound packets */ + unsigned long vjs_compressed; /* outbound compressed packets */ + unsigned long vjs_searches; /* searches for connection state */ + unsigned long vjs_misses; /* times couldn't find conn. state */ + unsigned long vjs_uncompressedin; /* inbound uncompressed packets */ + unsigned long vjs_compressedin; /* inbound compressed packets */ + unsigned long vjs_errorin; /* inbound unknown type packets */ + unsigned long 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 */ + u_char last_recv; /* last rcvd conn. id */ + u_char last_xmit; /* last sent conn. id */ + u_short flags; + u_char maxSlotIndex; + u_char 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 u_int 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 */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/slipif.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/slipif.c new file mode 100644 index 0000000..137ba89 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/lwip/netif/slipif.c @@ -0,0 +1,546 @@ +/** + * @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 + * + * Usage: This netif can be used in three ways: + * 1) For NO_SYS==0, an RX thread can be used which blocks on sio_read() + * until data is received. + * 2) In your main loop, call slipif_poll() to check for new RX bytes, + * completed packets are fed into netif->input(). + * 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!). + * + */ + +/* + * 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 + */ + +#include "netif/slipif.h" +#include "lwip/opt.h" + +#if LWIP_HAVE_SLIPIF + +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "lwip/sio.h" +#include "lwip/sys.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 chaing 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 = 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; +} + +/** + * 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 chaing 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, ip_addr_t *ipaddr) +{ + LWIP_UNUSED_ARG(ipaddr); + return slipif_output(netif, p); +} + +#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 chaing 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, 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 = 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; + } /* 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; + } + priv->state = SLIP_RECV_NORMAL; + 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_POOL); + + if (priv->p == NULL) { + LINK_STATS_INC(link.drop); + LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: no new pbuf! (DROP)\n")); + /* don't process any further since we got no pbuf to receive to */ + return NULL; + } + + if (priv->q != NULL) { + /* 'chain' the pbuf to the existing chain */ + pbuf_cat(priv->q, priv->p); + } else { + /* p is the first pbuf in the chain */ + priv->q = priv->p; + } + } + + /* this automatically drops bytes if > SLIP_MAX_SIZE */ + if ((priv->p != NULL) && (priv->recved <= SLIP_MAX_SIZE)) { + ((u8_t *)priv->p->payload)[priv->i] = c; + priv->recved++; + priv->i++; + if (priv->i >= priv->p->len) { + /* on to the next pbuf */ + priv->i = 0; + if (priv->p->next != NULL && priv->p->next->len > 0) { + /* p is a chain, on to the next in the chain */ + priv->p = priv->p->next; + } else { + /* p is a single pbuf, set it to NULL so next time a new + * pbuf is allocated */ + priv->p = NULL; + } + } + } + return NULL; +} + +/** Like slipif_rxbyte, but passes completed packets to netif->input + * + * @param netif The lwip network interface structure for this slipif + * @param data received character + */ +static void +slipif_rxbyte_input(struct netif *netif, u8_t c) +{ + struct pbuf *p; + p = slipif_rxbyte(netif, c); + if (p != NULL) { + if (netif->input(p, netif) != ERR_OK) { + pbuf_free(p); + } + } +} + +#if SLIP_USE_RX_THREAD +/** + * The SLIP input thread. + * + * Feed the IP layer with incoming packets + * + * @param nf the lwip network interface structure for this slipif + */ +static void +slipif_loop_thread(void *nf) +{ + u8_t c; + struct netif *netif = (struct netif *)nf; + struct slipif_priv *priv = (struct slipif_priv *)netif->state; + + while (1) { + if (sio_read(priv->sd, &c, 1) > 0) { + slipif_rxbyte_input(netif, c); + } + } +} +#endif /* SLIP_USE_RX_THREAD */ + +/** + * SLIP netif initialization + * + * Call the arch specific sio_open and remember + * the opened device in the state field of the netif. + * + * @param netif the lwip network interface structure for this slipif + * @return ERR_OK if serial line could be opened, + * ERR_MEM if no memory could be allocated, + * ERR_IF is serial line couldn't be opened + * + * @note netif->num must contain the number of the serial port to open + * (0 by default). If netif->state is != NULL, it is interpreted as an + * u8_t pointer pointing to the serial port number instead of netif->num. + * + */ +err_t +slipif_init(struct netif *netif) +{ + struct slipif_priv *priv; + u8_t sio_num; + + LWIP_DEBUGF(SLIP_DEBUG, ("slipif_init: netif->num=%"U16_F"\n", (u16_t)netif->num)); + + /* Allocate private data */ + priv = (struct slipif_priv *)mem_malloc(sizeof(struct slipif_priv)); + if (!priv) { + return ERR_MEM; + } + + netif->name[0] = 's'; + netif->name[1] = 'l'; + netif->output = slipif_output_v4; +#if LWIP_IPV6 + netif->output_ip6 = slipif_output_v6; +#endif /* LWIP_IPV6 */ + netif->mtu = SLIP_MAX_SIZE; + netif->flags |= NETIF_FLAG_POINTTOPOINT; + + /* 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 */ + NETIF_INIT_SNMP(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 */ + +#endif /* LWIP_HAVE_SLIPIF */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/make_all_lib.sh b/Distrib/ESPressif/RTOS/1.5.0/third_party/make_all_lib.sh new file mode 100644 index 0000000..7861f79 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/make_all_lib.sh @@ -0,0 +1,25 @@ +#!/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 + +for dir in freertos json lwip mbedtls nopoll openssl spiffs ssl; do + cd $dir + make clean + make + cp .output/eagle/debug/lib/lib$dir.a $SDK_PATH/lib/lib$dir.a + xtensa-lx106-elf-strip --strip-unneeded $SDK_PATH/lib/lib$dir.a + cd .. +done; \ No newline at end of file diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/make_lib.sh b/Distrib/ESPressif/RTOS/1.5.0/third_party/make_lib.sh new file mode 100644 index 0000000..6e3e75f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/make_lib.sh @@ -0,0 +1,23 @@ +#!/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 +cp .output/eagle/debug/lib/lib$1.a $SDK_PATH/lib/lib$1.a +xtensa-lx106-elf-strip --strip-unneeded $SDK_PATH/lib/lib$1.a +cd .. diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/Makefile b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/Makefile new file mode 100644 index 0000000..34f85f7 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/Makefile @@ -0,0 +1,48 @@ + +############################################################# +# 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 +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"' + +############################################################# +# 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 $(SDK_PATH)/include/lwip/posix +INCLUDES += -I $(SDK_PATH)/include/mbedtls +INCLUDES += -I ./ +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/Makefile b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/Makefile new file mode 100644 index 0000000..10f4067 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/aes.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/aes.c new file mode 100644 index 0000000..0630042 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/aesni.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/aesni.c new file mode 100644 index 0000000..83a5868 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/arc4.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/arc4.c new file mode 100644 index 0000000..ff0e993 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/asn1parse.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/asn1parse.c new file mode 100644 index 0000000..b37523d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/asn1write.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/asn1write.c new file mode 100644 index 0000000..00ed73c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/base64.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/base64.c new file mode 100644 index 0000000..36be7aa --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/bignum.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/bignum.c new file mode 100644 index 0000000..c55fdb8 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/blowfish.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/blowfish.c new file mode 100644 index 0000000..89be4d1 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/camellia.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/camellia.c new file mode 100644 index 0000000..e015ca2 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ccm.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ccm.c new file mode 100644 index 0000000..3463a0b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/certs.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/certs.c new file mode 100644 index 0000000..ffa48ab --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/cipher.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/cipher.c new file mode 100644 index 0000000..ccc0685 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/cipher_wrap.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/cipher_wrap.c new file mode 100644 index 0000000..814376b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ctr_drbg.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ctr_drbg.c new file mode 100644 index 0000000..aefddfa --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/debug.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/debug.c new file mode 100644 index 0000000..4752ab1 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/des.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/des.c new file mode 100644 index 0000000..61f214a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/dhm.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/dhm.c new file mode 100644 index 0000000..0f4d316 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ecdh.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ecdh.c new file mode 100644 index 0000000..c0a8147 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ecdsa.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ecdsa.c new file mode 100644 index 0000000..4156f3c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ecjpake.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ecjpake.c new file mode 100644 index 0000000..1fa1c2d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ecp.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ecp.c new file mode 100644 index 0000000..19bb488 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ecp_curves.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ecp_curves.c new file mode 100644 index 0000000..9a6e8eb --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/entropy.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/entropy.c new file mode 100644 index 0000000..cdbd35c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/entropy_poll.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/entropy_poll.c new file mode 100644 index 0000000..25a27be --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/error.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/error.c new file mode 100644 index 0000000..debda1d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/gcm.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/gcm.c new file mode 100644 index 0000000..aaacf97 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/havege.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/havege.c new file mode 100644 index 0000000..7623bc0 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/hmac_drbg.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/hmac_drbg.c new file mode 100644 index 0000000..bf5f9b5 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/md.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/md.c new file mode 100644 index 0000000..9c2ab6f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/md2.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/md2.c new file mode 100644 index 0000000..8976701 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/md4.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/md4.c new file mode 100644 index 0000000..11a77e3 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/md5.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/md5.c new file mode 100644 index 0000000..c36192f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/md_wrap.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/md_wrap.c new file mode 100644 index 0000000..3d21159 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/memory_buffer_alloc.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/memory_buffer_alloc.c new file mode 100644 index 0000000..b2c775a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/net.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/net.c new file mode 100644 index 0000000..a77268c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/oid.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/oid.c new file mode 100644 index 0000000..0d606c6 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/padlock.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/padlock.c new file mode 100644 index 0000000..b85ff9c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/pem.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/pem.c new file mode 100644 index 0000000..1ee3966 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/pk.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/pk.c new file mode 100644 index 0000000..10bd0a5 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/pk_wrap.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/pk_wrap.c new file mode 100644 index 0000000..626c3b9 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/pkcs11.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/pkcs11.c new file mode 100644 index 0000000..0ea6425 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/pkcs12.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/pkcs12.c new file mode 100644 index 0000000..7023b9d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/pkcs5.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/pkcs5.c new file mode 100644 index 0000000..44af986 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/pkparse.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/pkparse.c new file mode 100644 index 0000000..275429e --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/pkwrite.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/pkwrite.c new file mode 100644 index 0000000..83b798c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/platform.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/platform.c new file mode 100644 index 0000000..d634c62 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ripemd160.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ripemd160.c new file mode 100644 index 0000000..a55cc3e --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/rsa.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/rsa.c new file mode 100644 index 0000000..efdd055 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/sha1.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/sha1.c new file mode 100644 index 0000000..c9acc64 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/sha256.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/sha256.c new file mode 100644 index 0000000..946e672 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/sha512.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/sha512.c new file mode 100644 index 0000000..1ee22a6 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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 + +#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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ssl_cache.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ssl_cache.c new file mode 100644 index 0000000..711bc53 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ssl_ciphersuites.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ssl_ciphersuites.c new file mode 100644 index 0000000..862deb3 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ssl_cli.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ssl_cli.c new file mode 100644 index 0000000..486a420 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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_ssl_finished_write(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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ssl_cookie.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ssl_cookie.c new file mode 100644 index 0000000..7e0c573 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ssl_srv.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ssl_srv.c new file mode 100644 index 0000000..155bda6 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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_ssl_finished_write(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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ssl_ticket.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ssl_ticket.c new file mode 100644 index 0000000..0e27900 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ssl_tls.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ssl_tls.c new file mode 100644 index 0000000..51b2d54 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/ssl_tls.c @@ -0,0 +1,7735 @@ +/* + * 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 ); +} + +/* + * 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 ) + { + 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 ) ); +} + +#if defined(ESP8266_PLATFORM) +#define MBEDTLS_SSL_OUTBUFFER_LEN ( 2920 \ + + MBEDTLS_SSL_COMPRESSION_ADD \ + + 29 /* counter + header + IV */ \ + + MBEDTLS_SSL_MAC_ADD \ + + MBEDTLS_SSL_PADDING_ADD \ + ) + +typedef struct{ + uint8* finished_buf; + int finished_len; +}mbedtls_finished, *pmbedtls_finished; + +pmbedtls_finished pfinished = NULL; + +static pmbedtls_finished mbedtls_ssl_finished_new(int len) +{ + pmbedtls_finished finished = (pmbedtls_finished)zalloc(sizeof(mbedtls_finished)); + if (finished){ + finished->finished_len = len; + finished->finished_buf = (uint8*)zalloc(finished->finished_len + 1); + if (finished->finished_buf == NULL){ + free(finished); + finished = NULL; + } + } + return finished; +} + +static void mbedtls_ssl_finished_free(pmbedtls_finished *pfinished) +{ + free((*pfinished)->finished_buf); + free(*pfinished); + *pfinished = NULL; +} + +static int mbedtls_ssl_finished_handle(mbedtls_ssl_context *ssl) +{ + int ret = 0; + const size_t len = MBEDTLS_SSL_OUTBUFFER_LEN; + + ssl->out_buf = (unsigned char*)zalloc(len); + if (ssl->out_buf != NULL){ + 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; + memcpy(ssl->out_ctr, pfinished->finished_buf, pfinished->finished_len); + mbedtls_ssl_finished_free(&pfinished); + } else{ + ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; + } + + return ret; +} + +int mbedtls_ssl_finished_write(mbedtls_ssl_context *ssl) +{ + int ret = 0; + + pfinished = mbedtls_ssl_finished_new(ssl->out_msglen + 29); + if (pfinished != NULL) + memcpy(pfinished->finished_buf, ssl->out_ctr, pfinished->finished_len); + else + ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; + return ret; +} + +int mbedtls_ssl_finished_hanshake(mbedtls_ssl_context *ssl) +{ + if( ssl->handshake ) + { + mbedtls_ssl_handshake_free( ssl->handshake ); + mbedtls_ssl_transform_free( ssl->transform_negotiate ); + mbedtls_ssl_session_free( ssl->session_negotiate ); + + free( ssl->handshake ); + free( ssl->transform_negotiate ); + free( ssl->session_negotiate ); + ssl->handshake = NULL; + ssl->transform_negotiate = NULL; + ssl->session_negotiate = NULL; + } + + if( ssl->session ) + { + mbedtls_ssl_session_free( ssl->session ); + free( ssl->session ); + ssl->session = NULL; + } + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + if( ssl->hostname != NULL ) + { + mbedtls_zeroize( ssl->hostname, strlen( ssl->hostname ) ); + free( ssl->hostname ); + ssl->hostname = NULL; + } +#endif + + mbedtls_ssl_finished_handle(ssl); +} + +#endif + +/* + * 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 ); + } + + if( ssl->out_buf != NULL ) + { + mbedtls_zeroize( ssl->out_buf, MBEDTLS_SSL_OUTBUFFER_LEN ); + mbedtls_free( ssl->out_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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/threading.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/threading.c new file mode 100644 index 0000000..1b6d9cd --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/timing.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/timing.c new file mode 100644 index 0000000..5d8b25b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/version.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/version.c new file mode 100644 index 0000000..6ca80d4 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/version_features.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/version_features.c new file mode 100644 index 0000000..1575e09 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/x509.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/x509.c new file mode 100644 index 0000000..ffc3d6c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/x509_create.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/x509_create.c new file mode 100644 index 0000000..823747b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/x509_crl.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/x509_crl.c new file mode 100644 index 0000000..125a773 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/x509_crt.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/x509_crt.c new file mode 100644 index 0000000..d9a5bce --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/x509_crt.c @@ -0,0 +1,2398 @@ +/* + * 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 */ + 2048, +}; + +/* + * Next-default profile + */ +const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_next ICACHE_RODATA_ATTR = +{ + /* Hashes from SHA-256 and above */ + 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 + 2048, +}; + +/* + * NSA Suite B Profile + */ +const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_suiteb ICACHE_RODATA_ATTR = +{ + /* Only SHA-256 and 384 */ + 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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/x509_csr.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/x509_csr.c new file mode 100644 index 0000000..dbf659b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/x509write_crt.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/x509write_crt.c new file mode 100644 index 0000000..9041d44 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/x509write_csr.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/x509write_csr.c new file mode 100644 index 0000000..0b9a285 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/xtea.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/library/xtea.c new file mode 100644 index 0000000..fe0a350 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/platform/Makefile b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/platform/Makefile new file mode 100644 index 0000000..749b478 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/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/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/platform/esp_hardware.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/platform/esp_hardware.c new file mode 100644 index 0000000..8240838 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/platform/esp_hardware.c @@ -0,0 +1,26 @@ +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include "esp_common.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; +} +#endif + diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/platform/net.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/platform/net.c new file mode 100644 index 0000000..91e96fd --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/mbedtls/platform/net.c @@ -0,0 +1,516 @@ +/* + * TCP/IP or UDP/IP networking functions + * modified for LWIP support on ESP32 + * + * 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) + */ + +#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 +#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; + 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, 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( 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; + } + + /*SO_REUSEADDR option dafault is disable in source code(lwip)*/ +#if SO_REUSE + 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; + } +#endif + /*bind interface dafault don't process the addr is 0xffffffff for TCP Protocol*/ + struct sockaddr_in *serv_addr = NULL; + serv_addr = (struct sockaddr_in *)cur->ai_addr; + serv_addr->sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */ + if( bind( ctx->fd, (struct sockaddr *)serv_addr, 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, 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 ); + + /* Is this a TCP or UDP socket? */ + if( getsockopt( bind_ctx->fd, SOL_SOCKET, SO_TYPE, + (void *) &type, (socklen_t *) &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 = 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_in 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_in ); + if( getsockname( client_ctx->fd, + (struct sockaddr *) &local_addr, &n ) != 0 || + ( bind_ctx->fd = (int) socket( AF_INET, + 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 ) + { + 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 ); + } + + 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 ); + + 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/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/Makefile b/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/Makefile new file mode 100644 index 0000000..471098f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/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 = libnopoll.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/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll-regression-client.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll-regression-client.c new file mode 100644 index 0000000..d5e7d1e --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll-regression-client.c @@ -0,0 +1,3080 @@ +/* + * LibNoPoll: A websocket library + * Copyright (C) 2013 Advanced Software Production Line, S.L. + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * You may find a copy of the license under this software is released + * at COPYING file. This is LGPL software: you are welcome to develop + * proprietary applications using this library without any royalty or + * fee but returning back any change, improvement or addition in the + * form of source code, project image, documentation patches, etc. + * + * For commercial support on build Websocket enabled solutions + * contact us: + * + * Postal address: + * Advanced Software Production Line, S.L. + * Edificio Alius A, Oficina 102, + * C/ Antonio Suarez Nº 10, + * Alcalá de Henares 28802 Madrid + * Spain + * + * Email address: + * info@aspl.es - http://www.aspl.es/nopoll + */ +#include +#include "ssl/ssl_compat-1.0.h" +#include "esp_common.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#if defined(__NOPOLL_PTHREAD_SUPPORT__) +#include +noPollPtr __nopoll_regtest_mutex_create (void) { + pthread_mutex_t * mutex = nopoll_new (pthread_mutex_t, 1); + if (mutex == NULL) + return NULL; + + /* init the mutex using default values */ + if (pthread_mutex_init (mutex, NULL) != 0) { + return NULL; + } /* end if */ + + return mutex; +} + +void __nopoll_regtest_mutex_destroy (noPollPtr _mutex) { + pthread_mutex_t * mutex = _mutex; + if (mutex == NULL) + return; + + if (pthread_mutex_destroy (mutex) != 0) { + /* do some reporting */ + return; + } + nopoll_free (mutex); + + return; +} + +void __nopoll_regtest_mutex_lock (noPollPtr _mutex) { + pthread_mutex_t * mutex = _mutex; + + /* lock the mutex */ + if (pthread_mutex_lock (mutex) != 0) { + /* do some reporting */ + return; + } /* end if */ + return; +} + +void __nopoll_regtest_mutex_unlock (noPollPtr _mutex) { + pthread_mutex_t * mutex = _mutex; + + /* unlock mutex */ + if (pthread_mutex_unlock (mutex) != 0) { + /* do some reporting */ + return; + } /* end if */ + return; +} +#endif + +nopoll_bool debug = nopoll_false; +nopoll_bool show_critical_only = nopoll_false; + +#define local_host_name "iot.espressif.cn" +#define local_host_url "v1/datastreams/tem_hum/datapoint" +#define local_host_port "9000" +#define local_host_ports "9443" + +nopoll_bool test_sending_and_check_echo (noPollConn * conn, const char * label, const char * msg) +{ + char buffer[1024]; + int length = strlen (msg); + int bytes_read; + + /* wait for the reply */ + while (nopoll_true) { + if (nopoll_conn_is_ready (conn)) + break; + nopoll_sleep (10000); + } /* end if */ + + /* send content text(utf-8) */ + printf ("%s: sending content..\n", label); + if (nopoll_conn_send_text (conn, msg, length) != length) { + printf ("ERROR: Expected to find proper send operation..\n"); + return nopoll_false; + } + + /* wait for the reply (try to read 1024, blocking and with a 3 seconds timeout) */ + bytes_read = nopoll_conn_read (conn, buffer, length, nopoll_true, 3000); + if (bytes_read > 0) + buffer[bytes_read] = 0; + + if (bytes_read != length) { + printf ("ERROR: expected to find 14 bytes but found %d..\n", bytes_read); + return nopoll_false; + } /* end if */ + + /* check content received */ + if (! nopoll_cmp (buffer, msg)) { + printf ("ERROR: expected to find message 'This is a test' but something different was received: '%s'..\n", + buffer); + return nopoll_false; + } /* end if */ + + printf ("%s: received reply and echo matches..\n", label); + + /* return that we sent and received the echo reply */ + return nopoll_true; +} + +void __report_critical (noPollCtx * ctx, noPollDebugLevel level, const char * log_msg, noPollPtr user_data) +{ + if (level == NOPOLL_LEVEL_CRITICAL) { + printf ("CRITICAL: %s\n", log_msg); + } + return; +} + +noPollCtx * create_ctx (void) { + + /* create a context */ + noPollCtx * ctx = nopoll_ctx_new (); + nopoll_log_enable (ctx, debug); + nopoll_log_color_enable (ctx, debug); + + /* configure handler */ + if (show_critical_only) + nopoll_log_set_handler (ctx, __report_critical, NULL); + return ctx; +} + +nopoll_bool test_01_strings (void) { + /* check string compare functions */ + if (! nopoll_ncmp ("GET ", "GET ", 4)) { + printf ("ERROR (1): expected to find right equal comparison..\n"); + return nopoll_false; + } + + if (! nopoll_ncmp ("GET VALUE", "GET ", 4)) { + printf ("ERROR (2): expected to find right equal comparison..\n"); + return nopoll_false; + } + + return nopoll_true; +} + +nopoll_bool test_01_base64 (void) { + char buffer[1024]; + int size = 1024; + int iterator = 0; + + /* call to produce base 64 (we do a loop to ensure we don't + * leak through openssl (220) bytes */ + while (iterator < 10) { + size = 1024; + if (! nopoll_base64_encode ("This is a test", 14, buffer, &size)) { + printf ("ERROR: failed to encode this is a test..\n"); + return nopoll_false; + } /* end if */ + + /* check result */ + if (! nopoll_cmp (buffer, "VGhpcyBpcyBhIHRlc3Q=")) { + printf ("ERROR: expected to find encoded base64 string %s but found %s..\n", + "VGhpcyBpcyBhIHRlc3Q=", buffer); + return nopoll_false; + } + + iterator++; + } + + /* now decode content */ + iterator = 0; + while (iterator < 10) { + size = 1024; + if (! nopoll_base64_decode ("VGhpcyBpcyBhIHRlc3Q=", 20, buffer, &size)) { + printf ("ERROR: failed to decode base64 content..\n"); + } + + /* check result */ + if (! nopoll_cmp (buffer, "This is a test")) { + printf ("ERROR: expected to find encoded base64 string %s but found %s..\n", + "This is a test", buffer); + return nopoll_false; + } /* end if */ + + iterator++; + } + + + return nopoll_true; +} + +nopoll_bool test_01_masking (void) { + + char mask[4]; + int mask_value; + char buffer[1024]; + noPollCtx * ctx; + + /* clear buffer */ + memset (buffer, 0, 1024); + + /* create context */ + ctx = create_ctx (); + +#if defined(NOPOLL_OS_WIN32) + mask_value = rand (); +#else + mask_value = os_random (); +#endif + printf ("Test-01 masking: using masking value %d\n", mask_value); + nopoll_set_32bit (mask_value, mask); + + memcpy (buffer, "This is a test value", 20); + nopoll_conn_mask_content (ctx, buffer, 20, mask, 0); + + if (nopoll_ncmp (buffer, "This is a test value", 20)) { + printf ("ERROR: expected to find different values after masking but found the same..\n"); + return nopoll_false; + } + + /* revert changes */ + nopoll_conn_mask_content (ctx, buffer, 20, mask, 0); + + if (! nopoll_ncmp (buffer, "This is a test value", 20)) { + printf ("ERROR: expected to find SAME values after masking but found the same..\n"); + return nopoll_false; + } /* end if */ + + /* now check transfering these values to the mask */ + if (nopoll_get_32bit (mask) != mask_value) { + printf ("ERROR: found failure while reading the mask from from buffer..\n"); + return nopoll_false; + } + printf ("Test 01 masking: found mask in the buffer %d == %d\n", + nopoll_get_32bit (mask), mask_value); + + nopoll_ctx_unref (ctx); + return nopoll_true; +} + +nopoll_bool test_01 (void) { + noPollCtx * ctx; + noPollConn * conn; + + /* create context */ + ctx = create_ctx (); + + /* check connections registered */ + if (nopoll_ctx_conns (ctx) != 0) { + printf ("ERROR: expected to find 0 registered connections but found: %d\n", nopoll_ctx_conns (ctx)); + return nopoll_false; + } /* end if */ + + nopoll_ctx_unref (ctx); + + /* reinit again */ + ctx = create_ctx (); + + /* call to create a connection */ + conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error (conn=%p, conn->session=%d, NOPOLL_INVALID_SOCKET=%d)..\n", + conn, (int) nopoll_conn_socket (conn), (int) NOPOLL_INVALID_SOCKET); + return nopoll_false; + } + + /* check connections registered */ + if (nopoll_ctx_conns (ctx) != 1) { + printf ("ERROR: expected to find 1 registered connections but found: %d\n", nopoll_ctx_conns (ctx)); + return nopoll_false; + } /* end if */ + + /* ensure connection status is ok */ + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR (3): expected to find proper connection status, but found failure.. (conn=%p, conn->session=%d, NOPOLL_INVALID_SOCKET=%d)..\n", + conn, (int) nopoll_conn_socket (conn), (int) NOPOLL_INVALID_SOCKET); + return nopoll_false; + } + + printf ("Test 01: reference counting for the connection: %d\n", nopoll_conn_ref_count (conn)); + + /* check if the connection already finished its connection + handshake */ + while (! nopoll_conn_is_ready (conn)) { + + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR (4.1 jkd412): expected to find proper connection handshake finished, but found connection is broken: session=%d, errno=%d : %s..\n", + (int) nopoll_conn_socket (conn), errno, strerror (errno)); + return nopoll_false; + } /* end if */ + + /* wait a bit 10ms */ + nopoll_sleep (100); + } /* end if */ + + /* finish connection */ + nopoll_conn_close (conn); + + /* finish */ + nopoll_ctx_unref (ctx); + + return nopoll_true; +} + +nopoll_bool test_02 (void) { + noPollCtx * ctx; + noPollConn * conn; + noPollMsg * msg; + int iter; + + /* create context */ + ctx = create_ctx (); + + /* check connections registered */ + if (nopoll_ctx_conns (ctx) != 0) { + printf ("ERROR: expected to find 0 registered connections but found: %d\n", nopoll_ctx_conns (ctx)); + return nopoll_false; + } /* end if */ + + nopoll_ctx_unref (ctx); + + /* reinit again */ + ctx = create_ctx (); + + /* call to create a connection */ + conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error.. (conn=%p, conn->session=%d, NOPOLL_INVALID_SOCKET=%d, errno=%d, strerr=%s)..\n", + conn, (int) nopoll_conn_socket (conn), (int) NOPOLL_INVALID_SOCKET, errno, strerror (errno)); + return nopoll_false; + } + + printf ("Test 02: sending basic content..\n"); + + /* send content text(utf-8) */ + if (nopoll_conn_send_text (conn, "This is a test", 14) != 14) { + printf ("ERROR: Expected to find proper send operation..\n"); + return nopoll_false; + } + + /* wait for the reply */ + iter = 0; + while ((msg = nopoll_conn_get_msg (conn)) == NULL) { + + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: received websocket connection close during wait reply..\n"); + return nopoll_false; + } + + nopoll_sleep (10000); + + if (iter > 10) + break; + } /* end if */ + + /* check content received */ + if (! nopoll_cmp ((char*) nopoll_msg_get_payload (msg), "This is a test")) { + printf ("ERROR: expected to find message 'This is a test' but something different was received: '%s'..\n", + (const char *) nopoll_msg_get_payload (msg)); + return nopoll_false; + } /* end if */ + + /* unref message */ + nopoll_msg_unref (msg); + + /* finish connection */ + nopoll_conn_close (conn); + + /* finish */ + nopoll_ctx_unref (ctx); + + return nopoll_true; +} + +nopoll_bool test_03 (void) { + noPollCtx * ctx; + noPollConn * conn; + char buffer[1024]; + int bytes_read; + + memset (buffer, 0, 1024); + + /* create context */ + ctx = create_ctx (); + + /* check connections registered */ + if (nopoll_ctx_conns (ctx) != 0) { + printf ("ERROR: expected to find 0 registered connections but found: %d\n", nopoll_ctx_conns (ctx)); + return nopoll_false; + } /* end if */ + + nopoll_ctx_unref (ctx); + + /* reinit again */ + ctx = create_ctx (); + + /* call to create a connection */ + conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } + + printf ("Test 03: sending basic content..\n"); + + /* send content text(utf-8) */ + if (nopoll_conn_send_text (conn, "This is a test", 14) != 14) { + printf ("ERROR: Expected to find proper send operation..\n"); + return nopoll_false; + } + + /* wait for the reply (try to read 1024, blocking and with a 3 seconds timeout) */ + printf ("Test 03: now reading reply..\n"); + bytes_read = nopoll_conn_read (conn, buffer, 14, nopoll_true, 3000); + + if (bytes_read != 14) { + printf ("ERROR: expected to find 14 bytes but found %d..\n", bytes_read); + return nopoll_false; + } /* end if */ + + /* check content received */ + if (! nopoll_ncmp (buffer, "This is a test", 14)) { + printf ("ERROR: expected to find message 'This is a test' but something different was received: '%s'..\n", + buffer); + return nopoll_false; + } /* end if */ + + /* finish connection */ + nopoll_conn_close (conn); + + /* finish */ + nopoll_ctx_unref (ctx); + + return nopoll_true; +} + +//nopoll_bool test_04 (int chunk_size) { +// noPollCtx * ctx; +// noPollConn * conn; +// char buffer[1024]; +// int bytes_read; +// FILE * file; +// struct stat stat_buf; +// int total_read = 0; +// const char * cmd; +// int retries = 0; +// +// /* create context */ +// ctx = create_ctx (); +// +// printf ("Test 04: running test with chunk_size=%d\n", chunk_size); +// +// /* check connections registered */ +// if (nopoll_ctx_conns (ctx) != 0) { +// printf ("ERROR: expected to find 0 registered connections but found: %d\n", nopoll_ctx_conns (ctx)); +// return nopoll_false; +// } /* end if */ +// +// nopoll_ctx_unref (ctx); +// +// printf ("Test 04: creating connection to download file..\n"); +// +// /* reinit again */ +// ctx = create_ctx (); +// +// /* call to create a connection */ +// conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, NULL, NULL, NULL); +// if (! nopoll_conn_is_ok (conn)) { +// printf ("ERROR: Expected to find proper client connection status, but found error..\n"); +// return nopoll_false; +// } +// +// printf ("Test 04: sending get-file..\n"); +// +// /* send content text(utf-8) */ +// if (nopoll_conn_send_text (conn, "get-file", 8) != 8) { +// printf ("ERROR: Expected to find proper send operation..\n"); +// return nopoll_false; +// } +// +//#if defined(NOPOLL_OS_WIN32) +// file = fopen ("tmp", "wb"); +//#else +// file = fopen ("tmp", "w"); +//#endif +// if (file == NULL) { +// printf ("ERROR: unable to open file tmp for content comparision\n"); +// return nopoll_false; +// } /* end if */ +// +// stat ("nopoll-regression-client.c", &stat_buf); +// +// printf ("Test 04: stat file (nopoll-regression-client.c = %d bytes)\n", (int) stat_buf.st_size); +// +// retries = 0; +// while (total_read < stat_buf.st_size) { +// /* wait for the reply (try to read 1024, blocking) */ +// bytes_read = nopoll_conn_read (conn, buffer, chunk_size, nopoll_true, 1000); +// /* printf ("Test 04: read %d bytes over the connection %d\n", bytes_read, nopoll_conn_get_id (conn)); */ +// +// if (bytes_read < 0) { +// printf ("ERROR: expected to find bytes from the connection but found: %d\n", bytes_read); +// return nopoll_false; +// } +// +// if (bytes_read == 0) { +// retries ++; +// if (retries > 100) { +// printf ("Test 04: nothing found (0 bytes), total read %d, total requested: %ld, for %d retries\n", +// total_read, stat_buf.st_size, retries); +// return nopoll_false; +// } /* end if */ +// continue; +// } /* end if */ +// +// /* write content */ +// if (fwrite (buffer, 1, bytes_read, file) != bytes_read) +// return nopoll_false; +// +// /* count total read bytes */ +// total_read += bytes_read; +// +// } /* end while */ +// fclose (file); +// +// /* now check both files */ +// printf ("Test 04: checking content download (chunk_size=%d)...\n", chunk_size); +// printf ("Test 04: about to run diff nopoll-regression-client.c tmp > /dev/null\n"); +//#if defined(NOPOLL_OS_WIN32) +// cmd = "diff -q nopoll-regression-client.c tmp"; +//#else +// cmd = "diff -q nopoll-regression-client.c tmp > /dev/null"; +//#endif +// if (system (cmd)) { +// printf ("ERROR: failed to download file from server, content differs. Check: diff nopoll-regression-client.c tmp\n"); +// return nopoll_false; +// } /* end if */ +// +// /* finish connection */ +// nopoll_conn_close (conn); +// +// /* finish */ +// nopoll_ctx_unref (ctx); +// +// return nopoll_true; +//} + +nopoll_bool test_04a (void) { + noPollCtx * ctx; + noPollConn * conn; + char buffer[1024]; + int result; + + /* reinit again */ + ctx = create_ctx (); + + /* call to create a connection */ + conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } + + /* attempt to read without blocking */ + printf ("Test 04-a: checking non-blocking API..\n"); + result = nopoll_conn_read (conn, buffer, 1024, nopoll_false, 0); + if (result != -1) { + printf ("ERROR: expected return result -1(%d)\n", result); + return nopoll_false; + } + + printf ("Test 04-a: ok, operation not blocked, result %d\n", result); + if (result != -1) { + printf ("ERROR: expected return result -1(%d)\n", result); + return nopoll_false; + } + + result = nopoll_conn_read (conn, buffer, 1024, nopoll_false, 300); + if (result != -1) { + printf ("ERROR: expected return result -1(%d)\n", result); + return nopoll_false; + } + + printf ("Test 04-a: ok, operation not blocked, result %d\n", result); + + result = nopoll_conn_read (conn, buffer, 1024, nopoll_false, 1000); + if (result != -1) { + printf ("ERROR: expected return result -1(%d)\n", result); + return nopoll_false; + } + + printf ("Test 04-a: ok, operation not blocked, result %d\n", result); + + /* finish connection */ + nopoll_conn_close (conn); + + /* finish */ + nopoll_ctx_unref (ctx); + + + return nopoll_true; +} + +nopoll_bool test_04b (void) { + noPollCtx * ctx; + noPollConn * conn; + int iterator; + int length; + int bytes_written; + const char * msg = NULL; + /* reinit again */ + ctx = create_ctx (); + + /* call to create a connection */ + conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } + + printf ("Test 04-b: waiting until connection is ok\n"); + nopoll_conn_wait_until_connection_ready (conn, 5); + + printf ("Test 04-b: sending was quick as possible to flood local buffers..\n"); + + /* get message length */ + length = strlen (msg); + iterator = 0; + while (iterator < 100) { + /* send a message */ + if (nopoll_conn_send_text (conn, msg, length) != length) { + if (errno == 0) { + printf ("ERROR: expected to find errno value but found 0..\n"); + } + printf ("Test 04-b: found expected error, checking errno=%d..\n", errno); + break; + } /* end if */ + + /* next iterator */ + iterator ++; + } /* end while */ + + if (errno != NOPOLL_EWOULDBLOCK && errno != EINPROGRESS) { + printf ("ERROR: expected to find errno=%d, but found errno=%d : %s\n", + (int)NOPOLL_EWOULDBLOCK, (int)errno, strerror (errno)); + return nopoll_false; + } /* end if */ + + /* write pending content */ + if (nopoll_conn_pending_write_bytes (conn) == 0) { + printf ("ERROR: expected to have pending bytes to be written.. but found 0..\n"); + return nopoll_false; + } /* end if */ + + iterator = 0; + while (iterator < 10) { + printf ("Test 04-b: found pending write bytes=%d\n", nopoll_conn_pending_write_bytes (conn)); + + /* call to flush bytes */ + nopoll_conn_complete_pending_write (conn); + + if (nopoll_conn_pending_write_bytes (conn) == 0) { + printf ("Test 04-b: all bytes written..\n"); + break; + } /* end if */ + + /* sleep a bit */ + nopoll_sleep (1000000); + + /* next iterator */ + iterator++; + } + + if (nopoll_conn_pending_write_bytes (conn) != 0) { + printf ("Test 04-b: expected to find no pending bytes waiting to be written but found: %d\n", nopoll_conn_pending_write_bytes (conn)); + return nopoll_false; + } /* end if */ + + nopoll_conn_close (conn); + + /* call to create a connection */ + conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } + + printf ("Test 04-b: waiting until connection is ok\n"); + nopoll_conn_wait_until_connection_ready (conn, 5); + + /* send a cleanup message */ + bytes_written = nopoll_conn_send_text (conn, "release-message", 15); + if (bytes_written != 15) { + printf ("Test 04-b: unable to send release message, bytes_written=%d, but expected=%d..\n", + bytes_written, 15); + return nopoll_false; + } /* end if */ + + printf ("Test 04-b: waiting a second before finishing test..\n"); + nopoll_sleep (1000000); + + /* finish connection */ + nopoll_conn_close (conn); + + /* finish */ + nopoll_ctx_unref (ctx); + + return nopoll_true; +} + +//nopoll_bool test_04c (void) { +// noPollCtx * ctx; +// noPollConn * conn; +// int length; +// int bytes_written; +// char buffer[4096]; +// FILE * handle; +// struct stat file_info; +// int iterator; +// char * cmd; +// const char * file_checked; +// const char * cmd_format; +// int total_bytes = 0; +// nopoll_bool flush_required = nopoll_false; +// +// /* reinit again */ +// ctx = create_ctx (); +// +// /* call to create a connection */ +// conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, NULL, NULL, NULL); +// if (! nopoll_conn_is_ok (conn)) { +// printf ("ERROR: Expected to find proper client connection status, but found error..\n"); +// return nopoll_false; +// } +// +// printf ("Test 04-c: waiting until connection is ok\n"); +// nopoll_conn_wait_until_connection_ready (conn, 5); +// +// /* remove local file */ +// if (stat ("copy-test-04c.txt", &file_info) == 0) { +// printf ("Test 04-c: FILE exists, removing (copy-test-04c.txt)\n"); +// /* remove file */ +// unlink ("copy-test-04c.txt"); +// } /* end if */ +// +// /* open file descriptor */ +// bytes_written = nopoll_conn_send_text (conn, "open-file: copy-test-04c.txt", 28); +// if (bytes_written != 28) { +// printf ("Test 04-c: unable to send open file command, bytes_written=%d, but expected=%d..\n", +// bytes_written, 15); +// return nopoll_false; +// } /* end if */ +// +// /* open the handle to send the content */ +// file_checked = "/boot/vmlinuz-2.6.32-5-amd64"; +//#if defined(NOPOLL_OS_WIN32) +// handle = fopen (file_checked, "rb"); +//#else +// handle = fopen (file_checked, "r"); +//#endif +// if (handle == NULL) { +// /* checking file */ +// file_checked = "nopoll-regression-client.c"; +//#if defined(NOPOLL_OS_WIN32) +// handle = fopen (file_checked, "rb"); +//#else +// handle = fopen (file_checked, "r"); +//#endif +// if (handle == NULL) { +// printf ("Test 04-c: failed to open file to be sent to the server..\n"); +// return nopoll_false; +// } /* end if */ +// } /* end if */ +// printf ("Test 04-c: running test with file: %s\n", file_checked); +// +// /* send content */ +// while (nopoll_true) { +// /* read content */ +// length = fread (buffer, 1, 4096, handle); +// +// /* write content */ +// if (length > 0) { +// bytes_written = nopoll_conn_send_text (conn, buffer, length); +// +// /* check for flush required */ +// if (nopoll_conn_pending_write_bytes (conn) > 0) +// flush_required = nopoll_true; +// +// /* call to flush writes */ +// bytes_written = nopoll_conn_flush_writes (conn, 10000000, bytes_written); +// +// if (bytes_written != length) { +// printf ("ERROR: Failed to send bytes read from file %d, bytes written were=%d (errno=%d, pending bytes: %d, total bytes: %d)..\n", +// length, bytes_written, errno, nopoll_conn_pending_write_bytes (conn), total_bytes); +// return nopoll_false; +// } /* end if */ +// } /* end if */ +// +// if (bytes_written > 0) +// total_bytes += bytes_written; +// +// if (length < 4096) { +// printf ("Test 04-c: last read operation found length=%d\n", length); +// break; +// } /* end if */ +// } /* end while */ +// +// fclose (handle); +// +// printf ("Test 04-c: pending bytes to be written are=%d\n", nopoll_conn_pending_write_bytes (conn)); +// +// /* send command to close file */ +// bytes_written = nopoll_conn_send_text (conn, "close-file", 10); +// if (bytes_written != 10) { +// printf ("Test 04-c: unable to send close file command\n"); +// return nopoll_false; +// } /* end if */ +// +//#if defined(NOPOLL_OS_WIN32) +// cmd_format = "diff -q copy-test-04c.txt %s"; +//#else +// cmd_format = "diff -q copy-test-04c.txt %s > /dev/null"; +//#endif +// cmd = nopoll_strdup_printf (cmd_format, file_checked); +// +// iterator = 0; +// while (iterator < 50) { +// /* checking file transferred */ +// printf ("Test 04-c: checking file transfered, iterator=%d..\n", iterator); +// if (system (cmd) == 0) +// break; +// +// iterator++; +// nopoll_sleep (500000); +// } /* end if */ +// +// if (system (cmd) != 0) { +// printf ("Test 04-c: file differs, test failing, run: diff copy-test-04c.txt %s\n", file_checked); +// return nopoll_false; +// } /* end if */ +// +// /* check total size */ +// if (stat ("copy-test-04c.txt", &file_info) == 0 && file_info.st_size != total_bytes) { +// printf ("Test 04-c: expected to find same total bytes written %d != %d\n", +// (int) file_info.st_size, (int) total_bytes); +// return nopoll_false; +// } /* end if */ +// +// if (stat (file_checked, &file_info) == 0 && file_info.st_size != total_bytes) { +// printf ("Test 04-c: expected to find same total bytes written %d != %d\n", +// (int) file_info.st_size, (int) total_bytes); +// return nopoll_false; +// } /* end if */ +// +// printf ("Test 04-c: file ok (%d bytes written)..\n", total_bytes); +// nopoll_free (cmd); +// +// if (! flush_required) { +// printf (" *** \n"); +// printf (" *** \n"); +// printf (" *** ATTENTION: !! Flush operations weren't required so this test didn't check everything (file used to check transfers was: %s) \n", +// file_checked); +// printf (" *** \n"); +// printf (" *** \n"); +// } +// +// /* sleep half a second */ +// nopoll_sleep (500000); +// +// /* finish connection */ +// nopoll_conn_close (conn); +// +// /* finish */ +// nopoll_ctx_unref (ctx); +// +// return nopoll_true; +//} + +nopoll_bool test_05 (void) { + + noPollCtx * ctx; + noPollConn * conn; + char buffer[1024]; + int bytes_read; + const char * msg = " klasdfkla akldfj klafklajetqkljt kjlwergklwejry90246tkgwr kñljwrglkjdfg lksdjglskg slkg camión adsfasdf pruébasdfad España asdfaklsjdflk jasfkjaslfjetql tjñqgkjadgklj aglkjalk jafkjaslfkjaskj asjaslfkjasfklajg klajefñlqkjetrlkqj lqkj ñlskdfjañlk asldfjñlafj añlfj ñdfjkjt4ñqlkjt lkj34tlkjañlgjañlkgjañlkgjw"; + + memset (buffer, 0, 1024); + + /* reinit again */ + ctx = create_ctx (); + + /* call to create a connection */ + conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } + + printf ("Test 05: sending UTF-8 content..\n"); + + /* send content text(utf-8) */ + if (nopoll_conn_send_text (conn, msg, -1) <= 0) { + printf ("ERROR: Expected to find proper send operation (nopoll_conn_send_test) returned less or 0..\n"); + return nopoll_false; + } + + /* wait for the reply (try to read 322, blocking and with a 3 seconds timeout) */ + bytes_read = nopoll_conn_read (conn, buffer, 322, nopoll_true, 3000); + if (bytes_read != 322) { + printf ("ERROR: expected to receive 322 bytes, but received %d\n", bytes_read); + return nopoll_false; + } + + if (! nopoll_ncmp (buffer, msg, 322)) { + printf ("ERROR: expected to receive another content....\n"); + printf ("Expected: %s\n", msg); + printf ("Received: %s\n", buffer); + + return nopoll_false; + } + + /* finish connection */ + nopoll_conn_close (conn); + + /* finish */ + nopoll_ctx_unref (ctx); + + return nopoll_true; +} + +nopoll_bool test_06 (void) { + + noPollCtx * ctx; + noPollConn * conn; + noPollConnOpts * opts; + + /* reinit again */ + ctx = create_ctx (); + + /* disable verification */ + opts = nopoll_conn_opts_new (); + nopoll_conn_opts_ssl_peer_verify (opts, nopoll_false); + + /* call to create a connection */ + conn = nopoll_conn_tls_new (ctx, opts, local_host_name, local_host_ports, NULL, local_host_url, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } + + /* check if the connection already finished its connection + handshake */ + while (! nopoll_conn_is_ready (conn)) { + + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR (4.1 jg72): expected to find proper connection handshake finished, but found connection is broken: session=%d, errno=%d : %s..\n", + (int) nopoll_conn_socket (conn), errno, strerror (errno)); + return nopoll_false; + } /* end if */ + + /* wait a bit 10ms */ + nopoll_sleep (100); + } /* end if */ + + if (! nopoll_conn_is_tls_on (conn)) { + printf ("ERROR (5): expected to find TLS enabled on the connection but found it isn't..\n"); + return nopoll_false; + } /* end if */ + + /* finish connection */ + nopoll_conn_close (conn); + + /* finish */ + nopoll_ctx_unref (ctx); + + return nopoll_true; +} + +nopoll_bool test_07 (void) { + + noPollCtx * ctx; + noPollConn * conn; + noPollConnOpts * opts; + + /* reinit again */ + ctx = create_ctx (); + + /* disable verification */ + opts = nopoll_conn_opts_new (); + nopoll_conn_opts_ssl_peer_verify (opts, nopoll_false); + + /* call to create a connection */ + conn = nopoll_conn_tls_new (ctx, opts, local_host_name, local_host_ports, NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } /* end if */ + + /* check if the connection already finished its connection + handshake */ + while (! nopoll_conn_is_ready (conn)) { + + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR (4.1 dk45): expected to find proper connection handshake finished, but found connection is broken: session=%d, errno=%d : %s..\n", + (int) nopoll_conn_socket (conn), errno, strerror (errno)); + return nopoll_false; + } /* end if */ + + /* wait a bit 10ms */ + nopoll_sleep (10000); + } /* end if */ + + printf ("Test 07: testing sending TLS content over the wire..\n"); + if (! test_sending_and_check_echo (conn, "Test 07", "This is a test")) + return nopoll_false; + + /* finish connection */ + nopoll_conn_close (conn); + + /* finish */ + nopoll_ctx_unref (ctx); + + return nopoll_true; +} + +nopoll_bool test_08 (void) { + + noPollCtx * ctx; + noPollConn * conn; + + /* reinit again */ + ctx = create_ctx (); + + /* call to connect to TLS port expecting non-TLS protocol */ + conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, NULL, NULL, NULL); + + /* wait a bit 100ms */ + nopoll_sleep (100000); + + if (nopoll_conn_is_ready (conn)) { + printf ("ERROR: Expected a FAILING connection status, but found error..\n"); + return nopoll_false; + } /* end if */ + + /* finish connection */ + nopoll_conn_close (conn); + + /* finish */ + nopoll_ctx_unref (ctx); + + return nopoll_true; +} + +nopoll_bool test_09 (void) { + + noPollCtx * ctx; + noPollConn * conn; + + /* reinit again */ + ctx = create_ctx (); + + /* setup the protocol version to see how it breaks (it should) */ + nopoll_ctx_set_protocol_version (ctx, 12); + + /* call to connect to TLS port expecting non-TLS protocol */ + conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, NULL, NULL, NULL); + + /* wait a bit 100ms */ + nopoll_sleep (100000); + + if (nopoll_conn_is_ready (conn)) { + printf ("ERROR: Expected a FAILING connection status due to protocol version error, but it working..\n"); + return nopoll_false; + } /* end if */ + + /* finish connection */ + nopoll_conn_close (conn); + + /* finish */ + nopoll_ctx_unref (ctx); + + return nopoll_true; +} + +nopoll_bool test_10 (void) { + + noPollCtx * ctx; + noPollConn * conn; + + /* reinit again */ + ctx = create_ctx (); + + /* call to connect from an origining that shouldn't be allowed */ + conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, NULL, NULL, "http://deny.aspl.es"); + + /* wait a bit 100ms */ + nopoll_sleep (100000); + + if (nopoll_conn_is_ready (conn)) { + printf ("ERROR: Expected a FAILING connection status due to origing denied, but it working..\n"); + return nopoll_false; + } /* end if */ + + /* finish connection */ + nopoll_conn_close (conn); + + /* finish */ + nopoll_ctx_unref (ctx); + + return nopoll_true; +} + +nopoll_bool test_11 (void) { + + noPollCtx * ctx; + noPollConn * conn; + + /* reinit again */ + ctx = create_ctx (); + + /* create a working connection */ + conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, NULL, NULL, NULL); + + if (! nopoll_conn_wait_until_connection_ready (conn, 5)) { + printf ("ERROR: Expected a FAILING connection status due to origing denied, but it working..\n"); + return nopoll_false; + } /* end if */ + + /* finish */ + nopoll_ctx_unref (ctx); + + /* finish connection */ + nopoll_conn_close (conn); + + return nopoll_true; +} + +nopoll_bool test_12 (void) { + + noPollCtx * ctx; + noPollConn * conn; + int iterator; + + /* time tracking */ + struct timeval start; + struct timeval stop; + struct timeval diff; + + + /* reinit again */ + ctx = create_ctx (); + + /* start */ +#if defined(NOPOLL_OS_WIN32) + nopoll_win32_gettimeofday (&start, NULL); +#else + gettimeofday (&start, NULL); +#endif + + printf ("Test 12: creating 1000 connections...\n"); + iterator = 0; + while (iterator < 1000) { + /* create a working connection */ + conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, NULL, NULL, NULL); + + if (! nopoll_conn_wait_until_connection_ready (conn, 5)) { + printf ("ERROR: Expected NOT to find a FAILING connection status, errno is=%d..\n", errno); + return nopoll_false; + } /* end if */ + + /* finish connection */ + nopoll_conn_close (conn); + + iterator++; + } /* end while */ + + /* finish */ + nopoll_ctx_unref (ctx); + + /* stop */ +#if defined(NOPOLL_OS_UNIX) + gettimeofday (&stop, NULL); +#else + nopoll_win32_gettimeofday (&stop, NULL); +#endif + + nopoll_timeval_substract (&stop, &start, &diff); + + printf ("Test 12: created %d connections in %ld.%ld secs\n", + iterator, diff.tv_sec, diff.tv_usec); + + + return nopoll_true; +} + +nopoll_bool test_13_test (noPollCtx * ctx, const char * serverName, const char * _certificateFile, const char * _privateKey) +{ + const char * certificateFile; + const char * privateKey; + + if (! nopoll_ctx_find_certificate (ctx, serverName, NULL, NULL, NULL)) { + printf ("Test 13: it SHOULD find something about found.server.com but function reported failure status..\n"); + return nopoll_false; + } + + if (! nopoll_ctx_find_certificate (ctx, serverName, &certificateFile, &privateKey, NULL)) { + printf ("Test 13: it SHOULD find something about found.server.com but function reported failure status..\n"); + return nopoll_false; + } + + if (! nopoll_cmp (certificateFile, _certificateFile)) { + printf ("Test 13: expected to find certificate %s, but found %s\n", _certificateFile, certificateFile); + return nopoll_false; + } + if (! nopoll_cmp (privateKey, _privateKey)) { + printf ("Test 13: expected to find certificate %s, but found %s\n", _privateKey, privateKey); + return nopoll_false; + } + return nopoll_true; +} + +nopoll_bool test_13 (void) +{ + noPollCtx * ctx; + + /* create ctx */ + ctx = nopoll_ctx_new (); + + if (nopoll_ctx_find_certificate (ctx, "not-found", NULL, NULL, NULL)) { + printf ("Test 13: it shouldn't find anything but function reported ok status..\n"); + return nopoll_false; + } + + /* register */ + if (! nopoll_ctx_set_certificate (ctx, "found.server.com", "test.crt", "test.key", NULL)) { + printf ("Test 13: unable to install certificate...\n"); + return nopoll_false; + } /* end if */ + + if (! test_13_test (ctx, "found.server.com", "test.crt", "test.key")) + return nopoll_false; + + /* register */ + if (! nopoll_ctx_set_certificate (ctx, "another.server.com", "another.test.crt", "another.test.key", NULL)) { + printf ("Test 13: unable to install certificate (another.server.com)...\n"); + return nopoll_false; + } /* end if */ + + + if (! test_13_test (ctx, "found.server.com", "test.crt", "test.key")) + return nopoll_false; + + if (! test_13_test (ctx, "another.server.com", "another.test.crt", "another.test.key")) + return nopoll_false; + + /* register */ + if (! nopoll_ctx_set_certificate (ctx, "other.server.com", "other.test.crt", "other.test.key", NULL)) { + printf ("Test 13: unable to install certificate (another.server.com)...\n"); + return nopoll_false; + } /* end if */ + + if (! test_13_test (ctx, "found.server.com", "test.crt", "test.key")) + return nopoll_false; + + if (! test_13_test (ctx, "another.server.com", "another.test.crt", "another.test.key")) + return nopoll_false; + + if (! test_13_test (ctx, "other.server.com", "other.test.crt", "other.test.key")) + return nopoll_false; + + /* release ctx */ + nopoll_ctx_unref (ctx); + + return nopoll_true; +} + +nopoll_bool test_14 (void) { + noPollCtx * ctx; + noPollConn * conn; + noPollMsg * msg; + int iter; + + /* create context */ + ctx = create_ctx (); + + /* check connections registered */ + if (nopoll_ctx_conns (ctx) != 0) { + printf ("ERROR: expected to find 0 registered connections but found: %d\n", nopoll_ctx_conns (ctx)); + return nopoll_false; + } /* end if */ + + nopoll_ctx_unref (ctx); + + /* reinit again */ + ctx = create_ctx (); + + /* call to create a connection */ + conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } + + printf ("Test 14: sending partial frames (Hel..)..\n"); + if (nopoll_conn_send_text_fragment (conn, "Hel", 3) != 3) { + printf ("ERROR: expected to be able to send Hel frame..\n"); + return nopoll_false; + } + printf ("Test 14: sending completing frame (..lo)..\n"); + if (nopoll_conn_send_text (conn, "lo", 2) != 2) { + printf ("ERROR: expected to be able to send lo completion frame..\n"); + return nopoll_false; + } + + /* wait for the reply */ + iter = 0; + while ((msg = nopoll_conn_get_msg (conn)) == NULL) { + + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: received websocket connection close during wait reply..\n"); + return nopoll_false; + } + + nopoll_sleep (10000); + + if (iter > 10) + break; + } /* end if */ + + /* check content received */ + if (! nopoll_cmp ((char*) nopoll_msg_get_payload (msg), "Hello")) { + printf ("ERROR: expected to find message 'This is a test' but something different was received: '%s'..\n", + (const char *) nopoll_msg_get_payload (msg)); + return nopoll_false; + } /* end if */ + + /* unref message */ + nopoll_msg_unref (msg); + + /* finish connection */ + nopoll_conn_close (conn); + + /* finish */ + nopoll_ctx_unref (ctx); + + return nopoll_true; +} + +nopoll_bool test_15 (void) { + noPollCtx * ctx; + noPollConn * conn; + + /* create context */ + ctx = create_ctx (); + + /* check connections registered */ + if (nopoll_ctx_conns (ctx) != 0) { + printf ("ERROR: expected to find 0 registered connections but found: %d\n", nopoll_ctx_conns (ctx)); + return nopoll_false; + } /* end if */ + + nopoll_ctx_unref (ctx); + + /* reinit again */ + ctx = create_ctx (); + + /* call to create a connection */ + conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } + + /* wait for the reply */ + while (nopoll_true) { + if (nopoll_conn_is_ready (conn)) + break; + printf ("Test 15: not ready yet..\n"); + nopoll_sleep (10000); + } /* end if */ + + printf ("Test 15: setting non-blocking state..\n"); + + if (! nopoll_conn_set_sock_block (nopoll_conn_socket (conn), nopoll_false)) { + printf ("ERROR: failed to configure non-blocking state to connection..\n"); + return nopoll_false; + } /* end if */ + + printf ("Test 15: attempting to read content..\n"); + + /* wait for the reply */ + if (nopoll_conn_get_msg (conn)) { + printf ("ERROR (1): expected to not be able to find a message..\n"); + return nopoll_false; + } + if (nopoll_conn_get_msg (conn)) { + printf ("ERROR (2): expected to not be able to find a message..\n"); + return nopoll_false; + } + if (nopoll_conn_get_msg (conn)) { + printf ("ERROR (3): expected to not be able to find a message..\n"); + return nopoll_false; + } + + printf ("Test 15: reads finished..\n"); + + /* check connection state */ + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: expected to find connection state ok, but failure found..\n"); + return nopoll_false; + } /* end if */ + + /* finish connection */ + nopoll_conn_close (conn); + + /* finish */ + nopoll_ctx_unref (ctx); + + return nopoll_true; +} + +nopoll_bool test_16 (void) { + noPollCtx * ctx; + noPollConn * conn; + int iterator; + + /* create context */ + ctx = create_ctx (); + + /* check connections registered */ + if (nopoll_ctx_conns (ctx) != 0) { + printf ("ERROR: expected to find 0 registered connections but found: %d\n", nopoll_ctx_conns (ctx)); + return nopoll_false; + } /* end if */ + + nopoll_ctx_unref (ctx); + + /* reinit again */ + ctx = create_ctx (); + + /* call to create a connection */ + conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } + + /* wait for the reply */ + while (nopoll_true) { + if (nopoll_conn_is_ready (conn)) + break; + printf ("Test 16: not ready yet..\n"); + nopoll_sleep (10000); + } /* end if */ + + iterator = 0; + while (iterator < 10) { + printf ("Test 16: send sleep in header content (waiting 1000 ms, iterator=%d)..\n", iterator); + if (__nopoll_conn_send_common (conn, "This is a test", 14, nopoll_true, 400000, NOPOLL_TEXT_FRAME) != 14) { + printf ("ERROR: failed to send content..\n"); + return nopoll_false; + } /* end if */ + + iterator++; + } /* end while */ + + printf ("Test 16: sends finished, now checking connection ..\n"); + + nopoll_sleep (100000); + + /* check connection state */ + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: expected to find connection state ok, but failure found..\n"); + return nopoll_false; + } /* end if */ + + /* finish connection */ + nopoll_conn_close (conn); + + /* finish */ + nopoll_ctx_unref (ctx); + + return nopoll_true; +} + +nopoll_bool test_17_send_and_receive_test (noPollCtx * ctx, noPollConn * conn, noPollConn * listener, + const char * message, int length, nopoll_bool read_in_the_middle, + nopoll_bool read_after_header, nopoll_bool read_after_mask) +{ + char buffer[1024]; + char buffer2[1024]; + NOPOLL_SOCKET _socket; + char mask[4]; + int desp; + + memset (buffer, 0, 1024); + + /* make it unblock */ + nopoll_conn_set_sock_block (nopoll_conn_socket (listener), nopoll_false); + + /* now send partial content */ + printf ("Test 17: sending normal message to test link..\n"); + if (nopoll_conn_send_text (conn, message, length) != length) { + printf ("ERROR: expected to properly send all bytes but it wasn't possible..\n"); + return nopoll_false; + } /* end if */ + + /* read reply */ + if (nopoll_conn_read (listener, buffer, length, nopoll_true, 0) != length) { + printf ("ERROR: expected read 22 bytes ...but there was a failure..\n"); + return nopoll_false; + } /* end if */ + + /* printf ("Test 17: sending partial content..\n"); */ + _socket = nopoll_conn_socket (conn); + buffer[0] = 129; + buffer[1] = 150; + send (_socket, buffer, 2, 0); + + if (read_after_header) { + nopoll_sleep (1000000); + printf ("Test 17: Reading after header..\n"); + nopoll_conn_read (listener, buffer2, length, nopoll_false, 0); + } + + /* send mask */ + mask[0] = 23; + mask[1] = 24; + mask[2] = 25; + mask[3] = 26; + send (_socket, mask, 4, 0); + + if (read_after_mask) { + nopoll_sleep (1000000); + printf ("Test 17: Reading after mask..\n"); + nopoll_conn_read (listener, buffer2, length, nopoll_false, 0); + } + + memcpy (buffer, message, length); + nopoll_conn_mask_content (ctx, buffer, length, mask, 0); + + send (_socket, buffer, 10, 0); + printf ("Test 17: sent partial content...wait a bit (2 seconds)..\n"); + nopoll_sleep (2000000); + + desp = 0; + if (read_in_the_middle) { + printf ("Test 17: reading in the middle (10 bytes)\n"); + memset (buffer2, 0, 100); + desp = nopoll_conn_read (listener, buffer2, length, nopoll_false, 0); + if (desp != 10) { + printf ("Test 17: failed to read some initial content (10), found %d bytes..\n", desp); + return nopoll_false; + } /* end if */ + + printf ("Test 17: read %d bytes..\n", desp); + } + + printf ("Test 17: now send the rest..\n"); + send (_socket, buffer + 10, length - 10, 0); + + /* copy content into original buffer */ + if (read_in_the_middle) + memcpy (buffer, buffer2, desp); + + printf ("Test 17: now read the content received..\n"); + /* now read the content */ + if (nopoll_conn_read (listener, buffer + desp, length - desp, nopoll_true, 0) != (length - desp)) { + printf ("ERROR: expected to receive 22 bytes but found something different..\n"); + return nopoll_false; + } /* end if */ + + if (! nopoll_ncmp (buffer, message, length)) { + printf ("ERROR: expected to receive test message but found: '%s'\n", buffer); + return nopoll_false; + } + + return nopoll_true; +} + +nopoll_bool test_17 (void) { + + noPollCtx * ctx; + noPollConn * conn; + noPollConn * listener, * master; + + /* reinit again */ + ctx = create_ctx (); + + /* create a listener */ + master = nopoll_listener_new (ctx, "0.0.0.0", "22351"); + printf ("Test 17: created master listener (conn-id=%d, status=%d)\n", + nopoll_conn_get_id (master), nopoll_conn_is_ok (master)); + if (! nopoll_conn_is_ok (master)) { + printf ("ERROR: expected proper master listener at 0.0.0.0:2235 creation but a failure was found..\n"); + return nopoll_false; + } /* end if */ + + /* call to create a connection */ + conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } /* end if */ + + + /* wait for the reply */ + printf ("Test 17: accepting listener..\n"); + listener = nopoll_conn_accept (ctx, master); + + if (! nopoll_conn_is_ok (listener)) { + printf ("ERROR: expected to find proper listener status (connection accepted), but found failure..\n"); + return nopoll_false; + } /* end if */ + + /** call test here **/ + if (! test_17_send_and_receive_test (ctx, conn, listener, "This is a test message", 22, + /* read in the middle */ + nopoll_false, + /* read after the header */ + nopoll_false, + /* read after the mask */ + nopoll_false)) + return nopoll_false; + + /** call test here **/ + if (! test_17_send_and_receive_test (ctx, conn, listener, "This is a test message", 22, + /* read in the middle */ + nopoll_true, + /* read after the header */ + nopoll_false, + /* read after the mask */ + nopoll_false)) + return nopoll_false; + + /** call test here **/ + if (! test_17_send_and_receive_test (ctx, conn, listener, "This is a test message", 22, + /* read in the middle */ + nopoll_false, + /* read after the header */ + nopoll_true, + /* read after the mask */ + nopoll_false)) + return nopoll_false; + + /** call test here **/ + if (! test_17_send_and_receive_test (ctx, conn, listener, "This is a test message", 22, + /* read in the middle */ + nopoll_false, + /* read after the header */ + nopoll_false, + /* read after the mask */ + nopoll_true)) + return nopoll_false; + + printf ("Test 17: closing connections..\n"); + nopoll_conn_close (listener); + nopoll_conn_close (master); + nopoll_conn_close (conn); + + printf ("Test 17: finishing context..\n"); + + /* finish */ + nopoll_ctx_unref (ctx); + + /* report finish */ + return nopoll_true; +} + +nopoll_bool test_18 (void) { + + noPollCtx * ctx; + noPollConn * conn; + noPollConnOpts * opts; + + /* reinit again */ + ctx = create_ctx (); + + /* disable verification */ + opts = nopoll_conn_opts_new (); + nopoll_conn_opts_ssl_peer_verify (opts, nopoll_false); + + /* call to create a connection */ + conn = nopoll_conn_tls_new (ctx, opts, local_host_name, local_host_ports, NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } + + printf ("Test 18: waiting on nopoll_loop_wait (1 seconds)...\n"); + nopoll_loop_wait (ctx, 1); + printf ("Test 18: waiting on nopoll_loop_wait (1 seconds)...\n"); + nopoll_loop_wait (ctx, 1); + + /* finish connection */ + nopoll_conn_close (conn); + + /* finish */ + nopoll_ctx_unref (ctx); + + /* report finish */ + return nopoll_true; +} + +nopoll_bool test_19 (void) { + + noPollCtx * ctx; + noPollConn * conn; + noPollConnOpts * opts; + + /* reinit again */ + ctx = create_ctx (); + + printf ("Test 19: testing SSLv23 connection...\n"); + + /* create options */ + opts = nopoll_conn_opts_new (); + nopoll_conn_opts_set_ssl_protocol (opts, NOPOLL_METHOD_SSLV23); + + /* create connection */ + conn = nopoll_conn_tls_new (ctx, opts, local_host_name, local_host_ports, NULL, NULL, NULL, NULL); + + /* check connection */ + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: failed to start listener connection..\n"); + return nopoll_false; + } /* end if */ + + if (! test_sending_and_check_echo (conn, "Test 19", "This is a test...checking SSL with different values...")) + return nopoll_false; + + /* finish connection */ + nopoll_conn_close (conn); + + printf ("Test 19: testing SSLv23 connection with TLSv1 server...\n"); + + /* create options */ + opts = nopoll_conn_opts_new (); + nopoll_conn_opts_set_ssl_protocol (opts, NOPOLL_METHOD_SSLV23); + + /* create connection */ + conn = nopoll_conn_tls_new (ctx, opts, local_host_name, local_host_ports, NULL, NULL, NULL, NULL); + + /* check connection */ + if (! nopoll_conn_is_ok (conn)) { + printf ("WARNING: failed to create connection (2)..unable to connect to TLSv1 server with NOPOLL_METHOD_SSLV23\n"); + } else { + if (! test_sending_and_check_echo (conn, "Test 19", "This is a test...checking SSL with different values...")) + return nopoll_false; + } /* end if */ + + nopoll_conn_close (conn); + + printf ("Test 19: perfect, got it working..\n"); + + /* create options */ + opts = nopoll_conn_opts_new (); + nopoll_conn_opts_set_ssl_protocol (opts, NOPOLL_METHOD_SSLV3); + + /* create connection */ + printf ("Test 19: checking SSLv3 with TLSv1..\n"); + conn = nopoll_conn_tls_new (ctx, opts, local_host_name, local_host_ports, NULL, NULL, NULL, NULL); + + /* check connection */ + if (nopoll_conn_is_ok (conn)) { + printf ("ERROR: expected a connection failure..\n"); + return nopoll_false; + } /* end if */ + printf (" ... it does not work, but this is expected..\n"); + + nopoll_conn_close (conn); + + /* finish */ + nopoll_ctx_unref (ctx); + + /* report finish */ + return nopoll_true; +} + +#if defined(__NOPOLL_PTHREAD_SUPPORT__) +nopoll_bool test_20 (void) { + + noPollPtr * mutex; + int iterator = 0; + + + while (iterator < 10) { + /* call to create mutex */ + mutex = __nopoll_regtest_mutex_create (); + if (mutex == NULL) + return nopoll_false; + + /* call to lock */ + __nopoll_regtest_mutex_lock (mutex); + __nopoll_regtest_mutex_unlock (mutex); + + /* call to destroy */ + __nopoll_regtest_mutex_destroy (mutex); + + /* next operation */ + iterator++; + } + + return nopoll_true; +} +#endif + +/* + * Use gen-certificates-test-21.sh to rebuild certificates. + * Reg test to check client auth certificate. + */ +nopoll_bool test_21 (void) { + + noPollCtx * ctx; + noPollConn * conn; + noPollConnOpts * opts; + + /* reinit again */ + ctx = create_ctx (); + + /* call to create a connection */ + printf ("Test 21: check ssl connection (with auth certificate)..\n"); + conn = nopoll_conn_tls_new (ctx, NULL, local_host_name, local_host_ports, NULL, NULL, NULL, NULL); + if (nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to FAILURE client connection status, but ok..\n"); + return nopoll_false; + } + nopoll_conn_close (conn); + + /* try again configuring conection certificates */ + printf ("Test 21: checking to connect again with client provided certificates..\n"); + opts = nopoll_conn_opts_new (); + nopoll_conn_opts_set_ssl_certs (opts, + /* certificate */ + "client.pem", + /* private key */ + "client.pem", + NULL, + /* ca certificate */ + "root.pem"); + conn = nopoll_conn_tls_new (ctx, opts, local_host_name, local_host_ports, NULL, NULL, NULL, NULL); + if (! test_sending_and_check_echo (conn, "Test 21", "This is a test")) { + printf ("ERROR: it should WORK, client certificate isn't working..\n"); + return nopoll_false; + } /* end if */ + + /* finish connection */ + nopoll_conn_close (conn); + + /* finish */ + nopoll_ctx_unref (ctx); + + return nopoll_true; +} + + +nopoll_bool __test_22_on_close_signal = nopoll_false; + +void __test_22_on_close (noPollCtx * ctx, noPollConn * conn, noPollPtr user_data) +{ + printf ("Test --: called on connection close for conn-id=%d\n", nopoll_conn_get_id (conn)); + __test_22_on_close_signal = nopoll_true; + + return; +} + +nopoll_bool test_22 (void) { + + noPollCtx * ctx; + noPollConn * conn; + NOPOLL_SOCKET _socket; + noPollMsg * msg; + noPollConnOpts * opts; + + printf ("Test 22: testing connection close notification for regular connections (client side)..\n"); + + /* init context */ + ctx = create_ctx (); + + /* create connection */ + conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } + + /* set connection close */ + nopoll_conn_set_on_close (conn, __test_22_on_close, NULL); + + /* call to close connection as we had lost the connection */ + _socket = nopoll_conn_socket (conn); + nopoll_close_socket (_socket); + + /* call to get content (we shouldn't get anythign) */ + msg = nopoll_conn_get_msg (conn); + if (msg) { + printf ("ERROR: we shouldn't get a msg frame, but a well defined pointer was found..\n"); + return nopoll_false; + } /* end if */ + + if (nopoll_conn_is_ok (conn)) { + printf ("ERROR: we shouldn't get an ok value from nopoll_conn_is_ok (conn)..\n"); + return nopoll_false; + } /* end if */ + + if (! __test_22_on_close_signal) { + printf ("ERROR: connection close should've been called but it wasn't..\n"); + return nopoll_false; + } /* end if */ + + /* close the connection */ + nopoll_conn_close (conn); + + __test_22_on_close_signal = nopoll_false; + printf ("Test 22: test close connection close notification for WSS:// (ssl connections), (client side)..\n"); + + /* disable verification */ + opts = nopoll_conn_opts_new (); + nopoll_conn_opts_ssl_peer_verify (opts, nopoll_false); + + /* call to create a connection */ + conn = nopoll_conn_tls_new (ctx, opts, local_host_name, local_host_ports, NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } + + /* set connection close */ + nopoll_conn_set_on_close (conn, __test_22_on_close, NULL); + + /* call to close connection as we had lost the connection */ + _socket = nopoll_conn_socket (conn); + nopoll_close_socket (_socket); + + /* call to get content (we shouldn't get anythign) */ + msg = nopoll_conn_get_msg (conn); + if (msg) { + printf ("ERROR: we shouldn't get a msg frame, but a well defined pointer was found..\n"); + return nopoll_false; + } /* end if */ + + if (nopoll_conn_is_ok (conn)) { + printf ("ERROR: we shouldn't get an ok value from nopoll_conn_is_ok (conn)..\n"); + return nopoll_false; + } /* end if */ + + if (! __test_22_on_close_signal) { + printf ("ERROR: connection close should've been called but it wasn't..\n"); + return nopoll_false; + } /* end if */ + + /* close the connection */ + nopoll_conn_close (conn); + + + nopoll_ctx_unref (ctx); + return nopoll_true; +} /* end if */ + +int test_23_get_connection_close_count (noPollCtx * ctx, noPollConn * conn) { + + int count_before_closing; + noPollMsg * msg; + + /* wait for the reply */ + while (nopoll_true) { + if (nopoll_conn_is_ready (conn)) + break; + nopoll_sleep (10000); + } /* end if */ + + /* send package to get number of connection close detected */ + if (nopoll_conn_send_text (conn, "get-connection-close-count", 26) != 26) { + printf ("ERROR: Expected to find proper send operation..\n"); + return nopoll_false; + } + + /* call to get content (we shouldn't get anythign) */ + while (nopoll_true) { + msg = nopoll_conn_get_msg (conn); + if (msg) + break; + + nopoll_sleep (10000); + } /* end if */ + + + count_before_closing = strtol ((const char *) nopoll_msg_get_payload (msg), NULL, 10); + printf ("Test 23: Message received: %d..\n", count_before_closing); + /* release message */ + nopoll_msg_unref (msg); + + return count_before_closing; +} + +nopoll_bool test_23 (void) { + + noPollCtx * ctx; + noPollConn * conn; + int count_before_closing; + int count_before_closing2; + noPollConnOpts * opts; + + printf ("Test 23: testing connection close notification for regular connections (client side)..\n"); + + /* init context */ + ctx = create_ctx (); + + /* create connection */ + conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } + + /* get connection close before closing */ + if ((count_before_closing = test_23_get_connection_close_count (ctx, conn)) == -1) + return nopoll_false; + printf ("Test 23: current connection close is: %d\n", count_before_closing); + + /* close the connection cleanly and check connection close is not called */ + nopoll_conn_close (conn); + + /* create connection */ + conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } + + if ((count_before_closing2 = test_23_get_connection_close_count (ctx, conn)) == -1) + return nopoll_false; + printf ("Test 23: current connection close is: %d\n", count_before_closing2); + + if (count_before_closing == count_before_closing2) { + printf ("ERROR: expected connection close notification ...but same values were found..\n"); + return nopoll_false; + } /* end if */ + + /* close the connection cleanly and check connection close is not called */ + nopoll_conn_close (conn); + + printf ("Test 23: now test TLS connections connection close..\n"); + + /* disable verification */ + opts = nopoll_conn_opts_new (); + nopoll_conn_opts_ssl_peer_verify (opts, nopoll_false); + + /* call to create a connection */ + conn = nopoll_conn_tls_new (ctx, opts, local_host_name, local_host_ports, NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } + + /* get connection close before closing */ + if ((count_before_closing = test_23_get_connection_close_count (ctx, conn)) == -1) + return nopoll_false; + + /* close the connection */ + nopoll_conn_close (conn); + + /* call to create a connection second connection */ + opts = nopoll_conn_opts_new (); + nopoll_conn_opts_ssl_peer_verify (opts, nopoll_false); + conn = nopoll_conn_tls_new (ctx, opts, local_host_name, local_host_ports, NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } + + if ((count_before_closing2 = test_23_get_connection_close_count (ctx, conn)) == -1) + return nopoll_false; + + /* close the connection */ + nopoll_conn_close (conn); + + if (count_before_closing == count_before_closing2) { + printf ("ERROR: expected connection close notification ...but same values were found..\n"); + return nopoll_false; + } /* end if */ + + nopoll_ctx_unref (ctx); + return nopoll_true; +} /* end if */ + +nopoll_bool test_24 (void) { + + noPollCtx * ctx; + noPollConn * conn; + noPollConnOpts * opts; + noPollMsg * msg; + + printf ("Test 24: test cookie support (set client and receive on server..)\n"); + + /* init context */ + ctx = create_ctx (); + + /* configure cookie */ + opts = nopoll_conn_opts_new (); + nopoll_conn_opts_set_cookie (opts, "theme=light; sessionToken=abc123"); + + /* create connection */ + conn = nopoll_conn_new_opts (ctx, opts, local_host_name, local_host_port, NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } + + /* send package to get number of connection close detected */ + if (nopoll_conn_send_text (conn, "get-cookie", 10) != 10) { + printf ("ERROR: Expected to find proper send operation..\n"); + return nopoll_false; + } + + /* call to get content (we shouldn't get anythign) */ + while (nopoll_true) { + msg = nopoll_conn_get_msg (conn); + if (msg) + break; + + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: connection failure found during message wait..\n"); + return nopoll_false; + } + + nopoll_sleep (10000); + } /* end if */ + + printf ("Test 24: received header set on server side: %s\n", nopoll_msg_get_payload (msg)); + if (! nopoll_cmp ((const char *) nopoll_msg_get_payload (msg), "theme=light; sessionToken=abc123")) { + printf ("ERROR: expected to receive different header, error was: %s\n", nopoll_msg_get_payload (msg)); + return nopoll_false; + } + + /* release message */ + nopoll_msg_unref (msg); + + + /* close the connection */ + nopoll_conn_close (conn); + + + nopoll_ctx_unref (ctx); + return nopoll_true; +} /* end if */ + +nopoll_bool test_25_check_cookie (noPollCtx * ctx, const char * cookie) { + noPollConn * conn; + noPollConnOpts * opts; + + /* configure cookie */ + opts = nopoll_conn_opts_new (); + + /* set a cookie bigger than 1044 */ + nopoll_conn_opts_set_cookie (opts, cookie); + + /* create connection */ + conn = nopoll_conn_new_opts (ctx, opts, local_host_name, local_host_port, NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } + + + /* close the connection */ + nopoll_conn_close (conn); + + return nopoll_true; +} + +nopoll_bool test_25 (void) { + + noPollCtx * ctx; + + printf ("Test 25: test cookie support (set client and receive on server..)\n"); + + /* init context */ + ctx = create_ctx (); + + if (! test_25_check_cookie (ctx, "theme=light; sessionToken=abc123 lkjsadfkljasdf lkjaseflkawjet klajw glkajy240u 4234lkj y3j 3q5yñkl aegar glkejry b theme=light; sessionToken=abc123 lkjsadfkljasdf lkjaseflkawjet klajw glkajy240u 4234lkj y3j 3q5yñkl aegar glkejry b theme=light; sessionToken=abc123 lkjsadfkljasdf lkjaseflkawjet klajw glkajy240u 4234lkj y3j 3q5yñkl aegar glkejry b theme=light; sessionToken=abc123 lkjsadfkljasdf lkjaseflkawjet klajw glkajy240u 4234lkj y3j 3q5yñkl aegar glkejry b theme=light; sessionToken=abc123 lkjsadfkljasdf lkjaseflkawjet klajw glkajy240u 4234lkj y3j 3q5yñkl aegar glkejry b theme=light; sessionToken=abc123 lkjsadfkljasdf lkjaseflkawjet klajw glkajy240u 4234lkj y3j 3q5yñkl aegar glkejry b theme=light; sessionToken=abc123 lkjsadfkljasdf lkjaseflkawjet klajw glkajy240u 4234lkj y3j 3q5yñkl aegar glkejry b theme=light; sessionToken=abc123 lkjsadfkljasdf lkjaseflkawjet klajw glkajy240u 4234lkj y3j 3q5yñkl aegar glkejry b theme=light; sessionToken=abc123 lkjsadfkljasdf lkjaseflkawjet klajw glkajy240u 4234lkj y3j 3q5yñkl aegar glkejry b ")) + return nopoll_false; + + + if (! test_25_check_cookie (ctx, "222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444asd35555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555affffffffff-23345")) + return nopoll_false; + + if (! test_25_check_cookie (ctx, "222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444asd35555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555affffffffff-233")) + return nopoll_false; + + if (! test_25_check_cookie (ctx, "222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444asd35555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555afffffff")) + return nopoll_false; + + if (! test_25_check_cookie (ctx, "22222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444222222222222222222222211111111111111111111111133333333333333333333333334444444444444444444444444asd35555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555afffffff")) + return nopoll_false; + + nopoll_ctx_unref (ctx); + return nopoll_true; +} /* end if */ + +nopoll_bool test_26 (void) { + + noPollConn * conn; + noPollCtx * ctx; + + /* init context */ + ctx = create_ctx (); + + /* create connection */ + conn = nopoll_conn_new (ctx, "echo.websocket.org", "80", NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } /* end if */ + + /* check test */ + if (! test_sending_and_check_echo (conn, "Test 26", "This is a test")) + return nopoll_false; + + /* close the connection */ + nopoll_conn_close (conn); + + /* release context */ + nopoll_ctx_unref (ctx); + + return nopoll_true; +} + +nopoll_bool test_27 (void) { + + noPollConn * conn; + noPollCtx * ctx; + + /* init context */ + ctx = create_ctx (); + + /* create connection */ + conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, "/", "chat-protocol", "http://www.aspl.es"); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } /* end if */ + + /* check test */ + if (! test_sending_and_check_echo (conn, "Test 27", "This is a test")) + return nopoll_false; + + /* check accepted protocol */ + if (! nopoll_cmp ("chat-protocol", nopoll_conn_get_accepted_protocol (conn))) { + printf ("ERROR: expected to find [chat-protocol] but found something: %s\n", + nopoll_conn_get_accepted_protocol (conn)); + return nopoll_false; + } /* end if */ + + printf ("Test 27: accepted protocol by the server: %s\n", nopoll_conn_get_accepted_protocol (conn)); + + /* close the connection */ + nopoll_conn_close (conn); + + /* create connection */ + conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, "/", "hello-protocol", "http://www.aspl.es"); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } /* end if */ + + /* check test */ + if (! test_sending_and_check_echo (conn, "Test 27", "This is a test")) + return nopoll_false; + + /* check accepted protocol */ + if (! nopoll_cmp ("hello-protocol-response", nopoll_conn_get_accepted_protocol (conn))) { + printf ("ERROR: expected to find [chat-protocol] but found something: %s\n", + nopoll_conn_get_accepted_protocol (conn)); + return nopoll_false; + } /* end if */ + + printf ("Test 27: accepted protocol by the server: %s\n", nopoll_conn_get_accepted_protocol (conn)); + + /* close the connection */ + nopoll_conn_close (conn); + + + /* release context */ + nopoll_ctx_unref (ctx); + + return nopoll_true; +} + + +nopoll_bool test_28 (void) { + + noPollConn * conn; + noPollCtx * ctx; + noPollMsg * msg; + + /* init context */ + ctx = create_ctx (); + + /* create connection */ + conn = nopoll_conn_new (ctx, local_host_name, local_host_port, NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } /* end if */ + + /* wait until it is connected */ + nopoll_conn_wait_until_connection_ready (conn, 5); + + /* send a message to request connection close with a particular message */ + if (nopoll_conn_send_text (conn, "close with message", 18) != 18) { + printf ("ERROR: failed to send close with message.."); + return nopoll_false; + } /* end while */ + + /* wait for the reply */ + while ((msg = nopoll_conn_get_msg (conn)) == NULL) { + + if (! nopoll_conn_is_ok (conn)) { + /* connection was closed by remote side */ + break; + } /* end if */ + + nopoll_sleep (10000); + } /* end if */ + + printf ("Test 28: close reason received, statud=%d, message=%s\n", + nopoll_conn_get_close_status (conn), + nopoll_conn_get_close_reason (conn)); + if (nopoll_conn_get_close_status (conn) != 1048) { + printf ("ERROR: expected different error code..\n"); + return nopoll_false; + } + + if (! nopoll_cmp (nopoll_conn_get_close_reason (conn), "Hey, this is a very reasonable error message")) { + printf ("ERROR: expected different error message..\n"); + return nopoll_false; + } /* end if */ + + /* close connection */ + nopoll_conn_close (conn); + + /* release context */ + nopoll_ctx_unref (ctx); + + return nopoll_true; +} + +LOCAL int websocket_main (char *argv) +{ + int iterator = *argv; + + printf ("** NoPoll: Websocket toolkit (regression test).\n"); + printf ("** Copyright (C) 2013 Advanced Software Production Line, S.L.\n**\n"); + + printf ("** To gather information about time performance you can use:\n**\n"); + printf ("** >> time ./nopoll-regression-client [--debug,--show-critical-only]\n**\n"); + printf ("** To gather information about memory consumed (and leaks) use:\n**\n"); + printf ("** >> libtool --mode=execute valgrind --leak-check=yes --error-limit=no ./nopoll-regression-client\n**\n"); + printf ("**\n"); + printf ("** Report bugs to:\n**\n"); + printf ("** noPoll mailing list\n**\n"); + switch (iterator) { + case 1: + if (test_01_strings()) { + printf("Test 01-strings: Library strings support [ OK ]\n"); + } else { + printf("Test 01-strings: Library strings support [ FAILED ]\n"); + // return -1; + } + break; + case 2: + if (test_02()) { + printf("Test 02: Simple request/reply [ OK ]\n"); + } else { + printf("Test 02: Simple request/reply [ FAILED ]\n"); + // return -1; + } + + break; + case 3: + + /* test streaming api */ + if (test_03()) { + printf("Test 03: test streaming api [ OK ]\n"); + } else { + printf("Test 03: test streaming api [ FAILED ]\n"); + // return -1; + } + + break; + case 4: + if (test_04a()) { + printf( + "Test 04-a: check non-blocking streaming and message based API [ OK ]\n"); + } else { + printf( + "Test 04-a: check non-blocking streaming and message based API [ FAILED ]\n"); + // return -1; + } + + if (test_04b()) { + printf( + "Test 04-b: try to overflow write access and recover from it [ OK ]\n"); + } else { + printf( + "Test 04-b: try to overflow write access and recover from it [ FAILED ]\n"); + // return -1; + } + + break; + case 5: + if (test_05()) { + printf("Test 05: sending utf-8 content [ OK ]\n"); + } else { + printf("Test 05: sending utf-8 content [ FAILED ]\n"); + // return -1; + } + + break; + case 6: + if (test_06()) { + printf("Test 06: testing basic TLS connect [ OK ]\n"); + } else { + printf("Test 06: testing basic TLS connect [ FAILED ]\n"); + // return -1; + } + + break; + case 7: + if (test_07()) { + printf("Test 07: testing TLS request/reply [ OK ]\n"); + } else { + printf("Test 07: testing TLS request/reply [ FAILED ]\n"); + // return -1; + } + + break; + case 8: + if (test_08()) { + printf("Test 08: test normal connect to TLS port [ OK ]\n"); + } else { + printf("Test 08: test normal connect to TLS port [ FAILED ]\n"); + // return -1; + } + + break; + case 9: + if (test_09()) { + printf( + "Test 09: ensure we only support Sec-WebSocket-Version: 13 [ OK ]\n"); + } else { + printf( + "Test 09: ensure we only support Sec-WebSocket-Version: 13 [ FAILED ]\n"); + // return -1; + } + + break; + case 10: + if (test_10()) { + printf( + "Test 10: test checking origing in on open and denying it [ OK ]\n"); + } else { + printf( + "Test 10: test checking origing in on open and denying it [ FAILED ]\n"); + // return -1; + } + + break; + case 11: + if (test_11()) { + printf("Test 11: release context after connection [ OK ]\n"); + } else { + printf("Test 11: release context after connection [ FAILED ]\n"); + // return -1; + } + + break; + case 12: + if (test_12()) { + printf( + "Test 12: create huge amount of connections in a short time [ OK ]\n"); + } else { + printf( + "Test 12: create huge amount of connections in a short time [ FAILED ]\n"); + // return -1; + } + + break; + case 13: + if (test_13()) { + printf("Test 13: testing certificate storage [ OK ]\n"); + } else { + printf("Test 13: testing certificate storage [ FAILED ]\n"); + // return -1; + } + + break; + case 14: + if (test_14()) { + printf( + "Test 14: testing sending frame with few content as indicated by header [ OK ]\n"); + } else { + printf( + "Test 14: testing sending frame with few content as indicated by header [ FAILED ]\n"); + // return -1; + } + + break; + case 15: + if (test_15()) { + printf( + "Test 15: checking non-blocking calls to get messages when no content is available [ OK ]\n"); + } else { + printf( + "Test 15: checking non-blocking calls to get messages when no content is available [ FAILED ]\n"); + // return -1; + } + + break; + case 16: + if (test_16()) { + printf( + "Test 16: check sending frames with sleep in header [ OK ]\n"); + } else { + printf( + "Test 16: check sending frames with sleep in header [ FAILED ]\n"); + // return -1; + } + + break; + case 17: + if (test_17()) { + printf("Test 17: check partial frame reception [ OK ]\n"); + } else { + printf("Test 17: check partial frame reception [ FAILED ]\n"); + // return -1; + } + + break; + case 18: + if (test_18()) { + printf( + "Test 18: check nopoll_loop_wait (second call) [ OK ]\n"); + } else { + printf( + "Test 18: check nopoll_loop_wait (second call) [ FAILED ]\n"); + // return -1; + } + + break; + case 19: + if (test_19()) { + printf( + "Test 19: support different SSL methods (SSLv23, SSLv3, TLSv1 [ OK ]\n"); + } else { + printf( + "Test 19: support different SSL methods (SSLv23, SSLv3, TLSv1 [ FAILED ]\n"); + // return -1; + } + + break; + case 20: + #if defined(__NOPOLL_PTHREAD_SUPPORT__) + if (test_20 ()) { + printf ("Test 20: check mutex support [ OK ]\n"); + } else { + printf ("Test 20: check mutex support [ FAILED ]\n"); + return -1; + } + #endif + + break; + case 21: + if (test_21()) { + printf( + "Test 21: client side ssl certificates verification [ OK ]\n"); + } else { + printf( + "Test 21: client side ssl certificates verification [ FAILED ]\n"); + // return -1; + } /* end if */ + + break; + case 22: + if (test_22()) { + printf( + "Test 22: test connection close trigger (client side) [ OK ]\n"); + } else { + printf( + "Test 22: test connection close trigger (client side) [ FAILED ]\n"); + // return -1; + } /* end if */ + + break; + case 23: + if (test_23()) { + printf( + "Test 23: test connection close trigger (server side) [ OK ]\n"); + } else { + printf( + "Test 23: test connection close trigger (server side) [ FAILED ]\n"); + // return -1; + } /* end if */ + + break; + case 24: + if (test_24()) { + printf( + "Test 24: check cookie support (client and server side) [ OK ]\n"); + } else { + printf( + "Test 24: check cookie support (client and server side) [ FAILED ]\n"); + // return -1; + } /* end if */ + + break; + case 25: + if (test_25()) { + printf("Test 25: check cookie attack [ OK ]\n"); + } else { + printf("Test 25: check cookie attack [ FAILED ]\n"); + // return -1; + } /* end if */ + + break; + case 26: + if (test_26()) { + printf("Test 26: checking echo.websocket.org [ OK ]\n"); + } else { + printf("Test 26: chekcing echo.websocket.org [ FAILED ]\n"); + // return -1; + } /* end if */ + + break; + case 27: + if (test_27()) { + printf("Test 27: checking setting protocol [ OK ]\n"); + } else { + printf("Test 27: chekcing setting protocol [ FAILED ]\n"); + // return -1; + } /* end if */ + + break; + case 28: + if (test_28()) { + printf("Test 28: checking setting protocol [ OK ]\n"); + } else { + printf("Test 28: chekcing setting protocol [ FAILED ]\n"); + // return -1; + } /* end if */ + break; + + default: + break; + } +#if 0 + iterator = 1; +// while (iterator < argc) { + /* check for debug */ + printf ("Checking agument: %s\n", argv[iterator]); + if (nopoll_cmp (argv[iterator], "--debug")) { + printf ("Activating debug..\n"); + debug = nopoll_true; + } /* end if */ + if (nopoll_cmp (argv[iterator], "--show-critical-only")) { + printf ("Activating reporting of critical messages..\n"); + show_critical_only = nopoll_true; + } /* end if */ + + /* next position */ + iterator++; +// } + + //printf ("INFO: starting tests with pid: %d\n", getpid ()); + if (test_01_strings ()) { + printf ("Test 01-strings: Library strings support [ OK ]\n"); + } else { + printf ("Test 01-strings: Library strings support [ FAILED ]\n"); +// return -1; + } + + if (test_01_base64 ()) { + printf ("Test 01-bas64: Library bas64 support [ OK ]\n"); + }else { + printf ("Test 01-bas64: Library bas64 support [ FAILED ]\n"); +// return -1; + } + + if (test_01_masking ()) { + printf ("Test 01-masking: Library websocket content masking support [ OK ]\n"); + }else { + printf ("Test 01-masking: Library websocket content masking support [ FAILED ]\n"); +// return -1; + } + + if (test_01 ()) { + printf ("Test 01: Simple connect and disconnect [ OK ]\n"); + }else { + printf ("Test 01: Simple connect and disconnect [ FAILED ]\n"); +// return -1; + } + + if (test_02 ()) { + printf ("Test 02: Simple request/reply [ OK ]\n"); + }else { + printf ("Test 02: Simple request/reply [ FAILED ]\n"); +// return -1; + } + + /* test streaming api */ + if (test_03 ()) { + printf ("Test 03: test streaming api [ OK ]\n"); + }else { + printf ("Test 03: test streaming api [ FAILED ]\n"); +// return -1; + } + +// if (test_04 (1024)) { +// printf ("Test 04: test streaming api (II) [ OK ]\n"); +// }else { +// printf ("Test 04: test streaming api (II) [ FAILED ]\n"); +//// return -1; +// } + +// if (test_04 (512)) { +// printf ("Test 04-a: test streaming api (III) [ OK ]\n"); +// }else { +// printf ("Test 04-a: test streaming api (III) [ FAILED ]\n"); +//// return -1; +// } + +// if (test_04 (137)) { +// printf ("Test 04-b: test streaming api (IV) [ OK ]\n"); +// }else { +// printf ("Test 04-b: test streaming api (IV) [ FAILED ]\n"); +//// return -1; +// } +// +// if (test_04 (17)) { +// printf ("Test 04-c: test streaming api (V) [ OK ]\n"); +// }else { +// printf ("Test 04-c: test streaming api (V) [ FAILED ]\n"); +//// return -1; +// } + + if (test_04a ()) { + printf ("Test 04-a: check non-blocking streaming and message based API [ OK ]\n"); + } else { + printf ("Test 04-a: check non-blocking streaming and message based API [ FAILED ]\n"); +// return -1; + } + + if (test_04b ()) { + printf ("Test 04-b: try to overflow write access and recover from it [ OK ]\n"); + } else { + printf ("Test 04-b: try to overflow write access and recover from it [ FAILED ]\n"); +// return -1; + } + +// if (test_04c ()) { +// printf ("Test 04-c: send a file and try to overflow (but retry) [ OK ]\n"); +// } else { +// printf ("Test 04-c: send a file and try to overflow (but retry) [ FAILED ]\n"); +//// return -1; +// } + + if (test_05 ()) { + printf ("Test 05: sending utf-8 content [ OK ]\n"); + } else { + printf ("Test 05: sending utf-8 content [ FAILED ]\n"); +// return -1; + } + + if (test_06 ()) { + printf ("Test 06: testing basic TLS connect [ OK ]\n"); + } else { + printf ("Test 06: testing basic TLS connect [ FAILED ]\n"); +// return -1; + } + + if (test_07 ()) { + printf ("Test 07: testing TLS request/reply [ OK ]\n"); + } else { + printf ("Test 07: testing TLS request/reply [ FAILED ]\n"); +// return -1; + } + + if (test_08 ()) { + printf ("Test 08: test normal connect to TLS port [ OK ]\n"); + } else { + printf ("Test 08: test normal connect to TLS port [ FAILED ]\n"); +// return -1; + } + + if (test_09 ()) { + printf ("Test 09: ensure we only support Sec-WebSocket-Version: 13 [ OK ]\n"); + } else { + printf ("Test 09: ensure we only support Sec-WebSocket-Version: 13 [ FAILED ]\n"); +// return -1; + } + + if (test_10 ()) { + printf ("Test 10: test checking origing in on open and denying it [ OK ]\n"); + } else { + printf ("Test 10: test checking origing in on open and denying it [ FAILED ]\n"); +// return -1; + } + + if (test_11 ()) { + printf ("Test 11: release context after connection [ OK ]\n"); + } else { + printf ("Test 11: release context after connection [ FAILED ]\n"); +// return -1; + } + + if (test_12 ()) { + printf ("Test 12: create huge amount of connections in a short time [ OK ]\n"); + } else { + printf ("Test 12: create huge amount of connections in a short time [ FAILED ]\n"); +// return -1; + } + + if (test_13 ()) { + printf ("Test 13: testing certificate storage [ OK ]\n"); + } else { + printf ("Test 13: testing certificate storage [ FAILED ]\n"); +// return -1; + } + + if (test_14 ()) { + printf ("Test 14: testing sending frame with few content as indicated by header [ OK ]\n"); + } else { + printf ("Test 14: testing sending frame with few content as indicated by header [ FAILED ]\n"); +// return -1; + } + + if (test_15 ()) { + printf ("Test 15: checking non-blocking calls to get messages when no content is available [ OK ]\n"); + } else { + printf ("Test 15: checking non-blocking calls to get messages when no content is available [ FAILED ]\n"); +// return -1; + } + + if (test_16 ()) { + printf ("Test 16: check sending frames with sleep in header [ OK ]\n"); + } else { + printf ("Test 16: check sending frames with sleep in header [ FAILED ]\n"); +// return -1; + } + + if (test_17 ()) { + printf ("Test 17: check partial frame reception [ OK ]\n"); + } else { + printf ("Test 17: check partial frame reception [ FAILED ]\n"); +// return -1; + } + + if (test_18 ()) { + printf ("Test 18: check nopoll_loop_wait (second call) [ OK ]\n"); + } else { + printf ("Test 18: check nopoll_loop_wait (second call) [ FAILED ]\n"); +// return -1; + } + + if (test_19 ()) { + printf ("Test 19: support different SSL methods (SSLv23, SSLv3, TLSv1 [ OK ]\n"); + } else { + printf ("Test 19: support different SSL methods (SSLv23, SSLv3, TLSv1 [ FAILED ]\n"); +// return -1; + } + + #if defined(__NOPOLL_PTHREAD_SUPPORT__) + if (test_20 ()) { + printf ("Test 20: check mutex support [ OK ]\n"); + } else { + printf ("Test 20: check mutex support [ FAILED ]\n"); + return -1; + } + #endif + + if (test_21 ()) { + printf ("Test 21: client side ssl certificates verification [ OK ]\n"); + } else { + printf ("Test 21: client side ssl certificates verification [ FAILED ]\n"); +// return -1; + } /* end if */ + + if (test_22 ()) { + printf ("Test 22: test connection close trigger (client side) [ OK ]\n"); + } else { + printf ("Test 22: test connection close trigger (client side) [ FAILED ]\n"); +// return -1; + } /* end if */ + + if (test_23 ()) { + printf ("Test 23: test connection close trigger (server side) [ OK ]\n"); + } else { + printf ("Test 23: test connection close trigger (server side) [ FAILED ]\n"); +// return -1; + } /* end if */ + + if (test_24 ()) { + printf ("Test 24: check cookie support (client and server side) [ OK ]\n"); + } else { + printf ("Test 24: check cookie support (client and server side) [ FAILED ]\n"); +// return -1; + } /* end if */ + + if (test_25 ()) { + printf ("Test 25: check cookie attack [ OK ]\n"); + } else { + printf ("Test 25: check cookie attack [ FAILED ]\n"); +// return -1; + } /* end if */ + + if (test_26 ()) { + printf ("Test 26: checking echo.websocket.org [ OK ]\n"); + } else { + printf ("Test 26: chekcing echo.websocket.org [ FAILED ]\n"); +// return -1; + } /* end if */ + + if (test_27 ()) { + printf ("Test 27: checking setting protocol [ OK ]\n"); + } else { + printf ("Test 27: chekcing setting protocol [ FAILED ]\n"); +// return -1; + } /* end if */ + + if (test_28 ()) { + printf ("Test 28: checking setting protocol [ OK ]\n"); + } else { + printf ("Test 28: chekcing setting protocol [ FAILED ]\n"); +// return -1; + } /* end if */ + + /* add support to reply with redirect 301 to an opening + * request: page 19 and 22 */ + + /* add support for basic HTTP auth before proceding with the + * handshake. The the possibility to use htpasswd tools. Page 19 and 22 */ + + /* add support to define cookies by the server: page 20 */ + + /* update the library to split message frames into smaller + * complete frames when bigger messages are received. */ + + /* add support for proxy mode */ + + /* check control files aren't flagged as fragmented */ + + /* upload a file to the server ...*/ + + /* more streaming api testing, get bigger content as a + * consequence of receiving several messages */ + + /* test streaming API when it timeouts */ + + /* test sending wrong mime headers */ + + /* test sending missing mime headers */ + + /* test injecting wrong bytes */ + + /* test sending lot of MIME headers (really lot of + * information) */ + + /* test checking protocols and denying it */ + + /* test sending ping */ + + /* test sending pong (without ping) */ + + /* test sending frames 126 == ( 65536) */ + + /* test sending frames 127 == ( more than 65536) */ + + /* test applying limits to incoming content */ + + /* test splitting into several frames content bigger */ + + /* test wrong UTF-8 content received on text frames */ + + /* add support to sending close frames with status code and a + * textual indication as defined by page 36 */ +#endif + /* call to cleanup */ + nopoll_cleanup_library (); + printf ("All tests ok!!\n"); + + return 0; +} +LOCAL xQueueHandle Web_QueueStop = NULL; + +LOCAL void websocket_task(void *pvParameters) +{ + bool ValueFromReceive = false; + portBASE_TYPE xStatus; + websocket_main((char*)pvParameters); + + while (1) { + xStatus = xQueueReceive(Web_QueueStop,&ValueFromReceive,0); + if (xStatus == pdPASS && ValueFromReceive == true){ + printf("websocket_task exit signal\n"); + break; + } + vTaskDelay(200 / portTICK_RATE_MS); + printf("websocket_task\n"); + } + vQueueDelete(Web_QueueStop); + Web_QueueStop = NULL; + vTaskDelete(NULL); + printf("delete the websocket_task\n"); +} + +/*start the websocket task*/ +void websocket_start(void *optarg) +{ + if (Web_QueueStop == NULL) + Web_QueueStop = xQueueCreate(1,1); + + if (Web_QueueStop != NULL) + xTaskCreate(websocket_task, "websocket_task", 512, optarg, 4, NULL); +} + +/*stop the websocket task*/ +sint8 websocket_stop(void) +{ + bool ValueToSend = true; + portBASE_TYPE xStatus; + + if (Web_QueueStop == NULL) + return -1; + + xStatus = xQueueSend(Web_QueueStop,&ValueToSend,0); + if (xStatus != pdPASS) + return -1; + else + return pdPASS; +} +/* end-of-file-found */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll.c new file mode 100644 index 0000000..1fb8980 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll.c @@ -0,0 +1,1729 @@ +/* + * LibNoPoll: A websocket library + * Copyright (C) 2013 Advanced Software Production Line, S.L. + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * You may find a copy of the license under this software is released + * at COPYING file. This is LGPL software: you are welcome to develop + * proprietary applications using this library without any royalty or + * fee but returning back any change, improvement or addition in the + * form of source code, project image, documentation patches, etc. + * + * For commercial support on build Websocket enabled solutions + * contact us: + * + * Postal address: + * Advanced Software Production Line, S.L. + * Edificio Alius A, Oficina 102, + * C/ Antonio Suarez Nº 10, + * Alcalá de Henares 28802 Madrid + * Spain + * + * Email address: + * info@aspl.es - http://www.aspl.es/nopoll + */ +#include +#include +#include "freertos/FreeRTOS.h" + +/** + * \defgroup nopoll_support noPoll Support: core support functions used by the library + */ + +/** + * \addtogroup nopoll_support + * @{ + */ + +/** + * @brief Allows to check if provided strings are equal. + * + * @param string1 The first string to check. The string must be ended by 0. + * @param string2 The second string to check. The string must be ended by 0. + * + * @return nopoll_true if both strings are equal, otherwise + * nopoll_false is returned. + */ +nopoll_bool nopoll_cmp (const char * string1, const char * string2) +{ + int iterator; + if (string1 == NULL && string2 == NULL) + return nopoll_true; + if (string1 == NULL || string2 == NULL) + return nopoll_false; + + /* next position */ + iterator = 0; + while (string1[iterator] && string1[iterator]) { + if (string1[iterator] != string2[iterator]) + return nopoll_false; + iterator++; + } /* end while */ + + /* last check, ensure both ends with 0 */ + return string1[iterator] == string2[iterator]; +} + +/** + * @brief Allows to check if provided strings are equal for the first + * bytes. + * + * @param string1 The first string to check. The string must be ended by 0. + * @param string2 The second string to check. The string must be ended by 0. + * @param bytes Number of bytes to check. The value must be > 0. + * + * @return nopoll_true if both strings are equal, otherwise + * nopoll_false is returned. + */ +nopoll_bool nopoll_ncmp (const char * string1, const char * string2, int bytes) +{ + int iterator; + if (bytes <= 0) + return nopoll_false; + if (string1 == NULL && string2 == NULL) + return nopoll_true; + if (string1 == NULL || string2 == NULL) + return nopoll_false; + + /* next position */ + iterator = 0; + while (string1[iterator] && + string2[iterator] && + iterator < bytes) { + if (string1[iterator] != string2[iterator]) + return nopoll_false; + iterator++; + } /* end while */ + + /* last check, ensure both ends with 0 */ + return iterator == bytes; +} + + +/** + * @brief Allows to produce an newly allocated string produced by the + * chunk received plus arguments, using the printf-like format. + * + * @param chunk The chunk to copy. + * + * @return A newly allocated chunk. + */ +char * nopoll_strdup_printf (const char * chunk, ...) +{ + char * result = NULL; + va_list args; + + if (chunk == NULL) + return NULL; + + /* open std args */ + va_start (args, chunk); + + /* get the string */ + result = nopoll_strdup_printfv (chunk, args); + + /* close std args */ + va_end (args); + + return result; +} + +/** + * @internal Allows to calculate the amount of memory required to + * store the string that will representing the construction provided + * by the printf-like format received and its arguments. + * + * @param format The printf-like format to be printed. + * + * @param args The set of arguments that the printf applies to. + * + * NOTE: not all printf specification is supported. Generally, the + * following is supported: %s, %d, %f, %g, %ld, %lg and all + * combinations that provides precision, number of items inside the + * integer part, etc: %6.2f, %+2d, etc. An especial case not supported + * is %lld, %llu and %llg. + * + * @return Return the number of bytes that must be allocated to hold + * the string (including the string terminator \0). If the format is + * not correct or it is not properly formated according to the value + * found at the argument set, the function will return -1. + */ +int nopoll_vprintf_len (const char * format, va_list args) +{ + /** IMPLEMENTATION NOTE: in the case this code is update, + * update exarg_vprintf_len **/ + +#if defined (NOPOLL_OS_WIN32) && ! defined (__GNUC__) +# if HAVE_VSCPRINTF + if (format == NULL) + return 0; + return _vscprintf (format, args) + 1; +# else + char buffer[8192]; + if (format == NULL) + return 0; + return _vsnprintf (buffer, 8191, format, args) + 1; +# endif +#else + /* gnu gcc case */ + if (format == NULL) + return 0; + return vsnprintf (NULL, 0, format, args) + 1; +#endif +} + +/** + * @brief DEPRECATED: Allows to produce an string representing the + * message hold by chunk with the parameters provided. + * + * @param chunk The message chunk to print. + * @param args The arguments for the chunk. + * + * @return A newly allocated string. + * + * IMPLEMENTATION NOTE: This function may have a fundamental bug due + * to the design of va_list arguments under amd64 platforms. In short, + * a function receiving a va_list argument can't use it twice. In you + * are running amd64, check your nopoll_config.h did find + * NOPOLL_HAVE_VASPRINTF. + */ +char * nopoll_strdup_printfv (const char * chunk, va_list args) +{ + /** IMPLEMENTATION NOTE: place update exarg_strdup_printfv + * code in the case this code is updated **/ +#if defined(SHOW_DEBUG_LOG) && ! defined(NOPOLL_HAVE_VASPRINTF) + noPollCtx * ctx = NULL; +#endif + +#if !defined(NOPOLL_HAVE_VASPRINTF) + int size; +#endif + char * result = NULL; + + if (chunk == NULL) + return NULL; + +#ifdef NOPOLL_HAVE_VASPRINTF + /* do the operation using the GNU extension */ + if (vasprintf (&result, chunk, args) == -1) + return NULL; +#else + /* get the amount of memory to be allocated */ + size = nopoll_vprintf_len (chunk, args); + + /* check result */ + if (size == -1) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "unable to calculate the amount of memory for the strdup_printf operation"); + return NULL; + } /* end if */ + + /* allocate memory */ + result = nopoll_new (char, size + 2); + + /* copy current size */ +# if defined(NOPOLL_OS_WIN32) && ! defined (__GNUC__) + size = _vsnprintf_s (result, size + 1, size, chunk, args); +# else + size = vsnprintf (result, size + 1, chunk, args); +# endif +#endif + /* return the result */ + return result; +} + +/** + * @internal Function used by \ref nopoll_trim. + */ +nopoll_bool nopoll_is_white_space (char * chunk) +{ + /* do not complain about receive a null refernce chunk */ + if (chunk == NULL) + return nopoll_false; + + if (chunk[0] == ' ') + return nopoll_true; + if (chunk[0] == '\n') + return nopoll_true; + if (chunk[0] == '\t') + return nopoll_true; + if (chunk[0] == '\r') + return nopoll_true; + + /* no white space was found */ + return nopoll_false; +} + +/** + * @brief Removes white spaces and new lines characters from the + * string providing the count of bytes trimmed from the string. + * + * @param chunk The chunk to trim. + * + * @param trimmed An optional reference that returns the count of bytes + * trimmed by the operation. + */ +void nopoll_trim (char * chunk, int * trimmed) +{ + int iterator; + int iterator2; + int end; + int total; + + /* perform some environment check */ + if (chunk == NULL) + return; + + /* check empty string received */ + if (strlen (chunk) == 0) { + if (trimmed) + *trimmed = 0; + return; + } + + /* check the amount of white spaces to remove from the + * begin */ + iterator = 0; + while (chunk[iterator] != 0) { + + /* check that the iterator is not pointing to a white + * space */ + if (! nopoll_is_white_space (chunk + iterator)) + break; + + /* update the iterator */ + iterator++; + } + + /* check for the really basic case where an empty string is found */ + if (iterator == (int) strlen (chunk)) { + /* an empty string, trim it all */ + chunk [0] = 0; + if (trimmed) + *trimmed = iterator; + return; + } /* end if */ + + /* now get the position for the last valid character in the + * chunk */ + total = strlen (chunk) -1; + end = total; + while (chunk[end] != 0) { + + /* stop if a white space is found */ + if (! nopoll_is_white_space (chunk + end)) { + break; + } + + /* update the iterator to eat the next white space */ + end--; + } + + /* the number of items trimmed */ + total -= end; + total += iterator; + + /* copy the exact amount of non white spaces items */ + iterator2 = 0; + while (iterator2 < (end - iterator + 1)) { + /* copy the content */ + chunk [iterator2] = chunk [iterator + iterator2]; + + /* update the iterator */ + iterator2++; + } + chunk [ end - iterator + 1] = 0; + + if (trimmed != NULL) + *trimmed = total; + + /* return the result reference */ + return; +} + +/** + * @brief Portable subsecond sleep. Suspends the calling thread during + * the provided amount of time. + * + * @param microseconds The amount of time to wait. + */ +void nopoll_sleep (long microseconds) +{ +#if defined(NOPOLL_OS_UNIX) +// usleep (microseconds); + vTaskDelay(microseconds / portTICK_RATE_MS); + return; +#elif defined(NOPOLL_OS_WIN32) + Sleep (microseconds / 1000); + return; +#endif +} + +noPollMutexCreate __nopoll_mutex_create = NULL; +noPollMutexDestroy __nopoll_mutex_destroy = NULL; +noPollMutexLock __nopoll_mutex_lock = NULL; +noPollMutexUnlock __nopoll_mutex_unlock = NULL; + +/** + * @brief Creates a mutex with the defined create mutex handler. + * + * See \ref nopoll_thread_handlers for more information. + * + * @return A mutex reference or NULL if it fails. + */ +noPollPtr nopoll_mutex_create (void) +{ + if (! __nopoll_mutex_create) + return NULL; + + /* call defined handler */ + return __nopoll_mutex_create (); +} + +/** + * @brief Implements a mutex lock operation on the provided + * reference. The function just skip when no mutex reference is + * received o no lock handler was defined. + * + * See \ref nopoll_thread_handlers for more information. + * + * @param mutex The mutex where do the lock operation. + * + * The function will just return if the reference isn't defined or the + * lock handler wasn't installed. + */ +void nopoll_mutex_lock (noPollPtr mutex) +{ + if (! __nopoll_mutex_lock) + return; + + /* call defined handler */ + __nopoll_mutex_lock (mutex); + return; +} + +/** + * @brief Implements a mutex unlock operation on the provided + * reference. The function just skip when no mutex reference is + * received o no unlock handler was defined. + * + * See \ref nopoll_thread_handlers for more information. + * + * @param mutex The mutex where do the unlock operation. + * + */ +void nopoll_mutex_unlock (noPollPtr mutex) +{ + if (! __nopoll_mutex_unlock) + return; + + /* call defined handler */ + __nopoll_mutex_unlock (mutex); + return; +} + +/** + * @brief Implements a mutex destroy operation on the provided + * reference. The function just skip when no mutex reference is + * received o no destroy handler was defined. + * + * See \ref nopoll_thread_handlers for more information. + * + * @param mutex The mutex to destroy operation. + * + */ +void nopoll_mutex_destroy (noPollPtr mutex) +{ + if (! __nopoll_mutex_destroy) + return; + + /* call defined handler */ + __nopoll_mutex_destroy (mutex); + return; +} + +/** + * @brief Global optional mutex handlers used by noPoll library to + * create, destroy, lock and unlock mutex. + * + * If you set this handlers, the library will use these functions to + * secure sensitive code paths that mustn't be protected while working + * with threads. + * + * If you don't provide these, the library will work as usual without + * doing any locking. + * + * @param mutex_create The handler used to create mutexes. + * + * @param mutex_destroy The handler used to destroy mutexes. + * + * @param mutex_lock The handler used to lock a particular mutex. + * + * @param mutex_unlock The handler used to unlock a particular mutex. + * + * The function must receive all handlers defined, otherwise no + * configuration will be done. + */ +void nopoll_thread_handlers (noPollMutexCreate mutex_create, + noPollMutexDestroy mutex_destroy, + noPollMutexLock mutex_lock, + noPollMutexUnlock mutex_unlock) +{ + /* check handlers before configuring anything */ + if (! mutex_create || + ! mutex_destroy || + ! mutex_lock || + ! mutex_unlock) + return; + + /* configured received handlers */ + __nopoll_mutex_create = mutex_create; + __nopoll_mutex_destroy = mutex_destroy; + __nopoll_mutex_lock = mutex_lock; + __nopoll_mutex_unlock = mutex_unlock; + + return; +} + +/** + * @brief Allows to encode the provided content, leaving the output on + * the buffer allocated by the caller. + * + * @param content The content to be encoded. + * + * @param length Content byte-length to encode. + * + * @param output Reference to the already allocated buffer where to + * place the output. + * + * @param output_size The buffer size. + * + * @return nopoll_true if the conversion was properly done, otherwise + * nopoll_false is returned. The function also returns nopoll_false in + * the case some parameter is not defined. + */ +nopoll_bool nopoll_base64_encode (const char * content, + int length, + char * output, + int * output_size) +{ + base64_encode(output, *output_size, (int*)output_size, (char *)content,length); + return nopoll_true; + +#if 0 + BIO * b64; + BIO * bmem; + BUF_MEM * bptr; + + if (content == NULL || output == NULL || length <= 0 || output_size == NULL) + return nopoll_false; + + /* create bio */ + b64 = BIO_new (BIO_f_base64()); + bmem = BIO_new (BIO_s_mem()); + + /* push */ + b64 = BIO_push(b64, bmem); + + if (BIO_write (b64, content, length) != length) { + BIO_free_all (b64); + return nopoll_false; + } + + if (BIO_flush (b64) != 1) { + BIO_free_all (b64); + return nopoll_false; + } + + /* now get content */ + BIO_get_mem_ptr (b64, &bptr); + + /* check output size */ + if ((*output_size) < bptr->length) { + BIO_free_all (b64); + + *output_size = bptr->length; + return nopoll_false; + } + + memcpy(output, bptr->data, bptr->length - 1); + output[bptr->length-1] = 0; + + BIO_free_all (b64); + + return nopoll_true; +#endif +} + +/** + * @brief Decodes the provided base64 content into the user provided + * buffer. + * + * @param content The content to be decoded. + * + * @param length Content byte-length to encode. + * + * @param output Reference to the already allocated buffer where to + * place the output. + * + * @param output_size The buffer size. + * + * @return nopoll_true if the conversion was properly done, otherwise + * nopoll_false is returned. The function also returns nopoll_false in + * the case some parameter is not defined. + */ +nopoll_bool nopoll_base64_decode (const char * content, + int length, + char * output, + int * output_size) +{ + int ret; + ret = base64_decode(content,length,output,output_size); + + return ret; + +#if 0 + BIO * b64; + BIO * bmem; + + if (content == NULL || output == NULL || length <= 0 || output_size == NULL) + return nopoll_false; + + /* create bio */ + bmem = BIO_new_mem_buf ((void *) content, length); + b64 = BIO_new (BIO_f_base64()); + BIO_set_flags (b64, BIO_FLAGS_BASE64_NO_NL); + + /* push */ + bmem = BIO_push(b64, bmem); + + *output_size = BIO_read (bmem, output, *output_size); + output[*output_size] = 0; + + BIO_free_all (bmem); + + return nopoll_true; +#endif +} + +/** + * @brief Performs a timeval substract leaving the result in + * (result). Subtract the `struct timeval' values a and b, storing the + * result in result. + * + * @param a First parameter to substract + * + * @param b Second parameter to substract + * + * @param result Result variable. Do no used a or b to place the + * result. + * + * @return 1 if the difference is negative, otherwise 0 (operations + * implemented is a - b). + */ +int nopoll_timeval_substract (struct timeval * a, + struct timeval * b, + struct timeval * result) +{ + /* Perform the carry for the later subtraction by updating + * y. */ + if (a->tv_usec < b->tv_usec) { + int nsec = (b->tv_usec - a->tv_usec) / 1000000 + 1; + b->tv_usec -= 1000000 * nsec; + b->tv_sec += nsec; + } + + if (a->tv_usec - b->tv_usec > 1000000) { + int nsec = (a->tv_usec - b->tv_usec) / 1000000; + b->tv_usec += 1000000 * nsec; + b->tv_sec -= nsec; + } + + /* get the result */ + result->tv_sec = a->tv_sec - b->tv_sec; + result->tv_usec = a->tv_usec - b->tv_usec; + + /* return 1 if result is negative. */ + return a->tv_sec < b->tv_sec; +} + +/** + * @brief Safe strdup () wrapper. + * + * @param buffer The string to copy + * + * @return A reference to the string copied or NULL if it fails. + */ +char * nopoll_strdup (const char * buffer) +{ + if (buffer == NULL) + return NULL; + + return strdup (buffer); +} + + +/* internal reference to track if we have to randomly init seed */ +nopoll_bool __nopoll_nonce_init = nopoll_false; + +/** + * @brief Fills the buffer provided with a random nonce of the + * requested size. The function try to read random bytes from the + * local PRNG to complete the bytes requested on the buffer.. + * + * @param buffer The buffer where the output is left + * + * @param nonce_size The size of the requested nonce to written into the caller buffer. + * + * @return nopoll_true if the nonce was created otherwise nopoll_false + * is returned. + */ +nopoll_bool nopoll_nonce (char * buffer, int nonce_size) +{ + long int random_value; + int iterator; + struct timeval tv; + + if (buffer == NULL || nonce_size <= 0) + return nopoll_false; + if (! __nopoll_nonce_init) { +#if defined(NOPOLL_OS_WIN32) + nopoll_win32_gettimeofday (&tv, NULL); +#else + gettimeofday (&tv, NULL); +#endif + +// srand (time(0) * tv.tv_usec); + __nopoll_nonce_init = nopoll_true; + } /* end if */ + + /* now get the value from random */ + iterator = 0; + while (iterator < nonce_size) { + /* gen random value */ +#if defined(NOPOLL_OS_WIN32) + random_value = rand (); +#else + random_value = os_random(); +#endif + + /* copy into the buffer */ + memcpy (buffer + iterator, &random_value, sizeof (random_value)); + iterator += sizeof (random_value); + } /* end while */ + + return nopoll_true; +} + +/** + * @internal Allows to extract a particular bit from a byte given the + * position. + * + * +------------------------+ + * | 7 6 5 4 3 2 1 0 | position + * +------------------------+ + */ +int nopoll_get_bit (char byte, int position) { + return ( ( byte & (1 << position) ) >> position); +} + +/** + * @internal Allows to set a particular bit on the first position of + * the buffer provided. + * + * +------------------------+ + * | 7 6 5 4 3 2 1 0 | position + * +------------------------+ + */ +void nopoll_set_bit (char * buffer, int position) { + buffer[0] |= (1 << position); + return; +} + +void nopoll_show_byte (noPollCtx * ctx, char byte, const char * label) { + + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, " byte (%s) = %d %d %d %d %d %d %d %d", + label, + nopoll_get_bit (byte, 7), + nopoll_get_bit (byte, 6), + nopoll_get_bit (byte, 5), + nopoll_get_bit (byte, 4), + nopoll_get_bit (byte, 3), + nopoll_get_bit (byte, 2), + nopoll_get_bit (byte, 1), + nopoll_get_bit (byte, 0)); + return; +} + +char * nopoll_int2bin (int a, char *buffer, int buf_size) { + int i; + + buffer += (buf_size - 1); + + for (i = 31; i >= 0; i--) { + *buffer-- = (a & 1) + '0'; + + a >>= 1; + } + + return buffer; +} + +#define BUF_SIZE 33 + +void nopoll_int2bin_print (noPollCtx * ctx, int value) { + + char buffer[BUF_SIZE]; + buffer[BUF_SIZE - 1] = '\0'; + + nopoll_int2bin (value, buffer, BUF_SIZE - 1); + + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "%d = %s", value, buffer); + + return; +} + +/** + * @internal Allows to get the 16 bit integer located at the buffer + * pointer. + * + * @param buffer The buffer pointer to extract the 16bit integer from. + * + * @return The 16 bit integer value found at the buffer pointer. + */ +int nopoll_get_16bit (const char * buffer) +{ + int high_part = buffer[0] << 8; + int low_part = buffer[1] & 0x000000ff; + + return (high_part | low_part) & 0x000000ffff; +} + +/** + * @internal Allows to get the 8bit integer located at the buffer + * pointer. + * + * @param buffer The buffer pointer to extract the 8bit integer from. + * + * @erturn The 8 bit integer value found at the buffer pointer. + */ +int nopoll_get_8bit (const char * buffer) +{ + return buffer[0] & 0x00000000ff; +} + +/** + * @internal Allows to set the 16 bit integer value into the 2 first + * bytes of the provided buffer. + * + * @param value The value to be configured in the buffer. + * + * @param buffer The buffer where the content will be placed. + */ +void nopoll_set_16bit (int value, char * buffer) +{ + buffer[0] = (value & 0x0000ff00) >> 8; + buffer[1] = value & 0x000000ff; + + return; +} + +/** + * @internal Allows to set the 32 bit integer value into the 4 first + * bytes of the provided buffer. + * + * @param value The value to be configured in the buffer. + * + * @param buffer The buffer where the content will be placed. + */ +void nopoll_set_32bit (int value, char * buffer) +{ + buffer[0] = (value & 0x00ff000000) >> 24; + buffer[1] = (value & 0x0000ff0000) >> 16; + buffer[2] = (value & 0x000000ff00) >> 8; + buffer[3] = value & 0x00000000ff; + + return; +} + +/** + * @brief Allows to get a 32bits integer value from the buffer. + * + * @param buffer The buffer where the integer will be retreived from. + * + * @return The integer value reported by the buffer. + */ +int nopoll_get_32bit (const char * buffer) +{ + int part1 = (int)(buffer[0] & 0x0ff) << 24; + int part2 = (int)(buffer[1] & 0x0ff) << 16; + int part3 = (int)(buffer[2] & 0x0ff) << 8; + int part4 = (int)(buffer[3] & 0x0ff); + + return part1 | part2 | part3 | part4; +} + +extern nopoll_bool __nopoll_tls_was_init; + +/** + * @brief Optional function that can be called at the very end of the + * noPoll usage to ensure all memory allocated by the library is + * released so debugging operations are easier. + * + * It is not required to call this function to get proper operation by + * the library. It is provided, especially due to TLS, to release all + * internal memory that may be allocated. + */ +void nopoll_cleanup_library (void) +{ + + if (__nopoll_tls_was_init) { + EVP_cleanup (); + CRYPTO_cleanup_all_ex_data (); + ERR_free_strings (); + + /* notify the library isn't initialized */ + __nopoll_tls_was_init = nopoll_false; + } /* end if */ + + return; +} /* end if */ + +/* @} */ + +/** + * \mainpage + * + * \section intro noPoll: a toolkit to add WebSocket support to your project + * + * noPoll is a clean implemetnation of the RFC 6455 : The Websocket protocol definition, written in ANSI C. + * + * Some of its features are: + * + * - Context based API design making the library stateless. Support to run several execution contexts in the same process. + * - Support for stream based API and message based API (handler notified) + * - Robust and well tested implementation checked by a strong regression test to ensure the library keeps on working as new features are added. + * - Flexible design that allows its integration into a external loop or to use its own waiting loop + * - Support for port share which allows running native protocol and WebSocket protocol on the same port. + * + * noPoll has been developed by Advanced Software Production Line, + * S.L. (http://www.aspl.es). It is \ref license "licensed under the LGPL 2.1" + * which allows open source and commercial usage. + * + * noPoll manual is available in the following link: + * + * - \ref nopoll_core_library_manual + * - \ref license + * + * Check out noPoll API documentation in the following links: + * + * 1) Common API definition: + * + * - \ref nopoll_support + * - \ref nopoll_decl_module + * - \ref nopoll_ctx + * - \ref nopoll_handlers + * - \ref nopoll_log + * - \ref nopoll_loop + * + * 2) Function for creating connections and listeners + * + * - \ref nopoll_conn + * - \ref nopoll_listener + * - \ref nopoll_conn_opts + * + * 3) Functions to handle messages (message based API): + * + * - \ref nopoll_msg + * + * \section contact_aspl Contact Us + * + * You can reach us at the noPoll mailing list: at noPoll users + * for any question you may find. + * + * If you are interested on getting commercial support, you can also + * contact us at: info@aspl.es. + */ + +/** + * \page nopoll_core_library_manual noPoll core library manual + * + * \section nopoll_core_library_manual_index Index + * + * Section 1: Basic concepts to starting writing with or integrating noPoll: + * + * - \ref installing_nopoll + * - \ref using_nopoll + * - \ref thread_safety + * - \ref creating_a_nopoll_ctx + * - \ref creating_basic_web_socket_server + * - \ref creating_basic_web_socket_client + * - \ref nopoll_manual_reading_content_from_connection + * - \ref nopoll_manual_handling_fragments_with_websocket + * + * Section 2: Advanced concepts to consider: + * + * - \ref nopoll_manual_retrying_write_operations + * - \ref nopoll_implementing_port_sharing + * + * Section 3: using noPoll TLS API: + * + * - \ref nopoll_implementing_mutual_auth + * - \ref nopoll_implementing_tls_extended_validation_post_check + * - \ref nopoll_implementing_tls_context_creator + * + * Section 4: Android platfom notes: + * + * - \ref nopoll_android_usage "4.1 Android noPoll's usage" + * + * \section installing_nopoll 1.1 How to install noPoll + * + * Currently, noPoll has only one dependency, which is OpenSSL + * (libssl) for all those crypto operations required by the protocol + * itself. + * + * After having that library installed in your system (check your OS + * documentation), download lastest tar.gz noPoll library from: http://code.google.com/p/no-poll + * + * Then, to compile the library follow the standard autoconf voodoo: + * + * \code + * >> tar xzvf nopoll-{version}.tar.gz + * >> cd nopoll-{version} + * >> ./configure + * >> make + * \endcode + * + * At this point, if everything went ok, you can check the library by running in one terminal: + * + * \code + * >> cd test/ + * >> ./nopoll-regression-listener + * \endcode + * + * And then in another terminal the client regression test: + * + * \code + * >> cd test/ + * >> ./nopoll-regression-client + * \endcode + * + * If everything looks fine, you can install nopoll into your system with the standard: + * \code + * >> make install + * \endcode + * + * \section using_nopoll 1.2. How to use noPoll library into your application + * + * After a successful noPoll installation, you should be able to + * include noPoll API functions by including the following header: + * + * \code + * #include + * \endcode + * + * Then you can use the following to get nopoll compilation flags: + * + * \code + * >> pkg-config nopoll --cflags + * >> pkg-config nopoll --libs + * \endcode + * + * Or if your project uses autoconf for the building process, just include the following into your configure.ac file: + * + * \code + * dnl check for websocket support (through noPoll) + * AC_ARG_ENABLE(websocket-support, [ --disable-websocket-support Makes the built with WebSocket extension library], + * enable_websocket_support="$enableval", + * enable_websocket_support=yes) + * if test "$enable_websocket_support" != "no" ; then + * PKG_CHECK_MODULES(NOPOLL, nopoll, [enable_websocket_support=yes], [enable_websocket_support=no]) + * AC_SUBST(NOPOLL_CFLAGS) + * AC_SUBST(NOPOLL_LIBS) + * fi + * AM_CONDITIONAL(ENABLE_WEBSOCKET_SUPPORT, test "x$enable_websocket_support" = "xyes") + * \endcode + * + * \section thread_safety 1.3. noPoll thread safety considerations + * + * noPoll is designed as a thread agnostic stateless library so it can + * fit in any project configuration (no matter if it uses threads or + * event notification). + * + * In the case you are planning to use noPoll in a project that uses + * threads and you expect to make calls to the noPoll API from + * different threads at the same time, then you must setup four + * callbacks that will help noPoll to create, destroy, lock and unlock + * mutexes. For that, check documentation about \ref + * nopoll_thread_handlers + * + * \section creating_a_nopoll_ctx 1.4. Creating a noPoll context + * + * Before working with noPoll API you must create a + * \ref noPollCtx object, which represents a single library instance + * state. You can create as much \ref noPollCtx objects inside the process as you + * want. To create it you must do something like: + * + * \code + * noPollCtx * ctx = nopoll_ctx_new (); + * if (! ctx) { + * // error some handling code here + * } + * + * // do some WebSocket operations (as client or listener)... + * + * // ...and once you are done and after terminating all messages and + * // connections created you have to release the context by doing the + * // following: + * nopoll_ctx_unref (ctx); + * \endcode + * + * + * + * + * \section creating_basic_web_socket_server 1.5. Creating a basic WebSocket server with noPoll (using noPoll own loop) + * + * \note Remember you can see many of the code already supported by noPoll by checking the nopoll regression listener at: https://dolphin.aspl.es/svn/publico/nopoll/trunk/test/nopoll-regression-listener.c + * + * Now let's see how to create a simple WebSocket server using noPoll own loop: + * \code + * // create a listener to receive connections on port 1234 + * noPollConn * listener = nopoll_listener_new (ctx, "0.0.0.0", "1234"); + * if (! nopoll_conn_is_ok (listener)) { + * // some error handling here + * } + * + * // now set a handler that will be called when a message (fragment or not) is received + * nopoll_ctx_set_on_msg (ctx, listener_on_message, NULL); + * + * // now call to wait for the loop to notify events + * nopoll_loop_wait (ctx, 0); + * \endcode + * + * Now, every time a frame is received, the handler + * listener_on_message will be called. Here is an example about + * that handler: + * + * \code + * void listener_on_message (noPollCtx * ctx, noPollConn * conn, noPollMsg * msg, noPollPtr * user_data) { + * // print the message (for debugging purposes) and reply + * printf ("Listener received (size: %d, ctx refs: %d): (first %d bytes, fragment: %d) '%s'\n", + * nopoll_msg_get_payload_size (msg), + * nopoll_ctx_ref_count (ctx), shown, nopoll_msg_is_fragment (msg), example); + * + * // reply to the message + * nopoll_conn_send_text (conn, "Message received", 16); + * + * return; + * } + * \endcode + * + * \section creating_basic_web_socket_client 1.6. Creating a basic WebSocket client with noPoll + * + * \note Remember you can see many of the code already supported by noPoll by checking the nopoll regression client at: https://dolphin.aspl.es/svn/publico/nopoll/trunk/test/nopoll-regression-client.c + * + * The process of creating a WebSocket connection is really + * simple. After creating a context (\ref noPollCtx) you connect to + * the listener by using: + * + * \code + * // call to create a connection + * noPollConn * conn = nopoll_conn_new (ctx, "localhost", "1234", NULL, NULL, NULL, NULL); + * if (! nopoll_conn_is_ok (conn)) { + * // some error handling here + * } + * + * \endcode + * + * After that, you can call to \ref nopoll_conn_is_ready to check if + * the connection is ready to send and receive content. If you don't + * have a loop to wait on, you can use the following function to wait + * for the connection to be ready: + * + * \code + * if (! nopoll_conn_wait_until_connection_ready (conn, 5)) { + * // some error handling + * } + * \endcode + * + * In any case, once the connection is ready, either because \ref + * nopoll_conn_is_ready returned \ref nopoll_true or because you used + * \ref nopoll_conn_wait_until_connection_ready, you can send a + * message by using the following: + * + * \code + * // send a message + * if (nopoll_conn_send_text (conn, "Hello there! this is a test", 27) != 27) { + * // send a message + * } + * \endcode + * + * Now, to receive the content from this connection see the following. + * + * \section nopoll_manual_reading_content_from_connection 1.7. How to handle read I/O operations on noPollConn objects (or how it integrates with existing I/O loops). + * + * Now, to receive content from connections (or to handle master listeners requests) you can use the following methods: + * + * - Use noPoll own I/O loop wait (\ref nopoll_loop_wait) and set a onMessage received handler (\ref nopoll_ctx_set_on_msg and \ref nopoll_conn_set_on_msg) + * + * - Use your already working I/O loop to wait for changes on the + * socket associated to the noPollConn object (see \ref + * nopoll_conn_socket). In the case of detecting changes on a master listener connection use to \ref nopoll_conn_accept to accept new incoming connections. In the case of detecting changes in connections with I/O, call to \ref nopoll_conn_get_msg to receive entire messages or \ref nopoll_conn_read (if you want to use streaming API). + * + * \section nopoll_manual_handling_fragments_with_websocket 1.8 Will noPoll automatically integrate fragments into a single message?. + * + * Ok, in general it does, however we would have to look into the + * particular case to give a correct answer. That's because the term + * "fragment" is *really* broad especially for WebSocket. + * + * In general, you shouldn't design in a way that this is important + * for your application to work. All about WebSocket must be designed + * as if you were working with a stream oriented socket. + * + * For example, WebSocket standard states that any intermediary may + * split or join frames. And by any intermediary we mean any WebSocket + * stack in the middle of the transmission including the sender and + * the receiver. + * + * The practical implication is that if your WebSocket peer sends a + * message, it may reach to the other peer consolidated along with + * other smaller messages or it may be received as several "complete" + * WebSocket frames. + * + * In general noPoll tries to consolidate internal frame fragments but + * only for some particular functions like (\ref + * nopoll_conn_get_msg). For example, if a frame fragment is received, + * that is, just the header and part of the body, this particular + * function will "wait" until the entire body is received. And by + * "wait" we mean the function will return NULL, waiting you to call + * again in the future to get the entire message. + * + * In general, even though the standard allows it (as we saw), noPoll + * doesn't do any split or join operation to avoid confusion. However, + * some API calls like \ref nopoll_conn_read, which provides an "stream + * view" of the connection, will serve bytes as they come (so the + * frame concept is not present in this case). + * + * \section nopoll_manual_retrying_write_operations 2.1. Retrying failed write operations + * + * Every time you do a write operation (using for example \ref + * nopoll_conn_send_text or \ref nopoll_conn_send_text_fragment) there + * is a possibility that the write operation failes because the socket + * isn't capable to keep on accepting more data. + * + * In that case, errno == 11 (or \ref NOPOLL_EWOULDBLOCK) is returned + * so you can check this to later retry the write operation. + * + * Because websocket involves sending headers that already includes + * the size of the message sent, you can't just retry by calling again + * to the send operation used (like \ref nopoll_conn_send_text), + * especially because you must "continue" the send operation where it + * was left instead of sending more content with additional + * headers. In short, you must complete the operation. + * + * To this end, you must use the following functions to check and + * complete pending write operations: + * + * - \ref nopoll_conn_pending_write_bytes + * - \ref nopoll_conn_complete_pending_write + * + * Here is a posible complete function considering all points: + * + * \code + * int websocket_write (noPollConn * conn, const char * content, int length) { + * // FIRST PART: normal send operation + * int tries = 0; + * int bytes_written; + * + * // do write operation and check + * bytes_written = nopoll_conn_send_text (conn, content, length); + * if (bytes_written == length) { + * // operation completed, just return bytes written + * return bytes_written; + * } + * + * // SECOND PART: retry in the case of failure + * // some failure found, check errno + * while (tries < 5 && errno == NOPOLL_EWOULDBLOCK && nopoll_conn_pending_write_bytes (conn) > 0) { + * // ok, unable to write all data but that data is waiting to be flushed + * // you can return here and then make your application to retry again or + * // try it right now, but with a little pause before continue + * nopoll_sleep (10000); // lets wait 10ns + * + * // flush and check if write operation completed + * if (nopoll_conn_complete_pending_write (conn) == 0) + * return length; + * + * // limit loop + * tries++; + * } + * + * // failure, return error code reported by the first call or the last retry + * return bytes_written; + * } + * \endcode + * + * As we can see, the example tries to first write the content and + * then check for errors, trying to complete write in the case of + * errno == NOPOLL_EWOULDBLOCK, but, before going ahead retrying, the + * function sleeps a bit. + * + * A very important note to consider is that this isn't by far + * the best way to do this. This example is just to demonstrate the + * concept. The "ideal" implementation would be not to do any retry + * here (second part) but let the engine looping and waiting for this + * WebSocket to retry later, letting the overall application to keep + * on doing other things meanwhile (like writing or handling I/O in other + * connections) rather than locking the caller (as the example do). + * + * Knowing this, if you want a ready to use function that implements + * concept (for the second part), you can directly use: + * + * - \ref nopoll_conn_flush_writes + * + * With it, a fairly complete and efficient write operation would be: + * + * \code + * // do write operation + * bytes_written = nopoll_conn_send_text (conn, content, length); + * + * // complete pending write by flushing and limitting operation for 2 seconds + * // pass to the function bytes_written as returned by nopoll_conn_send_text + * bytes_written = nopoll_conn_flush_writes (conn, 2000000, bytes_written); + * + * \endcode + * + * \section nopoll_implementing_port_sharing 2.2. Implementing protocol port sharing: running WebSocket and legacy protocol on the same port + * + * Current noPoll design allows to implement full WebSocket connection + * accept by calling to \ref nopoll_conn_accept but also it is + * possible to let other application to do the accept connection, try + * to guess if what is comming is a WebSocket connection, to then let + * noPoll to complete the accept socket operation. + * + * As a example, these concepts are being implemented by Vortex + * Library (http://www.aspl.es/vortex) to allow running on the same + * port BEEP and BEEP over WebSocket. + * + * The way each application implements "port sharing concept" is + * really especific to each case, but here are the general steps: + * + * - 1. Let the legacy application to accept the socket by the standard call accept () + * + * - 2. Then, call to recv (socket, buffer[3], 3, MSG_PEEK); to get just 3 bytes from the socket without removing them from the queue. + * + * - 3. Then check with something like the following to know if the incoming connection seems to be a WebSocket one or not: + * + * \code + * // detect tls conn + * nopoll_bool is_tls_conn = bytes[0] == 22 && bytes[1] == 3 && bytes[2] == 1; + * + * // detect then both values (TLS WebSocket and just WebScoket) + * if (! axl_memcmp ("GET", bytes, 3) && ! is_tls_conn) + * return nopoll_false; // nothing detected here (it doesn't seems + * // to be a websocket connection) continue as normal + * + * // nice, it seems we've found an incoming WebSocket connection + * \endcode + * + * - 4. In the case nothing was detected, stop, and continue with the + * usual accept process that was already in place. In the case you + * detected a posible WebSocket connection, then, you'll have to + * do something like: + * + * \code + * // Create a noPollConn listener object that presents the legacy listener where the connection was + * // received. In general is recommended to reuse these references to avoid creating over and over + * // again new references as new WebSocket connections are received. + * // + * noPollConn * nopoll_listener = nopoll_listener_from_socket (nopoll_ctx, listener_socket); + * + * // Create an accepted listener connection reusing the socket received + * // where nopoll_ctx is a reference to a noPollCtx object created and reused by all + * // connections accepted, and _socket represents the socket file descriptor + * // + * noPollConn * conn = nopoll_listener_from_socket (nopoll_ctx, _socket); + * if (! nopoll_conn_is_ok (conn)) { + * // ok, something failed, release and return + * nopoll_conn_close (conn); + * return; + * } + * + * // Now, initiate the entire WebSocket accept process (including TLS one) + * // where nopoll_ctx is the context we used before, nopoll_listener is a listener where + * // the connection was received, conn is the connection accepted and is_tls_conn + * // is an indication about what to expect about TLS process. + * // + * if (! nopoll_conn_accept_complete (nopoll_ctx, nopoll_listener, conn, _socket, is_tls_conn)) { + * // failed to accept connection, release connection + * nopoll_conn_close (conn); + * // optionally close listener reference if it is not reused + * nopoll_conn_close (nopoll_listener); + * return; + * } + * + * // now process incoming messages as configured (either because you've configured an onMessage handler) + * // or because you are handling directly all incoming content (streaming API). + * \endcode + * + * \section nopoll_implementing_mutual_auth 3.1. Implementing mutual TLS certificate verification + * + * In the case you want to verify provided client certificate at the + * server you can use the following code. It optionally provides the + * CA (as root.pem) which will make the listener to also verify client + * matches that CA. However, if you remove that CA (root.pem) your + * server will just verify peer's certificate: + * + * \code + * // configure server certificates (server.pem) signed by the + * // provided ca (root.pem) also configured in the last + * // parameter + * if (! nopoll_conn_opts_set_ssl_certs (opts, + * "server.pem", + * "server.key", + * NULL, + * "root.pem")) { + * printf ("ERROR: unable to setup certificates...\n"); + * return -1; + * } + * + * // configure peer verification + * nopoll_conn_opts_ssl_peer_verify (opts, nopoll_true); + * + * // create listener + * listener2 = nopoll_listener_tls_new_opts (ctx, opts, "0.0.0.0", "1239"); + * if (! nopoll_conn_is_ok (listener2)) { + * printf ("ERROR: Expected to find proper listener TLS connection status (:1236, SSLv23), but found..\n"); + * return -1; + * } + * \endcode + * + * Here the important part is calling to \ref + * nopoll_conn_opts_ssl_peer_verify. This is because peer verification + * is disabled for servers (that is, servers by default do not verify + * peer's certificate which usually is not provided). However, this is + * not true for clients which is by default enabled (of course, client + * must always verify server's certificate when connecting with + * TLS/SSL, was we have said, this can be controlled by \ref + * nopoll_conn_opts_ssl_peer_verify too). + * + * Now, in the case you want to provide client certificate for a + * WebSocket connecting node, use the following: + * + * + * \code + * // create connection options + * opts = nopoll_conn_opts_new (); + * nopoll_conn_opts_set_ssl_certs (opts, + * // certificate + * "client.pem", + * // private key + * "client.pem", + * NULL, + * // ca certificate + * "root.pem"); + * + * // connect to remote WebSocket server + * conn = nopoll_conn_tls_new (ctx, opts, "server-address", "1239", NULL, NULL, NULL, NULL); + * \endcode + * + * \section nopoll_implementing_tls_extended_validation_post_check 3.2. Doing extended validation as a post check task (TLS/SSL) + * + * The idea is to configure the following handler at your server/listener component: + * + * \code + * nopoll_ctx_set_post_ssl_check (ctx, your_post_ssl_check_handler, ); + * \endcode + * + * Now, somewhere, that handler will have the following signature and code example: + * + * \code + * nopoll_bool your_post_ssl_check_handler (noPollCtx * ctx, + * noPollConn * conn, + * noPollPtr SSL_CTX, + * noPollPtr SSL, + * noPollPtr user_data) + * { + * + * // Do here some additional checks on the certificate received (using SSL_CTX and SSL). + * // I the case of error, return nopoll_false to ensure the connection is not accepted. + * + * return nopoll_true; // to accept connection + * } + * \endcode + * + * For example, to get the certificate that is proposing the client you could use: + * + * \code + * cert = SSL_get_peer_certificate (SSL); + * \endcode + * + * \section nopoll_implementing_tls_context_creator 3.3. Creating TLS/SSL context to implement especific validation options + * + * In the case you want to create the SSL_CTX/SSL object so it uses + * certain configurations like chain certificates, etc, so that the + * verification will only work when matching these settings. + * + * If this is the case you'll have to use a different handler that + * will help noPoll engine to create the SSL context with the settings + * you want. By default, the SSL context is created with default + * settings if no handler is provided. + * + * In the case you want to provide a ssl context creator, use: + * + * \code + * nopoll_ctx_set_ssl_context_creator (ctx, your_ssl_context_creator, NULL); + * \endcode + * + * And your handler will have the following signature with a very + * basic configuration: + * + * \code + * SSL_CTX * your_ssl_context_creator (noPollCtx * ctx, noPollConn * conn, noPollConnOpts * opts, nopoll_bool is_client, noPollPtr user_data) + * { + * // very basic context creation using default settings provided by OpenSSL + * return SSL_CTX_new (is_client ? TLSv1_client_method () : TLSv1_server_method ()); + * } + * \endcode + * + * As you can see, the function must return an SSL_CTX for every + * connection received and attempting to start TLS session. + * + * + */ + +/** + * \page nopoll_android_usage Android noPoll's usage + * + * + * \section nopoll_android_usage Using noPoll's Android install and development kit + * + * Inside http://www.aspl.es/nopoll/downloads/android you'll find two types of downloads. + * One prefixed with -install.zip that provides just those binaries needed and -full.zip + * that provides a ready to use binaries with all the headers, etc needed to produce + * Android solutions using noPoll library. + * + * + * \section nopoll_general_notes General notes + * + * The idea behind these installers is the following. Because there + * are several platforms (android APIs) that you might want to support + * and for each platform there could be several archs (up to 6), these + * installers include all files compiled for each possible + * combination. + * + * That way, you only have to pick desired combinations to compile + * your project with ready to use binaries. + * + * + * \section nopoll_platforms_archs Platforms and archs + * + * In particular the following platforms are supported by the + * NDK. Each of them represents an android particular version: + * + * - android-12 + * - android-13 + * - android-14 + * - android-15 + * - android-16 + * - android-17 + * - android-18 + * - android-19 + * - android-21 + * - android-3 + * - android-4 + * - android-5 + * - android-8 + * - android-9 + * + * In the following link you have a declaration between each platform + * and each Android version: https://developer.android.com/ndk/guides/stable_apis.html + * + * Now, for each platform you may have different archs supported (cpu + * style): + * + * - arm + * - arm64 + * - mips + * - mips64 + * - x86 + * - x86_64 + * + * More information about this at: https://developer.android.com/ndk/guides/abis.html + * + * \section nopoll_using_install_bundle Using the install bundle + * + * Assuming previous information, please, uncompress + * nopoll-VERSION-instal.zip bundle. Inside it, you'll find a + * "install" folder that inside includes the following structure: + * + * \code + * install//lib//{libfiles}.so + * \endcode + * + * That way, if you need ready to use compiled libraries for android-21, arch mips64, the look at: + * + * \code + * install/android-21//lib/mips64/{libfiles}.so files. + * \endcode + * + * You might wonder why don't use a //lib + * scheme? That's good question. This is because Android + * architectural design. See "Native code in app packages" in the + * following link https://developer.android.com/ndk/guides/abis.html + * to know more about this structure. + * + * The idea is that you have to support all for a given + * (android-21 i.e.). + * + * In that case, the install.zip is prepared to pick the entire + * directory content of a given android platform (for example + * install/android-21/) so the structure follows the guide lines of + * Android but also provides you full support for all archs, in that + * platform, to all components that noPoll is made of. + * + * \section nopoll_use_development_kit Using development kit bundle (full.zip) + * + * Ok, now for compiling your project for android using this bundle, + * please grab a reference to the full installer and uncompress it. + * + * Inside, you'll find the following structure (more handy for a + * developer using autoconf or cmake): + * + * \code + * full///{ready to use devel files to compile using noPoll} + * \endcode + * + * + * Now, assuming you are working with an ARM device, running android + * 4.0, then you can use files found at: + * + * \code + * full/arm/android-14/bin/ + * include/ + * lib/ + * share/ + * ssl/ + * \endcode + * + * + * In your case, you only have to provide the following gcc flags to + * your cmake or autoconf environment as follows: + * + * 1) Compiler flags: + * + * \code + * CFLAGS="-I/full/arm/android-14/include -I/full/arm/android-14/include/vortex -I/full/arm/android-14/include/axl -I/full/arm/android-14/include/nopoll" + * \endcode + * + * 2) Linker flags: + * + * \code + * LDFLAGS=" -L/full/arm/android-14/lib -lvortex -lvortex-tls-1.1 -l axl -lssl -lcrypto -lpthread -pthread -lm" + * \endcode + * + * 3) And your compiler must match the target platform, for example, for ARM: + * + * \code + * CC := $(ANDROID_NDK_BIN)/arm-linux-androideabi-gcc + * CPP := $(ANDROID_NDK_BIN)/arm-linux-androideabi-g++ + * AR := $(ANDROID_NDK_BIN)/arm-linux-androideabi-ar + * LD := $(ANDROID_NDK_BIN)/arm-linux-androideabi-ld + * \endcode + * + * After that, according to your compiling tool, have it to use these + * indicatations to compile your source code using noPoll. + * + * + */ + +/** + * \page license noPoll License + * + * \section licence_intro noPoll terms of use + * The noPoll is release under the terms of the Lesser General + * Public license (LGPL). You can find it at + * http://www.gnu.org/licenses/licenses.html#LGPL. + * + * The main implication this license has is that you are allowed to + * use the noPoll for commercial application as well on open + * source application using GPL/LGPL compatible licenses. + * + * Restrictions for proprietary development are the following: + * + * - You have to provide back to the main repository or to your + * customers any change, modifications, improvements you may do to the + * noPoll. Of course, we would appreciate to add to the main + * noPoll repository any patch, idea or improvement you send + * us but you are not required to do so. + * + * - You cannot use our company name or image, the noPoll name + * or any trademark associated to that product or any product the + * Advanced Software Production Line company may have in a way that + * they could be damaged. Of course, we would appreciate your project, in + * the case it is a proprietary one, make a reference to us but you are + * not required to do so. + * + * \section license_about_static_linking About statically linking noPoll + * + * Statically linking noPoll or any other component based on GPL/LGPL + * is strictly forbidden by the license unless all components + * taking part into the final products are all of them GPL, LGPL, MIT, + * Bsds, etc, or similar licenses that allow an end user or the + * customer to download the entire product source code and clear + * instructions to rebuild it. + * + * If the library is being used by a proprietary product the only + * allowed option is dynamic linking (so final user is capable of + * updating that dynamic linked part) or a practical procedure where + * the propritary binary object along with the instructions to relink + * the LGPL part (including an update or modification of it) is + * provided. + * + * An end user or customer using a product using LGPL components must + * be able to rebuild those components by introducing updates or + * improvements. + * + * Thus, statically linking a LGPL components without considering + * previous points takes away this user/customer right because he/she + * cannot replace/update that LGPL component anymore unless you can + * have access to the whole solution. + * + * - See more about this at: https://www.gnu.org/licenses/lgpl-2.1.html + * - Also at: http://stackoverflow.com/questions/10130143/gpl-lgpl-and-static-linking + * - LGPL 2.1 Guide: http://copyleft.org/guide/comprehensive-gpl-guidech11.html + * + * \section other Contact us to know more about licenses. + * + * Use the following contact information to reach us about this issue. + * + * \code + * Postal address: + * Advanced Software Production Line, S.L. + * C/ Antonio Suarez Nº 10, + * Edificio Alius A, Despacho 102 + * Alcalá de Henares 28802 (Madrid) + * Spain + * + * Email address: + * info@aspl.es - http://www.aspl.es/nopoll + * Fax and Telephones: + * (+34) 91 669 55 32 - (+34) 91 231 44 50 + * From outside Spain must use (+34) prefix. + * \endcode + * + * + */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_conn.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_conn.c new file mode 100644 index 0000000..42f0fac --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_conn.c @@ -0,0 +1,4157 @@ +/* + * LibNoPoll: A websocket library + * Copyright (C) 2013 Advanced Software Production Line, S.L. + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * You may find a copy of the license under this software is released + * at COPYING file. This is LGPL software: you are welcome to develop + * proprietary applications using this library without any royalty or + * fee but returning back any change, improvement or addition in the + * form of source code, project image, documentation patches, etc. + * + * For commercial support on build Websocket enabled solutions + * contact us: + * + * Postal address: + * Advanced Software Production Line, S.L. + * Edificio Alius A, Oficina 102, + * C/ Antonio Suarez Nº 10, + * Alcalá de Henares 28802 Madrid + * Spain + * + * Email address: + * info@aspl.es - http://www.aspl.es/nopoll + */ + +/** + * \defgroup nopoll_conn noPoll Connection: functions required to create WebSocket client connections. + */ + +/** + * \addtogroup nopoll_conn + * @{ + */ + +#include +#include + + + +/** + * @brief Allows to enable/disable non-blocking/blocking behavior on + * the provided socket. + * + * @param socket The socket to be configured. + * + * @param enable nopoll_true to enable blocking I/O, otherwise use + * nopoll_false to enable non blocking I/O. + * + * @return nopoll_true if the operation was properly done, otherwise + * nopoll_false is returned. + */ +nopoll_bool nopoll_conn_set_sock_block (NOPOLL_SOCKET socket, + nopoll_bool enable) +{ +#if defined(NOPOLL_OS_UNIX) + int flags; +#endif + + if (enable) { + /* enable blocking mode */ +#if defined(NOPOLL_OS_WIN32) + if (!nopoll_win32_blocking_enable (socket)) { + return nopoll_false; + } +#else + if ((flags = fcntl (socket, F_GETFL, 0)) < -1) { + return nopoll_false; + } /* end if */ + + flags &= ~O_NONBLOCK; + if (fcntl (socket, F_SETFL, flags) < -1) { + return nopoll_false; + } /* end if */ +#endif + } else { + /* enable nonblocking mode */ +#if defined(NOPOLL_OS_WIN32) + /* win32 case */ + if (!nopoll_win32_nonblocking_enable (socket)) { + return nopoll_false; + } +#else + /* unix case */ + if ((flags = fcntl (socket, F_GETFL, 0)) < -1) { + return nopoll_false; + } + + flags |= O_NONBLOCK; + if (fcntl (socket, F_SETFL, flags) < -1) { + return nopoll_false; + } +#endif + } /* end if */ + + return nopoll_true; +} + + +/** + * @brief Allows to get current timeout set for \ref noPollConn + * connect operation. + * + * See also \ref nopoll_conn_connect_timeout. + * + * @return Current timeout configured. Returned value is measured in + * microseconds (1 second = 1000000 microseconds). If a null value is + * received, 0 is return and no timeout is implemented. + */ +long nopoll_conn_get_connect_timeout (noPollCtx * ctx) +{ + /* check context recevied */ + if (ctx == NULL) { + /* get the the default connect */ + return (0); + } /* end if */ + + /* return current value */ + return ctx->conn_connect_std_timeout; +} + +/** + * @brief Allows to configure nopoll connect timeout. + * + * This function allows to set the TCP connect timeout used by \ref + * nopoll_conn_new. + * + * @param ctx The context where the operation will be performed. + * + * @param microseconds_to_wait Timeout value to be used. The value + * provided is measured in microseconds. Use 0 to restore the connect + * timeout to the default value. + */ +void nopoll_conn_connect_timeout (noPollCtx * ctx, + long microseconds_to_wait) +{ + /* check reference received */ + if (ctx == NULL) + return; + + /* configure new value */ + ctx->conn_connect_std_timeout = microseconds_to_wait; + + return; +} + + +/** + * @brief Allows to configure tcp no delay flag (enable/disable Nagle + * algorithm). + * + * @param socket The socket to be configured. + * + * @param enable The value to be configured, nopoll_true to enable tcp no + * delay. + * + * @return nopoll_true if the operation is completed. + */ +nopoll_bool nopoll_conn_set_sock_tcp_nodelay (NOPOLL_SOCKET socket, + nopoll_bool enable) +{ + /* local variables */ + int result; + +#if defined(NOPOLL_OS_WIN32) + BOOL flag = enable ? TRUE : FALSE; + result = setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(BOOL)); +#else + int flag = enable; + result = setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof (flag)); +#endif + if (result == NOPOLL_INVALID_SOCKET) { + return nopoll_false; + } + + /* properly configured */ + return nopoll_true; +} /* end */ + +/** + * @internal Allows to create a plain socket connection against the + * host and port provided. + * + * @param ctx The context where the connection happens. + * + * @param host The host server to connect to. + * + * @param port The port server to connect to. + * + * @return A connected socket or -1 if it fails. + */ +NOPOLL_SOCKET nopoll_conn_sock_connect (noPollCtx * ctx, + const char * host, + const char * port) +{ + struct hostent * hostent; + struct sockaddr_in saddr; + NOPOLL_SOCKET session; + + /* resolve hosting name */ + hostent = gethostbyname (host); + if (hostent == NULL) { + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "unable to resolve host name %s", host); + return -1; + } /* end if */ + + /* create the socket and check if it */ + session = socket (AF_INET, SOCK_STREAM, 0); + if (session == NOPOLL_INVALID_SOCKET) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "unable to create socket"); + return -1; + } /* end if */ + + /* disable nagle */ + nopoll_conn_set_sock_tcp_nodelay (session, nopoll_true); + + /* prepare socket configuration to operate using TCP/IP + * socket */ + memset(&saddr, 0, sizeof(saddr)); + saddr.sin_addr.s_addr = ((struct in_addr *)(hostent->h_addr))->s_addr; + saddr.sin_family = AF_INET; + saddr.sin_port = htons((uint16_t) strtol (port, NULL, 10)); + + /* set non blocking status */ +// nopoll_conn_set_sock_block (session, nopoll_false); + + /* do a tcp connect */ + if (connect (session, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { + if(errno != NOPOLL_EINPROGRESS && errno != NOPOLL_EWOULDBLOCK && errno != NOPOLL_ENOTCONN) { + shutdown (session, SHUT_RDWR); + nopoll_close_socket (session); + + nopoll_log (ctx, NOPOLL_LEVEL_WARNING, "unable to connect to remote host %s:%s errno=%d", + host, port, errno); + return -1; + } /* end if */ + } /* end if */ + + /* return socket created */ + return session; +} + + + + +/** + * @internal Function that builds the client init greetings that will + * be send to the server according to registered implementation. + */ +char * __nopoll_conn_get_client_init (noPollConn * conn, noPollConnOpts * opts) +{ + /* build sec-websocket-key */ + char key[50]; + int key_size = 50; + char nonce[17]; + + /* get the nonce */ + if (! nopoll_nonce (nonce, 16)) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Failed to get nonce, unable to produce Sec-WebSocket-Key."); + return NULL; + } /* end if */ + + /* now base 64 */ + if (! nopoll_base64_encode (nonce, 16, key, &key_size)) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Unable to base 64 encode characters for Sec-WebSocket-Key"); + return NULL; + } + + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Created Sec-WebSocket-Key nonce: %s", key); + + /* create accept and store */ + conn->handshake = nopoll_new (noPollHandShake, 1); + conn->handshake->expected_accept = nopoll_strdup (key); + + /* send initial handshake |cookie |prot | */ + return nopoll_strdup_printf ("GET %s HTTP/1.1\r\nHost: %s\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Key: %s\r\nOrigin: %s\r\n%s%s%s%s%s%s%s%sSec-WebSocket-Version: %d\r\n\r\n", + conn->get_url, conn->host_name, + /* sec-websocket-key */ + key, + /* Origin */ + conn->origin, + /* Cookie */ + (opts && opts->cookie) ? "Cookie" : "", + (opts && opts->cookie) ? ": " : "", + (opts && opts->cookie) ? opts->cookie : "", + (opts && opts->cookie) ? "\r\n" : "", + /* protocol part */ + conn->protocols ? "Sec-WebSocket-Protocol" : "", + conn->protocols ? ": " : "", + conn->protocols ? conn->protocols : "", + conn->protocols ? "\r\n" : "", + conn->ctx->protocol_version); +} + + +/** + * @internal Function that dumps all errors found on current ssl context. + */ +int nopoll_conn_log_ssl (noPollConn * conn) +{ +#if defined(SHOW_DEBUG_LOG) + noPollCtx * ctx = conn->ctx; +#endif + char log_buffer [512]; + unsigned long err; + int error_position; + int aux_position; + + while ((err = ERR_get_error()) != 0) { + ERR_error_string_n (err, log_buffer, sizeof (log_buffer)); + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "tls stack: %s (find reason(code) at openssl/ssl.h)", log_buffer); + + /* find error code position */ + error_position = 0; + while (log_buffer[error_position] != ':' && log_buffer[error_position] != 0 && error_position < 511) + error_position++; + error_position++; + aux_position = error_position; + while (log_buffer[aux_position] != 0) { + if (log_buffer[aux_position] == ':') { + log_buffer[aux_position] = 0; + break; + } + aux_position++; + } /* end while */ + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, " details, run: openssl errstr %s", log_buffer + error_position); + } + + recv (conn->session, log_buffer, 1, MSG_PEEK); + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, " noPoll id=%d, socket: %d (after testing errno: %d)", + conn->id, conn->session, errno); + + + return (0); +} + +int __nopoll_conn_tls_handle_error (noPollConn * conn, int res, const char * label, nopoll_bool * needs_retry) +{ + int ssl_err; + + (*needs_retry) = nopoll_false; + + /* get error returned */ + ssl_err = SSL_get_error (conn->ssl, res); + switch (ssl_err) { + case SSL_ERROR_NONE: + /* no error, return the number of bytes read */ + /* nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "%s, ssl_err=%d, perfect, no error reported, bytes read=%d", + label, ssl_err, res); */ + return res; + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_X509_LOOKUP: + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "%s, ssl_err=%d returned that isn't ready to read/write: you should retry", + label, ssl_err); + (*needs_retry) = nopoll_true; + return -2; + case SSL_ERROR_SYSCALL: + if(res < 0) { /* not EOF */ + if(errno == NOPOLL_EINTR) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "%s interrupted by a signal: retrying", label); + /* report to retry */ + return -2; + } + nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "SSL_read (SSL_ERROR_SYSCALL)"); + return -1; + } + nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "SSL socket closed on %s (res=%d, ssl_err=%d, errno=%d)", + label, res, ssl_err, errno); + nopoll_conn_log_ssl (conn); + + return res; + case SSL_ERROR_ZERO_RETURN: /* close_notify received */ + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "SSL closed on %s", label); + return res; + case SSL_ERROR_SSL: + nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "%s function error (received SSL_ERROR_SSL) (res=%d, ssl_err=%d, errno=%d)", + label, res, ssl_err, errno); + nopoll_conn_log_ssl (conn); + return -1; + default: + /* nothing to handle */ + break; + } + nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "%s/SSL_get_error returned %d", label, res); + return -1; + +} + +/** + * @internal Default connection receive until handshake is complete. + */ +int nopoll_conn_tls_receive (noPollConn * conn, char * buffer, int buffer_size) +{ + int res; + nopoll_bool needs_retry; + int tries = 0; + + /* call to read content */ + while (tries < 50) { + res = SSL_read (conn->ssl, buffer, buffer_size); + /* nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "SSL: received %d bytes..", res); */ + + /* call to handle error */ + res = __nopoll_conn_tls_handle_error (conn, res, "SSL_read", &needs_retry); + + if (! needs_retry) + break; + + /* next operation */ + tries++; + } + /* nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, " SSL: after procesing error %d bytes..", res); */ + return res; +} + +/** + * @internal Default connection send until handshake is complete. + */ +int nopoll_conn_tls_send (noPollConn * conn, char * buffer, int buffer_size) +{ + int res; + nopoll_bool needs_retry; + int tries = 0; + + /* call to read content */ + while (tries < 50) { + res = SSL_write (conn->ssl, buffer, buffer_size); + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "SSL: sent %d bytes (requested: %d)..", res, buffer_size); + + /* call to handle error */ + res = __nopoll_conn_tls_handle_error (conn, res, "SSL_write", &needs_retry); + /* nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, " SSL: after processing error, sent %d bytes (requested: %d)..", res, buffer_size); */ + + if (! needs_retry) + break; + + /* next operation */ + nopoll_sleep (tries * 10000); + tries++; + } + return res; +} + + +SSL_CTX * __nopoll_conn_get_ssl_context (noPollCtx * ctx, noPollConn * conn, noPollConnOpts * opts, nopoll_bool is_client) +{ + /* call to user defined function if the context creator is defined */ + if (ctx && ctx->context_creator) + return ctx->context_creator (ctx, conn, opts, is_client, ctx->context_creator_data); + + if (opts == NULL) { + /* printf ("**** REPORTING TLSv1 ****\n"); */ + return (SSL_CTX *)SSL_CTX_new (is_client ? TLSv1_client_method () : TLSv1_server_method ()); + } /* end if */ + + switch (opts->ssl_protocol) { + case NOPOLL_METHOD_TLSV1: + return (SSL_CTX *)SSL_CTX_new (is_client ? TLSv1_client_method () : TLSv1_server_method ()); +//#if defined(TLSv1_1_client_method) + case NOPOLL_METHOD_TLSV1_1: + /* printf ("**** REPORTING TLSv1.1 ****\n"); */ + return (SSL_CTX *)SSL_CTX_new (is_client ? TLSv1_1_client_method () : TLSv1_1_server_method ()); +//#endif + case NOPOLL_METHOD_SSLV3: + /* printf ("**** REPORTING SSLv3 ****\n"); */ + return (SSL_CTX *)SSL_CTX_new (is_client ? SSLv3_client_method () : SSLv3_server_method ()); + case NOPOLL_METHOD_SSLV23: + /* printf ("**** REPORTING SSLv23 ****\n"); */ + return (SSL_CTX *)SSL_CTX_new (is_client ? SSLv23_client_method () : SSLv23_server_method ()); + } + + /* reached this point, report default TLSv1 method */ + return (SSL_CTX *)SSL_CTX_new (is_client ? TLSv1_client_method () : TLSv1_server_method ()); +} + +noPollCtx * __nopoll_conn_ssl_ctx_debug = NULL; + +int __nopoll_conn_ssl_verify_callback (int ok, X509_STORE_CTX * store) { + char data[256]; + X509 * cert; +#if defined(SHOW_DEBUG_LOG) + int depth; + int err; +#endif + + if (! ok) { + cert = (X509 *)X509_STORE_CTX_get_current_cert (store); +#if defined(SHOW_DEBUG_LOG) + depth = X509_STORE_CTX_get_error_depth (store); + err = X509_STORE_CTX_get_error (store); +#endif + + nopoll_log (__nopoll_conn_ssl_ctx_debug, NOPOLL_LEVEL_CRITICAL, "CERTIFICATE: error=%d at depth: %d", err, depth); + + X509_NAME_oneline (X509_get_issuer_name (cert), data, 256); + nopoll_log (__nopoll_conn_ssl_ctx_debug, NOPOLL_LEVEL_CRITICAL, "CERTIFICATE: issuer: %s", data); + + X509_NAME_oneline (X509_get_subject_name (cert), data, 256); + nopoll_log (__nopoll_conn_ssl_ctx_debug, NOPOLL_LEVEL_CRITICAL, "CERTIFICATE: subject: %s", data); + + nopoll_log (__nopoll_conn_ssl_ctx_debug, NOPOLL_LEVEL_CRITICAL, "CERTIFICATE: error %d:%s", err, X509_verify_cert_error_string (err)); + + } + return ok; /* return same value */ +} + +nopoll_bool __nopoll_conn_set_ssl_client_options (noPollCtx * ctx, noPollConn * conn, noPollConnOpts * options) +{ + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Checking to establish SSL options (%p)", options); + + if (options && options->ca_certificate) { + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Setting CA certificate: %s", options->ca_certificate); + if (SSL_CTX_load_verify_locations (conn->ssl_ctx, options->ca_certificate, NULL) != 1) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to configure CA certificate (%s), SSL_CTX_load_verify_locations () failed", options->ca_certificate); + return nopoll_false; + } /* end if */ + + } /* end if */ + + /* enable default verification paths */ + if (SSL_CTX_set_default_verify_paths (conn->ssl_ctx) != 1) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Unable to configure default verification paths, SSL_CTX_set_default_verify_paths () failed"); + return nopoll_false; + } /* end if */ + + if (options && options->chain_certificate) { + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Setting chain certificate: %s", options->chain_certificate); + if (SSL_CTX_use_certificate_chain_file (conn->ssl_ctx, options->chain_certificate) != 1) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to configure chain certificate (%s), SSL_CTX_use_certificate_chain_file () failed", options->chain_certificate); + return nopoll_false; + } /* end if */ + } /* end if */ + + if (options && options->certificate) { + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Setting certificate: %s", options->certificate); + if (SSL_CTX_use_certificate_chain_file (conn->ssl_ctx, options->certificate) != 1) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to configure client certificate (%s), SSL_CTX_use_certificate_file () failed", options->certificate); + return nopoll_false; + } /* end if */ + } /* end if */ + + if (options && options->private_key) { + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Setting private key: %s", options->private_key); + if (SSL_CTX_use_PrivateKey_file (conn->ssl_ctx, options->private_key, SSL_FILETYPE_PEM) != 1) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to configure private key (%s), SSL_CTX_use_PrivateKey_file () failed", options->private_key); + return nopoll_false; + } /* end if */ + } /* end if */ + + if (options && options->private_key && options->certificate) { + if (!SSL_CTX_check_private_key (conn->ssl_ctx)) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Certificate and private key do not matches, verification fails, SSL_CTX_check_private_key ()"); + return nopoll_false; + } /* end if */ + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Certificate (%s) and private key (%s) matches", options->certificate, options->private_key); + } /* end if */ + + /* if no option and it is not disabled */ + if (options == NULL || ! options->disable_ssl_verify) { + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Enabling certificate peer verification"); + /** really, really ugly hack to let + * __nopoll_conn_ssl_verify_callback to be able to get + * access to the context required to drop some logs */ + __nopoll_conn_ssl_ctx_debug = ctx; + SSL_CTX_set_verify (conn->ssl_ctx, SSL_VERIFY_PEER, __nopoll_conn_ssl_verify_callback); + SSL_CTX_set_verify_depth (conn->ssl_ctx, 10); + } /* end if */ + + return nopoll_true; +} + + +/** + * @internal Internal implementation used to do a connect. + */ +noPollConn * __nopoll_conn_new_common (noPollCtx * ctx, + noPollConnOpts * options, + nopoll_bool enable_tls, + const char * host_ip, + const char * host_port, + const char * host_name, + const char * get_url, + const char * protocols, + const char * origin) +{ + noPollConn * conn; + NOPOLL_SOCKET session; + char * content; + int size; + int ssl_error; + X509 * server_cert; + int iterator; + long remaining_timeout; + + if (! ctx || ! host_ip) { + /* release connection options */ + __nopoll_conn_opts_release_if_needed (options); + return NULL; + } /* end if */ + + /* set default connection port */ + if (host_port == NULL) + host_port = "80"; + + /* create socket connection in a non block manner */ + session = nopoll_conn_sock_connect (ctx, host_ip, host_port); + if (session == NOPOLL_INVALID_SOCKET) { + /* release connection options */ + __nopoll_conn_opts_release_if_needed (options); + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to connect to remote host %s:%s", host_ip, host_port); + return NULL; + } /* end if */ + + /* create the connection */ + conn = nopoll_new (noPollConn, 1); + if (conn == NULL) { + /* release connection options */ + __nopoll_conn_opts_release_if_needed (options); + return NULL; + } /* end if */ + + conn->refs = 1; + + /* create mutex */ + conn->ref_mutex = nopoll_mutex_create (); + + /* register connection into context */ + if (! nopoll_ctx_register_conn (ctx, conn)) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to register connection into the context, unable to create connection"); + nopoll_free (conn); + /* release connection options */ + __nopoll_conn_opts_release_if_needed (options); + + return NULL; + } + + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Created noPoll conn-id=%d (ptr: %p, context: %p, socket: %d)", + conn->id, conn, ctx, session); + + /* configure context */ + conn->ctx = ctx; + conn->session = session; + conn->role = NOPOLL_ROLE_CLIENT; + + /* record host and port */ + conn->host = nopoll_strdup (host_ip); + conn->port = nopoll_strdup (host_port); + + /* configure default handlers */ + conn->receive = nopoll_conn_default_receive; + conn->sends = nopoll_conn_default_send; + + /* build host name */ + if (host_name == NULL) + conn->host_name = nopoll_strdup (host_ip); + else + conn->host_name = nopoll_strdup (host_name); + + /* build origin */ + if (origin == NULL) + conn->origin = nopoll_strdup_printf ("http://%s", conn->host_name); + else + conn->origin = nopoll_strdup (origin); + + /* get url */ + if (get_url == NULL) + conn->get_url = nopoll_strdup ("/"); + else + conn->get_url = nopoll_strdup (get_url); + + /* protocols */ + if (protocols != NULL) + conn->protocols = nopoll_strdup (protocols); + + + /* get client init payload */ + content = __nopoll_conn_get_client_init (conn, options); + + if (content == NULL) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to build client init message, unable to connect"); + nopoll_conn_shutdown (conn); + + /* release connection options */ + __nopoll_conn_opts_release_if_needed (options); + + return NULL; + } /* end if */ + + /* check for TLS support */ + if (enable_tls) { + /* found TLS connection request, enable it */ + conn->ssl_ctx = __nopoll_conn_get_ssl_context (ctx, conn, options, nopoll_true); + + /* check for client side SSL configuration */ + if (! __nopoll_conn_set_ssl_client_options (ctx, conn, options)) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Unable to configure additional SSL options, unable to continue", + conn->ssl_ctx, conn->ssl); + goto fail_ssl_connection; + } /* end if */ + + /* create context and check for result */ + conn->ssl = (SSL*)SSL_new (conn->ssl_ctx); + if (conn->ssl_ctx == NULL || conn->ssl == NULL) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Unable to create SSL context internal references are null (conn->ssl_ctx=%p, conn->ssl=%p)", + conn->ssl_ctx, conn->ssl); + fail_ssl_connection: + + nopoll_free (content); + nopoll_conn_shutdown (conn); + + /* release connection options */ + __nopoll_conn_opts_release_if_needed (options); + + return conn; + } /* end if */ + + /* set socket */ + SSL_set_fd (conn->ssl, conn->session); + + /* do the initial connect connect */ + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "connecting to remote TLS site"); + iterator = 0; + while (SSL_connect (conn->ssl) <= 0) { + + /* get ssl error */ + ssl_error = SSL_get_error (conn->ssl, -1); + + switch (ssl_error) { + case SSL_ERROR_WANT_READ: + nopoll_log (ctx, NOPOLL_LEVEL_WARNING, "still not prepared to continue because read wanted, conn-id=%d (%p, session: %d), errno=%d", + conn->id, conn, conn->session, errno); + break; + case SSL_ERROR_WANT_WRITE: + nopoll_log (ctx, NOPOLL_LEVEL_WARNING, "still not prepared to continue because write wanted, conn-id=%d (%p)", + conn->id, conn); + break; + case SSL_ERROR_SYSCALL: + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "syscall error while doing TLS handshake, ssl error (code:%d), conn-id: %d (%p), errno: %d, session: %d", + ssl_error, conn->id, conn, errno, conn->session); + nopoll_conn_log_ssl (conn); + nopoll_conn_shutdown (conn); + nopoll_free (content); + + /* release connection options */ + __nopoll_conn_opts_release_if_needed (options); + + return conn; + default: + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "there was an error with the TLS negotiation, ssl error (code:%d) : %s", + ssl_error, ERR_error_string (ssl_error, NULL)); + nopoll_conn_log_ssl (conn); + nopoll_conn_shutdown (conn); + nopoll_free (content); + + /* release connection options */ + __nopoll_conn_opts_release_if_needed (options); + + return conn; + } /* end switch */ + + /* try and limit max reconnect allowed */ + iterator++; + + if (iterator > 100) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Max retry calls=%d to SSL_connect reached, shutting down connection id=%d, errno=%d", + iterator, conn->id, errno); + nopoll_free (content); + + /* release connection options */ + __nopoll_conn_opts_release_if_needed (options); + + return conn; + } /* end if */ + + /* wait a bit before retry */ + nopoll_sleep (10000); + + } /* end while */ + + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Client TLS handshake finished, configuring I/O handlers"); + + /* check remote certificate (if it is present) */ + server_cert = (X509*)SSL_get_peer_certificate (conn->ssl); + if (server_cert == NULL) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "server side didn't set a certificate for this session, these are bad news"); + + /* release connection options */ + nopoll_free (content); + __nopoll_conn_opts_release_if_needed (options); + + return conn; + } + X509_free (server_cert); + + /* call to check post ssl checks after SSL finalization */ + if (conn->ctx && conn->ctx->post_ssl_check) { + if (! conn->ctx->post_ssl_check (conn->ctx, conn, conn->ssl_ctx, conn->ssl, conn->ctx->post_ssl_check_data)) { + /* TLS post check failed */ + nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "TLS/SSL post check function failed, dropping connection"); + nopoll_conn_shutdown (conn); + return NULL; + } /* end if */ + } /* end if */ + + /* configure default handlers */ + conn->receive = nopoll_conn_tls_receive; + conn->sends = nopoll_conn_tls_send; + + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "TLS I/O handlers configured"); + conn->tls_on = nopoll_true; + } /* end if */ + + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Sending websocket client init: %s", content); + size = strlen (content); + + /* call to send content */ + remaining_timeout = ctx->conn_connect_std_timeout; + while (remaining_timeout > 0) { + if (size != conn->sends (conn, content, size)) { + /* for some reason, under FreeBSD, a ENOTCONN is reported when they should be returning EINPROGRESS and/or EWOULDBLOCK */ + if (errno == NOPOLL_EWOULDBLOCK || errno == NOPOLL_EINPROGRESS || errno == NOPOLL_ENOTCONN) { + /* nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Connection in progress (errno=%d), session: %d", errno, session); */ + nopoll_sleep (10000); + remaining_timeout -= 10000; + continue; + } /* end if */ + + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to send websocket init message, error code was: %d (2), closing session", errno); + nopoll_conn_shutdown (conn); + } /* end if */ + + break; + } + + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Web socket initial client handshake sent"); + + /* release content */ + nopoll_free (content); + + /* release connection options */ + __nopoll_conn_opts_release_if_needed (options); + + /* return connection created */ + return conn; +} + + +/** + * @brief Creates a new Websocket connection to the provided + * destination, physically located at host_ip and host_port. + * + * @param ctx The noPoll context to which this new connection will be associated. + * + * @param host_ip The websocket server address to connect to. + * + * @param host_port The websocket server port to connect to. If NULL + * is provided, port 80 is used. + * + * @param host_name This is the Host: header value that will be + * sent. This header is used by the websocket server to activate the + * right virtual host configuration. If null is provided, Host: will + * use host_ip value. + * + * @param get_url As part of the websocket handshake, an url is passed + * to the remote server inside a GET method. This parameter allows to + * configure this. If NULL is provided, then / will be used. + * + * @param origin Websocket origin to be notified to the server. + * + * @param protocols Optional protocols requested to be activated for + * this connection (an string of list of strings separated by a white + * space). If the server accepts the connection you can use \ref + * nopoll_conn_get_accepted_protocol to get the protocol accepted by + * the server. + * + * @return A reference to the connection created or NULL if it + * fails. Keep in mind the connection reported may not be connected at + * the time is returned by this function. You can use \ref + * nopoll_conn_is_ready and \ref nopoll_conn_is_ok to ensure it can be + * used. There is also a helper function (NOTE it is blocking) that + * can help you implement a very simple wait until ready operation: + * \ref nopoll_conn_wait_until_connection_ready (however, it is not + * recommended for any serious, non-command line programming). + */ +noPollConn * nopoll_conn_new (noPollCtx * ctx, + const char * host_ip, + const char * host_port, + const char * host_name, + const char * get_url, + const char * protocols, + const char * origin) +{ + /* call common implementation */ + return __nopoll_conn_new_common (ctx, NULL, nopoll_false, + host_ip, host_port, host_name, + get_url, protocols, origin); +} + +/** + * @brief Creates a new Websocket connection to the provided + * destination, physically located at host_ip and host_port and + * allowing to provide a noPollConnOpts object. + * + * @param ctx The noPoll context to which this new connection will be associated. + * + * @param opts The connection options to use during the connection and + * the usage of this connection. + * + * @param host_ip The websocket server address to connect to. + * + * @param host_port The websocket server port to connect to. If NULL + * is provided, port 80 is used. + * + * @param host_name This is the Host: header value that will be + * sent. This header is used by the websocket server to activate the + * right virtual host configuration. If null is provided, Host: will + * use host_ip value. + * + * @param get_url As part of the websocket handshake, an url is passed + * to the remote server inside a GET method. This parameter allows to + * configure this. If NULL is provided, then / will be used. + * + * @param origin Websocket origin to be notified to the server. + * + * @param protocols Optional protocols requested to be activated for + * this connection (an string of list of strings separated by a white + * space). If the server accepts the connection you can use \ref + * nopoll_conn_get_accepted_protocol to get the protocol accepted by + * the server. + * + * @return A reference to the connection created or NULL if it + * fails. Keep in mind the connection reported may not be connected at + * the time is returned by this function. You can use \ref + * nopoll_conn_is_ready and \ref nopoll_conn_is_ok to ensure it can be + * used. There is also a helper function (NOTE it is blocking) that + * can help you implement a very simple wait until ready operation: + * \ref nopoll_conn_wait_until_connection_ready (however, it is not + * recommended for any serious, non-command line programming). + */ +noPollConn * nopoll_conn_new_opts (noPollCtx * ctx, + noPollConnOpts * opts, + const char * host_ip, + const char * host_port, + const char * host_name, + const char * get_url, + const char * protocols, + const char * origin) +{ + /* call common implementation */ + return __nopoll_conn_new_common (ctx, opts, nopoll_false, + host_ip, host_port, host_name, + get_url, protocols, origin); +} + +nopoll_bool __nopoll_tls_was_init = nopoll_false; + +/** + * @brief Allows to create a client WebSocket connection over TLS. + * + * The function works like nopoll_tls_conn_new with the same semantics + * but providing a way to create a WebSocket session under the + * supervision of TLS. + * + * @param ctx The context where the operation will take place. + * + * @param options Optional configuration object. See \ref nopoll_conn_opts_new and \ref nopoll_conn_opts_set_ssl_protocol (for example). + * + * @param host_ip The websocket server address to connect to. + * + * @param host_port The websocket server port to connect to. If NULL + * is provided, port 443 is used. + * + * @param host_name This is the Host: header value that will be + * sent. This header is used by the websocket server to activate the + * right virtual host configuration. If null is provided, Host: will + * use host_ip value. + * + * @param get_url As part of the websocket handshake, an url is passed + * to the remote server inside a GET method. This parameter allows to + * configure this. If NULL is provided, then / will be used. + * + * @param origin Websocket origin to be notified to the server. + * + * @param protocols Optional protocols requested to be activated for + * this connection (an string of list of strings separated by a white + * space). If the server accepts the connection you can use \ref + * nopoll_conn_get_accepted_protocol to get the protocol accepted by + * the server. + * + * @return A reference to the connection created or NULL if it + * fails. Keep in mind the connection reported may not be connected at + * the time is returned by this function. You can use \ref + * nopoll_conn_is_ready and \ref nopoll_conn_is_ok to ensure it can be + * used. There is also a helper function (NOTE it is blocking) that + * can help you implement a very simple wait until ready operation: + * \ref nopoll_conn_wait_until_connection_ready (however, it is not + * recommended for any serious, non-command line programming). + * + */ +noPollConn * nopoll_conn_tls_new (noPollCtx * ctx, + noPollConnOpts * options, + const char * host_ip, + const char * host_port, + const char * host_name, + const char * get_url, + const char * protocols, + const char * origin) +{ + /* init ssl ciphers and engines */ + if (! __nopoll_tls_was_init) { + __nopoll_tls_was_init = nopoll_true; + SSL_library_init (); + } /* end if */ + + /* call common implementation */ + return __nopoll_conn_new_common (ctx, options, nopoll_true, + host_ip, host_port, host_name, + get_url, protocols, origin); +} + +/** + * @brief Allows to acquire a reference to the provided connection. + * + * @param conn The conection to be referenced + * + * @return nopoll_true In the case the function acquired a reference + * otherwise nopoll_false is returned. + */ +nopoll_bool nopoll_conn_ref (noPollConn * conn) +{ + if (conn == NULL) + return nopoll_false; + + /* lock the mutex */ + nopoll_mutex_lock (conn->ref_mutex); + if (conn->refs <= 0) { + /* unlock the mutex */ + nopoll_mutex_unlock (conn->ref_mutex); + return nopoll_false; + } + + conn->refs++; + + /* release here the mutex */ + nopoll_mutex_unlock (conn->ref_mutex); + + return nopoll_true; +} + +/** + * @brief Allows to get current reference counting state for the + * provided connection. + * + * @param conn The connection queried for its reference counting. + * + * @return The reference counting or -1 if it fails. + */ +int nopoll_conn_ref_count (noPollConn * conn) +{ + if (! conn) + return -1; + return conn->refs; +} + +/** + * @brief Allows to check if the provided connection is in connected + * state (just to the connection). This is different to be ready to send and receive content + * because the session needs to be first established. + * + * You can use \ref nopoll_conn_is_ready to ensure the connection is + * ready to be used (read or write operation can be done because + * handshake has finished). + * + * For example, you might connect to a raw socket server and + * nopoll_conn_is_ok will report that everything is ok because the + * socket is indeed connected but because you are connecting to a + * non-websocket server, it will not work because the WebSocket + * session establishment didn't take place and hence + * nopoll_conn_is_ready will fail. + * + * Please, see the following link for a complete example that connects + * and ensure the connection is ready (for a client): http://www.aspl.es/nopoll/html/nopoll_core_library_manual.html#creating_basic_web_socket_client + * + * @param conn The websocket connection to be checked. + * + * @return nopoll_true in the case the connection is working otherwise + * nopoll_false is returned. + */ +nopoll_bool nopoll_conn_is_ok (noPollConn * conn) +{ + if (conn == NULL) + return nopoll_false; + + /* return current socket status */ + return conn->session != NOPOLL_INVALID_SOCKET; +} + +/** + * @brief Allows to check if the connection is ready to be used + * (handshake completed). + * + * @param conn The connection to be checked. + * + * @return nopoll_true in the case the handshake was completed + * otherwise nopoll_false is returned. The function also returns + * nopoll_false in case \ref nopoll_conn_is_ok is failing. + */ +nopoll_bool nopoll_conn_is_ready (noPollConn * conn) +{ + if (conn == NULL) + return nopoll_false; + if (conn->session == NOPOLL_INVALID_SOCKET) + return nopoll_false; + if (! conn->handshake_ok) { + /* acquire here handshake mutex */ + nopoll_mutex_lock (conn->ref_mutex); + + /* complete handshake */ + nopoll_conn_complete_handshake (conn); + + /* release here handshake mutex */ + nopoll_mutex_unlock (conn->ref_mutex); + } + return conn->handshake_ok; +} + +/** + * @brief Allows to check if the provided connection is working under a TLS session. + * + * @param conn The connection where the TLS is being queired to be enabled. + * + * @return nopoll_true in the case TLS is enabled, otherwise* nopoll_false is returned. Note the function also returns* nopoll_false when the reference received is NULL. + */ +nopoll_bool nopoll_conn_is_tls_on (noPollConn * conn) +{ + if (! conn) + return nopoll_false; + + /* return TLS on */ + return conn->tls_on; +} + +/** + * @brief Allows to get the socket associated to this nopoll + * connection. + * + * @return The socket reference or -1 if it fails. + */ +NOPOLL_SOCKET nopoll_conn_socket (noPollConn * conn) +{ + if (conn == NULL) + return -1; + return conn->session; +} + +/** + * @brief Allows to set up the socket reference to be used by this + * noPollConn. + * + * @param conn The connection to setup with a new socket. + * + * @param _socket The socket that will be configured. + */ +void nopoll_conn_set_socket (noPollConn * conn, NOPOLL_SOCKET _socket) +{ + if (conn == NULL) + return; + conn->session = _socket; + return; +} + +/** + * @brief Allows to get the connection id from the provided + * connection. + * + * @param conn The connection from where the unique identifier will be + * returned. + * + * @return The identifier or -1 if it fails. + */ +int nopoll_conn_get_id (noPollConn * conn) +{ + if (conn == NULL) + return -1; + return conn->id; +} + +/** + * @brief Allows to get the noPollCtx context object associated to the + * connection (or where the connection is working). + * + * @param conn The connection that is requested to return its context. + * + * @return A reference to the context or NULL if it fails. + */ +noPollCtx * nopoll_conn_ctx (noPollConn * conn) +{ + if (conn == NULL) + return NULL; + return conn->ctx; +} + +/** + * @brief Allows to get the connection role. + * + * @return The connection role, see \ref noPollRole for details. + */ +noPollRole nopoll_conn_role (noPollConn * conn) +{ + if (conn == NULL) + return NOPOLL_ROLE_UNKNOWN; + return conn->role; +} + +/** + * @brief Returns the host location this connection connects to or it is + * listening (according to the connection role \ref noPollRole). + * + * If you are looking for a way to get the Host: header value received + * for this connection during the handshake, use: \ref + * nopoll_conn_get_host_header. + * + * @param conn The connection to check for the host value. + * + * @return The host location value or NULL if it fails. + */ +const char * nopoll_conn_host (noPollConn * conn) +{ + if (conn == NULL) + return NULL; + return conn->host; +} + +/** + * @brief Allows to get the connection Origin header content received. + * + * @param conn The websocket connection where the operation takes place. + * + * @return The Origin value received during the handshake for this + * connection or NULL if it fails to get this value. + */ +const char * nopoll_conn_get_origin (noPollConn * conn) +{ + if (conn == NULL || conn->handshake == NULL) + return NULL; + return conn->origin; +} /* end if */ + +/** + * @brief Allows to get the Host: header value that was received for + * this connection during the handshake. + * + * @param conn The websocket connection where the operation takes place. + * + * @return The Host value received during the handshake for this + * connection or NULL if it fails to get this value (or it wasn't + * defined). + */ +const char * nopoll_conn_get_host_header (noPollConn * conn) +{ + if (conn == NULL || conn->host_name == NULL) + return NULL; + return conn->host_name; +} + +/** + * @brief Allows to get cookie header content received during + * handshake (if received). + * + * @param conn The websocket connection where the operation takes place. + * + * @return A reference to the cookie value or NULL if nothing is + * configured or if failed to get it. + */ +const char * nopoll_conn_get_cookie (noPollConn * conn) +{ + + if (conn == NULL || conn->handshake == NULL) + return NULL; + return conn->handshake->cookie; +} + +/** + * @brief Allows to get accepted protocol in the case a protocol was + * requested during connection. + * + * @param conn The connection where the operation is taking place. + * + * @return A reference to the protocol accepted or NULL if no protocol + * was mentioned during the handshake. + */ +const char * nopoll_conn_get_accepted_protocol (noPollConn * conn) +{ + if (conn == NULL) + return NULL; + return conn->accepted_protocol; /* report accepted protocol */ +} + +/** + * @brief Allows to get requested protocols for the provided + * connection + * + * @param conn The connection where the operation is taking place. + * + * @return A reference to the protocol or list of protocols requested + * by this connection. + */ +const char * nopoll_conn_get_requested_protocol (noPollConn * conn) +{ + if (conn == NULL) + return NULL; + return conn->protocols; /* report requested protocol */ +} + +/** + * @brief Allows to configure accepted protocol on the provided + * connection. + * + * @param conn The connection where the accepted protocol will be + * notified. This function is only useful at server side to notify + * accepted protocol to the connecting client. Caller is entirely + * responsible on setting an appropriate value that is understood by + * the client. No especial check is done on the value provided to this function. + * + * @param protocol The protocol to configure in the reply, that is, + * the protocol accepted by the server. + * + * If no protocol is configured and the client requests a protocol, + * the server will reply by default the same accepting it. + */ +void nopoll_conn_set_accepted_protocol (noPollConn * conn, const char * protocol) +{ + if (conn == NULL || protocol == NULL) + return; + + /* set accepted protocol */ + conn->accepted_protocol = nopoll_strdup (protocol); + return; +} + +/** + * @brief Returns the port location this connection connects to or it + * is listening (according to the connection role \ref noPollRole). + * + * @param conn The connection to check for the port value. + * + * @return The port location value or NULL if it fails. + */ +const char * nopoll_conn_port (noPollConn * conn) +{ + if (conn == NULL) + return NULL; + return conn->port; +} + +/** + * @brief Optionally, remote peer can close the connection providing an + * error code (\ref nopoll_conn_get_close_status) and a reason (\ref nopoll_conn_get_close_reason). + * + * These functions are used to get those values. + * + * @param conn The connection where the peer reported close status is being asked. + * + * @return Status code reported by the remote peer or 0 if nothing was reported. + */ +int nopoll_conn_get_close_status (noPollConn * conn) +{ + if (conn == NULL) + return 0; + return conn->peer_close_status; +} + +/** + * @brief Optionally, remote peer can close the connection providing an + * error code (\ref nopoll_conn_get_close_status) and a reason (\ref nopoll_conn_get_close_reason). + * + * These functions are used to get those values. + * + * @param conn The connection where the peer reported close reason is being asked. + * + * @return Status close reason reported by the remote peer or NULL if nothing was reported. + */ +const char * nopoll_conn_get_close_reason (noPollConn * conn) +{ + if (conn == NULL) + return NULL; + return conn->peer_close_reason; +} + +/** + * @brief Call to close the connection immediately without going + * through websocket close negotiation. + * + * @param conn The connection to be shutted down. + */ +void nopoll_conn_shutdown (noPollConn * conn) +{ +#if defined(SHOW_DEBUG_LOG) + const char * role = NULL; +#endif + + if (conn == NULL) + return; + + /* report connection close */ +#if defined(SHOW_DEBUG_LOG) + if (conn->role == NOPOLL_ROLE_LISTENER) + role = "listener"; + else if (conn->role == NOPOLL_ROLE_MAIN_LISTENER) + role = "master-listener"; + else if (conn->role == NOPOLL_ROLE_UNKNOWN) + role = "unknown"; + else if (conn->role == NOPOLL_ROLE_CLIENT) + role = "client"; + else + role = "unknown"; + + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "shutting down connection id=%d (session: %d, role: %s)", + conn->id, conn->session, role); +#endif + + /* call to on close handler if defined */ + if (conn->session != NOPOLL_INVALID_SOCKET && conn->on_close) + conn->on_close (conn->ctx, conn, conn->on_close_data); + + /* shutdown connection here */ + if (conn->session != NOPOLL_INVALID_SOCKET) { + shutdown (conn->session, SHUT_RDWR); + nopoll_close_socket (conn->session); + } + conn->session = NOPOLL_INVALID_SOCKET; + + return; +} + +/** + * @brief Allows to close an opened \ref noPollConn no matter its role + * (\ref noPollRole). + * + * @param conn The connection to close. + * + * @param status Optional status code to send to remote side. If + * status is < 0, no status code is sent. + * + * @param reason Pointer to the content to be sent. + * + * @param reason_size The amount of bytes that should be used from content pointer. + */ +void nopoll_conn_close_ext (noPollConn * conn, int status, const char * reason, int reason_size) +{ + int refs; + char * content; +#if defined(SHOW_DEBUG_LOG) + const char * role = "unknown"; +#endif + + /* check input data */ + if (conn == NULL) + return; + +#if defined(SHOW_DEBUG_LOG) + if (conn->role == NOPOLL_ROLE_LISTENER) + role = "listener"; + else if (conn->role == NOPOLL_ROLE_MAIN_LISTENER) + role = "master-listener"; + else if (conn->role == NOPOLL_ROLE_UNKNOWN) + role = "unknown"; + else if (conn->role == NOPOLL_ROLE_CLIENT) + role = "client"; + + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Calling to close close id=%d (session %d, refs: %d, role: %s)", + conn->id, conn->session, conn->refs, role); +#endif + if (conn->session != NOPOLL_INVALID_SOCKET) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "requested proper connection close id=%d (session %d)", conn->id, conn->session); + + /* build reason indication */ + content = NULL; + if (reason && reason_size > 0) { + /* send content */ + content = nopoll_new (char, reason_size + 3); + if (content) { + nopoll_set_16bit (status, content); + memcpy (content + 2, reason, reason_size); + } /* end if */ + } /* end if */ + + /* send close without reason */ + nopoll_conn_send_frame (conn, nopoll_true /* has_fin */, + /* masked */ + conn->role == NOPOLL_ROLE_CLIENT, NOPOLL_CLOSE_FRAME, + /* content size and content */ + reason_size > 0 ? reason_size + 2 : 0, content, + /* sleep in header */ + 0); + + /* release content (if defined) */ + nopoll_free (content); + + /* call to shutdown connection */ + nopoll_conn_shutdown (conn); + } /* end if */ + + /* unregister connection from context */ + refs = nopoll_conn_ref_count (conn); + nopoll_ctx_unregister_conn (conn->ctx, conn); + + /* avoid calling next unref in the case not enough references + * are found */ + if (refs <= 1) + return; + + /* call to unref connection */ + nopoll_conn_unref (conn); + + return; +} + +/** + * @brief Allows to close an opened \ref noPollConn no matter its role + * (\ref noPollRole). + * + * @param conn The connection to close. + * + * There is available an alternative extended version that allows to + * send the status code and the error message: \ref + * nopoll_conn_close_ext + */ +void nopoll_conn_close (noPollConn * conn) +{ + /* call to close without providing a reason */ + nopoll_conn_close_ext (conn, 0, NULL, 0); + return; +} + +/** + * @brief Allows to define a user level pointer associated to this + * connection. This pointer can be later be retrieved using \ref + * nopoll_conn_get_hook. + * + * @param conn The connection where the pointer will be associated. + * + * @param ptr The pointer to associate to the connection. + */ +void nopoll_conn_set_hook (noPollConn * conn, noPollPtr ptr) +{ + if (conn == NULL) + return; + conn->hook = ptr; + return; +} + + +/** + * @brief Allows to get the user level pointer defined by \ref + * nopoll_conn_get_hook. + * + * @param conn The connection where the uesr level pointer was stored. + * + * @return A reference to the pointer stored. + */ +noPollPtr nopoll_conn_get_hook (noPollConn * conn) +{ + if (conn == NULL) + return NULL; + return conn->hook; +} + +/** + * @brief Allows to unref connection reference acquired via \ref + * nopoll_conn_ref. + * + * @param conn The connection to be unrefered. + */ +void nopoll_conn_unref (noPollConn * conn) +{ + if (conn == NULL) + return; + + /* acquire here the mutex */ + nopoll_mutex_lock (conn->ref_mutex); + + conn->refs--; + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Releasing connection id %d reference, current ref count status is: %d", + conn->id, conn->refs); + if (conn->refs != 0) { + /* release here the mutex */ + nopoll_mutex_unlock (conn->ref_mutex); + return; + } + /* release here the mutex */ + nopoll_mutex_unlock (conn->ref_mutex); + + /* release message */ + if (conn->pending_msg) + nopoll_msg_unref (conn->pending_msg); + + /* release ctx */ + if (conn->ctx) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Released context refs, now: %d", conn->ctx->refs); + nopoll_ctx_unref (conn->ctx); + } /* end if */ + conn->ctx = NULL; + + /* free all internal strings */ + nopoll_free (conn->host); + nopoll_free (conn->port); + nopoll_free (conn->host_name); + nopoll_free (conn->origin); + nopoll_free (conn->protocols); + nopoll_free (conn->accepted_protocol); + nopoll_free (conn->get_url); + + /* close reason if any */ + nopoll_free (conn->peer_close_reason); + + /* release TLS certificates */ + nopoll_free (conn->certificate); + nopoll_free (conn->private_key); + nopoll_free (conn->chain_certificate); + + /* release uncomplete message */ + if (conn->previous_msg) + nopoll_msg_unref (conn->previous_msg); + + if (conn->ssl) + SSL_free (conn->ssl); + if (conn->ssl_ctx) + SSL_CTX_free (conn->ssl_ctx); + + /* release handshake internal data */ + if (conn->handshake) { + nopoll_free (conn->handshake->websocket_key); + nopoll_free (conn->handshake->websocket_version); + nopoll_free (conn->handshake->websocket_accept); + nopoll_free (conn->handshake->expected_accept); + nopoll_free (conn->handshake->cookie); + nopoll_free (conn->handshake); + } /* end if */ + + /* release connection options if defined and reuse flag is not defined */ + if (conn->opts && ! conn->opts->reuse) + nopoll_conn_opts_free (conn->opts); + + /* release pending write buffer */ + nopoll_free (conn->pending_write); + + /* release mutex */ + nopoll_mutex_destroy (conn->ref_mutex); + + nopoll_free (conn); + + return; +} + +/** + * @internal Default connection receive until handshake is complete. + */ +int nopoll_conn_default_receive (noPollConn * conn, char * buffer, int buffer_size) +{ + return recv (conn->session, buffer, buffer_size, 0); +} + +/** + * @internal Default connection send until handshake is complete. + */ +int nopoll_conn_default_send (noPollConn * conn, char * buffer, int buffer_size) +{ + return send (conn->session, buffer, buffer_size, 0); +} + +/** + * @internal Read the next line, byte by byte until it gets a \n or + * maxlen is reached. Some code errors are used to manage exceptions + * (see return values) + * + * @param connection The connection where the read operation will be done. + * + * @param buffer A buffer to store content read from the network. + * + * @param maxlen max content to read from the network. + * + * @return values returned by this function follows: + * 0 - remote peer have closed the connection + * -1 - an error have happened while reading + * -2 - could read because this connection is on non-blocking mode and there is no data. + * n - some data was read. + * + **/ +int nopoll_conn_readline (noPollConn * conn, char * buffer, int maxlen) +{ + int n, rc; + int desp; + char c, *ptr; +#if defined(SHOW_DEBUG_LOG) +# if !defined(SHOW_FORMAT_BUGS) + noPollCtx * ctx = conn->ctx; +# endif +#endif + + /* clear the buffer received */ + /* memset (buffer, 0, maxlen * sizeof (char )); */ + + /* check for pending line read */ + desp = 0; + if (conn->pending_line) { + /* get size and check exceeded values */ + desp = strlen (conn->pending_line); + if (desp >= maxlen) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, + "found fragmented frame line header but allowed size was exceeded (desp:%d >= maxlen:%d)", + desp, maxlen); + nopoll_conn_shutdown (conn); + return -1; + } /* end if */ + + /* now store content into the buffer */ + memcpy (buffer, conn->pending_line, desp); + + /* clear from the conn the line */ + nopoll_free (conn->pending_line); + conn->pending_line = NULL; + } + + /* read current next line */ + ptr = (buffer + desp); + for (n = 1; n < (maxlen - desp); n++) { + nopoll_readline_again: + if (( rc = conn->receive (conn, &c, 1)) == 1) { + *ptr++ = c; + if (c == '\x0A') + break; + }else if (rc == 0) { + if (n == 1) + return 0; + else + break; + } else { + if (errno == NOPOLL_EINTR) + goto nopoll_readline_again; + if ((errno == NOPOLL_EWOULDBLOCK) || (errno == NOPOLL_EAGAIN) || (rc == -2)) { + if (n > 0) { + /* store content read until now */ + if ((n + desp - 1) > 0) { + buffer[n+desp - 1] = 0; + conn->pending_line = nopoll_strdup (buffer); + } /* end if */ + } /* end if */ + return -2; + } + + if (nopoll_conn_is_ok (conn) && errno == 0 && rc == 0) { + nopoll_log (ctx, NOPOLL_LEVEL_WARNING, "unable to read line, but errno is 0, and connection is ok, return to keep on trying.."); + return -2; + } + + /* if the conn is closed, just return + * without logging a message */ + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "unable to read line, error code errno: %d, rc: %d (%s)", + errno, rc, strerror (errno)); + return (-1); + } + } + *ptr = 0; + return (n + desp); + +} + +/** + * @brief Allows to get the master listener that was used to accept + * the provided connection that represents a listener connection. + * + * @param conn A listener connection that was accepted for which we + * want to get the master listener connection. The connection must be + * a \ref NOPOLL_ROLE_LISTENER (as reported by \ref nopoll_conn_role). + * + * @return A reference to the master listener connection or NULL if it + * fails. It can only fail when NULL reference is received or the + * connection is not a \ref NOPOLL_ROLE_LISTENER. + */ +noPollConn * nopoll_conn_get_listener (noPollConn * conn) +{ + /* check if the incoming connection is a NOPOLL_ROLE_LISTENER + * that is an accepted connection */ + if (conn == NULL || conn->role != NOPOLL_ROLE_LISTENER) + return NULL; + + return conn->listener; +} + +void __nopoll_pack_content (char * buffer, int start, int bytes) +{ + int iterator = 0; + while (iterator < bytes) { + /* copy bytes to the begining of the array */ + buffer[iterator] = buffer[start + iterator]; + + /* next position */ + iterator++; + } /* end while */ + + return; +} + +/** + * @internal Function used to read bytes from the wire. + * + * @return The function returns the number of bytes read, 0 when no + * bytes were available and -1 when it fails. + */ +int __nopoll_conn_receive (noPollConn * conn, char * buffer, int maxlen) +{ + int nread; + + if (conn->pending_buf_bytes > 0) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Calling with bytes we can reuse (%d), requested: %d", + conn->pending_buf_bytes, maxlen); + + if (conn->pending_buf_bytes >= maxlen) { + /* we have more in the buffer to serve than + * requested, ok, copy into the buffer and + * pack */ + + memcpy (buffer, conn->pending_buf, maxlen); + __nopoll_pack_content (conn->pending_buf, maxlen, conn->pending_buf_bytes - maxlen); + conn->pending_buf_bytes -= maxlen; + return maxlen; + } + + /* ok, we don't have enough bytes to serve + * directly, so copy what we have */ + memcpy (buffer, conn->pending_buf, conn->pending_buf_bytes); + + /* copy number of bytes served to reduce next request */ + nread = conn->pending_buf_bytes; + conn->pending_buf_bytes = 0; + + /* call again to get bytes reducing the request in the + * amount of bytes served */ + return __nopoll_conn_receive (conn, buffer + nread, maxlen - nread) + nread; + + } /* end if */ + + keep_reading: + /* clear buffer */ + /* memset (buffer, 0, maxlen * sizeof (char )); */ +#if defined(NOPOLL_OS_UNIX) + errno = 0; +#endif + if ((nread = conn->receive (conn, buffer, maxlen)) == NOPOLL_SOCKET_ERROR) { + /* nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, " returning errno=%d (%s)", errno, strerror (errno)); */ + if (errno == NOPOLL_EAGAIN) + return 0; + if (errno == NOPOLL_EWOULDBLOCK) + return 0; + if (errno == NOPOLL_EINTR) + goto keep_reading; + + nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "unable to readn=%d, error code was: %d (%s) (shutting down connection)", maxlen, errno, strerror (errno)); + nopoll_conn_shutdown (conn); + return -1; + } + + /* nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, " returning bytes read = %d", nread); */ + if (nread == 0) { + /* check for blocking operations */ + if (errno == NOPOLL_EAGAIN || errno == NOPOLL_EWOULDBLOCK) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "unable to read from conn-id=%d (%s:%s), connection is not ready (errno: %d : %s)", + conn->id, conn->host, conn->port, errno, strerror (errno)); + return 0; + } /* end if */ + + nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "received connection close while reading from conn id %d (errno=%d : %s) (%d, %d, %d), shutting down connection..", + conn->id, errno, strerror (errno), + NOPOLL_EAGAIN, NOPOLL_EWOULDBLOCK, NOPOLL_EINTR); + nopoll_conn_shutdown (conn); + } /* end if */ + + /* ensure we don't access outside the array */ + if (nread < 0) + nread = 0; + + buffer[nread] = 0; + return nread; +} + +nopoll_bool nopoll_conn_get_http_url (noPollConn * conn, const char * buffer, int buffer_size, const char * method, char ** url) +{ + int iterator; + int iterator2; +#if defined(SHOW_DEBUG_LOG) +# if ! defined(SHOW_FORMAT_BUGS) + noPollCtx * ctx = conn->ctx; +# endif +#endif + + /* check if we already received method */ + if (conn->get_url) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Received GET method declartion when it was already received during handshake..closing session"); + nopoll_conn_shutdown (conn); + return nopoll_false; + } /* end if */ + + /* the get url must have a minimum size: GET / HTTP/1.1\r\n 16 (15 if only \n) */ + if (buffer_size < 15) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Received uncomplete GET method during handshake, closing session"); + nopoll_conn_shutdown (conn); + return nopoll_false; + } /* end if */ + + /* skip white spaces */ + iterator = 4; + while (iterator < buffer_size && buffer[iterator] == ' ') + iterator++; + if (buffer_size == iterator) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Received a %s method without an starting request url, closing session", method); + nopoll_conn_shutdown (conn); + return nopoll_false; + } /* end if */ + + /* now check url format */ + if (buffer[iterator] != '/') { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Received a %s method with a request url that do not start with /, closing session", method); + nopoll_conn_shutdown (conn); + return nopoll_false; + } + + /* ok now find the rest of the url content util the next white space */ + iterator2 = (iterator + 1); + while (iterator2 < buffer_size && buffer[iterator2] != ' ') + iterator2++; + if (buffer_size == iterator2) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Received a %s method with an uncomplate request url, closing session", method); + nopoll_conn_shutdown (conn); + return nopoll_false; + } /* end if */ + + (*url) = nopoll_new (char, iterator2 - iterator + 1); + memcpy (*url, buffer + iterator, iterator2 - iterator); + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Found url method: '%s'", *url); + + /* now check final HTTP header */ + iterator = iterator2 + 1; + while (iterator < buffer_size && buffer[iterator] == ' ') + iterator++; + if (buffer_size == iterator) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Received a %s method with an uncomplate request url, closing session", method); + nopoll_conn_shutdown (conn); + return nopoll_false; + } /* end if */ + + /* now check trailing content */ + return nopoll_cmp (buffer + iterator, "HTTP/1.1\r\n") || nopoll_cmp (buffer + iterator, "HTTP/1.1\n"); +} + +/** + * @internal Function that parses the mime header found on the + * provided buffer. + */ +nopoll_bool nopoll_conn_get_mime_header (noPollCtx * ctx, noPollConn * conn, const char * buffer, int buffer_size, char ** header, char ** value) +{ + int iterator = 0; + int iterator2 = 0; + + /* nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Processing content: %s", buffer); */ + + /* ok, find the first : */ + while (iterator < buffer_size && buffer[iterator] && buffer[iterator] != ':') + iterator++; + if (buffer[iterator] != ':') { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Expected to find mime header separator : but it wasn't found (buffer_size=%d, iterator=%d, content: [%s]..", + buffer_size, iterator, buffer); + return nopoll_false; + } + + /* copy the header value */ + (*header) = nopoll_new (char, iterator + 1); + memcpy (*header, buffer, iterator); + + /* now get the mime header value */ + iterator2 = iterator + 1; + while (iterator2 < buffer_size && buffer[iterator2] && buffer[iterator2] != '\n') + iterator2++; + if (buffer[iterator2] != '\n') { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, + "Expected to find mime header value end (13) but it wasn't found (iterator=%d, iterator2=%d, for header: [%s], found value: [%d]), inside content: [%s]..", + iterator, iterator2, (*header), (int)buffer[iterator2], buffer); + nopoll_free (*header); + (*header) = NULL; + (*value) = NULL; + return nopoll_false; + } + + /* copy the value */ + (*value) = nopoll_new (char, (iterator2 - iterator) + 1); + memcpy (*value, buffer + iterator + 1, iterator2 - iterator); + + /* trim content */ + nopoll_trim (*value, NULL); + nopoll_trim (*header, NULL); + + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Found MIME header: '%s' -> '%s'", *header, *value); + return nopoll_true; +} + +/** + * @internal Function that ensures we don't receive any + */ +nopoll_bool nopoll_conn_check_mime_header_repeated (noPollConn * conn, + char * header, + char * value, + const char * ref_header, + noPollPtr check) +{ + if (strcasecmp (ref_header, header) == 0) { + if (check) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Provided header %s twice, closing connection", header); + nopoll_free (header); + nopoll_free (value); + nopoll_conn_shutdown (conn); + return nopoll_true; + } /* end if */ + } /* end if */ + return nopoll_false; +} + +char * nopoll_conn_produce_accept_key (noPollCtx * ctx, const char * websocket_key) +{ + const char * static_guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + char * accept_key; + int accept_key_size; + int key_length; + + if (websocket_key == NULL) + return NULL; + + key_length = strlen (websocket_key); + + unsigned char buffer[EVP_MAX_MD_SIZE]; + EVP_MD_CTX mdctx; + const EVP_MD * md = NULL; + unsigned int md_len = EVP_MAX_MD_SIZE; + + accept_key_size = key_length + 36 + 1; + accept_key = nopoll_new (char, accept_key_size); + + memcpy (accept_key, websocket_key, key_length); + memcpy (accept_key + key_length, static_guid, 36); + + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "base key value: %s", accept_key); + + /* now sha-1 */ + md = (EVP_MD *)EVP_sha1 (); + EVP_DigestInit (&mdctx, md); + EVP_DigestUpdate (&mdctx, accept_key, strlen (accept_key)); + EVP_DigestFinal (&mdctx, buffer, &md_len); + + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Sha-1 length is: %u", md_len); + /* now convert into base64 */ + if (! nopoll_base64_encode ((const char *) buffer, md_len, (char *) accept_key, &accept_key_size)) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to base64 sec-websocket-key value.."); + return NULL; + } + + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Returning Sec-Websocket-Accept: %s", accept_key); + + return accept_key; + +} + +nopoll_bool nopoll_conn_complete_handshake_check_listener (noPollCtx * ctx, noPollConn * conn) +{ + char * reply; + int reply_size; + char * accept_key; + noPollActionHandler on_ready; + noPollPtr on_ready_data; + const char * protocol; + + /* call to check listener handshake */ + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Checking client handshake data.."); + + /* ensure we have all minumum data */ + if (! conn->handshake->upgrade_websocket || + ! conn->handshake->connection_upgrade || + ! conn->handshake->websocket_key || + ! conn->origin || + ! conn->handshake->websocket_version) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Client from %s:%s didn't provide all websocket handshake values required, closing session (Upgraded: websocket %d, Connection: upgrade%d, Sec-WebSocket-Key: %p, Origin: %p, Sec-WebSocket-Version: %p)", + conn->host, conn->port, + conn->handshake->upgrade_websocket, + conn->handshake->connection_upgrade, + conn->handshake->websocket_key, + conn->origin, + conn->handshake->websocket_version); + return nopoll_false; + } /* end if */ + + /* check protocol support */ + if (strtol (conn->handshake->websocket_version, NULL, 10) != ctx->protocol_version) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Received request for an unsupported protocol version: %s, expected: %d", + conn->handshake->websocket_version, ctx->protocol_version); + return nopoll_false; + } /* end if */ + + /* now call the user app level to accept the websocket + connection */ + if (ctx->on_open) { + if (! ctx->on_open (ctx, conn, ctx->on_open_data)) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Client from %s:%s was denied by application level (on open handler %p), clossing session", + conn->host, conn->port, ctx->on_open); + nopoll_conn_shutdown (conn); + return nopoll_false; + } + } /* end if */ + + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Client from %s:%s was accepted, replying accept", + conn->host, conn->port); + + /* produce accept key */ + accept_key = nopoll_conn_produce_accept_key (ctx, conn->handshake->websocket_key); + + /* ok, send handshake reply */ + if (conn->protocols || conn->accepted_protocol) { + /* set protocol in the reply taking preference by the + value configured at conn->accepted_protocol */ + protocol = conn->accepted_protocol; + if (! protocol) + protocol = conn->protocols; + + /* send accept header accepting protocol requested by the user */ + reply = nopoll_strdup_printf ("HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: %s\r\nSec-WebSocket-Protocol: %s\r\n\r\n", + accept_key, protocol); + } else { + /* send accept header without telling anything about protocols */ + reply = nopoll_strdup_printf ("HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: %s\r\n\r\n", + accept_key); + } + + nopoll_free (accept_key); + if (reply == NULL) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Unable to build reply, closing session"); + return nopoll_false; + } /* end if */ + + reply_size = strlen (reply); + if (reply_size != conn->sends (conn, reply, reply_size)) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Unable to send reply, there was a failure, error code was: %d", errno); + nopoll_free (reply); + return nopoll_false; + } /* end if */ + + /* free reply */ + nopoll_free (reply); + + /* now call the user app level to accept the websocket + connection */ + if (ctx->on_ready || conn->on_ready) { + /* set on ready handler, first considering conn->on_ready and then ctx->on_ready */ + on_ready = conn->on_ready; + on_ready_data = conn->on_ready_data; + if (! on_ready) { + on_ready = ctx->on_ready; + on_ready_data = ctx->on_ready_data; + } /* end if */ + + if (on_ready && ! on_ready (ctx, conn, on_ready_data)) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Client from %s:%s was denied by application level (on ready handler: %p), clossing session", + conn->host, conn->port, on_ready); + nopoll_conn_shutdown (conn); + return nopoll_false; + } + } /* end if */ + + return nopoll_true; /* signal handshake was completed */ +} + +nopoll_bool nopoll_conn_complete_handshake_check_client (noPollCtx * ctx, noPollConn * conn) +{ + char * accept; + nopoll_bool result; + + /* check all data received */ + if (! conn->handshake->websocket_accept || + ! conn->handshake->upgrade_websocket || + ! conn->handshake->connection_upgrade) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Received uncomplete listener handshake reply (%p %d %d)", + conn->handshake->websocket_accept, conn->handshake->upgrade_websocket, conn->handshake->connection_upgrade); + return nopoll_false; + } /* end if */ + + /* check accept value here */ + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Checking accept key from listener.."); + accept = nopoll_conn_produce_accept_key (ctx, conn->handshake->websocket_key); + + result = nopoll_cmp (accept, conn->handshake->websocket_key); + if (! result) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Unable to accept connection Sec-Websocket-Accept %s is not expected %s, closing session", + accept, conn->handshake->websocket_key); + nopoll_conn_shutdown (conn); + } + nopoll_free (accept); + + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Sec-Websocket-Accept matches expected value..nopoll_conn_complete_handshake_check_client (%p, %p)=%d", + ctx, conn, result); + + return result; +} + + +/** + * @internal Function used to validate all handshake received until + * now. + */ +void nopoll_conn_complete_handshake_check (noPollConn * conn) +{ + noPollCtx * ctx = conn->ctx; + nopoll_bool result = nopoll_false; + + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "calling to check handshake received on connection id %d role %d..", + conn->id, conn->role); + + if (conn->role == NOPOLL_ROLE_LISTENER) { + result = nopoll_conn_complete_handshake_check_listener (ctx, conn); + } else if (conn->role == NOPOLL_ROLE_CLIENT) { + result = nopoll_conn_complete_handshake_check_client (ctx, conn); + } /* end if */ + + /* flag connection as ready: now we can get messages */ + if (result) { + conn->handshake_ok = nopoll_true; + } else { + nopoll_conn_shutdown (conn); + } /* end if */ + + return; +} + +/** + * @internal Handler that implements one step of the websocket + * listener handshake received from client, until it is completed. + * + * @return Returns 0 to return (because error or because no data is + * available) or 1 to signal the caller continue reading if it is + * possible. + */ +int nopoll_conn_complete_handshake_listener (noPollCtx * ctx, noPollConn * conn, char * buffer, int buffer_size) +{ + char * header; + char * value; + + /* handle content */ + if (nopoll_ncmp (buffer, "GET ", 4)) { + /* get url method */ + nopoll_conn_get_http_url (conn, buffer, buffer_size, "GET", &conn->get_url); + return 1; + } /* end if */ + + /* get mime header */ + if (! nopoll_conn_get_mime_header (ctx, conn, buffer, buffer_size, &header, &value)) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to acquire mime header from remote peer during handshake, closing connection"); + nopoll_conn_shutdown (conn); + return 0; + } + + /* ok, process here predefined headers */ + if (nopoll_conn_check_mime_header_repeated (conn, header, value, "Host", conn->host_name)) + return 0; + if (nopoll_conn_check_mime_header_repeated (conn, header, value, "Upgrade", INT_TO_PTR (conn->handshake->upgrade_websocket))) + return 0; + if (nopoll_conn_check_mime_header_repeated (conn, header, value, "Connection", INT_TO_PTR (conn->handshake->connection_upgrade))) + return 0; + if (nopoll_conn_check_mime_header_repeated (conn, header, value, "Sec-WebSocket-Key", conn->handshake->websocket_key)) + return 0; + if (nopoll_conn_check_mime_header_repeated (conn, header, value, "Origin", conn->origin)) + return 0; + if (nopoll_conn_check_mime_header_repeated (conn, header, value, "Sec-WebSocket-Protocol", conn->protocols)) + return 0; + if (nopoll_conn_check_mime_header_repeated (conn, header, value, "Sec-WebSocket-Version", conn->handshake->websocket_version)) + return 0; + if (nopoll_conn_check_mime_header_repeated (conn, header, value, "Cookie", conn->handshake->cookie)) + return 0; + + /* set the value if required */ + if (strcasecmp (header, "Host") == 0) + conn->host_name = value; + else if (strcasecmp (header, "Sec-Websocket-Key") == 0) + conn->handshake->websocket_key = value; + else if (strcasecmp (header, "Origin") == 0) + conn->origin = value; + else if (strcasecmp (header, "Sec-Websocket-Protocol") == 0) + conn->protocols = value; + else if (strcasecmp (header, "Sec-Websocket-Version") == 0) + conn->handshake->websocket_version = value; + else if (strcasecmp (header, "Upgrade") == 0) { + conn->handshake->upgrade_websocket = 1; + nopoll_free (value); + } else if (strcasecmp (header, "Connection") == 0) { + conn->handshake->connection_upgrade = 1; + nopoll_free (value); + } else if (strcasecmp (header, "Cookie") == 0) { + /* record cookie so it can be used by the application level */ + conn->handshake->cookie = value; + } else { + /* release value, no body claimed it */ + nopoll_free (value); + } /* end if */ + + /* release the header */ + nopoll_free (header); + + return 1; /* continue reading lines */ +} + +/** + * @internal Handler that implements one step of the websocket + * client handshake received from the server, until it is completed. + * + * @return Returns 0 to return (because error or because no data is + * available) or 1 to signal the caller continue reading if it is + * possible. + */ +int nopoll_conn_complete_handshake_client (noPollCtx * ctx, noPollConn * conn, char * buffer, int buffer_size) +{ + char * header; + char * value; + int iterator; + + /* handle content */ + if (! conn->handshake->received_101 && nopoll_ncmp (buffer, "HTTP/1.1 ", 9)) { + iterator = 9; + while (iterator < buffer_size && buffer[iterator] && buffer[iterator] == ' ') + iterator++; + if (! nopoll_ncmp (buffer + iterator, "101", 3)) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "websocket server denied connection with: %s", buffer + iterator); + return 0; /* do not continue */ + } /* end if */ + + /* flag that we have received HTTP/1.1 101 indication */ + conn->handshake->received_101 = nopoll_true; + + return 1; + } /* end if */ + + /* get mime header */ + if (! nopoll_conn_get_mime_header (ctx, conn, buffer, buffer_size, &header, &value)) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to acquire mime header from remote peer during handshake, closing connection"); + nopoll_conn_shutdown (conn); + return 0; + } + + /* ok, process here predefined headers */ + if (nopoll_conn_check_mime_header_repeated (conn, header, value, "Upgrade", INT_TO_PTR (conn->handshake->upgrade_websocket))) + return 0; + if (nopoll_conn_check_mime_header_repeated (conn, header, value, "Connection", INT_TO_PTR (conn->handshake->connection_upgrade))) + return 0; + if (nopoll_conn_check_mime_header_repeated (conn, header, value, "Sec-WebSocket-Accept", conn->handshake->websocket_accept)) + return 0; + if (nopoll_conn_check_mime_header_repeated (conn, header, value, "Sec-WebSocket-Protocol", conn->accepted_protocol)) + return 0; + + /* set the value if required */ + if (strcasecmp (header, "Sec-Websocket-Accept") == 0) + conn->handshake->websocket_accept = value; + else if (strcasecmp (header, "Sec-Websocket-Protocol") == 0) + conn->accepted_protocol = value; + else if (strcasecmp (header, "Upgrade") == 0) { + conn->handshake->upgrade_websocket = 1; + nopoll_free (value); + } else if (strcasecmp (header, "Connection") == 0) { + conn->handshake->connection_upgrade = 1; + nopoll_free (value); + } else { + /* release value, no body claimed it */ + nopoll_free (value); + } /* end if */ + + /* release the header */ + nopoll_free (header); + + return 1; /* continue reading lines */ +} + +/** + * @internal Function that completes the handshake in an non-blocking + * manner taking into consideration the connection type (listener or + * client). + */ +void nopoll_conn_complete_handshake (noPollConn * conn) +{ + char buffer[1024]; + int buffer_size; + noPollCtx * ctx = conn->ctx; + + /* ensure we didn't complete handshake */ + if (conn->handshake_ok) + return; + + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Checking to complete conn-id=%d WebSocket handshake, role %d", conn->id, conn->role); + + /* ensure handshake object is created */ + if (conn->handshake == NULL) + conn->handshake = nopoll_new (noPollHandShake, 1); + + /* get lines and complete the handshake data */ + while (nopoll_true) { + /* clear buffer for debugging functions */ + buffer[0] = 0; + /* get next line to process */ + buffer_size = nopoll_conn_readline (conn, buffer, 1024); + if (buffer_size == 0 || buffer_size == -1) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Unexpected connection close during handshake..closing connection"); + nopoll_conn_shutdown (conn); + return; + } /* end if */ + + /* no data at this moment, return to avoid consuming data */ + if (buffer_size == -2) { + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "No more data available on connection id %d", conn->id); + return; + } + + /* drop a debug line */ + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Bytes read %d from connection id %d: %s", buffer_size, conn->id, buffer); + + /* check if we have received the end of the + websocket client handshake */ + if (buffer_size == 2 && nopoll_ncmp (buffer, "\r\n", 2)) { + nopoll_conn_complete_handshake_check (conn); + return; + } + + if (conn->role == NOPOLL_ROLE_LISTENER) { + /* call to complete listener handshake */ + if (nopoll_conn_complete_handshake_listener (ctx, conn, buffer, buffer_size) == 1) + continue; + } else if (conn->role == NOPOLL_ROLE_CLIENT) { + /* call to complete listener handshake */ + if (nopoll_conn_complete_handshake_client (ctx, conn, buffer, buffer_size) == 1) + continue; + } else { + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Called to handle connection handshake on a connection with an unexpected role: %d, closing session", + conn->role); + nopoll_conn_shutdown (conn); + return; + } + } /* end while */ + + return; +} + +void nopoll_conn_mask_content (noPollCtx * ctx, char * payload, int payload_size, char * mask, int desp) +{ + int iter = 0; + int mask_index = 0; + + while (iter < payload_size) { + /* rotate mask and apply it */ + mask_index = (iter + desp) % 4; + payload[iter] ^= mask[mask_index]; + iter++; + } /* end while */ + + return; +} + + +/** + * @brief Allows to get the next message available on the provided + * connection. The function returns NULL in the case no message is + * still ready to be returned. + * + * The function do not block. + * + * @param conn The connection where the read operation will take + * place. + * + * @return A reference to a noPollMsg object or NULL if there is + * nothing available. In case the function returns NULL, check + * connection status with \ref nopoll_conn_is_ok. + */ +noPollMsg * nopoll_conn_get_msg (noPollConn * conn) +{ + char buffer[20]; + int bytes; + noPollMsg * msg; + int ssl_error; + int header_size; +#if defined(SHOW_DEBUG_LOG) + long result; +#endif +#if defined(NOPOLL_64BIT_PLATFORM) + unsigned char *len; +#endif + + if (conn == NULL) + return NULL; + + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, + "=== START: conn-id=%d (errno=%d, session: %d, conn->handshake_ok: %d, conn->pending_ssl_accept: %d) ===", + conn->id, errno, conn->session, conn->handshake_ok, conn->pending_ssl_accept); + + /* check for accept SSL connection */ + if (conn->pending_ssl_accept) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Received connect over a connection (id %d) with TLS handshake pending to be finished, processing..", + conn->id); + + /* get ssl error */ + ssl_error = SSL_accept (conn->ssl); + if (ssl_error == -1) { + /* get error */ + ssl_error = SSL_get_error (conn->ssl, -1); + + nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "accept function have failed (for listener side) ssl_error=%d : dumping error stack..", ssl_error); + + switch (ssl_error) { + case SSL_ERROR_WANT_READ: + nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "still not prepared to continue because read wanted conn-id=%d (%p, session %d)", + conn->id, conn, conn->session); + return NULL; + case SSL_ERROR_WANT_WRITE: + nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "still not prepared to continue because write wanted conn-id=%d (%p)", + conn->id, conn); + return NULL; + default: + break; + } /* end switch */ + + /* TLS-fication process have failed */ + nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "there was an error while accepting TLS connection"); + nopoll_conn_log_ssl (conn); + nopoll_conn_shutdown (conn); + return NULL; + } /* end if */ + + /* ssl accept */ + conn->pending_ssl_accept = nopoll_false; + nopoll_conn_set_sock_block (conn->session, nopoll_false); + +#if defined(SHOW_DEBUG_LOG) + result = SSL_get_verify_result (conn->ssl); + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Completed TLS operation from %s:%s (conn id %d, ssl veriry result: %d)", + conn->host, conn->port, conn->id, (int) result); +#endif + + /* configure default handlers */ + conn->receive = nopoll_conn_tls_receive; + conn->sends = nopoll_conn_tls_send; + + /* call to check post ssl checks after SSL finalization */ + if (conn->ctx && conn->ctx->post_ssl_check) { + if (! conn->ctx->post_ssl_check (conn->ctx, conn, conn->ssl_ctx, conn->ssl, conn->ctx->post_ssl_check_data)) { + /* TLS post check failed */ + nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "TLS/SSL post check function failed, dropping connection"); + nopoll_conn_shutdown (conn); + return NULL; + } /* end if */ + } /* end if */ + + /* set this connection has TLS ok */ + conn->tls_on = nopoll_true; + +#if defined(NOPOLL_OS_UNIX) + /* report NULL because this was a call to complete TLS */ + errno = NOPOLL_EWOULDBLOCK; /* simulate there is no data available to stop + here. If there is no data indeed, on next + call it will not fail */ +#endif + return NULL; + + } /* end if */ + + /* check connection status */ + if (! conn->handshake_ok) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Connection id %d handshake is not complete, running..", conn->id); + /* acquire here handshake mutex */ + nopoll_mutex_lock (conn->ref_mutex); + + /* complete handshake */ + nopoll_conn_complete_handshake (conn); + + /* release here handshake mutex */ + nopoll_mutex_unlock (conn->ref_mutex); + + if (! conn->handshake_ok) + return NULL; + } /* end if */ + + if (conn->previous_msg) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "Reading bytes (previously read %d) from a previous unfinished frame (pending: %d) over conn-id=%d", + conn->previous_msg->payload_size, conn->previous_msg->remain_bytes, conn->id); + + /* build next message holder to continue with this content */ + if (conn->previous_msg->payload_size > 0) { + msg = nopoll_msg_new (); + if (msg == NULL) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Failed to allocate memory for received message, closing session id: %d", + conn->id); + nopoll_conn_shutdown (conn); + return NULL; + } /* end if */ + + /* flag this message as a fragment */ + msg->is_fragment = nopoll_true; + + /* get fin bytes */ + msg->has_fin = 1; /* for now final message */ + msg->op_code = 0; /* continuation frame */ + + /* copy initial mask indication */ + msg->is_masked = conn->previous_msg->is_masked; + msg->payload_size = conn->previous_msg->remain_bytes; + msg->unmask_desp = conn->previous_msg->unmask_desp; + + /* copy mask */ + memcpy (msg->mask, conn->previous_msg->mask, 4); + + if (msg->is_masked) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Reusing mask value = %d from previous frame (%d)", nopoll_get_32bit (msg->mask)); + nopoll_show_byte (conn->ctx, msg->mask[0], "mask[0]"); + nopoll_show_byte (conn->ctx, msg->mask[1], "mask[1]"); + nopoll_show_byte (conn->ctx, msg->mask[2], "mask[2]"); + nopoll_show_byte (conn->ctx, msg->mask[3], "mask[3]"); + } + + /* release previous reference because de don't need it anymore */ + nopoll_msg_unref (conn->previous_msg); + } else { + /* reuse reference */ + msg = conn->previous_msg; + + /* update remaining bytes */ + msg->payload_size = msg->remain_bytes; + nopoll_free (msg->payload); + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "reusing noPollMsg reference (%p) since last payload read was 0, remaining: %d", msg, + msg->payload_size); + } + + /* nullify references */ + conn->previous_msg = NULL; + + goto read_payload; + + } /* end if */ + + /* + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-------+-+-------------+-------------------------------+ + |F|R|R|R| opcode|M| Payload len | Extended payload length | + |I|S|S|S| (4) |A| (7) | (16/63) | + |N|V|V|V| |S| | (if payload len==126/127) | + | |1|2|3| |K| | | + +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + + | Extended payload length continued, if payload len == 127 | + + - - - - - - - - - - - - - - - +-------------------------------+ + | |Masking-key, if MASK set to 1 | + +-------------------------------+-------------------------------+ + | Masking-key (continued) | Payload Data | + +-------------------------------- - - - - - - - - - - - - - - - + + : Payload Data continued ... : + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + | Payload Data continued ... | + +---------------------------------------------------------------+ + */ + /* nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Found data in opened connection id %d..", conn->id);*/ + + /* get the first 4 bytes from the websocket header */ + bytes = __nopoll_conn_receive (conn, buffer, 2); + if (bytes == 0) { + /* connection not ready */ + nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "Connection id=%d without data, errno=%d : %s, returning no message", + conn->id, errno, strerror (errno)); + return NULL; + } + + if (bytes <= 0) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Received connection close, finishing connection session"); + nopoll_conn_shutdown (conn); + return NULL; + } /* end if */ + + if (bytes != 2) { + /* ok, store content read into the pending buffer for next call */ + memcpy (conn->pending_buf + conn->pending_buf_bytes, buffer, bytes); + conn->pending_buf_bytes += bytes; + + nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, + "Expected to receive complete websocket frame header but found only %d bytes over conn-id=%d, saving to reuse later", + bytes, conn->id); + return NULL; + } /* end if */ + + /* record header size */ + header_size = 2; + + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Received %d bytes for websocket header", bytes); + nopoll_show_byte (conn->ctx, buffer[0], "header[0]"); + nopoll_show_byte (conn->ctx, buffer[1], "header[1]"); + + /* build next message */ + msg = nopoll_msg_new (); + if (msg == NULL) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Failed to allocate memory for received message, closing session id: %d", + conn->id); + nopoll_conn_shutdown (conn); + return NULL; + } /* end if */ + + /* get fin bytes */ + msg->has_fin = nopoll_get_bit (buffer[0], 7); + msg->op_code = buffer[0] & 0x0F; + msg->is_masked = nopoll_get_bit (buffer[1], 7); + msg->payload_size = buffer[1] & 0x7F; + + /* ensure FIN = 1 in case we are listener */ + if (conn->role == NOPOLL_ROLE_LISTENER && ! msg->is_masked) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Received websocket frame with mask bit set to zero, closing session id: %d", + conn->id); + nopoll_msg_unref (msg); + nopoll_conn_shutdown (conn); + return NULL; + } /* end if */ + + /* check payload size value */ + if (msg->payload_size < 0) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Received wrong payload size at first 7 bits, closing session id: %d", + conn->id); + nopoll_msg_unref (msg); + nopoll_conn_shutdown (conn); + return NULL; + } /* end if */ + + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "interim payload size received: %d", (int) msg->payload_size); + + /* read the rest */ + if (msg->payload_size < 126) { + /* nothing to declare here */ + + } else if (msg->payload_size == 126) { + /* get extended 2 bytes length as unsigned 16 bit + unsigned integer */ + bytes = __nopoll_conn_receive (conn, buffer + 2, 2); + if (bytes != 2) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "Failed to get next 2 bytes to read header from the wire, failed to received content, shutting down id=%d the connection", conn->id); + nopoll_msg_unref (msg); + nopoll_conn_shutdown (conn); + return NULL; + } /* end if */ + + /* add to the header bytes read */ + header_size += bytes; + + msg->payload_size = nopoll_get_16bit (buffer + 2); + + } else if (msg->payload_size == 127) { +#if defined(NOPOLL_64BIT_PLATFORM) + /* read more content (next 8 bytes) */ + if ((bytes = __nopoll_conn_receive (conn, buffer, 8)) != 8) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, + "Expected to receive next 6 bytes for websocket frame header but found only %d bytes, closing session: %d", + bytes, conn->id); + nopoll_conn_shutdown (conn); + return NULL; + } /* end if */ + + len = (unsigned char*)buffer; + msg->payload_size = 0; + msg->payload_size |= ((long)(len[0]) << 56); + msg->payload_size |= ((long)(len[1]) << 48); + msg->payload_size |= ((long)(len[2]) << 40); + msg->payload_size |= ((long)(len[3]) << 32); + msg->payload_size |= ((long)(len[4]) << 24); + msg->payload_size |= ((long)(len[5]) << 16); + msg->payload_size |= ((long)(len[6]) << 8); + msg->payload_size |= len[7]; +#else + nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "noPoll doesn't support messages bigger than 65k on this plataform (support for 64bit not found)"); + nopoll_msg_unref (msg); + nopoll_conn_shutdown (conn); + return NULL; +#endif + } /* end if */ + + if (msg->op_code == NOPOLL_PONG_FRAME) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "PONG received over connection id=%d", conn->id); + nopoll_msg_unref (msg); + return NULL; + } /* end if */ + + if (msg->op_code == NOPOLL_CLOSE_FRAME) { + if (msg->payload_size == 0) { + /* nothing more to add here, close frame + without content received, so we have no + reason to keep on reading */ + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Proper connection close frame received id=%d, shutting down", conn->id); + nopoll_msg_unref (msg); + nopoll_conn_shutdown (conn); + return NULL; + } /* end if */ + + /* received close frame with content, try to read the content */ + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Proper connection close frame received id=%d with content bytes=%d, reading reason..", + conn->id, msg->payload_size); + } /* end if */ + + if (msg->op_code == NOPOLL_PING_FRAME) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "PING received over connection id=%d, replying PONG", conn->id); + nopoll_msg_unref (msg); + + /* call to send pong */ + nopoll_conn_send_pong (conn); + + return NULL; + } /* end if */ + + /* get more bytes */ + if (msg->is_masked) { + bytes = __nopoll_conn_receive (conn, (char *) msg->mask, 4); + if (bytes != 4) { + /* record header read so far */ + memcpy (conn->pending_buf, buffer, header_size); + conn->pending_buf_bytes = header_size; + /* record mask read so far if required */ + if (bytes > 0) { + memcpy (conn->pending_buf + header_size, msg->mask, bytes); + conn->pending_buf_bytes += bytes; + } /* end if */ + + /* release message because it not available here */ + nopoll_msg_unref (msg); + if (bytes >= 0 && nopoll_conn_is_ok (conn)) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, + "Expected to receive incoming mask after header (4 bytes) but found %d bytes on conn-id=%d, saving %d for future operations ", + bytes, conn->id, conn->pending_buf_bytes); + return NULL; + } /* end if */ + + nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Expected to receive incoming mask after header (4 bytes) but found %d bytes, shutting down id=%d the connection", + bytes, conn->id); + nopoll_conn_shutdown (conn); + return NULL; + } /* end if */ + + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Received mask value = %d", nopoll_get_32bit (msg->mask)); + nopoll_show_byte (conn->ctx, msg->mask[0], "mask[0]"); + nopoll_show_byte (conn->ctx, msg->mask[1], "mask[1]"); + nopoll_show_byte (conn->ctx, msg->mask[2], "mask[2]"); + nopoll_show_byte (conn->ctx, msg->mask[3], "mask[3]"); + } /* end if */ + + /* check payload size */ + if (msg->payload_size == 0) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "Found incoming frame with payload size 0, shutting down id=%d the connection", conn->id); + nopoll_msg_unref (msg); + nopoll_conn_shutdown (conn); + return NULL; + } /* end if */ + + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Detected incoming websocket frame: fin(%d), op_code(%d), is_masked(%d), payload size(%ld), mask=%d", + msg->has_fin, msg->op_code, msg->is_masked, msg->payload_size, nopoll_get_32bit (msg->mask)); + + /* check here for the limit of message we are willing to accept */ + /* FIX SECURITY ISSUE */ + +read_payload: + + /* copy payload received */ + msg->payload = nopoll_new (char, msg->payload_size + 1); + if (msg->payload == NULL) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Unable to acquire memory to read the incoming frame, dropping connection id=%d", conn->id); + nopoll_msg_unref (msg); + nopoll_conn_shutdown (conn); + return NULL; + } /* end if */ + + bytes = __nopoll_conn_receive (conn, (char *) msg->payload, msg->payload_size); + if (bytes < 0) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Connection lost during message reception, dropping connection id=%d, bytes=%d, errno=%d : %s", + conn->id, bytes, errno, strerror (errno)); + nopoll_msg_unref (msg); + nopoll_conn_shutdown (conn); + return NULL; + } /* end if */ + + if (bytes != msg->payload_size) { + /* record we've got content pending to be read */ + msg->remain_bytes = msg->payload_size - bytes; + + /* set connection in remaining data to read */ + nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "Received fewer bytes than expected (bytes: %d < payload size: %d)", + bytes, (int) msg->payload_size); + msg->payload_size = bytes; + + /* grab a reference to previous message to reuse itsdata but only when bytes > 0 + because when bytes == 0, the reference is reused since it is not returned + to the caller (see next lines) */ + if (bytes > 0) + nopoll_msg_ref (msg); + conn->previous_msg = msg; + + /* flag this message as a fragment */ + msg->is_fragment = nopoll_true; + + /* flag that this message doesn't have FIN = 0 because + * we wasn't able to read it entirely */ + msg->has_fin = 0; + } /* end if */ + + /* flag the message was being a fragment according to previous flag */ + msg->is_fragment = msg->is_fragment || conn->previous_was_fragment || msg->has_fin == 0; + + /* update was a fragment */ + conn->previous_was_fragment = msg->is_fragment && msg->has_fin == 0; + + /* do not notify any frame since no content was found */ + if (bytes == 0 && msg == conn->previous_msg) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "bytes == %d, msg (%p) == conn->previous_msg (%p)", + bytes, msg, conn->previous_msg); + return NULL; + } /* end if */ + + /* now unmask content (if required) */ + if (msg->is_masked) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Unmasking (payload size %d, mask: %d, msg: %p, desp: %d)", + msg->payload_size, nopoll_get_32bit (msg->mask), msg, msg->unmask_desp); + nopoll_conn_mask_content (conn->ctx, (char*) msg->payload, msg->payload_size, (char*) msg->mask, msg->unmask_desp); + + /* flag what was unmasked */ + msg->unmask_desp += msg->payload_size; + } /* end if */ + + /* check here close frame with reason */ + if (msg->op_code == NOPOLL_CLOSE_FRAME) { + /* try to read reason and report those values */ + if (msg->payload_size >= 2) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Close frame received id=%d with content bytes=%d, peer status=%d, peer reason=%s, reading reason..", + conn->id, msg->payload_size, nopoll_get_16bit ((char*)msg->payload), (char*)msg->payload + 2); + + /* get values so the user can get them */ + conn->peer_close_status = nopoll_get_16bit (msg->payload); + conn->peer_close_reason = nopoll_strdup ((const char*)msg->payload + 2); + } /* end if */ + + /* release message, close the connection and return + NULL to notify caller nothing to read for the + application */ + nopoll_msg_unref (msg); + nopoll_conn_shutdown (conn); + return NULL; + } + + return msg; +} + +/** + * @internal Implementation to send Frames according to various + * parameters passed in into the function. This is the core function + * used to send frames in noPoll. + * + * @param conn The connection where the content will be sent. + * + * @param content The content that will be sent (user level content) + * + * @param length The length of such content to be sent. + * + * @param has_fin nopoll_true/nopoll_false to signal FIN header flag + * + * @param sleep_in_header Optional hacking option that allows to + * include a pause between sending the header and the rest of the + * content. + */ +int __nopoll_conn_send_common (noPollConn * conn, const char * content, long length, nopoll_bool has_fin, long sleep_in_header, noPollOpCode frame_type) +{ + if (conn == NULL || content == NULL || length == 0 || length < -1) + return -1; + + if (conn->role == NOPOLL_ROLE_MAIN_LISTENER) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Trying to send content over a master listener connection"); + return -1; + } /* end if */ + + if (length == -1) { + if (NOPOLL_BINARY_FRAME == frame_type) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Received length == -1 for binary frame. Unable to guess length"); + return -1; + } /* end if */ + + length = strlen (content); + } + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "nopoll_conn_send_text: Attempting to send %d bytes", (int) length); + + /* sending content as client */ + if (conn->role == NOPOLL_ROLE_CLIENT) { + return nopoll_conn_send_frame (conn, /* fin */ has_fin, /* masked */ nopoll_true, + frame_type, length, (noPollPtr) content, sleep_in_header); + } /* end if */ + + /* sending content as listener */ + return nopoll_conn_send_frame (conn, /* fin */ has_fin, /* masked */ nopoll_false, + frame_type, length, (noPollPtr) content, sleep_in_header); +} + +/** + * @brief Allows to send an UTF-8 text (op code 1) message over the + * provided connection with the provided length. + * + * @param conn The connection where the message will be sent. + * + * @param content The content to be sent (it should be utf-8 content + * or the function will fail). + * + * @param length Amount of bytes to take from the content to be + * sent. If provided -1, it is assumed you are passing in a C-like + * string nul terminated, so, that's the content to be sent. + * + * @return The number of bytes written otherwise < 0 is returned in + * case of failure. The function will fail if some parameter is NULL + * or undefined, or the content provided is not UTF-8. In the case of + * failure, also check errno variable to know more what went wrong. + * + * See \ref nopoll_manual_retrying_write_operations to know more about error codes and when it is possible to retry write operations. + */ +int nopoll_conn_send_text (noPollConn * conn, const char * content, long length) +{ + /* do a send common operation with FIN = 1 */ + return __nopoll_conn_send_common (conn, content, length, nopoll_true, 0, NOPOLL_TEXT_FRAME); +} + +/** + * @brief Allows to send an UTF-8 text (op code 1) message over the + * provided connection with the provided length but flagging the frame + * sent as not complete (more frames to come, that is, FIN = 0). + * + * @param conn The connection where the message will be sent. + * + * @param content The content to be sent (it should be utf-8 content + * or the function will fail). + * + * @param length Amount of bytes to take from the content to be + * sent. If provided -1, it is assumed you are passing in a C-like + * string nul terminated, so, that's the content to be sent. + * + * @return The number of bytes written otherwise < 0 is returned in + * case of failure. The function will fail if some parameter is NULL + * or undefined, or the content provided is not UTF-8. In the case of + * failure, also check errno variable to know more what went wrong. + * + * See \ref nopoll_manual_retrying_write_operations to know more about + * error codes and when it is possible to retry write operations. + */ +int nopoll_conn_send_text_fragment (noPollConn * conn, const char * content, long length) +{ + /* do a send common operation with FIN = 0 */ + return __nopoll_conn_send_common (conn, content, length, nopoll_false, 0, NOPOLL_TEXT_FRAME); +} + +/** + * @brief Allows to send a binary (op code 2) message over the + * provided connection with the provided length. + * + * @param conn The connection where the message will be sent. + * + * @param content The content to be sent (it should be utf-8 content + * or the function will fail). + * + * @param length Amount of bytes to take from the content to be + * sent. Note you cannot pass in -1 (unlike \ref nopoll_conn_send_text). + * + * @return The number of bytes written otherwise < 0 is returned in + * case of failure. The function will fail if some parameter is NULL + * or undefined. In the case of failure, also check errno variable to + * know more what went wrong. + * + * See \ref nopoll_manual_retrying_write_operations to know more about error codes and when it is possible to retry write operations. + */ +int nopoll_conn_send_binary (noPollConn * conn, const char * content, long length) +{ + return __nopoll_conn_send_common (conn, content, length, nopoll_true, 0, NOPOLL_BINARY_FRAME); +} + + +/** + * @brief Allows to send a binary (op code 2) message over the + * provided connection with the provided length but flagging the frame + * sent as not complete (more frames to come, that is, FIN = 0). + * + * @param conn The connection where the message will be sent. + * + * @param content The content to be sent (it should be utf-8 content + * or the function will fail). + * + * @param length Amount of bytes to take from the content to be + * sent. Note you cannot pass in -1 (unlike \ref + * nopoll_conn_send_text). + * + * @return The number of bytes written otherwise < 0 is returned in + * case of failure. The function will fail if some parameter is NULL + * or undefined. In the case of failure, also check errno variable to + * know more what went wrong. + * + * See \ref nopoll_manual_retrying_write_operations to know more about + * error codes and when it is possible to retry write operations. + */ +int nopoll_conn_send_binary_fragment (noPollConn * conn, const char * content, long length) +{ + return __nopoll_conn_send_common (conn, content, length, nopoll_true, 0, NOPOLL_BINARY_FRAME); +} + + +/** + * @brief Allows to read the provided amount of bytes from the + * provided connection, leaving the content read on the buffer + * provided. + * + * Optionally, the function allows blocking the caller until the + * amount of bytes requested are satisfied. Also, the function allows + * to timeout the operation after provided amount of time. + * + * @param conn The connection where the read operation will take place. + * + * @param buffer The buffer where the result is returned. Memory + * buffer must be enough to hold bytes requested and must be acquired + * by the caller. + * + * @param bytes Number of bytes to be read from the connection. + * + * @param block If nopoll_true, the caller will be blocked until the + * amount of bytes requested are satisfied or until the timeout is + * reached (if enabled). If nopoll_false is provided, the function + * won't block and will return all bytes available at this moment. + * + * @param timeout (milliseconds 1sec = 1000ms) If provided a value + * higher than 0, a timeout will be enabled to complete the + * operation. If the timeout is reached, the function will return the + * bytes read so far. Please note that the function has a precision of + * 10ms. + * + * @return Number of bytes read or -1 if it fails. The function + * returns -1 when no content is available to be read and you pass + * block == nopoll_false + * + * Note that the function doesn't clear the buffer received. Only + * memory (bytes) notified by the value returned by this function + * should be accessed by the caller. In the same direction you can't + * use the buffer as a nul-terminated string because the function + * doesn't add the final \0 to the content read. + * + */ +int nopoll_conn_read (noPollConn * conn, char * buffer, int bytes, nopoll_bool block, long int timeout) +{ + long int wait_slice = 0; + noPollMsg * msg = NULL; + struct timeval start; + struct timeval stop; + struct timeval diff; + long ellapsed = 0; + int desp = 0; + int amount; + int total_read = 0; + int total_pending = 0; + + /* report error value */ + if (conn == NULL || buffer == NULL || bytes <= 0) + return -1; + + if (timeout > 1000) + wait_slice = 100; + else if (timeout > 100) + wait_slice = 50; + else if (timeout > 10) + wait_slice = 10; + + if (timeout > 0) +#if defined(NOPOLL_OS_WIN32) + nopoll_win32_gettimeofday (&start, NULL); +#else + gettimeofday (&start, NULL); +#endif + + /* clear the buffer */ + memset (buffer, 0, bytes); + + /* check here if we have a pending message to read */ + if (conn->pending_msg) { + /* nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "nopoll_conn_read (found pending content: %d, requested %d)", conn->pending_diff, bytes); */ + /* get references to pending data */ + amount = conn->pending_diff; + msg = conn->pending_msg; + if (amount > bytes) { + /* check if bytes requested are bigger the + * conn->pending_diff */ + if (bytes < conn->pending_diff) { + conn->pending_diff -= bytes; + } else { + /* update values */ + bytes = conn->pending_diff; + conn->pending_diff = 0; + } /* end if */ + + amount = bytes; + } else { + conn->pending_diff = 0; + } + + /* read content */ + memcpy (buffer, ((unsigned char *) nopoll_msg_get_payload (msg)) + conn->pending_desp, amount); + total_read += amount; + desp = amount; + /* nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "nopoll_conn_read total amount satisfied is not %d, requested %d", total_read, bytes); */ + + /* increase pending desp */ + conn->pending_desp += amount; + + /* now release internally the content if consumed the message */ + if (conn->pending_diff == 0) { + nopoll_msg_unref (conn->pending_msg); + conn->pending_msg = NULL; + } /* end if */ + + /* see if we have finished */ + if (total_read == bytes || ! block) { + if (total_read == 0 && ! block) + return -1; + + return total_read; + } + + /* nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "### ====> Read %d bytes from previous pending frame, requested %d. Pending diff %d", total_read, bytes, conn->pending_diff); */ + } /* end if */ + + + /* for for the content */ + while (nopoll_true) { + /* call to get next message */ + msg = nopoll_conn_get_msg (conn); + if (msg == NULL) { + if (! nopoll_conn_is_ok (conn)) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Received websocket conn-id=%d close during wait reply..", + conn->id); + if (total_read == 0 && ! block) + return -1; + return total_read; + } /* end if */ + + if (! block) { + if (total_read == 0 && ! block) + return -1; + return total_read; + } /* end if */ + + } /* end if */ + + /* get the message content into the buffer */ + if (msg) { + /* get the amount of bytes we can read */ + amount = nopoll_msg_get_payload_size (msg); + total_pending = bytes - total_read; + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "(New Frame) received %d bytes (pending requested %d bytes, desp: %d)", amount, total_pending, desp); + if (amount > total_pending) { + /* save here the difference between + * what we have read and remaining data */ + conn->pending_desp = total_pending; + conn->pending_diff = amount - total_pending; + conn->pending_msg = msg; + amount = total_pending; + + /* acquire a reference to the message */ + nopoll_msg_ref (msg); + } /* end if */ + /* copy data */ + memcpy (buffer + desp, nopoll_msg_get_payload (msg), amount); + total_read += amount; + desp += amount; + /* nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "nopoll_conn_read total amount satisfied is not %d, requested %d, desp: %d", + total_read, bytes, desp); */ + + /* release message */ + nopoll_msg_unref (msg); + + /* return amount read */ + if (total_read == bytes || ! block) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Finishing nopoll_conn_read because block=%d or total bytes requested=%d satisfied=%d ", + block, bytes, total_read); + + if (total_read == 0 && ! block) + return -1; + return total_read; + } + } + + /* check to stop due to timeout */ + if (timeout > 0) { +#if defined(NOPOLL_OS_WIN32) + nopoll_win32_gettimeofday (&stop, NULL); +#else + gettimeofday (&stop, NULL); +#endif + nopoll_timeval_substract (&stop, &start, &diff); + + ellapsed = (diff.tv_sec * 1000) + (diff.tv_usec / 1000); + if (ellapsed > (timeout)) + break; + } /* end if */ + + nopoll_sleep (wait_slice); + } /* end while */ + + /* reached this point, return that timeout was reached */ + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Finishing nopoll_conn_read timeout reached=%ld ms , returning total bytes requested=%d satisfied=%d ", + timeout, bytes, total_read); + + if (total_read == 0 && ! block) + return -1; + return total_read; +} + +/** + * @brief Allows to send a ping message over the Websocket connection + * provided. The function will not block the caller. + * + * @param conn The connection where the PING operation will be sent. + * + * @return nopoll_true if the operation was sent without any error, + * otherwise nopoll_false is returned. + */ +nopoll_bool nopoll_conn_send_ping (noPollConn * conn) +{ + return nopoll_conn_send_frame (conn, nopoll_true, nopoll_false, NOPOLL_PING_FRAME, 0, NULL, 0); +} + +/** + * @brief Allows to configure an on message handler on the provided + * connection that overrides the one configured at \ref noPollCtx. + * + * @param conn The connection to be configured with a particular on message handler. + * + * @param on_msg The on message handler configured. + * + * @param user_data User defined pointer to be passed in into the on message handler when it is called. + * + */ +void nopoll_conn_set_on_msg (noPollConn * conn, + noPollOnMessageHandler on_msg, + noPollPtr user_data) +{ + if (conn == NULL) + return; + + /* configure on message handler */ + conn->on_msg = on_msg; + conn->on_msg_data = user_data; + + return; +} + +/** + * @brief Allows to configure a handler that is called when the + * connection provided is ready to send and receive because all + * WebSocket handshake protocol finished OK. + * + * Unlike handlers configured at \ref nopoll_ctx_set_on_open and \ref + * nopoll_ctx_set_on_accept which get notified when the connection + * isn't still working (because WebSocket handshake wasn't finished + * yet), on read handlers configured here will get called just after + * the WebSocket handshake has taken place. + * + * @param conn The connection to configure. + * + * @param on_ready The handler to be called when a connection is fully + * ready to send and receive content because WebSocket handshake has + * finished. The function must return nopoll_true to accept the + * connection. By returning nopoll_false the handler is signalling to + * terminate the connection. + * + * @param user_data Optional user data pointer passed to the on ready + * handler. + * + */ +void nopoll_conn_set_on_ready (noPollConn * conn, + noPollActionHandler on_ready, + noPollPtr user_data) +{ + if (conn == NULL) + return; + + /* set the handler */ + conn->on_ready = on_ready; + if (conn->on_ready == NULL) + conn->on_ready_data = NULL; + else + conn->on_ready_data = user_data; + return; +} + +/** + * @brief Allows to configure an OnClose handler that will be called + * when the connection is closed. + * + * @param conn The connection to configure with the on close handle. + * + * @param on_close The handler to be configured. + * + * @param user_data A reference pointer to be passed in into the handler. + */ +void nopoll_conn_set_on_close (noPollConn * conn, + noPollOnCloseHandler on_close, + noPollPtr user_data) +{ + if (conn == NULL) + return; + + /* configure on close handler */ + conn->on_close = on_close; + conn->on_close_data = user_data; + + return; +} + +/** + * @internal Allows to send a pong message over the Websocket + * connection provided. The function will not block the caller. This + * function is not intended to be used by normal API consumer. + * + * @param conn The connection where the PING operation will be sent. + * + * @param nopoll_true if the operation was sent without any error, + * otherwise nopoll_false is returned. + */ +nopoll_bool nopoll_conn_send_pong (noPollConn * conn) +{ + return nopoll_conn_send_frame (conn, nopoll_true, nopoll_false, NOPOLL_PONG_FRAME, 0, NULL, 0); +} + +/** + * @brief Allows to call to complete last pending write process that may be + * pending from a previous uncompleted write operation. The function + * returns the number of bytes that were written. + * + * @param conn The connection where the pending write operation + * operation will take place. In the case conn == NULL is received, 0 + * is returned. Keep in mind this. + * + * @return In the case no pending write is in place, the function + * returns 0. Otherwise, the function returns the pending bytes that + * were written. The function returns -1 in the case of failure. + * + * You can call this function as many times as you want until you get + * a 0. You can view it as a flush operation. + */ +int nopoll_conn_complete_pending_write (noPollConn * conn) +{ + int bytes_written = 0; + char * reference; + int pending_bytes; + + if (conn == NULL || conn->pending_write == NULL) + return 0; + + /* simple implementation */ + bytes_written = conn->sends (conn, conn->pending_write, conn->pending_write_bytes); + if (bytes_written == conn->pending_write_bytes) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Completed pending write operation with bytes=%d", bytes_written); + nopoll_free (conn->pending_write); + conn->pending_write = NULL; + return bytes_written; + } /* end if */ + + if (bytes_written > 0) { + /* bytes written but not everything */ + pending_bytes = conn->pending_write_bytes - bytes_written; + reference = nopoll_new (char, pending_bytes); + memcpy (reference, conn->pending_write + bytes_written, pending_bytes); + nopoll_free (conn->pending_write); + conn->pending_write = reference; + return bytes_written; + } + + nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "Found complete write operation didn't finish well, result=%d, errno=%d, conn-id=%d", + bytes_written, errno, conn->id); + return bytes_written; +} + +/** + * @brief Allows to check if there are pending write bytes. The + * function returns the number of pending write bytes that are waiting + * to be flushed. To do so you must call \ref nopoll_conn_complete_pending_write. + * + * @param conn The connection to be checked to have pending bytes to be written. + * + * @return The number of bytes pending to be written. The function + * also returns 0 when conn reference received is NULL. + */ +int nopoll_conn_pending_write_bytes (noPollConn * conn) +{ + if (conn == NULL || conn->pending_write == NULL) + return 0; + + return conn->pending_write_bytes; +} + +/** + * @brief Ready to use function that checks for pending write + * operations and flush them waiting until they are done or until the + * timeout provided by the user is reached. + * + * This function uses \ref nopoll_conn_pending_write_bytes and \ref + * nopoll_conn_complete_pending_write to check and complete pending + * write operations. + * + * Because writing pending bytes is a common operation, this function + * is provided as a ready to use function to call after a write operation (for + * example \ref nopoll_conn_send_text). + * + * @param conn The connection where pending bytes must be written. + * + * @param timeout Timeout in milliseconds to limit the flush operation. + * + * @param previous_result Optional parameter that can receive the + * number of bytes optionally read before this call. The value + * received on this function will be added to the result, checking + * first it contains a value higher than 0. This is an option to + * clarify the interface. If you don't have the value to be passed to + * this function at the time needed, just pass 0. + * + * @return Bytes that were written. If no pending bytes must be written, the function returns 0. + */ +int nopoll_conn_flush_writes (noPollConn * conn, long timeout, int previous_result) +{ + int iterator = 0; + int bytes_written; + int total = 0; + int multiplier = 1; + long wait_implemented = 0; + + /* check for errno and pending write operations */ + if (errno != NOPOLL_EWOULDBLOCK || nopoll_conn_pending_write_bytes (conn) == 0) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "called flush but nothing is pending=%d or errno=%d isn't %d", + nopoll_conn_pending_write_bytes (conn), errno, NOPOLL_EWOULDBLOCK); + return previous_result > 0 ? previous_result : 0; + } + + while (iterator < 100 && nopoll_conn_pending_write_bytes (conn) > 0) { + + /* stop operation if timeout reached */ + if (wait_implemented >= timeout) + break; + + nopoll_sleep (100000 * multiplier); + wait_implemented += (100000 * multiplier); + + /* write content pending */ + bytes_written = nopoll_conn_complete_pending_write (conn); + + if (bytes_written > 0) + total += bytes_written; + + /* next position */ + iterator++; + multiplier++; + } /* end while */ + + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "finishing flush operation, total written=%d, added to previous result=%d", + total, previous_result); + + /* add value received */ + if (previous_result > 0) + return total + previous_result; + + /* just bytes written */ + return total; +} + + +/** + * @internal Function used to send a frame over the provided + * connection. + * + * @param conn The connection where the send operation will hapen. + * + * @param fin If the frame to be sent must be flagged as a fin frame. + * + * @param masked The frame to be sent is masked or not. + * + * @param op_code The frame op code to be configured. + * + * @param length The frame payload length. + * + * @param content Pointer to the data to be sent in the frame. + */ +int nopoll_conn_send_frame (noPollConn * conn, nopoll_bool fin, nopoll_bool masked, + noPollOpCode op_code, long length, noPollPtr content, long sleep_in_header) + +{ + char header[14]; + int header_size; + char * send_buffer; + int bytes_written = 0; + char mask[4]; + unsigned int mask_value = 0; + int desp = 0; + int tries; +#if defined(SHOW_DEBUG_LOG) + noPollDebugLevel level; +#endif + + /* check for pending send operation */ + if (nopoll_conn_complete_pending_write (conn) != 0) + return -1; + + /* clear header */ + memset (header, 0, 14); + + /* set header codes */ + if (fin) + nopoll_set_bit (header, 7); + + if (masked) { + nopoll_set_bit (header + 1, 7); + + /* define a random mask */ +#if defined(NOPOLL_OS_WIN32) + mask_value = (unsigned int) rand (); +#else + mask_value = (unsigned int) os_random (); +#endif + memset (mask, 0, 4); + nopoll_set_32bit (mask_value, mask); + } /* end if */ + + if (op_code) { + /* set initial 4 bits */ + header[0] |= op_code & 0x0f; + } + + /* set default header size */ + header_size = 2; + + /* according to message length */ + if (length < 126) { + header[1] |= length; + } else if (length < 65535) { + /* set the next header length is at least 65535 */ + header[1] |= 126; + header_size += 2; + /* set length into the next bytes */ + nopoll_set_16bit (length, header + 2); +#if defined(NOPOLL_64BIT_PLATFORM) + } else if (length < 9223372036854775807ULL) { + /* not supported yet */ + return -1; +#else + } else { + nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Unable to send the requested message, this requested is bigger than the value that can be supported by this platform (it should be < 65k)"); + return -1; +#endif + } + + /* place mask */ + if (masked) { + nopoll_set_32bit (mask_value, header + header_size); + header_size += 4; + } /* end if */ + + /* allocate enough memory to send content */ + send_buffer = nopoll_new (char, length + header_size + 2); + if (send_buffer == NULL) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Unable to allocate memory to implement send operation"); + return -1; + } /* end if */ + + /* copy content to be sent */ + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Copying into the buffer %d bytes of header (total memory allocated: %d)", + header_size, (int) length + header_size + 1); + memcpy (send_buffer, header, header_size); + if (length > 0) { + memcpy (send_buffer + header_size, content, length); + + /* mask content before sending if requested */ + if (masked) { + nopoll_conn_mask_content (conn->ctx, send_buffer + header_size, length, mask, 0); + } + } /* end if */ + + + /* send content */ + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Mask used for this delivery: %d (about to send %d bytes)", + nopoll_get_32bit (send_buffer + header_size - 2), (int) length + header_size); + /* clear errno status before writting */ + desp = 0; + tries = 0; + while (nopoll_true) { + /* try to write bytes */ + if (sleep_in_header == 0) { + bytes_written = conn->sends (conn, send_buffer + desp, length + header_size - desp); + } else { + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Found sleep in header indication, sending header: %d bytes (waiting %ld)", header_size, sleep_in_header); + bytes_written = conn->sends (conn, send_buffer, header_size); + if (bytes_written == header_size) { + /* sleep after header ... */ + nopoll_sleep (sleep_in_header); + + /* now send the rest of the content (without the header) */ + bytes_written = conn->sends (conn, send_buffer + header_size, length); + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Rest of content written %d (header size: %d, length: %d)", + bytes_written, header_size, length); + bytes_written = length + header_size; + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "final bytes_written %d", bytes_written); + } else { + nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "Requested to write %d bytes for the header but %d were written", + header_size, bytes_written); + return -1; + } /* end if */ + } /* end if */ + + if ((bytes_written + desp) != (length + header_size)) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, + "Requested to write %d bytes but found %d written (masked? %d, mask: %u, header size: %d, length: %d), errno = %d : %s", + (int) length + header_size - desp, bytes_written, masked, mask_value, header_size, (int) length, errno, strerror (errno)); + } else { + /* accomulate bytes written to continue */ + if (bytes_written > 0) + desp += bytes_written; + + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Bytes written to the wire %d (masked? %d, mask: %u, header size: %d, length: %d)", + bytes_written, masked, mask_value, header_size, (int) length); + break; + } /* end if */ + + /* accomulate bytes written to continue */ + if (bytes_written > 0) + desp += bytes_written; + + /* increase tries */ + tries++; + + if ((errno != 0) || tries > 50) { + nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "Found errno=%d (%s) value while trying to bytes to the WebSocket conn-id=%d or max tries reached=%d", + errno, strerror (errno), conn->id, tries); + break; + } /* end if */ + + /* wait a bit */ + nopoll_sleep (100000); + + } /* end while */ + + /* record pending write bytes */ + conn->pending_write_bytes = length + header_size - desp; + +#if defined(SHOW_DEBUG_LOG) + level = NOPOLL_LEVEL_DEBUG; + if (desp != (length + header_size)) + level = NOPOLL_LEVEL_CRITICAL; + else if (errno == NOPOLL_EWOULDBLOCK && conn->pending_write_bytes > 0) + level = NOPOLL_LEVEL_WARNING; + + nopoll_log (conn->ctx, level, + "Write operation finished with with last result=%d, bytes_written=%d, requested=%d, remaining=%d (conn-id=%d)", + /* report want we are going to report: result */ + bytes_written <= 0 ? bytes_written : desp - header_size, + /* bytes written */ + desp - header_size, + length, conn->pending_write_bytes, conn->id); +#endif + + /* check pending bytes for the next operation */ + if (conn->pending_write_bytes > 0) { + conn->pending_write = nopoll_new (char, conn->pending_write_bytes); + memcpy (conn->pending_write, send_buffer + length + header_size - conn->pending_write_bytes, conn->pending_write_bytes); + + nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Stored %d bytes starting from %d out of %d bytes (header size: %d)", + conn->pending_write_bytes, length + header_size - conn->pending_write_bytes, length + header_size, header_size); + } /* end if */ + + + /* release memory */ + nopoll_free (send_buffer); + + /* report at least what was written */ + if (desp - header_size > 0) + return desp - header_size; + + /* report last operation */ + return bytes_written; +} + +/** + * @brief Allows to accept a new incoming WebSocket connection on the + * provided listener. + * + * @param ctx The context where the operation will take place. + * + * @param listener The WebSocket listener that is receiving a new incoming connection. + * + * @return A newly created \ref noPollConn reference or NULL if it + * fails. + */ +noPollConn * nopoll_conn_accept (noPollCtx * ctx, noPollConn * listener) +{ + NOPOLL_SOCKET session; + + nopoll_return_val_if_fail (ctx, ctx && listener, NULL); + + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Calling to accept web socket connection over master id=%d, socket=%d", + listener->id, listener->session); + + /* recevied a new connection: accept the + * connection and ask the app level to accept + * or not */ + session = nopoll_listener_accept (listener->session); + if (session == NOPOLL_INVALID_SOCKET) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Received invalid socket value from accept(2): %d, error code errno=: %d", + session, errno); + return NULL; + } /* end if */ + + return nopoll_conn_accept_socket (ctx, listener, session); +} + + +/** + * @brief Allows to accept a new incoming WebSocket connection on the + * provided listener but with a socket already accepted. + * + * @param ctx The context where the operation will take place. + * + * @param listener The WebSocket listener that is receiving a new incoming connection. + * + * @param session An already accepted socket from the provided + * listener. + * + * @return A newly created \ref noPollConn reference or NULL if it + * fails. + */ +noPollConn * nopoll_conn_accept_socket (noPollCtx * ctx, noPollConn * listener, NOPOLL_SOCKET session) +{ + noPollConn * conn; + + nopoll_return_val_if_fail (ctx, ctx && listener, NULL); + + /* create the connection */ + conn = nopoll_listener_from_socket (ctx, session); + if (conn == NULL) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Received NULL pointer after calling to create listener from session.."); + return NULL; + } /* end if */ + + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Accepted new WebSocket conn-id=%d, socket=%d, over master id=%d, socket=%d", + conn->id, conn->session, listener->id, listener->session); + + /* configure the listener reference that accepted this + * connection */ + conn->listener = listener; + + if (! nopoll_conn_accept_complete (ctx, listener, conn, session, listener->tls_on)) + return NULL; + + /* report listener created */ + return conn; +} + +/** + * @internal Function to support accept listener operations. + */ +nopoll_bool __nopoll_conn_accept_complete_common (noPollCtx * ctx, noPollConnOpts * options, noPollConn * listener, noPollConn * conn, NOPOLL_SOCKET session, nopoll_bool tls_on) { + + const char * certificateFile = NULL; + const char * privateKey = NULL; + const char * chainCertificate = NULL; + const char * serverName = NULL; + + /* check input parameters */ + if (! (ctx && listener && conn && session != NOPOLL_INVALID_SOCKET)) { + nopoll_conn_shutdown (conn); + nopoll_ctx_unregister_conn (ctx, conn); + + /* release connection options */ + __nopoll_conn_opts_release_if_needed (options); + + return nopoll_false; + } /* end if */ + + /* configure non blocking mode */ + nopoll_conn_set_sock_block (session, nopoll_true); + + /* now check for accept handler */ + if (ctx->on_accept) { + /* call to on accept */ + if (! ctx->on_accept (ctx, conn, ctx->on_accept_data)) { + nopoll_log (ctx, NOPOLL_LEVEL_WARNING, "Application level denied accepting connection from %s:%s, closing", + conn->host, conn->port); + nopoll_conn_shutdown (conn); + nopoll_ctx_unregister_conn (ctx, conn); + + /* release connection options */ + __nopoll_conn_opts_release_if_needed (options); + + return nopoll_false; + } /* end if */ + } /* end if */ + + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Connection received and accepted from %s:%s (conn refs: %d, ctx refs: %d)", + listener->host, listener->port, listener->refs, ctx->refs); + + if (listener->tls_on || tls_on) { + /* reached this point, ensure tls is enabled on this + * session */ + conn->tls_on = nopoll_true; + + /* get here SNI to query about the serverName */ + + /* 1) GET FROM OPTIONS: detect here if we have + * certificates provided through options */ + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Starting TLS process, options=%p, listener=%p", options, listener); + + if (options) { + certificateFile = options->certificate; + privateKey = options->private_key; + } /* end if */ + if (certificateFile == NULL || privateKey == NULL) { + + /* 2) GET FROM LISTENER: get references to currently configured certificate file */ + certificateFile = listener->certificate; + privateKey = listener->private_key; + if (certificateFile == NULL || privateKey == NULL) { + /* 3) GET FROM STORE: check if the + * certificate is already installed */ + nopoll_ctx_find_certificate (ctx, serverName, &certificateFile, &privateKey, &chainCertificate); + } + } /* end if */ + + /* check certificates and private key */ + if (certificateFile == NULL || privateKey == NULL) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Unable to accept secure web socket connection, certificate file %s and/or key file %s isn't defined", + certificateFile ? certificateFile : "", + privateKey ? privateKey : ""); + nopoll_conn_shutdown (conn); + nopoll_ctx_unregister_conn (ctx, conn); + + /* release connection options */ + __nopoll_conn_opts_release_if_needed (options); + + return nopoll_false; + } /* end if */ + + /* init ssl ciphers and engines */ + if (! __nopoll_tls_was_init) { + __nopoll_tls_was_init = nopoll_true; + SSL_library_init (); + } /* end if */ + + /* now configure chainCertificate */ + if (listener->chain_certificate) + chainCertificate = listener->chain_certificate; + else if (options && options->chain_certificate) + chainCertificate = options->chain_certificate; + + /* create ssl context */ + conn->ssl_ctx = __nopoll_conn_get_ssl_context (ctx, conn, listener->opts, nopoll_false); + + /* Configure ca certificate in the case it is defined */ + if (options && options->ca_certificate) { + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Setting up CA certificate: %s", options->ca_certificate); + if (SSL_CTX_load_verify_locations (conn->ssl_ctx, options->ca_certificate, NULL) != 1) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to configure CA certificate (%s), SSL_CTX_load_verify_locations () failed", options->ca_certificate); + return nopoll_false; + } /* end if */ + + } /* end if */ + + /* enable default verification paths */ + if (SSL_CTX_set_default_verify_paths (conn->ssl_ctx) != 1) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Unable to configure default verification paths, SSL_CTX_set_default_verify_paths () failed"); + return nopoll_false; + } /* end if */ + + /* configure chain certificate */ + if (chainCertificate) { + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Setting up chain certificate: %s", chainCertificate); + if (SSL_CTX_use_certificate_chain_file (conn->ssl_ctx, chainCertificate) != 1) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to configure chain certificate (%s), SSL_CTX_use_certificate_chain_file () failed", chainCertificate); + return nopoll_false; + } /* end if */ + } /* end if */ + + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Using certificate file: %s (with ssl context ref: %p)", certificateFile, conn->ssl_ctx); + if (conn->ssl_ctx == NULL || SSL_CTX_use_certificate_chain_file (conn->ssl_ctx, certificateFile) != 1) { + /* drop an error log */ + if (conn->ssl_ctx == NULL) + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Unable to accept incoming connection, failed to create SSL context. Context creator returned NULL pointer"); + else + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "there was an error while setting certificate file into the SSl context, unable to start TLS profile. Failure found at SSL_CTX_use_certificate_file function. Tried certificate file: %s", + certificateFile); + + /* dump error stack */ + nopoll_conn_shutdown (conn); + nopoll_ctx_unregister_conn (ctx, conn); + + /* release connection options */ + __nopoll_conn_opts_release_if_needed (options); + + return nopoll_false; + } /* end if */ + + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Using certificate key: %s", privateKey); + if (SSL_CTX_use_PrivateKey_file (conn->ssl_ctx, privateKey, SSL_FILETYPE_PEM) != 1) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, + "there was an error while setting private file into the SSl context, unable to start TLS profile. Failure found at SSL_CTX_use_PrivateKey_file function. Tried private file: %s", + privateKey); + /* dump error stack */ + nopoll_conn_shutdown (conn); + nopoll_ctx_unregister_conn (ctx, conn); + + /* release connection options */ + __nopoll_conn_opts_release_if_needed (options); + + return nopoll_false; + } + + /* check for private key and certificate file to match. */ + if (! SSL_CTX_check_private_key (conn->ssl_ctx)) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, + "seems that certificate file and private key doesn't match!, unable to start TLS profile. Failure found at SSL_CTX_check_private_key function. Used certificate %s, and key: %s", + certificateFile, privateKey); + /* dump error stack */ + nopoll_conn_shutdown (conn); + + /* release connection options */ + __nopoll_conn_opts_release_if_needed (options); + + return nopoll_false; + } /* end if */ + + if (options != NULL && ! options->disable_ssl_verify) { + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Enabling certificate client peer verification from server"); + /** really, really ugly hack to let + * __nopoll_conn_ssl_verify_callback to be able to get + * access to the context required to drop some logs */ + __nopoll_conn_ssl_ctx_debug = ctx; + SSL_CTX_set_verify (conn->ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, __nopoll_conn_ssl_verify_callback); + SSL_CTX_set_verify_depth (conn->ssl_ctx, 5); + } /* end if */ + + + /* create SSL context */ + conn->ssl = (SSL*)SSL_new (conn->ssl_ctx); + if (conn->ssl == NULL) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "error while creating TLS transport, SSL_new (%p) returned NULL", conn->ssl_ctx); + nopoll_conn_shutdown (conn); + nopoll_ctx_unregister_conn (ctx, conn); + + /* release connection options */ + __nopoll_conn_opts_release_if_needed (options); + + return nopoll_false; + } /* end if */ + + /* set the file descriptor */ + SSL_set_fd (conn->ssl, conn->session); + + /* don't complete here the operation but flag it as + * pending */ + conn->pending_ssl_accept = nopoll_true; + nopoll_conn_set_sock_block (conn->session, nopoll_false); + + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Prepared TLS session to be activated on next reads (conn id %d)", conn->id); + + } /* end if */ + + /* release connection options */ + __nopoll_conn_opts_release_if_needed (options); + + return nopoll_true; +} + +/** + * @brief Allows to complete accept operation by setting up all I/O + * handlers required to make the WebSocket connection to work. + * + * @param ctx The context where the operation takes place. + * + * @param listener The listener where the connection was accepted. + * + * @param conn The connection that was accepted. + * + * @param session The socket associated to the listener accepted. + * + * @param tls_on A boolean indication if the TLS interface should be + * enabled or not. + * + * @return nopoll_true if the listener was accepted otherwise nopoll_false is returned. + */ +nopoll_bool nopoll_conn_accept_complete (noPollCtx * ctx, noPollConn * listener, noPollConn * conn, NOPOLL_SOCKET session, nopoll_bool tls_on) { + + if (listener->opts) { + if (! nopoll_conn_opts_ref (listener->opts)) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Unable to acquire a reference to the connection option at nopoll_conn_accept_complete() function nopoll_conn_opts_ref () failed.."); + return nopoll_false; + } /* end if */ + } /* end if */ + + return __nopoll_conn_accept_complete_common (ctx, listener->opts, listener, conn, session, tls_on); +} + +/** + * @brief Allows to implement a wait operation until the provided + * connection is ready or the provided timeout is reached. + * + * @param conn The connection that is being waited to be created. + * + * @param timeout The timeout operation to limit the wait + * operation. Timeout is provided in seconds. + * + * @return The function returns when the timeout was reached or the + * connection is ready. In the case the connection is ready when the + * function finished nopoll_true is returned, otherwise nopoll_false. + */ +nopoll_bool nopoll_conn_wait_until_connection_ready (noPollConn * conn, + int timeout) +{ + long int total_timeout = timeout * 1000000; + + /* check if the connection already finished its connection + handshake */ + while (! nopoll_conn_is_ready (conn) && total_timeout > 0) { + + /* check if the connection is ok */ + if (! nopoll_conn_is_ok (conn)) + return nopoll_false; + + /* wait a bit 0,5ms */ + nopoll_sleep (500); + + /* reduce the amount of time we have to wait */ + total_timeout = total_timeout - 500; + } /* end if */ + + /* report if the connection is ok */ + return nopoll_conn_is_ok (conn) && nopoll_conn_is_ready (conn); +} + +/* @} */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_conn_opts.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_conn_opts.c new file mode 100644 index 0000000..c5a4b7d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_conn_opts.c @@ -0,0 +1,325 @@ +/* + * LibNoPoll: A websocket library + * Copyright (C) 2013 Advanced Software Production Line, S.L. + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * You may find a copy of the license under this software is released + * at COPYING file. This is LGPL software: you are welcome to develop + * proprietary applications using this library without any royalty or + * fee but returning back any change, improvement or addition in the + * form of source code, project image, documentation patches, etc. + * + * For commercial support on build Websocket enabled solutions + * contact us: + * + * Postal address: + * Advanced Software Production Line, S.L. + * Edificio Alius A, Oficina 102, + * C/ Antonio Suarez Nº 10, + * Alcalá de Henares 28802 Madrid + * Spain + * + * Email address: + * info@aspl.es - http://www.aspl.es/nopoll + */ +#include +#include + +/** + * \defgroup nopoll_conn_opts noPoll Connection Options: API to change default connection options. + */ + +/** + * \addtogroup nopoll_conn_opts + * @{ + */ + +/** + * @brief Create a new connection options object. + * + * @return A newly created connection options object. In general you don't have to worry about releasing this object because this is automatically done by functions using this object. However, if you call to \ref nopoll_conn_opts_set_reuse (opts, nopoll_true), then you'll have to use \ref nopoll_conn_opts_free to release the object after it is no longer used. The function may return NULL in case of memory allocation problems. Creating an object without setting anything will cause the library to provide same default behaviour as not providing it. + */ +noPollConnOpts * nopoll_conn_opts_new (void) +{ + noPollConnOpts * result; + + /* create configuration object */ + result = nopoll_new (noPollConnOpts, 1); + if (! result) + return NULL; + + result->reuse = nopoll_false; /* this is not needed, just to clearly state defaults */ + result->ssl_protocol = NOPOLL_METHOD_TLSV1; + + result->mutex = nopoll_mutex_create (); + result->refs = 1; + + /* by default, disable ssl peer verification */ + result->disable_ssl_verify = nopoll_true; + + return result; +} + +/** + * @brief Set ssl protocol method to be used on the API receiving this + * configuration object. + * + * @param opts The connection options object. + * + * @param ssl_protocol SSL protocol to use. See \ref noPollSslProtocol for more information. + */ +void nopoll_conn_opts_set_ssl_protocol (noPollConnOpts * opts, noPollSslProtocol ssl_protocol) +{ + if (opts == NULL) + return; + opts->ssl_protocol = ssl_protocol; + return; +} + + +/** + * @brief Allows to certificate, private key and optional chain + * certificate and ca for on a particular options that can be used for + * a client and a listener connection. + * + * @param opts The connection options where these settings will be + * applied. + * + * @param certificate The certificate to use on the connection. + * + * @param private_key client_certificate private key. + * + * @param chain_certificate Optional chain certificate to use + * + * @param ca_certificate Optional CA certificate to use during the + * process. + * + * @return nopoll_true in the case all certificate files provided are + * reachable. + */ +nopoll_bool nopoll_conn_opts_set_ssl_certs (noPollConnOpts * opts, + const char * certificate, + const char * private_key, + const char * chain_certificate, + const char * ca_certificate) +{ + if (opts == NULL) + return nopoll_false; + + /* store certificate settings */ + opts->certificate = nopoll_strdup (certificate); + if (opts->certificate) +// if (access (opts->certificate, R_OK) != 0) +// return nopoll_false; + opts->private_key = nopoll_strdup (private_key); + if (opts->private_key) +// if (access (opts->private_key, R_OK) != 0) +// return nopoll_false; + opts->chain_certificate = nopoll_strdup (chain_certificate); + if (opts->chain_certificate) +// if (access (opts->chain_certificate, R_OK) != 0) +// return nopoll_false; + opts->ca_certificate = nopoll_strdup (ca_certificate); + if (opts->ca_certificate) +// if (access (opts->ca_certificate, R_OK) != 0) +// return nopoll_false; + + return nopoll_true; +} + +/** + * @brief Allows to disable peer ssl certificate verification. This is + * not recommended for production enviroment. This affects in a + * different manner to a listener connection and a client connection. + * + * For a client connection, by default, peer verification is enabled + * and this function may help to disable it during development or + * other reasons. + * + * In the case of the servers (created by using \ref + * nopoll_listener_new for example) this is not required because by + * default peer verification is disabled by default. + * + * @param opts The connection option to configure. + * + * @param verify nopoll_true to disable verification + * otherwise, nopoll_false should be used. By default SSL verification + * is enabled. + * + */ +void nopoll_conn_opts_ssl_peer_verify (noPollConnOpts * opts, nopoll_bool verify) +{ + if (opts == NULL) + return; + opts->disable_ssl_verify = ! verify; + return; +} + +/** + * @brief Allows to set Cookie header content to be sent during the + * connection handshake. If configured and the remote side server is a + * noPoll peer, use \ref nopoll_conn_get_cookie to get this value. + * + * @param opts The connection option to configure. + * + * @param cookie_content Content for the cookie. If you pass NULL the + * cookie is unset. + */ +void nopoll_conn_opts_set_cookie (noPollConnOpts * opts, const char * cookie_content) +{ + if (opts == NULL) + return; + + if (cookie_content) { + /* configure cookie content to be sent */ + opts->cookie = nopoll_strdup (cookie_content); + } else { + nopoll_free (opts->cookie); + opts->cookie = NULL; + } /* end if */ + + return; +} + + +/** + * @brief Allows to increase a reference to the connection options + * provided. + * + * @param opts The connection option reference over which a connection + * reference is needed. + * + * @return nopoll_true in the case the operation went ok, otherwise + * nopoll_false is returned. + */ +nopoll_bool nopoll_conn_opts_ref (noPollConnOpts * opts) +{ + if (opts == NULL) + return nopoll_false; + + /* lock the mutex */ + nopoll_mutex_lock (opts->mutex); + if (opts->refs <= 0) { + /* unlock the mutex */ + nopoll_mutex_unlock (opts->mutex); + return nopoll_false; + } + + opts->refs++; + + /* release here the mutex */ + nopoll_mutex_unlock (opts->mutex); + + return nopoll_true; +} + +/** + * @brief Allows to unref a reference acquired by \ref nopoll_conn_opts_ref + * + * @param opts The connection opts to release. + */ +void nopoll_conn_opts_unref (noPollConnOpts * opts) +{ + /* call free implementation */ + nopoll_conn_opts_free (opts); + return; +} + + +/** + * @brief Set reuse-flag be used on the API receiving this + * configuration object. By setting nopoll_true will cause the API to + * not release the object when finished. Instead, the caller will be + * able to use this object in additional API calls but, after + * finishing, a call to \ref nopoll_conn_opts_set_reuse function is + * required. + * + * @param opts The connection options object. + * + * @param reuse nopoll_true to reuse the object across calls, + * otherwise nopoll_false to make the API function to release the + * object when done. + */ +void nopoll_conn_opts_set_reuse (noPollConnOpts * opts, nopoll_bool reuse) +{ + if (opts == NULL) + return; + opts->reuse = reuse; + return; +} + +void __nopoll_conn_opts_free_common (noPollConnOpts * opts) +{ + if (opts == NULL) + return; + + /* acquire here the mutex */ + nopoll_mutex_lock (opts->mutex); + + opts->refs--; + if (opts->refs != 0) { + /* release here the mutex */ + nopoll_mutex_unlock (opts->mutex); + return; + } + /* release here the mutex */ + nopoll_mutex_unlock (opts->mutex); + + nopoll_free (opts->certificate); + nopoll_free (opts->private_key); + nopoll_free (opts->chain_certificate); + nopoll_free (opts->ca_certificate); + + /* cookie */ + nopoll_free (opts->cookie); + + /* release mutex */ + nopoll_mutex_destroy (opts->mutex); + nopoll_free (opts); + return; +} + +/** + * @brief Allows to release a connection object reported by \ref nopoll_conn_opts_new + * + * IMPORTANT NOTE: do not use this function over a \ref noPollConnOpts if it is not flagged with \ref nopoll_conn_opts_set_reuse (opts, nopoll_true). + * + * Default behaviour provided by the API implies that every connection + * options object created by \ref nopoll_conn_opts_new is + * automatically released by the API consuming that object. + */ +void nopoll_conn_opts_free (noPollConnOpts * opts) +{ + __nopoll_conn_opts_free_common (opts); + return; +} /* end if */ + +/** + * @internal API. Do not use it. It may change at any time without any + * previous indication. + */ +void __nopoll_conn_opts_release_if_needed (noPollConnOpts * options) +{ + if (! options) + return; + if (options && options->reuse) + return; + __nopoll_conn_opts_free_common (options); + return; +} + +/* @} */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_ctx.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_ctx.c new file mode 100644 index 0000000..3ee1beb --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_ctx.c @@ -0,0 +1,802 @@ +/* + * LibNoPoll: A websocket library + * Copyright (C) 2013 Advanced Software Production Line, S.L. + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * You may find a copy of the license under this software is released + * at COPYING file. This is LGPL software: you are welcome to develop + * proprietary applications using this library without any royalty or + * fee but returning back any change, improvement or addition in the + * form of source code, project image, documentation patches, etc. + * + * For commercial support on build Websocket enabled solutions + * contact us: + * + * Postal address: + * Advanced Software Production Line, S.L. + * Edificio Alius A, Oficina 102, + * C/ Antonio Suarez Nº 10, + * Alcalá de Henares 28802 Madrid + * Spain + * + * Email address: + * info@aspl.es - http://www.aspl.es/nopoll + */ +#include +#include +//#include + +/** + * \defgroup nopoll_ctx noPoll Context: context handling functions used by the library + */ + +/** + * \addtogroup nopoll_ctx + * @{ + */ +void __nopoll_ctx_sigpipe_do_nothing (int _signal) +{ +#if !defined(NOPOLL_OS_WIN32) + /* do nothing sigpipe handler to be able to manage EPIPE error + * returned by write ops. */ + + /* the following line is to ensure ancient glibc version that + * restores to the default handler once the signal handling is + * executed. */ +// signal (SIGPIPE, __nopoll_ctx_sigpipe_do_nothing); +#endif + return; +} + + +/** + * @brief Creates an empty Nopoll context. + */ +noPollCtx * nopoll_ctx_new (void) { + noPollCtx * result = nopoll_new (noPollCtx, 1); + if (result == NULL) + return NULL; + +#if defined(NOPOLL_OS_WIN32) + if (! nopoll_win32_init (result)) + return NULL; +#endif + + /* set initial reference */ + result->conn_id = 1; + result->refs = 1; + result->conn_id = 1; + + /* 20 seconds for connection timeout */ + result->conn_connect_std_timeout = 20000000; + + /* default log initialization */ + result->not_executed = nopoll_true; + result->debug_enabled = nopoll_false; + + /* colored log */ + result->not_executed_color = nopoll_true; + result->debug_color_enabled = nopoll_false; + + /* default back log */ + result->backlog = 5; + + /* current list length */ + result->conn_length = 0; + +#if !defined(NOPOLL_OS_WIN32) + /* install sigpipe handler */ +// signal (SIGPIPE, __nopoll_ctx_sigpipe_do_nothing); +#endif + + /* setup default protocol version */ + result->protocol_version = 13; + + /* create mutexes */ + result->ref_mutex = nopoll_mutex_create (); + + return result; +} + +/** + * @brief Allows to acquire a reference to the provided context. This + * reference is released by calling to \ref nopoll_ctx_unref. + * + * @param ctx The context to acquire a reference. + * + * @return The function returns nopoll_true in the case the reference + * was acquired, otherwise nopoll_false is returned. + */ +nopoll_bool nopoll_ctx_ref (noPollCtx * ctx) +{ + /* return false value */ + nopoll_return_val_if_fail (ctx, ctx, nopoll_false); + + /* acquire mutex here */ + nopoll_mutex_lock (ctx->ref_mutex); + + ctx->refs++; + + /* release mutex here */ + nopoll_mutex_unlock (ctx->ref_mutex); + + return nopoll_true; +} + + +/** + * @brief allows to release a reference acquired to the provided + * noPoll context. + * + * @param ctx The noPoll context reference to release.. + */ +void nopoll_ctx_unref (noPollCtx * ctx) +{ + noPollCertificate * cert; + int iterator; + + nopoll_return_if_fail (ctx, ctx); + + /* acquire mutex here */ + nopoll_mutex_lock (ctx->ref_mutex); + + ctx->refs--; + if (ctx->refs != 0) { + /* release mutex here */ + nopoll_mutex_unlock (ctx->ref_mutex); + return; + } + /* release mutex here */ + nopoll_mutex_unlock (ctx->ref_mutex); + + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Releasing no poll context %p (%d, conns: %d)", ctx, ctx->refs, ctx->conn_length); + + iterator = 0; + while (iterator < ctx->certificates_length) { + /* get reference */ + cert = &(ctx->certificates[iterator]); + + /* release */ + nopoll_free (cert->serverName); + nopoll_free (cert->certificateFile); + nopoll_free (cert->privateKey); + nopoll_free (cert->optionalChainFile); + + /* next position */ + iterator++; + } /* end while */ + + /* release mutex */ + nopoll_mutex_destroy (ctx->ref_mutex); + + /* release all certificates buckets */ + nopoll_free (ctx->certificates); + + /* release connection */ + nopoll_free (ctx->conn_list); + ctx->conn_length = 0; + nopoll_free (ctx); + return; +} + +/** + * @brief Allows to get current reference counting for the provided + * context. + * + * @param ctx The context the reference counting is being requested. + * + * @return The reference counting or -1 if it fails. + */ +int nopoll_ctx_ref_count (noPollCtx * ctx) +{ + int result; + if (! ctx) + return -1; + + /* lock */ + nopoll_mutex_lock (ctx->ref_mutex); + + result = ctx->refs; + + /* unlock */ + nopoll_mutex_unlock (ctx->ref_mutex); + + return result; +} + +/** + * @internal Function used to register the provided connection on the + * provided context. + * + * @param ctx The context where the connection will be registered. + * + * @param conn The connection to be registered. + * + * @return nopoll_true if the connection was registered, otherwise + * nopoll_false is returned. + */ +nopoll_bool nopoll_ctx_register_conn (noPollCtx * ctx, + noPollConn * conn) +{ + int iterator; + + nopoll_return_val_if_fail (ctx, ctx && conn, nopoll_false); + + /* acquire mutex here */ + nopoll_mutex_lock (ctx->ref_mutex); + + /* get connection */ + conn->id = ctx->conn_id; + ctx->conn_id ++; + + /* register connection */ + iterator = 0; + while (iterator < ctx->conn_length) { + + /* register reference */ + if (ctx->conn_list[iterator] == 0) { + ctx->conn_list[iterator] = conn; + + /* update connection list number */ + ctx->conn_num++; + + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "registered connection id %d, role: %d", conn->id, conn->role); + + /* release */ + nopoll_mutex_unlock (ctx->ref_mutex); + + /* acquire reference */ + nopoll_ctx_ref (ctx); + + /* acquire a reference to the conection */ + nopoll_conn_ref (conn); + + /* release mutex here */ + return nopoll_true; + } + + iterator++; + } /* end while */ + + /* if reached this place it means no more buckets are + * available, acquire more memory (increase 10 by 10) */ + ctx->conn_length += 10; + ctx->conn_list = (noPollConn**) nopoll_realloc (ctx->conn_list, sizeof (noPollConn *) * (ctx->conn_length)); + if (ctx->conn_list == NULL) { + /* release mutex */ + nopoll_mutex_unlock (ctx->ref_mutex); + + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "General connection registration error, memory acquisition failed.."); + return nopoll_false; + } /* end if */ + + /* clear new positions */ + iterator = (ctx->conn_length - 10); + while (iterator < ctx->conn_length) { + ctx->conn_list[iterator] = 0; + /* next position */ + iterator++; + } /* end while */ + + /* release mutex here */ + nopoll_mutex_unlock (ctx->ref_mutex); + + /* ok, now register connection because we have memory */ + return nopoll_ctx_register_conn (ctx, conn); +} + +/** + * @internal Function used to register the provided connection on the + * provided context. + * + * @param ctx The context where the connection will be registered. + * + * @param conn The connection to be registered. + */ +void nopoll_ctx_unregister_conn (noPollCtx * ctx, + noPollConn * conn) +{ + int iterator; + + nopoll_return_if_fail (ctx, ctx && conn); + + /* acquire mutex here */ + nopoll_mutex_lock (ctx->ref_mutex); + + /* find the connection and remove it from the array */ + iterator = 0; + while (iterator < ctx->conn_length) { + + /* check the connection reference */ + if (ctx->conn_list && ctx->conn_list[iterator] && ctx->conn_list[iterator]->id == conn->id) { + /* remove reference */ + ctx->conn_list[iterator] = NULL; + + /* update connection list number */ + ctx->conn_num--; + + /* release */ + nopoll_mutex_unlock (ctx->ref_mutex); + + /* acquire a reference to the conection */ + nopoll_conn_unref (conn); + + break; + } /* end if */ + + iterator++; + } /* end while */ + + /* release mutex here */ + nopoll_mutex_unlock (ctx->ref_mutex); + + return; +} + +/** + * @brief Allows to get number of connections currently registered. + * + * @param ctx The context where the operation is requested. + * + * @return Number of connections registered on this context or -1 if it fails. + */ +int nopoll_ctx_conns (noPollCtx * ctx) +{ + nopoll_return_val_if_fail (ctx, ctx, -1); + return ctx->conn_num; +} + +/** + * @brief Allows to find the certificate associated to the provided serverName. + * + * @param ctx The context where the operation will take place. + * + * @param serverName the servername to use as pattern to find the + * right certificate. If NULL is provided the first certificate not + * refering to any serverName will be returned. + * + * @param certificateFile If provided a reference and the function + * returns nopoll_true, it will contain the certificateFile found. + * + * @param privateKey If provided a reference and the function + * returns nopoll_true, it will contain the privateKey found. + * + * @param optionalChainFile If provided a reference and the function + * returns nopoll_true, it will contain the optionalChainFile found. + * + * @return nopoll_true in the case the certificate was found, + * otherwise nopoll_false is returned. + */ +nopoll_bool nopoll_ctx_find_certificate (noPollCtx * ctx, + const char * serverName, + const char ** certificateFile, + const char ** privateKey, + const char ** optionalChainFile) +{ + noPollCertificate * cert; + + int iterator = 0; + nopoll_return_val_if_fail (ctx, ctx, nopoll_false); + + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Finding a certificate for serverName=%s", serverName ? serverName : ""); + + while (iterator < ctx->certificates_length) { + /* get cert */ + cert = &(ctx->certificates[iterator]); + if (cert) { + /* found a certificate */ + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, " certificate stored associated to serverName=%s", cert->serverName ? cert->serverName : ""); + if ((serverName == NULL && cert->serverName == NULL) || + (nopoll_cmp (serverName, cert->serverName))) { + if (certificateFile) + (*certificateFile) = cert->certificateFile; + if (privateKey) + (*privateKey) = cert->privateKey; + if (optionalChainFile) + (*optionalChainFile) = cert->optionalChainFile; + return nopoll_true; + } /* end if */ + } /* end if */ + + /* next position */ + iterator++; + } + + /* check for default certificate when serverName isn't defined */ + if (serverName == NULL) { + /* requested a certificate for an undefined serverName */ + iterator = 0; + while (iterator < ctx->certificates_length) { + /* get cert */ + cert = &(ctx->certificates[iterator]); + if (cert) { + /* found a certificate */ + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, " serverName not defined, selecting first certificate from the list"); + if (certificateFile) + (*certificateFile) = cert->certificateFile; + if (privateKey) + (*privateKey) = cert->privateKey; + if (optionalChainFile) + (*optionalChainFile) = cert->optionalChainFile; + return nopoll_true; + } /* end if */ + } /* end if */ + + /* next position */ + iterator++; + } /* end if */ + + return nopoll_false; +} + +/** + * @brief Allows to install a certificate to be used in general by all + * listener connections working under the provided context. + * + * @param ctx The context where the certificate will be installed. + * + * @param serverName The optional server name to to limit the use of + * this certificate to the value provided here. Provide a NULL value + * to make the certificate provide to work under any server notified + * (Host: header) or via SNI (server name identification associated to + * the TLS transport). + * + * @param certificateFile The certificate file to be installed. + * + * @param privateKey The private key file to use used. + * + * @param optionalChainFile Optional chain file with additional + * material to complete the certificate definition. + * + * @return nopoll_true if the certificate was installed otherwise + * nopoll_false. The function returns nopoll_false when ctx, certificateFile or privateKey are NULL. + */ +nopoll_bool nopoll_ctx_set_certificate (noPollCtx * ctx, + const char * serverName, + const char * certificateFile, + const char * privateKey, + const char * optionalChainFile) +{ + int length; + noPollCertificate * cert; + + /* check values before proceed */ + nopoll_return_val_if_fail (ctx, ctx && certificateFile && privateKey, nopoll_false); + + /* check if the certificate is already installed */ + if (nopoll_ctx_find_certificate (ctx, serverName, NULL, NULL, NULL)) + return nopoll_true; + + /* update certificate storage to hold all values */ + ctx->certificates_length++; + length = ctx->certificates_length; + if (length == 1) + ctx->certificates = nopoll_new (noPollCertificate, 1); + else + ctx->certificates = (noPollCertificate *) nopoll_realloc (ctx->certificates, sizeof (noPollCertificate) * (length)); + + /* hold certificate */ + cert = &(ctx->certificates[length - 1]); + + cert->serverName = NULL; + if (serverName) + cert->serverName = nopoll_strdup (serverName); + + cert->certificateFile = NULL; + if (certificateFile) + cert->certificateFile = nopoll_strdup (certificateFile); + + cert->privateKey = NULL; + if (privateKey) + cert->privateKey = nopoll_strdup (privateKey); + + cert->optionalChainFile = NULL; + if (optionalChainFile) + cert->optionalChainFile = nopoll_strdup (optionalChainFile); + + return nopoll_true; +} + +/** + * @brief Allows to configure the on open handler, the handler that is + * called when it is received an incoming websocket connection and all + * websocket client handshake data was received (but still not required). + * + * This handler differs from \ref nopoll_ctx_set_on_accept this + * handler is called after all client handshake data was received. + * + * Note the connection is still not fully working at this point + * because the handshake hasn't been sent to the remote peer yet. This + * means that attempting to send any content inside this handler (for + * example by using \ref nopoll_conn_send_text) will cause a protocol + * violation (because remote side is expecting a handshake reply but + * received something different). + * + * In the case you want to sent content right away after receiving a + * connection (on a listener), you can use \ref + * nopoll_ctx_set_on_ready "On Ready" handler which is called just + * after the connection has been fully accepted and handshake reply is + * fully written. + * + * @param ctx The context that will be configured. + * + * @param on_open The handler to be configured on this context. + * + * @param user_data User defined pointer to be passed to the on open + * handler + */ +void nopoll_ctx_set_on_open (noPollCtx * ctx, + noPollActionHandler on_open, + noPollPtr user_data) +{ + nopoll_return_if_fail (ctx, ctx && on_open); + + /* set the handler */ + ctx->on_open = on_open; + if (ctx->on_open == NULL) + ctx->on_open_data = NULL; + else + ctx->on_open_data = user_data; + return; +} + +/** + * @brief Allows to configure a handler that is called when a + * connection is received and it is ready to send and receive because + * all WebSocket handshake protocol finished OK. + * + * Unlike handlers configured at \ref nopoll_ctx_set_on_open and \ref + * nopoll_ctx_set_on_accept which get notified when the connection + * isn't still working (because WebSocket handshake wasn't finished + * yet), on read handlers configured here will get called just after + * the WebSocket handshake has taken place. + * + * @param ctx The context that will be configured. + * + * @param on_ready The handler to be called when a connection is fully + * ready to send and receive content because WebSocket handshake has + * finished. The function must return nopoll_true to accept the + * connection. By returning nopoll_false the handler is signalling to + * terminate the connection. + * + * @param user_data Optional user data pointer passed to the on ready + * handler. + * + */ +void nopoll_ctx_set_on_ready (noPollCtx * ctx, + noPollActionHandler on_ready, + noPollPtr user_data) +{ + nopoll_return_if_fail (ctx, ctx && on_ready); + + /* set the handler */ + ctx->on_ready = on_ready; + if (ctx->on_ready == NULL) + ctx->on_ready_data = NULL; + else + ctx->on_ready_data = user_data; + return; +} + +/** + * @brief Allows to configure the accept handler that will be called + * when a connection is received but before any handshake takes place. + * + * @param ctx The context that will be configured. + * + * @param on_accept The handler to be called when a connection is + * received. Here the handler must return nopoll_true to accept the + * connection, otherwise nopoll_false should be returned. + * + * @param user_data Optional user data pointer passed to the on accept + * handler. + * + */ +void nopoll_ctx_set_on_accept (noPollCtx * ctx, + noPollActionHandler on_accept, + noPollPtr user_data) +{ + nopoll_return_if_fail (ctx, ctx && on_accept); + + /* set the handler */ + ctx->on_accept = on_accept; + if (ctx->on_accept == NULL) + ctx->on_accept_data = NULL; + else + ctx->on_accept_data = user_data; + return; +} + +/** + * @brief Allows to set a general handler to get notifications about a + * message received over any connection that is running under the + * provided context (noPollCtx). + * + * @param ctx The context where the notification will happen + * + * @param on_msg The handler to be called when an incoming message is + * received. + * + * @param user_data User defined pointer that is passed in into the + * handler when called. + * + * Note that the handler configured here will be overriden by the handler configured by \ref nopoll_conn_set_on_msg + * + */ +void nopoll_ctx_set_on_msg (noPollCtx * ctx, + noPollOnMessageHandler on_msg, + noPollPtr user_data) +{ + nopoll_return_if_fail (ctx, ctx); + + /* set new handler */ + ctx->on_msg = on_msg; + ctx->on_msg_data = user_data; + + return; +} + +/** + * @brief Allows to configure the handler that will be used to let + * user land code to define OpenSSL SSL_CTX object. + * + * By default, SSL_CTX (SSL Context) object is created by default + * settings that works for most of the cases. In the case you want to + * configure particular configurations that should be enabled on the + * provided SSL_CTX that is going to be used by the client ---while + * connecting--- or server ---while receiving a connection--- then use + * this function to setup your creator handler. + * + * See \ref noPollSslContextCreator for more information about this + * handler. + * + */ +void nopoll_ctx_set_ssl_context_creator (noPollCtx * ctx, + noPollSslContextCreator context_creator, + noPollPtr user_data) +{ + if (ctx == NULL) + return; + + /* set handlers as indicated by the caller */ + ctx->context_creator = context_creator; + ctx->context_creator_data = user_data; + return; +} + +/** + * @brief Allows to configure a function that will implement an post SSL/TLS check. + * + * See the following function to get more information: \ref noPollSslPostCheck + * + * @param ctx The context where the operation is taking place. + * + * @param post_ssl_check The handler that is going to be called + * everything a new connection with SSL is established by a client or + * received by a server. The handler is executed right after the SSL + * handshake finishes without error. + * + * @param user_data A reference to user defined pointer that will be + * passed in to the handler. + */ +void nopoll_ctx_set_post_ssl_check (noPollCtx * ctx, + noPollSslPostCheck post_ssl_check, + noPollPtr user_data) +{ + if (ctx == NULL) + return; + + /* set handlers as indicated by the caller */ + ctx->post_ssl_check = post_ssl_check; + ctx->post_ssl_check_data = user_data; + return; +} + +/** + * @brief Allows to iterate over all connections currently registered + * on the provided context, optionally stopping the foreach process, + * returning the connection reference selected if the foreach handler + * returns nopoll_true. + * + * @param ctx The nopoll context where the foreach operation will take + * place. + * + * @param foreach The foreach handler to be called for each connection + * registered. + * + * @param user_data An optional reference to a pointer that will be + * passed to the handler. + * + * @return Returns the connection selected (in the case the foreach + * function returns nopoll_false) or NULL in the case all foreach + * executions returned nopoll_true. Keep in mind the function also + * returns NULL if ctx or foreach parameter is NULL. + * + * See \ref noPollForeachConn for a signature example. + */ +noPollConn * nopoll_ctx_foreach_conn (noPollCtx * ctx, + noPollForeachConn foreach, + noPollPtr user_data) +{ + noPollConn * result; + int iterator; + nopoll_return_val_if_fail (ctx, ctx && foreach, NULL); + + /* acquire here the mutex to protect connection list */ + nopoll_mutex_lock (ctx->ref_mutex); + + /* nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Doing foreach over conn_length array (%p): %d", ctx, ctx->conn_length); */ + + /* find the connection and remove it from the array */ + iterator = 0; + while (iterator < ctx->conn_length) { + + /* check the connection reference */ + if (ctx->conn_list[iterator]) { + /* call to notify connection */ + if (foreach (ctx, ctx->conn_list[iterator], user_data)) { + /* get a reference to avoid races + * after releasing the mutex */ + result = ctx->conn_list[iterator]; + + /* release */ + nopoll_mutex_unlock (ctx->ref_mutex); + + /* release here the mutex to protect connection list */ + return result; + } /* end if */ + } /* end if */ + + iterator++; + } /* end while */ + + /* release here the mutex to protect connection list */ + nopoll_mutex_unlock (ctx->ref_mutex); + + return NULL; +} + + +/** + * @brief Allows to change the protocol version that is send in all + * client connections created under the provided context and the + * protocol version accepted by listener created under this context + * too. + * + * This is a really basic (mostly fake) protocol version support + * because it only allows to change the version string sent (but + * nothing more for now). It is useful for testing purposes. + * + * @param ctx The noPoll context where the protocol version change + * will be applied. + * + * @param version The value representing the protocol version. By + * default this function isn't required to be called because it + * already has the right protocol value configured (13). + */ +void nopoll_ctx_set_protocol_version (noPollCtx * ctx, int version) +{ + /* check input data */ + nopoll_return_if_fail (ctx, ctx || version); + + /* setup the new protocol version */ + ctx->protocol_version = version; + + return; +} + +/* @} */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_decl.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_decl.c new file mode 100644 index 0000000..527ae26 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_decl.c @@ -0,0 +1,94 @@ +/* + * LibNoPoll: A websocket library + * Copyright (C) 2013 Advanced Software Production Line, S.L. + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * You may find a copy of the license under this software is released + * at COPYING file. This is LGPL software: you are welcome to develop + * proprietary applications using this library without any royalty or + * fee but returning back any change, improvement or addition in the + * form of source code, project image, documentation patches, etc. + * + * For commercial support on build Websocket enabled solutions + * contact us: + * + * Postal address: + * Advanced Software Production Line, S.L. + * Edificio Alius A, Oficina 102, + * C/ Antonio Suarez Nº 10, + * Alcalá de Henares 28802 Madrid + * Spain + * + * Email address: + * info@aspl.es - http://www.aspl.es/nopoll + */ +#include + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +/** + * \addtogroup nopoll_decl_module + * @{ + */ + +/** + * @brief Calloc helper for nopoll library. + * + * @param count How many items to allocate. + * @param size Size of one item. + * + * @return A newly allocated pointer. + * @see nopoll_free + */ +noPollPtr nopoll_calloc(size_t count, size_t size) +{ + return (void *)os_calloc (count, size); +} + +/** + * @brief Realloc helper for nopoll library. + * + * @param ref the reference to reallocate. + * @param size Size of the new reference. + * + * @return A newly allocated pointer. + * @see nopoll_free + */ +noPollPtr nopoll_realloc(noPollPtr ref, size_t size) +{ + return (void *)os_realloc (ref, size); +} + +/** + * @brief Allows to deallocate memory referenced by ref but + * checking before that the reference is different from null. + * + * @param ref The reference to clear. + */ +void nopoll_free (noPollPtr ref) +{ + os_free (ref); + return; +} + + +/** + * @} + */ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_io.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_io.c new file mode 100644 index 0000000..133e99e --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_io.c @@ -0,0 +1,233 @@ +/* + * LibNoPoll: A websocket library + * Copyright (C) 2013 Advanced Software Production Line, S.L. + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * You may find a copy of the license under this software is released + * at COPYING file. This is LGPL software: you are welcome to develop + * proprietary applications using this library without any royalty or + * fee but returning back any change, improvement or addition in the + * form of source code, project image, documentation patches, etc. + * + * For commercial support on build Websocket enabled solutions + * contact us: + * + * Postal address: + * Advanced Software Production Line, S.L. + * Edificio Alius A, Oficina 102, + * C/ Antonio Suarez Nº 10, + * Alcalá de Henares 28802 Madrid + * Spain + * + * Email address: + * info@aspl.es - http://www.aspl.es/nopoll + */ +#include +#include + +typedef struct _noPollSelect { + noPollCtx * ctx; + fd_set set; + int length; + int max_fds; +} noPollSelect; + +/** + * @internal nopoll implementation to create a compatible "select" IO + * call fd set reference. + * + * @return A newly allocated fd_set reference. + */ +noPollPtr nopoll_io_wait_select_create (noPollCtx * ctx) +{ + noPollSelect * select = nopoll_new (noPollSelect, 1); + + /* set default behaviour expected for the set */ + select->ctx = ctx; + + /* clear the set */ + FD_ZERO (&(select->set)); + + return select; +} + +/** + * @internal noPoll implementation to destroy the "select" IO call + * created by the default create. + * + * @param fd_group The fd group to be deallocated. + */ +void nopoll_io_wait_select_destroy (noPollCtx * ctx, noPollPtr fd_group) +{ + fd_set * __fd_set = (fd_set *) fd_group; + + /* release memory allocated */ + nopoll_free (__fd_set); + + /* nothing more to do */ + return; +} + +/** + * @internal noPoll implementation to clear the "select" IO call + * created by the default create. + * + * @param fd_group The fd group to be deallocated. + */ +void nopoll_io_wait_select_clear (noPollCtx * ctx, noPollPtr __fd_group) +{ + noPollSelect * select = (noPollSelect *) __fd_group; + + /* clear the fd set */ + select->length = 0; + FD_ZERO (&(select->set)); + + /* nothing more to do */ + return; +} + +/** + * @internal Default internal implementation for the wait operation to + * change its status at least one socket description inside the fd set + * provided. + * + * @param __fd_group The fd set having all sockets to be watched. + * @param wait_to The operation requested. + * + * @return Number of connections that changed or -1 if something wailed + */ +int nopoll_io_wait_select_wait (noPollCtx * ctx, noPollPtr __fd_group) +{ + int result = -1; + struct timeval tv; + noPollSelect * _select = (noPollSelect *) __fd_group; + + /* init wait */ + tv.tv_sec = 0; + tv.tv_usec = 500000; + result = select (_select->max_fds + 1, &(_select->set), NULL, NULL, &tv); + + /* check result */ + if ((result == NOPOLL_SOCKET_ERROR) && (errno == NOPOLL_EINTR)) + return -1; + + return result; +} + +/** + * @internal noPoll select implementation for the "add to" on fd set + * operation. + * + * @param fds The socket descriptor to be added. + * + * @param fd_set The fd set where the socket descriptor will be added. + */ +nopoll_bool nopoll_io_wait_select_add_to (int fds, + noPollCtx * ctx, + noPollConn * conn, + noPollPtr __fd_set) +{ + noPollSelect * select = (noPollSelect *) __fd_set; + + if (fds < 0) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, + "received a non valid socket (%d), unable to add to the set", fds); + return nopoll_false; + } + + /* set the value */ + FD_SET (fds, &(select->set)); + + /* update length */ + select->length++; + + /* update max fds */ + if (fds > select->max_fds) + select->max_fds = fds; + + return nopoll_true; +} + +/** + * @internal + * + * @brief Default noPoll implementation for the "is set" on fd + * set operation. + * + * @param fds The socket descriptor to be checked to be active on the + * given fd group. + * + * @param fd_set The fd set where the socket descriptor will be checked. + */ +nopoll_bool nopoll_io_wait_select_is_set (noPollCtx * ctx, + int fds, + noPollPtr __fd_set) +{ + noPollSelect * select = (noPollSelect *) __fd_set; + + return FD_ISSET (fds, &(select->set)); +} + + +/** + * @brief Creates an object that represents the best IO wait mechanism + * found on the current system. + * + * @param ctx The context where the engine will be created/associated. + * + * @param engine Use \ref NOPOLL_IO_ENGINE_DEFAULT or the engine you + * want to use. + * + * @return The selected IO wait mechanism or NULL if it fails. + */ +noPollIoEngine * nopoll_io_get_engine (noPollCtx * ctx, noPollIoEngineType engine_type) +{ + noPollIoEngine * engine = nopoll_new (noPollIoEngine, 1); + if (engine == NULL) + return NULL; + + /* configure default implementation */ + engine->create = nopoll_io_wait_select_create; + engine->destroy = nopoll_io_wait_select_destroy; + engine->clear = nopoll_io_wait_select_clear; + engine->wait = nopoll_io_wait_select_wait; + engine->addto = nopoll_io_wait_select_add_to; + engine->isset = nopoll_io_wait_select_is_set; + + /* call to create the object */ + engine->ctx = ctx; + engine->io_object = engine->create (ctx); + + /* return the engine that was created */ + return engine; +} + +/** + * @brief Release the io engine created by \ref nopoll_io_get_engine. + * + * @param engine The engine to be released. + */ +void nopoll_io_release_engine (noPollIoEngine * engine) +{ + if (engine == NULL) + return; + engine->destroy (engine->ctx, engine->io_object); + nopoll_free (engine); + return; +} + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_listener.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_listener.c new file mode 100644 index 0000000..0876c74 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_listener.c @@ -0,0 +1,441 @@ +/* + * LibNoPoll: A websocket library + * Copyright (C) 2013 Advanced Software Production Line, S.L. + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * You may find a copy of the license under this software is released + * at COPYING file. This is LGPL software: you are welcome to develop + * proprietary applications using this library without any royalty or + * fee but returning back any change, improvement or addition in the + * form of source code, project image, documentation patches, etc. + * + * For commercial support on build Websocket enabled solutions + * contact us: + * + * Postal address: + * Advanced Software Production Line, S.L. + * Edificio Alius A, Oficina 102, + * C/ Antonio Suarez Nº 10, + * Alcalá de Henares 28802 Madrid + * Spain + * + * Email address: + * info@aspl.es - http://www.aspl.es/nopoll + */ +#include +#include + +/** + * \defgroup nopoll_listener noPoll Listener: functions required to create WebSocket listener connections. + */ + +/** + * \addtogroup nopoll_listener + * @{ + */ + +/** + * @internal Creates a listener socket on the provided port. + */ +NOPOLL_SOCKET nopoll_listener_sock_listen (noPollCtx * ctx, + const char * host, + const char * port) +{ + struct hostent * he; + struct in_addr * haddr; + struct sockaddr_in saddr; + struct sockaddr_in sin; + NOPOLL_SOCKET fd; + int tries; + +#if defined(NOPOLL_OS_WIN32) + int sin_size = sizeof (sin); +#else + int unit = 1; + socklen_t sin_size = sizeof (sin); +#endif + uint16_t int_port; + int bind_res; + + nopoll_return_val_if_fail (ctx, ctx, -2); + nopoll_return_val_if_fail (ctx, host, -2); + nopoll_return_val_if_fail (ctx, port || strlen (port) == 0, -2); + + /* resolve hostname */ + he = gethostbyname (host); + if (he == NULL) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "unable to get hostname by calling gethostbyname"); + return -1; + } /* end if */ + + haddr = ((struct in_addr *) (he->h_addr_list)[0]); + if ((fd = socket(AF_INET, SOCK_STREAM, 0)) <= 2) { + /* do not allow creating sockets reusing stdin (0), + stdout (1), stderr (2) */ + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "failed to create listener socket: %d (errno=%d)", fd, errno); + return -1; + } /* end if */ + +#if defined(NOPOLL_OS_WIN32) + /* Do not issue a reuse addr which causes on windows to reuse + * the same address:port for the same process. Under linux, + * reusing the address means that consecutive process can + * reuse the address without being blocked by a wait + * state. */ + /* setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&unit, sizeof(BOOL)); */ +#else + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &unit, sizeof (unit)); +#endif + + /* get integer port */ + int_port = (uint16_t) atoi (port); + + memset(&saddr, 0, sizeof(struct sockaddr_in)); + saddr.sin_family = AF_INET; + saddr.sin_port = htons(int_port); + memcpy(&saddr.sin_addr, haddr, sizeof(struct in_addr)); + + /* call to bind */ + tries = 0; + while (1) { + bind_res = bind(fd, (struct sockaddr *)&saddr, sizeof (struct sockaddr_in)); + if (bind_res == NOPOLL_SOCKET_ERROR) { + /* check if we can retry */ + tries++; + if (tries < 25) { + nopoll_log (ctx, NOPOLL_LEVEL_WARNING, + "unable to bind address (port:%u already in use or insufficient permissions, errno=%d : %s), retrying=%d on socket: %d", + int_port, errno, strerror (errno), tries, fd); + nopoll_sleep (100000); + continue; + } /* end if */ + + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, + "unable to bind address (port:%u already in use or insufficient permissions, errno=%d : %s). Closing socket: %d", + int_port, errno, strerror (errno), fd); + nopoll_close_socket (fd); + return -1; + } /* end if */ + + /* reached this point, bind was ok */ + break; + } /* end while */ + + if (listen(fd, ctx->backlog) == NOPOLL_SOCKET_ERROR) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "an error have occur while executing listen"); + return -1; + } /* end if */ + + /* notify listener */ + if (getsockname (fd, (struct sockaddr *) &sin, &sin_size) < -1) { + return -1; + } /* end if */ + + /* report and return fd */ + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "running listener at %s:%d (socket: %d)", inet_ntoa(sin.sin_addr), ntohs (sin.sin_port), fd); + return fd; +} + +/** + * @brief Creates a new websocket server listener on the provided host + * name and port. + * + * @param ctx The context where the operation will take place. + * + * @param host The hostname or address interface to bind on. + * + * @param port The port where to listen, or NULL to use default port: 80. + * + * @return A reference to a \ref noPollConn object representing the + * listener or NULL if it fails. + */ +noPollConn * nopoll_listener_new (noPollCtx * ctx, + const char * host, + const char * port) +{ + return nopoll_listener_new_opts (ctx, NULL, host, port); +} + +/** + * @brief Creates a new websocket server listener on the provided host + * name and port. + * + * @param ctx The context where the operation will take place. + * + * @param opts Optional connection options to configure this listener. + * + * @param host The hostname or address interface to bind on. + * + * @param port The port where to listen, or NULL to use default port: 80. + * + * @return A reference to a \ref noPollConn object representing the + * listener or NULL if it fails. + */ +noPollConn * nopoll_listener_new_opts (noPollCtx * ctx, + noPollConnOpts * opts, + const char * host, + const char * port) +{ + NOPOLL_SOCKET session; + noPollConn * listener; + + nopoll_return_val_if_fail (ctx, ctx && host, NULL); + + /* call to create the socket */ + session = nopoll_listener_sock_listen (ctx, host, port); + if (session == NOPOLL_INVALID_SOCKET) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to start listener error was: %d", errno); + return NULL; + } /* end if */ + + /* create noPollConn ection object */ + listener = nopoll_new (noPollConn, 1); + listener->refs = 1; + listener->session = session; + listener->ctx = ctx; + listener->role = NOPOLL_ROLE_MAIN_LISTENER; + + /* record host and port */ + listener->host = nopoll_strdup (host); + listener->port = nopoll_strdup (port); + + /* register connection into context */ + nopoll_ctx_register_conn (ctx, listener); + + /* configure default handlers */ + listener->receive = nopoll_conn_default_receive; + listener->sends = nopoll_conn_default_send; + + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Listener created, started: %s:%s (socket: %d)", listener->host, listener->port, listener->session); + + return listener; +} + +/** + * @brief Allows to create a new WebSocket listener but expecting the + * incoming connection to be under TLS supervision. The function works + * like \ref nopoll_listener_new (providing wss:// services). + * + * @param ctx The context where the operation will take place. + * + * @param host The hostname or address interface to bind on. + * + * @param port The port where to listen, or NULL to use default port: 80. + * + * @return A reference to a \ref noPollConn object representing the + * listener or NULL if it fails. + */ +noPollConn * nopoll_listener_tls_new (noPollCtx * ctx, + const char * host, + const char * port) +{ + return nopoll_listener_tls_new_opts (ctx, NULL, host, port); +} + + +/** + * @brief Allows to create a new WebSocket listener but expecting the + * incoming connection to be under TLS supervision. The function works + * like \ref nopoll_listener_new (providing wss:// services). + * + * @param ctx The context where the operation will take place. + * + * @param opts The connection options to configure this particular + * listener. + * + * @param host The hostname or address interface to bind on. + * + * @param port The port where to listen, or NULL to use default port: 80. + * + * @return A reference to a \ref noPollConn object representing the + * listener or NULL if it fails. + */ +noPollConn * nopoll_listener_tls_new_opts (noPollCtx * ctx, + noPollConnOpts * opts, + const char * host, + const char * port) +{ + noPollConn * listener; + + /* call to get listener from base function */ + listener = nopoll_listener_new (ctx, host, port); + if (! listener) + return listener; + + /* setup TLS support */ + listener->tls_on = nopoll_true; + listener->opts = opts; + + return listener; +} + +/** + * @brief Allows to configure the TLS certificate and key to be used + * on the provided connection. + * + * @param listener The listener that is going to be configured with the providing certificate and key. + * + * @param certificate The path to the public certificate file (PEM + * format) to be used for every TLS connection received under the + * provided listener. + * + * @param private_key The path to the key file (PEM format) to be used for + * every TLS connection received under the provided listener. + * + * @param chain_file The path to additional chain certificates (PEM + * format). You can safely pass here a NULL value. + * + * @return nopoll_true if the certificates were configured, otherwise + * nopoll_false is returned. + */ +nopoll_bool nopoll_listener_set_certificate (noPollConn * listener, + const char * certificate, + const char * private_key, + const char * chain_file) +{ +// FILE * handle; +// +// if (! listener || ! certificate || ! private_key) +// return nopoll_false; +// +// /* check certificate file */ +// handle = fopen (certificate, "r"); +// if (! handle) { +// nopoll_log (listener->ctx, NOPOLL_LEVEL_CRITICAL, "Failed to open certificate file from %s", certificate); +// return nopoll_false; +// } /* end if */ +// fclose (handle); +// +// /* check private file */ +// handle = fopen (private_key, "r"); +// if (! handle) { +// nopoll_log (listener->ctx, NOPOLL_LEVEL_CRITICAL, "Failed to open private key file from %s", private_key); +// return nopoll_false; +// } /* end if */ +// fclose (handle); +// +// if (chain_file) { +// /* check private file */ +// handle = fopen (chain_file, "r"); +// if (! handle) { +// nopoll_log (listener->ctx, NOPOLL_LEVEL_CRITICAL, "Failed to open chain certificate file from %s", private_key); +// return nopoll_false; +// } /* end if */ +// fclose (handle); +// } /* end if */ +// +// /* copy certificates to be used */ +// listener->certificate = nopoll_strdup (certificate); +// listener->private_key = nopoll_strdup (private_key); +// if (chain_file) +// listener->chain_certificate = nopoll_strdup (chain_file); +// +// nopoll_log (listener->ctx, NOPOLL_LEVEL_DEBUG, "Configured certificate: %s, key: %s, for conn id: %d", +// listener->certificate, listener->private_key, listener->id); + + /* certificates configured */ + return nopoll_true; +} + +/** + * @brief Creates a websocket listener from the socket provided. + * + * @param ctx The context where the listener will be associated. + * + * @param session The session to associate to the listener. + * + * @return A reference to a listener connection object or NULL if it + * fails. + */ +noPollConn * nopoll_listener_from_socket (noPollCtx * ctx, + NOPOLL_SOCKET session) +{ + noPollConn * listener; + struct sockaddr_in sin; +#if defined(NOPOLL_OS_WIN32) + /* windows flavors */ + int sin_size = sizeof (sin); +#else + /* unix flavors */ + socklen_t sin_size = sizeof (sin); +#endif + + nopoll_return_val_if_fail (ctx, ctx && session > 0, NULL); + + /* create noPollConn ection object */ + listener = nopoll_new (noPollConn, 1); + listener->refs = 1; + listener->session = session; + listener->ctx = ctx; + listener->role = NOPOLL_ROLE_LISTENER; + + /* get peer value */ + memset (&sin, 0, sizeof (struct sockaddr_in)); + if (getpeername (session, (struct sockaddr *) &sin, &sin_size) < -1) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "unable to get remote hostname and port"); + return NULL; + } /* end if */ + + /* record host and port */ + /* lock mutex here to protect inet_ntoa */ + listener->host = nopoll_strdup (inet_ntoa (sin.sin_addr)); + /* release mutex here to protect inet_ntoa */ + listener->port = nopoll_strdup_printf ("%d", ntohs (sin.sin_port)); + + /* configure default handlers */ + listener->receive = nopoll_conn_default_receive; + listener->sends = nopoll_conn_default_send; + + /* register connection into context */ + if (! nopoll_ctx_register_conn (ctx, listener)) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to register connection into the context, unable to create connection"); + nopoll_conn_ref (listener); + return NULL; + } /* end if */ + + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Listener created, started: %s:%s (socket: %d)", listener->host, listener->port, listener->session); + + /* reduce reference counting here because ctx_register_conn + * already acquired a reference */ + nopoll_conn_unref (listener); + + return listener; +} + +/** + * @internal Public function that performs a TCP listener accept. + * + * @param server_socket The listener socket where the accept() + * operation will be called. + * + * @return Returns a connected socket descriptor or -1 if it fails. + */ +NOPOLL_SOCKET nopoll_listener_accept (NOPOLL_SOCKET server_socket) +{ + struct sockaddr_in inet_addr; +#if defined(NOPOLL_OS_WIN32) + int addrlen; +#else + socklen_t addrlen; +#endif + addrlen = sizeof(struct sockaddr_in); + + /* accept the connection new connection */ + return accept (server_socket, (struct sockaddr *)&inet_addr, &addrlen); +} + +/* @} */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_log.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_log.c new file mode 100644 index 0000000..8ce36f8 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_log.c @@ -0,0 +1,245 @@ +/* + * LibNoPoll: A websocket library + * Copyright (C) 2013 Advanced Software Production Line, S.L. + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * You may find a copy of the license under this software is released + * at COPYING file. This is LGPL software: you are welcome to develop + * proprietary applications using this library without any royalty or + * fee but returning back any change, improvement or addition in the + * form of source code, project image, documentation patches, etc. + * + * For commercial support on build Websocket enabled solutions + * contact us: + * + * Postal address: + * Advanced Software Production Line, S.L. + * Edificio Alius A, Oficina 102, + * C/ Antonio Suarez Nº 10, + * Alcalá de Henares 28802 Madrid + * Spain + * + * Email address: + * info@aspl.es - http://www.aspl.es/nopoll + */ +#include +#include + +/** + * \defgroup nopoll_log noPoll Log: Console log reporting for noPoll library + */ + +/** + * \addtogroup nopoll_log + * @{ + */ + +/** + * @brief Allows to check if the log reporting inside the system is + * enabled. + * + * @return nopoll_true if the log is enabled or nopoll_false + */ +nopoll_bool nopoll_log_is_enabled (noPollCtx * ctx) +{ + if (ctx == NULL) + return nopoll_false; + + /* return current value */ + return ctx->debug_enabled; +} + +/** + * + * @brief Allows to get current log configuration, to use colors. + * + * @return nopoll_true if the color log is enabled or nopoll_false + */ +nopoll_bool nopoll_log_color_is_enabled (noPollCtx * ctx) +{ + + if (ctx == NULL) + return nopoll_false; + + /* return current value */ + return ctx->debug_color_enabled; +} + +/** + * @brief Allows to control how to activate the log reporting to the + * console from the nopoll core library. + * + * @param ctx The context where the operation will take place. + * + * @param value nopoll_true to enable log to console, otherwise nopoll_false is + * returned. + */ +void nopoll_log_enable (noPollCtx * ctx, nopoll_bool value) +{ + if (ctx == NULL) + return; + + /* activate debuging according to the variable */ + ctx->debug_enabled = value; + return; +} + +/** + * @brief Allows to control how to activate the colog log reporting to + * the console from the nopoll core library. + * + * @param ctx The context where the operation will take place. + * + * @param value nopoll_true to enable log to console, otherwise nopoll_false is + * returned. + */ +void nopoll_log_color_enable (noPollCtx * ctx, nopoll_bool value) +{ + if (ctx == NULL) + return; + + /* activate color debuging according to the variable */ + ctx->debug_color_enabled = value; + return; +} + +/** + * @brief Allows to define a log handler that will receive all logs + * produced under the provided content. + * + * @param ctx The context that is going to be configured. + * + * @param handler The handler to be called for each log to be + * notified. Passing in NULL is allowed to remove any previously + * configured handler. + * + * @param user_data User defined pointer to be passed in into the + * handler configured along with the log notified. + */ +void nopoll_log_set_handler (noPollCtx * ctx, noPollLogHandler handler, noPollPtr user_data) +{ + nopoll_return_if_fail (ctx, ctx); + + ctx->log_handler = handler; + ctx->log_user_data = user_data; + + return; +} + +/** + * @internal Allows to drop a log to the console. + * + * This function allow to drop a log to the console using the given + * domain, as an identification of which subsystem have reported the + * information, and report level. This report level is used to notify + * the consideration of the log reported. + * + * The function allows to provide a printf like interface to report + * messages. Here are some examples: + * + * \code + * // drop a log about current library initialization + * nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "library properly initialized status=%d", status); + * \endcode + * + * + * @param ctx The context where the operation will take place. + * + * @param level The level that this message is classificed. + * + * @param message The message to report. The message to report must be + * not NULL. + */ +void __nopoll_log (noPollCtx * ctx, const char * function_name, const char * file, int line, noPollDebugLevel level, const char * message, ...) +{ + +#ifdef SHOW_DEBUG_LOG + va_list args; + char * log_msg; + char * log_msg2; + + if (ctx && ctx->log_handler) { + /* print the message */ + va_start (args, message); + log_msg = nopoll_strdup_printfv (message, args); + va_end (args); + + log_msg2 = log_msg; + log_msg = nopoll_strdup_printf ("%s:%d %s ", file, line, log_msg); + nopoll_free (log_msg2); + + ctx->log_handler (ctx, level, log_msg, ctx->log_user_data); + nopoll_free (log_msg); + return; + } + + /* check if the log is enabled */ + if (! nopoll_log_is_enabled (ctx)) + return; + +// /* printout the process pid */ +// if (nopoll_log_color_is_enabled (ctx)) +// printf ("\e[1;36m(proc %d)\e[0m: ", getpid ()); +// else +// printf ("(proc %d): ", getpid ()); + + /* drop a log according to the level */ + if (nopoll_log_color_is_enabled (ctx)) { + switch (level) { + case NOPOLL_LEVEL_DEBUG: + printf ("(\e[1;32mdebug\e[0m) "); + break; + case NOPOLL_LEVEL_WARNING: + printf ("(\e[1;33mwarning\e[0m) "); + break; + case NOPOLL_LEVEL_CRITICAL: + printf ("(\e[1;31mcritical\e[0m) "); + break; + } + } else { + switch (level) { + case NOPOLL_LEVEL_DEBUG: + printf ("(debug)"); + break; + case NOPOLL_LEVEL_WARNING: + printf ("(warning)"); + break; + case NOPOLL_LEVEL_CRITICAL: + printf ("(critical) "); + break; + } + } + + /* drop a log according to the domain */ + printf ("%s:%d ", file, line); + + /* print the message */ + va_start (args, message); +// vprintf (message, args); + va_end (args); + + printf ("\n"); + + /* ensure that the log is droped to the console */ +// fflush (stdout); +#endif + + /* return */ + return; +} + +/* @} */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_loop.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_loop.c new file mode 100644 index 0000000..fb142ff --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_loop.c @@ -0,0 +1,269 @@ +/* + * LibNoPoll: A websocket library + * Copyright (C) 2013 Advanced Software Production Line, S.L. + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * You may find a copy of the license under this software is released + * at COPYING file. This is LGPL software: you are welcome to develop + * proprietary applications using this library without any royalty or + * fee but returning back any change, improvement or addition in the + * form of source code, project image, documentation patches, etc. + * + * For commercial support on build Websocket enabled solutions + * contact us: + * + * Postal address: + * Advanced Software Production Line, S.L. + * Edificio Alius A, Oficina 102, + * C/ Antonio Suarez Nº 10, + * Alcalá de Henares 28802 Madrid + * Spain + * + * Email address: + * info@aspl.es - http://www.aspl.es/nopoll + */ +#include +#include + +/** + * \defgroup nopoll_loop noPoll Loop: basic support to create a watching loop for WebSocket listeners + */ + +/** + * \addtogroup nopoll_loop + * @{ + */ + +/** + * @internal Function used by nopoll_loop_wait to register all + * connections into the io waiting object. + */ +nopoll_bool nopoll_loop_register (noPollCtx * ctx, noPollConn * conn, noPollPtr user_data) +{ + /* do not add connections that aren't working */ + if (! nopoll_conn_is_ok (conn)) { + /* remove this connection from registry */ + nopoll_ctx_unregister_conn (ctx, conn); + return nopoll_false; /* keep foreach, don't stop */ + } + + /* register the connection socket */ + /* nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Adding socket id: %d", conn->session);*/ + if (! ctx->io_engine->addto (conn->session, ctx, conn, ctx->io_engine->io_object)) { + /* remove this connection from registry */ + nopoll_ctx_unregister_conn (ctx, conn); + nopoll_log (ctx, NOPOLL_LEVEL_WARNING, "Failed to add socket %d to the watching set", conn->session); + } + + return nopoll_false; /* keep foreach, don't stop */ +} + +/** + * @internal Function used to handle incoming data from from the + * connection and to notify this data on the connection. + */ +void nopoll_loop_process_data (noPollCtx * ctx, noPollConn * conn) +{ + noPollMsg * msg; + + /* call to get messages from the connection */ + msg = nopoll_conn_get_msg (conn); + if (msg == NULL) + return; + + /* found message, notify it */ + if (conn->on_msg) + conn->on_msg (ctx, conn, msg, conn->on_msg_data); + else if (ctx->on_msg) + ctx->on_msg (ctx, conn, msg, ctx->on_msg_data); + + /* release message */ + nopoll_msg_unref (msg); + return; +} + +/** + * @internal Function used to detected which connections has something + * interesting to be notified. + * + */ +nopoll_bool nopoll_loop_process (noPollCtx * ctx, noPollConn * conn, noPollPtr user_data) +{ + int * conn_changed = (int *) user_data; + + /* check if the connection have something to notify */ + if (ctx->io_engine->isset (ctx, conn->session, ctx->io_engine->io_object)) { + + /* call to notify action according to role */ + switch (conn->role) { + case NOPOLL_ROLE_CLIENT: + case NOPOLL_ROLE_LISTENER: + /* received data, notify */ + nopoll_loop_process_data (ctx, conn); + break; + case NOPOLL_ROLE_MAIN_LISTENER: + /* call to handle */ + nopoll_conn_accept (ctx, conn); + break; + default: + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Found connection with unknown role, closing and dropping"); + nopoll_conn_shutdown (conn); + break; + } + + /* reduce connection changed */ + (*conn_changed)--; + } /* end if */ + + return (*conn_changed) == 0; +} + +/** + * @internal Function used to init internal io wait mechanism... + * + * @param ctx The noPoll context to be initialized if it wasn't + */ +void nopoll_loop_init (noPollCtx * ctx) +{ + if (ctx == NULL) + return; + + /* grab the mutex for the following check */ + if (ctx->io_engine == NULL) { + ctx->io_engine = nopoll_io_get_engine (ctx, NOPOLL_IO_ENGINE_DEFAULT); + if (ctx->io_engine == NULL) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to create IO wait engine, unable to implement wait call"); + return; + } + } /* end if */ + /* release the mutex */ + + return; +} + +/** + * @brief Flag to stop the current loop implemented (if any) on the provided context. + * + * @param ctx The context where the loop is being done, and wanted to + * be stopped. + * + */ +void nopoll_loop_stop (noPollCtx * ctx) +{ + if (! ctx) + return; + ctx->keep_looping = nopoll_false; + return; +} /* end if */ + +/** + * @brief Allows to implement a wait over all connections registered + * under the provided context during the provided timeout until + * something is detected meaningful to the user, calling to the action + * handler defined, optionally receving the user data pointer. + * + * @param ctx The context object where the wait will be implemented. + * + * @param timeout The timeout to wait for changes. If no changes + * happens, the function returns. The function will block the caller + * until a call to \ref nopoll_loop_stop is done in the case timeout + * passed is 0. + * + * @return The function returns 0 when finished or -2 in the case ctx + * is NULL or timeout is negative. + */ +int nopoll_loop_wait (noPollCtx * ctx, long timeout) +{ + struct timeval start; + struct timeval stop; + struct timeval diff; + long ellapsed; + int wait_status; + + nopoll_return_val_if_fail (ctx, ctx, -2); + nopoll_return_val_if_fail (ctx, timeout >= 0, -2); + + /* call to init io engine */ + nopoll_loop_init (ctx); + + /* get as reference current time */ + if (timeout > 0) +#if defined(NOPOLL_OS_WIN32) + nopoll_win32_gettimeofday (&start, NULL); +#else + gettimeofday (&start, NULL); +#endif + + /* set to keep looping everything this function is called */ + ctx->keep_looping = nopoll_true; + + while (ctx->keep_looping) { + /* ok, now implement wait operation */ + ctx->io_engine->clear (ctx, ctx->io_engine->io_object); + + /* add all connections */ + /* nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Adding connections to watch: %d", ctx->conn_num); */ + nopoll_ctx_foreach_conn (ctx, nopoll_loop_register, NULL); + + /* if (errno == EBADF) { */ + /* detected some descriptor not properly + * working, try to check them */ + /* nopoll_ctx_foreach_conn (ctx, nopoll_loop_clean_descriptors, NULL); */ + /* nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Found some descriptor is not valid (errno==%d)", errno); + continue; */ + /* } */ /* end if */ + + /* implement wait operation */ + /* nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Waiting for changes into %d connections", ctx->conn_num); */ + wait_status = ctx->io_engine->wait (ctx, ctx->io_engine->io_object); + /* nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Waiting finished with result %d", wait_status); */ + if (wait_status == -1) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Received error from wait operation, error code was: %d", errno); + break; + } /* end if */ + + /* check how many connections changed and restart */ + if (wait_status > 0) { + /* check and call for connections with something + * interesting */ + nopoll_ctx_foreach_conn (ctx, nopoll_loop_process, &wait_status); + } + + /* check to stop wait operation */ + if (timeout > 0) { +#if defined(NOPOLL_OS_WIN32) + nopoll_win32_gettimeofday (&stop, NULL); +#else + gettimeofday (&stop, NULL); +#endif + nopoll_timeval_substract (&stop, &start, &diff); + ellapsed = (diff.tv_sec * 1000000) + diff.tv_usec; + if (ellapsed > timeout) + break; + } /* end if */ + } /* end while */ + + /* release engine */ + nopoll_io_release_engine (ctx->io_engine); + ctx->io_engine = NULL; + + return 0; +} + +/* @} */ + + diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_msg.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_msg.c new file mode 100644 index 0000000..a7951ce --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_msg.c @@ -0,0 +1,320 @@ +/* + * LibNoPoll: A websocket library + * Copyright (C) 2013 Advanced Software Production Line, S.L. + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * You may find a copy of the license under this software is released + * at COPYING file. This is LGPL software: you are welcome to develop + * proprietary applications using this library without any royalty or + * fee but returning back any change, improvement or addition in the + * form of source code, project image, documentation patches, etc. + * + * For commercial support on build Websocket enabled solutions + * contact us: + * + * Postal address: + * Advanced Software Production Line, S.L. + * Edificio Alius A, Oficina 102, + * C/ Antonio Suarez Nº 10, + * Alcalá de Henares 28802 Madrid + * Spain + * + * Email address: + * info@aspl.es - http://www.aspl.es/nopoll + */ +#include +#include + +/** + * \defgroup nopoll_msg noPoll Message: functions for handling and using noPoll messages (websocket messages) + */ + +/** + * \addtogroup nopoll_msg + * @{ + */ + +/** + * @internal function that creates an empty message holder. + * @return A newly created reference or NULL if it fails. + */ +noPollMsg * nopoll_msg_new (void) +{ + noPollMsg * msg = nopoll_new (noPollMsg, 1); + if (msg == NULL) + return NULL; + + msg->refs = 1; + msg->ref_mutex = nopoll_mutex_create (); + + return msg; +} + +/** + * @brief Allows to get a reference to the payload content inside the + * provided websocket message. + * + * @param msg The websocket message to get the payload from. + * + * @return A reference to the payload or NULL if it fails. See \ref + * nopoll_msg_get_payload_size to get payload size. + */ +const unsigned char * nopoll_msg_get_payload (noPollMsg * msg) +{ + if (msg == NULL) + return NULL; + return msg->payload; +} + +/** + * @brief Allows to get the payload byte length stored on the provided + * message. + * + * @param msg The websocket message to get the payload from. + * + * @return The payload size or -1 if it fails (only when msg is NULL). + */ +int nopoll_msg_get_payload_size (noPollMsg * msg) +{ + if (msg == NULL) + return -1; + return msg->payload_size; +} + +/** + * @brief Allows to acquire a reference to the provided websocket + * message. + * + * @param msg The websocket message to acquire a reference. + * + * @return nopoll_true if the reference was acquired, otherwise + * nopoll_false is returned. + */ +nopoll_bool nopoll_msg_ref (noPollMsg * msg) +{ + /* check recieved reference */ + if (msg == NULL) + return nopoll_false; + + /* acquire mutex here */ + nopoll_mutex_lock (msg->ref_mutex); + + msg->refs++; + + /* release mutex here */ + nopoll_mutex_unlock (msg->ref_mutex); + + return nopoll_true; +} + +/** + * @brief Allows to get current reference counting for the provided + * message. + * + * @param msg The message for which we are requesting for the + * reference counting. + * + * @return Reference counting or -1 if it fails (returned when msg + * reference received is NULL). + */ +int nopoll_msg_ref_count (noPollMsg * msg) +{ + int result; + + /* check recieved reference */ + if (msg == NULL) + return -1; + + /* acquire mutex here */ + nopoll_mutex_lock (msg->ref_mutex); + + result = msg->refs; + + /* release mutex here */ + nopoll_mutex_unlock (msg->ref_mutex); + + return result; +} + +/** + * @brief Allows to get if the provided message reference has FIN flag + * on (or off) to indicate if it is a final frame. + * + * When a series of messages are received and they conform together a + * single message, the last message is flagged with FIN = 1 while the + * rest before go with FIN = 0. + * + * For example, if a user level application is splitted into 4 frame + * fragments, then the WebSocket peer will receive 3 fragments with + * FIN = 0 and the last fragment with FIN = 1. + * + * You can use \ref nopoll_msg_is_fragment to know if a particular + * message was produced due to a fragmentation found at the network + * level. This happens when the entire frame wasn't sent or it + * couldn't be read entirely. In the example before, the four frames + * will be also flagged as fragments too. + * + * @param msg The message that is being checked for FIN flag. + * + * @return nopoll_true if the message is a final one, otherwise + * nopoll_false is returned. The function returns nopoll_false when + * message reference received is NULL. + * + */ +nopoll_bool nopoll_msg_is_final (noPollMsg * msg) +{ + if (msg == NULL) + return nopoll_false; + + return msg->has_fin; +} + +/** + * @brief Allows to check if the message represents a frame fragment. + * + * The function allows to check if the provided noPollMsg is a + * fragment from a bigger frame or message that was splitted as a + * consequence of not being able to read the entire frame or because + * it wasn't sent complete from the other side. See \ref + * nopoll_msg_is_final for more information. + * + * The function also returns that the message is a fragment when the frame has FIN = 0. + * + * @param msg The message checked to be a fragment or not. + * + * @return nopoll_true if the message is a fragment, otherwise + * nopoll_false is returned. + */ +nopoll_bool nopoll_msg_is_fragment (noPollMsg * msg) +{ + if (msg == NULL) + return nopoll_false; + return msg->is_fragment || msg->has_fin == 0; +} + +/** + * @brief Get message OpCode to get the type of message that was + * received. + * + * @param msg The message that is being checked for its OpCode + * + * @return The op code or -1 in the case NULL reference is received. + */ +noPollOpCode nopoll_msg_opcode (noPollMsg * msg) +{ + if (msg == NULL) + return NOPOLL_UNKNOWN_OP_CODE; + return (noPollOpCode) msg->op_code; +} + +/** + * @brief Allows to join the provided noPollMsg references to create a + * newly allocated message (or reusing same reference but increasing reference + * counting) that contains both content. + * + * @param msg The message to be join to the next message. Headers from + * this message will be used as reference for the headers to be + * used. In the case this is NULL, the second argument will be used as + * argument and reference counting will be updated. + * + * @param msg2 The message to be join as a second part for the first + * argument. + * + * Here are some examples showing how the function works. The notation + * along the argument indicates the reference counting at the end of + * the function. + * + * msgA (2) = nopoll_msg_join (msgA (1), NULL); + * msgB (2) = nopoll_msg_join (NULL, msgB (1)); + * msgC (1) = nopoll_msg_join (msgA (1), msgB (1)); + * NULL = nopoll_msg_join (NULL, NULL); + * + * @return The function returns the newly allocated or reused + * reference with increased reference counting or NULL if it fails. + */ +noPollMsg * nopoll_msg_join (noPollMsg * msg, noPollMsg * msg2) +{ + noPollMsg * result; + + /* check for basic cases */ + if (msg == NULL && msg2 == NULL) + return NULL; + if (msg == NULL && msg2) { + nopoll_msg_ref (msg2); + return msg2; + } /* ned if */ + if (msg && msg2 == NULL) { + nopoll_msg_ref (msg); + return msg; + } /* end if */ + + /* now, join content */ + result = nopoll_msg_new (); + result->has_fin = msg->has_fin; + result->op_code = msg->op_code; + result->is_masked = msg->is_masked; + if (result->is_masked) + memcpy (result->mask, msg->mask, 4); + + /* copy payload size and content */ + result->payload_size = msg->payload_size + msg2->payload_size; + result->payload = nopoll_new (char, result->payload_size + 1); + + /* copy content from first message */ + memcpy (result->payload, msg->payload, msg->payload_size); + + /* copy content from second message */ + memcpy (((unsigned char *) result->payload) + msg->payload_size , msg2->payload, msg2->payload_size); + + /* return joined message */ + return result; +} + +/** + * @brief Allows to release the reference acquired, finished the + * object if all references are terminated. + * + * @param msg The websocket message to be finished. + */ +void nopoll_msg_unref (noPollMsg * msg) +{ + if (msg == NULL) + return; + + /* acquire mutex here */ + nopoll_mutex_lock (msg->ref_mutex); + + msg->refs--; + if (msg->refs != 0) { + /* release mutex here */ + nopoll_mutex_unlock (msg->ref_mutex); + return; + } + /* release mutex */ + nopoll_mutex_unlock (msg->ref_mutex); + nopoll_mutex_destroy (msg->ref_mutex); + + /* free websocket message */ + nopoll_free (msg->payload); + nopoll_free (msg); + + /* release mutex here */ + return; +} + + +/* @} */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_win32.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_win32.c new file mode 100644 index 0000000..b8dbfdb --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/nopoll/nopoll_win32.c @@ -0,0 +1,136 @@ +/* + * LibNoPoll: A websocket library + * Copyright (C) 2013 Advanced Software Production Line, S.L. + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * You may find a copy of the license under this software is released + * at COPYING file. This is LGPL software: you are welcome to develop + * proprietary applications using this library without any royalty or + * fee but returning back any change, improvement or addition in the + * form of source code, project image, documentation patches, etc. + * + * For commercial support on build Websocket enabled solutions + * contact us: + * + * Postal address: + * Advanced Software Production Line, S.L. + * Edificio Alius A, Oficina 102, + * C/ Antonio Suarez Nº 10, + * Alcalá de Henares 28802 Madrid + * Spain + * + * Email address: + * info@aspl.es - http://www.aspl.es/nopoll + */ + +#include + +#define LOG_DOMAIN "nopoll-win32" + +#if defined(NOPOLL_OS_WIN32) + +nopoll_bool __nopoll_win32_was_init = nopoll_false; + +int nopoll_win32_init (noPollCtx * ctx) +{ + WORD wVersionRequested; + WSADATA wsaData; + int error; + + if (__nopoll_win32_was_init) + return nopoll_true; + + wVersionRequested = MAKEWORD( 2, 2 ); + + error = WSAStartup( wVersionRequested, &wsaData ); + if (error != NO_ERROR) { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "unable to init winsock api, exiting.."); + return nopoll_false; + } + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "winsock initialization ok"); + /* flag the library as initialized */ + __nopoll_win32_was_init = nopoll_true; + return nopoll_true; +} + +BOOL APIENTRY DllMain (HINSTANCE hInst, + DWORD reason, + LPVOID reserved) +{ + + /* always returns true because nopoll init is done through + * nopoll_init */ + return nopoll_true; +} + +int __nopoll_win32_blocking_socket_set (NOPOLL_SOCKET socket, + int status) +{ + unsigned long enable = status; + + return (ioctlsocket (socket, FIONBIO, &enable) == 0); +} + +int nopoll_win32_nonblocking_enable (NOPOLL_SOCKET socket) +{ + return __nopoll_win32_blocking_socket_set (socket, 1); +} + +int nopoll_win32_blocking_enable (NOPOLL_SOCKET socket) +{ + return __nopoll_win32_blocking_socket_set (socket, 0); +} + +#if ! defined(HAVE_GETTIMEOFDAY) + + +/** + * @brief The function obtains the current time, expressed as seconds + * and microseconds since the Epoch, and store it in the timeval + * structure pointed to by tv. As posix says gettimeoday should return + * zero and should not reserve any value for error, this function + * returns zero. + * + * The timeval struct have the following members: + * + * \code + * struct timeval { + * long tv_sec; + * long tv_usec; + * } timeval; + * \endcode + * + * @param tv Timeval struct. + * @param notUsed Not defined. + * + * @return The function allways return 0. + */ +int nopoll_win32_gettimeofday(struct timeval *tv, noPollPtr notUsed) +{ + union { + long long ns100; + FILETIME fileTime; + } now; + + GetSystemTimeAsFileTime (&now.fileTime); + tv->tv_usec = (long) ((now.ns100 / 10LL) % 1000000LL); + tv->tv_sec = (long) ((now.ns100 - 116444736000000000LL) / 10000000LL); + return (0); +} /* end gettimeofday */ +#endif /* end ! defined(HAVE_GETTIMEOFDAY) */ + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/Makefile b/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/Makefile new file mode 100644 index 0000000..354bbb4 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/Makefile @@ -0,0 +1,54 @@ + +############################################################# +# 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 = libopenssl.a +COMPONENTS_libopenssl = library/liblibrary.a platform/libplatform.a +endif + +CCFLAGS += -fno-aggressive-loop-optimizations + +############################################################# +# 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 += -D_POSIX_SOURCE \ + -DLWIP_OPEN_SRC \ + -DPBUF_RSV_FOR_WLAN \ + -DEBUF_LWIP \ + -DMEMLEAK_DEBUG + +############################################################# +# 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 $(SDK_PATH)/include/openssl/ \ + -I $(SDK_PATH)/include/openssl/openssl \ + -I $(SDK_PATH)/include/openssl/internal \ + -I $(SDK_PATH)/include/openssl/platform +INCLUDES += -I ./ +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/OpenSSL-APIs.rst b/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/OpenSSL-APIs.rst new file mode 100644 index 0000000..93e438d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/OpenSSL-APIs.rst @@ -0,0 +1,1797 @@ +OpenSSL-APIs +------------ + +This directory does not contain OpenSSL itself, but the code here can be used as a wrapper for applications using the OpenSSL API. +It uses mbedTLS to do the actual work, so anyone compiling openssl code needs the mbedtls library and header file. + +OpenSSL APIs not mentioned in this article are not open to public for the time, +also do not have the corresponding function. +If user calls it directly, it will always return an error or may show cannot link at compiling time. + +Chapter Introduction +==================== + +- Chapter 1. SSL Context Method Create +- Chapter 2. SSL Context Fucntion +- Chapter 3. SSL Fucntion +- Chapter 4. SSL X509 Certification and Private Key Function + + +Chapter 1. SSL Context Method Create +==================================== + +1.1 const SSL_METHOD* ``SSLv3_client_method`` (void) + + Arguments:: + + none + + Return:: + + SSLV3.0 version SSL context client method point + + Description:: + + create the target SSL context method + + Example:: + + void example(void) + { + const SSL_METHOD *method = SSLv3_client_method(); + + ... + } + +1.2 const SSL_METHOD* ``TLSv1_client_method`` (void) + + Arguments:: + + none + + Return:: + + TLSV1.0 version SSL context client method point + + Description:: + + create the target SSL context method + + Example:: + + void example(void) + { + const SSL_METHOD *method = TLSv1_client_method(); + + ... + } + +1.3 const SSL_METHOD* ``TLSv1_1_client_method`` (void) + + Arguments:: + + none + + Return:: + + TLSV1.1 version SSL context client method point + + Description:: + + create the target SSL context method + + Example:: + + void example(void) + { + const SSL_METHOD *method = TLSv1_1_client_method(); + + ... + } + +1.4 const SSL_METHOD* ``TLSv1_2_client_method`` (void) + + Arguments:: + + none + + Return:: + + TLSV1.2 version SSL context client method point + + Description:: + + create the target SSL context method + + Example:: + + void example(void) + { + const SSL_METHOD *method = TLSv1_2_client_method(); + + ... + } + +1.5 const SSL_METHOD* ``TLS_client_method`` (void) + + Arguments:: + + none + + Return:: + + TLSV1.2 version SSL context client method point + + Description:: + + create the default SSL context method, it's always to be TLSV1.2 + + Example:: + + void example(void) + { + const SSL_METHOD *method = TLSv1_2_client_method(); + + ... + } + +1.6 const SSL_METHOD* ``SSLv3_server_method`` (void) + + Arguments:: + + none + + Return:: + + SSLV3.0 version SSL context server method point + + Description:: + + create the target SSL context method + + Example:: + + void example(void) + { + const SSL_METHOD *method = SSLv3_server_method(); + + ... + } + +1.7 const SSL_METHOD* ``TLSv1_server_method`` (void) + + Arguments:: + + none + + Return:: + + TLSV1.0 version SSL context server method point + + Description:: + + create the target SSL context method + + Example:: + + void example(void) + { + const SSL_METHOD *method = TLSv1_server_method(); + + ... + } + +1.8 const SSL_METHOD* ``TLSv1_1_server_method`` (void) + + Arguments:: + + none + + Return:: + + TLSV1.1 version SSL context server method point + + Description:: + + create the target SSL context method + + Example : + + void example(void) + { + const SSL_METHOD *method = TLSv1_1_server_method(); + + ... + } + + +1.9 const SSL_METHOD* ``TLSv1_2_server_method`` (void) + + Arguments:: + + none + + Return:: + + TLSV1.2 version SSL context server method point + + Description:: + + create the target SSL context method + + Example:: + + void example(void) + { + const SSL_METHOD *method = TLSv1_2_server_method(); + + ... + } + +1.10 const SSL_METHOD* ``TLS_server_method`` (void) + + Arguments:: + + none + + Return:: + + TLSV1.2 version SSL context server method point + + Description:: + + create the default SSL context method, it's always to be TLSV1.2 + + Example:: + + void example(void) + { + const SSL_METHOD *method = TLSv1_2_server_method(); + + ... + } + + +Chapter 2. SSL Context Fucntion +=============================== + + +2.1 SSL_CTX* ``SSL_CTX_new`` (const SSL_METHOD *method) + + Arguments:: + + method - the SSL context method point + + Return:: + + context point + + Description:: + + create a SSL context + + Example:: + + void example(void) + { + SSL_CTX *ctx = SSL_CTX_new(SSLv3_server_method()); + + ... + } + + +2.2 ``void SSL_CTX_free`` (SSL_CTX *ctx) + + Arguments:: + + ctx - the SSL context point + + Return:: + + none + + Description:: + + free a SSL context + + Example:: + + void example(void) + { + SSL_CTX *ctx; + + ... ... + + SSL_CTX_free(ctx); + } + + +2.3 ``int SSL_CTX_set_ssl_version`` (SSL_CTX *ctx, const SSL_METHOD *meth) + + Arguments:: + + ctx - SSL context point + meth - SSL method point + + Return:: + + 1 : OK + 0 : failed + + Description:: + + set the SSL context version + + Example:: + + void example(void) + { + SSL_CTX *ctx; + const SSL_METHOD *meth; + + ... ... + + SSL_CTX_set_ssl_version(ctx, meth); + } + + +2.4 const SSL_METHOD* ``SSL_CTX_get_ssl_method`` (SSL_CTX *ctx) + + Arguments:: + + ctx - SSL context point + + Return:: + + SSL context method + + Description:: + + get the SSL context method + + Example:: + + void example(void) + { + const SSL_METHOD *method; + SSL_CTX *ctx; + + ... ... + + method = SSL_CTX_get_ssl_method(ctx); + } + + + +Chapter 3. SSL Fucntion +======================= + + +3.1 SSL* ``SSL_new`` (SSL_CTX *ctx) + + Arguments:: + + ctx - SSL context point + + Return:: + + SSL method + + Description:: + + create a SSL + + Example:: + + void example(void) + { + SSL *ssl; + SSL_CTX *ctx; + + ... ... + + ssl = SSL_new(ctx); + } + + +3.2 void ``SSL_free`` (SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + none + + Description:: + + free SSL + + Example:: + + void example(void) + { + SSL *ssl; + + ... ... + + SSL_free(ssl); + } + + +3.3 int ``SSL_do_handshake`` (SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + 1 : OK + 0 : failed, connect is close by remote + -1 : a error catch + + Description:: + + perform the SSL handshake + + Example:: + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_do_handshake(ssl); + } + + +3.4 int ``SSL_connect`` (SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + 1 : OK + 0 : failed, connect is close by remote + -1 : a error catch + + Description:: + + connect to the remote SSL server + + Example:: + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_connect(ssl); + } + + +3.5 int ``SSL_accept`` (SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + 1 : OK + 0 : failed, connect is close by remote + -1 : a error catch + + Description:: + + accept the remote connection + + Example:: + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_accept(ssl); + } + + +3.6 int ``SSL_shutdown`` (SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + 1 : OK + 0 : failed, connect is close by remote + -1 : a error catch + + Description:: + + shutdown the connection + + Example:: + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_shutdown(ssl); + } + + +3.7 int ``SSL_clear`` (SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + 1 : OK + 0 : failed + + Description:: + + shutdown the connection + + Example:: + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_clear(ssl); + } + + +3.8 int ``SSL_read`` (SSL *ssl, void *buffer, int len) + + Arguments:: + + ssl - point + buffer - data buffer point + len - data length + + Return:: + + > 0 : OK, and return received data bytes + = 0 : no data received or connection is closed + < 0 : an error catch + + Description:: + + read data from remote + + Example:: + + void example(void) + { + SSL *ssl; + char *buf; + int len; + int ret; + + ... ... + + ret = SSL_read(ssl, buf, len); + } + +3.9 int ``SSL_write`` (SSL *ssl, const void *buffer, int len) + + Arguments:: + + ssl - SSL point + buffer - data buffer point + len - data length + + Return:: + + > 0 : OK, and return received data bytes + = 0 : no data sent or connection is closed + < 0 : an error catch + + Description:: + + send the data to remote + + Example:: + + void example(void) + { + SSL *ssl; + char *buf; + int len; + int ret; + + ... ... + + ret = SSL_write(ssl, buf, len); + } + + +3.10 ``SSL_CTX *SSL_get_SSL_CTX`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + SSL context + + Description:: + + get SSL context of the SSL + + Example:: + + void example(void) + { + SSL *ssl; + SSL_CTX *ctx; + + ... ... + + ctx = SSL_get_SSL_CTX(ssl); + } + + +3.11 int ``SSL_get_shutdown`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + shutdown mode + + Description:: + + get SSL shutdown mode + + Example:: + + void example(void) + { + SSL *ssl; + int mode; + + ... ... + + mode = SSL_get_SSL_CTX(ssl); + } + + +3.12 void ``SSL_set_shutdown`` (SSL *ssl, int mode) + + Arguments:: + + ssl - SSL point + + Return:: + + shutdown mode + + Description:: + + set SSL shutdown mode + + Example:: + + void example(void) + { + SSL *ssl; + int mode = 0; + + ... ... + + SSL_set_shutdown(ssl, mode); + } + + +3.13 const SSL_METHOD* ``SSL_get_ssl_method`` (SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + SSL method + + Description:: + + set SSL shutdown mode + + Example:: + + void example(void) + { + SSL *ssl; + const SSL_METHOD *method; + + ... ... + + method = SSL_get_ssl_method(ssl); + } + + +3.14 int ``SSL_set_ssl_method`` (SSL *ssl, const SSL_METHOD *method) + + Arguments:: + + ssl - SSL point + meth - SSL method point + + Return:: + + 1 : OK + 0 : failed + + Description:: + + set the SSL method + + Example:: + + void example(void) + { + int ret; + SSL *ssl; + const SSL_METHOD *method; + + ... ... + + ret = SSL_set_ssl_method(ssl, method); + } + + +3.15 int ``SSL_pending`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + data bytes + + Description:: + + get received data bytes + + Example:: + + void example(void) + { + int ret; + SSL *ssl; + + ... ... + + ret = SSL_pending(ssl); + } + + +3.16 int ``SSL_has_pending`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + 1 : Yes + 0 : No + + Description:: + + check if data is received + + Example:: + + void example(void) + { + int ret; + SSL *ssl; + + ... ... + + ret = SSL_has_pending(ssl); + } + + +3.17 int ``SSL_get_fd`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + >= 0 : socket id + < 0 : a error catch + + Description:: + + get the socket of the SSL + + Example:: + + void example(void) + { + int ret; + SSL *ssl; + + ... ... + + ret = SSL_get_fd(ssl); + } + + +3.18 int ``SSL_get_rfd`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + >= 0 : socket id + < 0 : a error catch + + Description:: + + get the read only socket of the SSL + + Example:: + + void example(void) + { + int ret; + SSL *ssl; + + ... ... + + ret = SSL_get_rfd(ssl); + } + + +3.19 int ``SSL_get_wfd`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + >= 0 : socket id + < 0 : a error catch + + Description:: + + get the write only socket of the SSL + + Example:: + + void example(void) + { + int ret; + SSL *ssl; + + ... ... + + ret = SSL_get_wfd(ssl); + } + + +3.20 int ``SSL_set_fd`` (SSL *ssl, int fd) + + Arguments:: + + ssl - SSL point + fd - socket id + + Return:: + + 1 : OK + 0 : failed + + Description:: + + set socket to SSL + + Example:: + + void example(void) + { + int ret; + SSL *ssl; + int socket; + + ... ... + + ret = SSL_set_fd(ssl, socket); + } + + +3.21 int ``SSL_set_rfd`` (SSL *ssl, int fd) + + Arguments:: + + ssl - SSL point + fd - socket id + + Return:: + + 1 : OK + 0 : failed + + Description:: + + set read only socket to SSL + + Example:: + + void example(void) + { + int ret; + SSL *ssl; + int socket; + + ... ... + + ret = SSL_set_rfd(ssl, socket); + } + + +3.22 int ``SSL_set_wfd`` (SSL *ssl, int fd) + + Arguments:: + + ssl - SSL point + fd - socket id + + Return:: + + 1 : OK + 0 : failed + + Description:: + + set write only socket to SSL + + Example:: + + void example(void) + { + int ret; + SSL *ssl; + int socket; + + ... ... + + ret = SSL_set_wfd(ssl, socket); + } + + +3.23 int ``SSL_version`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + SSL version + + Description:: + + get SSL version + + Example:: + + void example(void) + { + int version; + SSL *ssl; + + ... ... + + version = SSL_version(ssl); + } + + +3.24 const char* ``SSL_get_version`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + SSL version string + + Description:: + + get the SSL current version string + + Example:: + + void example(void) + { + char *version; + SSL *ssl; + + ... ... + + version = SSL_get_version(ssl); + } + + +3.25 OSSL_HANDSHAKE_STATE ``SSL_get_state`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + SSL state + + Description:: + + get the SSL state + + Example:: + + void example(void) + { + OSSL_HANDSHAKE_STATE state; + SSL *ssl; + + ... ... + + state = SSL_get_state(ssl); + } + + +3.26 const char* ``SSL_alert_desc_string`` (int value) + + Arguments:: + + value - SSL description + + Return:: + + alert value string + + Description:: + + get alert description string + + Example:: + + void example(void) + { + int val; + char *str; + + ... ... + + str = SSL_alert_desc_string(val); + } + + +3.27 const char* ``SSL_alert_desc_string_long`` (int value) + + Arguments:: + + value - SSL description + + Return:: + + alert value long string + + Description:: + + get alert description long string + + Example:: + + void example(void) + { + int val; + char *str; + + ... ... + + str = SSL_alert_desc_string_long(val); + } + + +3.28 const char* ``SSL_alert_type_string`` (int value) + + Arguments:: + + value - SSL type description + + Return:: + + alert type string + + Description:: + + get alert type string + + Example:: + + void example(void) + { + int val; + char *str; + + ... ... + + str = SSL_alert_type_string(val); + } + + +3.29 const char* ``SSL_alert_type_string_long`` (int value) + + Arguments:: + + value - SSL type description + + Return:: + + alert type long string + + Description:: + + get alert type long string + + Example:: + + void example(void) + { + int val; + char *str; + + ... ... + + str = SSL_alert_type_string_long(val); + } + +3.30 const char* ``SSL_rstate_string`` (SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + state string + + Description:: + + get the state string where SSL is reading + + Example:: + + void example(void) + { + SSL *ssl; + char *str; + + ... ... + + str = SSL_rstate_string(ssl); + } + + +3.31 const char* ``SSL_rstate_string_long`` (SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + state long string + + Description:: + + get the state long string where SSL is reading + + Example:: + + void example(void) + { + SSL *ssl; + char *str; + + ... ... + + str = SSL_rstate_string_long(ssl); + } + + +3.32 const char* ``SSL_state_string`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + state string + + Description:: + + get the state string + + Example:: + + void example(void) + { + SSL *ssl; + const char *str; + + ... ... + + str = SSL_state_string(ssl); + } + + +3.33 char* ``SSL_state_string_long`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + state long string + + Description:: + + get the state long string + + Example:: + + void example(void) + { + SSL *ssl; + char *str; + + ... ... + + str = SSL_state_string(ssl); + } + + +3.34 int ``SSL_get_error`` (const SSL *ssl, int ret_code) + + Arguments:: + + ssl - SSL point + ret_code - SSL return code + + Return:: + + SSL error number + + Description:: + + get SSL error code + + Example:: + + void example(void) + { + SSL *ssl; + int ret; + int err; + + ... ... + + err = SSL_get_error(ssl, ret); + } + +3.35 int ``SSL_want`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + specifical statement + + Description:: + + get the SSL specifical statement + + Example:: + + void example(void) + { + SSL *ssl; + int state; + + ... ... + + state = SSL_want(ssl); + } + + +3.36 int ``SSL_want_nothing`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + 0 : false + 1 : true + + Description:: + + check if SSL want nothing + + Example:: + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_want(ssl); + } + + +3.37 int ``SSL_want_read`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + 0 : false + 1 : true + + Description:: + + check if SSL want to read + + Example:: + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_want_read(ssl); + } + + +3.38 int ``SSL_want_write`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + 0 : false + 1 : true + + Description:: + + check if SSL want to write + + Example:: + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_want_write(ssl); + } + + +Chapter 4. SSL X509 Certification and Private Key Function +========================================================== + + +4.1 X509* ``d2i_X509`` (X509 **cert, const unsigned char *buffer, long len) + + Arguments:: + + cert - a point pointed to X509 certification + buffer - a point pointed to the certification context memory point + length - certification bytes + + Return:: + + X509 certification object point + + Description:: + + load a character certification context into system context. If '*cert' is pointed to the + certification, then load certification into it. Or create a new X509 certification object + + Example:: + + void example(void) + { + X509 *new; + X509 *cert; + unsigned char *buffer; + long len; + ... ... + + new = d2i_X509(&cert, buffer, len); + } + + +4.2 int ``SSL_add_client_CA`` (SSL *ssl, X509 *x) + + Arguments:: + + ssl - SSL point + x - CA certification point + + Return:: + + 1 : OK + 0 : failed + + Description:: + + add CA client certification into the SSL + + Example:: + + void example(void) + { + int ret; + SSL *ssl; + X509 *new; + + ... ... + + ret = SSL_add_client_CA(ssl, new); + } + + +4.3 int ``SSL_CTX_add_client_CA`` (SSL_CTX *ctx, X509 *x) + + Arguments:: + + ctx - SSL context point + x - CA certification point + + Return:: + + 1 : OK + 0 : failed + + Description:: + + add CA client certification into the SSL context + + Example:: + + void example(void) + { + int ret; + SSL_CTX *ctx; + X509 *new; + + ... ... + + ret = SSL_add_clSSL_CTX_add_client_CAient_CA(ctx, new); + } + + +4.4 X509* ``SSL_get_certificate`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + SSL certification point + + Description:: + + get the SSL certification point + + Example:: + + void example(void) + { + SSL *ssl; + X509 *cert; + + ... ... + + cert = SSL_get_certificate(ssl); + } + + +4.5 long ``SSL_get_verify_result`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + the result of verifying + + Description:: + + get the verifying result of the SSL certification + + Example:: + + void example(void) + { + SSL *ssl; + long ret; + + ... ... + + ret = SSL_get_verify_result(ssl); + } + + +4.6 int ``SSL_CTX_use_certificate`` (SSL_CTX *ctx, X509 *x) + + Arguments:: + + ctx - the SSL context point + pkey - certification object point + + Return:: + + 1 : OK + 0 : failed + + Description:: + + load the certification into the SSL_CTX or SSL object + + Example:: + + void example(void) + { + int ret; + SSL_CTX *ctx + X509 *new; + + ... ... + + ret = SSL_CTX_use_certificate(ctx, new); + } + + +4.7 int ``SSL_CTX_use_certificate_ASN1`` (SSL_CTX *ctx, int len, const unsigned char *d) + + Arguments:: + + ctx - SSL context point + len - certification length + d - data point + + Return:: + + 1 : OK + 0 : failed + + Description:: + + load the ASN1 certification into SSL context + + Example:: + + void example(void) + { + int ret; + SSL_CTX *ctx; + const unsigned char *buf; + int len; + + ... ... + + ret = SSL_CTX_use_certificate_ASN1(ctx, len, buf); + } + + +4.8 int ``SSL_CTX_use_PrivateKey`` (SSL_CTX *ctx, EVP_PKEY *pkey) + + Arguments:: + + ctx - SSL context point + pkey - private key object point + + Return:: + + 1 : OK + 0 : failed + + Description:: + + load the private key into the context object + + Example:: + + void example(void) + { + int ret; + SSL_CTX *ctx; + EVP_PKEY *pkey; + + ... ... + + ret = SSL_CTX_use_PrivateKey(ctx, pkey); + } + + +4.9 int ``SSL_CTX_use_PrivateKey_ASN1`` (int pk, SSL_CTX *ctx, const unsigned char *d, long len) + + Arguments:: + + ctx - SSL context point + d - data point + len - private key length + + Return:: + + 1 : OK + 0 : failed + + Description:: + + load the ASN1 private key into SSL context + + Example:: + + void example(void) + { + int ret; + int pk; + SSL_CTX *ctx; + const unsigned char *buf; + long len; + + ... ... + + ret = SSL_CTX_use_PrivateKey_ASN1(pk, ctx, buf, len); + } + + +4.10 int ``SSL_CTX_use_RSAPrivateKey_ASN1`` (SSL_CTX *ctx, const unsigned char *d, long len) + + Arguments:: + + ctx - SSL context point + d - data point + len - private key length + + Return:: + + 1 : OK + 0 : failed + + Description:: + + load the RSA ASN1 private key into SSL context + + Example:: + + void example(void) + { + int ret; + SSL_CTX *ctx; + const unsigned char *buf; + long len; + + ... ... + + ret = SSL_CTX_use_RSAPrivateKey_ASN1(ctx, buf, len); + } + + +4.11 int ``SSL_use_certificate_ASN1`` (SSL *ssl, int len, const unsigned char *d) + + Arguments:: + + ssl - SSL point + len - data bytes + d - data point + + Return:: + + 1 : OK + 0 : failed + + Description:: + + load certification into the SSL + + Example:: + + void example(void) + { + int ret; + SSL *ssl; + const unsigned char *buf; + long len; + + ... ... + + ret = SSL_use_certificate_ASN1(ssl, len, buf); + } + + +4.12 X509* ``SSL_get_peer_certificate`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + peer certification + + Description:: + + get peer certification + + Example:: + + void example(void) + { + SSL *ssl; + X509 *peer; + + ... ... + + peer = SSL_get_peer_certificate(ssl); + } + diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/library/Makefile b/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/library/Makefile new file mode 100644 index 0000000..836e81d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/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/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/library/ssl_cert.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/library/ssl_cert.c new file mode 100644 index 0000000..5c60812 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/library/ssl_cert.c @@ -0,0 +1,87 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#include "ssl_cert.h" +#include "ssl_pkey.h" +#include "ssl_x509.h" +#include "ssl_dbg.h" +#include "ssl_port.h" + +/** + * @brief create a certification object according to input certification + */ +CERT *__ssl_cert_new(CERT *ic) +{ + CERT *cert; + + X509 *ix; + EVP_PKEY *ipk; + + cert = ssl_mem_zalloc(sizeof(CERT)); + if (!cert) { + SSL_DEBUG(SSL_CERT_ERROR_LEVEL, "no enough memory > (cert)"); + goto no_mem; + } + + if (ic) { + ipk = ic->pkey; + ix = ic->x509; + } else { + ipk = NULL; + ix = NULL; + } + + cert->pkey = __EVP_PKEY_new(ipk); + if (!cert->pkey) { + SSL_DEBUG(SSL_CERT_ERROR_LEVEL, "__EVP_PKEY_new() return NULL"); + goto pkey_err; + } + + cert->x509 = __X509_new(ix); + if (!cert->x509) { + SSL_DEBUG(SSL_CERT_ERROR_LEVEL, "__X509_new() return NULL"); + goto x509_err; + } + + return cert; + +x509_err: + EVP_PKEY_free(cert->pkey); +pkey_err: + ssl_mem_free(cert); +no_mem: + return NULL; +} + +/** + * @brief create a certification object include private key object + */ +CERT *ssl_cert_new(void) +{ + return __ssl_cert_new(NULL); +} + +/** + * @brief free a certification object + */ +void ssl_cert_free(CERT *cert) +{ + SSL_ASSERT3(cert); + + X509_free(cert->x509); + + EVP_PKEY_free(cert->pkey); + + ssl_mem_free(cert); +} diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/library/ssl_lib.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/library/ssl_lib.c new file mode 100644 index 0000000..43c1300 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/library/ssl_lib.c @@ -0,0 +1,1556 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#include "ssl_lib.h" +#include "ssl_pkey.h" +#include "ssl_x509.h" +#include "ssl_cert.h" +#include "ssl_dbg.h" +#include "ssl_port.h" + +#define SSL_SEND_DATA_MAX_LENGTH 1460 + +/** + * @brief create a new SSL session object + */ +static SSL_SESSION* SSL_SESSION_new(void) +{ + SSL_SESSION *session; + + session = ssl_mem_zalloc(sizeof(SSL_SESSION)); + if (!session) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "no enough memory > (session)"); + goto failed1; + } + + session->peer = X509_new(); + if (!session->peer) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "X509_new() return NULL"); + goto failed2; + } + + return session; + +failed2: + ssl_mem_free(session); +failed1: + return NULL; +} + +/** + * @brief free a new SSL session object + */ +static void SSL_SESSION_free(SSL_SESSION *session) +{ + X509_free(session->peer); + ssl_mem_free(session); +} + +/** + * @brief Discover whether the current connection is in the error state + */ +int ossl_statem_in_error(const SSL *ssl) +{ + SSL_ASSERT1(ssl); + + if (ssl->statem.state == MSG_FLOW_ERROR) + return 1; + + return 0; +} + +/** + * @brief get the SSL specifical statement + */ +int SSL_want(const SSL *ssl) +{ + SSL_ASSERT1(ssl); + + return ssl->rwstate; +} + +/** + * @brief check if SSL want nothing + */ +int SSL_want_nothing(const SSL *ssl) +{ + SSL_ASSERT1(ssl); + + return (SSL_want(ssl) == SSL_NOTHING); +} + +/** + * @brief check if SSL want to read + */ +int SSL_want_read(const SSL *ssl) +{ + SSL_ASSERT1(ssl); + + return (SSL_want(ssl) == SSL_READING); +} + +/** + * @brief check if SSL want to write + */ +int SSL_want_write(const SSL *ssl) +{ + SSL_ASSERT1(ssl); + + return (SSL_want(ssl) == SSL_WRITING); +} + +/** + * @brief check if SSL want to lookup X509 certification + */ +int SSL_want_x509_lookup(const SSL *ssl) +{ + SSL_ASSERT1(ssl); + + return (SSL_want(ssl) == SSL_WRITING); +} + +/** + * @brief get SSL error code + */ +int SSL_get_error(const SSL *ssl, int ret_code) +{ + int ret = SSL_ERROR_SYSCALL; + + SSL_ASSERT1(ssl); + + if (ret_code > 0) + ret = SSL_ERROR_NONE; + else if (ret_code < 0) + { + if (SSL_want_read(ssl)) + ret = SSL_ERROR_WANT_READ; + else if (SSL_want_write(ssl)) + ret = SSL_ERROR_WANT_WRITE; + else + ret = SSL_ERROR_SYSCALL; //unknown + } + else // ret_code == 0 + { + if (ssl->shutdown & SSL_RECEIVED_SHUTDOWN) + ret = SSL_ERROR_ZERO_RETURN; + else + ret = SSL_ERROR_SYSCALL; + } + + return ret; +} + +/** + * @brief get the SSL state + */ +OSSL_HANDSHAKE_STATE SSL_get_state(const SSL *ssl) +{ + OSSL_HANDSHAKE_STATE state; + + SSL_ASSERT1(ssl); + + state = SSL_METHOD_CALL(get_state, ssl); + + return state; +} + +/** + * @brief create a SSL context + */ +SSL_CTX* SSL_CTX_new(const SSL_METHOD *method) +{ + SSL_CTX *ctx; + CERT *cert; + X509 *client_ca; + + if (!method) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "no no_method"); + return NULL; + } + + client_ca = X509_new(); + if (!client_ca) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "X509_new() return NULL"); + goto failed1; + } + + cert = ssl_cert_new(); + if (!cert) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "ssl_cert_new() return NULL"); + goto failed2; + } + + ctx = (SSL_CTX *)ssl_mem_zalloc(sizeof(SSL_CTX)); + if (!ctx) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "no enough memory > (ctx)"); + goto failed3; + } + + ctx->method = method; + ctx->client_CA = client_ca; + ctx->cert = cert; + + ctx->version = method->version; + + return ctx; + +failed3: + ssl_cert_free(cert); +failed2: + X509_free(client_ca); +failed1: + return NULL; +} + +/** + * @brief free a SSL context + */ +void SSL_CTX_free(SSL_CTX* ctx) +{ + SSL_ASSERT3(ctx); + + ssl_cert_free(ctx->cert); + + X509_free(ctx->client_CA); + + ssl_mem_free(ctx); +} + +/** + * @brief set the SSL context version + */ +int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth) +{ + SSL_ASSERT1(ctx); + SSL_ASSERT1(meth); + + ctx->method = meth; + + ctx->version = meth->version; + + return 1; +} + +/** + * @brief get the SSL context current method + */ +const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *ctx) +{ + SSL_ASSERT2(ctx); + + return ctx->method; +} + +/** + * @brief create a SSL + */ +SSL *SSL_new(SSL_CTX *ctx) +{ + int ret = 0; + SSL *ssl; + + if (!ctx) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "no ctx"); + return NULL; + } + + ssl = (SSL *)ssl_mem_zalloc(sizeof(SSL)); + if (!ssl) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "no enough memory > (ssl)"); + goto failed1; + } + + ssl->session = SSL_SESSION_new(); + if (!ssl->session) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "SSL_SESSION_new() return NULL"); + goto failed2; + } + + ssl->cert = __ssl_cert_new(ctx->cert); + if (!ssl->cert) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "__ssl_cert_new() return NULL"); + goto failed3; + } + + ssl->client_CA = __X509_new(ctx->client_CA); + if (!ssl->client_CA) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "__X509_new() return NULL"); + goto failed4; + } + + ssl->ctx = ctx; + ssl->method = ctx->method; + + ssl->version = ctx->version; + ssl->options = ctx->options; + + ssl->verify_mode = ctx->verify_mode; + + ret = SSL_METHOD_CALL(new, ssl); + if (ret) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "SSL_METHOD_CALL(new) return %d", ret); + goto failed5; + } + + ssl->rwstate = SSL_NOTHING; + + return ssl; + +failed5: + X509_free(ssl->client_CA); +failed4: + ssl_cert_free(ssl->cert); +failed3: + SSL_SESSION_free(ssl->session); +failed2: + ssl_mem_free(ssl); +failed1: + return NULL; +} + +/** + * @brief free the SSL + */ +void SSL_free(SSL *ssl) +{ + SSL_ASSERT3(ssl); + + SSL_METHOD_CALL(free, ssl); + + X509_free(ssl->client_CA); + + ssl_cert_free(ssl->cert); + + SSL_SESSION_free(ssl->session); + + ssl_mem_free(ssl); +} + +/** + * @brief perform the SSL handshake + */ +int SSL_do_handshake(SSL *ssl) +{ + int ret; + + SSL_ASSERT1(ssl); + + ret = SSL_METHOD_CALL(handshake, ssl); + + return ret; +} + +/** + * @brief connect to the remote SSL server + */ +int SSL_connect(SSL *ssl) +{ + SSL_ASSERT1(ssl); + + return SSL_do_handshake(ssl); +} + +/** + * @brief accept the remote connection + */ +int SSL_accept(SSL *ssl) +{ + SSL_ASSERT1(ssl); + + return SSL_do_handshake(ssl); +} + +/** + * @brief shutdown the connection + */ +int SSL_shutdown(SSL *ssl) +{ + int ret; + + SSL_ASSERT1(ssl); + + if (SSL_get_state(ssl) != TLS_ST_OK) return 1; + + ret = SSL_METHOD_CALL(shutdown, ssl); + + return ret; +} + +/** + * @brief reset the SSL + */ +int SSL_clear(SSL *ssl) +{ + int ret; + + SSL_ASSERT1(ssl); + + ret = SSL_shutdown(ssl); + if (1 != ret) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "SSL_shutdown return %d", ret); + goto failed1; + } + + SSL_METHOD_CALL(free, ssl); + + ret = SSL_METHOD_CALL(new, ssl); + if (!ret) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "SSL_METHOD_CALL(new) return %d", ret); + goto failed1; + } + + return 1; + +failed1: + return ret; +} + +/** + * @brief read data from to remote + */ +int SSL_read(SSL *ssl, void *buffer, int len) +{ + int ret; + + SSL_ASSERT1(ssl); + SSL_ASSERT1(buffer); + SSL_ASSERT1(len); + + ssl->rwstate = SSL_READING; + + ret = SSL_METHOD_CALL(read, ssl, buffer, len); + + if (ret == len) + ssl->rwstate = SSL_NOTHING; + + return ret; +} + +/** + * @brief send the data to remote + */ +int SSL_write(SSL *ssl, const void *buffer, int len) +{ + int ret; + int send_bytes; + const unsigned char *pbuf; + + SSL_ASSERT1(ssl); + SSL_ASSERT1(buffer); + SSL_ASSERT1(len); + + ssl->rwstate = SSL_WRITING; + + send_bytes = len; + pbuf = (const unsigned char *)buffer; + + do { + int bytes; + + if (send_bytes > SSL_SEND_DATA_MAX_LENGTH) + bytes = SSL_SEND_DATA_MAX_LENGTH; + else + bytes = send_bytes; + + ret = SSL_METHOD_CALL(send, ssl, buffer, bytes); + if (ret > 0) { + pbuf += ret; + send_bytes -= ret; + } + } while (ret > 0 && send_bytes); + + if (ret >= 0) { + ret = len - send_bytes; + ssl->rwstate = SSL_NOTHING; + } else + ret = -1; + + return ret; +} + +/** + * @brief get SSL context of the SSL + */ +SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl) +{ + SSL_ASSERT2(ssl); + + return ssl->ctx; +} + +/** + * @brief get the SSL current method + */ +const SSL_METHOD *SSL_get_ssl_method(SSL *ssl) +{ + SSL_ASSERT2(ssl); + + return ssl->method; +} + +/** + * @brief set the SSL method + */ +int SSL_set_ssl_method(SSL *ssl, const SSL_METHOD *method) +{ + int ret; + + SSL_ASSERT1(ssl); + SSL_ASSERT1(method); + + if (ssl->version != method->version) { + + ret = SSL_shutdown(ssl); + if (1 != ret) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "SSL_shutdown return %d", ret); + goto failed1; + } + + SSL_METHOD_CALL(free, ssl); + + ssl->method = method; + + ret = SSL_METHOD_CALL(new, ssl); + if (!ret) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "SSL_METHOD_CALL(new) return %d", ret); + goto failed1; + } + } else { + ssl->method = method; + } + + + return 1; + +failed1: + return ret; +} + +/** + * @brief get SSL shutdown mode + */ +int SSL_get_shutdown(const SSL *ssl) +{ + SSL_ASSERT1(ssl); + + return ssl->shutdown; +} + +/** + * @brief set SSL shutdown mode + */ +void SSL_set_shutdown(SSL *ssl, int mode) +{ + SSL_ASSERT3(ssl); + + ssl->shutdown = mode; +} + + +/** + * @brief get the number of the bytes to be read + */ +int SSL_pending(const SSL *ssl) +{ + int ret; + + SSL_ASSERT1(ssl); + + ret = SSL_METHOD_CALL(pending, ssl); + + return ret; +} + +/** + * @brief check if some data can be read + */ +int SSL_has_pending(const SSL *ssl) +{ + int ret; + + SSL_ASSERT1(ssl); + + if (SSL_pending(ssl)) + ret = 1; + else + ret = 0; + + return ret; +} + +/** + * @brief clear the SSL context option bit of "op" + */ +unsigned long SSL_CTX_clear_options(SSL_CTX *ctx, unsigned long op) +{ + SSL_ASSERT1(ctx); + + return ctx->options &= ~op; +} + +/** + * @brief get the SSL context option + */ +unsigned long SSL_CTX_get_options(SSL_CTX *ctx) +{ + SSL_ASSERT1(ctx); + + return ctx->options; +} + +/** + * @brief set the option of the SSL context + */ +unsigned long SSL_CTX_set_options(SSL_CTX *ctx, unsigned long opt) +{ + SSL_ASSERT1(ctx); + + return ctx->options |= opt; +} + +/** + * @brief clear SSL option + */ +unsigned long SSL_clear_options(SSL *ssl, unsigned long op) +{ + SSL_ASSERT1(ssl); + + return ssl->options & ~op; +} + +/** + * @brief get SSL option + */ +unsigned long SSL_get_options(SSL *ssl) +{ + SSL_ASSERT1(ssl); + + return ssl->options; +} + +/** + * @brief clear SSL option + */ +unsigned long SSL_set_options(SSL *ssl, unsigned long op) +{ + SSL_ASSERT1(ssl); + + return ssl->options |= op; +} + +/** + * @brief get the socket handle of the SSL + */ +int SSL_get_fd(const SSL *ssl) +{ + int ret; + + SSL_ASSERT1(ssl); + + ret = SSL_METHOD_CALL(get_fd, ssl, 0); + + return ret; +} + +/** + * @brief get the read only socket handle of the SSL + */ +int SSL_get_rfd(const SSL *ssl) +{ + int ret; + + SSL_ASSERT1(ssl); + + ret = SSL_METHOD_CALL(get_fd, ssl, 0); + + return ret; +} + +/** + * @brief get the write only socket handle of the SSL + */ +int SSL_get_wfd(const SSL *ssl) +{ + int ret; + + SSL_ASSERT1(ssl); + + ret = SSL_METHOD_CALL(get_fd, ssl, 0); + + return ret; +} + +/** + * @brief bind the socket file description into the SSL + */ +int SSL_set_fd(SSL *ssl, int fd) +{ + SSL_ASSERT1(ssl); + SSL_ASSERT1(fd >= 0); + + SSL_METHOD_CALL(set_fd, ssl, fd, 0); + + return 1; +} + +/** + * @brief bind the read only socket file description into the SSL + */ +int SSL_set_rfd(SSL *ssl, int fd) +{ + SSL_ASSERT1(ssl); + SSL_ASSERT1(fd >= 0); + + SSL_METHOD_CALL(set_fd, ssl, fd, 0); + + return 1; +} + +/** + * @brief bind the write only socket file description into the SSL + */ +int SSL_set_wfd(SSL *ssl, int fd) +{ + SSL_ASSERT1(ssl); + SSL_ASSERT1(fd >= 0); + + SSL_METHOD_CALL(set_fd, ssl, fd, 0); + + return 1; +} + +/** + * @brief get SSL version + */ +int SSL_version(const SSL *ssl) +{ + SSL_ASSERT1(ssl); + + return ssl->version; +} + +/** + * @brief get the SSL version string + */ +static const char* ssl_protocol_to_string(int version) +{ + const char *str; + + if (version == TLS1_2_VERSION) + str = "TLSv1.2"; + else if (version == TLS1_1_VERSION) + str = "TLSv1.1"; + else if (version == TLS1_VERSION) + str = "TLSv1"; + else if (version == SSL3_VERSION) + str = "SSLv3"; + else + str = "unknown"; + + return str; +} + +/** + * @brief get the SSL current version + */ +const char *SSL_get_version(const SSL *ssl) +{ + SSL_ASSERT2(ssl); + + return ssl_protocol_to_string(SSL_version(ssl)); +} + +/** + * @brief get alert description string + */ +const char* SSL_alert_desc_string(int value) +{ + const char *str; + + switch (value & 0xff) + { + case SSL3_AD_CLOSE_NOTIFY: + str = "CN"; + break; + case SSL3_AD_UNEXPECTED_MESSAGE: + str = "UM"; + break; + case SSL3_AD_BAD_RECORD_MAC: + str = "BM"; + break; + case SSL3_AD_DECOMPRESSION_FAILURE: + str = "DF"; + break; + case SSL3_AD_HANDSHAKE_FAILURE: + str = "HF"; + break; + case SSL3_AD_NO_CERTIFICATE: + str = "NC"; + break; + case SSL3_AD_BAD_CERTIFICATE: + str = "BC"; + break; + case SSL3_AD_UNSUPPORTED_CERTIFICATE: + str = "UC"; + break; + case SSL3_AD_CERTIFICATE_REVOKED: + str = "CR"; + break; + case SSL3_AD_CERTIFICATE_EXPIRED: + str = "CE"; + break; + case SSL3_AD_CERTIFICATE_UNKNOWN: + str = "CU"; + break; + case SSL3_AD_ILLEGAL_PARAMETER: + str = "IP"; + break; + case TLS1_AD_DECRYPTION_FAILED: + str = "DC"; + break; + case TLS1_AD_RECORD_OVERFLOW: + str = "RO"; + break; + case TLS1_AD_UNKNOWN_CA: + str = "CA"; + break; + case TLS1_AD_ACCESS_DENIED: + str = "AD"; + break; + case TLS1_AD_DECODE_ERROR: + str = "DE"; + break; + case TLS1_AD_DECRYPT_ERROR: + str = "CY"; + break; + case TLS1_AD_EXPORT_RESTRICTION: + str = "ER"; + break; + case TLS1_AD_PROTOCOL_VERSION: + str = "PV"; + break; + case TLS1_AD_INSUFFICIENT_SECURITY: + str = "IS"; + break; + case TLS1_AD_INTERNAL_ERROR: + str = "IE"; + break; + case TLS1_AD_USER_CANCELLED: + str = "US"; + break; + case TLS1_AD_NO_RENEGOTIATION: + str = "NR"; + break; + case TLS1_AD_UNSUPPORTED_EXTENSION: + str = "UE"; + break; + case TLS1_AD_CERTIFICATE_UNOBTAINABLE: + str = "CO"; + break; + case TLS1_AD_UNRECOGNIZED_NAME: + str = "UN"; + break; + case TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE: + str = "BR"; + break; + case TLS1_AD_BAD_CERTIFICATE_HASH_VALUE: + str = "BH"; + break; + case TLS1_AD_UNKNOWN_PSK_IDENTITY: + str = "UP"; + break; + default: + str = "UK"; + break; + } + + return str; +} + +/** + * @brief get alert description long string + */ +const char* SSL_alert_desc_string_long(int value) +{ + const char *str; + + switch (value & 0xff) + { + case SSL3_AD_CLOSE_NOTIFY: + str = "close notify"; + break; + case SSL3_AD_UNEXPECTED_MESSAGE: + str = "unexpected_message"; + break; + case SSL3_AD_BAD_RECORD_MAC: + str = "bad record mac"; + break; + case SSL3_AD_DECOMPRESSION_FAILURE: + str = "decompression failure"; + break; + case SSL3_AD_HANDSHAKE_FAILURE: + str = "handshake failure"; + break; + case SSL3_AD_NO_CERTIFICATE: + str = "no certificate"; + break; + case SSL3_AD_BAD_CERTIFICATE: + str = "bad certificate"; + break; + case SSL3_AD_UNSUPPORTED_CERTIFICATE: + str = "unsupported certificate"; + break; + case SSL3_AD_CERTIFICATE_REVOKED: + str = "certificate revoked"; + break; + case SSL3_AD_CERTIFICATE_EXPIRED: + str = "certificate expired"; + break; + case SSL3_AD_CERTIFICATE_UNKNOWN: + str = "certificate unknown"; + break; + case SSL3_AD_ILLEGAL_PARAMETER: + str = "illegal parameter"; + break; + case TLS1_AD_DECRYPTION_FAILED: + str = "decryption failed"; + break; + case TLS1_AD_RECORD_OVERFLOW: + str = "record overflow"; + break; + case TLS1_AD_UNKNOWN_CA: + str = "unknown CA"; + break; + case TLS1_AD_ACCESS_DENIED: + str = "access denied"; + break; + case TLS1_AD_DECODE_ERROR: + str = "decode error"; + break; + case TLS1_AD_DECRYPT_ERROR: + str = "decrypt error"; + break; + case TLS1_AD_EXPORT_RESTRICTION: + str = "export restriction"; + break; + case TLS1_AD_PROTOCOL_VERSION: + str = "protocol version"; + break; + case TLS1_AD_INSUFFICIENT_SECURITY: + str = "insufficient security"; + break; + case TLS1_AD_INTERNAL_ERROR: + str = "internal error"; + break; + case TLS1_AD_USER_CANCELLED: + str = "user canceled"; + break; + case TLS1_AD_NO_RENEGOTIATION: + str = "no renegotiation"; + break; + case TLS1_AD_UNSUPPORTED_EXTENSION: + str = "unsupported extension"; + break; + case TLS1_AD_CERTIFICATE_UNOBTAINABLE: + str = "certificate unobtainable"; + break; + case TLS1_AD_UNRECOGNIZED_NAME: + str = "unrecognized name"; + break; + case TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE: + str = "bad certificate status response"; + break; + case TLS1_AD_BAD_CERTIFICATE_HASH_VALUE: + str = "bad certificate hash value"; + break; + case TLS1_AD_UNKNOWN_PSK_IDENTITY: + str = "unknown PSK identity"; + break; + default: + str = "unknown"; + break; + } + + return str; +} + +/** + * @brief get alert type string + */ +const char *SSL_alert_type_string(int value) +{ + const char *str; + + switch (value >> 8) + { + case SSL3_AL_WARNING: + str = "W"; + break; + case SSL3_AL_FATAL: + str = "F"; + break; + default: + str = "U"; + break; + } + + return str; +} + +/** + * @brief get alert type long string + */ +const char *SSL_alert_type_string_long(int value) +{ + const char *str; + + switch (value >> 8) + { + case SSL3_AL_WARNING: + str = "warning"; + break; + case SSL3_AL_FATAL: + str = "fatal"; + break; + default: + str = "unknown"; + break; + } + + return str; +} + +/** + * @brief get the state string where SSL is reading + */ +const char *SSL_rstate_string(SSL *ssl) +{ + const char *str; + + SSL_ASSERT2(ssl); + + switch (ssl->rlayer.rstate) + { + case SSL_ST_READ_HEADER: + str = "RH"; + break; + case SSL_ST_READ_BODY: + str = "RB"; + break; + case SSL_ST_READ_DONE: + str = "RD"; + break; + default: + str = "unknown"; + break; + } + + return str; +} + +/** + * @brief get the statement long string where SSL is reading + */ +const char *SSL_rstate_string_long(SSL *ssl) +{ + const char *str = "unknown"; + + SSL_ASSERT2(ssl); + + switch (ssl->rlayer.rstate) + { + case SSL_ST_READ_HEADER: + str = "read header"; + break; + case SSL_ST_READ_BODY: + str = "read body"; + break; + case SSL_ST_READ_DONE: + str = "read done"; + break; + default: + break; + } + + return str; +} + +/** + * @brief get SSL statement string + */ +char *SSL_state_string(const SSL *ssl) +{ + char *str = "UNKWN "; + + SSL_ASSERT2(ssl); + + if (ossl_statem_in_error(ssl)) + str = "SSLERR"; + else + { + switch (SSL_get_state(ssl)) + { + case TLS_ST_BEFORE: + str = "PINIT "; + break; + case TLS_ST_OK: + str = "SSLOK "; + break; + case TLS_ST_CW_CLNT_HELLO: + str = "TWCH"; + break; + case TLS_ST_CR_SRVR_HELLO: + str = "TRSH"; + break; + case TLS_ST_CR_CERT: + str = "TRSC"; + break; + case TLS_ST_CR_KEY_EXCH: + str = "TRSKE"; + break; + case TLS_ST_CR_CERT_REQ: + str = "TRCR"; + break; + case TLS_ST_CR_SRVR_DONE: + str = "TRSD"; + break; + case TLS_ST_CW_CERT: + str = "TWCC"; + break; + case TLS_ST_CW_KEY_EXCH: + str = "TWCKE"; + break; + case TLS_ST_CW_CERT_VRFY: + str = "TWCV"; + break; + case TLS_ST_SW_CHANGE: + case TLS_ST_CW_CHANGE: + str = "TWCCS"; + break; + case TLS_ST_SW_FINISHED: + case TLS_ST_CW_FINISHED: + str = "TWFIN"; + break; + case TLS_ST_SR_CHANGE: + case TLS_ST_CR_CHANGE: + str = "TRCCS"; + break; + case TLS_ST_SR_FINISHED: + case TLS_ST_CR_FINISHED: + str = "TRFIN"; + break; + case TLS_ST_SW_HELLO_REQ: + str = "TWHR"; + break; + case TLS_ST_SR_CLNT_HELLO: + str = "TRCH"; + break; + case TLS_ST_SW_SRVR_HELLO: + str = "TWSH"; + break; + case TLS_ST_SW_CERT: + str = "TWSC"; + break; + case TLS_ST_SW_KEY_EXCH: + str = "TWSKE"; + break; + case TLS_ST_SW_CERT_REQ: + str = "TWCR"; + break; + case TLS_ST_SW_SRVR_DONE: + str = "TWSD"; + break; + case TLS_ST_SR_CERT: + str = "TRCC"; + break; + case TLS_ST_SR_KEY_EXCH: + str = "TRCKE"; + break; + case TLS_ST_SR_CERT_VRFY: + str = "TRCV"; + break; + case DTLS_ST_CR_HELLO_VERIFY_REQUEST: + str = "DRCHV"; + break; + case DTLS_ST_SW_HELLO_VERIFY_REQUEST: + str = "DWCHV"; + break; + default: + break; + } + } + + return str; +} + +/** + * @brief get SSL statement long string + */ +char *SSL_state_string_long(const SSL *ssl) +{ + char *str = "UNKWN "; + + SSL_ASSERT2(ssl); + + if (ossl_statem_in_error(ssl)) + str = "SSLERR"; + else + { + switch (SSL_get_state(ssl)) + { + case TLS_ST_BEFORE: + str = "before SSL initialization"; + break; + case TLS_ST_OK: + str = "SSL negotiation finished successfully"; + break; + case TLS_ST_CW_CLNT_HELLO: + str = "SSLv3/TLS write client hello"; + break; + case TLS_ST_CR_SRVR_HELLO: + str = "SSLv3/TLS read server hello"; + break; + case TLS_ST_CR_CERT: + str = "SSLv3/TLS read server certificate"; + break; + case TLS_ST_CR_KEY_EXCH: + str = "SSLv3/TLS read server key exchange"; + break; + case TLS_ST_CR_CERT_REQ: + str = "SSLv3/TLS read server certificate request"; + break; + case TLS_ST_CR_SESSION_TICKET: + str = "SSLv3/TLS read server session ticket"; + break; + case TLS_ST_CR_SRVR_DONE: + str = "SSLv3/TLS read server done"; + break; + case TLS_ST_CW_CERT: + str = "SSLv3/TLS write client certificate"; + break; + case TLS_ST_CW_KEY_EXCH: + str = "SSLv3/TLS write client key exchange"; + break; + case TLS_ST_CW_CERT_VRFY: + str = "SSLv3/TLS write certificate verify"; + break; + case TLS_ST_CW_CHANGE: + case TLS_ST_SW_CHANGE: + str = "SSLv3/TLS write change cipher spec"; + break; + case TLS_ST_CW_FINISHED: + case TLS_ST_SW_FINISHED: + str = "SSLv3/TLS write finished"; + break; + case TLS_ST_CR_CHANGE: + case TLS_ST_SR_CHANGE: + str = "SSLv3/TLS read change cipher spec"; + break; + case TLS_ST_CR_FINISHED: + case TLS_ST_SR_FINISHED: + str = "SSLv3/TLS read finished"; + break; + case TLS_ST_SR_CLNT_HELLO: + str = "SSLv3/TLS read client hello"; + break; + case TLS_ST_SW_HELLO_REQ: + str = "SSLv3/TLS write hello request"; + break; + case TLS_ST_SW_SRVR_HELLO: + str = "SSLv3/TLS write server hello"; + break; + case TLS_ST_SW_CERT: + str = "SSLv3/TLS write certificate"; + break; + case TLS_ST_SW_KEY_EXCH: + str = "SSLv3/TLS write key exchange"; + break; + case TLS_ST_SW_CERT_REQ: + str = "SSLv3/TLS write certificate request"; + break; + case TLS_ST_SW_SESSION_TICKET: + str = "SSLv3/TLS write session ticket"; + break; + case TLS_ST_SW_SRVR_DONE: + str = "SSLv3/TLS write server done"; + break; + case TLS_ST_SR_CERT: + str = "SSLv3/TLS read client certificate"; + break; + case TLS_ST_SR_KEY_EXCH: + str = "SSLv3/TLS read client key exchange"; + break; + case TLS_ST_SR_CERT_VRFY: + str = "SSLv3/TLS read certificate verify"; + break; + case DTLS_ST_CR_HELLO_VERIFY_REQUEST: + str = "DTLS1 read hello verify request"; + break; + case DTLS_ST_SW_HELLO_VERIFY_REQUEST: + str = "DTLS1 write hello verify request"; + break; + default: + break; + } + } + + return str; +} + +/** + * @brief set the SSL context read buffer length + */ +void SSL_CTX_set_default_read_buffer_len(SSL_CTX *ctx, size_t len) +{ + SSL_ASSERT3(ctx); + + ctx->read_buffer_len = len; +} + +/** + * @brief set the SSL read buffer length + */ +void SSL_set_default_read_buffer_len(SSL *ssl, size_t len) +{ + SSL_ASSERT3(ssl); + SSL_ASSERT3(len); + + SSL_METHOD_CALL(set_bufflen, ssl, len); +} + +/** + * @brief set the SSL information callback function + */ +void SSL_set_info_callback(SSL *ssl, void (*cb) (const SSL *ssl, int type, int val)) +{ + SSL_ASSERT3(ssl); + + ssl->info_callback = cb; +} + +/** + * @brief add SSL context reference count by '1' + */ +int SSL_CTX_up_ref(SSL_CTX *ctx) +{ + SSL_ASSERT1(ctx); + + /** + * no support multi-thread SSL here + */ + ctx->references++; + + return 1; +} + +/** + * @brief set the SSL security level + */ +void SSL_set_security_level(SSL *ssl, int level) +{ + SSL_ASSERT3(ssl); + + ssl->cert->sec_level = level; +} + +/** + * @brief get the SSL security level + */ +int SSL_get_security_level(const SSL *ssl) +{ + SSL_ASSERT1(ssl); + + return ssl->cert->sec_level; +} + +/** + * @brief get the SSL verifying mode of the SSL context + */ +int SSL_CTX_get_verify_mode(const SSL_CTX *ctx) +{ + SSL_ASSERT1(ctx); + + return ctx->verify_mode; +} + +/** + * @brief set the session timeout time + */ +long SSL_CTX_set_timeout(SSL_CTX *ctx, long t) +{ + long l; + + SSL_ASSERT1(ctx); + + l = ctx->session_timeout; + ctx->session_timeout = t; + + return l; +} + +/** + * @brief get the session timeout time + */ +long SSL_CTX_get_timeout(const SSL_CTX *ctx) +{ + SSL_ASSERT1(ctx); + + return ctx->session_timeout; +} + +/** + * @brief set the SSL if we can read as many as data + */ +void SSL_set_read_ahead(SSL *ssl, int yes) +{ + SSL_ASSERT3(ssl); + + ssl->rlayer.read_ahead = yes; +} + +/** + * @brief set the SSL context if we can read as many as data + */ +void SSL_CTX_set_read_ahead(SSL_CTX *ctx, int yes) +{ + SSL_ASSERT3(ctx); + + ctx->read_ahead = yes; +} + +/** + * @brief get the SSL ahead signal if we can read as many as data + */ +int SSL_get_read_ahead(const SSL *ssl) +{ + SSL_ASSERT1(ssl); + + return ssl->rlayer.read_ahead; +} + +/** + * @brief get the SSL context ahead signal if we can read as many as data + */ +long SSL_CTX_get_read_ahead(SSL_CTX *ctx) +{ + SSL_ASSERT1(ctx); + + return ctx->read_ahead; +} + +/** + * @brief check if the SSL context can read as many as data + */ +long SSL_CTX_get_default_read_ahead(SSL_CTX *ctx) +{ + SSL_ASSERT1(ctx); + + return ctx->read_ahead; +} + +/** + * @brief set SSL session time + */ +long SSL_set_time(SSL *ssl, long t) +{ + SSL_ASSERT1(ssl); + + ssl->session->time = t; + + return t; +} + +/** + * @brief set SSL session timeout time + */ +long SSL_set_timeout(SSL *ssl, long t) +{ + SSL_ASSERT1(ssl); + + ssl->session->timeout = t; + + return t; +} + +/** + * @brief get the verifying result of the SSL certification + */ +long SSL_get_verify_result(const SSL *ssl) +{ + SSL_ASSERT1(ssl); + + return SSL_METHOD_CALL(get_verify_result, ssl); +} + +/** + * @brief get the SSL verifying depth of the SSL context + */ +int SSL_CTX_get_verify_depth(const SSL_CTX *ctx) +{ + SSL_ASSERT1(ctx); + + return ctx->param.depth; +} + +/** + * @brief set the SSL verify depth of the SSL context + */ +void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth) +{ + SSL_ASSERT3(ctx); + + ctx->param.depth = depth; +} + +/** + * @brief get the SSL verifying depth of the SSL + */ +int SSL_get_verify_depth(const SSL *ssl) +{ + SSL_ASSERT1(ssl); + + return ssl->param.depth; +} + +/** + * @brief set the SSL verify depth of the SSL + */ +void SSL_set_verify_depth(SSL *ssl, int depth) +{ + SSL_ASSERT3(ssl); + + ssl->param.depth = depth; +} + +/** + * @brief set the SSL context verifying of the SSL context + */ +void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, int (*verify_callback)(int, X509_STORE_CTX *)) +{ + SSL_ASSERT3(ctx); + + ctx->verify_mode = mode; + ctx->default_verify_callback = verify_callback; +} + +/** + * @brief set the SSL verifying of the SSL context + */ +void SSL_set_verify(SSL *ssl, int mode, int (*verify_callback)(int, X509_STORE_CTX *)) +{ + SSL_ASSERT3(ssl); + + ssl->verify_mode = mode; + ssl->verify_callback = verify_callback; +} diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/library/ssl_methods.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/library/ssl_methods.c new file mode 100644 index 0000000..0002360 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/library/ssl_methods.c @@ -0,0 +1,81 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#include "ssl_methods.h" +#include "ssl_pm.h" + +/** + * TLS method function collection + */ +IMPLEMENT_TLS_METHOD_FUNC(TLS_method_func, + ssl_pm_new, ssl_pm_free, + ssl_pm_handshake, ssl_pm_shutdown, ssl_pm_clear, + ssl_pm_read, ssl_pm_send, ssl_pm_pending, + ssl_pm_set_fd, ssl_pm_get_fd, + ssl_pm_set_bufflen, + ssl_pm_get_verify_result, + ssl_pm_get_state); + +/** + * TLS or SSL client method collection + */ +IMPLEMENT_TLS_METHOD(TLS_ANY_VERSION, 0, TLS_method_func, TLS_client_method); + +IMPLEMENT_TLS_METHOD(TLS1_2_VERSION, 0, TLS_method_func, TLSv1_2_client_method); + +IMPLEMENT_TLS_METHOD(TLS1_1_VERSION, 0, TLS_method_func, TLSv1_1_client_method); + +IMPLEMENT_TLS_METHOD(TLS1_VERSION, 0, TLS_method_func, TLSv1_client_method); + +IMPLEMENT_SSL_METHOD(SSL3_VERSION, 0, TLS_method_func, SSLv3_client_method); + +/** + * TLS or SSL server method collection + */ +IMPLEMENT_TLS_METHOD(TLS_ANY_VERSION, 1, TLS_method_func, TLS_server_method); + +IMPLEMENT_TLS_METHOD(TLS1_1_VERSION, 1, TLS_method_func, TLSv1_1_server_method); + +IMPLEMENT_TLS_METHOD(TLS1_2_VERSION, 1, TLS_method_func, TLSv1_2_server_method); + +IMPLEMENT_TLS_METHOD(TLS1_VERSION, 0, TLS_method_func, TLSv1_server_method); + +IMPLEMENT_SSL_METHOD(SSL3_VERSION, 1, TLS_method_func, SSLv3_server_method); + +/** + * TLS or SSL method collection + */ +IMPLEMENT_TLS_METHOD(TLS_ANY_VERSION, -1, TLS_method_func, TLS_method); + +IMPLEMENT_SSL_METHOD(TLS1_2_VERSION, -1, TLS_method_func, TLSv1_2_method); + +IMPLEMENT_SSL_METHOD(TLS1_1_VERSION, -1, TLS_method_func, TLSv1_1_method); + +IMPLEMENT_SSL_METHOD(TLS1_VERSION, -1, TLS_method_func, TLSv1_method); + +IMPLEMENT_SSL_METHOD(SSL3_VERSION, -1, TLS_method_func, SSLv3_method); + +/** + * @brief get X509 object method + */ +IMPLEMENT_X509_METHOD(X509_method, + x509_pm_new, x509_pm_free, + x509_pm_load, x509_pm_show_info); + +/** + * @brief get private key object method + */ +IMPLEMENT_PKEY_METHOD(EVP_PKEY_method, + pkey_pm_new, pkey_pm_free, + pkey_pm_load); diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/library/ssl_pkey.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/library/ssl_pkey.c new file mode 100644 index 0000000..567a33e --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/library/ssl_pkey.c @@ -0,0 +1,239 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#include "ssl_pkey.h" +#include "ssl_methods.h" +#include "ssl_dbg.h" +#include "ssl_port.h" + +/** + * @brief create a private key object according to input private key + */ +EVP_PKEY* __EVP_PKEY_new(EVP_PKEY *ipk) +{ + int ret; + EVP_PKEY *pkey; + + pkey = ssl_mem_zalloc(sizeof(EVP_PKEY)); + if (!pkey) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "no enough memory > (pkey)"); + goto no_mem; + } + + if (ipk) { + pkey->method = ipk->method; + } else { + pkey->method = EVP_PKEY_method(); + } + + ret = EVP_PKEY_METHOD_CALL(new, pkey, ipk); + if (ret) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "EVP_PKEY_METHOD_CALL(new) return %d", ret); + goto failed; + } + + return pkey; + +failed: + ssl_mem_free(pkey); +no_mem: + return NULL; +} + +/** + * @brief create a private key object + */ +EVP_PKEY* EVP_PKEY_new(void) +{ + return __EVP_PKEY_new(NULL); +} + +/** + * @brief free a private key object + */ +void EVP_PKEY_free(EVP_PKEY *pkey) +{ + SSL_ASSERT3(pkey); + + EVP_PKEY_METHOD_CALL(free, pkey); + + ssl_mem_free(pkey); +} + +/** + * @brief load a character key context into system context. If '*a' is pointed to the + * private key, then load key into it. Or create a new private key object + */ +EVP_PKEY *d2i_PrivateKey(int type, + EVP_PKEY **a, + const unsigned char **pp, + long length) +{ + int m = 0; + int ret; + EVP_PKEY *pkey; + + SSL_ASSERT2(pp); + SSL_ASSERT2(*pp); + SSL_ASSERT2(length); + + if (a && *a) { + pkey = *a; + } else { + pkey = EVP_PKEY_new();; + if (!pkey) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "EVP_PKEY_new() return NULL"); + goto failed1; + } + + m = 1; + } + + ret = EVP_PKEY_METHOD_CALL(load, pkey, *pp, length); + if (ret) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "EVP_PKEY_METHOD_CALL(load) return %d", ret); + goto failed2; + } + + if (a) + *a = pkey; + + return pkey; + +failed2: + if (m) + EVP_PKEY_free(pkey); +failed1: + return NULL; +} + +/** + * @brief set the SSL context private key + */ +int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey) +{ + SSL_ASSERT1(ctx); + SSL_ASSERT1(pkey); + + if (ctx->cert->pkey == pkey) + return 1; + + if (ctx->cert->pkey) + EVP_PKEY_free(ctx->cert->pkey); + + ctx->cert->pkey = pkey; + + return 1; +} + +/** + * @brief set the SSL private key + */ +int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey) +{ + SSL_ASSERT1(ssl); + SSL_ASSERT1(pkey); + + if (ssl->cert->pkey == pkey) + return 1; + + if (ssl->cert->pkey) + EVP_PKEY_free(ssl->cert->pkey); + + ssl->cert->pkey = pkey; + + return 1; +} + +/** + * @brief load private key into the SSL context + */ +int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, + const unsigned char *d, long len) +{ + int ret; + EVP_PKEY *pk; + + pk = d2i_PrivateKey(0, NULL, &d, len); + if (!pk) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "d2i_PrivateKey() return NULL"); + goto failed1; + } + + ret = SSL_CTX_use_PrivateKey(ctx, pk); + if (!ret) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "SSL_CTX_use_PrivateKey() return %d", ret); + goto failed2; + } + + return 1; + +failed2: + EVP_PKEY_free(pk); +failed1: + return 0; +} + +/** + * @brief load private key into the SSL + */ +int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, + const unsigned char *d, long len) +{ + int ret; + EVP_PKEY *pk; + + pk = d2i_PrivateKey(0, NULL, &d, len); + if (!pk) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "d2i_PrivateKey() return NULL"); + goto failed1; + } + + ret = SSL_use_PrivateKey(ssl, pk); + if (!ret) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "SSL_use_PrivateKey() return %d", ret); + goto failed2; + } + + return 1; + +failed2: + EVP_PKEY_free(pk); +failed1: + return 0; +} + +/** + * @brief load the private key file into SSL context + */ +int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type) +{ + return 0; +} + +/** + * @brief load the private key file into SSL + */ +int SSL_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type) +{ + return 0; +} + +/** + * @brief load the RSA ASN1 private key into SSL context + */ +int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d, long len) +{ + return SSL_CTX_use_PrivateKey_ASN1(0, ctx, d, len); +} diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/library/ssl_stack.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/library/ssl_stack.c new file mode 100644 index 0000000..da836da --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/library/ssl_stack.c @@ -0,0 +1,74 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#include "ssl_stack.h" +#include "ssl_dbg.h" +#include "ssl_port.h" + +#ifndef CONFIG_MIN_NODES + #define MIN_NODES 4 +#else + #define MIN_NODES CONFIG_MIN_NODES +#endif + +/** + * @brief create a openssl stack object + */ +OPENSSL_STACK* OPENSSL_sk_new(OPENSSL_sk_compfunc c) +{ + OPENSSL_STACK *stack; + char **data; + + stack = ssl_mem_zalloc(sizeof(OPENSSL_STACK)); + if (!stack) { + SSL_DEBUG(SSL_STACK_ERROR_LEVEL, "no enough memory > (stack)"); + goto no_mem1; + } + + data = ssl_mem_zalloc(sizeof(*data) * MIN_NODES); + if (!data) { + SSL_DEBUG(SSL_STACK_ERROR_LEVEL, "no enough memory > (data)"); + goto no_mem2; + } + + stack->data = data; + stack->num_alloc = MIN_NODES; + stack->c = c; + + return stack; + +no_mem2: + ssl_mem_free(stack); +no_mem1: + return NULL; +} + +/** + * @brief create a NULL function openssl stack object + */ +OPENSSL_STACK *OPENSSL_sk_new_null(void) +{ + return OPENSSL_sk_new((OPENSSL_sk_compfunc)NULL); +} + +/** + * @brief free openssl stack object + */ +void OPENSSL_sk_free(OPENSSL_STACK *stack) +{ + SSL_ASSERT3(stack); + + ssl_mem_free(stack->data); + ssl_mem_free(stack); +} diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/library/ssl_x509.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/library/ssl_x509.c new file mode 100644 index 0000000..ef0503c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/library/ssl_x509.c @@ -0,0 +1,285 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#include "ssl_x509.h" +#include "ssl_methods.h" +#include "ssl_dbg.h" +#include "ssl_port.h" + +/** + * @brief show X509 certification information + */ +int __X509_show_info(X509 *x) +{ + return X509_METHOD_CALL(show_info, x); +} + +/** + * @brief create a X509 certification object according to input X509 certification + */ +X509* __X509_new(X509 *ix) +{ + int ret; + X509 *x; + + x = ssl_mem_zalloc(sizeof(X509)); + if (!x) { + SSL_DEBUG(SSL_X509_ERROR_LEVEL, "no enough memory > (x)"); + goto no_mem; + } + + if (ix) + x->method = ix->method; + else + x->method = X509_method(); + + ret = X509_METHOD_CALL(new, x, ix); + if (ret) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "X509_METHOD_CALL(new) return %d", ret); + goto failed; + } + + return x; + +failed: + ssl_mem_free(x); +no_mem: + return NULL; +} + +/** + * @brief create a X509 certification object + */ +X509* X509_new(void) +{ + return __X509_new(NULL); +} + +/** + * @brief free a X509 certification object + */ +void X509_free(X509 *x) +{ + SSL_ASSERT3(x); + + X509_METHOD_CALL(free, x); + + ssl_mem_free(x); +}; + +/** + * @brief load a character certification context into system context. If '*cert' is pointed to the + * certification, then load certification into it. Or create a new X509 certification object + */ +X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len) +{ + int m = 0; + int ret; + X509 *x; + + SSL_ASSERT2(buffer); + SSL_ASSERT2(len); + + if (cert && *cert) { + x = *cert; + } else { + x = X509_new(); + if (!x) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "X509_new() return NULL"); + goto failed1; + } + m = 1; + } + + ret = X509_METHOD_CALL(load, x, buffer, len); + if (ret) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "X509_METHOD_CALL(load) return %d", ret); + goto failed2; + } + + return x; + +failed2: + if (m) + X509_free(x); +failed1: + return NULL; +} + +/** + * @brief set SSL context client CA certification + */ +int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x) +{ + SSL_ASSERT1(ctx); + SSL_ASSERT1(x); + + if (ctx->client_CA == x) + return 1; + + X509_free(ctx->client_CA); + + ctx->client_CA = x; + + return 1; +} + +/** + * @brief add CA client certification into the SSL + */ +int SSL_add_client_CA(SSL *ssl, X509 *x) +{ + SSL_ASSERT1(ssl); + SSL_ASSERT1(x); + + if (ssl->client_CA == x) + return 1; + + X509_free(ssl->client_CA); + + ssl->client_CA = x; + + return 1; +} + +/** + * @brief set the SSL context certification + */ +int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) +{ + SSL_ASSERT1(ctx); + SSL_ASSERT1(x); + + if (ctx->cert->x509 == x) + return 1; + + X509_free(ctx->cert->x509); + + ctx->cert->x509 = x; + + return 1; +} + +/** + * @brief set the SSL certification + */ +int SSL_use_certificate(SSL *ssl, X509 *x) +{ + SSL_ASSERT1(ssl); + SSL_ASSERT1(x); + + if (ssl->cert->x509 == x) + return 1; + + X509_free(ssl->cert->x509); + + ssl->cert->x509 = x; + + return 1; +} + +/** + * @brief get the SSL certification point + */ +X509 *SSL_get_certificate(const SSL *ssl) +{ + SSL_ASSERT2(ssl); + + return ssl->cert->x509; +} + +/** + * @brief load certification into the SSL context + */ +int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, + const unsigned char *d) +{ + int ret; + X509 *x; + + x = d2i_X509(NULL, d, len); + if (!x) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "d2i_X509() return NULL"); + goto failed1; + } + + ret = SSL_CTX_use_certificate(ctx, x); + if (!ret) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "SSL_CTX_use_certificate() return %d", ret); + goto failed2; + } + + return 1; + +failed2: + X509_free(x); +failed1: + return 0; +} + +/** + * @brief load certification into the SSL + */ +int SSL_use_certificate_ASN1(SSL *ssl, int len, + const unsigned char *d) +{ + int ret; + X509 *x; + + x = d2i_X509(NULL, d, len); + if (!x) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "d2i_X509() return NULL"); + goto failed1; + } + + ret = SSL_use_certificate(ssl, x); + if (!ret) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "SSL_use_certificate() return %d", ret); + goto failed2; + } + + return 1; + +failed2: + X509_free(x); +failed1: + return 0; +} + +/** + * @brief load the certification file into SSL context + */ +int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type) +{ + return 0; +} + +/** + * @brief load the certification file into SSL + */ +int SSL_use_certificate_file(SSL *ssl, const char *file, int type) +{ + return 0; +} + +/** + * @brief get peer certification + */ +X509 *SSL_get_peer_certificate(const SSL *ssl) +{ + SSL_ASSERT2(ssl); + + return ssl->session->peer; +} + diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/platform/Makefile b/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/platform/Makefile new file mode 100644 index 0000000..3fc3ed2 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/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/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/platform/ssl_pm.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/platform/ssl_pm.c new file mode 100644 index 0000000..74a0f4f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/openssl/platform/ssl_pm.c @@ -0,0 +1,667 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#include "ssl_pm.h" +#include "ssl_port.h" +#include "ssl_dbg.h" + +/* mbedtls include */ +#include "mbedtls/platform.h" +#include "mbedtls/net.h" +#include "mbedtls/debug.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/error.h" +#include "mbedtls/certs.h" + +#define X509_INFO_STRING_LENGTH 3072 +#define OPENSSL_READ_BUFFER_LENGTH_MIN 2048 +#define OPENSSL_READ_BUFFER_LENGTH_MAX 8192 + +struct ssl_pm +{ + /* local socket file description */ + mbedtls_net_context fd; + /* remote client socket file description */ + mbedtls_net_context cl_fd; + + mbedtls_ssl_config conf; + + mbedtls_ctr_drbg_context ctr_drbg; + + mbedtls_ssl_context ssl; + + mbedtls_entropy_context entropy; +}; + +struct x509_pm +{ + mbedtls_x509_crt *x509_crt; + + mbedtls_x509_crt *ex_crt; +}; + +struct pkey_pm +{ + mbedtls_pk_context *pkey; + + mbedtls_pk_context *ex_pkey; +}; + +unsigned int max_content_len; + +/*********************************************************************************************/ +/************************************ SSL arch interface *************************************/ + +#ifdef CONFIG_OPENSSL_LOWLEVEL_DEBUG + +/* mbedtls debug level */ +#define MBEDTLS_DEBUG_LEVEL 4 + +/** + * @brief mbedtls debug function + */ +static void ssl_platform_debug(void *ctx, int level, + const char *file, int line, + const char *str) +{ + /* Shorten 'file' from the whole file path to just the filename + + This is a bit wasteful because the macros are compiled in with + the full _FILE_ path in each case. + */ + char *file_sep = rindex(file, '/'); + if(file_sep) + file = file_sep + 1; + + SSL_DEBUG(SSL_DEBUG_ON, "%s:%d %s", file, line, str); +} +#endif + +/** + * @brief create SSL low-level object + */ +int ssl_pm_new(SSL *ssl) +{ + struct ssl_pm *ssl_pm; + int ret; + + const unsigned char pers[] = "OpenSSL PM"; + size_t pers_len = sizeof(pers); + + int endpoint; + int version; + + const SSL_METHOD *method = ssl->method; + + if (ssl->ctx->read_buffer_len < OPENSSL_READ_BUFFER_LENGTH_MIN || + ssl->ctx->read_buffer_len > OPENSSL_READ_BUFFER_LENGTH_MAX) + return -1; + + ssl_pm = ssl_mem_zalloc(sizeof(struct ssl_pm)); + if (!ssl_pm) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (ssl_pm)"); + goto no_mem; + } + + max_content_len = ssl->ctx->read_buffer_len; + + mbedtls_net_init(&ssl_pm->fd); + mbedtls_net_init(&ssl_pm->cl_fd); + + mbedtls_ssl_config_init(&ssl_pm->conf); + mbedtls_ctr_drbg_init(&ssl_pm->ctr_drbg); + mbedtls_entropy_init(&ssl_pm->entropy); + mbedtls_ssl_init(&ssl_pm->ssl); + + ret = mbedtls_ctr_drbg_seed(&ssl_pm->ctr_drbg, mbedtls_entropy_func, &ssl_pm->entropy, pers, pers_len); + if (ret) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ctr_drbg_seed() return -0x%x", -ret); + goto mbedtls_err1; + } + + if (method->endpoint) { + endpoint = MBEDTLS_SSL_IS_SERVER; + } else { + endpoint = MBEDTLS_SSL_IS_CLIENT; + } + ret = mbedtls_ssl_config_defaults(&ssl_pm->conf, endpoint, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); + if (ret) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_config_defaults() return -0x%x", -ret); + goto mbedtls_err2; + } + + if (TLS_ANY_VERSION != ssl->version) { + if (TLS1_2_VERSION == ssl->version) + version = MBEDTLS_SSL_MINOR_VERSION_3; + else if (TLS1_1_VERSION == ssl->version) + version = MBEDTLS_SSL_MINOR_VERSION_2; + else if (TLS1_VERSION == ssl->version) + version = MBEDTLS_SSL_MINOR_VERSION_1; + else + version = MBEDTLS_SSL_MINOR_VERSION_0; + + mbedtls_ssl_conf_max_version(&ssl_pm->conf, MBEDTLS_SSL_MAJOR_VERSION_3, version); + mbedtls_ssl_conf_min_version(&ssl_pm->conf, MBEDTLS_SSL_MAJOR_VERSION_3, version); + } else { + mbedtls_ssl_conf_max_version(&ssl_pm->conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3); + mbedtls_ssl_conf_min_version(&ssl_pm->conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0); + } + + mbedtls_ssl_conf_rng(&ssl_pm->conf, mbedtls_ctr_drbg_random, &ssl_pm->ctr_drbg); + +#ifdef CONFIG_OPENSSL_LOWLEVEL_DEBUG + mbedtls_debug_set_threshold(MBEDTLS_DEBUG_LEVEL); + mbedtls_ssl_conf_dbg(&ssl_pm->conf, ssl_platform_debug, NULL); +#else + mbedtls_ssl_conf_dbg(&ssl_pm->conf, NULL, NULL); +#endif + + ret = mbedtls_ssl_setup(&ssl_pm->ssl, &ssl_pm->conf); + if (ret) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_setup() return -0x%x", -ret); + goto mbedtls_err2; + } + + mbedtls_ssl_set_bio(&ssl_pm->ssl, &ssl_pm->fd, mbedtls_net_send, mbedtls_net_recv, NULL); + + ssl->ssl_pm = ssl_pm; + + return 0; + +mbedtls_err2: + mbedtls_ssl_config_free(&ssl_pm->conf); + mbedtls_ctr_drbg_free(&ssl_pm->ctr_drbg); +mbedtls_err1: + mbedtls_entropy_free(&ssl_pm->entropy); + ssl_mem_free(ssl_pm); +no_mem: + return -1; +} + +/** + * @brief free SSL low-level object + */ +void ssl_pm_free(SSL *ssl) +{ + struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + + mbedtls_ctr_drbg_free(&ssl_pm->ctr_drbg); + mbedtls_entropy_free(&ssl_pm->entropy); + mbedtls_ssl_config_free(&ssl_pm->conf); + mbedtls_ssl_free(&ssl_pm->ssl); + + ssl_mem_free(ssl_pm); + ssl->ssl_pm = NULL; +} + +/** + * @brief reload SSL low-level certification object + */ +static int ssl_pm_reload_crt(SSL *ssl) +{ + int ret; + int mode; + struct ssl_pm *ssl_pm = ssl->ssl_pm; + struct x509_pm *ca_pm = (struct x509_pm *)ssl->client_CA->x509_pm; + + struct pkey_pm *pkey_pm = (struct pkey_pm *)ssl->cert->pkey->pkey_pm; + struct x509_pm *crt_pm = (struct x509_pm *)ssl->cert->x509->x509_pm; + + if (ssl->verify_mode == SSL_VERIFY_PEER) + mode = MBEDTLS_SSL_VERIFY_REQUIRED; + else if (ssl->verify_mode == SSL_VERIFY_FAIL_IF_NO_PEER_CERT) + mode = MBEDTLS_SSL_VERIFY_OPTIONAL; + else if (ssl->verify_mode == SSL_VERIFY_CLIENT_ONCE) + mode = MBEDTLS_SSL_VERIFY_UNSET; + else + mode = MBEDTLS_SSL_VERIFY_NONE; + + mbedtls_ssl_conf_authmode(&ssl_pm->conf, mode); + + if (ca_pm->x509_crt) { + mbedtls_ssl_conf_ca_chain(&ssl_pm->conf, ca_pm->x509_crt, NULL); + } else if (ca_pm->ex_crt) { + mbedtls_ssl_conf_ca_chain(&ssl_pm->conf, ca_pm->ex_crt, NULL); + } + + if (crt_pm->x509_crt && pkey_pm->pkey) { + ret = mbedtls_ssl_conf_own_cert(&ssl_pm->conf, crt_pm->x509_crt, pkey_pm->pkey); + } else if (crt_pm->ex_crt && pkey_pm->ex_pkey) { + ret = mbedtls_ssl_conf_own_cert(&ssl_pm->conf, crt_pm->ex_crt, pkey_pm->ex_pkey); + } else { + ret = 0; + } + + if (ret) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_conf_own_cert() return -0x%x", -ret); + ret = -1; + } + + return ret; +} + +/* + * Perform the mbedtls SSL handshake instead of mbedtls_ssl_handshake. + * We can add debug here. + */ +static int mbedtls_handshake( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + + while (ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER) { + ret = mbedtls_ssl_handshake_step(ssl); + + SSL_DEBUG(SSL_PLATFORM_DEBUG_LEVEL, "ssl ret %d state %d", ret, ssl->state); + + if (ret != 0) + break; + } + + return ret; +} + +int ssl_pm_handshake(SSL *ssl) +{ + int ret; + struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + + ret = ssl_pm_reload_crt(ssl); + if (ret) + return 0; + + ssl_speed_up_enter(); + + while((ret = mbedtls_handshake(&ssl_pm->ssl)) != 0) { + if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + break; + } + } + + ssl_speed_up_exit(); + + if (ret) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_handshake() return -0x%x", -ret); + ret = 0; + } else { + struct x509_pm *x509_pm = (struct x509_pm *)ssl->session->peer->x509_pm; + + x509_pm->ex_crt = (mbedtls_x509_crt *)mbedtls_ssl_get_peer_cert(&ssl_pm->ssl); + ret = 1; + } + + return ret; +} + +int ssl_pm_shutdown(SSL *ssl) +{ + int ret; + struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + + ret = mbedtls_ssl_close_notify(&ssl_pm->ssl); + if (ret) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_close_notify() return -0x%x", -ret); + ret = -1; + } else { + struct x509_pm *x509_pm = (struct x509_pm *)ssl->session->peer->x509_pm; + + x509_pm->ex_crt = NULL; + } + + return ret; +} + +int ssl_pm_clear(SSL *ssl) +{ + return ssl_pm_shutdown(ssl); +} + + +int ssl_pm_read(SSL *ssl, void *buffer, int len) +{ + int ret; + struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + + ret = mbedtls_ssl_read(&ssl_pm->ssl, buffer, len); + if (ret < 0) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_read() return -0x%x", -ret); + ret = -1; + } + + return ret; +} + +int ssl_pm_send(SSL *ssl, const void *buffer, int len) +{ + int ret; + struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + + ret = mbedtls_ssl_write(&ssl_pm->ssl, buffer, len); + if (ret < 0) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_write() return -0x%x", -ret); + ret = -1; + } + + return ret; +} + +int ssl_pm_pending(const SSL *ssl) +{ + struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + + return mbedtls_ssl_get_bytes_avail(&ssl_pm->ssl); +} + +void ssl_pm_set_fd(SSL *ssl, int fd, int mode) +{ + struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + + ssl_pm->fd.fd = fd; +} + +int ssl_pm_get_fd(const SSL *ssl, int mode) +{ + struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + + return ssl_pm->fd.fd; +} + +OSSL_HANDSHAKE_STATE ssl_pm_get_state(const SSL *ssl) +{ + OSSL_HANDSHAKE_STATE state; + + struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + + switch (ssl_pm->ssl.state) + { + case MBEDTLS_SSL_CLIENT_HELLO: + state = TLS_ST_CW_CLNT_HELLO; + break; + case MBEDTLS_SSL_SERVER_HELLO: + state = TLS_ST_SW_SRVR_HELLO; + break; + case MBEDTLS_SSL_SERVER_CERTIFICATE: + state = TLS_ST_SW_CERT; + break; + case MBEDTLS_SSL_SERVER_HELLO_DONE: + state = TLS_ST_SW_SRVR_DONE; + break; + case MBEDTLS_SSL_CLIENT_KEY_EXCHANGE: + state = TLS_ST_CW_KEY_EXCH; + break; + case MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC: + state = TLS_ST_CW_CHANGE; + break; + case MBEDTLS_SSL_CLIENT_FINISHED: + state = TLS_ST_CW_FINISHED; + break; + case MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC: + state = TLS_ST_SW_CHANGE; + break; + case MBEDTLS_SSL_SERVER_FINISHED: + state = TLS_ST_SW_FINISHED; + break; + case MBEDTLS_SSL_CLIENT_CERTIFICATE: + state = TLS_ST_CW_CERT; + break; + case MBEDTLS_SSL_SERVER_KEY_EXCHANGE: + state = TLS_ST_SR_KEY_EXCH; + break; + case MBEDTLS_SSL_SERVER_NEW_SESSION_TICKET: + state = TLS_ST_SW_SESSION_TICKET; + break; + case MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT: + state = TLS_ST_SW_CERT_REQ; + break; + case MBEDTLS_SSL_HANDSHAKE_OVER: + state = TLS_ST_OK; + break; + default : + state = TLS_ST_BEFORE; + break; + } + + return state; +} + +int x509_pm_show_info(X509 *x) +{ + int ret; + char *buf; + mbedtls_x509_crt *x509_crt; + struct x509_pm *x509_pm = x->x509_pm; + + if (x509_pm->x509_crt) + x509_crt = x509_pm->x509_crt; + else if (x509_pm->ex_crt) + x509_crt = x509_pm->ex_crt; + else + x509_crt = NULL; + + if (!x509_crt) + return -1; + + buf = ssl_mem_malloc(X509_INFO_STRING_LENGTH); + if (!buf) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (buf)"); + goto no_mem; + } + + ret = mbedtls_x509_crt_info(buf, X509_INFO_STRING_LENGTH - 1, "", x509_crt); + if (ret <= 0) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_x509_crt_info() return -0x%x", -ret); + goto mbedtls_err1; + } + + buf[ret] = 0; + + ssl_mem_free(buf); + + SSL_DEBUG(SSL_DEBUG_ON, "%s", buf); + + return 0; + +mbedtls_err1: + ssl_mem_free(buf); +no_mem: + return -1; +} + +int x509_pm_new(X509 *x, X509 *m_x) +{ + struct x509_pm *x509_pm; + + x509_pm = ssl_mem_zalloc(sizeof(struct x509_pm)); + if (!x509_pm) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (x509_pm)"); + goto failed1; + } + + x->x509_pm = x509_pm; + + if (m_x) { + struct x509_pm *m_x509_pm = (struct x509_pm *)m_x->x509_pm; + + x509_pm->ex_crt = m_x509_pm->x509_crt; + } + + return 0; + +failed1: + return -1; +} + +void x509_pm_free(X509 *x) +{ + struct x509_pm *x509_pm = (struct x509_pm *)x->x509_pm; + + if (x509_pm->x509_crt) { + mbedtls_x509_crt_free(x509_pm->x509_crt); + + ssl_mem_free(x509_pm->x509_crt); + x509_pm->x509_crt = NULL; + } + + ssl_mem_free(x->x509_pm); + x->x509_pm = NULL; +} + +int x509_pm_load(X509 *x, const unsigned char *buffer, int len) +{ + int ret; + unsigned char *load_buf; + struct x509_pm *x509_pm = (struct x509_pm *)x->x509_pm; + + if (x509_pm->x509_crt) + mbedtls_x509_crt_free(x509_pm->x509_crt); + + if (!x509_pm->x509_crt) { + x509_pm->x509_crt = ssl_mem_malloc(sizeof(mbedtls_x509_crt)); + if (!x509_pm->x509_crt) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (x509_pm->x509_crt)"); + goto no_mem; + } + } + + load_buf = ssl_mem_malloc(len + 1); + if (!load_buf) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (load_buf)"); + goto failed; + } + + ssl_memcpy(load_buf, buffer, len); + load_buf[len] = '\0'; + + mbedtls_x509_crt_init(x509_pm->x509_crt); + + ret = mbedtls_x509_crt_parse(x509_pm->x509_crt, load_buf, len + 1); + ssl_mem_free(load_buf); + + if (ret) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_x509_crt_parse return -0x%x", -ret); + goto failed; + } + + return 0; + +failed: + mbedtls_x509_crt_free(x509_pm->x509_crt); + ssl_mem_free(x509_pm->x509_crt); + x509_pm->x509_crt = NULL; +no_mem: + return -1; +} + +int pkey_pm_new(EVP_PKEY *pk, EVP_PKEY *m_pkey) +{ + struct pkey_pm *pkey_pm; + + pkey_pm = ssl_mem_zalloc(sizeof(struct pkey_pm)); + if (!pkey_pm) + return -1; + + pk->pkey_pm = pkey_pm; + + if (m_pkey) { + struct pkey_pm *m_pkey_pm = (struct pkey_pm *)m_pkey->pkey_pm; + + pkey_pm->ex_pkey = m_pkey_pm->pkey; + } + + return 0; +} + +void pkey_pm_free(EVP_PKEY *pk) +{ + struct pkey_pm *pkey_pm = (struct pkey_pm *)pk->pkey_pm; + + if (pkey_pm->pkey) { + mbedtls_pk_free(pkey_pm->pkey); + + ssl_mem_free(pkey_pm->pkey); + pkey_pm->pkey = NULL; + } + + ssl_mem_free(pk->pkey_pm); + pk->pkey_pm = NULL; +} + +int pkey_pm_load(EVP_PKEY *pk, const unsigned char *buffer, int len) +{ + int ret; + unsigned char *load_buf; + struct pkey_pm *pkey_pm = (struct pkey_pm *)pk->pkey_pm; + + if (pkey_pm->pkey) + mbedtls_pk_free(pkey_pm->pkey); + + if (!pkey_pm->pkey) { + pkey_pm->pkey = ssl_mem_malloc(sizeof(mbedtls_pk_context)); + if (!pkey_pm->pkey) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (pkey_pm->pkey)"); + goto no_mem; + } + } + + load_buf = ssl_mem_malloc(len + 1); + if (!load_buf) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (load_buf)"); + goto failed; + } + + ssl_memcpy(load_buf, buffer, len); + load_buf[len] = '\0'; + + mbedtls_pk_init(pkey_pm->pkey); + + ret = mbedtls_pk_parse_key(pkey_pm->pkey, load_buf, len + 1, NULL, 0); + ssl_mem_free(load_buf); + + if (ret) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_pk_parse_key return -0x%x", -ret); + goto failed; + } + + return 0; + +failed: + mbedtls_pk_free(pkey_pm->pkey); + ssl_mem_free(pkey_pm->pkey); + pkey_pm->pkey = NULL; +no_mem: + return -1; +} + + + +void ssl_pm_set_bufflen(SSL *ssl, int len) +{ + max_content_len = len; +} + +long ssl_pm_get_verify_result(const SSL *ssl) +{ + long ret; + long verify_result; + struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + + ret = mbedtls_ssl_get_verify_result(&ssl_pm->ssl); + if (ret) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_get_verify_result() return -0x%x", -ret); + verify_result = X509_V_ERR_UNSPECIFIED; + } else + verify_result = X509_V_OK; + + return verify_result; +} diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/spiffs/Makefile b/Distrib/ESPressif/RTOS/1.5.0/third_party/spiffs/Makefile new file mode 100644 index 0000000..9fe9201 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/spiffs/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 = libspiffs.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/Distrib/ESPressif/RTOS/1.5.0/third_party/spiffs/esp_spiffs.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/spiffs/esp_spiffs.c new file mode 100644 index 0000000..7778522 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/spiffs/esp_spiffs.c @@ -0,0 +1,292 @@ +#include "esp_common.h" + +#include +#include + +#define NUM_SYS_FD 3 + +static spiffs fs; + +static u8_t *spiffs_work_buf; +static u8_t *spiffs_fd_buf; +static u8_t *spiffs_cache_buf; + +#define FLASH_UNIT_SIZE 4 + +static s32_t esp_spiffs_readwrite(u32_t addr, u32_t size, u8_t *p, int write) +{ + /* + * With proper configurarion spiffs never reads or writes more than + * LOG_PAGE_SIZE + */ + + if (size > fs.cfg.log_page_size) { + printf("Invalid size provided to read/write (%d)\n\r", (int) size); + return SPIFFS_ERR_NOT_CONFIGURED; + } + + char tmp_buf[fs.cfg.log_page_size + FLASH_UNIT_SIZE * 2]; + u32_t aligned_addr = addr & (-FLASH_UNIT_SIZE); + u32_t aligned_size = + ((size + (FLASH_UNIT_SIZE - 1)) & -FLASH_UNIT_SIZE) + FLASH_UNIT_SIZE; + + int res = spi_flash_read(aligned_addr, (u32_t *) tmp_buf, aligned_size); + + if (res != 0) { + printf("spi_flash_read failed: %d (%d, %d)\n\r", res, (int) aligned_addr, + (int) aligned_size); + return res; + } + + if (!write) { + memcpy(p, tmp_buf + (addr - aligned_addr), size); + return SPIFFS_OK; + } + + memcpy(tmp_buf + (addr - aligned_addr), p, size); + + res = spi_flash_write(aligned_addr, (u32_t *) tmp_buf, aligned_size); + + if (res != 0) { +// printf("spi_flash_write failed: %d (%d, %d)\n\r", res, +// (int) aligned_addr, (int) aligned_size); + return res; + } + + return SPIFFS_OK; +} + +static s32_t esp_spiffs_read(u32_t addr, u32_t size, u8_t *dst) +{ + return esp_spiffs_readwrite(addr, size, dst, 0); +} + +static s32_t esp_spiffs_write(u32_t addr, u32_t size, u8_t *src) +{ + return esp_spiffs_readwrite(addr, size, src, 1); +} + +static s32_t esp_spiffs_erase(u32_t addr, u32_t size) +{ + /* + * With proper configurarion spiffs always + * provides here sector address & sector size + */ + if (size != fs.cfg.phys_erase_block || addr % fs.cfg.phys_erase_block != 0) { + printf("Invalid size provided to esp_spiffs_erase (%d, %d)\n\r", + (int) addr, (int) size); + return SPIFFS_ERR_NOT_CONFIGURED; + } + + return spi_flash_erase_sector(addr / fs.cfg.phys_erase_block); +} + +s32_t esp_spiffs_init(struct esp_spiffs_config *config) +{ + if (SPIFFS_mounted(&fs)) { + return -1; + } + + spiffs_config cfg; + s32_t ret; + + cfg.phys_size = config->phys_size; + cfg.phys_addr = config->phys_addr; + cfg.phys_erase_block = config->phys_erase_block; + cfg.log_block_size = config->log_block_size; + cfg.log_page_size = config->log_page_size; + + cfg.hal_read_f = esp_spiffs_read; + cfg.hal_write_f = esp_spiffs_write; + cfg.hal_erase_f = esp_spiffs_erase; + + if (spiffs_work_buf != NULL) { + free(spiffs_work_buf); + spiffs_work_buf = NULL; + } + spiffs_work_buf = malloc(config->log_page_size * 2); + + if (spiffs_work_buf == NULL) { + return -1; + } + + if (spiffs_fd_buf != NULL) { + free(spiffs_fd_buf); + spiffs_fd_buf = NULL; + } + spiffs_fd_buf = malloc(config->fd_buf_size); + + if (spiffs_fd_buf == NULL) { + free(spiffs_work_buf); + return -1; + } + + if (spiffs_cache_buf != NULL) { + free(spiffs_cache_buf); + spiffs_cache_buf = NULL; + } + spiffs_cache_buf = malloc(config->cache_buf_size); + + if (spiffs_cache_buf == NULL) { + free(spiffs_work_buf); + free(spiffs_fd_buf); + return -1; + } + + ret = SPIFFS_mount(&fs, &cfg, spiffs_work_buf, + spiffs_fd_buf, config->fd_buf_size, + spiffs_cache_buf, config->cache_buf_size, + 0); + + if (ret == -1) { + free(spiffs_work_buf); + free(spiffs_fd_buf); + free(spiffs_cache_buf); + } + + return ret; +} + +void esp_spiffs_deinit(u8_t format) +{ + if (SPIFFS_mounted(&fs)) { + SPIFFS_unmount(&fs); + free(spiffs_work_buf); + free(spiffs_fd_buf); + free(spiffs_cache_buf); + + if (format) { + SPIFFS_format(&fs); + } + } +} + +int _open_r(struct _reent *r, const char *filename, int flags, int mode) +{ + spiffs_mode sm = 0; + int res; + int rw = (flags & 3); + + if (rw == O_RDONLY || rw == O_RDWR) { + sm |= SPIFFS_RDONLY; + } + + if (rw == O_WRONLY || rw == O_RDWR) { + sm |= SPIFFS_WRONLY; + } + + if (flags & O_CREAT) { + sm |= SPIFFS_CREAT; + } + + if (flags & O_TRUNC) { + sm |= SPIFFS_TRUNC; + } + + if (flags & O_APPEND) { + sm |= SPIFFS_APPEND; + } + + /* Supported in newer versions of SPIFFS. */ + /* if (flags && O_EXCL) sm |= SPIFFS_EXCL; */ + /* if (flags && O_DIRECT) sm |= SPIFFS_DIRECT; */ + + res = SPIFFS_open(&fs, (char *) filename, sm, 0); + + if (res >= 0) { + res += NUM_SYS_FD; + } + + return res; +} + +_ssize_t _read_r(struct _reent *r, int fd, void *buf, size_t len) +{ + + ssize_t res; + + if (fd < NUM_SYS_FD) { + res = -1; + } else { + res = SPIFFS_read(&fs, fd - NUM_SYS_FD, buf, len); + } + + return res; +} + +_ssize_t _write_r(struct _reent *r, int fd, void *buf, size_t len) +{ + + if (fd < NUM_SYS_FD) { + return -1; + } + + int res = SPIFFS_write(&fs, fd - NUM_SYS_FD, (char *) buf, len); + return res; +} + +_off_t _lseek_r(struct _reent *r, int fd, _off_t where, int whence) +{ + + ssize_t res; + + if (fd < NUM_SYS_FD) { + res = -1; + } else { + res = SPIFFS_lseek(&fs, fd - NUM_SYS_FD, where, whence); + } + + return res; +} + +int _close_r(struct _reent *r, int fd) +{ + + if (fd < NUM_SYS_FD) { + return -1; + } + + SPIFFS_close(&fs, fd - NUM_SYS_FD); + return 0; +} + +int _rename_r(struct _reent *r, const char *from, const char *to) +{ + + int res = SPIFFS_rename(&fs, (char *) from, (char *) to); + return res; +} + +int _unlink_r(struct _reent *r, const char *filename) +{ + + int res = SPIFFS_remove(&fs, (char *) filename); + return res; +} + +int _fstat_r(struct _reent *r, int fd, struct stat *s) +{ + + int res; + spiffs_stat ss; + memset(s, 0, sizeof(*s)); + + if (fd < NUM_SYS_FD) { + s->st_ino = fd; + s->st_rdev = fd; + s->st_mode = S_IFCHR | 0666; + return 0; + } + + res = SPIFFS_fstat(&fs, fd - NUM_SYS_FD, &ss); + + if (res < 0) { + return res; + } + + s->st_ino = ss.obj_id; + s->st_mode = 0666; + s->st_nlink = 1; + s->st_size = ss.size; + return 0; +} diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/spiffs/spiffs_cache.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/spiffs/spiffs_cache.c new file mode 100644 index 0000000..4fde4d3 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/spiffs/spiffs_cache.c @@ -0,0 +1,303 @@ +/* + * spiffs_cache.c + * + * Created on: Jun 23, 2013 + * Author: petera + */ + +#include "spiffs.h" +#include "spiffs_nucleus.h" + +#if SPIFFS_CACHE + +// returns cached page for give page index, or null if no such cached page +static spiffs_cache_page *spiffs_cache_page_get(spiffs *fs, spiffs_page_ix pix) { + spiffs_cache *cache = spiffs_get_cache(fs); + if ((cache->cpage_use_map & cache->cpage_use_mask) == 0) return 0; + int i; + for (i = 0; i < cache->cpage_count; i++) { + spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i); + if ((cache->cpage_use_map & (1<flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 && + cp->pix == pix ) { + SPIFFS_CACHE_DBG("CACHE_GET: have cache page %i for %04x\n", i, pix); + cp->last_access = cache->last_access; + return cp; + } + } + //SPIFFS_CACHE_DBG("CACHE_GET: no cache for %04x\n", pix); + return 0; +} + +// frees cached page +static s32_t spiffs_cache_page_free(spiffs *fs, int ix, u8_t write_back) { + s32_t res = SPIFFS_OK; + spiffs_cache *cache = spiffs_get_cache(fs); + spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, ix); + if (cache->cpage_use_map & (1<flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 && + (cp->flags & SPIFFS_CACHE_FLAG_DIRTY)) { + u8_t *mem = spiffs_get_cache_page(fs, cache, ix); + res = fs->cfg.hal_write_f(SPIFFS_PAGE_TO_PADDR(fs, cp->pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), mem); + } + + cp->flags = 0; + cache->cpage_use_map &= ~(1 << ix); + + if (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) { + SPIFFS_CACHE_DBG("CACHE_FREE: free cache page %i objid %04x\n", ix, cp->obj_id); + } else { + SPIFFS_CACHE_DBG("CACHE_FREE: free cache page %i pix %04x\n", ix, cp->pix); + } + } + + return res; +} + +// removes the oldest accessed cached page +static s32_t spiffs_cache_page_remove_oldest(spiffs *fs, u8_t flag_mask, u8_t flags) { + s32_t res = SPIFFS_OK; + spiffs_cache *cache = spiffs_get_cache(fs); + + if ((cache->cpage_use_map & cache->cpage_use_mask) != cache->cpage_use_mask) { + // at least one free cpage + return SPIFFS_OK; + } + + // all busy, scan thru all to find the cpage which has oldest access + int i; + int cand_ix = -1; + u32_t oldest_val = 0; + for (i = 0; i < cache->cpage_count; i++) { + spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i); + if ((cache->last_access - cp->last_access) > oldest_val && + (cp->flags & flag_mask) == flags) { + oldest_val = cache->last_access - cp->last_access; + cand_ix = i; + } + } + + if (cand_ix >= 0) { + res = spiffs_cache_page_free(fs, cand_ix, 1); + } + + return res; +} + +// allocates a new cached page and returns it, or null if all cache pages are busy +static spiffs_cache_page *spiffs_cache_page_allocate(spiffs *fs) { + spiffs_cache *cache = spiffs_get_cache(fs); + if (cache->cpage_use_map == 0xffffffff) { + // out of cache memory + return 0; + } + int i; + for (i = 0; i < cache->cpage_count; i++) { + if ((cache->cpage_use_map & (1<cpage_use_map |= (1<last_access = cache->last_access; + SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page %i\n", i); + return cp; + } + } + // out of cache entries + return 0; +} + +// drops the cache page for give page index +void spiffs_cache_drop_page(spiffs *fs, spiffs_page_ix pix) { + spiffs_cache_page *cp = spiffs_cache_page_get(fs, pix); + if (cp) { + spiffs_cache_page_free(fs, cp->ix, 0); + } +} + +// ------------------------------ + +// reads from spi flash or the cache +s32_t spiffs_phys_rd( + spiffs *fs, + u8_t op, + spiffs_file fh, + u32_t addr, + u32_t len, + u8_t *dst) { + (void)fh; + s32_t res = SPIFFS_OK; + spiffs_cache *cache = spiffs_get_cache(fs); + spiffs_cache_page *cp = spiffs_cache_page_get(fs, SPIFFS_PADDR_TO_PAGE(fs, addr)); + cache->last_access++; + if (cp) { +#if SPIFFS_CACHE_STATS + fs->cache_hits++; +#endif + cp->last_access = cache->last_access; + } else { + if ((op & SPIFFS_OP_TYPE_MASK) == SPIFFS_OP_T_OBJ_LU2) { + // for second layer lookup functions, we do not cache in order to prevent shredding + return fs->cfg.hal_read_f( + addr , + len, + dst); + } +#if SPIFFS_CACHE_STATS + fs->cache_misses++; +#endif + res = spiffs_cache_page_remove_oldest(fs, SPIFFS_CACHE_FLAG_TYPE_WR, 0); + cp = spiffs_cache_page_allocate(fs); + if (cp) { + cp->flags = SPIFFS_CACHE_FLAG_WRTHRU; + cp->pix = SPIFFS_PADDR_TO_PAGE(fs, addr); + } + + s32_t res2 = fs->cfg.hal_read_f( + addr - SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr), + SPIFFS_CFG_LOG_PAGE_SZ(fs), + spiffs_get_cache_page(fs, cache, cp->ix)); + if (res2 != SPIFFS_OK) { + res = res2; + } + } + u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix); + memcpy(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len); + return res; +} + +// writes to spi flash and/or the cache +s32_t spiffs_phys_wr( + spiffs *fs, + u8_t op, + spiffs_file fh, + u32_t addr, + u32_t len, + u8_t *src) { + (void)fh; + spiffs_page_ix pix = SPIFFS_PADDR_TO_PAGE(fs, addr); + spiffs_cache *cache = spiffs_get_cache(fs); + spiffs_cache_page *cp = spiffs_cache_page_get(fs, pix); + + if (cp && (op & SPIFFS_OP_COM_MASK) != SPIFFS_OP_C_WRTHRU) { + // have a cache page + // copy in data to cache page + + if ((op & SPIFFS_OP_COM_MASK) == SPIFFS_OP_C_DELE && + (op & SPIFFS_OP_TYPE_MASK) != SPIFFS_OP_T_OBJ_LU) { + // page is being deleted, wipe from cache - unless it is a lookup page + spiffs_cache_page_free(fs, cp->ix, 0); + return fs->cfg.hal_write_f(addr, len, src); + } + + u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix); + memcpy(&mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], src, len); + + cache->last_access++; + cp->last_access = cache->last_access; + + if (cp->flags & SPIFFS_CACHE_FLAG_WRTHRU) { + // page is being updated, no write-cache, just pass thru + return fs->cfg.hal_write_f(addr, len, src); + } else { + return SPIFFS_OK; + } + } else { + // no cache page, no write cache - just write thru + return fs->cfg.hal_write_f(addr, len, src); + } +} + +#if SPIFFS_CACHE_WR +// returns the cache page that this fd refers, or null if no cache page +spiffs_cache_page *spiffs_cache_page_get_by_fd(spiffs *fs, spiffs_fd *fd) { + spiffs_cache *cache = spiffs_get_cache(fs); + + if ((cache->cpage_use_map & cache->cpage_use_mask) == 0) { + // all cpages free, no cpage cannot be assigned to obj_id + return 0; + } + + int i; + for (i = 0; i < cache->cpage_count; i++) { + spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i); + if ((cache->cpage_use_map & (1<flags & SPIFFS_CACHE_FLAG_TYPE_WR) && + cp->obj_id == fd->obj_id) { + return cp; + } + } + + return 0; +} + +// allocates a new cache page and refers this to given fd - flushes an old cache +// page if all cache is busy +spiffs_cache_page *spiffs_cache_page_allocate_by_fd(spiffs *fs, spiffs_fd *fd) { + // before this function is called, it is ensured that there is no already existing + // cache page with same object id + spiffs_cache_page_remove_oldest(fs, SPIFFS_CACHE_FLAG_TYPE_WR, 0); + spiffs_cache_page *cp = spiffs_cache_page_allocate(fs); + if (cp == 0) { + // could not get cache page + return 0; + } + + cp->flags = SPIFFS_CACHE_FLAG_TYPE_WR; + cp->obj_id = fd->obj_id; + fd->cache_page = cp; + return cp; +} + +// unrefers all fds that this cache page refers to and releases the cache page +void spiffs_cache_fd_release(spiffs *fs, spiffs_cache_page *cp) { + if (cp == 0) return; + u32_t i; + spiffs_fd *fds = (spiffs_fd *)fs->fd_space; + for (i = 0; i < fs->fd_count; i++) { + spiffs_fd *cur_fd = &fds[i]; + if (cur_fd->file_nbr != 0 && cur_fd->cache_page == cp) { + cur_fd->cache_page = 0; + } + } + spiffs_cache_page_free(fs, cp->ix, 0); + + cp->obj_id = 0; +} + +#endif + +// initializes the cache +void spiffs_cache_init(spiffs *fs) { + if (fs->cache == 0) return; + u32_t sz = fs->cache_size; + u32_t cache_mask = 0; + int i; + int cache_entries = + (sz - sizeof(spiffs_cache)) / (SPIFFS_CACHE_PAGE_SIZE(fs)); + if (cache_entries <= 0) return; + + for (i = 0; i < cache_entries; i++) { + cache_mask <<= 1; + cache_mask |= 1; + } + + spiffs_cache cache; + memset(&cache, 0, sizeof(spiffs_cache)); + cache.cpage_count = cache_entries; + cache.cpages = (u8_t *)((u8_t *)fs->cache + sizeof(spiffs_cache)); + + cache.cpage_use_map = 0xffffffff; + cache.cpage_use_mask = cache_mask; + memcpy(fs->cache, &cache, sizeof(spiffs_cache)); + + spiffs_cache *c = spiffs_get_cache(fs); + + memset(c->cpages, 0, c->cpage_count * SPIFFS_CACHE_PAGE_SIZE(fs)); + + c->cpage_use_map &= ~(c->cpage_use_mask); + for (i = 0; i < cache.cpage_count; i++) { + spiffs_get_cache_page_hdr(fs, c, i)->ix = i; + } +} + +#endif // SPIFFS_CACHE diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/spiffs/spiffs_check.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/spiffs/spiffs_check.c new file mode 100644 index 0000000..2180a2a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/spiffs/spiffs_check.c @@ -0,0 +1,973 @@ +/* + * spiffs_check.c + * + * Contains functionality for checking file system consistency + * and mending problems. + * Three levels of consistency checks are implemented: + * + * Look up consistency + * Checks if indices in lookup pages are coherent with page headers + * Object index consistency + * Checks if there are any orphaned object indices (missing object index headers). + * If an object index is found but not its header, the object index is deleted. + * This is critical for the following page consistency check. + * Page consistency + * Checks for pages that ought to be indexed, ought not to be indexed, are multiple indexed + * + * + * Created on: Jul 7, 2013 + * Author: petera + */ + +#include "spiffs.h" +#include "spiffs_nucleus.h" + +//--------------------------------------- +// Look up consistency + +// searches in the object indices and returns the referenced page index given +// the object id and the data span index +// destroys fs->lu_work +static s32_t spiffs_object_get_data_page_index_reference( + spiffs *fs, + spiffs_obj_id obj_id, + spiffs_span_ix data_spix, + spiffs_page_ix *pix, + spiffs_page_ix *objix_pix) { + s32_t res; + + // calculate object index span index for given data page span index + spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix); + + // find obj index for obj id and span index + res = spiffs_obj_lu_find_id_and_span(fs, obj_id | SPIFFS_OBJ_ID_IX_FLAG, objix_spix, 0, objix_pix); + SPIFFS_CHECK_RES(res); + + // load obj index entry + u32_t addr = SPIFFS_PAGE_TO_PADDR(fs, *objix_pix); + if (objix_spix == 0) { + // get referenced page from object index header + addr += sizeof(spiffs_page_object_ix_header) + data_spix * sizeof(spiffs_page_ix); + } else { + // get referenced page from object index + addr += sizeof(spiffs_page_object_ix) + SPIFFS_OBJ_IX_ENTRY(fs, data_spix) * sizeof(spiffs_page_ix); + } + + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, 0, addr, sizeof(spiffs_page_ix), (u8_t *)pix); + + return res; +} + +// copies page contents to a new page +static s32_t spiffs_rewrite_page(spiffs *fs, spiffs_page_ix cur_pix, spiffs_page_header *p_hdr, spiffs_page_ix *new_pix) { + s32_t res; + res = spiffs_page_allocate_data(fs, p_hdr->obj_id, p_hdr, 0,0,0,0, new_pix); + SPIFFS_CHECK_RES(res); + res = spiffs_phys_cpy(fs, 0, + SPIFFS_PAGE_TO_PADDR(fs, *new_pix) + sizeof(spiffs_page_header), + SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header), + SPIFFS_DATA_PAGE_SIZE(fs)); + SPIFFS_CHECK_RES(res); + return res; +} + +// rewrites the object index for given object id and replaces the +// data page index to a new page index +static s32_t spiffs_rewrite_index(spiffs *fs, spiffs_obj_id obj_id, spiffs_span_ix data_spix, spiffs_page_ix new_data_pix, spiffs_page_ix objix_pix) { + s32_t res; + spiffs_block_ix bix; + int entry; + spiffs_page_ix free_pix; + obj_id |= SPIFFS_OBJ_ID_IX_FLAG; + + // find free entry + res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry); + SPIFFS_CHECK_RES(res); + free_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry); + + // calculate object index span index for given data page span index + spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix); + if (objix_spix == 0) { + // calc index in index header + entry = data_spix; + } else { + // calc entry in index + entry = SPIFFS_OBJ_IX_ENTRY(fs, data_spix); + } + // load index + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); + SPIFFS_CHECK_RES(res); + spiffs_page_header *objix_p_hdr = (spiffs_page_header *)fs->lu_work; + + // be ultra safe, double check header against provided data + if (objix_p_hdr->obj_id != obj_id) { + spiffs_page_delete(fs, free_pix); + return SPIFFS_ERR_CHECK_OBJ_ID_MISM; + } + if (objix_p_hdr->span_ix != objix_spix) { + spiffs_page_delete(fs, free_pix); + return SPIFFS_ERR_CHECK_SPIX_MISM; + } + if ((objix_p_hdr->flags & (SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_IXDELE | SPIFFS_PH_FLAG_INDEX | + SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET)) != + (SPIFFS_PH_FLAG_IXDELE | SPIFFS_PH_FLAG_DELET)) { + spiffs_page_delete(fs, free_pix); + return SPIFFS_ERR_CHECK_FLAGS_BAD; + } + + // rewrite in mem + if (objix_spix == 0) { + ((spiffs_page_ix*)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix_header)))[data_spix] = new_data_pix; + } else { + ((spiffs_page_ix*)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = new_data_pix; + } + + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT, + 0, SPIFFS_PAGE_TO_PADDR(fs, free_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); + SPIFFS_CHECK_RES(res); + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT, + 0, SPIFFS_BLOCK_TO_PADDR(fs, SPIFFS_BLOCK_FOR_PAGE(fs, free_pix)) + SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, free_pix) * sizeof(spiffs_page_ix), + sizeof(spiffs_obj_id), + (u8_t *)&obj_id); + SPIFFS_CHECK_RES(res); + res = spiffs_page_delete(fs, objix_pix); + + return res; +} + +// deletes an object just by marking object index header as deleted +static s32_t spiffs_delete_obj_lazy(spiffs *fs, spiffs_obj_id obj_id) { + spiffs_page_ix objix_hdr_pix; + s32_t res; + res = spiffs_obj_lu_find_id_and_span(fs, obj_id, 0, 0, &objix_hdr_pix); + if (res == SPIFFS_ERR_NOT_FOUND) { + return SPIFFS_OK; + } + SPIFFS_CHECK_RES(res); + u8_t flags = 0xff & ~SPIFFS_PH_FLAG_IXDELE; + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT, + 0, SPIFFS_PAGE_TO_PADDR(fs, objix_hdr_pix) + offsetof(spiffs_page_header, flags), + sizeof(u8_t), + (u8_t *)&flags); + return res; +} + +// validates the given look up entry +static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, spiffs_page_header *p_hdr, + spiffs_page_ix cur_pix, spiffs_block_ix cur_block, int cur_entry, int *reload_lu) { + (void)cur_block; + (void)cur_entry; + u8_t delete_page = 0; + s32_t res = SPIFFS_OK; + spiffs_page_ix objix_pix; + spiffs_page_ix ref_pix; + // check validity, take actions + if (((lu_obj_id == SPIFFS_OBJ_ID_DELETED) && (p_hdr->flags & SPIFFS_PH_FLAG_DELET)) || + ((lu_obj_id == SPIFFS_OBJ_ID_FREE) && (p_hdr->flags & SPIFFS_PH_FLAG_USED) == 0)) { + // look up entry deleted / free but used in page header + SPIFFS_CHECK_DBG("LU: pix %04x deleted/free in lu but not on page\n", cur_pix); + *reload_lu = 1; + delete_page = 1; + if (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) { + // header says data page + // data page can be removed if not referenced by some object index + res = spiffs_object_get_data_page_index_reference(fs, p_hdr->obj_id, p_hdr->span_ix, &ref_pix, &objix_pix); + if (res == SPIFFS_ERR_NOT_FOUND) { + // no object with this id, so remove page safely + res = SPIFFS_OK; + } else { + SPIFFS_CHECK_RES(res); + if (ref_pix == cur_pix) { + // data page referenced by object index but deleted in lu + // copy page to new place and re-write the object index to new place + spiffs_page_ix new_pix; + res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix); + SPIFFS_CHECK_DBG("LU: FIXUP: data page not found elsewhere, rewriting %04x to new page %04x\n", cur_pix, new_pix); + SPIFFS_CHECK_RES(res); + *reload_lu = 1; + SPIFFS_CHECK_DBG("LU: FIXUP: %04x rewritten to %04x, affected objix_pix %04x\n", cur_pix, new_pix, objix_pix); + res = spiffs_rewrite_index(fs, p_hdr->obj_id, p_hdr->span_ix, new_pix, objix_pix); + if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) { + // index bad also, cannot mend this file + SPIFFS_CHECK_DBG("LU: FIXUP: index bad %i, cannot mend!\n", res); + res = spiffs_page_delete(fs, new_pix); + SPIFFS_CHECK_RES(res); + res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id); + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0); + } else { + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, p_hdr->obj_id, p_hdr->span_ix); + } + SPIFFS_CHECK_RES(res); + } + } + } else { + // header says index page + // index page can be removed if other index with same obj_id and spanix is found + res = spiffs_obj_lu_find_id_and_span(fs, p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, cur_pix, 0); + if (res == SPIFFS_ERR_NOT_FOUND) { + // no such index page found, check for a data page amongst page headers + // lu cannot be trusted + res = spiffs_obj_lu_find_id_and_span_by_phdr(fs, p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, 0); + if (res == SPIFFS_OK) { // ignore other errors + // got a data page also, assume lu corruption only, rewrite to new page + spiffs_page_ix new_pix; + res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix); + SPIFFS_CHECK_DBG("LU: FIXUP: ix page with data not found elsewhere, rewriting %04x to new page %04x\n", cur_pix, new_pix); + SPIFFS_CHECK_RES(res); + *reload_lu = 1; + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix); + } + } else { + SPIFFS_CHECK_RES(res); + } + } + } + if (lu_obj_id != SPIFFS_OBJ_ID_FREE && lu_obj_id != SPIFFS_OBJ_ID_DELETED) { + // look up entry used + if ((p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG) != (lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG)) { + SPIFFS_CHECK_DBG("LU: pix %04x differ in obj_id lu:%04x ph:%04x\n", cur_pix, lu_obj_id, p_hdr->obj_id); + delete_page = 1; + if ((p_hdr->flags & SPIFFS_PH_FLAG_DELET) == 0 || + (p_hdr->flags & SPIFFS_PH_FLAG_FINAL) || + (p_hdr->flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_IXDELE)) == 0) { + // page deleted or not finalized, just remove it + } else { + if (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) { + // if data page, check for reference to this page + res = spiffs_object_get_data_page_index_reference(fs, p_hdr->obj_id, p_hdr->span_ix, &ref_pix, &objix_pix); + if (res == SPIFFS_ERR_NOT_FOUND) { + // no object with this id, so remove page safely + res = SPIFFS_OK; + } else { + SPIFFS_CHECK_RES(res); + // if found, rewrite page with object id, update index, and delete current + if (ref_pix == cur_pix) { + spiffs_page_ix new_pix; + res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix); + SPIFFS_CHECK_RES(res); + res = spiffs_rewrite_index(fs, p_hdr->obj_id, p_hdr->span_ix, new_pix, objix_pix); + if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) { + // index bad also, cannot mend this file + SPIFFS_CHECK_DBG("LU: FIXUP: index bad %i, cannot mend!\n", res); + res = spiffs_page_delete(fs, new_pix); + SPIFFS_CHECK_RES(res); + res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id); + *reload_lu = 1; + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0); + } + SPIFFS_CHECK_RES(res); + } + } + } else { + // else if index, check for other pages with both obj_id's and spanix + spiffs_page_ix objix_pix_lu, objix_pix_ph; + // see if other object index page exists for lookup obj id and span index + res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, 0, &objix_pix_lu); + if (res == SPIFFS_ERR_NOT_FOUND) { + res = SPIFFS_OK; + objix_pix_lu = 0; + } + SPIFFS_CHECK_RES(res); + // see if other object index exists for page header obj id and span index + res = spiffs_obj_lu_find_id_and_span(fs, p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, 0, &objix_pix_ph); + if (res == SPIFFS_ERR_NOT_FOUND) { + res = SPIFFS_OK; + objix_pix_ph = 0; + } + SPIFFS_CHECK_RES(res); + // if both obj_id's found, just delete current + if (objix_pix_ph == 0 || objix_pix_lu == 0) { + // otherwise try finding first corresponding data pages + spiffs_page_ix data_pix_lu, data_pix_ph; + // see if other data page exists for look up obj id and span index + res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &data_pix_lu); + if (res == SPIFFS_ERR_NOT_FOUND) { + res = SPIFFS_OK; + objix_pix_lu = 0; + } + SPIFFS_CHECK_RES(res); + // see if other data page exists for page header obj id and span index + res = spiffs_obj_lu_find_id_and_span(fs, p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &data_pix_ph); + if (res == SPIFFS_ERR_NOT_FOUND) { + res = SPIFFS_OK; + objix_pix_ph = 0; + } + SPIFFS_CHECK_RES(res); + + spiffs_page_header new_ph; + new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL); + new_ph.span_ix = p_hdr->span_ix; + spiffs_page_ix new_pix; + if ((objix_pix_lu && data_pix_lu && data_pix_ph && objix_pix_ph == 0) || + (objix_pix_lu == 0 && data_pix_ph && objix_pix_ph == 0)) { + // got a data page for page header obj id + // rewrite as obj_id_ph + new_ph.obj_id = p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG; + res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix); + SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page %04x as %04x to pix %04x\n", cur_pix, new_ph.obj_id, new_pix); + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix); + SPIFFS_CHECK_RES(res); + *reload_lu = 1; + } else if ((objix_pix_ph && data_pix_ph && data_pix_lu && objix_pix_lu == 0) || + (objix_pix_ph == 0 && data_pix_lu && objix_pix_lu == 0)) { + // got a data page for look up obj id + // rewrite as obj_id_lu + new_ph.obj_id = lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG; + SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page %04x as %04x\n", cur_pix, new_ph.obj_id); + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix); + res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix); + SPIFFS_CHECK_RES(res); + *reload_lu = 1; + } else { + // cannot safely do anything + SPIFFS_CHECK_DBG("LU: FIXUP: nothing to do, just delete\n"); + } + } + } + } + } else if (((lu_obj_id & SPIFFS_OBJ_ID_IX_FLAG) && (p_hdr->flags & SPIFFS_PH_FLAG_INDEX)) || + ((lu_obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0 && (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) == 0)) { + SPIFFS_CHECK_DBG("LU: %04x lu/page index marking differ\n", cur_pix); + spiffs_page_ix data_pix, objix_pix_d; + // see if other data page exists for given obj id and span index + res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, cur_pix, &data_pix); + if (res == SPIFFS_ERR_NOT_FOUND) { + res = SPIFFS_OK; + data_pix = 0; + } + SPIFFS_CHECK_RES(res); + // see if other object index exists for given obj id and span index + res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, cur_pix, &objix_pix_d); + if (res == SPIFFS_ERR_NOT_FOUND) { + res = SPIFFS_OK; + objix_pix_d = 0; + } + SPIFFS_CHECK_RES(res); + + delete_page = 1; + // if other data page exists and object index exists, just delete page + if (data_pix && objix_pix_d) { + SPIFFS_CHECK_DBG("LU: FIXUP: other index and data page exists, simply remove\n"); + } else + // if only data page exists, make this page index + if (data_pix && objix_pix_d == 0) { + SPIFFS_CHECK_DBG("LU: FIXUP: other data page exists, make this index\n"); + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, lu_obj_id, p_hdr->span_ix); + spiffs_page_header new_ph; + spiffs_page_ix new_pix; + new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX); + new_ph.obj_id = lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG; + new_ph.span_ix = p_hdr->span_ix; + res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &new_pix); + SPIFFS_CHECK_RES(res); + res = spiffs_phys_cpy(fs, 0, SPIFFS_PAGE_TO_PADDR(fs, new_pix) + sizeof(spiffs_page_header), + SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header), + SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header)); + SPIFFS_CHECK_RES(res); + } else + // if only index exists, make data page + if (data_pix == 0 && objix_pix_d) { + SPIFFS_CHECK_DBG("LU: FIXUP: other index page exists, make this data\n"); + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, lu_obj_id, p_hdr->span_ix); + spiffs_page_header new_ph; + spiffs_page_ix new_pix; + new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL); + new_ph.obj_id = lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG; + new_ph.span_ix = p_hdr->span_ix; + res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &new_pix); + SPIFFS_CHECK_RES(res); + res = spiffs_phys_cpy(fs, 0, SPIFFS_PAGE_TO_PADDR(fs, new_pix) + sizeof(spiffs_page_header), + SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header), + SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header)); + SPIFFS_CHECK_RES(res); + } else { + // if nothing exists, we cannot safely make a decision - delete + } + } + else if ((p_hdr->flags & SPIFFS_PH_FLAG_DELET) == 0) { + SPIFFS_CHECK_DBG("LU: pix %04x busy in lu but deleted on page\n", cur_pix); + delete_page = 1; + } else if ((p_hdr->flags & SPIFFS_PH_FLAG_FINAL)) { + SPIFFS_CHECK_DBG("LU: pix %04x busy but not final\n", cur_pix); + // page can be removed if not referenced by object index + *reload_lu = 1; + res = spiffs_object_get_data_page_index_reference(fs, lu_obj_id, p_hdr->span_ix, &ref_pix, &objix_pix); + if (res == SPIFFS_ERR_NOT_FOUND) { + // no object with this id, so remove page safely + res = SPIFFS_OK; + delete_page = 1; + } else { + SPIFFS_CHECK_RES(res); + if (ref_pix != cur_pix) { + SPIFFS_CHECK_DBG("LU: FIXUP: other finalized page is referred, just delete\n"); + delete_page = 1; + } else { + // page referenced by object index but not final + // just finalize + SPIFFS_CHECK_DBG("LU: FIXUP: unfinalized page is referred, finalizing\n"); + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix); + u8_t flags = 0xff & ~SPIFFS_PH_FLAG_FINAL; + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT, + 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + offsetof(spiffs_page_header, flags), + sizeof(u8_t), (u8_t*)&flags); + } + } + } + } + + if (delete_page) { + SPIFFS_CHECK_DBG("LU: FIXUP: deleting page %04x\n", cur_pix); + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0); + res = spiffs_page_delete(fs, cur_pix); + SPIFFS_CHECK_RES(res); + } + + return res; +} + +static s32_t spiffs_lookup_check_v(spiffs *fs, spiffs_obj_id obj_id, spiffs_block_ix cur_block, int cur_entry, + u32_t user_data, void *user_p) { + (void)user_data; + (void)user_p; + s32_t res = SPIFFS_OK; + spiffs_page_header p_hdr; + spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, cur_block, cur_entry); + + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, + (cur_block * 256)/fs->block_count, 0); + + // load header + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr); + SPIFFS_CHECK_RES(res); + + int reload_lu = 0; + + res = spiffs_lookup_check_validate(fs, obj_id, &p_hdr, cur_pix, cur_block, cur_entry, &reload_lu); + SPIFFS_CHECK_RES(res); + + if (res == SPIFFS_OK) { + return reload_lu ? SPIFFS_VIS_COUNTINUE_RELOAD : SPIFFS_VIS_COUNTINUE; + } + return res; +} + + +// Scans all object look up. For each entry, corresponding page header is checked for validity. +// If an object index header page is found, this is also checked +s32_t spiffs_lookup_consistency_check(spiffs *fs, u8_t check_all_objects) { + (void)check_all_objects; + s32_t res = SPIFFS_OK; + + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 0, 0); + + res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_lookup_check_v, 0, 0, 0, 0); + + if (res == SPIFFS_VIS_END) { + res = SPIFFS_OK; + } + + if (res != SPIFFS_OK) { + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_ERROR, res, 0); + } + + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 256, 0); + + return res; +} + +//--------------------------------------- +// Page consistency + +// Scans all pages (except lu pages), reserves 4 bits in working memory for each page +// bit 0: 0 == FREE|DELETED, 1 == USED +// bit 1: 0 == UNREFERENCED, 1 == REFERENCED +// bit 2: 0 == NOT_INDEX, 1 == INDEX +// bit 3: unused +// A consistent file system will have only pages being +// * x000 free, unreferenced, not index +// * x011 used, referenced only once, not index +// * x101 used, unreferenced, index +// The working memory might not fit all pages so several scans might be needed +static s32_t spiffs_page_consistency_check_i(spiffs *fs) { + const u32_t bits = 4; + const spiffs_page_ix pages_per_scan = SPIFFS_CFG_LOG_PAGE_SZ(fs) * 8 / bits; + + s32_t res = SPIFFS_OK; + spiffs_page_ix pix_offset = 0; + + // for each range of pages fitting into work memory + while (pix_offset < SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count) { + // set this flag to abort all checks and rescan the page range + u8_t restart = 0; + memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs)); + + spiffs_block_ix cur_block = 0; + // build consistency bitmap for id range traversing all blocks + while (!restart && cur_block < fs->block_count) { + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, + (pix_offset*256)/(SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count) + + ((((cur_block * pages_per_scan * 256)/ (SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count))) / fs->block_count), + 0); + + // traverse each page except for lookup pages + spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_PAGES(fs) + SPIFFS_PAGES_PER_BLOCK(fs) * cur_block; + while (!restart && cur_pix < SPIFFS_PAGES_PER_BLOCK(fs) * (cur_block+1)) { + // read header + spiffs_page_header p_hdr; + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr); + SPIFFS_CHECK_RES(res); + + u8_t within_range = (cur_pix >= pix_offset && cur_pix < pix_offset + pages_per_scan); + const u32_t pix_byte_ix = (cur_pix - pix_offset) / (8/bits); + const u8_t pix_bit_ix = (cur_pix & ((8/bits)-1)) * bits; + + if (within_range && + (p_hdr.flags & SPIFFS_PH_FLAG_DELET) && (p_hdr.flags & SPIFFS_PH_FLAG_USED) == 0) { + // used + fs->work[pix_byte_ix] |= (1<<(pix_bit_ix + 0)); + } + if ((p_hdr.flags & SPIFFS_PH_FLAG_DELET) && + (p_hdr.flags & SPIFFS_PH_FLAG_IXDELE) && + (p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED)) == 0) { + // found non-deleted index + if (within_range) { + fs->work[pix_byte_ix] |= (1<<(pix_bit_ix + 2)); + } + + // load non-deleted index + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); + SPIFFS_CHECK_RES(res); + + // traverse index for referenced pages + spiffs_page_ix *object_page_index; + spiffs_page_header *objix_p_hdr = (spiffs_page_header *)fs->lu_work; + + int entries; + int i; + spiffs_span_ix data_spix_offset; + if (p_hdr.span_ix == 0) { + // object header page index + entries = SPIFFS_OBJ_HDR_IX_LEN(fs); + data_spix_offset = 0; + object_page_index = (spiffs_page_ix *)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix_header)); + } else { + // object page index + entries = SPIFFS_OBJ_IX_LEN(fs); + data_spix_offset = SPIFFS_OBJ_HDR_IX_LEN(fs) + SPIFFS_OBJ_IX_LEN(fs) * (p_hdr.span_ix - 1); + object_page_index = (spiffs_page_ix *)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix)); + } + + // for all entries in index + for (i = 0; !restart && i < entries; i++) { + spiffs_page_ix rpix = object_page_index[i]; + u8_t rpix_within_range = rpix >= pix_offset && rpix < pix_offset + pages_per_scan; + + if ((rpix != (spiffs_page_ix)-1 && rpix > SPIFFS_MAX_PAGES(fs)) + || (rpix_within_range && SPIFFS_IS_LOOKUP_PAGE(fs, rpix))) { + + // bad reference + SPIFFS_CHECK_DBG("PA: pix %04x bad pix / LU referenced from page %04x\n", + rpix, cur_pix); + // check for data page elsewhere + spiffs_page_ix data_pix; + res = spiffs_obj_lu_find_id_and_span(fs, objix_p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, + data_spix_offset + i, 0, &data_pix); + if (res == SPIFFS_ERR_NOT_FOUND) { + res = SPIFFS_OK; + data_pix = 0; + } + SPIFFS_CHECK_RES(res); + if (data_pix == 0) { + // if not, allocate free page + spiffs_page_header new_ph; + new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL); + new_ph.obj_id = objix_p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG; + new_ph.span_ix = data_spix_offset + i; + res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &data_pix); + SPIFFS_CHECK_RES(res); + SPIFFS_CHECK_DBG("PA: FIXUP: found no existing data page, created new @ %04x\n", data_pix); + } + // remap index + SPIFFS_CHECK_DBG("PA: FIXUP: rewriting index pix %04x\n", cur_pix); + res = spiffs_rewrite_index(fs, objix_p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, + data_spix_offset + i, data_pix, cur_pix); + if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) { + // index bad also, cannot mend this file + SPIFFS_CHECK_DBG("PA: FIXUP: index bad %i, cannot mend - delete object\n", res); + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, objix_p_hdr->obj_id, 0); + // delete file + res = spiffs_page_delete(fs, cur_pix); + } else { + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, objix_p_hdr->obj_id, objix_p_hdr->span_ix); + } + SPIFFS_CHECK_RES(res); + restart = 1; + + } else if (rpix_within_range) { + + // valid reference + // read referenced page header + spiffs_page_header rp_hdr; + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, rpix), sizeof(spiffs_page_header), (u8_t*)&rp_hdr); + SPIFFS_CHECK_RES(res); + + // cross reference page header check + if (rp_hdr.obj_id != (p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) || + rp_hdr.span_ix != data_spix_offset + i || + (rp_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED)) != + (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_INDEX)) { + SPIFFS_CHECK_DBG("PA: pix %04x has inconsistent page header ix id/span:%04x/%04x, ref id/span:%04x/%04x flags:%02x\n", + rpix, p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, data_spix_offset + i, + rp_hdr.obj_id, rp_hdr.span_ix, rp_hdr.flags); + // try finding correct page + spiffs_page_ix data_pix; + res = spiffs_obj_lu_find_id_and_span(fs, p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, + data_spix_offset + i, rpix, &data_pix); + if (res == SPIFFS_ERR_NOT_FOUND) { + res = SPIFFS_OK; + data_pix = 0; + } + SPIFFS_CHECK_RES(res); + if (data_pix == 0) { + // not found, this index is badly borked + SPIFFS_CHECK_DBG("PA: FIXUP: index bad, delete object id %04x\n", p_hdr.obj_id); + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0); + res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id); + SPIFFS_CHECK_RES(res); + break; + } else { + // found it, so rewrite index + SPIFFS_CHECK_DBG("PA: FIXUP: found correct data pix %04x, rewrite ix pix %04x id %04x\n", + data_pix, cur_pix, p_hdr.obj_id); + res = spiffs_rewrite_index(fs, p_hdr.obj_id, data_spix_offset + i, data_pix, cur_pix); + if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) { + // index bad also, cannot mend this file + SPIFFS_CHECK_DBG("PA: FIXUP: index bad %i, cannot mend!\n", res); + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0); + res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id); + } else { + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix); + } + SPIFFS_CHECK_RES(res); + restart = 1; + } + } + else { + // mark rpix as referenced + const u32_t rpix_byte_ix = (rpix - pix_offset) / (8/bits); + const u8_t rpix_bit_ix = (rpix & ((8/bits)-1)) * bits; + if (fs->work[rpix_byte_ix] & (1<<(rpix_bit_ix + 1))) { + SPIFFS_CHECK_DBG("PA: pix %04x multiple referenced from page %04x\n", + rpix, cur_pix); + // Here, we should have fixed all broken references - getting this means there + // must be multiple files with same object id. Only solution is to delete + // the object which is referring to this page + SPIFFS_CHECK_DBG("PA: FIXUP: removing object %04x and page %04x\n", + p_hdr.obj_id, cur_pix); + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0); + res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id); + SPIFFS_CHECK_RES(res); + // extra precaution, delete this page also + res = spiffs_page_delete(fs, cur_pix); + SPIFFS_CHECK_RES(res); + restart = 1; + } + fs->work[rpix_byte_ix] |= (1<<(rpix_bit_ix + 1)); + } + } + } // for all index entries + } // found index + + // next page + cur_pix++; + } + // next block + cur_block++; + } + // check consistency bitmap + if (!restart) { + spiffs_page_ix objix_pix; + spiffs_page_ix rpix; + + u32_t byte_ix; + u8_t bit_ix; + for (byte_ix = 0; !restart && byte_ix < SPIFFS_CFG_LOG_PAGE_SZ(fs); byte_ix++) { + for (bit_ix = 0; !restart && bit_ix < 8/bits; bit_ix ++) { + u8_t bitmask = (fs->work[byte_ix] >> (bit_ix * bits)) & 0x7; + spiffs_page_ix cur_pix = pix_offset + byte_ix * (8/bits) + bit_ix; + + // 000 ok - free, unreferenced, not index + + if (bitmask == 0x1) { + + // 001 + SPIFFS_CHECK_DBG("PA: pix %04x USED, UNREFERENCED, not index\n", cur_pix); + + u8_t rewrite_ix_to_this = 0; + u8_t delete_page = 0; + // check corresponding object index entry + spiffs_page_header p_hdr; + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr); + SPIFFS_CHECK_RES(res); + + res = spiffs_object_get_data_page_index_reference(fs, p_hdr.obj_id, p_hdr.span_ix, + &rpix, &objix_pix); + if (res == SPIFFS_OK) { + if (((rpix == (spiffs_page_ix)-1 || rpix > SPIFFS_MAX_PAGES(fs)) || (SPIFFS_IS_LOOKUP_PAGE(fs, rpix)))) { + // pointing to a bad page altogether, rewrite index to this + rewrite_ix_to_this = 1; + SPIFFS_CHECK_DBG("PA: corresponding ref is bad: %04x, rewrite to this %04x\n", rpix, cur_pix); + } else { + // pointing to something else, check what + spiffs_page_header rp_hdr; + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, rpix), sizeof(spiffs_page_header), (u8_t*)&rp_hdr); + SPIFFS_CHECK_RES(res); + if (((p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) == rp_hdr.obj_id) && + ((rp_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL)) == + (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_DELET))) { + // pointing to something else valid, just delete this page then + SPIFFS_CHECK_DBG("PA: corresponding ref is good but different: %04x, delete this %04x\n", rpix, cur_pix); + delete_page = 1; + } else { + // pointing to something weird, update index to point to this page instead + if (rpix != cur_pix) { + SPIFFS_CHECK_DBG("PA: corresponding ref is weird: %04x %s%s%s%s, rewrite this %04x\n", rpix, + (rp_hdr.flags & SPIFFS_PH_FLAG_INDEX) ? "" : "INDEX ", + (rp_hdr.flags & SPIFFS_PH_FLAG_DELET) ? "" : "DELETED ", + (rp_hdr.flags & SPIFFS_PH_FLAG_USED) ? "NOTUSED " : "", + (rp_hdr.flags & SPIFFS_PH_FLAG_FINAL) ? "NOTFINAL " : "", + cur_pix); + rewrite_ix_to_this = 1; + } else { + // should not happen, destined for fubar + } + } + } + } else if (res == SPIFFS_ERR_NOT_FOUND) { + SPIFFS_CHECK_DBG("PA: corresponding ref not found, delete %04x\n", cur_pix); + delete_page = 1; + res = SPIFFS_OK; + } + + if (rewrite_ix_to_this) { + // if pointing to invalid page, redirect index to this page + SPIFFS_CHECK_DBG("PA: FIXUP: rewrite index id %04x data spix %04x to point to this pix: %04x\n", + p_hdr.obj_id, p_hdr.span_ix, cur_pix); + res = spiffs_rewrite_index(fs, p_hdr.obj_id, p_hdr.span_ix, cur_pix, objix_pix); + if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) { + // index bad also, cannot mend this file + SPIFFS_CHECK_DBG("PA: FIXUP: index bad %i, cannot mend!\n", res); + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0); + res = spiffs_page_delete(fs, cur_pix); + SPIFFS_CHECK_RES(res); + res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id); + } else { + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix); + } + SPIFFS_CHECK_RES(res); + restart = 1; + continue; + } else if (delete_page) { + SPIFFS_CHECK_DBG("PA: FIXUP: deleting page %04x\n", cur_pix); + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0); + res = spiffs_page_delete(fs, cur_pix); + } + SPIFFS_CHECK_RES(res); + } + if (bitmask == 0x2) { + + // 010 + SPIFFS_CHECK_DBG("PA: pix %04x FREE, REFERENCED, not index\n", cur_pix); + + // no op, this should be taken care of when checking valid references + } + + // 011 ok - busy, referenced, not index + + if (bitmask == 0x4) { + + // 100 + SPIFFS_CHECK_DBG("PA: pix %04x FREE, unreferenced, INDEX\n", cur_pix); + + // this should never happen, major fubar + } + + // 101 ok - busy, unreferenced, index + + if (bitmask == 0x6) { + + // 110 + SPIFFS_CHECK_DBG("PA: pix %04x FREE, REFERENCED, INDEX\n", cur_pix); + + // no op, this should be taken care of when checking valid references + } + if (bitmask == 0x7) { + + // 111 + SPIFFS_CHECK_DBG("PA: pix %04x USED, REFERENCED, INDEX\n", cur_pix); + + // no op, this should be taken care of when checking valid references + } + } + } + } + // next page range + if (!restart) { + pix_offset += pages_per_scan; + } + } // while page range not reached end + return res; +} + +// Checks consistency amongst all pages and fixes irregularities +s32_t spiffs_page_consistency_check(spiffs *fs) { + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 0, 0); + s32_t res = spiffs_page_consistency_check_i(fs); + if (res != SPIFFS_OK) { + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_ERROR, res, 0); + } + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 256, 0); + return res; +} + +//--------------------------------------- +// Object index consistency + +// searches for given object id in temporary object id index, +// returns the index or -1 +static int spiffs_object_index_search(spiffs *fs, spiffs_obj_id obj_id) { + u32_t i; + spiffs_obj_id *obj_table = (spiffs_obj_id *)fs->work; + obj_id &= ~SPIFFS_OBJ_ID_IX_FLAG; + for (i = 0; i < SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id); i++) { + if ((obj_table[i] & ~SPIFFS_OBJ_ID_IX_FLAG) == obj_id) { + return i; + } + } + return -1; +} + +static s32_t spiffs_object_index_consistency_check_v(spiffs *fs, spiffs_obj_id obj_id, spiffs_block_ix cur_block, + int cur_entry, u32_t user_data, void *user_p) { + (void)user_data; + s32_t res_c = SPIFFS_VIS_COUNTINUE; + s32_t res = SPIFFS_OK; + u32_t *log_ix = (u32_t *)user_p; + spiffs_obj_id *obj_table = (spiffs_obj_id *)fs->work; + + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, + (cur_block * 256)/fs->block_count, 0); + + if (obj_id != SPIFFS_OBJ_ID_FREE && obj_id != SPIFFS_OBJ_ID_DELETED && (obj_id & SPIFFS_OBJ_ID_IX_FLAG)) { + spiffs_page_header p_hdr; + spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, cur_block, cur_entry); + + // load header + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr); + SPIFFS_CHECK_RES(res); + + if (p_hdr.span_ix == 0 && + (p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) == + (SPIFFS_PH_FLAG_DELET)) { + SPIFFS_CHECK_DBG("IX: pix %04x, obj id:%04x spix:%04x header not fully deleted - deleting\n", + cur_pix, obj_id, p_hdr.span_ix); + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_PAGE, cur_pix, obj_id); + res = spiffs_page_delete(fs, cur_pix); + SPIFFS_CHECK_RES(res); + return res_c; + } + + if ((p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) == + (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) { + return res_c; + } + + if (p_hdr.span_ix == 0) { + // objix header page, register objid as reachable + int r = spiffs_object_index_search(fs, obj_id); + if (r == -1) { + // not registered, do it + obj_table[*log_ix] = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG; + (*log_ix)++; + if (*log_ix >= SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)) { + *log_ix = 0; + } + } + } else { // span index + // objix page, see if header can be found + int r = spiffs_object_index_search(fs, obj_id); + u8_t delete = 0; + if (r == -1) { + // not in temporary index, try finding it + spiffs_page_ix objix_hdr_pix; + res = spiffs_obj_lu_find_id_and_span(fs, obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &objix_hdr_pix); + res_c = SPIFFS_VIS_COUNTINUE_RELOAD; + if (res == SPIFFS_OK) { + // found, register as reachable + obj_table[*log_ix] = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG; + } else if (res == SPIFFS_ERR_NOT_FOUND) { + // not found, register as unreachable + delete = 1; + obj_table[*log_ix] = obj_id | SPIFFS_OBJ_ID_IX_FLAG; + } else { + SPIFFS_CHECK_RES(res); + } + (*log_ix)++; + if (*log_ix >= SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)) { + *log_ix = 0; + } + } else { + // in temporary index, check reachable flag + if ((obj_table[r] & SPIFFS_OBJ_ID_IX_FLAG)) { + // registered as unreachable + delete = 1; + } + } + + if (delete) { + SPIFFS_CHECK_DBG("IX: FIXUP: pix %04x, obj id:%04x spix:%04x is orphan index - deleting\n", + cur_pix, obj_id, p_hdr.span_ix); + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_ORPHANED_INDEX, cur_pix, obj_id); + res = spiffs_page_delete(fs, cur_pix); + SPIFFS_CHECK_RES(res); + } + } // span index + } // valid object index id + + return res_c; +} + +// Removes orphaned and partially deleted index pages. +// Scans for index pages. When an index page is found, corresponding index header is searched for. +// If no such page exists, the index page cannot be reached as no index header exists and must be +// deleted. +s32_t spiffs_object_index_consistency_check(spiffs *fs) { + s32_t res = SPIFFS_OK; + // impl note: + // fs->work is used for a temporary object index memory, listing found object ids and + // indicating whether they can be reached or not. Acting as a fifo if object ids cannot fit. + // In the temporary object index memory, SPIFFS_OBJ_ID_IX_FLAG bit is used to indicate + // a reachable/unreachable object id. + memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs)); + u32_t obj_id_log_ix = 0; + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 0, 0); + res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_object_index_consistency_check_v, 0, &obj_id_log_ix, + 0, 0); + if (res == SPIFFS_VIS_END) { + res = SPIFFS_OK; + } + if (res != SPIFFS_OK) { + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_ERROR, res, 0); + } + if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 256, 0); + return res; +} + diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/spiffs/spiffs_gc.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/spiffs/spiffs_gc.c new file mode 100644 index 0000000..5752e70 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/spiffs/spiffs_gc.c @@ -0,0 +1,568 @@ +#include "spiffs.h" +#include "spiffs_nucleus.h" + +// Erases a logical block and updates the erase counter. +// If cache is enabled, all pages that might be cached in this block +// is dropped. +static s32_t spiffs_gc_erase_block( + spiffs *fs, + spiffs_block_ix bix) { + s32_t res; + + SPIFFS_GC_DBG("gc: erase block %i\n", bix); + res = spiffs_erase_block(fs, bix); + SPIFFS_CHECK_RES(res); + +#if SPIFFS_CACHE + { + u32_t i; + for (i = 0; i < SPIFFS_PAGES_PER_BLOCK(fs); i++) { + spiffs_cache_drop_page(fs, SPIFFS_PAGE_FOR_BLOCK(fs, bix) + i); + } + } +#endif + return res; +} + +// Searches for blocks where all entries are deleted - if one is found, +// the block is erased. Compared to the non-quick gc, the quick one ensures +// that no updates are needed on existing objects on pages that are erased. +s32_t spiffs_gc_quick( + spiffs *fs, u16_t max_free_pages) { + s32_t res = SPIFFS_OK; + u32_t blocks = fs->block_count; + spiffs_block_ix cur_block = 0; + u32_t cur_block_addr = 0; + int cur_entry = 0; + spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work; + + SPIFFS_GC_DBG("gc_quick: running\n", cur_block); +#if SPIFFS_GC_STATS + fs->stats_gc_runs++; +#endif + + int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)); + + // find fully deleted blocks + // check each block + while (res == SPIFFS_OK && blocks--) { + u16_t deleted_pages_in_block = 0; + u16_t free_pages_in_block = 0; + + int obj_lookup_page = 0; + // check each object lookup page + while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) { + int entry_offset = obj_lookup_page * entries_per_page; + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, + 0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); + // check each entry + while (res == SPIFFS_OK && + cur_entry - entry_offset < entries_per_page && + cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) { + spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset]; + if (obj_id == SPIFFS_OBJ_ID_DELETED) { + deleted_pages_in_block++; + } else if (obj_id == SPIFFS_OBJ_ID_FREE) { + // kill scan, go for next block + free_pages_in_block++; + if (free_pages_in_block > max_free_pages) { + obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs); + res = 1; // kill object lu loop + break; + } + } else { + // kill scan, go for next block + obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs); + res = 1; // kill object lu loop + break; + } + cur_entry++; + } // per entry + obj_lookup_page++; + } // per object lookup page + if (res == 1) res = SPIFFS_OK; + + if (res == SPIFFS_OK && + deleted_pages_in_block + free_pages_in_block == SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs) && + free_pages_in_block <= max_free_pages) { + // found a fully deleted block + fs->stats_p_deleted -= deleted_pages_in_block; + res = spiffs_gc_erase_block(fs, cur_block); + return res; + } + + cur_entry = 0; + cur_block++; + cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs); + } // per block + + if (res == SPIFFS_OK) { + res = SPIFFS_ERR_NO_DELETED_BLOCKS; + } + return res; +} + +// Checks if garbage collecting is necessary. If so a candidate block is found, +// cleansed and erased +s32_t spiffs_gc_check( + spiffs *fs, + u32_t len) { + s32_t res; + s32_t free_pages = + (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count-2) + - fs->stats_p_allocated - fs->stats_p_deleted; + int tries = 0; + + if (fs->free_blocks > 3 && + (s32_t)len < free_pages * (s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) { + return SPIFFS_OK; + } + + u32_t needed_pages = (len + SPIFFS_DATA_PAGE_SIZE(fs) - 1) / SPIFFS_DATA_PAGE_SIZE(fs); +// if (fs->free_blocks <= 2 && (s32_t)needed_pages > free_pages) { +// SPIFFS_GC_DBG("gc: full freeblk:%i needed:%i free:%i dele:%i\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted); +// return SPIFFS_ERR_FULL; +// } + if ((s32_t)needed_pages > (s32_t)(free_pages + fs->stats_p_deleted)) { + SPIFFS_GC_DBG("gc_check: full freeblk:%i needed:%i free:%i dele:%i\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted); + return SPIFFS_ERR_FULL; + } + + do { + SPIFFS_GC_DBG("\ngc_check #%i: run gc free_blocks:%i pfree:%i pallo:%i pdele:%i [%i] len:%i of %i\n", + tries, + fs->free_blocks, free_pages, fs->stats_p_allocated, fs->stats_p_deleted, (free_pages+fs->stats_p_allocated+fs->stats_p_deleted), + len, free_pages*SPIFFS_DATA_PAGE_SIZE(fs)); + + spiffs_block_ix *cands; + int count; + spiffs_block_ix cand; + s32_t prev_free_pages = free_pages; + // if the fs is crammed, ignore block age when selecting candidate - kind of a bad state + res = spiffs_gc_find_candidate(fs, &cands, &count, free_pages <= 0); + SPIFFS_CHECK_RES(res); + if (count == 0) { + SPIFFS_GC_DBG("gc_check: no candidates, return\n"); + return (s32_t)needed_pages < free_pages ? SPIFFS_OK : SPIFFS_ERR_FULL; + } +#if SPIFFS_GC_STATS + fs->stats_gc_runs++; +#endif + cand = cands[0]; + fs->cleaning = 1; + //printf("gcing: cleaning block %i\n", cand); + res = spiffs_gc_clean(fs, cand); + fs->cleaning = 0; + if (res < 0) { + SPIFFS_GC_DBG("gc_check: cleaning block %i, result %i\n", cand, res); + } else { + SPIFFS_GC_DBG("gc_check: cleaning block %i, result %i\n", cand, res); + } + SPIFFS_CHECK_RES(res); + + res = spiffs_gc_erase_page_stats(fs, cand); + SPIFFS_CHECK_RES(res); + + res = spiffs_gc_erase_block(fs, cand); + SPIFFS_CHECK_RES(res); + + free_pages = + (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2) + - fs->stats_p_allocated - fs->stats_p_deleted; + + if (prev_free_pages <= 0 && prev_free_pages == free_pages) { + // abort early to reduce wear, at least tried once + SPIFFS_GC_DBG("gc_check: early abort, no result on gc when fs crammed\n"); + break; + } + + } while (++tries < SPIFFS_GC_MAX_RUNS && (fs->free_blocks <= 2 || + (s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs))); + + free_pages = + (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2) + - fs->stats_p_allocated - fs->stats_p_deleted; + if ((s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) { + res = SPIFFS_ERR_FULL; + } + + SPIFFS_GC_DBG("gc_check: finished, %i dirty, blocks %i free, %i pages free, %i tries, res %i\n", + fs->stats_p_allocated + fs->stats_p_deleted, + fs->free_blocks, free_pages, tries, res); + + return res; +} + +// Updates page statistics for a block that is about to be erased +s32_t spiffs_gc_erase_page_stats( + spiffs *fs, + spiffs_block_ix bix) { + s32_t res = SPIFFS_OK; + int obj_lookup_page = 0; + int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)); + spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work; + int cur_entry = 0; + u32_t dele = 0; + u32_t allo = 0; + + // check each object lookup page + while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) { + int entry_offset = obj_lookup_page * entries_per_page; + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, + 0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); + // check each entry + while (res == SPIFFS_OK && + cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) { + spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset]; + if (obj_id == SPIFFS_OBJ_ID_FREE) { + } else if (obj_id == SPIFFS_OBJ_ID_DELETED) { + dele++; + } else { + allo++; + } + cur_entry++; + } // per entry + obj_lookup_page++; + } // per object lookup page + SPIFFS_GC_DBG("gc_check: wipe pallo:%i pdele:%i\n", allo, dele); + fs->stats_p_allocated -= allo; + fs->stats_p_deleted -= dele; + return res; +} + +// Finds block candidates to erase +s32_t spiffs_gc_find_candidate( + spiffs *fs, + spiffs_block_ix **block_candidates, + int *candidate_count, + char fs_crammed) { + s32_t res = SPIFFS_OK; + u32_t blocks = fs->block_count; + spiffs_block_ix cur_block = 0; + u32_t cur_block_addr = 0; + spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work; + int cur_entry = 0; + + // using fs->work area as sorted candidate memory, (spiffs_block_ix)cand_bix/(s32_t)score + int max_candidates = MIN(fs->block_count, (SPIFFS_CFG_LOG_PAGE_SZ(fs)-8)/(sizeof(spiffs_block_ix) + sizeof(s32_t))); + *candidate_count = 0; + memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs)); + + // divide up work area into block indices and scores + // todo alignment? + spiffs_block_ix *cand_blocks = (spiffs_block_ix *)fs->work; + s32_t *cand_scores = (s32_t *)(fs->work + max_candidates * sizeof(spiffs_block_ix)); + + *block_candidates = cand_blocks; + + int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)); + + // check each block + while (res == SPIFFS_OK && blocks--) { + u16_t deleted_pages_in_block = 0; + u16_t used_pages_in_block = 0; + + int obj_lookup_page = 0; + // check each object lookup page + while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) { + int entry_offset = obj_lookup_page * entries_per_page; + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, + 0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); + // check each entry + while (res == SPIFFS_OK && + cur_entry - entry_offset < entries_per_page && + cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) { + spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset]; + if (obj_id == SPIFFS_OBJ_ID_FREE) { + // when a free entry is encountered, scan logic ensures that all following entries are free also + res = 1; // kill object lu loop + break; + } else if (obj_id == SPIFFS_OBJ_ID_DELETED) { + deleted_pages_in_block++; + } else { + used_pages_in_block++; + } + cur_entry++; + } // per entry + obj_lookup_page++; + } // per object lookup page + if (res == 1) res = SPIFFS_OK; + + // calculate score and insert into candidate table + // stoneage sort, but probably not so many blocks + if (res == SPIFFS_OK && deleted_pages_in_block > 0) { + // read erase count + spiffs_obj_id erase_count; + res = _spiffs_rd(fs, SPIFFS_OP_C_READ | SPIFFS_OP_T_OBJ_LU2, 0, + SPIFFS_ERASE_COUNT_PADDR(fs, cur_block), + sizeof(spiffs_obj_id), (u8_t *)&erase_count); + SPIFFS_CHECK_RES(res); + + spiffs_obj_id erase_age; + if (fs->max_erase_count > erase_count) { + erase_age = fs->max_erase_count - erase_count; + } else { + erase_age = SPIFFS_OBJ_ID_FREE - (erase_count - fs->max_erase_count); + } + + s32_t score = + deleted_pages_in_block * SPIFFS_GC_HEUR_W_DELET + + used_pages_in_block * SPIFFS_GC_HEUR_W_USED + + erase_age * (fs_crammed ? 0 : SPIFFS_GC_HEUR_W_ERASE_AGE); + int cand_ix = 0; + SPIFFS_GC_DBG("gc_check: bix:%i del:%i use:%i score:%i\n", cur_block, deleted_pages_in_block, used_pages_in_block, score); + while (cand_ix < max_candidates) { + if (cand_blocks[cand_ix] == (spiffs_block_ix)-1) { + cand_blocks[cand_ix] = cur_block; + cand_scores[cand_ix] = score; + break; + } else if (cand_scores[cand_ix] < score) { + int reorder_cand_ix = max_candidates - 2; + while (reorder_cand_ix >= cand_ix) { + cand_blocks[reorder_cand_ix + 1] = cand_blocks[reorder_cand_ix]; + cand_scores[reorder_cand_ix + 1] = cand_scores[reorder_cand_ix]; + reorder_cand_ix--; + } + cand_blocks[cand_ix] = cur_block; + cand_scores[cand_ix] = score; + break; + } + cand_ix++; + } + (*candidate_count)++; + } + + cur_entry = 0; + cur_block++; + cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs); + } // per block + + return res; +} + +typedef enum { + FIND_OBJ_DATA, + MOVE_OBJ_DATA, + MOVE_OBJ_IX, + FINISHED +} spiffs_gc_clean_state; + +typedef struct { + spiffs_gc_clean_state state; + spiffs_obj_id cur_obj_id; + spiffs_span_ix cur_objix_spix; + spiffs_page_ix cur_objix_pix; + int stored_scan_entry_index; + u8_t obj_id_found; +} spiffs_gc; + +// Empties given block by moving all data into free pages of another block +// Strategy: +// loop: +// scan object lookup for object data pages +// for first found id, check spix and load corresponding object index page to memory +// push object scan lookup entry index +// rescan object lookup, find data pages with same id and referenced by same object index +// move data page, update object index in memory +// when reached end of lookup, store updated object index +// pop object scan lookup entry index +// repeat loop until end of object lookup +// scan object lookup again for remaining object index pages, move to new page in other block +// +s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) { + s32_t res = SPIFFS_OK; + int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)); + int cur_entry = 0; + spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work; + spiffs_gc gc; + spiffs_page_ix cur_pix = 0; + spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work; + spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work; + + SPIFFS_GC_DBG("gc_clean: cleaning block %i\n", bix); + + memset(&gc, 0, sizeof(spiffs_gc)); + gc.state = FIND_OBJ_DATA; + + if (fs->free_cursor_block_ix == bix) { + // move free cursor to next block, cannot use free pages from the block we want to clean + fs->free_cursor_block_ix = (bix+1)%fs->block_count; + fs->free_cursor_obj_lu_entry = 0; + SPIFFS_GC_DBG("gc_clean: move free cursor to block %i\n", fs->free_cursor_block_ix); + } + + while (res == SPIFFS_OK && gc.state != FINISHED) { + SPIFFS_GC_DBG("gc_clean: state = %i entry:%i\n", gc.state, cur_entry); + gc.obj_id_found = 0; + + // scan through lookup pages + int obj_lookup_page = cur_entry / entries_per_page; + u8_t scan = 1; + // check each object lookup page + while (scan && res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) { + int entry_offset = obj_lookup_page * entries_per_page; + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, + 0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), + SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); + // check each entry + while (scan && res == SPIFFS_OK && + cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) { + spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset]; + cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, cur_entry); + + // act upon object id depending on gc state + switch (gc.state) { + case FIND_OBJ_DATA: + if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE && + ((obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0)) { + SPIFFS_GC_DBG("gc_clean: FIND_DATA state:%i - found obj id %04x\n", gc.state, obj_id); + gc.obj_id_found = 1; + gc.cur_obj_id = obj_id; + scan = 0; + } + break; + case MOVE_OBJ_DATA: + if (obj_id == gc.cur_obj_id) { + spiffs_page_header p_hdr; + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr); + SPIFFS_CHECK_RES(res); + SPIFFS_GC_DBG("gc_clean: MOVE_DATA found data page %04x:%04x @ %04x\n", gc.cur_obj_id, p_hdr.span_ix, cur_pix); + if (SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix) != gc.cur_objix_spix) { + SPIFFS_GC_DBG("gc_clean: MOVE_DATA no objix spix match, take in another run\n"); + } else { + spiffs_page_ix new_data_pix; + if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) { + // move page + res = spiffs_page_move(fs, 0, 0, obj_id, &p_hdr, cur_pix, &new_data_pix); + SPIFFS_GC_DBG("gc_clean: MOVE_DATA move objix %04x:%04x page %04x to %04x\n", gc.cur_obj_id, p_hdr.span_ix, cur_pix, new_data_pix); + SPIFFS_CHECK_RES(res); + // move wipes obj_lu, reload it + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, + 0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), + SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); + SPIFFS_CHECK_RES(res); + } else { + // page is deleted but not deleted in lookup, scrap it + SPIFFS_GC_DBG("gc_clean: MOVE_DATA wipe objix %04x:%04x page %04x\n", obj_id, p_hdr.span_ix, cur_pix); + res = spiffs_page_delete(fs, cur_pix); + SPIFFS_CHECK_RES(res); + new_data_pix = SPIFFS_OBJ_ID_FREE; + } + // update memory representation of object index page with new data page + if (gc.cur_objix_spix == 0) { + // update object index header page + ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[p_hdr.span_ix] = new_data_pix; + SPIFFS_GC_DBG("gc_clean: MOVE_DATA wrote page %04x to objix_hdr entry %02x in mem\n", new_data_pix, SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix)); + } else { + // update object index page + ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix)] = new_data_pix; + SPIFFS_GC_DBG("gc_clean: MOVE_DATA wrote page %04x to objix entry %02x in mem\n", new_data_pix, SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix)); + } + } + } + break; + case MOVE_OBJ_IX: + if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE && + (obj_id & SPIFFS_OBJ_ID_IX_FLAG)) { + // found an index object id + spiffs_page_header p_hdr; + spiffs_page_ix new_pix; + // load header + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr); + SPIFFS_CHECK_RES(res); + if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) { + // move page + res = spiffs_page_move(fs, 0, 0, obj_id, &p_hdr, cur_pix, &new_pix); + SPIFFS_GC_DBG("gc_clean: MOVE_OBJIX move objix %04x:%04x page %04x to %04x\n", obj_id, p_hdr.span_ix, cur_pix, new_pix); + SPIFFS_CHECK_RES(res); + spiffs_cb_object_event(fs, 0, SPIFFS_EV_IX_UPD, obj_id, p_hdr.span_ix, new_pix, 0); + // move wipes obj_lu, reload it + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, + 0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), + SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); + SPIFFS_CHECK_RES(res); + } else { + // page is deleted but not deleted in lookup, scrap it + SPIFFS_GC_DBG("gc_clean: MOVE_OBJIX wipe objix %04x:%04x page %04x\n", obj_id, p_hdr.span_ix, cur_pix); + res = spiffs_page_delete(fs, cur_pix); + if (res == SPIFFS_OK) { + spiffs_cb_object_event(fs, 0, SPIFFS_EV_IX_DEL, obj_id, p_hdr.span_ix, cur_pix, 0); + } + } + SPIFFS_CHECK_RES(res); + } + break; + default: + scan = 0; + break; + } + cur_entry++; + } // per entry + obj_lookup_page++; + } // per object lookup page + + if (res != SPIFFS_OK) break; + + // state finalization and switch + switch (gc.state) { + case FIND_OBJ_DATA: + if (gc.obj_id_found) { + // find out corresponding obj ix page and load it to memory + spiffs_page_header p_hdr; + spiffs_page_ix objix_pix; + gc.stored_scan_entry_index = cur_entry; + cur_entry = 0; + gc.state = MOVE_OBJ_DATA; + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr); + SPIFFS_CHECK_RES(res); + gc.cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix); + SPIFFS_GC_DBG("gc_clean: FIND_DATA find objix span_ix:%04x\n", gc.cur_objix_spix); + res = spiffs_obj_lu_find_id_and_span(fs, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_spix, 0, &objix_pix); + SPIFFS_CHECK_RES(res); + SPIFFS_GC_DBG("gc_clean: FIND_DATA found object index at page %04x\n", objix_pix); + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); + SPIFFS_CHECK_RES(res); + SPIFFS_VALIDATE_OBJIX(objix->p_hdr, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_spix); + gc.cur_objix_pix = objix_pix; + } else { + gc.state = MOVE_OBJ_IX; + cur_entry = 0; // restart entry scan index + } + break; + case MOVE_OBJ_DATA: { + // store modified objix (hdr) page + spiffs_page_ix new_objix_pix; + gc.state = FIND_OBJ_DATA; + cur_entry = gc.stored_scan_entry_index; + if (gc.cur_objix_spix == 0) { + // store object index header page + res = spiffs_object_update_index_hdr(fs, 0, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_pix, fs->work, 0, 0, &new_objix_pix); + SPIFFS_GC_DBG("gc_clean: MOVE_DATA store modified objix_hdr page, %04x:%04x\n", new_objix_pix, 0); + SPIFFS_CHECK_RES(res); + } else { + // store object index page + res = spiffs_page_move(fs, 0, fs->work, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, gc.cur_objix_pix, &new_objix_pix); + SPIFFS_GC_DBG("gc_clean: MOVE_DATA store modified objix page, %04x:%04x\n", new_objix_pix, objix->p_hdr.span_ix); + SPIFFS_CHECK_RES(res); + spiffs_cb_object_event(fs, 0, SPIFFS_EV_IX_UPD, gc.cur_obj_id, objix->p_hdr.span_ix, new_objix_pix, 0); + } + } + break; + case MOVE_OBJ_IX: + gc.state = FINISHED; + break; + default: + cur_entry = 0; + break; + } + SPIFFS_GC_DBG("gc_clean: state-> %i\n", gc.state); + } // while state != FINISHED + + + return res; +} + diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/spiffs/spiffs_hydrogen.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/spiffs/spiffs_hydrogen.c new file mode 100644 index 0000000..977c003 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/spiffs/spiffs_hydrogen.c @@ -0,0 +1,960 @@ +/* + * spiffs_hydrogen.c + * + * Created on: Jun 16, 2013 + * Author: petera + */ + +#include "spiffs.h" +#include "spiffs_nucleus.h" + +static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh); + +#if SPIFFS_BUFFER_HELP +u32_t SPIFFS_buffer_bytes_for_filedescs(spiffs *fs, u32_t num_descs) { + return num_descs * sizeof(spiffs_fd); +} +#if SPIFFS_CACHE +u32_t SPIFFS_buffer_bytes_for_cache(spiffs *fs, u32_t num_pages) { + return sizeof(spiffs_cache) + num_pages * (sizeof(spiffs_cache_page) + SPIFFS_CFG_LOG_PAGE_SZ(fs)); +} +#endif +#endif + +u8_t SPIFFS_mounted(spiffs *fs) { + return SPIFFS_CHECK_MOUNT(fs); +} + +s32_t SPIFFS_format(spiffs *fs) { + SPIFFS_API_CHECK_CFG(fs); + if (SPIFFS_CHECK_MOUNT(fs)) { + fs->err_code = SPIFFS_ERR_MOUNTED; + return -1; + } + + s32_t res; + SPIFFS_LOCK(fs); + + spiffs_block_ix bix = 0; + while (bix < fs->block_count) { + fs->max_erase_count = 0; + res = spiffs_erase_block(fs, bix); + if (res != SPIFFS_OK) { + res = SPIFFS_ERR_ERASE_FAIL; + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + bix++; + } + + SPIFFS_UNLOCK(fs); + + return 0; +} + +s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work, + u8_t *fd_space, u32_t fd_space_size, + void *cache, u32_t cache_size, + spiffs_check_callback check_cb_f) { + SPIFFS_LOCK(fs); + memset(fs, 0, sizeof(spiffs)); + memcpy(&fs->cfg, config, sizeof(spiffs_config)); + fs->block_count = SPIFFS_CFG_PHYS_SZ(fs) / SPIFFS_CFG_LOG_BLOCK_SZ(fs); + fs->work = &work[0]; + fs->lu_work = &work[SPIFFS_CFG_LOG_PAGE_SZ(fs)]; + memset(fd_space, 0, fd_space_size); + // align fd_space pointer to pointer size byte boundary, below is safe + u8_t ptr_size = sizeof(void*); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpointer-to-int-cast" + u8_t addr_lsb = ((u8_t)fd_space) & (ptr_size-1); +#pragma GCC diagnostic pop + if (addr_lsb) { + fd_space += (ptr_size-addr_lsb); + fd_space_size -= (ptr_size-addr_lsb); + } + fs->fd_space = fd_space; + fs->fd_count = (fd_space_size/sizeof(spiffs_fd)); + + // align cache pointer to 4 byte boundary, below is safe +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpointer-to-int-cast" + addr_lsb = ((u8_t)cache) & (ptr_size-1); +#pragma GCC diagnostic pop + if (addr_lsb) { + u8_t *cache_8 = (u8_t *)cache; + cache_8 += (ptr_size-addr_lsb); + cache = cache_8; + cache_size -= (ptr_size-addr_lsb); + } + if (cache_size & (ptr_size-1)) { + cache_size -= (cache_size & (ptr_size-1)); + } +#if SPIFFS_CACHE + fs->cache = cache; + fs->cache_size = (cache_size > (config->log_page_size*32)) ? config->log_page_size*32 : cache_size; + spiffs_cache_init(fs); +#endif + + s32_t res; + +#if SPIFFS_USE_MAGIC + res = SPIFFS_CHECK_MAGIC_POSSIBLE(fs) ? SPIFFS_OK : SPIFFS_ERR_MAGIC_NOT_POSSIBLE; + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); +#endif + + fs->config_magic = SPIFFS_CONFIG_MAGIC; + + res = spiffs_obj_lu_scan(fs); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + SPIFFS_DBG("page index byte len: %i\n", SPIFFS_CFG_LOG_PAGE_SZ(fs)); + SPIFFS_DBG("object lookup pages: %i\n", SPIFFS_OBJ_LOOKUP_PAGES(fs)); + SPIFFS_DBG("page pages per block: %i\n", SPIFFS_PAGES_PER_BLOCK(fs)); + SPIFFS_DBG("page header length: %i\n", sizeof(spiffs_page_header)); + SPIFFS_DBG("object header index entries: %i\n", SPIFFS_OBJ_HDR_IX_LEN(fs)); + SPIFFS_DBG("object index entries: %i\n", SPIFFS_OBJ_IX_LEN(fs)); + SPIFFS_DBG("available file descriptors: %i\n", fs->fd_count); + SPIFFS_DBG("free blocks: %i\n", fs->free_blocks); + + fs->check_cb_f = check_cb_f; + + fs->mounted = 1; + + SPIFFS_UNLOCK(fs); + + return 0; +} + +void SPIFFS_unmount(spiffs *fs) { + if (!SPIFFS_CHECK_CFG(fs) || !SPIFFS_CHECK_MOUNT(fs)) return; + SPIFFS_LOCK(fs); + u32_t i; + spiffs_fd *fds = (spiffs_fd *)fs->fd_space; + for (i = 0; i < fs->fd_count; i++) { + spiffs_fd *cur_fd = &fds[i]; + if (cur_fd->file_nbr != 0) { +#if SPIFFS_CACHE + (void)spiffs_fflush_cache(fs, cur_fd->file_nbr); +#endif + spiffs_fd_return(fs, cur_fd->file_nbr); + } + } + fs->mounted = 0; + + SPIFFS_UNLOCK(fs); +} + +s32_t SPIFFS_errno(spiffs *fs) { + return fs->err_code; +} + +void SPIFFS_clearerr(spiffs *fs) { + fs->err_code = SPIFFS_OK; +} + +s32_t SPIFFS_creat(spiffs *fs, char *path, spiffs_mode mode) { + (void)mode; + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + spiffs_obj_id obj_id; + s32_t res; + + res = spiffs_obj_lu_find_free_obj_id(fs, &obj_id, (u8_t *)path); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + res = spiffs_object_create(fs, obj_id, (u8_t *)path, SPIFFS_TYPE_FILE, 0); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + SPIFFS_UNLOCK(fs); + return 0; +} + +spiffs_file SPIFFS_open(spiffs *fs, char *path, spiffs_flags flags, spiffs_mode mode) { + (void)mode; + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + spiffs_fd *fd; + spiffs_page_ix pix; + + s32_t res = spiffs_fd_find_new(fs, &fd); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + res = spiffs_object_find_object_index_header_by_name(fs, (u8_t*)path, &pix); + if ((flags & SPIFFS_CREAT) == 0) { + if (res < SPIFFS_OK) { + spiffs_fd_return(fs, fd->file_nbr); + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + } + + if ((flags & SPIFFS_CREAT) && res == SPIFFS_ERR_NOT_FOUND) { + spiffs_obj_id obj_id; + // no need to enter conflicting name here, already looked for it above + res = spiffs_obj_lu_find_free_obj_id(fs, &obj_id, 0); + if (res < SPIFFS_OK) { + spiffs_fd_return(fs, fd->file_nbr); + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + res = spiffs_object_create(fs, obj_id, (u8_t*)path, SPIFFS_TYPE_FILE, &pix); + if (res < SPIFFS_OK) { + spiffs_fd_return(fs, fd->file_nbr); + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + flags &= ~SPIFFS_TRUNC; + } else { + if (res < SPIFFS_OK) { + spiffs_fd_return(fs, fd->file_nbr); + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + } + res = spiffs_object_open_by_page(fs, pix, fd, flags, mode); + if (res < SPIFFS_OK) { + spiffs_fd_return(fs, fd->file_nbr); + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + if (flags & SPIFFS_TRUNC) { + res = spiffs_object_truncate(fd, 0, 0); + if (res < SPIFFS_OK) { + spiffs_fd_return(fs, fd->file_nbr); + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + } + + fd->fdoffset = 0; + + SPIFFS_UNLOCK(fs); + + return fd->file_nbr; +} + +spiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_flags flags, spiffs_mode mode) { + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + spiffs_fd *fd; + + s32_t res = spiffs_fd_find_new(fs, &fd); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + res = spiffs_object_open_by_page(fs, e->pix, fd, flags, mode); + if (res < SPIFFS_OK) { + spiffs_fd_return(fs, fd->file_nbr); + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + if (flags & SPIFFS_TRUNC) { + res = spiffs_object_truncate(fd, 0, 0); + if (res < SPIFFS_OK) { + spiffs_fd_return(fs, fd->file_nbr); + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + } + + fd->fdoffset = 0; + + SPIFFS_UNLOCK(fs); + + return fd->file_nbr; +} + +s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len) { + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + spiffs_fd *fd; + s32_t res; + + res = spiffs_fd_get(fs, fh, &fd); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + if ((fd->flags & SPIFFS_RDONLY) == 0) { + res = SPIFFS_ERR_NOT_READABLE; + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + } + +#if SPIFFS_CACHE_WR + spiffs_fflush_cache(fs, fh); +#endif + + if (fd->fdoffset + len >= fd->size) { + // reading beyond file size + s32_t avail = fd->size - fd->fdoffset; + if (avail <= 0) { + SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_END_OF_OBJECT); + } + res = spiffs_object_read(fd, fd->fdoffset, avail, (u8_t*)buf); + if (res == SPIFFS_ERR_END_OF_OBJECT) { + fd->fdoffset += avail; + SPIFFS_UNLOCK(fs); + return avail; + } else { + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + len = avail; + } + } else { + // reading within file size + res = spiffs_object_read(fd, fd->fdoffset, len, (u8_t*)buf); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + } + fd->fdoffset += len; + + SPIFFS_UNLOCK(fs); + + return len; +} + +static s32_t spiffs_hydro_write(spiffs *fs, spiffs_fd *fd, void *buf, u32_t offset, s32_t len) { + (void)fs; + s32_t res = SPIFFS_OK; + s32_t remaining = len; + if (fd->size != SPIFFS_UNDEFINED_LEN && offset < fd->size) { + s32_t m_len = MIN((s32_t)(fd->size - offset), len); + res = spiffs_object_modify(fd, offset, (u8_t *)buf, m_len); + SPIFFS_CHECK_RES(res); + remaining -= m_len; + u8_t *buf_8 = (u8_t *)buf; + buf_8 += m_len; + buf = buf_8; + offset += m_len; + } + if (remaining > 0) { + res = spiffs_object_append(fd, offset, (u8_t *)buf, remaining); + SPIFFS_CHECK_RES(res); + } + return len; + +} + +s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) { + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + spiffs_fd *fd; + s32_t res; + u32_t offset; + + res = spiffs_fd_get(fs, fh, &fd); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + if ((fd->flags & SPIFFS_WRONLY) == 0) { + res = SPIFFS_ERR_NOT_WRITABLE; + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + } + + offset = fd->fdoffset; + +#if SPIFFS_CACHE_WR + if (fd->cache_page == 0) { + // see if object id is associated with cache already + fd->cache_page = spiffs_cache_page_get_by_fd(fs, fd); + } +#endif + if (fd->flags & SPIFFS_APPEND) { + if (fd->size == SPIFFS_UNDEFINED_LEN) { + offset = 0; + } else { + offset = fd->size; + } +#if SPIFFS_CACHE_WR + if (fd->cache_page) { + offset = MAX(offset, fd->cache_page->offset + fd->cache_page->size); + } +#endif + } + +#if SPIFFS_CACHE_WR + if ((fd->flags & SPIFFS_DIRECT) == 0) { + if (len < (s32_t)SPIFFS_CFG_LOG_PAGE_SZ(fs)) { + // small write, try to cache it + u8_t alloc_cpage = 1; + if (fd->cache_page) { + // have a cached page for this fd already, check cache page boundaries + if (offset < fd->cache_page->offset || // writing before cache + offset > fd->cache_page->offset + fd->cache_page->size || // writing after cache + offset + len > fd->cache_page->offset + SPIFFS_CFG_LOG_PAGE_SZ(fs)) // writing beyond cache page + { + // boundary violation, write back cache first and allocate new + SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page %i for fd %i:%04x, boundary viol, offs:%i size:%i\n", + fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size); + res = spiffs_hydro_write(fs, fd, + spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix), + fd->cache_page->offset, fd->cache_page->size); + spiffs_cache_fd_release(fs, fd->cache_page); + SPIFFS_API_CHECK_RES(fs, res); + } else { + // writing within cache + alloc_cpage = 0; + } + } + + if (alloc_cpage) { + fd->cache_page = spiffs_cache_page_allocate_by_fd(fs, fd); + if (fd->cache_page) { + fd->cache_page->offset = offset; + fd->cache_page->size = 0; + SPIFFS_CACHE_DBG("CACHE_WR_ALLO: allocating cache page %i for fd %i:%04x\n", + fd->cache_page->ix, fd->file_nbr, fd->obj_id); + } + } + + if (fd->cache_page) { + u32_t offset_in_cpage = offset - fd->cache_page->offset; + SPIFFS_CACHE_DBG("CACHE_WR_WRITE: storing to cache page %i for fd %i:%04x, offs %i:%i len %i\n", + fd->cache_page->ix, fd->file_nbr, fd->obj_id, + offset, offset_in_cpage, len); + spiffs_cache *cache = spiffs_get_cache(fs); + u8_t *cpage_data = spiffs_get_cache_page(fs, cache, fd->cache_page->ix); + memcpy(&cpage_data[offset_in_cpage], buf, len); + fd->cache_page->size = MAX(fd->cache_page->size, offset_in_cpage + len); + fd->fdoffset += len; + SPIFFS_UNLOCK(fs); + return len; + } else { + res = spiffs_hydro_write(fs, fd, buf, offset, len); + SPIFFS_API_CHECK_RES(fs, res); + fd->fdoffset += len; + SPIFFS_UNLOCK(fs); + return res; + } + } else { + // big write, no need to cache it - but first check if there is a cached write already + if (fd->cache_page) { + // write back cache first + SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page %i for fd %i:%04x, big write, offs:%i size:%i\n", + fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size); + res = spiffs_hydro_write(fs, fd, + spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix), + fd->cache_page->offset, fd->cache_page->size); + spiffs_cache_fd_release(fs, fd->cache_page); + SPIFFS_API_CHECK_RES(fs, res); + res = spiffs_hydro_write(fs, fd, buf, offset, len); + SPIFFS_API_CHECK_RES(fs, res); + } + } + } +#endif + + res = spiffs_hydro_write(fs, fd, buf, offset, len); + SPIFFS_API_CHECK_RES(fs, res); + fd->fdoffset += len; + + SPIFFS_UNLOCK(fs); + + return res; +} + +s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) { + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + spiffs_fd *fd; + s32_t res; + res = spiffs_fd_get(fs, fh, &fd); + SPIFFS_API_CHECK_RES(fs, res); + +#if SPIFFS_CACHE_WR + spiffs_fflush_cache(fs, fh); +#endif + + switch (whence) { + case SPIFFS_SEEK_CUR: + offs = fd->fdoffset+offs; + break; + case SPIFFS_SEEK_END: + offs = (fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size) + offs; + break; + } + + if (offs > (s32_t)fd->size) { + res = SPIFFS_ERR_END_OF_OBJECT; + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + spiffs_span_ix data_spix = offs / SPIFFS_DATA_PAGE_SIZE(fs); + spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix); + if (fd->cursor_objix_spix != objix_spix) { + spiffs_page_ix pix; + res = spiffs_obj_lu_find_id_and_span( + fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, objix_spix, 0, &pix); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + fd->cursor_objix_spix = objix_spix; + fd->cursor_objix_pix = pix; + } + fd->fdoffset = offs; + + SPIFFS_UNLOCK(fs); + + return offs; +} + +s32_t SPIFFS_remove(spiffs *fs, char *path) { + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + spiffs_fd *fd; + spiffs_page_ix pix; + s32_t res; + + res = spiffs_fd_find_new(fs, &fd); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + res = spiffs_object_find_object_index_header_by_name(fs, (u8_t *)path, &pix); + if (res != SPIFFS_OK) { + spiffs_fd_return(fs, fd->file_nbr); + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + res = spiffs_object_open_by_page(fs, pix, fd, 0,0); + if (res != SPIFFS_OK) { + spiffs_fd_return(fs, fd->file_nbr); + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + res = spiffs_object_truncate(fd, 0, 1); + if (res != SPIFFS_OK) { + spiffs_fd_return(fs, fd->file_nbr); + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + SPIFFS_UNLOCK(fs); + return 0; +} + +s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh) { + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + spiffs_fd *fd; + s32_t res; + res = spiffs_fd_get(fs, fh, &fd); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + if ((fd->flags & SPIFFS_WRONLY) == 0) { + res = SPIFFS_ERR_NOT_WRITABLE; + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + } + +#if SPIFFS_CACHE_WR + spiffs_cache_fd_release(fs, fd->cache_page); +#endif + + res = spiffs_object_truncate(fd, 0, 1); + + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + SPIFFS_UNLOCK(fs); + + return 0; +} + +static s32_t spiffs_stat_pix(spiffs *fs, spiffs_page_ix pix, spiffs_file fh, spiffs_stat *s) { + spiffs_page_object_ix_header objix_hdr; + spiffs_obj_id obj_id; + s32_t res =_spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, fh, + SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr); + SPIFFS_API_CHECK_RES(fs, res); + + u32_t obj_id_addr = SPIFFS_BLOCK_TO_PADDR(fs, SPIFFS_BLOCK_FOR_PAGE(fs , pix)) + + SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, pix) * sizeof(spiffs_obj_id); + res =_spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, fh, + obj_id_addr, sizeof(spiffs_obj_id), (u8_t *)&obj_id); + SPIFFS_API_CHECK_RES(fs, res); + + s->obj_id = obj_id; + s->type = objix_hdr.type; + s->size = objix_hdr.size == SPIFFS_UNDEFINED_LEN ? 0 : objix_hdr.size; + strncpy((char *)s->name, (char *)objix_hdr.name, SPIFFS_OBJ_NAME_LEN); + + return res; +} + +s32_t SPIFFS_stat(spiffs *fs, char *path, spiffs_stat *s) { + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + s32_t res; + spiffs_page_ix pix; + + res = spiffs_object_find_object_index_header_by_name(fs, (u8_t*)path, &pix); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + res = spiffs_stat_pix(fs, pix, 0, s); + + SPIFFS_UNLOCK(fs); + + return res; +} + +s32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s) { + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + spiffs_fd *fd; + s32_t res; + + res = spiffs_fd_get(fs, fh, &fd); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + +#if SPIFFS_CACHE_WR + spiffs_fflush_cache(fs, fh); +#endif + + res = spiffs_stat_pix(fs, fd->objix_hdr_pix, fh, s); + + SPIFFS_UNLOCK(fs); + + return res; +} + +// Checks if there are any cached writes for the object id associated with +// given filehandle. If so, these writes are flushed. +static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) { + s32_t res = SPIFFS_OK; +#if SPIFFS_CACHE_WR + + spiffs_fd *fd; + res = spiffs_fd_get(fs, fh, &fd); + SPIFFS_API_CHECK_RES(fs, res); + + if ((fd->flags & SPIFFS_DIRECT) == 0) { + if (fd->cache_page == 0) { + // see if object id is associated with cache already + fd->cache_page = spiffs_cache_page_get_by_fd(fs, fd); + } + if (fd->cache_page) { + SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page %i for fd %i:%04x, flush, offs:%i size:%i\n", + fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size); + res = spiffs_hydro_write(fs, fd, + spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix), + fd->cache_page->offset, fd->cache_page->size); + if (res < SPIFFS_OK) { + fs->err_code = res; + } + spiffs_cache_fd_release(fs, fd->cache_page); + } + } +#endif + + return res; +} + +s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) { + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + s32_t res = SPIFFS_OK; +#if SPIFFS_CACHE_WR + SPIFFS_LOCK(fs); + res = spiffs_fflush_cache(fs, fh); + SPIFFS_API_CHECK_RES_UNLOCK(fs,res); + SPIFFS_UNLOCK(fs); +#endif + + return res; +} + +void SPIFFS_close(spiffs *fs, spiffs_file fh) { + if (!SPIFFS_CHECK_CFG((fs))) { + (fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED; + return; + } + + if (!SPIFFS_CHECK_MOUNT(fs)) { + fs->err_code = SPIFFS_ERR_NOT_MOUNTED; + return; + } + SPIFFS_LOCK(fs); + +#if SPIFFS_CACHE + spiffs_fflush_cache(fs, fh); +#endif + spiffs_fd_return(fs, fh); + + SPIFFS_UNLOCK(fs); +} + +s32_t SPIFFS_rename(spiffs *fs, char *old, char *new) { + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + spiffs_page_ix pix_old, pix_dummy; + spiffs_fd *fd; + + s32_t res = spiffs_object_find_object_index_header_by_name(fs, (u8_t*)old, &pix_old); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + res = spiffs_object_find_object_index_header_by_name(fs, (u8_t*)new, &pix_dummy); + if (res == SPIFFS_ERR_NOT_FOUND) { + res = SPIFFS_OK; + } else if (res == SPIFFS_OK) { + res = SPIFFS_ERR_CONFLICTING_NAME; + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + res = spiffs_fd_find_new(fs, &fd); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + res = spiffs_object_open_by_page(fs, pix_old, fd, 0, 0); + if (res != SPIFFS_OK) { + spiffs_fd_return(fs, fd->file_nbr); + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, fd->objix_hdr_pix, 0, (u8_t*)new, + 0, &pix_dummy); + + spiffs_fd_return(fs, fd->file_nbr); + + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + SPIFFS_UNLOCK(fs); + + return res; +} + +spiffs_DIR *SPIFFS_opendir(spiffs *fs, char *name, spiffs_DIR *d) { + (void)name; + + if (!SPIFFS_CHECK_CFG((fs))) { + (fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED; + return 0; + } + + if (!SPIFFS_CHECK_MOUNT(fs)) { + fs->err_code = SPIFFS_ERR_NOT_MOUNTED; + return 0; + } + + d->fs = fs; + d->block = 0; + d->entry = 0; + return d; +} + +static s32_t spiffs_read_dir_v( + spiffs *fs, + spiffs_obj_id obj_id, + spiffs_block_ix bix, + int ix_entry, + u32_t user_data, + void *user_p) { + (void)user_data; + s32_t res; + spiffs_page_object_ix_header objix_hdr; + if (obj_id == SPIFFS_OBJ_ID_FREE || obj_id == SPIFFS_OBJ_ID_DELETED || + (obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0) { + return SPIFFS_VIS_COUNTINUE; + } + + spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry); + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr); + if (res != SPIFFS_OK) return res; + if ((obj_id & SPIFFS_OBJ_ID_IX_FLAG) && + objix_hdr.p_hdr.span_ix == 0 && + (objix_hdr.p_hdr.flags& (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE)) == + (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) { + struct spiffs_dirent *e = (struct spiffs_dirent *)user_p; + e->obj_id = obj_id; + strcpy((char *)e->name, (char *)objix_hdr.name); + e->type = objix_hdr.type; + e->size = objix_hdr.size == SPIFFS_UNDEFINED_LEN ? 0 : objix_hdr.size; + e->pix = pix; + return SPIFFS_OK; + } + + return SPIFFS_VIS_COUNTINUE; +} + +struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) { + if (!SPIFFS_CHECK_MOUNT(d->fs)) { + d->fs->err_code = SPIFFS_ERR_NOT_MOUNTED; + return 0; + } + SPIFFS_LOCK(fs); + + spiffs_block_ix bix; + int entry; + s32_t res; + struct spiffs_dirent *ret = 0; + + res = spiffs_obj_lu_find_entry_visitor(d->fs, + d->block, + d->entry, + SPIFFS_VIS_NO_WRAP, + 0, + spiffs_read_dir_v, + 0, + e, + &bix, + &entry); + if (res == SPIFFS_OK) { + d->block = bix; + d->entry = entry + 1; + ret = e; + } else { + d->fs->err_code = res; + } + SPIFFS_UNLOCK(fs); + return ret; +} + +s32_t SPIFFS_closedir(spiffs_DIR *d) { + SPIFFS_API_CHECK_CFG(d->fs); + SPIFFS_API_CHECK_MOUNT(d->fs); + return 0; +} + +s32_t SPIFFS_check(spiffs *fs) { + s32_t res; + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + res = spiffs_lookup_consistency_check(fs, 0); + + res = spiffs_object_index_consistency_check(fs); + + res = spiffs_page_consistency_check(fs); + + res = spiffs_obj_lu_scan(fs); + + SPIFFS_UNLOCK(fs); + return res; +} + +s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used) { + s32_t res = SPIFFS_OK; + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + u32_t pages_per_block = SPIFFS_PAGES_PER_BLOCK(fs); + u32_t blocks = fs->block_count; + u32_t obj_lu_pages = SPIFFS_OBJ_LOOKUP_PAGES(fs); + u32_t data_page_size = SPIFFS_DATA_PAGE_SIZE(fs); + u32_t total_data_pages = (blocks - 2) * (pages_per_block - obj_lu_pages) + 1; // -2 for spare blocks, +1 for emergency page + + if (total) { + *total = total_data_pages * data_page_size; + } + + if (used) { + *used = fs->stats_p_allocated * data_page_size; + } + + SPIFFS_UNLOCK(fs); + return res; +} + +s32_t SPIFFS_gc_quick(spiffs *fs, u16_t max_free_pages) { + s32_t res; + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + res = spiffs_gc_quick(fs, max_free_pages); + + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + SPIFFS_UNLOCK(fs); + return 0; +} + + +s32_t SPIFFS_gc(spiffs *fs, u32_t size) { + s32_t res; + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + res = spiffs_gc_check(fs, size); + + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + SPIFFS_UNLOCK(fs); + return 0; +} + + +#if SPIFFS_TEST_VISUALISATION +s32_t SPIFFS_vis(spiffs *fs) { + s32_t res = SPIFFS_OK; + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)); + spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work; + spiffs_block_ix bix = 0; + + while (bix < fs->block_count) { + // check each object lookup page + int obj_lookup_page = 0; + int cur_entry = 0; + + while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) { + int entry_offset = obj_lookup_page * entries_per_page; + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, + 0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); + // check each entry + while (res == SPIFFS_OK && + cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) { + spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset]; + if (cur_entry == 0) { + spiffs_printf("%4i ", bix); + } else if ((cur_entry & 0x3f) == 0) { + spiffs_printf(" "); + } + if (obj_id == SPIFFS_OBJ_ID_FREE) { + spiffs_printf(SPIFFS_TEST_VIS_FREE_STR); + } else if (obj_id == SPIFFS_OBJ_ID_DELETED) { + spiffs_printf(SPIFFS_TEST_VIS_DELE_STR); + } else if (obj_id & SPIFFS_OBJ_ID_IX_FLAG){ + spiffs_printf(SPIFFS_TEST_VIS_INDX_STR(obj_id)); + } else { + spiffs_printf(SPIFFS_TEST_VIS_DATA_STR(obj_id)); + } + cur_entry++; + if ((cur_entry & 0x3f) == 0) { + spiffs_printf("\n"); + } + } // per entry + obj_lookup_page++; + } // per object lookup page + + spiffs_obj_id erase_count; + res = _spiffs_rd(fs, SPIFFS_OP_C_READ | SPIFFS_OP_T_OBJ_LU2, 0, + SPIFFS_ERASE_COUNT_PADDR(fs, bix), + sizeof(spiffs_obj_id), (u8_t *)&erase_count); + SPIFFS_CHECK_RES(res); + + if (erase_count != (spiffs_obj_id)-1) { + spiffs_printf("\tera_cnt: %i\n", erase_count); + } else { + spiffs_printf("\tera_cnt: N/A\n"); + } + + bix++; + } // per block + + spiffs_printf("era_cnt_max: %i\n", fs->max_erase_count); + spiffs_printf("last_errno: %i\n", fs->err_code); + spiffs_printf("blocks: %i\n", fs->block_count); + spiffs_printf("free_blocks: %i\n", fs->free_blocks); + spiffs_printf("page_alloc: %i\n", fs->stats_p_allocated); + spiffs_printf("page_delet: %i\n", fs->stats_p_deleted); + u32_t total, used; + SPIFFS_info(fs, &total, &used); + spiffs_printf("used: %i of %i\n", used, total); + + SPIFFS_UNLOCK(fs); + return res; +} +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/spiffs/spiffs_nucleus.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/spiffs/spiffs_nucleus.c new file mode 100644 index 0000000..bfd028f --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/spiffs/spiffs_nucleus.c @@ -0,0 +1,1899 @@ +#include "spiffs.h" +#include "spiffs_nucleus.h" + +static s32_t spiffs_page_data_check(spiffs *fs, spiffs_fd *fd, spiffs_page_ix pix, spiffs_span_ix spix) { + s32_t res = SPIFFS_OK; + if (pix == (spiffs_page_ix)-1) { + // referring to page 0xffff...., bad object index + return SPIFFS_ERR_INDEX_REF_FREE; + } + if (pix % SPIFFS_PAGES_PER_BLOCK(fs) < SPIFFS_OBJ_LOOKUP_PAGES(fs)) { + // referring to an object lookup page, bad object index + return SPIFFS_ERR_INDEX_REF_LU; + } + if (pix > SPIFFS_MAX_PAGES(fs)) { + // referring to a bad page + return SPIFFS_ERR_INDEX_REF_INVALID; + } +#if SPIFFS_PAGE_CHECK + spiffs_page_header ph; + res = _spiffs_rd( + fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_READ, + fd->file_nbr, + SPIFFS_PAGE_TO_PADDR(fs, pix), + sizeof(spiffs_page_header), + (u8_t *)&ph); + SPIFFS_CHECK_RES(res); + SPIFFS_VALIDATE_DATA(ph, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, spix); +#endif + return res; +} + +static s32_t spiffs_page_index_check(spiffs *fs, spiffs_fd *fd, spiffs_page_ix pix, spiffs_span_ix spix) { + s32_t res = SPIFFS_OK; + if (pix == (spiffs_page_ix)-1) { + // referring to page 0xffff...., bad object index + return SPIFFS_ERR_INDEX_FREE; + } + if (pix % SPIFFS_PAGES_PER_BLOCK(fs) < SPIFFS_OBJ_LOOKUP_PAGES(fs)) { + // referring to an object lookup page, bad object index + return SPIFFS_ERR_INDEX_LU; + } + if (pix > SPIFFS_MAX_PAGES(fs)) { + // referring to a bad page + return SPIFFS_ERR_INDEX_INVALID; + } +#if SPIFFS_PAGE_CHECK + spiffs_page_header ph; + res = _spiffs_rd( + fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, + fd->file_nbr, + SPIFFS_PAGE_TO_PADDR(fs, pix), + sizeof(spiffs_page_header), + (u8_t *)&ph); + SPIFFS_CHECK_RES(res); + SPIFFS_VALIDATE_OBJIX(ph, fd->obj_id, spix); +#endif + return res; +} + +#if !SPIFFS_CACHE + +s32_t spiffs_phys_rd( + spiffs *fs, + u32_t addr, + u32_t len, + u8_t *dst) { + return fs->cfg.hal_read_f(addr, len, dst); +} + +s32_t spiffs_phys_wr( + spiffs *fs, + u32_t addr, + u32_t len, + u8_t *src) { + return fs->cfg.hal_write_f(addr, len, src); +} + +#endif + +s32_t spiffs_phys_cpy( + spiffs *fs, + spiffs_file fh, + u32_t dst, + u32_t src, + u32_t len) { + s32_t res; + u8_t b[SPIFFS_COPY_BUFFER_STACK]; + while (len > 0) { + u32_t chunk_size = MIN(SPIFFS_COPY_BUFFER_STACK, len); + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_MOVS, fh, src, chunk_size, b); + SPIFFS_CHECK_RES(res); + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_MOVD, fh, dst, chunk_size, b); + SPIFFS_CHECK_RES(res); + len -= chunk_size; + src += chunk_size; + dst += chunk_size; + } + return SPIFFS_OK; +} + +// Find object lookup entry containing given id with visitor. +// Iterate over object lookup pages in each block until a given object id entry is found. +// When found, the visitor function is called with block index, entry index and user_data. +// If visitor returns SPIFFS_VIS_CONTINUE, the search goes on. Otherwise, the search will be +// ended and visitor's return code is returned to caller. +// If no visitor is given (0) the search returns on first entry with matching object id. +// If no match is found in all look up, SPIFFS_VIS_END is returned. +// @param fs the file system +// @param starting_block the starting block to start search in +// @param starting_lu_entry the look up index entry to start search in +// @param flags ored combination of SPIFFS_VIS_CHECK_ID, SPIFFS_VIS_CHECK_PH, +// SPIFFS_VIS_NO_WRAP +// @param obj_id argument object id +// @param v visitor callback function +// @param user_data any data, passed to the callback visitor function +// @param user_p any pointer, passed to the callback visitor function +// @param block_ix reported block index where match was found +// @param lu_entry reported look up index where match was found +s32_t spiffs_obj_lu_find_entry_visitor( + spiffs *fs, + spiffs_block_ix starting_block, + int starting_lu_entry, + u8_t flags, + spiffs_obj_id obj_id, + spiffs_visitor_f v, + u32_t user_data, + void *user_p, + spiffs_block_ix *block_ix, + int *lu_entry) { + s32_t res = SPIFFS_OK; + s32_t entry_count = fs->block_count * SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs); + spiffs_block_ix cur_block = starting_block; + u32_t cur_block_addr = starting_block * SPIFFS_CFG_LOG_BLOCK_SZ(fs); + + spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work; + int cur_entry = starting_lu_entry; + int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)); + + // wrap initial + if (cur_entry >= (int)SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) - 1) { + cur_entry = 0; + cur_block++; + cur_block_addr = cur_block * SPIFFS_CFG_LOG_BLOCK_SZ(fs); + if (cur_block >= fs->block_count) { + if (flags & SPIFFS_VIS_NO_WRAP) { + return SPIFFS_VIS_END; + } else { + // block wrap + cur_block = 0; + cur_block_addr = 0; + } + } + } + + // check each block + while (res == SPIFFS_OK && entry_count > 0) { + int obj_lookup_page = cur_entry / entries_per_page; + // check each object lookup page + while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) { + int entry_offset = obj_lookup_page * entries_per_page; + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, + 0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); + // check each entry + while (res == SPIFFS_OK && + cur_entry - entry_offset < entries_per_page && // for non-last obj lookup pages + cur_entry < (int)SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs)) // for last obj lookup page + { + if ((flags & SPIFFS_VIS_CHECK_ID) == 0 || obj_lu_buf[cur_entry-entry_offset] == obj_id) { + if (block_ix) *block_ix = cur_block; + if (lu_entry) *lu_entry = cur_entry; + if (v) { + res = v( + fs, + (flags & SPIFFS_VIS_CHECK_PH) ? obj_id : obj_lu_buf[cur_entry-entry_offset], + cur_block, + cur_entry, + user_data, + user_p); + if (res == SPIFFS_VIS_COUNTINUE || res == SPIFFS_VIS_COUNTINUE_RELOAD) { + if (res == SPIFFS_VIS_COUNTINUE_RELOAD) { + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, + 0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); + SPIFFS_CHECK_RES(res); + } + res = SPIFFS_OK; + cur_entry++; + entry_count--; + continue; + } else { + return res; + } + } else { + return SPIFFS_OK; + } + } + entry_count--; + cur_entry++; + } // per entry + obj_lookup_page++; + } // per object lookup page + cur_entry = 0; + cur_block++; + cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs); + if (cur_block >= fs->block_count) { + if (flags & SPIFFS_VIS_NO_WRAP) { + return SPIFFS_VIS_END; + } else { + // block wrap + cur_block = 0; + cur_block_addr = 0; + } + } + } // per block + + SPIFFS_CHECK_RES(res); + + return SPIFFS_VIS_END; +} + +s32_t spiffs_erase_block( + spiffs *fs, + spiffs_block_ix bix) { + s32_t res; + u32_t addr = SPIFFS_BLOCK_TO_PADDR(fs, bix); + s32_t size = SPIFFS_CFG_LOG_BLOCK_SZ(fs); + + // here we ignore res, just try erasing the block + while (size > 0) { + SPIFFS_DBG("erase %08x:%08x\n", addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs)); + (void)fs->cfg.hal_erase_f(addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs)); + addr += SPIFFS_CFG_PHYS_ERASE_SZ(fs); + size -= SPIFFS_CFG_PHYS_ERASE_SZ(fs); + } + fs->free_blocks++; + + // register erase count for this block + res = _spiffs_wr(fs, SPIFFS_OP_C_WRTHRU | SPIFFS_OP_T_OBJ_LU2, 0, + SPIFFS_ERASE_COUNT_PADDR(fs, bix), + sizeof(spiffs_obj_id), (u8_t *)&fs->max_erase_count); + SPIFFS_CHECK_RES(res); + +#if SPIFFS_USE_MAGIC + // finally, write magic + spiffs_obj_id magic = SPIFFS_MAGIC(fs); + res = _spiffs_wr(fs, SPIFFS_OP_C_WRTHRU | SPIFFS_OP_T_OBJ_LU2, 0, + SPIFFS_MAGIC_PADDR(fs, bix), + sizeof(spiffs_obj_id), (u8_t *)&magic); + SPIFFS_CHECK_RES(res); +#endif + + fs->max_erase_count++; + if (fs->max_erase_count == SPIFFS_OBJ_ID_IX_FLAG) { + fs->max_erase_count = 0; + } + + return res; +} + + +static s32_t spiffs_obj_lu_scan_v( + spiffs *fs, + spiffs_obj_id obj_id, + spiffs_block_ix bix, + int ix_entry, + u32_t user_data, + void *user_p) { + (void)bix; + (void)user_data; + (void)user_p; + if (obj_id == SPIFFS_OBJ_ID_FREE) { + if (ix_entry == 0) { + fs->free_blocks++; + // todo optimize further, return SPIFFS_NEXT_BLOCK + } + } else if (obj_id == SPIFFS_OBJ_ID_DELETED) { + fs->stats_p_deleted++; + } else { + fs->stats_p_allocated++; + } + + return SPIFFS_VIS_COUNTINUE; +} + + +// Scans thru all obj lu and counts free, deleted and used pages +// Find the maximum block erase count +// Checks magic if enabled +s32_t spiffs_obj_lu_scan( + spiffs *fs) { + s32_t res; + spiffs_block_ix bix; + int entry; +#if SPIFFS_USE_MAGIC + spiffs_block_ix unerased_bix = (spiffs_block_ix)-1; +#endif + + // find out erase count + // if enabled, check magic + bix = 0; + spiffs_obj_id erase_count_final; + spiffs_obj_id erase_count_min = SPIFFS_OBJ_ID_FREE; + spiffs_obj_id erase_count_max = 0; + while (bix < fs->block_count) { +#if SPIFFS_USE_MAGIC + spiffs_obj_id magic; + res = _spiffs_rd(fs, + SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_MAGIC_PADDR(fs, bix) , + sizeof(spiffs_obj_id), (u8_t *)&magic); + + SPIFFS_CHECK_RES(res); + if (magic != SPIFFS_MAGIC(fs)) { + if (unerased_bix == (spiffs_block_ix)-1) { + // allow one unerased block as it might be powered down during an erase + unerased_bix = bix; + } else { + // more than one unerased block, bail out + SPIFFS_CHECK_RES(SPIFFS_ERR_NOT_A_FS); + } + } +#endif + spiffs_obj_id erase_count; + res = _spiffs_rd(fs, + SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_ERASE_COUNT_PADDR(fs, bix) , + sizeof(spiffs_obj_id), (u8_t *)&erase_count); + SPIFFS_CHECK_RES(res); + if (erase_count != SPIFFS_OBJ_ID_FREE) { + erase_count_min = MIN(erase_count_min, erase_count); + erase_count_max = MAX(erase_count_max, erase_count); + } + bix++; + } + + if (erase_count_min == 0 && erase_count_max == SPIFFS_OBJ_ID_FREE) { + // clean system, set counter to zero + erase_count_final = 0; + } else if (erase_count_max - erase_count_min > (SPIFFS_OBJ_ID_FREE)/2) { + // wrap, take min + erase_count_final = erase_count_min+1; + } else { + erase_count_final = erase_count_max+1; + } + + fs->max_erase_count = erase_count_final; + +#if SPIFFS_USE_MAGIC + if (unerased_bix != (spiffs_block_ix)-1) { + // found one unerased block, remedy + SPIFFS_DBG("mount: erase block %i\n", bix); + res = spiffs_erase_block(fs, unerased_bix); + SPIFFS_CHECK_RES(res); + } +#endif + + // count blocks + + fs->free_blocks = 0; + fs->stats_p_allocated = 0; + fs->stats_p_deleted = 0; + + res = spiffs_obj_lu_find_entry_visitor(fs, + 0, + 0, + 0, + 0, + spiffs_obj_lu_scan_v, + 0, + 0, + &bix, + &entry); + + if (res == SPIFFS_VIS_END) { + res = SPIFFS_OK; + } + + SPIFFS_CHECK_RES(res); + + return res; +} + +// Find free object lookup entry +// Iterate over object lookup pages in each block until a free object id entry is found +s32_t spiffs_obj_lu_find_free( + spiffs *fs, + spiffs_block_ix starting_block, + int starting_lu_entry, + spiffs_block_ix *block_ix, + int *lu_entry) { + s32_t res; + if (!fs->cleaning && fs->free_blocks < 2) { + res = spiffs_gc_quick(fs, 0); + if (res == SPIFFS_ERR_NO_DELETED_BLOCKS) { + res = SPIFFS_OK; + } + SPIFFS_CHECK_RES(res); + if (fs->free_blocks < 2) { + return SPIFFS_ERR_FULL; + } + } + res = spiffs_obj_lu_find_id(fs, starting_block, starting_lu_entry, + SPIFFS_OBJ_ID_FREE, block_ix, lu_entry); + if (res == SPIFFS_OK) { + fs->free_cursor_block_ix = *block_ix; + fs->free_cursor_obj_lu_entry = *lu_entry; + if (*lu_entry == 0) { + fs->free_blocks--; + } + } + if (res == SPIFFS_VIS_END) { + SPIFFS_DBG("fs full\n"); + } + + return res == SPIFFS_VIS_END ? SPIFFS_ERR_FULL : res; +} + +// Find object lookup entry containing given id +// Iterate over object lookup pages in each block until a given object id entry is found +s32_t spiffs_obj_lu_find_id( + spiffs *fs, + spiffs_block_ix starting_block, + int starting_lu_entry, + spiffs_obj_id obj_id, + spiffs_block_ix *block_ix, + int *lu_entry) { + s32_t res = spiffs_obj_lu_find_entry_visitor( + fs, starting_block, starting_lu_entry, SPIFFS_VIS_CHECK_ID, obj_id, 0, 0, 0, block_ix, lu_entry); + if (res == SPIFFS_VIS_END) { + res = SPIFFS_ERR_NOT_FOUND; + } + return res; +} + + +static s32_t spiffs_obj_lu_find_id_and_span_v( + spiffs *fs, + spiffs_obj_id obj_id, + spiffs_block_ix bix, + int ix_entry, + u32_t user_data, + void *user_p) { + s32_t res; + spiffs_page_header ph; + spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry); + res = _spiffs_rd(fs, 0, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_header), (u8_t *)&ph); + SPIFFS_CHECK_RES(res); + if (ph.obj_id == obj_id && + ph.span_ix == (spiffs_span_ix)user_data && + (ph.flags & (SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_USED)) == SPIFFS_PH_FLAG_DELET && + !((obj_id & SPIFFS_OBJ_ID_IX_FLAG) && (ph.flags & SPIFFS_PH_FLAG_IXDELE) == 0 && ph.span_ix == 0) && + (user_p == 0 || *((spiffs_page_ix *)user_p) != pix)) { + return SPIFFS_OK; + } else { + return SPIFFS_VIS_COUNTINUE; + } +} + +// Find object lookup entry containing given id and span index +// Iterate over object lookup pages in each block until a given object id entry is found +s32_t spiffs_obj_lu_find_id_and_span( + spiffs *fs, + spiffs_obj_id obj_id, + spiffs_span_ix spix, + spiffs_page_ix exclusion_pix, + spiffs_page_ix *pix) { + s32_t res; + spiffs_block_ix bix; + int entry; + + res = spiffs_obj_lu_find_entry_visitor(fs, + fs->cursor_block_ix, + fs->cursor_obj_lu_entry, + SPIFFS_VIS_CHECK_ID, + obj_id, + spiffs_obj_lu_find_id_and_span_v, + (u32_t)spix, + exclusion_pix ? &exclusion_pix : 0, + &bix, + &entry); + + if (res == SPIFFS_VIS_END) { + res = SPIFFS_ERR_NOT_FOUND; + } + + SPIFFS_CHECK_RES(res); + + if (pix) { + *pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry); + } + + fs->cursor_block_ix = bix; + fs->cursor_obj_lu_entry = entry; + + return res; +} + +// Find object lookup entry containing given id and span index in page headers only +// Iterate over object lookup pages in each block until a given object id entry is found +s32_t spiffs_obj_lu_find_id_and_span_by_phdr( + spiffs *fs, + spiffs_obj_id obj_id, + spiffs_span_ix spix, + spiffs_page_ix exclusion_pix, + spiffs_page_ix *pix) { + s32_t res; + spiffs_block_ix bix; + int entry; + + res = spiffs_obj_lu_find_entry_visitor(fs, + fs->cursor_block_ix, + fs->cursor_obj_lu_entry, + SPIFFS_VIS_CHECK_PH, + obj_id, + spiffs_obj_lu_find_id_and_span_v, + (u32_t)spix, + exclusion_pix ? &exclusion_pix : 0, + &bix, + &entry); + + if (res == SPIFFS_VIS_END) { + res = SPIFFS_ERR_NOT_FOUND; + } + + SPIFFS_CHECK_RES(res); + + if (pix) { + *pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry); + } + + fs->cursor_block_ix = bix; + fs->cursor_obj_lu_entry = entry; + + return res; +} + +// Allocates a free defined page with given obj_id +// Occupies object lookup entry and page +// data may be NULL; where only page header is stored, len and page_offs is ignored +s32_t spiffs_page_allocate_data( + spiffs *fs, + spiffs_obj_id obj_id, + spiffs_page_header *ph, + u8_t *data, + u32_t len, + u32_t page_offs, + u8_t finalize, + spiffs_page_ix *pix) { + s32_t res = SPIFFS_OK; + spiffs_block_ix bix; + int entry; + + // find free entry + res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry); + SPIFFS_CHECK_RES(res); + + // occupy page in object lookup + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT, + 0, SPIFFS_BLOCK_TO_PADDR(fs, bix) + entry * sizeof(spiffs_obj_id), sizeof(spiffs_obj_id), (u8_t*)&obj_id); + SPIFFS_CHECK_RES(res); + + fs->stats_p_allocated++; + + // write page header + ph->flags &= ~SPIFFS_PH_FLAG_USED; + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT, + 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, entry), sizeof(spiffs_page_header), (u8_t*)ph); + SPIFFS_CHECK_RES(res); + + // write page data + if (data) { + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT, + 0,SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, entry) + sizeof(spiffs_page_header) + page_offs, len, data); + SPIFFS_CHECK_RES(res); + } + + // finalize header if necessary + if (finalize && (ph->flags & SPIFFS_PH_FLAG_FINAL)) { + ph->flags &= ~SPIFFS_PH_FLAG_FINAL; + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT, + 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, entry) + offsetof(spiffs_page_header, flags), + sizeof(u8_t), + (u8_t *)&ph->flags); + SPIFFS_CHECK_RES(res); + } + + // return written page + if (pix) { + *pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry); + } + + return res; +} + +// Moves a page from src to a free page and finalizes it. Updates page index. Page data is given in param page. +// If page data is null, provided header is used for metainfo and page data is physically copied. +s32_t spiffs_page_move( + spiffs *fs, + spiffs_file fh, + u8_t *page_data, + spiffs_obj_id obj_id, + spiffs_page_header *page_hdr, + spiffs_page_ix src_pix, + spiffs_page_ix *dst_pix) { + s32_t res; + u8_t was_final = 0; + spiffs_page_header *p_hdr; + spiffs_block_ix bix; + int entry; + spiffs_page_ix free_pix; + + // find free entry + res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry); + SPIFFS_CHECK_RES(res); + free_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry); + + if (dst_pix) *dst_pix = free_pix; + + p_hdr = page_data ? (spiffs_page_header *)page_data : page_hdr; + if (page_data) { + // got page data + was_final = (p_hdr->flags & SPIFFS_PH_FLAG_FINAL) == 0; + // write unfinalized page + p_hdr->flags |= SPIFFS_PH_FLAG_FINAL; + p_hdr->flags &= ~SPIFFS_PH_FLAG_USED; + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT, + 0, SPIFFS_PAGE_TO_PADDR(fs, free_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), page_data); + } else { + // copy page data + res = spiffs_phys_cpy(fs, fh, SPIFFS_PAGE_TO_PADDR(fs, free_pix), SPIFFS_PAGE_TO_PADDR(fs, src_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs)); + } + SPIFFS_CHECK_RES(res); + + // mark entry in destination object lookup + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT, + 0, SPIFFS_BLOCK_TO_PADDR(fs, SPIFFS_BLOCK_FOR_PAGE(fs, free_pix)) + SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, free_pix) * sizeof(spiffs_page_ix), + sizeof(spiffs_obj_id), + (u8_t *)&obj_id); + SPIFFS_CHECK_RES(res); + + fs->stats_p_allocated++; + + if (was_final) { + // mark finalized in destination page + p_hdr->flags &= ~(SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_USED); + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT, + fh, + SPIFFS_PAGE_TO_PADDR(fs, free_pix) + offsetof(spiffs_page_header, flags), + sizeof(u8_t), + (u8_t *)&p_hdr->flags); + SPIFFS_CHECK_RES(res); + } + // mark source deleted + res = spiffs_page_delete(fs, src_pix); + return res; +} + +// Deletes a page and removes it from object lookup. +s32_t spiffs_page_delete( + spiffs *fs, + spiffs_page_ix pix) { + s32_t res; + spiffs_page_header hdr; + hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_USED); + // mark deleted entry in source object lookup + spiffs_obj_id d_obj_id = SPIFFS_OBJ_ID_DELETED; + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_DELE, + 0, + SPIFFS_BLOCK_TO_PADDR(fs, SPIFFS_BLOCK_FOR_PAGE(fs, pix)) + SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, pix) * sizeof(spiffs_page_ix), + sizeof(spiffs_obj_id), + (u8_t *)&d_obj_id); + SPIFFS_CHECK_RES(res); + + fs->stats_p_deleted++; + fs->stats_p_allocated--; + + // mark deleted in source page + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_DELE, + 0, + SPIFFS_PAGE_TO_PADDR(fs, pix) + offsetof(spiffs_page_header, flags), + sizeof(u8_t), + (u8_t *)&hdr.flags); + + return res; +} + +// Create an object index header page with empty index and undefined length +s32_t spiffs_object_create( + spiffs *fs, + spiffs_obj_id obj_id, + u8_t name[SPIFFS_OBJ_NAME_LEN], + spiffs_obj_type type, + spiffs_page_ix *objix_hdr_pix) { + s32_t res = SPIFFS_OK; + spiffs_block_ix bix; + spiffs_page_object_ix_header oix_hdr; + int entry; + + res = spiffs_gc_check(fs, SPIFFS_DATA_PAGE_SIZE(fs)); + SPIFFS_CHECK_RES(res); + + obj_id |= SPIFFS_OBJ_ID_IX_FLAG; + + // find free entry + res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry); + SPIFFS_CHECK_RES(res); + SPIFFS_DBG("create: found free page @ %04x bix:%i entry:%i\n", SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry), bix, entry); + + // occupy page in object lookup + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT, + 0, SPIFFS_BLOCK_TO_PADDR(fs, bix) + entry * sizeof(spiffs_obj_id), sizeof(spiffs_obj_id), (u8_t*)&obj_id); + SPIFFS_CHECK_RES(res); + + fs->stats_p_allocated++; + + // write empty object index page + oix_hdr.p_hdr.obj_id = obj_id; + oix_hdr.p_hdr.span_ix = 0; + oix_hdr.p_hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED); + oix_hdr.type = type; + oix_hdr.size = SPIFFS_UNDEFINED_LEN; // keep ones so we can update later without wasting this page + strncpy((char *)&oix_hdr.name, (char *)name, SPIFFS_OBJ_NAME_LEN); + + + // update page + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT, + 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, entry), sizeof(spiffs_page_object_ix_header), (u8_t*)&oix_hdr); + + SPIFFS_CHECK_RES(res); + spiffs_cb_object_event(fs, 0, SPIFFS_EV_IX_NEW, obj_id, 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry), SPIFFS_UNDEFINED_LEN); + + if (objix_hdr_pix) { + *objix_hdr_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry); + } + + return res; +} + +// update object index header with any combination of name/size/index +// new_objix_hdr_data may be null, if so the object index header page is loaded +// name may be null, if so name is not changed +// size may be null, if so size is not changed +s32_t spiffs_object_update_index_hdr( + spiffs *fs, + spiffs_fd *fd, + spiffs_obj_id obj_id, + spiffs_page_ix objix_hdr_pix, + u8_t *new_objix_hdr_data, + u8_t name[SPIFFS_OBJ_NAME_LEN], + u32_t size, + spiffs_page_ix *new_pix) { + s32_t res = SPIFFS_OK; + spiffs_page_object_ix_header *objix_hdr; + spiffs_page_ix new_objix_hdr_pix; + + obj_id |= SPIFFS_OBJ_ID_IX_FLAG; + + if (new_objix_hdr_data) { + // object index header page already given to us, no need to load it + objix_hdr = (spiffs_page_object_ix_header *)new_objix_hdr_data; + } else { + // read object index header page + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, + fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, objix_hdr_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); + SPIFFS_CHECK_RES(res); + objix_hdr = (spiffs_page_object_ix_header *)fs->work; + } + + SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, obj_id, 0); + + // change name + if (name) { + strncpy((char *)objix_hdr->name, (char *)name, SPIFFS_OBJ_NAME_LEN); + } + if (size) { + objix_hdr->size = size; + } + + // move and update page + res = spiffs_page_move(fs, fd == 0 ? 0 : fd->file_nbr, (u8_t*)objix_hdr, obj_id, 0, objix_hdr_pix, &new_objix_hdr_pix); + + if (res == SPIFFS_OK) { + if (new_pix) { + *new_pix = new_objix_hdr_pix; + } + // callback on object index update + spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_UPD, obj_id, objix_hdr->p_hdr.span_ix, new_objix_hdr_pix, objix_hdr->size); + if (fd) fd->objix_hdr_pix = new_objix_hdr_pix; // if this is not in the registered cluster + } + + return res; +} + +void spiffs_cb_object_event( + spiffs *fs, + spiffs_fd *fd, + int ev, + spiffs_obj_id obj_id, + spiffs_span_ix spix, + spiffs_page_ix new_pix, + u32_t new_size) { + (void)fd; + // update index caches in all file descriptors + obj_id &= ~SPIFFS_OBJ_ID_IX_FLAG; + u32_t i; + spiffs_fd *fds = (spiffs_fd *)fs->fd_space; + for (i = 0; i < fs->fd_count; i++) { + spiffs_fd *cur_fd = &fds[i]; + if (cur_fd->file_nbr == 0 || (cur_fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != obj_id) continue; + if (spix == 0) { + if (ev == SPIFFS_EV_IX_NEW || ev == SPIFFS_EV_IX_UPD) { + SPIFFS_DBG(" callback: setting fd %i:%04x objix_hdr_pix to %04x, size:%i\n", cur_fd->file_nbr, cur_fd->obj_id, new_pix, new_size); + cur_fd->objix_hdr_pix = new_pix; + if (new_size != 0) { + cur_fd->size = new_size; + } + } else if (ev == SPIFFS_EV_IX_DEL) { + cur_fd->file_nbr = 0; + cur_fd->obj_id = SPIFFS_OBJ_ID_DELETED; + } + } + if (cur_fd->cursor_objix_spix == spix) { + if (ev == SPIFFS_EV_IX_NEW || ev == SPIFFS_EV_IX_UPD) { + SPIFFS_DBG(" callback: setting fd %i:%04x span:%04x objix_pix to %04x\n", cur_fd->file_nbr, cur_fd->obj_id, spix, new_pix); + cur_fd->cursor_objix_pix = new_pix; + } else { + cur_fd->cursor_objix_pix = 0; + } + } + } +} + +// Open object by id +s32_t spiffs_object_open_by_id( + spiffs *fs, + spiffs_obj_id obj_id, + spiffs_fd *fd, + spiffs_flags flags, + spiffs_mode mode) { + s32_t res = SPIFFS_OK; + spiffs_page_ix pix; + + res = spiffs_obj_lu_find_id_and_span(fs, obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix); + SPIFFS_CHECK_RES(res); + + res = spiffs_object_open_by_page(fs, pix, fd, flags, mode); + + return res; +} + +// Open object by page index +s32_t spiffs_object_open_by_page( + spiffs *fs, + spiffs_page_ix pix, + spiffs_fd *fd, + spiffs_flags flags, + spiffs_mode mode) { + (void)mode; + s32_t res = SPIFFS_OK; + spiffs_page_object_ix_header oix_hdr; + spiffs_obj_id obj_id; + + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, + fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&oix_hdr); + SPIFFS_CHECK_RES(res); + + spiffs_block_ix bix = SPIFFS_BLOCK_FOR_PAGE(fs, pix); + int entry = SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, pix); + + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, + 0, SPIFFS_BLOCK_TO_PADDR(fs, bix) + entry * sizeof(spiffs_obj_id), sizeof(spiffs_obj_id), (u8_t *)&obj_id); + + fd->fs = fs; + fd->objix_hdr_pix = pix; + fd->size = oix_hdr.size; + fd->offset = 0; + fd->cursor_objix_pix = pix; + fd->cursor_objix_spix = 0; + fd->obj_id = obj_id; + fd->flags = flags; + + SPIFFS_VALIDATE_OBJIX(oix_hdr.p_hdr, fd->obj_id, 0); + + SPIFFS_DBG("open: fd %i is obj id %04x\n", fd->file_nbr, fd->obj_id); + + return res; +} + +// Append to object +// keep current object index (header) page in fs->work buffer +s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { + spiffs *fs = fd->fs; + s32_t res = SPIFFS_OK; + u32_t written = 0; + + SPIFFS_DBG("append: %i bytes @ offs %i of size %i\n", len, offset, fd->size); + + if (offset > fd->size) { + SPIFFS_DBG("append: offset reversed to size\n"); + offset = fd->size; + } + + res = spiffs_gc_check(fs, len + SPIFFS_DATA_PAGE_SIZE(fs)); // add an extra page of data worth for meta + if (res != SPIFFS_OK) { + SPIFFS_DBG("append: gc check fail %i\n", res); + } + SPIFFS_CHECK_RES(res); + + spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work; + spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work; + spiffs_page_header p_hdr; + + spiffs_span_ix cur_objix_spix = 0; + spiffs_span_ix prev_objix_spix = (spiffs_span_ix)-1; + spiffs_page_ix cur_objix_pix = fd->objix_hdr_pix; + spiffs_page_ix new_objix_hdr_page; + + spiffs_span_ix data_spix = offset / SPIFFS_DATA_PAGE_SIZE(fs); + spiffs_page_ix data_page; + u32_t page_offs = offset % SPIFFS_DATA_PAGE_SIZE(fs); + + // write all data + while (res == SPIFFS_OK && written < len) { + // calculate object index page span index + cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix); + + // handle storing and loading of object indices + if (cur_objix_spix != prev_objix_spix) { + // new object index page + // within this clause we return directly if something fails, object index mess-up + if (written > 0) { + // store previous object index page, unless first pass + SPIFFS_DBG("append: %04x store objix %04x:%04x, written %i\n", fd->obj_id, + cur_objix_pix, prev_objix_spix, written); + if (prev_objix_spix == 0) { + // this is an update to object index header page + objix_hdr->size = offset+written; + if (offset == 0) { + // was an empty object, update same page (size was 0xffffffff) + res = spiffs_page_index_check(fs, fd, cur_objix_pix, 0); + SPIFFS_CHECK_RES(res); + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT, + fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); + SPIFFS_CHECK_RES(res); + } else { + // was a nonempty object, update to new page + res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, + fd->objix_hdr_pix, fs->work, 0, offset+written, &new_objix_hdr_page); + SPIFFS_CHECK_RES(res); + SPIFFS_DBG("append: %04x store new objix_hdr, %04x:%04x, written %i\n", fd->obj_id, + new_objix_hdr_page, 0, written); + } + } else { + // this is an update to an object index page + res = spiffs_page_index_check(fs, fd, cur_objix_pix, prev_objix_spix); + SPIFFS_CHECK_RES(res); + + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT, + fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); + SPIFFS_CHECK_RES(res); + spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_UPD,fd->obj_id, objix->p_hdr.span_ix, cur_objix_pix, 0); + // update length in object index header page + res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, + fd->objix_hdr_pix, 0, 0, offset+written, &new_objix_hdr_page); + SPIFFS_CHECK_RES(res); + SPIFFS_DBG("append: %04x store new size I %i in objix_hdr, %04x:%04x, written %i\n", fd->obj_id, + offset+written, new_objix_hdr_page, 0, written); + } + fd->size = offset+written; + fd->offset = offset+written; + } + + // create or load new object index page + if (cur_objix_spix == 0) { + // load object index header page, must always exist + SPIFFS_DBG("append: %04x load objixhdr page %04x:%04x\n", fd->obj_id, cur_objix_pix, cur_objix_spix); + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, + fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); + SPIFFS_CHECK_RES(res); + SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix); + } else { + spiffs_span_ix len_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, (fd->size-1)/SPIFFS_DATA_PAGE_SIZE(fs)); + // on subsequent passes, create a new object index page + if (written > 0 || cur_objix_spix > len_objix_spix) { + p_hdr.obj_id = fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG; + p_hdr.span_ix = cur_objix_spix; + p_hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX); + res = spiffs_page_allocate_data(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, + &p_hdr, 0, 0, 0, 1, &cur_objix_pix); + SPIFFS_CHECK_RES(res); + spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_NEW, fd->obj_id, cur_objix_spix, cur_objix_pix, 0); + // quick "load" of new object index page + memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs)); + memcpy(fs->work, &p_hdr, sizeof(spiffs_page_header)); + SPIFFS_DBG("append: %04x create objix page, %04x:%04x, written %i\n", fd->obj_id + , cur_objix_pix, cur_objix_spix, written); + } else { + // on first pass, we load existing object index page + spiffs_page_ix pix; + SPIFFS_DBG("append: %04x find objix span_ix:%04x\n", fd->obj_id, cur_objix_spix); + if (fd->cursor_objix_spix == cur_objix_spix) { + pix = fd->cursor_objix_pix; + } else { + res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &pix); + SPIFFS_CHECK_RES(res); + } + SPIFFS_DBG("append: %04x found object index at page %04x [fd size %i]\n", fd->obj_id, pix, fd->size); + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, + fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); + SPIFFS_CHECK_RES(res); + SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix); + cur_objix_pix = pix; + } + fd->cursor_objix_pix = cur_objix_pix; + fd->cursor_objix_spix = cur_objix_spix; + fd->offset = offset+written; + fd->size = offset+written; + } + prev_objix_spix = cur_objix_spix; + } + + // write data + u32_t to_write = MIN(len-written, SPIFFS_DATA_PAGE_SIZE(fs) - page_offs); + if (page_offs == 0) { + // at beginning of a page, allocate and write a new page of data + p_hdr.obj_id = fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG; + p_hdr.span_ix = data_spix; + p_hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL); // finalize immediately + res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, + &p_hdr, &data[written], to_write, page_offs, 1, &data_page); + SPIFFS_DBG("append: %04x store new data page, %04x:%04x offset:%i, len %i, written %i\n", fd->obj_id, + data_page, data_spix, page_offs, to_write, written); + } else { + // append to existing page, fill out free data in existing page + if (cur_objix_spix == 0) { + // get data page from object index header page + data_page = ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix]; + } else { + // get data page from object index page + data_page = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)]; + } + + res = spiffs_page_data_check(fs, fd, data_page, data_spix); + SPIFFS_CHECK_RES(res); + + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT, + fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, data_page) + sizeof(spiffs_page_header) + page_offs, to_write, &data[written]); + SPIFFS_DBG("append: %04x store to existing data page, %04x:%04x offset:%i, len %i, written %i\n", fd->obj_id + , data_page, data_spix, page_offs, to_write, written); + } + + if (res != SPIFFS_OK) break; + + // update memory representation of object index page with new data page + if (cur_objix_spix == 0) { + // update object index header page + ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = data_page; + SPIFFS_DBG("append: %04x wrote page %04x to objix_hdr entry %02x in mem\n", fd->obj_id + , data_page, data_spix); + objix_hdr->size = offset+written; + } else { + // update object index page + ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = data_page; + SPIFFS_DBG("append: %04x wrote page %04x to objix entry %02x in mem\n", fd->obj_id + , data_page, SPIFFS_OBJ_IX_ENTRY(fs, data_spix)); + } + + // update internals + page_offs = 0; + data_spix++; + written += to_write; + } // while all data + + fd->size = offset+written; + fd->offset = offset+written; + fd->cursor_objix_pix = cur_objix_pix; + fd->cursor_objix_spix = cur_objix_spix; + + // finalize updated object indices + s32_t res2 = SPIFFS_OK; + if (cur_objix_spix != 0) { + // wrote beyond object index header page + // write last modified object index page, unless object header index page + SPIFFS_DBG("append: %04x store objix page, %04x:%04x, written %i\n", fd->obj_id, + cur_objix_pix, cur_objix_spix, written); + + res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix); + SPIFFS_CHECK_RES(res2); + + res2 = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT, + fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); + SPIFFS_CHECK_RES(res2); + spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, cur_objix_pix, 0); + + // update size in object header index page + res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, + fd->objix_hdr_pix, 0, 0, offset+written, &new_objix_hdr_page); + SPIFFS_DBG("append: %04x store new size II %i in objix_hdr, %04x:%04x, written %i, res %i\n", fd->obj_id + , offset+written, new_objix_hdr_page, 0, written, res2); + SPIFFS_CHECK_RES(res2); + } else { + // wrote within object index header page + if (offset == 0) { + // wrote to empty object - simply update size and write whole page + objix_hdr->size = offset+written; + SPIFFS_DBG("append: %04x store fresh objix_hdr page, %04x:%04x, written %i\n", fd->obj_id + , cur_objix_pix, cur_objix_spix, written); + + res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix); + SPIFFS_CHECK_RES(res2); + + res2 = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT, + fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); + SPIFFS_CHECK_RES(res2); + // callback on object index update + spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_UPD, fd->obj_id, objix_hdr->p_hdr.span_ix, cur_objix_pix, objix_hdr->size); + } else { + // modifying object index header page, update size and make new copy + res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, + fd->objix_hdr_pix, fs->work, 0, offset+written, &new_objix_hdr_page); + SPIFFS_DBG("append: %04x store modified objix_hdr page, %04x:%04x, written %i\n", fd->obj_id + , new_objix_hdr_page, 0, written); + SPIFFS_CHECK_RES(res2); + } + } + + return res; +} + +// Modify object +// keep current object index (header) page in fs->work buffer +s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { + spiffs *fs = fd->fs; + s32_t res = SPIFFS_OK; + u32_t written = 0; + + res = spiffs_gc_check(fs, len + SPIFFS_DATA_PAGE_SIZE(fs)); + SPIFFS_CHECK_RES(res); + + spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work; + spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work; + spiffs_page_header p_hdr; + + spiffs_span_ix cur_objix_spix = 0; + spiffs_span_ix prev_objix_spix = (spiffs_span_ix)-1; + spiffs_page_ix cur_objix_pix = fd->objix_hdr_pix; + spiffs_page_ix new_objix_hdr_pix; + + spiffs_span_ix data_spix = offset / SPIFFS_DATA_PAGE_SIZE(fs); + spiffs_page_ix data_pix; + u32_t page_offs = offset % SPIFFS_DATA_PAGE_SIZE(fs); + + + // write all data + while (res == SPIFFS_OK && written < len) { + // calculate object index page span index + cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix); + + // handle storing and loading of object indices + if (cur_objix_spix != prev_objix_spix) { + // new object index page + // within this clause we return directly if something fails, object index mess-up + if (written > 0) { + // store previous object index (header) page, unless first pass + if (prev_objix_spix == 0) { + // store previous object index header page + res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, + fd->objix_hdr_pix, fs->work, 0, 0, &new_objix_hdr_pix); + SPIFFS_DBG("modify: store modified objix_hdr page, %04x:%04x, written %i\n", new_objix_hdr_pix, 0, written); + SPIFFS_CHECK_RES(res); + } else { + // store new version of previous object index page + spiffs_page_ix new_objix_pix; + + res = spiffs_page_index_check(fs, fd, cur_objix_pix, prev_objix_spix); + SPIFFS_CHECK_RES(res); + + res = spiffs_page_move(fs, fd->file_nbr, (u8_t*)objix, fd->obj_id, 0, cur_objix_pix, &new_objix_pix); + SPIFFS_DBG("modify: store previous modified objix page, %04x:%04x, written %i\n", new_objix_pix, objix->p_hdr.span_ix, written); + SPIFFS_CHECK_RES(res); + spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, new_objix_pix, 0); + } + } + + // load next object index page + if (cur_objix_spix == 0) { + // load object index header page, must exist + SPIFFS_DBG("modify: load objixhdr page %04x:%04x\n", cur_objix_pix, cur_objix_spix); + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, + fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); + SPIFFS_CHECK_RES(res); + SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix); + } else { + // load existing object index page on first pass + spiffs_page_ix pix; + SPIFFS_DBG("modify: find objix span_ix:%04x\n", cur_objix_spix); + if (fd->cursor_objix_spix == cur_objix_spix) { + pix = fd->cursor_objix_pix; + } else { + res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &pix); + SPIFFS_CHECK_RES(res); + } + SPIFFS_DBG("modify: found object index at page %04x\n", pix); + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, + fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); + SPIFFS_CHECK_RES(res); + SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix); + cur_objix_pix = pix; + } + fd->cursor_objix_pix = cur_objix_pix; + fd->cursor_objix_spix = cur_objix_spix; + fd->offset = offset+written; + prev_objix_spix = cur_objix_spix; + } + + // write partial data + u32_t to_write = MIN(len-written, SPIFFS_DATA_PAGE_SIZE(fs) - page_offs); + spiffs_page_ix orig_data_pix; + if (cur_objix_spix == 0) { + // get data page from object index header page + orig_data_pix = ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix]; + } else { + // get data page from object index page + orig_data_pix = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)]; + } + + p_hdr.obj_id = fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG; + p_hdr.span_ix = data_spix; + p_hdr.flags = 0xff; + if (page_offs == 0 && to_write == SPIFFS_DATA_PAGE_SIZE(fs)) { + // a full page, allocate and write a new page of data + res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, + &p_hdr, &data[written], to_write, page_offs, 1, &data_pix); + SPIFFS_DBG("modify: store new data page, %04x:%04x offset:%i, len %i, written %i\n", data_pix, data_spix, page_offs, to_write, written); + } else { + // write to existing page, allocate new and copy unmodified data + + res = spiffs_page_data_check(fs, fd, orig_data_pix, data_spix); + SPIFFS_CHECK_RES(res); + + res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, + &p_hdr, 0, 0, 0, 0, &data_pix); + if (res != SPIFFS_OK) break; + + // copy unmodified data + if (page_offs > 0) { + // before modification + res = spiffs_phys_cpy(fs, fd->file_nbr, + SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header), + SPIFFS_PAGE_TO_PADDR(fs, orig_data_pix) + sizeof(spiffs_page_header), + page_offs); + if (res != SPIFFS_OK) break; + } + if (page_offs + to_write < SPIFFS_DATA_PAGE_SIZE(fs)) { + // after modification + res = spiffs_phys_cpy(fs, fd->file_nbr, + SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + page_offs + to_write, + SPIFFS_PAGE_TO_PADDR(fs, orig_data_pix) + sizeof(spiffs_page_header) + page_offs + to_write, + SPIFFS_DATA_PAGE_SIZE(fs) - (page_offs + to_write)); + if (res != SPIFFS_OK) break; + } + + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT, + fd->file_nbr, + SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + page_offs, to_write, &data[written]); + if (res != SPIFFS_OK) break; + p_hdr.flags &= ~SPIFFS_PH_FLAG_FINAL; + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT, + fd->file_nbr, + SPIFFS_PAGE_TO_PADDR(fs, data_pix) + offsetof(spiffs_page_header, flags), + sizeof(u8_t), + (u8_t *)&p_hdr.flags); + if (res != SPIFFS_OK) break; + + SPIFFS_DBG("modify: store to existing data page, src:%04x, dst:%04x:%04x offset:%i, len %i, written %i\n", orig_data_pix, data_pix, data_spix, page_offs, to_write, written); + } + + // delete original data page + res = spiffs_page_delete(fs, orig_data_pix); + if (res != SPIFFS_OK) break; + // update memory representation of object index page with new data page + if (cur_objix_spix == 0) { + // update object index header page + ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = data_pix; + SPIFFS_DBG("modify: wrote page %04x to objix_hdr entry %02x in mem\n", data_pix, data_spix); + } else { + // update object index page + ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = data_pix; + SPIFFS_DBG("modify: wrote page %04x to objix entry %02x in mem\n", data_pix, SPIFFS_OBJ_IX_ENTRY(fs, data_spix)); + } + + // update internals + page_offs = 0; + data_spix++; + written += to_write; + } // while all data + + fd->offset = offset+written; + fd->cursor_objix_pix = cur_objix_pix; + fd->cursor_objix_spix = cur_objix_spix; + + // finalize updated object indices + s32_t res2 = SPIFFS_OK; + if (cur_objix_spix != 0) { + // wrote beyond object index header page + // write last modified object index page + // move and update page + spiffs_page_ix new_objix_pix; + + res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix); + SPIFFS_CHECK_RES(res2); + + res2 = spiffs_page_move(fs, fd->file_nbr, (u8_t*)objix, fd->obj_id, 0, cur_objix_pix, &new_objix_pix); + SPIFFS_DBG("modify: store modified objix page, %04x:%04x, written %i\n", new_objix_pix, cur_objix_spix, written); + fd->cursor_objix_pix = new_objix_pix; + fd->cursor_objix_spix = cur_objix_spix; + SPIFFS_CHECK_RES(res2); + spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, new_objix_pix, 0); + + } else { + // wrote within object index header page + res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, + fd->objix_hdr_pix, fs->work, 0, 0, &new_objix_hdr_pix); + SPIFFS_DBG("modify: store modified objix_hdr page, %04x:%04x, written %i\n", new_objix_hdr_pix, 0, written); + SPIFFS_CHECK_RES(res2); + } + + return res; +} + +static s32_t spiffs_object_find_object_index_header_by_name_v( + spiffs *fs, + spiffs_obj_id obj_id, + spiffs_block_ix bix, + int ix_entry, + u32_t user_data, + void *user_p) { + (void)user_data; + s32_t res; + spiffs_page_object_ix_header objix_hdr; + spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry); + if (obj_id == SPIFFS_OBJ_ID_FREE || obj_id == SPIFFS_OBJ_ID_DELETED || + (obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0) { + return SPIFFS_VIS_COUNTINUE; + } + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr); + SPIFFS_CHECK_RES(res); + if (objix_hdr.p_hdr.span_ix == 0 && + (objix_hdr.p_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE)) == + (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) { + if (strcmp((char *)user_p, (char *)objix_hdr.name) == 0) { + return SPIFFS_OK; + } + } + + return SPIFFS_VIS_COUNTINUE; +} + +// Finds object index header page by name +s32_t spiffs_object_find_object_index_header_by_name( + spiffs *fs, + u8_t name[SPIFFS_OBJ_NAME_LEN], + spiffs_page_ix *pix) { + s32_t res; + spiffs_block_ix bix; + int entry; + + res = spiffs_obj_lu_find_entry_visitor(fs, + fs->cursor_block_ix, + fs->cursor_obj_lu_entry, + 0, + 0, + spiffs_object_find_object_index_header_by_name_v, + 0, + name, + &bix, + &entry); + + if (res == SPIFFS_VIS_END) { + res = SPIFFS_ERR_NOT_FOUND; + } + SPIFFS_CHECK_RES(res); + + if (pix) { + *pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry); + } + + fs->cursor_block_ix = bix; + fs->cursor_obj_lu_entry = entry; + + return res; +} + +// Truncates object to new size. If new size is null, object may be removed totally +s32_t spiffs_object_truncate( + spiffs_fd *fd, + u32_t new_size, + u8_t remove) { + s32_t res = SPIFFS_OK; + spiffs *fs = fd->fs; + + res = spiffs_gc_check(fs, remove ? 0 : SPIFFS_DATA_PAGE_SIZE(fs)); + SPIFFS_CHECK_RES(res); + + spiffs_page_ix objix_pix = fd->objix_hdr_pix; + spiffs_span_ix data_spix = (fd->size > 0 ? fd->size-1 : 0) / SPIFFS_DATA_PAGE_SIZE(fs); + u32_t cur_size = fd->size == (u32_t)SPIFFS_UNDEFINED_LEN ? 0 : fd->size ; + spiffs_span_ix cur_objix_spix = 0; + spiffs_span_ix prev_objix_spix = (spiffs_span_ix)-1; + spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work; + spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work; + spiffs_page_ix data_pix; + spiffs_page_ix new_objix_hdr_pix; + + // before truncating, check if object is to be fully removed and mark this + if (remove && new_size == 0) { + u8_t flags = ~( SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE); + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT, + fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, fd->objix_hdr_pix) + offsetof(spiffs_page_header, flags), + sizeof(u8_t), + (u8_t *)&flags); + SPIFFS_CHECK_RES(res); + } + + // delete from end of object until desired len is reached + while (cur_size > new_size) { + cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix); + + // put object index for current data span index in work buffer + if (prev_objix_spix != cur_objix_spix) { + if (prev_objix_spix != (spiffs_span_ix)-1) { + // remove previous object index page + SPIFFS_DBG("truncate: delete objix page %04x:%04x\n", objix_pix, prev_objix_spix); + + res = spiffs_page_index_check(fs, fd, objix_pix, prev_objix_spix); + SPIFFS_CHECK_RES(res); + + res = spiffs_page_delete(fs, objix_pix); + SPIFFS_CHECK_RES(res); + spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_DEL, fd->obj_id, objix->p_hdr.span_ix, objix_pix, 0); + if (prev_objix_spix > 0) { + // update object index header page + SPIFFS_DBG("truncate: update objix hdr page %04x:%04x to size %i\n", fd->objix_hdr_pix, prev_objix_spix, cur_size); + res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, + fd->objix_hdr_pix, 0, 0, cur_size, &new_objix_hdr_pix); + SPIFFS_CHECK_RES(res); + fd->size = cur_size; + } + } + // load current object index (header) page + if (cur_objix_spix == 0) { + objix_pix = fd->objix_hdr_pix; + } else { + res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &objix_pix); + SPIFFS_CHECK_RES(res); + } + + SPIFFS_DBG("truncate: load objix page %04x:%04x for data spix:%04x\n", objix_pix, cur_objix_spix, data_spix); + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, + fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); + SPIFFS_CHECK_RES(res); + SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix); + fd->cursor_objix_pix = objix_pix; + fd->cursor_objix_spix = cur_objix_spix; + fd->offset = cur_size; + + prev_objix_spix = cur_objix_spix; + } + + if (cur_objix_spix == 0) { + // get data page from object index header page + data_pix = ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix]; + ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = SPIFFS_OBJ_ID_FREE; + } else { + // get data page from object index page + data_pix = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)]; + ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = SPIFFS_OBJ_ID_FREE; + } + + SPIFFS_DBG("truncate: got data pix %04x\n", data_pix); + + if (cur_size - SPIFFS_DATA_PAGE_SIZE(fs) >= new_size) { + // delete full data page + res = spiffs_page_data_check(fs, fd, data_pix, data_spix); + if (res != SPIFFS_ERR_DELETED && res != SPIFFS_OK && res != SPIFFS_ERR_INDEX_REF_FREE) { + SPIFFS_DBG("truncate: err validating data pix %i\n", res); + break; + } + + if (res == SPIFFS_OK) { + res = spiffs_page_delete(fs, data_pix); + if (res != SPIFFS_OK) { + SPIFFS_DBG("truncate: err deleting data pix %i\n", res); + break; + } + } else if (res == SPIFFS_ERR_DELETED || res == SPIFFS_ERR_INDEX_REF_FREE) { + res = SPIFFS_OK; + } + + // update current size + if (cur_size % SPIFFS_DATA_PAGE_SIZE(fs) == 0) { + cur_size -= SPIFFS_DATA_PAGE_SIZE(fs); + } else { + cur_size -= cur_size % SPIFFS_DATA_PAGE_SIZE(fs); + } + fd->size = cur_size; + fd->offset = cur_size; + SPIFFS_DBG("truncate: delete data page %04x for data spix:%04x, cur_size:%i\n", data_pix, data_spix, cur_size); + } else { + // delete last page, partially + spiffs_page_header p_hdr; + spiffs_page_ix new_data_pix; + u32_t bytes_to_remove = SPIFFS_DATA_PAGE_SIZE(fs) - (new_size % SPIFFS_DATA_PAGE_SIZE(fs)); + SPIFFS_DBG("truncate: delete %i bytes from data page %04x for data spix:%04x, cur_size:%i\n", bytes_to_remove, data_pix, data_spix, cur_size); + + res = spiffs_page_data_check(fs, fd, data_pix, data_spix); + if (res != SPIFFS_OK) break; + + p_hdr.obj_id = fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG; + p_hdr.span_ix = data_spix; + p_hdr.flags = 0xff; + // allocate new page and copy unmodified data + res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, + &p_hdr, 0, 0, 0, 0, &new_data_pix); + if (res != SPIFFS_OK) break; + res = spiffs_phys_cpy(fs, 0, + SPIFFS_PAGE_TO_PADDR(fs, new_data_pix) + sizeof(spiffs_page_header), + SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header), + SPIFFS_DATA_PAGE_SIZE(fs) - bytes_to_remove); + if (res != SPIFFS_OK) break; + // delete original data page + res = spiffs_page_delete(fs, data_pix); + if (res != SPIFFS_OK) break; + p_hdr.flags &= ~SPIFFS_PH_FLAG_FINAL; + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT, + fd->file_nbr, + SPIFFS_PAGE_TO_PADDR(fs, new_data_pix) + offsetof(spiffs_page_header, flags), + sizeof(u8_t), + (u8_t *)&p_hdr.flags); + if (res != SPIFFS_OK) break; + + // update memory representation of object index page with new data page + if (cur_objix_spix == 0) { + // update object index header page + ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = new_data_pix; + SPIFFS_DBG("truncate: wrote page %04x to objix_hdr entry %02x in mem\n", new_data_pix, SPIFFS_OBJ_IX_ENTRY(fs, data_spix)); + } else { + // update object index page + ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = new_data_pix; + SPIFFS_DBG("truncate: wrote page %04x to objix entry %02x in mem\n", new_data_pix, SPIFFS_OBJ_IX_ENTRY(fs, data_spix)); + } + cur_size = new_size; + fd->size = new_size; + fd->offset = cur_size; + break; + } + data_spix--; + } // while all data + + // update object indices + if (cur_objix_spix == 0) { + // update object index header page + if (cur_size == 0) { + if (remove) { + // remove object altogether + SPIFFS_DBG("truncate: remove object index header page %04x\n", objix_pix); + + res = spiffs_page_index_check(fs, fd, objix_pix, 0); + SPIFFS_CHECK_RES(res); + + res = spiffs_page_delete(fs, objix_pix); + SPIFFS_CHECK_RES(res); + spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_DEL, fd->obj_id, 0, objix_pix, 0); + } else { + // make uninitialized object + SPIFFS_DBG("truncate: reset objix_hdr page %04x\n", objix_pix); + memset(fs->work + sizeof(spiffs_page_object_ix_header), 0xff, + SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix_header)); + res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, + objix_pix, fs->work, 0, SPIFFS_UNDEFINED_LEN, &new_objix_hdr_pix); + SPIFFS_CHECK_RES(res); + } + } else { + // update object index header page + SPIFFS_DBG("truncate: update object index header page with indices and size\n"); + res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, + objix_pix, fs->work, 0, cur_size, &new_objix_hdr_pix); + SPIFFS_CHECK_RES(res); + } + } else { + // update both current object index page and object index header page + spiffs_page_ix new_objix_pix; + + res = spiffs_page_index_check(fs, fd, objix_pix, cur_objix_spix); + SPIFFS_CHECK_RES(res); + + // move and update object index page + res = spiffs_page_move(fs, fd->file_nbr, (u8_t*)objix_hdr, fd->obj_id, 0, objix_pix, &new_objix_pix); + SPIFFS_CHECK_RES(res); + spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, new_objix_pix, 0); + SPIFFS_DBG("truncate: store modified objix page, %04x:%04x\n", new_objix_pix, cur_objix_spix); + fd->cursor_objix_pix = new_objix_pix; + fd->cursor_objix_spix = cur_objix_spix; + fd->offset = cur_size; + // update object index header page with new size + res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, + fd->objix_hdr_pix, 0, 0, cur_size, &new_objix_hdr_pix); + SPIFFS_CHECK_RES(res); + } + fd->size = cur_size; + + return res; +} + +s32_t spiffs_object_read( + spiffs_fd *fd, + u32_t offset, + u32_t len, + u8_t *dst) { + s32_t res = SPIFFS_OK; + spiffs *fs = fd->fs; + spiffs_page_ix objix_pix; + spiffs_page_ix data_pix; + spiffs_span_ix data_spix = offset / SPIFFS_DATA_PAGE_SIZE(fs); + u32_t cur_offset = offset; + spiffs_span_ix cur_objix_spix; + spiffs_span_ix prev_objix_spix = (spiffs_span_ix)-1; + spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work; + spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work; + + while (cur_offset < offset + len) { + cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix); + if (prev_objix_spix != cur_objix_spix) { + // load current object index (header) page + if (cur_objix_spix == 0) { + objix_pix = fd->objix_hdr_pix; + } else { + SPIFFS_DBG("read: find objix %04x:%04x\n", fd->obj_id, cur_objix_spix); + res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &objix_pix); + SPIFFS_CHECK_RES(res); + } + SPIFFS_DBG("read: load objix page %04x:%04x for data spix:%04x\n", objix_pix, cur_objix_spix, data_spix); + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, + fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); + SPIFFS_CHECK_RES(res); + SPIFFS_VALIDATE_OBJIX(objix->p_hdr, fd->obj_id, cur_objix_spix); + + fd->offset = cur_offset; + fd->cursor_objix_pix = objix_pix; + fd->cursor_objix_spix = cur_objix_spix; + + prev_objix_spix = cur_objix_spix; + } + + if (cur_objix_spix == 0) { + // get data page from object index header page + data_pix = ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix]; + } else { + // get data page from object index page + data_pix = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)]; + } + + // all remaining data + u32_t len_to_read = offset + len - cur_offset; + // remaining data in page + len_to_read = MIN(len_to_read, SPIFFS_DATA_PAGE_SIZE(fs) - (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs))); + // remaining data in file + len_to_read = MIN(len_to_read, fd->size); + SPIFFS_DBG("read: offset:%i rd:%i data spix:%04x is data_pix:%04x addr:%08x\n", cur_offset, len_to_read, data_spix, data_pix, + SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs))); + if (len_to_read <= 0) { + res = SPIFFS_ERR_END_OF_OBJECT; + break; + } + res = spiffs_page_data_check(fs, fd, data_pix, data_spix); + SPIFFS_CHECK_RES(res); + res = _spiffs_rd( + fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_READ, + fd->file_nbr, + SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs)), + len_to_read, + dst); + SPIFFS_CHECK_RES(res); + dst += len_to_read; + cur_offset += len_to_read; + fd->offset = cur_offset; + data_spix++; + } + + return res; +} + +typedef struct { + spiffs_obj_id min_obj_id; + spiffs_obj_id max_obj_id; + u32_t compaction; + const u8_t *conflicting_name; +} spiffs_free_obj_id_state; + +static s32_t spiffs_obj_lu_find_free_obj_id_bitmap_v(spiffs *fs, spiffs_obj_id id, spiffs_block_ix bix, int ix_entry, + u32_t user_data, void *user_p) { + if (id != SPIFFS_OBJ_ID_FREE && id != SPIFFS_OBJ_ID_DELETED) { + spiffs_obj_id min_obj_id = user_data; + u8_t *conflicting_name = (u8_t *)user_p; + + // if conflicting name parameter is given, also check if this name is found in object index hdrs + if (conflicting_name && (id & SPIFFS_OBJ_ID_IX_FLAG)) { + spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry); + int res; + spiffs_page_object_ix_header objix_hdr; + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr); + SPIFFS_CHECK_RES(res); + if (objix_hdr.p_hdr.span_ix == 0 && + (objix_hdr.p_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE)) == + (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) { + if (strcmp((char *)user_p, (char *)objix_hdr.name) == 0) { + return SPIFFS_ERR_CONFLICTING_NAME; + } + } + } + + id &= ~SPIFFS_OBJ_ID_IX_FLAG; + u32_t bit_ix = (id-min_obj_id) & 7; + int byte_ix = (id-min_obj_id) >> 3; + if (byte_ix >= 0 && (u32_t)byte_ix < SPIFFS_CFG_LOG_PAGE_SZ(fs)) { + fs->work[byte_ix] |= (1<conflicting_name && strcmp((const char *)state->conflicting_name, (char *)objix_hdr.name) == 0) { + return SPIFFS_ERR_CONFLICTING_NAME; + } + + id &= ~SPIFFS_OBJ_ID_IX_FLAG; + if (id >= state->min_obj_id && id <= state->max_obj_id) { + u8_t *map = (u8_t *)fs->work; + int ix = (id - state->min_obj_id) / state->compaction; + //SPIFFS_DBG("free_obj_id: add ix %i for id %04x min:%04x max%04x comp:%i\n", ix, id, state->min_obj_id, state->max_obj_id, state->compaction); + map[ix]++; + } + } + } + return SPIFFS_VIS_COUNTINUE; +} + +// Scans thru all object lookup for object index header pages. If total possible number of +// object ids cannot fit into a work buffer, these are grouped. When a group containing free +// object ids is found, the object lu is again scanned for object ids within group and bitmasked. +// Finally, the bitmasked is searched for a free id +s32_t spiffs_obj_lu_find_free_obj_id(spiffs *fs, spiffs_obj_id *obj_id, u8_t *conflicting_name) { + s32_t res = SPIFFS_OK; + u32_t max_objects = (SPIFFS_CFG_PHYS_SZ(fs) / (u32_t)SPIFFS_CFG_LOG_PAGE_SZ(fs)) / 2; + spiffs_free_obj_id_state state; + spiffs_obj_id free_obj_id = SPIFFS_OBJ_ID_FREE; + state.min_obj_id = 1; + state.max_obj_id = max_objects + 1; + if (state.max_obj_id & SPIFFS_OBJ_ID_IX_FLAG) { + state.max_obj_id = ((spiffs_obj_id)-1) & ~SPIFFS_OBJ_ID_IX_FLAG; + } + state.compaction = 0; + state.conflicting_name = conflicting_name; + while (res == SPIFFS_OK && free_obj_id == SPIFFS_OBJ_ID_FREE) { + if (state.max_obj_id - state.min_obj_id <= (spiffs_obj_id)SPIFFS_CFG_LOG_PAGE_SZ(fs)*8) { + // possible to represent in bitmap + u32_t i, j; + SPIFFS_DBG("free_obj_id: BITM min:%04x max:%04x\n", state.min_obj_id, state.max_obj_id); + + memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs)); + res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_obj_lu_find_free_obj_id_bitmap_v, state.min_obj_id, + conflicting_name, 0, 0); + if (res == SPIFFS_VIS_END) res = SPIFFS_OK; + SPIFFS_CHECK_RES(res); + // traverse bitmask until found free obj_id + for (i = 0; i < SPIFFS_CFG_LOG_PAGE_SZ(fs); i++) { + u8_t mask = fs->work[i]; + if (mask == 0xff) { + continue; + } + for (j = 0; j < 8; j++) { + if ((mask & (1<work; + u8_t min_count = 0xff; + + for (i = 0; i < SPIFFS_CFG_LOG_PAGE_SZ(fs)/sizeof(u8_t); i++) { + if (map[i] < min_count) { + min_count = map[i]; + min_i = i; + if (min_count == 0) { + break; + } + } + } + + if (min_count == state.compaction) { + // there are no free objids! + SPIFFS_DBG("free_obj_id: compacted table is full\n"); + return SPIFFS_ERR_FULL; + } + + SPIFFS_DBG("free_obj_id: COMP select index:%i min_count:%i min:%04x max:%04x compact:%i\n", min_i, min_count, state.min_obj_id, state.max_obj_id, state.compaction); + + if (min_count == 0) { + // no id in this range, skip compacting and use directly + *obj_id = min_i * state.compaction + state.min_obj_id; + return SPIFFS_OK; + } else { + SPIFFS_DBG("free_obj_id: COMP SEL chunk:%04x min:%04x -> %04x\n", state.compaction, state.min_obj_id, state.min_obj_id + min_i * state.compaction); + state.min_obj_id += min_i * state.compaction; + state.max_obj_id = state.min_obj_id + state.compaction; + // decrease compaction + } + if ((state.max_obj_id - state.min_obj_id <= (spiffs_obj_id)SPIFFS_CFG_LOG_PAGE_SZ(fs)*8)) { + // no need for compacting, use bitmap + continue; + } + } + // in a work memory of log_page_size bytes, we may fit in log_page_size ids + // todo what if compaction is > 255 - then we cannot fit it in a byte + state.compaction = (state.max_obj_id-state.min_obj_id) / ((SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(u8_t))); + SPIFFS_DBG("free_obj_id: COMP min:%04x max:%04x compact:%i\n", state.min_obj_id, state.max_obj_id, state.compaction); + + memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs)); + res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_obj_lu_find_free_obj_id_compact_v, 0, &state, 0, 0); + if (res == SPIFFS_VIS_END) res = SPIFFS_OK; + SPIFFS_CHECK_RES(res); + state.conflicting_name = 0; // searched for conflicting name once, no need to do it again + } + } + + return res; +} + +s32_t spiffs_fd_find_new(spiffs *fs, spiffs_fd **fd) { + u32_t i; + spiffs_fd *fds = (spiffs_fd *)fs->fd_space; + for (i = 0; i < fs->fd_count; i++) { + spiffs_fd *cur_fd = &fds[i]; + if (cur_fd->file_nbr == 0) { + cur_fd->file_nbr = i+1; + *fd = cur_fd; + return SPIFFS_OK; + } + } + return SPIFFS_ERR_OUT_OF_FILE_DESCS; +} + +s32_t spiffs_fd_return(spiffs *fs, spiffs_file f) { + if (f <= 0 || f > (s16_t)fs->fd_count) { + return SPIFFS_ERR_BAD_DESCRIPTOR; + } + spiffs_fd *fds = (spiffs_fd *)fs->fd_space; + spiffs_fd *fd = &fds[f-1]; + if (fd->file_nbr == 0) { + return SPIFFS_ERR_FILE_CLOSED; + } + fd->file_nbr = 0; + return SPIFFS_OK; +} + +s32_t spiffs_fd_get(spiffs *fs, spiffs_file f, spiffs_fd **fd) { + if (f <= 0 || f > (s16_t)fs->fd_count) { + return SPIFFS_ERR_BAD_DESCRIPTOR; + } + spiffs_fd *fds = (spiffs_fd *)fs->fd_space; + *fd = &fds[f-1]; + if ((*fd)->file_nbr == 0) { + return SPIFFS_ERR_FILE_CLOSED; + } + return SPIFFS_OK; +} diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/Makefile b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/Makefile new file mode 100644 index 0000000..0aff9d1 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/Makefile @@ -0,0 +1,47 @@ + +############################################################# +# 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 = libssl.a +COMPONENTS_libssl = crypto/libsslcrypto.a \ + ssl/libsslssl.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/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/Makefile b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/Makefile new file mode 100644 index 0000000..d26b65a --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/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 = libsslcrypto.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/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/sha256.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/sha256.c new file mode 100644 index 0000000..aaa6dee --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/sha256.c @@ -0,0 +1,287 @@ +/* + * Copyright (c) 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. + */ + +//#include +//#include "os_port.h" +#include "ssl/ssl_os_port.h" +#include "ssl/ssl_crypto.h" +//#include "crypto.h" +#include "lwip/mem.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +#define GET_UINT32(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] ); \ +} + +#define PUT_UINT32(n,b,i) \ +{ \ + (b)[(i) ] = (uint8_t) ((n) >> 24); \ + (b)[(i) + 1] = (uint8_t) ((n) >> 16); \ + (b)[(i) + 2] = (uint8_t) ((n) >> 8); \ + (b)[(i) + 3] = (uint8_t) ((n) ); \ +} + +static const uint8_t sha256_padding[64] 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 +}; + +/** + * Initialize the SHA256 context + */ +void ICACHE_FLASH_ATTR SHA256_Init(SHA256_CTX *ctx) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + 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; +} + +static void ICACHE_FLASH_ATTR SHA256_Process(const uint8_t digest[64], SHA256_CTX *ctx) +{ + uint32_t temp1, temp2, W[64]; + uint32_t A, B, C, D, E, F, G, H; + + GET_UINT32(W[0], digest, 0); + GET_UINT32(W[1], digest, 4); + GET_UINT32(W[2], digest, 8); + GET_UINT32(W[3], digest, 12); + GET_UINT32(W[4], digest, 16); + GET_UINT32(W[5], digest, 20); + GET_UINT32(W[6], digest, 24); + GET_UINT32(W[7], digest, 28); + GET_UINT32(W[8], digest, 32); + GET_UINT32(W[9], digest, 36); + GET_UINT32(W[10], digest, 40); + GET_UINT32(W[11], digest, 44); + GET_UINT32(W[12], digest, 48); + GET_UINT32(W[13], digest, 52); + GET_UINT32(W[14], digest, 56); + GET_UINT32(W[15], digest, 60); + +#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; \ +} + + 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]; + + P(A, B, C, D, E, F, G, H, W[ 0], 0x428A2F98); + P(H, A, B, C, D, E, F, G, W[ 1], 0x71374491); + P(G, H, A, B, C, D, E, F, W[ 2], 0xB5C0FBCF); + P(F, G, H, A, B, C, D, E, W[ 3], 0xE9B5DBA5); + P(E, F, G, H, A, B, C, D, W[ 4], 0x3956C25B); + P(D, E, F, G, H, A, B, C, W[ 5], 0x59F111F1); + P(C, D, E, F, G, H, A, B, W[ 6], 0x923F82A4); + P(B, C, D, E, F, G, H, A, W[ 7], 0xAB1C5ED5); + P(A, B, C, D, E, F, G, H, W[ 8], 0xD807AA98); + P(H, A, B, C, D, E, F, G, W[ 9], 0x12835B01); + P(G, H, A, B, C, D, E, F, W[10], 0x243185BE); + P(F, G, H, A, B, C, D, E, W[11], 0x550C7DC3); + P(E, F, G, H, A, B, C, D, W[12], 0x72BE5D74); + P(D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE); + P(C, D, E, F, G, H, A, B, W[14], 0x9BDC06A7); + P(B, C, D, E, F, G, H, A, W[15], 0xC19BF174); + P(A, B, C, D, E, F, G, H, R(16), 0xE49B69C1); + P(H, A, B, C, D, E, F, G, R(17), 0xEFBE4786); + P(G, H, A, B, C, D, E, F, R(18), 0x0FC19DC6); + P(F, G, H, A, B, C, D, E, R(19), 0x240CA1CC); + P(E, F, G, H, A, B, C, D, R(20), 0x2DE92C6F); + P(D, E, F, G, H, A, B, C, R(21), 0x4A7484AA); + P(C, D, E, F, G, H, A, B, R(22), 0x5CB0A9DC); + P(B, C, D, E, F, G, H, A, R(23), 0x76F988DA); + P(A, B, C, D, E, F, G, H, R(24), 0x983E5152); + P(H, A, B, C, D, E, F, G, R(25), 0xA831C66D); + P(G, H, A, B, C, D, E, F, R(26), 0xB00327C8); + P(F, G, H, A, B, C, D, E, R(27), 0xBF597FC7); + P(E, F, G, H, A, B, C, D, R(28), 0xC6E00BF3); + P(D, E, F, G, H, A, B, C, R(29), 0xD5A79147); + P(C, D, E, F, G, H, A, B, R(30), 0x06CA6351); + P(B, C, D, E, F, G, H, A, R(31), 0x14292967); + P(A, B, C, D, E, F, G, H, R(32), 0x27B70A85); + P(H, A, B, C, D, E, F, G, R(33), 0x2E1B2138); + P(G, H, A, B, C, D, E, F, R(34), 0x4D2C6DFC); + P(F, G, H, A, B, C, D, E, R(35), 0x53380D13); + P(E, F, G, H, A, B, C, D, R(36), 0x650A7354); + P(D, E, F, G, H, A, B, C, R(37), 0x766A0ABB); + P(C, D, E, F, G, H, A, B, R(38), 0x81C2C92E); + P(B, C, D, E, F, G, H, A, R(39), 0x92722C85); + P(A, B, C, D, E, F, G, H, R(40), 0xA2BFE8A1); + P(H, A, B, C, D, E, F, G, R(41), 0xA81A664B); + P(G, H, A, B, C, D, E, F, R(42), 0xC24B8B70); + P(F, G, H, A, B, C, D, E, R(43), 0xC76C51A3); + P(E, F, G, H, A, B, C, D, R(44), 0xD192E819); + P(D, E, F, G, H, A, B, C, R(45), 0xD6990624); + P(C, D, E, F, G, H, A, B, R(46), 0xF40E3585); + P(B, C, D, E, F, G, H, A, R(47), 0x106AA070); + P(A, B, C, D, E, F, G, H, R(48), 0x19A4C116); + P(H, A, B, C, D, E, F, G, R(49), 0x1E376C08); + P(G, H, A, B, C, D, E, F, R(50), 0x2748774C); + P(F, G, H, A, B, C, D, E, R(51), 0x34B0BCB5); + P(E, F, G, H, A, B, C, D, R(52), 0x391C0CB3); + P(D, E, F, G, H, A, B, C, R(53), 0x4ED8AA4A); + P(C, D, E, F, G, H, A, B, R(54), 0x5B9CCA4F); + P(B, C, D, E, F, G, H, A, R(55), 0x682E6FF3); + P(A, B, C, D, E, F, G, H, R(56), 0x748F82EE); + P(H, A, B, C, D, E, F, G, R(57), 0x78A5636F); + P(G, H, A, B, C, D, E, F, R(58), 0x84C87814); + P(F, G, H, A, B, C, D, E, R(59), 0x8CC70208); + P(E, F, G, H, A, B, C, D, R(60), 0x90BEFFFA); + P(D, E, F, G, H, A, B, C, R(61), 0xA4506CEB); + P(C, D, E, F, G, H, A, B, R(62), 0xBEF9A3F7); + P(B, C, D, E, F, G, H, A, R(63), 0xC67178F2); + + 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; +} + +/** + * Accepts an array of octets as the next portion of the message. + */ +void ICACHE_FLASH_ATTR SHA256_Update(SHA256_CTX *ctx, const uint8_t * msg, int len) +{ + uint32_t left = ctx->total[0] & 0x3F; + uint32_t fill = 64 - left; + + ctx->total[0] += len; + ctx->total[0] &= 0xFFFFFFFF; + + if (ctx->total[0] < len) + ctx->total[1]++; + + if (left && len >= fill) + { + memcpy((void *) (ctx->buffer + left), (void *)msg, fill); + SHA256_Process(ctx->buffer, ctx); + len -= fill; + msg += fill; + left = 0; + } + + while (len >= 64) + { + SHA256_Process(msg, ctx); + len -= 64; + msg += 64; + } + + if (len) + { + memcpy((void *) (ctx->buffer + left), (void *) msg, len); + } +} + +/** + * Return the 256-bit message digest into the user's array + */ +void ICACHE_FLASH_ATTR SHA256_Final(uint8_t *digest, SHA256_CTX *ctx) +{ + uint32_t last, padn; + uint32_t high, low; + uint8_t msglen[8]; + + uint8_t *sha256_padding_ram = (uint8_t *)SSL_MALLOC(64); + + memcpy(sha256_padding_ram, sha256_padding, 64); + + high = (ctx->total[0] >> 29) + | (ctx->total[1] << 3); + low = (ctx->total[0] << 3); + + PUT_UINT32(high, msglen, 0); + PUT_UINT32(low, msglen, 4); + + last = ctx->total[0] & 0x3F; + padn = (last < 56) ? (56 - last) : (120 - last); + + SHA256_Update(ctx, sha256_padding_ram, padn); + SHA256_Update(ctx, msglen, 8); + + PUT_UINT32(ctx->state[0], digest, 0); + PUT_UINT32(ctx->state[1], digest, 4); + PUT_UINT32(ctx->state[2], digest, 8); + PUT_UINT32(ctx->state[3], digest, 12); + PUT_UINT32(ctx->state[4], digest, 16); + PUT_UINT32(ctx->state[5], digest, 20); + PUT_UINT32(ctx->state[6], digest, 24); + PUT_UINT32(ctx->state[7], digest, 28); + + SSL_FREE(sha256_padding_ram); +} diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/sha384.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/sha384.c new file mode 100644 index 0000000..23da0ab --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/sha384.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 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. + */ + +//#include +//#include "os_port.h" +#include "ssl/ssl_os_port.h" +#include "ssl/ssl_crypto.h" +//#include "crypto.h" +#include "lwip/mem.h" + +/** +* Initialize the SHA384 context +*/ + void ICACHE_FLASH_ATTR SHA384_Init(SHA384_CTX *ctx) + { + //Set initial hash value + ctx->h_dig.h[0] = 0xCBBB9D5DC1059ED8ULL; + ctx->h_dig.h[1] = 0x629A292A367CD507ULL; + ctx->h_dig.h[2] = 0x9159015A3070DD17ULL; + ctx->h_dig.h[3] = 0x152FECD8F70E5939ULL; + ctx->h_dig.h[4] = 0x67332667FFC00B31ULL; + ctx->h_dig.h[5] = 0x8EB44A8768581511ULL; + ctx->h_dig.h[6] = 0xDB0C2E0D64F98FA7ULL; + ctx->h_dig.h[7] = 0x47B5481DBEFA4FA4ULL; + + // Number of bytes in the buffer + ctx->size = 0; + // Total length of the message + ctx->totalSize = 0; + } + +/** +* Accepts an array of octets as the next portion of the message. +*/ +void ICACHE_FLASH_ATTR SHA384_Update(SHA384_CTX *ctx, const uint8_t * msg, int len) +{ + // The function is defined in the exact same manner as SHA-512 + SHA512_Update(ctx, msg, len); +} + +/** +* Return the 384-bit message digest into the user's array +*/ +void ICACHE_FLASH_ATTR SHA384_Final(uint8_t *digest, SHA384_CTX *ctx) +{ + // The function is defined in the exact same manner as SHA-512 + SHA512_Final(NULL, ctx); + + // Copy the resulting digest + if (digest != NULL) + memcpy(digest, ctx->h_dig.digest, SHA384_SIZE); +} + diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/sha512.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/sha512.c new file mode 100644 index 0000000..3b9f2ac --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/sha512.c @@ -0,0 +1,233 @@ +/* + * Copyright (c) 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. + */ + +//#include +//#include "os_port.h" +#include "ssl/ssl_os_port.h" +#include "ssl/ssl_crypto.h" +//#include "crypto.h" +#include "lwip/mem.h" + +#define SHR64(a, n) ((a) >> (n)) +#define ROR64(a, n) (((a) >> (n)) | ((a) << (64 - (n)))) +#define CH(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define MAJ(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z))) +#define SIGMA1(x) (ROR64(x, 28) ^ ROR64(x, 34) ^ ROR64(x, 39)) +#define SIGMA2(x) (ROR64(x, 14) ^ ROR64(x, 18) ^ ROR64(x, 41)) +#define SIGMA3(x) (ROR64(x, 1) ^ ROR64(x, 8) ^ SHR64(x, 7)) +#define SIGMA4(x) (ROR64(x, 19) ^ ROR64(x, 61) ^ SHR64(x, 6)) +#define MIN(x, y) ((x) < (y) ? x : y) + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +static const uint8_t padding[128] ICACHE_RODATA_ATTR STORE_ATTR = +{ + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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 uint64_t k[80] ICACHE_RODATA_ATTR STORE_ATTR = +{ + 0x428A2F98D728AE22ULL, 0x7137449123EF65CDULL, 0xB5C0FBCFEC4D3B2FULL, 0xE9B5DBA58189DBBCULL, + 0x3956C25BF348B538ULL, 0x59F111F1B605D019ULL, 0x923F82A4AF194F9BULL, 0xAB1C5ED5DA6D8118ULL, + 0xD807AA98A3030242ULL, 0x12835B0145706FBEULL, 0x243185BE4EE4B28CULL, 0x550C7DC3D5FFB4E2ULL, + 0x72BE5D74F27B896FULL, 0x80DEB1FE3B1696B1ULL, 0x9BDC06A725C71235ULL, 0xC19BF174CF692694ULL, + 0xE49B69C19EF14AD2ULL, 0xEFBE4786384F25E3ULL, 0x0FC19DC68B8CD5B5ULL, 0x240CA1CC77AC9C65ULL, + 0x2DE92C6F592B0275ULL, 0x4A7484AA6EA6E483ULL, 0x5CB0A9DCBD41FBD4ULL, 0x76F988DA831153B5ULL, + 0x983E5152EE66DFABULL, 0xA831C66D2DB43210ULL, 0xB00327C898FB213FULL, 0xBF597FC7BEEF0EE4ULL, + 0xC6E00BF33DA88FC2ULL, 0xD5A79147930AA725ULL, 0x06CA6351E003826FULL, 0x142929670A0E6E70ULL, + 0x27B70A8546D22FFCULL, 0x2E1B21385C26C926ULL, 0x4D2C6DFC5AC42AEDULL, 0x53380D139D95B3DFULL, + 0x650A73548BAF63DEULL, 0x766A0ABB3C77B2A8ULL, 0x81C2C92E47EDAEE6ULL, 0x92722C851482353BULL, + 0xA2BFE8A14CF10364ULL, 0xA81A664BBC423001ULL, 0xC24B8B70D0F89791ULL, 0xC76C51A30654BE30ULL, + 0xD192E819D6EF5218ULL, 0xD69906245565A910ULL, 0xF40E35855771202AULL, 0x106AA07032BBD1B8ULL, + 0x19A4C116B8D2D0C8ULL, 0x1E376C085141AB53ULL, 0x2748774CDF8EEB99ULL, 0x34B0BCB5E19B48A8ULL, + 0x391C0CB3C5C95A63ULL, 0x4ED8AA4AE3418ACBULL, 0x5B9CCA4F7763E373ULL, 0x682E6FF3D6B2B8A3ULL, + 0x748F82EE5DEFB2FCULL, 0x78A5636F43172F60ULL, 0x84C87814A1F0AB72ULL, 0x8CC702081A6439ECULL, + 0x90BEFFFA23631E28ULL, 0xA4506CEBDE82BDE9ULL, 0xBEF9A3F7B2C67915ULL, 0xC67178F2E372532BULL, + 0xCA273ECEEA26619CULL, 0xD186B8C721C0C207ULL, 0xEADA7DD6CDE0EB1EULL, 0xF57D4F7FEE6ED178ULL, + 0x06F067AA72176FBAULL, 0x0A637DC5A2C898A6ULL, 0x113F9804BEF90DAEULL, 0x1B710B35131C471BULL, + 0x28DB77F523047D84ULL, 0x32CAAB7B40C72493ULL, 0x3C9EBE0A15C9BEBCULL, 0x431D67C49C100D4CULL, + 0x4CC5D4BECB3E42B6ULL, 0x597F299CFC657E2AULL, 0x5FCB6FAB3AD6FAECULL, 0x6C44198C4A475817ULL +}; + +/** +* Initialize the SHA512 context +*/ +void ICACHE_FLASH_ATTR SHA512_Init(SHA512_CTX *ctx) +{ + ctx->h_dig.h[0] = 0x6A09E667F3BCC908ULL; + ctx->h_dig.h[1] = 0xBB67AE8584CAA73BULL; + ctx->h_dig.h[2] = 0x3C6EF372FE94F82BULL; + ctx->h_dig.h[3] = 0xA54FF53A5F1D36F1ULL; + ctx->h_dig.h[4] = 0x510E527FADE682D1ULL; + ctx->h_dig.h[5] = 0x9B05688C2B3E6C1FULL; + ctx->h_dig.h[6] = 0x1F83D9ABFB41BD6BULL; + ctx->h_dig.h[7] = 0x5BE0CD19137E2179ULL; + ctx->size = 0; + ctx->totalSize = 0; +} + +static void ICACHE_FLASH_ATTR SHA512_Process(SHA512_CTX *ctx) +{ + int t; + uint64_t temp1; + uint64_t temp2; + + // Initialize the 8 working registers + uint64_t a = ctx->h_dig.h[0]; + uint64_t b = ctx->h_dig.h[1]; + uint64_t c = ctx->h_dig.h[2]; + uint64_t d = ctx->h_dig.h[3]; + uint64_t e = ctx->h_dig.h[4]; + uint64_t f = ctx->h_dig.h[5]; + uint64_t g = ctx->h_dig.h[6]; + uint64_t h = ctx->h_dig.h[7]; + + // Process message in 16-word blocks + uint64_t *w = ctx->w_buf.w; + + // Convert from big-endian byte order to host byte order + for (t = 0; t < 16; t++) + w[t] = be64toh(w[t]); + + // Prepare the message schedule + for (t = 16; t < 80; t++) + w[t] = SIGMA4(w[t - 2]) + w[t - 7] + SIGMA3(w[t - 15]) + w[t - 16]; + + // SHA-512 hash computation + for (t = 0; t < 80; t++) + { + // Calculate T1 and T2 + temp1 = h + SIGMA2(e) + CH(e, f, g) + k[t] + w[t]; + temp2 = SIGMA1(a) + MAJ(a, b, c); + + // Update the working registers + h = g; + g = f; + f = e; + e = d + temp1; + d = c; + c = b; + b = a; + a = temp1 + temp2; + } + + // Update the hash value + ctx->h_dig.h[0] += a; + ctx->h_dig.h[1] += b; + ctx->h_dig.h[2] += c; + ctx->h_dig.h[3] += d; + ctx->h_dig.h[4] += e; + ctx->h_dig.h[5] += f; + ctx->h_dig.h[6] += g; + ctx->h_dig.h[7] += h; + } + +/** +* Accepts an array of octets as the next portion of the message. +*/ +void ICACHE_FLASH_ATTR SHA512_Update(SHA512_CTX *ctx, const uint8_t * msg, int len) +{ + // Process the incoming data + while (len > 0) + { + // The buffer can hold at most 128 bytes + size_t n = MIN(len, 128 - ctx->size); + + // Copy the data to the buffer + memcpy(ctx->w_buf.buffer + ctx->size, msg, n); + + // Update the SHA-512 ctx + ctx->size += n; + ctx->totalSize += n; + // Advance the data pointer + msg = (uint8_t *) msg + n; + // Remaining bytes to process + len -= n; + + // Process message in 16-word blocks + if (ctx->size == 128) + { + // Transform the 16-word block + SHA512_Process(ctx); + // Empty the buffer + ctx->size = 0; + } + } +} + +/** +* Return the 512-bit message digest into the user's array +*/ +void ICACHE_FLASH_ATTR SHA512_Final(uint8_t *digest, SHA512_CTX *ctx) +{ + int i; + size_t paddingSize; + uint64_t totalSize; + + uint8_t *padding_ram = (uint8_t *)SSL_MALLOC(128); + + memcpy(padding_ram, padding, 128); + + // Length of the original message (before padding) + totalSize = ctx->totalSize * 8; + + // Pad the message so that its length is congruent to 112 modulo 128 + paddingSize = (ctx->size < 112) ? (112 - ctx->size) : + (128 + 112 - ctx->size); + // Append padding + SHA512_Update(ctx, padding, paddingSize); + + // Append the length of the original message + ctx->w_buf.w[14] = 0; + ctx->w_buf.w[15] = be64toh(totalSize); + + // Calculate the message digest + SHA512_Process(ctx); + + // Convert from host byte order to big-endian byte order + for (i = 0; i < 8; i++) + ctx->h_dig.h[i] = be64toh(ctx->h_dig.h[i]); + + // Copy the resulting digest + if (digest != NULL) + memcpy(digest, ctx->h_dig.digest, SHA512_SIZE); + + SSL_FREE(padding_ram); + } + diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_aes.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_aes.c new file mode 100644 index 0000000..d0acd82 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_aes.c @@ -0,0 +1,466 @@ +/* + * 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. + */ + +/** + * AES implementation - this is a small code version. There are much faster + * versions around but they are much larger in size (i.e. they use large + * submix tables). + */ + +#include "ssl/ssl_os_port.h" +#include "ssl/ssl_crypto.h" + +/* all commented out in skeleton mode */ +#ifndef CONFIG_SSL_SKELETON_MODE + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +#define rot1(x) (((x) << 24) | ((x) >> 8)) +#define rot2(x) (((x) << 16) | ((x) >> 16)) +#define rot3(x) (((x) << 8) | ((x) >> 24)) + +/* + * This cute trick does 4 'mul by two' at once. Stolen from + * Dr B. R. Gladman but I'm sure the u-(u>>7) is + * a standard graphics trick + * The key to this is that we need to xor with 0x1b if the top bit is set. + * a 1xxx xxxx 0xxx 0xxx First we mask the 7bit, + * b 1000 0000 0000 0000 then we shift right by 7 putting the 7bit in 0bit, + * c 0000 0001 0000 0000 we then subtract (c) from (b) + * d 0111 1111 0000 0000 and now we and with our mask + * e 0001 1011 0000 0000 + */ +#define mt 0x80808080 +#define ml 0x7f7f7f7f +#define mh 0xfefefefe +#define mm 0x1b1b1b1b +#define mul2(x,t) ((t)=((x)&mt), \ + ((((x)+(x))&mh)^(((t)-((t)>>7))&mm))) + +#define inv_mix_col(x,f2,f4,f8,f9) (\ + (f2)=mul2(x,f2), \ + (f4)=mul2(f2,f4), \ + (f8)=mul2(f4,f8), \ + (f9)=(x)^(f8), \ + (f8)=((f2)^(f4)^(f8)), \ + (f2)^=(f9), \ + (f4)^=(f9), \ + (f8)^=rot3(f2), \ + (f8)^=rot2(f4), \ + (f8)^rot1(f9)) + +/* + * AES S-box + */ +static const uint8_t aes_sbox[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, +}; + +/* + * AES is-box + */ +static const uint8_t aes_isbox[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 +}; + +static const unsigned char Rcon[30] ICACHE_RODATA_ATTR STORE_ATTR = +{ + 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80, + 0x1b,0x36,0x6c,0xd8,0xab,0x4d,0x9a,0x2f, + 0x5e,0xbc,0x63,0xc6,0x97,0x35,0x6a,0xd4, + 0xb3,0x7d,0xfa,0xef,0xc5,0x91, +}; + +/* ----- static functions ----- */ +static void AES_encrypt(const AES_CTX *ctx, uint32_t *data); +static void AES_decrypt(const AES_CTX *ctx, uint32_t *data); + +/* Perform doubling in Galois Field GF(2^8) using the irreducible polynomial + x^8+x^4+x^3+x+1 */ +static unsigned char ICACHE_FLASH_ATTR AES_xtime(uint32_t x) +{ + return (x&0x80) ? (x<<1)^0x1b : x<<1; +} + +/** + * Set up AES with the key/iv and cipher size. + */ +void ICACHE_FLASH_ATTR AES_set_key(AES_CTX *ctx, const uint8_t *key, + const uint8_t *iv, AES_MODE mode) +{ + int i, ii; + uint32_t *W, tmp, tmp2; + unsigned char *ip; + int words; + + unsigned char *Rcon_ram = (unsigned char *)SSL_MALLOC(32); + + switch (mode) + { + case AES_MODE_128: + i = 10; + words = 4; + break; + + case AES_MODE_256: + i = 14; + words = 8; + break; + + default: /* fail silently */ + return; + } + + ctx->rounds = i; + ctx->key_size = words; + W = ctx->ks; + for (i = 0; i < words; i+=2) + { + W[i+0]= ((uint32_t)key[ 0]<<24)| + ((uint32_t)key[ 1]<<16)| + ((uint32_t)key[ 2]<< 8)| + ((uint32_t)key[ 3] ); + W[i+1]= ((uint32_t)key[ 4]<<24)| + ((uint32_t)key[ 5]<<16)| + ((uint32_t)key[ 6]<< 8)| + ((uint32_t)key[ 7] ); + key += 8; + } + +// ip = Rcon; + ip = Rcon_ram; + memcpy(ip, Rcon, 32); // align, copy two byte more + ii = 4 * (ctx->rounds+1); + for (i = words; i> 8)&0xff)<<16; + tmp2|=(uint32_t)system_get_data_of_array_8(aes_sbox, (tmp>>16)&0xff)<<24; + tmp2|=(uint32_t)system_get_data_of_array_8(aes_sbox, (tmp>>24) ); + tmp=tmp2^(((unsigned int)*ip)<<24); + ip++; + } + + if ((words == 8) && ((i % words) == 4)) + { + tmp2 =(uint32_t)system_get_data_of_array_8(aes_sbox, (tmp )&0xff) ; + tmp2|=(uint32_t)system_get_data_of_array_8(aes_sbox, (tmp>> 8)&0xff)<< 8; + tmp2|=(uint32_t)system_get_data_of_array_8(aes_sbox, (tmp>>16)&0xff)<<16; + tmp2|=(uint32_t)system_get_data_of_array_8(aes_sbox, (tmp>>24) )<<24; + tmp=tmp2; + } + + W[i]=W[i-words]^tmp; + } + + SSL_FREE(Rcon_ram); + + /* copy the iv across */ + memcpy(ctx->iv, iv, 16); +} + +/** + * Change a key for decryption. + */ +void ICACHE_FLASH_ATTR AES_convert_key(AES_CTX *ctx) +{ + int i; + uint32_t *k,w,t1,t2,t3,t4; + + k = ctx->ks; + k += 4; + + for (i= ctx->rounds*4; i > 4; i--) + { + w= *k; + w = inv_mix_col(w,t1,t2,t3,t4); + *k++ =w; + } +} + +/** + * Encrypt a byte sequence (with a block size 16) using the AES cipher. + */ +void ICACHE_FLASH_ATTR AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length) +{ + int i; + uint32_t tin[4], tout[4], iv[4]; + + memcpy(iv, ctx->iv, AES_IV_SIZE); + for (i = 0; i < 4; i++) + tout[i] = ntohl(iv[i]); + + for (length -= AES_BLOCKSIZE; length >= 0; length -= AES_BLOCKSIZE) + { + uint32_t msg_32[4]; + uint32_t out_32[4]; + memcpy(msg_32, msg, AES_BLOCKSIZE); + msg += AES_BLOCKSIZE; + + for (i = 0; i < 4; i++) + tin[i] = ntohl(msg_32[i])^tout[i]; + + AES_encrypt(ctx, tin); + + for (i = 0; i < 4; i++) + { + tout[i] = tin[i]; + out_32[i] = htonl(tout[i]); + } + + memcpy(out, out_32, AES_BLOCKSIZE); + out += AES_BLOCKSIZE; + } + + for (i = 0; i < 4; i++) + iv[i] = htonl(tout[i]); + memcpy(ctx->iv, iv, AES_IV_SIZE); +} + +/** + * Decrypt a byte sequence (with a block size 16) using the AES cipher. + */ +void ICACHE_FLASH_ATTR AES_cbc_decrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length) +{ + int i; + uint32_t tin[4], xor[4], tout[4], data[4], iv[4]; + + memcpy(iv, ctx->iv, AES_IV_SIZE); + for (i = 0; i < 4; i++) + xor[i] = ntohl(iv[i]); + + for (length -= 16; length >= 0; length -= 16) + { + uint32_t msg_32[4]; + uint32_t out_32[4]; + memcpy(msg_32, msg, AES_BLOCKSIZE); + msg += AES_BLOCKSIZE; + + for (i = 0; i < 4; i++) + { + tin[i] = ntohl(msg_32[i]); + data[i] = tin[i]; + } + + AES_decrypt(ctx, data); + + for (i = 0; i < 4; i++) + { + tout[i] = data[i]^xor[i]; + xor[i] = tin[i]; + out_32[i] = htonl(tout[i]); + } + + memcpy(out, out_32, AES_BLOCKSIZE); + out += AES_BLOCKSIZE; + } + + for (i = 0; i < 4; i++) + iv[i] = htonl(xor[i]); + memcpy(ctx->iv, iv, AES_IV_SIZE); +} + +/** + * Encrypt a single block (16 bytes) of data + */ +static void ICACHE_FLASH_ATTR AES_encrypt(const AES_CTX *ctx, uint32_t *data) +{ + /* To make this code smaller, generate the sbox entries on the fly. + * This will have a really heavy effect upon performance. + */ + uint32_t tmp[4]; + uint32_t tmp1, old_a0, a0, a1, a2, a3, row; + int curr_rnd; + int rounds = ctx->rounds; + const uint32_t *k = ctx->ks; + + /* Pre-round key addition */ + for (row = 0; row < 4; row++) + data[row] ^= *(k++); + + /* Encrypt one block. */ + for (curr_rnd = 0; curr_rnd < rounds; curr_rnd++) + { + /* Perform ByteSub and ShiftRow operations together */ + for (row = 0; row < 4; row++) + { + a0 = (uint32_t)system_get_data_of_array_8(aes_sbox, (data[row%4]>>24)&0xFF); + a1 = (uint32_t)system_get_data_of_array_8(aes_sbox, (data[(row+1)%4]>>16)&0xFF); + a2 = (uint32_t)system_get_data_of_array_8(aes_sbox, (data[(row+2)%4]>>8)&0xFF); + a3 = (uint32_t)system_get_data_of_array_8(aes_sbox, (data[(row+3)%4])&0xFF); + + /* Perform MixColumn iff not last round */ + if (curr_rnd < (rounds - 1)) + { + tmp1 = a0 ^ a1 ^ a2 ^ a3; + old_a0 = a0; + a0 ^= tmp1 ^ AES_xtime(a0 ^ a1); + a1 ^= tmp1 ^ AES_xtime(a1 ^ a2); + a2 ^= tmp1 ^ AES_xtime(a2 ^ a3); + a3 ^= tmp1 ^ AES_xtime(a3 ^ old_a0); + } + + tmp[row] = ((a0 << 24) | (a1 << 16) | (a2 << 8) | a3); + } + + /* KeyAddition - note that it is vital that this loop is separate from + the MixColumn operation, which must be atomic...*/ + for (row = 0; row < 4; row++) + data[row] = tmp[row] ^ *(k++); + } +} + +/** + * Decrypt a single block (16 bytes) of data + */ +static void ICACHE_FLASH_ATTR AES_decrypt(const AES_CTX *ctx, uint32_t *data) +{ + uint32_t tmp[4]; + uint32_t xt0,xt1,xt2,xt3,xt4,xt5,xt6; + uint32_t a0, a1, a2, a3, row; + int curr_rnd; + int rounds = ctx->rounds; + const uint32_t *k = ctx->ks + ((rounds+1)*4); + + /* pre-round key addition */ + for (row=4; row > 0;row--) + data[row-1] ^= *(--k); + + /* Decrypt one block */ + for (curr_rnd = 0; curr_rnd < rounds; curr_rnd++) + { + /* Perform ByteSub and ShiftRow operations together */ + for (row = 4; row > 0; row--) + { + a0 = system_get_data_of_array_8(aes_isbox, (data[(row+3)%4]>>24)&0xFF); + a1 = system_get_data_of_array_8(aes_isbox, (data[(row+2)%4]>>16)&0xFF); + a2 = system_get_data_of_array_8(aes_isbox, (data[(row+1)%4]>>8)&0xFF); + a3 = system_get_data_of_array_8(aes_isbox, (data[row%4])&0xFF); + + /* Perform MixColumn iff not last round */ + if (curr_rnd<(rounds-1)) + { + /* The MDS cofefficients (0x09, 0x0B, 0x0D, 0x0E) + are quite large compared to encryption; this + operation slows decryption down noticeably. */ + xt0 = AES_xtime(a0^a1); + xt1 = AES_xtime(a1^a2); + xt2 = AES_xtime(a2^a3); + xt3 = AES_xtime(a3^a0); + xt4 = AES_xtime(xt0^xt1); + xt5 = AES_xtime(xt1^xt2); + xt6 = AES_xtime(xt4^xt5); + + xt0 ^= a1^a2^a3^xt4^xt6; + xt1 ^= a0^a2^a3^xt5^xt6; + xt2 ^= a0^a1^a3^xt4^xt6; + xt3 ^= a0^a1^a2^xt5^xt6; + tmp[row-1] = ((xt0<<24)|(xt1<<16)|(xt2<<8)|xt3); + } + else + tmp[row-1] = ((a0<<24)|(a1<<16)|(a2<<8)|a3); + } + + for (row = 4; row > 0; row--) + data[row-1] = tmp[row-1] ^ *(--k); + } +} + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_bigint.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_bigint.c new file mode 100644 index 0000000..f468260 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_bigint.c @@ -0,0 +1,1520 @@ +/* + * 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. + */ + +/** + * @defgroup bigint_api Big Integer API + * @brief The bigint implementation as used by the axTLS project. + * + * The bigint library is for RSA encryption/decryption as well as signing. + * This code tries to minimise use of malloc/free by maintaining a small + * cache. A bigint context may maintain state by being made "permanent". + * It be be later released with a bi_depermanent() and bi_free() call. + * + * It supports the following reduction techniques: + * - Classical + * - Barrett + * - Montgomery + * + * It also implements the following: + * - Karatsuba multiplication + * - Squaring + * - Sliding window exponentiation + * - Chinese Remainder Theorem (implemented in rsa.c). + * + * All the algorithms used are pretty standard, and designed for different + * data bus sizes. Negative numbers are not dealt with at all, so a subtraction + * may need to be tested for negativity. + * + * This library steals some ideas from Jef Poskanzer + * + * and GMP . It gets most of its implementation + * detail from "The Handbook of Applied Cryptography" + * + * @{ + */ + +#include "ssl/ssl_os_port.h" +#include "ssl/ssl_bigint.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +#define V1 v->comps[v->size-1] /**< v1 for division */ +#define V2 v->comps[v->size-2] /**< v2 for division */ +#define U(j) tmp_u->comps[tmp_u->size-j-1] /**< uj for division */ +#define Q(j) quotient->comps[quotient->size-j-1] /**< qj for division */ + +static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bi, comp i); +static bigint *bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom); +static bigint *alloc(BI_CTX *ctx, int size); +static bigint *trim(bigint *bi); +static void more_comps(bigint *bi, int n); +#if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \ + defined(CONFIG_BIGINT_MONTGOMERY) +static bigint *comp_right_shift(bigint *biR, int num_shifts); +static bigint *comp_left_shift(bigint *biR, int num_shifts); +#endif + +#ifdef CONFIG_BIGINT_CHECK_ON +static void check(const bigint *bi); +#else +#define check(A) /**< disappears in normal production mode */ +#endif + + +/** + * @brief Start a new bigint context. + * @return A bigint context. + */ +BI_CTX * ICACHE_FLASH_ATTR bi_initialize(void) +{ + /* calloc() sets everything to zero */ + BI_CTX *ctx = (BI_CTX *)SSL_ZALLOC(sizeof(BI_CTX)); + + /* the radix */ + ctx->bi_radix = alloc(ctx, 2); + ctx->bi_radix->comps[0] = 0; + ctx->bi_radix->comps[1] = 1; + bi_permanent(ctx->bi_radix); + return ctx; +} + +/** + * @brief Close the bigint context and free any resources. + * + * Free up any used memory - a check is done if all objects were not + * properly freed. + * @param ctx [in] The bigint session context. + */ +void ICACHE_FLASH_ATTR bi_terminate(BI_CTX *ctx) +{ + bi_depermanent(ctx->bi_radix); + bi_free(ctx, ctx->bi_radix); + + if (ctx->active_count != 0) + { +#ifdef CONFIG_SSL_FULL_MODE + ssl_printf("bi_terminate: there were %d un-freed bigints\n", + ctx->active_count); +#endif + return; /* wujg : org ---> abort(); */ + } + + bi_clear_cache(ctx); + SSL_FREE(ctx); +} + +/** + *@brief Clear the memory cache. + */ +void ICACHE_FLASH_ATTR bi_clear_cache(BI_CTX *ctx) +{ + bigint *p, *pn; + + if (ctx->free_list == NULL) + return; + + for (p = ctx->free_list; p != NULL; p = pn) + { + pn = p->next; + SSL_FREE(p->comps); + SSL_FREE(p); + } + + ctx->free_count = 0; + ctx->free_list = NULL; +} + +/** + * @brief Increment the number of references to this object. + * It does not do a full copy. + * @param bi [in] The bigint to copy. + * @return A reference to the same bigint. + */ +bigint * ICACHE_FLASH_ATTR bi_copy(bigint *bi) +{ + check(bi); + if (bi->refs != PERMANENT) + bi->refs++; + return bi; +} + +/** + * @brief Simply make a bigint object "unfreeable" if bi_free() is called on it. + * + * For this object to be freed, bi_depermanent() must be called. + * @param bi [in] The bigint to be made permanent. + */ +void ICACHE_FLASH_ATTR bi_permanent(bigint *bi) +{ + check(bi); + if (bi->refs != 1) + { +#ifdef CONFIG_SSL_FULL_MODE + ssl_printf("bi_permanent: refs was not 1\n"); +#endif + return; /* wujg : org ----> abort(); */ + } + + bi->refs = PERMANENT; +} + +/** + * @brief Take a permanent object and make it eligible for freedom. + * @param bi [in] The bigint to be made back to temporary. + */ +void ICACHE_FLASH_ATTR bi_depermanent(bigint *bi) +{ + check(bi); + if (bi->refs != PERMANENT) + { +#ifdef CONFIG_SSL_FULL_MODE + ssl_printf("bi_depermanent: bigint was not permanent\n"); +#endif + return; /* wujg : org ----> abort(); */ + } + + bi->refs = 1; +} + +/** + * @brief Free a bigint object so it can be used again. + * + * The memory itself it not actually freed, just tagged as being available + * @param ctx [in] The bigint session context. + * @param bi [in] The bigint to be freed. + */ +void ICACHE_FLASH_ATTR bi_free(BI_CTX *ctx, bigint *bi) +{ + check(bi); + if (bi->refs == PERMANENT) + { + return; + } + + if (--bi->refs > 0) + { + return; + } + + bi->next = ctx->free_list; + ctx->free_list = bi; + ctx->free_count++; + + if (--ctx->active_count < 0) + { +#ifdef CONFIG_SSL_FULL_MODE + ssl_printf("bi_free: active_count went negative " + "- double-freed bigint?\n"); +#endif + return; /* wujg : org ----> abort(); */ + } +} + +/** + * @brief Convert an (unsigned) integer into a bigint. + * @param ctx [in] The bigint session context. + * @param i [in] The (unsigned) integer to be converted. + * + */ +bigint * ICACHE_FLASH_ATTR int_to_bi(BI_CTX *ctx, comp i) +{ + bigint *biR = alloc(ctx, 1); + biR->comps[0] = i; + return biR; +} + +/** + * @brief Do a full copy of the bigint object. + * @param ctx [in] The bigint session context. + * @param bi [in] The bigint object to be copied. + */ +bigint * ICACHE_FLASH_ATTR bi_clone(BI_CTX *ctx, const bigint *bi) +{ + bigint *biR = alloc(ctx, bi->size); + check(bi); + memcpy(biR->comps, bi->comps, bi->size*COMP_BYTE_SIZE); + return biR; +} + +/** + * @brief Perform an addition operation between two bigints. + * @param ctx [in] The bigint session context. + * @param bia [in] A bigint. + * @param bib [in] Another bigint. + * @return The result of the addition. + */ +bigint * ICACHE_FLASH_ATTR bi_add(BI_CTX *ctx, bigint *bia, bigint *bib) +{ + int n; + comp carry = 0; + comp *pa, *pb; + + check(bia); + check(bib); + + n = max(bia->size, bib->size); + more_comps(bia, n+1); + more_comps(bib, n); + pa = bia->comps; + pb = bib->comps; + + do + { + comp sl, rl, cy1; + sl = *pa + *pb++; + rl = sl + carry; + cy1 = sl < *pa; + carry = cy1 | (rl < sl); + *pa++ = rl; + } while (--n != 0); + + *pa = carry; /* do overflow */ + bi_free(ctx, bib); + return trim(bia); +} + +/** + * @brief Perform a subtraction operation between two bigints. + * @param ctx [in] The bigint session context. + * @param bia [in] A bigint. + * @param bib [in] Another bigint. + * @param is_negative [out] If defined, indicates that the result was negative. + * is_negative may be null. + * @return The result of the subtraction. The result is always positive. + */ +bigint * ICACHE_FLASH_ATTR bi_subtract(BI_CTX *ctx, + bigint *bia, bigint *bib, int *is_negative) +{ + int n = bia->size; + comp *pa, *pb, carry = 0; + + check(bia); + check(bib); + + more_comps(bib, n); + pa = bia->comps; + pb = bib->comps; + + do + { + comp sl, rl, cy1; + sl = *pa - *pb++; + rl = sl - carry; + cy1 = sl > *pa; + carry = cy1 | (rl > sl); + *pa++ = rl; + } while (--n != 0); + + if (is_negative) /* indicate a negative result */ + { + *is_negative = carry; + } + + bi_free(ctx, trim(bib)); /* put bib back to the way it was */ + return trim(bia); +} + +/** + * Perform a multiply between a bigint an an (unsigned) integer + */ +static bigint * ICACHE_FLASH_ATTR bi_int_multiply(BI_CTX *ctx, bigint *bia, comp b) +{ + int j = 0, n = bia->size; + bigint *biR = alloc(ctx, n + 1); + comp carry = 0; + comp *r = biR->comps; + comp *a = bia->comps; + + check(bia); + + /* clear things to start with */ + memset(r, 0, ((n+1)*COMP_BYTE_SIZE)); + + do + { + long_comp tmp = *r + (long_comp)a[j]*b + carry; + *r++ = (comp)tmp; /* downsize */ + carry = (comp)(tmp >> COMP_BIT_SIZE); + } while (++j < n); + + *r = carry; + bi_free(ctx, bia); + return trim(biR); +} + +/** + * @brief Does both division and modulo calculations. + * + * Used extensively when doing classical reduction. + * @param ctx [in] The bigint session context. + * @param u [in] A bigint which is the numerator. + * @param v [in] Either the denominator or the modulus depending on the mode. + * @param is_mod [n] Determines if this is a normal division (0) or a reduction + * (1). + * @return The result of the division/reduction. + */ +bigint * ICACHE_FLASH_ATTR bi_divide(BI_CTX *ctx, bigint *u, bigint *v, int is_mod) +{ + int n = v->size, m = u->size-n; + int j = 0, orig_u_size = u->size; + uint8_t mod_offset = ctx->mod_offset; + comp d; + bigint *quotient, *tmp_u; + comp q_dash; + + check(u); + check(v); + + /* if doing reduction and we are < mod, then return mod */ + if (is_mod && bi_compare(v, u) > 0) + { + bi_free(ctx, v); + return u; + } + + quotient = alloc(ctx, m+1); + tmp_u = alloc(ctx, n+1); + v = trim(v); /* make sure we have no leading 0's */ + d = (comp)((long_comp)COMP_RADIX/(V1+1)); + + /* clear things to start with */ + memset(quotient->comps, 0, ((quotient->size)*COMP_BYTE_SIZE)); + + /* normalise */ + if (d > 1) + { + u = bi_int_multiply(ctx, u, d); + + if (is_mod) + { + v = ctx->bi_normalised_mod[mod_offset]; + } + else + { + v = bi_int_multiply(ctx, v, d); + } + } + + if (orig_u_size == u->size) /* new digit position u0 */ + { + more_comps(u, orig_u_size + 1); + } + + do + { + /* get a temporary short version of u */ + memcpy(tmp_u->comps, &u->comps[u->size-n-1-j], (n+1)*COMP_BYTE_SIZE); + + /* calculate q' */ + if (U(0) == V1) + { + q_dash = COMP_RADIX-1; + } + else + { + q_dash = (comp)(((long_comp)U(0)*COMP_RADIX + U(1))/V1); + + if (v->size > 1 && V2) + { + /* we are implementing the following: + if (V2*q_dash > (((U(0)*COMP_RADIX + U(1) - + q_dash*V1)*COMP_RADIX) + U(2))) ... */ + comp inner = (comp)((long_comp)COMP_RADIX*U(0) + U(1) - + (long_comp)q_dash*V1); + if ((long_comp)V2*q_dash > (long_comp)inner*COMP_RADIX + U(2)) + { + q_dash--; + } + } + } + + /* multiply and subtract */ + if (q_dash) + { + int is_negative; + tmp_u = bi_subtract(ctx, tmp_u, + bi_int_multiply(ctx, bi_copy(v), q_dash), &is_negative); + more_comps(tmp_u, n+1); + + Q(j) = q_dash; + + /* add back */ + if (is_negative) + { + Q(j)--; + tmp_u = bi_add(ctx, tmp_u, bi_copy(v)); + + /* lop off the carry */ + tmp_u->size--; + v->size--; + } + } + else + { + Q(j) = 0; + } + + /* copy back to u */ + memcpy(&u->comps[u->size-n-1-j], tmp_u->comps, (n+1)*COMP_BYTE_SIZE); + } while (++j <= m); + + bi_free(ctx, tmp_u); + bi_free(ctx, v); + + if (is_mod) /* get the remainder */ + { + bi_free(ctx, quotient); + return bi_int_divide(ctx, trim(u), d); + } + else /* get the quotient */ + { + bi_free(ctx, u); + return trim(quotient); + } +} + +/* + * Perform an integer divide on a bigint. + */ +static bigint * ICACHE_FLASH_ATTR bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom) +{ + int i = biR->size - 1; + long_comp r = 0; + + check(biR); + + do + { + r = (r<comps[i]; + biR->comps[i] = (comp)(r / denom); + r %= denom; + } while (--i >= 0); + + return trim(biR); +} + +#ifdef CONFIG_BIGINT_MONTGOMERY +/** + * There is a need for the value of integer N' such that B^-1(B-1)-N^-1N'=1, + * where B^-1(B-1) mod N=1. Actually, only the least significant part of + * N' is needed, hence the definition N0'=N' mod b. We reproduce below the + * simple algorithm from an article by Dusse and Kaliski to efficiently + * find N0' from N0 and b */ +static comp ICACHE_FLASH_ATTR modular_inverse(bigint *bim) +{ + int i; + comp t = 1; + comp two_2_i_minus_1 = 2; /* 2^(i-1) */ + long_comp two_2_i = 4; /* 2^i */ + comp N = bim->comps[0]; + + for (i = 2; i <= COMP_BIT_SIZE; i++) + { + if ((long_comp)N*t%two_2_i >= two_2_i_minus_1) + { + t += two_2_i_minus_1; + } + + two_2_i_minus_1 <<= 1; + two_2_i <<= 1; + } + + return (comp)(COMP_RADIX-t); +} +#endif + +#if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \ + defined(CONFIG_BIGINT_MONTGOMERY) +/** + * Take each component and shift down (in terms of components) + */ +static bigint * ICACHE_FLASH_ATTR comp_right_shift(bigint *biR, int num_shifts) +{ + int i = biR->size-num_shifts; + comp *x = biR->comps; + comp *y = &biR->comps[num_shifts]; + + check(biR); + + if (i <= 0) /* have we completely right shifted? */ + { + biR->comps[0] = 0; /* return 0 */ + biR->size = 1; + return biR; + } + + do + { + *x++ = *y++; + } while (--i > 0); + + biR->size -= num_shifts; + return biR; +} + +/** + * Take each component and shift it up (in terms of components) + */ +static bigint * ICACHE_FLASH_ATTR comp_left_shift(bigint *biR, int num_shifts) +{ + int i = biR->size-1; + comp *x, *y; + + check(biR); + + if (num_shifts <= 0) + { + return biR; + } + + more_comps(biR, biR->size + num_shifts); + + x = &biR->comps[i+num_shifts]; + y = &biR->comps[i]; + + do + { + *x-- = *y--; + } while (i--); + + memset(biR->comps, 0, num_shifts*COMP_BYTE_SIZE); /* zero LS comps */ + return biR; +} +#endif + +/** + * @brief Allow a binary sequence to be imported as a bigint. + * @param ctx [in] The bigint session context. + * @param data [in] The data to be converted. + * @param size [in] The number of bytes of data. + * @return A bigint representing this data. + */ +bigint * ICACHE_FLASH_ATTR bi_import(BI_CTX *ctx, const uint8_t *data, int size) +{ + bigint *biR = alloc(ctx, (size+COMP_BYTE_SIZE-1)/COMP_BYTE_SIZE); + int i, j = 0, offset = 0; + + memset(biR->comps, 0, biR->size*COMP_BYTE_SIZE); + + for (i = size-1; i >= 0; i--) + { + biR->comps[offset] += data[i] << (j*8); + + if (++j == COMP_BYTE_SIZE) + { + j = 0; + offset ++; + } + } + + return trim(biR); +} + +#ifdef CONFIG_SSL_FULL_MODE +/** + * @brief The testharness uses this code to import text hex-streams and + * convert them into bigints. + * @param ctx [in] The bigint session context. + * @param data [in] A string consisting of hex characters. The characters must + * be in upper case. + * @return A bigint representing this data. + */ +bigint * ICACHE_FLASH_ATTR bi_str_import(BI_CTX *ctx, const char *data) +{ + int size = strlen(data); + bigint *biR = alloc(ctx, (size+COMP_NUM_NIBBLES-1)/COMP_NUM_NIBBLES); + int i, j = 0, offset = 0; + memset(biR->comps, 0, biR->size*COMP_BYTE_SIZE); + + for (i = size-1; i >= 0; i--) + { + int num = (data[i] <= '9') ? (data[i] - '0') : (data[i] - 'A' + 10); + biR->comps[offset] += num << (j*4); + + if (++j == COMP_NUM_NIBBLES) + { + j = 0; + offset ++; + } + } + + return biR; +} + +void ICACHE_FLASH_ATTR bi_print(const char *label, bigint *x) +{ + int i, j; + + if (x == NULL) + { + ssl_printf("%s: (null)\n", label); + return; + } + + ssl_printf("%s: (size %d)\n", label, x->size); + for (i = x->size-1; i >= 0; i--) + { + for (j = COMP_NUM_NIBBLES-1; j >= 0; j--) + { + comp mask = 0x0f << (j*4); + comp num = (x->comps[i] & mask) >> (j*4); + os_putc((num <= 9) ? (num + '0') : (num + 'A' - 10)); + } + } + + ssl_printf("\n"); +} +#endif + +/** + * @brief Take a bigint and convert it into a byte sequence. + * + * This is useful after a decrypt operation. + * @param ctx [in] The bigint session context. + * @param x [in] The bigint to be converted. + * @param data [out] The converted data as a byte stream. + * @param size [in] The maximum size of the byte stream. Unused bytes will be + * zeroed. + */ +void ICACHE_FLASH_ATTR bi_export(BI_CTX *ctx, bigint *x, uint8_t *data, int size) +{ + int i, j, k = size-1; + + check(x); + memset(data, 0, size); /* ensure all leading 0's are cleared */ + + for (i = 0; i < x->size; i++) + { + for (j = 0; j < COMP_BYTE_SIZE; j++) + { + comp mask = 0xff << (j*8); + int num = (x->comps[i] & mask) >> (j*8); + data[k--] = num; + + if (k < 0) + { + goto buf_done; + } + } + } +buf_done: + + bi_free(ctx, x); +} + +/** + * @brief Pre-calculate some of the expensive steps in reduction. + * + * This function should only be called once (normally when a session starts). + * When the session is over, bi_free_mod() should be called. bi_mod_power() + * relies on this function being called. + * @param ctx [in] The bigint session context. + * @param bim [in] The bigint modulus that will be used. + * @param mod_offset [in] There are three moduluii that can be stored - the + * standard modulus, and its two primes p and q. This offset refers to which + * modulus we are referring to. + * @see bi_free_mod(), bi_mod_power(). + */ +void ICACHE_FLASH_ATTR bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset) +{ + int k = bim->size; + comp d = (comp)((long_comp)COMP_RADIX/(bim->comps[k-1]+1)); +#ifdef CONFIG_BIGINT_MONTGOMERY + bigint *R, *R2; +#endif + + ctx->bi_mod[mod_offset] = bim; + bi_permanent(ctx->bi_mod[mod_offset]); + ctx->bi_normalised_mod[mod_offset] = bi_int_multiply(ctx, bim, d); + bi_permanent(ctx->bi_normalised_mod[mod_offset]); + +#if defined(CONFIG_BIGINT_MONTGOMERY) + /* set montgomery variables */ + R = comp_left_shift(bi_clone(ctx, ctx->bi_radix), k-1); /* R */ + R2 = comp_left_shift(bi_clone(ctx, ctx->bi_radix), k*2-1); /* R^2 */ + ctx->bi_RR_mod_m[mod_offset] = bi_mod(ctx, R2); /* R^2 mod m */ + ctx->bi_R_mod_m[mod_offset] = bi_mod(ctx, R); /* R mod m */ + + bi_permanent(ctx->bi_RR_mod_m[mod_offset]); + bi_permanent(ctx->bi_R_mod_m[mod_offset]); + + ctx->N0_dash[mod_offset] = modular_inverse(ctx->bi_mod[mod_offset]); + +#elif defined (CONFIG_BIGINT_BARRETT) + ctx->bi_mu[mod_offset] = + bi_divide(ctx, comp_left_shift( + bi_clone(ctx, ctx->bi_radix), k*2-1), ctx->bi_mod[mod_offset], 0); + bi_permanent(ctx->bi_mu[mod_offset]); +#endif +} + +/** + * @brief Used when cleaning various bigints at the end of a session. + * @param ctx [in] The bigint session context. + * @param mod_offset [in] The offset to use. + * @see bi_set_mod(). + */ +void ICACHE_FLASH_ATTR bi_free_mod(BI_CTX *ctx, int mod_offset) +{ + bi_depermanent(ctx->bi_mod[mod_offset]); + bi_free(ctx, ctx->bi_mod[mod_offset]); +#if defined (CONFIG_BIGINT_MONTGOMERY) + bi_depermanent(ctx->bi_RR_mod_m[mod_offset]); + bi_depermanent(ctx->bi_R_mod_m[mod_offset]); + bi_free(ctx, ctx->bi_RR_mod_m[mod_offset]); + bi_free(ctx, ctx->bi_R_mod_m[mod_offset]); +#elif defined(CONFIG_BIGINT_BARRETT) + bi_depermanent(ctx->bi_mu[mod_offset]); + bi_free(ctx, ctx->bi_mu[mod_offset]); +#endif + bi_depermanent(ctx->bi_normalised_mod[mod_offset]); + bi_free(ctx, ctx->bi_normalised_mod[mod_offset]); +} + +/** + * Perform a standard multiplication between two bigints. + * + * Barrett reduction has no need for some parts of the product, so ignore bits + * of the multiply. This routine gives Barrett its big performance + * improvements over Classical/Montgomery reduction methods. + */ +static bigint * ICACHE_FLASH_ATTR regular_multiply(BI_CTX *ctx, bigint *bia, bigint *bib, + int inner_partial, int outer_partial) +{ + int i = 0, j; + int n = bia->size; + int t = bib->size; + bigint *biR = alloc(ctx, n + t); + comp *sr = biR->comps; + comp *sa = bia->comps; + comp *sb = bib->comps; + + check(bia); + check(bib); + + /* clear things to start with */ + memset(biR->comps, 0, ((n+t)*COMP_BYTE_SIZE)); + + do + { + long_comp tmp; + comp carry = 0; + int r_index = i; + j = 0; + + if (outer_partial && outer_partial-i > 0 && outer_partial < n) + { + r_index = outer_partial-1; + j = outer_partial-i-1; + } + + do + { + if (inner_partial && r_index >= inner_partial) + { + break; + } + + tmp = sr[r_index] + ((long_comp)sa[j])*sb[i] + carry; + sr[r_index++] = (comp)tmp; /* downsize */ + carry = tmp >> COMP_BIT_SIZE; + } while (++j < n); + + sr[r_index] = carry; + } while (++i < t); + + bi_free(ctx, bia); + bi_free(ctx, bib); + return trim(biR); +} + +#ifdef CONFIG_BIGINT_KARATSUBA +/* + * Karatsuba improves on regular multiplication due to only 3 multiplications + * being done instead of 4. The additional additions/subtractions are O(N) + * rather than O(N^2) and so for big numbers it saves on a few operations + */ +static bigint * ICACHE_FLASH_ATTR karatsuba(BI_CTX *ctx, bigint *bia, bigint *bib, int is_square) +{ + bigint *x0, *x1; + bigint *p0, *p1, *p2; + int m; + + if (is_square) + { + m = (bia->size + 1)/2; + } + else + { + m = (max(bia->size, bib->size) + 1)/2; + } + + x0 = bi_clone(ctx, bia); + x0->size = m; + x1 = bi_clone(ctx, bia); + comp_right_shift(x1, m); + bi_free(ctx, bia); + + /* work out the 3 partial products */ + if (is_square) + { + p0 = bi_square(ctx, bi_copy(x0)); + p2 = bi_square(ctx, bi_copy(x1)); + p1 = bi_square(ctx, bi_add(ctx, x0, x1)); + } + else /* normal multiply */ + { + bigint *y0, *y1; + y0 = bi_clone(ctx, bib); + y0->size = m; + y1 = bi_clone(ctx, bib); + comp_right_shift(y1, m); + bi_free(ctx, bib); + + p0 = bi_multiply(ctx, bi_copy(x0), bi_copy(y0)); + p2 = bi_multiply(ctx, bi_copy(x1), bi_copy(y1)); + p1 = bi_multiply(ctx, bi_add(ctx, x0, x1), bi_add(ctx, y0, y1)); + } + + p1 = bi_subtract(ctx, + bi_subtract(ctx, p1, bi_copy(p2), NULL), bi_copy(p0), NULL); + + comp_left_shift(p1, m); + comp_left_shift(p2, 2*m); + return bi_add(ctx, p1, bi_add(ctx, p0, p2)); +} +#endif + +/** + * @brief Perform a multiplication operation between two bigints. + * @param ctx [in] The bigint session context. + * @param bia [in] A bigint. + * @param bib [in] Another bigint. + * @return The result of the multiplication. + */ +bigint * ICACHE_FLASH_ATTR bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib) +{ + check(bia); + check(bib); + +#ifdef CONFIG_BIGINT_KARATSUBA + if (min(bia->size, bib->size) < MUL_KARATSUBA_THRESH) + { + return regular_multiply(ctx, bia, bib, 0, 0); + } + + return karatsuba(ctx, bia, bib, 0); +#else + return regular_multiply(ctx, bia, bib, 0, 0); +#endif +} + +#ifdef CONFIG_BIGINT_SQUARE +/* + * Perform the actual square operion. It takes into account overflow. + */ +static bigint * ICACHE_FLASH_ATTR regular_square(BI_CTX *ctx, bigint *bi) +{ + int t = bi->size; + int i = 0, j; + bigint *biR = alloc(ctx, t*2+1); + comp *w = biR->comps; + comp *x = bi->comps; + long_comp carry; + memset(w, 0, biR->size*COMP_BYTE_SIZE); + + do + { + long_comp tmp = w[2*i] + (long_comp)x[i]*x[i]; + w[2*i] = (comp)tmp; + carry = tmp >> COMP_BIT_SIZE; + + for (j = i+1; j < t; j++) + { + uint8_t c = 0; + long_comp xx = (long_comp)x[i]*x[j]; + if ((COMP_MAX-xx) < xx) + c = 1; + + tmp = (xx<<1); + + if ((COMP_MAX-tmp) < w[i+j]) + c = 1; + + tmp += w[i+j]; + + if ((COMP_MAX-tmp) < carry) + c = 1; + + tmp += carry; + w[i+j] = (comp)tmp; + carry = tmp >> COMP_BIT_SIZE; + + if (c) + carry += COMP_RADIX; + } + + tmp = w[i+t] + carry; + w[i+t] = (comp)tmp; + w[i+t+1] = tmp >> COMP_BIT_SIZE; + } while (++i < t); + + bi_free(ctx, bi); + return trim(biR); +} + +/** + * @brief Perform a square operation on a bigint. + * @param ctx [in] The bigint session context. + * @param bia [in] A bigint. + * @return The result of the multiplication. + */ +bigint * ICACHE_FLASH_ATTR bi_square(BI_CTX *ctx, bigint *bia) +{ + check(bia); + +#ifdef CONFIG_BIGINT_KARATSUBA + if (bia->size < SQU_KARATSUBA_THRESH) + { + return regular_square(ctx, bia); + } + + return karatsuba(ctx, bia, NULL, 1); +#else + return regular_square(ctx, bia); +#endif +} +#endif + +/** + * @brief Compare two bigints. + * @param bia [in] A bigint. + * @param bib [in] Another bigint. + * @return -1 if smaller, 1 if larger and 0 if equal. + */ +int ICACHE_FLASH_ATTR bi_compare(bigint *bia, bigint *bib) +{ + int r, i; + + check(bia); + check(bib); + + if (bia->size > bib->size) + r = 1; + else if (bia->size < bib->size) + r = -1; + else + { + comp *a = bia->comps; + comp *b = bib->comps; + + /* Same number of components. Compare starting from the high end + * and working down. */ + r = 0; + i = bia->size - 1; + + do + { + if (a[i] > b[i]) + { + r = 1; + break; + } + else if (a[i] < b[i]) + { + r = -1; + break; + } + } while (--i >= 0); + } + + return r; +} + +/* + * Allocate and zero more components. Does not consume bi. + */ +static void ICACHE_FLASH_ATTR more_comps(bigint *bi, int n) +{ + comp * bi_backs = NULL; + if (n > bi->max_comps) + { + bi->max_comps = max(bi->max_comps * 2, n); + if(bi->comps) { + //bi->comps = (comp*)SSL_REALLOC(bi->comps, bi->max_comps * COMP_BYTE_SIZE); + bi_backs = (comp*)SSL_ZALLOC(bi->max_comps * COMP_BYTE_SIZE); + if(bi_backs) { + memcpy(bi_backs,bi->comps,bi->max_comps * COMP_BYTE_SIZE); + SSL_FREE(bi->comps); + bi->comps = bi_backs; + } + } + } + + if (n > bi->size) + { + memset(&bi->comps[bi->size], 0, (n-bi->size)*COMP_BYTE_SIZE); + } + + bi->size = n; +} + +/* + * Make a new empty bigint. It may just use an old one if one is available. + * Otherwise get one off the heap. + */ +static bigint * ICACHE_FLASH_ATTR alloc(BI_CTX *ctx, int size) +{ + bigint *biR; + + /* Can we recycle an old bigint? */ + if (ctx->free_list != NULL) + { + biR = ctx->free_list; + ctx->free_list = biR->next; + ctx->free_count--; + + if (biR->refs != 0) + { +#ifdef CONFIG_SSL_FULL_MODE + ssl_printf("alloc: refs was not 0\n"); +#endif + return biR; /* wujg : org ----> abort(); */ + } + + more_comps(biR, size); + } + else + { + /* No free bigints available - create a new one. */ + biR = (bigint *)SSL_MALLOC(sizeof(bigint)); + biR->comps = (comp*)SSL_MALLOC(size * COMP_BYTE_SIZE); + biR->max_comps = size; /* give some space to spare */ + } + + biR->size = size; + biR->refs = 1; + biR->next = NULL; + ctx->active_count++; + return biR; +} + +/* + * Work out the highest '1' bit in an exponent. Used when doing sliding-window + * exponentiation. + */ +static int ICACHE_FLASH_ATTR find_max_exp_index(bigint *biexp) +{ + int i = COMP_BIT_SIZE-1; + comp shift = COMP_RADIX/2; + comp test = biexp->comps[biexp->size-1]; /* assume no leading zeroes */ + + check(biexp); + + do + { + if (test & shift) + { + return i+(biexp->size-1)*COMP_BIT_SIZE; + } + + shift >>= 1; + } while (i-- != 0); + + return -1; /* error - must have been a leading 0 */ +} + +/* + * Is a particular bit is an exponent 1 or 0? Used when doing sliding-window + * exponentiation. + */ +static int ICACHE_FLASH_ATTR exp_bit_is_one(bigint *biexp, int offset) +{ + comp test = biexp->comps[offset / COMP_BIT_SIZE]; + int num_shifts = offset % COMP_BIT_SIZE; + comp shift = 1; + int i; + + check(biexp); + + for (i = 0; i < num_shifts; i++) + { + shift <<= 1; + } + + return (test & shift) != 0; +} + +#ifdef CONFIG_BIGINT_CHECK_ON +/* + * Perform a sanity check on bi. + */ +static void ICACHE_FLASH_ATTR check(const bigint *bi) +{ + if (bi->refs <= 0) + { + ssl_printf("check: zero or negative refs in bigint\n"); + return; /* wujg : org ----> abort(); */ + } + + if (bi->next != NULL) + { + ssl_printf("check: attempt to use a bigint from " + "the free list\n"); + return; /* wujg : org ----> abort(); */ + } +} +#endif + +/* + * Delete any leading 0's (and allow for 0). + */ +static bigint * ICACHE_FLASH_ATTR trim(bigint *bi) +{ + check(bi); + + while (bi->comps[bi->size-1] == 0 && bi->size > 1) + { + bi->size--; + } + + return bi; +} + +#if defined(CONFIG_BIGINT_MONTGOMERY) +/** + * @brief Perform a single montgomery reduction. + * @param ctx [in] The bigint session context. + * @param bixy [in] A bigint. + * @return The result of the montgomery reduction. + */ +bigint * ICACHE_FLASH_ATTR bi_mont(BI_CTX *ctx, bigint *bixy) +{ + int i = 0, n; + uint8_t mod_offset = ctx->mod_offset; + bigint *bim = ctx->bi_mod[mod_offset]; + comp mod_inv = ctx->N0_dash[mod_offset]; + + check(bixy); + + if (ctx->use_classical) /* just use classical instead */ + { + return bi_mod(ctx, bixy); + } + + n = bim->size; + + do + { + bixy = bi_add(ctx, bixy, comp_left_shift( + bi_int_multiply(ctx, bim, bixy->comps[i]*mod_inv), i)); + } while (++i < n); + + comp_right_shift(bixy, n); + + if (bi_compare(bixy, bim) >= 0) + { + bixy = bi_subtract(ctx, bixy, bim, NULL); + } + + return bixy; +} + +#elif defined(CONFIG_BIGINT_BARRETT) +/* + * Stomp on the most significant components to give the illusion of a "mod base + * radix" operation + */ +static bigint * ICACHE_FLASH_ATTR comp_mod(bigint *bi, int mod) +{ + check(bi); + + if (bi->size > mod) + { + bi->size = mod; + } + + return bi; +} + +/** + * @brief Perform a single Barrett reduction. + * @param ctx [in] The bigint session context. + * @param bi [in] A bigint. + * @return The result of the Barrett reduction. + */ +bigint * ICACHE_FLASH_ATTR bi_barrett(BI_CTX *ctx, bigint *bi) +{ + bigint *q1, *q2, *q3, *r1, *r2, *r; + uint8_t mod_offset = ctx->mod_offset; + bigint *bim = ctx->bi_mod[mod_offset]; + int k = bim->size; + + check(bi); + check(bim); + + /* use Classical method instead - Barrett cannot help here */ + if (bi->size > k*2) + { + return bi_mod(ctx, bi); + } + + q1 = comp_right_shift(bi_clone(ctx, bi), k-1); + + /* do outer partial multiply */ + q2 = regular_multiply(ctx, q1, ctx->bi_mu[mod_offset], 0, k-1); + q3 = comp_right_shift(q2, k+1); + r1 = comp_mod(bi, k+1); + + /* do inner partial multiply */ + r2 = comp_mod(regular_multiply(ctx, q3, bim, k+1, 0), k+1); + r = bi_subtract(ctx, r1, r2, NULL); + + /* if (r >= m) r = r - m; */ + if (bi_compare(r, bim) >= 0) + { + r = bi_subtract(ctx, r, bim, NULL); + } + + return r; +} +#endif /* CONFIG_BIGINT_BARRETT */ + +#ifdef CONFIG_BIGINT_SLIDING_WINDOW +/* + * Work out g1, g3, g5, g7... etc for the sliding-window algorithm + */ +static void ICACHE_FLASH_ATTR precompute_slide_window(BI_CTX *ctx, int window, bigint *g1) +{ + int k = 1, i; + bigint *g2; + + for (i = 0; i < window-1; i++) /* compute 2^(window-1) */ + { + k <<= 1; + } + + ctx->g = (bigint **)SSL_MALLOC(k*sizeof(bigint *)); + ctx->g[0] = bi_clone(ctx, g1); + bi_permanent(ctx->g[0]); + g2 = bi_residue(ctx, bi_square(ctx, ctx->g[0])); /* g^2 */ + + for (i = 1; i < k; i++) + { + ctx->g[i] = bi_residue(ctx, bi_multiply(ctx, ctx->g[i-1], bi_copy(g2))); + bi_permanent(ctx->g[i]); + } + + bi_free(ctx, g2); + ctx->window = k; +} +#endif + +/** + * @brief Perform a modular exponentiation. + * + * This function requires bi_set_mod() to have been called previously. This is + * one of the optimisations used for performance. + * @param ctx [in] The bigint session context. + * @param bi [in] The bigint on which to perform the mod power operation. + * @param biexp [in] The bigint exponent. + * @return The result of the mod exponentiation operation + * @see bi_set_mod(). + */ +bigint * ICACHE_FLASH_ATTR bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp) +{ + int i = find_max_exp_index(biexp), j, window_size = 1; + bigint *biR = int_to_bi(ctx, 1); + +#if defined(CONFIG_BIGINT_MONTGOMERY) + uint8_t mod_offset = ctx->mod_offset; + if (!ctx->use_classical) + { + /* preconvert */ + bi = bi_mont(ctx, + bi_multiply(ctx, bi, ctx->bi_RR_mod_m[mod_offset])); /* x' */ + bi_free(ctx, biR); + biR = ctx->bi_R_mod_m[mod_offset]; /* A */ + } +#endif + + check(bi); + check(biexp); + +#ifdef CONFIG_BIGINT_SLIDING_WINDOW + for (j = i; j > 32; j /= 5) /* work out an optimum size */ + window_size++; + + /* work out the slide constants */ + precompute_slide_window(ctx, window_size, bi); +#else /* just one constant */ + ctx->g = (bigint **)SSL_MALLOC(sizeof(bigint *)); + ctx->g[0] = bi_clone(ctx, bi); + ctx->window = 1; + bi_permanent(ctx->g[0]); +#endif + + /* if sliding-window is off, then only one bit will be done at a time and + * will reduce to standard left-to-right exponentiation */ + do + { + if (exp_bit_is_one(biexp, i)) + { + int l = i-window_size+1; + int part_exp = 0; + + if (l < 0) /* LSB of exponent will always be 1 */ + l = 0; + else + { + while (exp_bit_is_one(biexp, l) == 0) + l++; /* go back up */ + } + + /* build up the section of the exponent */ + for (j = i; j >= l; j--) + { + biR = bi_residue(ctx, bi_square(ctx, biR)); + if (exp_bit_is_one(biexp, j)) + part_exp++; + + if (j != l) + part_exp <<= 1; + } + + part_exp = (part_exp-1)/2; /* adjust for array */ + biR = bi_residue(ctx, bi_multiply(ctx, biR, ctx->g[part_exp])); + i = l-1; + } + else /* square it */ + { + biR = bi_residue(ctx, bi_square(ctx, biR)); + i--; + } + } while (i >= 0); + + /* cleanup */ + for (i = 0; i < ctx->window; i++) + { + bi_depermanent(ctx->g[i]); + bi_free(ctx, ctx->g[i]); + } + + SSL_FREE(ctx->g); + bi_free(ctx, bi); + bi_free(ctx, biexp); +#if defined CONFIG_BIGINT_MONTGOMERY + return ctx->use_classical ? biR : bi_mont(ctx, biR); /* convert back */ +#else /* CONFIG_BIGINT_CLASSICAL or CONFIG_BIGINT_BARRETT */ + return biR; +#endif +} + +#ifdef CONFIG_SSL_CERT_VERIFICATION +/** + * @brief Perform a modular exponentiation using a temporary modulus. + * + * We need this function to check the signatures of certificates. The modulus + * of this function is temporary as it's just used for authentication. + * @param ctx [in] The bigint session context. + * @param bi [in] The bigint to perform the exp/mod. + * @param bim [in] The temporary modulus. + * @param biexp [in] The bigint exponent. + * @return The result of the mod exponentiation operation + * @see bi_set_mod(). + */ +bigint * ICACHE_FLASH_ATTR bi_mod_power2(BI_CTX *ctx, bigint *bi, bigint *bim, bigint *biexp) +{ + bigint *biR, *tmp_biR; + + /* Set up a temporary bigint context and transfer what we need between + * them. We need to do this since we want to keep the original modulus + * which is already in this context. This operation is only called when + * doing peer verification, and so is not expensive :-) */ + BI_CTX *tmp_ctx = bi_initialize(); + bi_set_mod(tmp_ctx, bi_clone(tmp_ctx, bim), BIGINT_M_OFFSET); + tmp_biR = bi_mod_power(tmp_ctx, + bi_clone(tmp_ctx, bi), + bi_clone(tmp_ctx, biexp)); + biR = bi_clone(ctx, tmp_biR); + bi_free(tmp_ctx, tmp_biR); + bi_free_mod(tmp_ctx, BIGINT_M_OFFSET); + bi_terminate(tmp_ctx); + + bi_free(ctx, bi); + bi_free(ctx, bim); + bi_free(ctx, biexp); + return biR; +} +#endif + +#ifdef CONFIG_BIGINT_CRT +/** + * @brief Use the Chinese Remainder Theorem to quickly perform RSA decrypts. + * + * @param ctx [in] The bigint session context. + * @param bi [in] The bigint to perform the exp/mod. + * @param dP [in] CRT's dP bigint + * @param dQ [in] CRT's dQ bigint + * @param p [in] CRT's p bigint + * @param q [in] CRT's q bigint + * @param qInv [in] CRT's qInv bigint + * @return The result of the CRT operation + */ +bigint * ICACHE_FLASH_ATTR bi_crt(BI_CTX *ctx, bigint *bi, + bigint *dP, bigint *dQ, + bigint *p, bigint *q, bigint *qInv) +{ + bigint *m1, *m2, *h; + + /* Montgomery has a condition the 0 < x, y < m and these products violate + * that condition. So disable Montgomery when using CRT */ +#if defined(CONFIG_BIGINT_MONTGOMERY) + ctx->use_classical = 1; +#endif + ctx->mod_offset = BIGINT_P_OFFSET; + m1 = bi_mod_power(ctx, bi_copy(bi), dP); + + ctx->mod_offset = BIGINT_Q_OFFSET; + m2 = bi_mod_power(ctx, bi, dQ); + + h = bi_subtract(ctx, bi_add(ctx, m1, p), bi_copy(m2), NULL); + h = bi_multiply(ctx, h, qInv); + ctx->mod_offset = BIGINT_P_OFFSET; + h = bi_residue(ctx, h); +#if defined(CONFIG_BIGINT_MONTGOMERY) + ctx->use_classical = 0; /* reset for any further operation */ +#endif + return bi_add(ctx, m2, bi_multiply(ctx, q, h)); +} +#endif +/** @} */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_crypto_misc.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_crypto_misc.c new file mode 100644 index 0000000..39fb178 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_crypto_misc.c @@ -0,0 +1,418 @@ +/* + * 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. + */ + +/** + * Some misc. routines to help things out + */ + +#include "ssl/ssl_os_port.h" +#include "ssl/ssl_ssl.h" +#include "ssl/ssl_crypto_misc.h" + +//#include "lwip/sockets.h" +#include + +#ifdef CONFIG_WIN32_USE_CRYPTO_LIB +#include "wincrypt.h" +#endif + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +#ifndef WIN32 +//static int rng_fd = -1; +#elif defined(CONFIG_WIN32_USE_CRYPTO_LIB) +static HCRYPTPROV gCryptProv; +#endif + +#if (!defined(CONFIG_USE_DEV_URANDOM) && !defined(CONFIG_WIN32_USE_CRYPTO_LIB)) +/* change to processor registers as appropriate */ +#define ENTROPY_POOL_SIZE 32 +#define ENTROPY_COUNTER1 ((((uint64_t)tv.tv_sec)<<32) | tv.tv_usec) +#define ENTROPY_COUNTER2 rand() +static uint8_t entropy_pool[ENTROPY_POOL_SIZE]; +#endif + +const char unsupported_str[] ICACHE_RODATA_ATTR STORE_ATTR = "Error: Feature not supported\n"; + +#ifndef CONFIG_SSL_SKELETON_MODE +/** + * Retrieve a file and put it into memory + * @return The size of the file, or -1 on failure. + */ +int ICACHE_FLASH_ATTR get_file(const char *filename, uint8_t **buf) +{ +#ifdef FILE + int total_bytes = 0; + int bytes_read = 0; + int filesize; + FILE *stream = fopen(filename, "rb"); + + if (stream == NULL) + { +#ifdef CONFIG_SSL_FULL_MODE + printf("file '%s' does not exist\n", filename); //TTY_FLUSH(); +#endif + return -1; + } + + /* Win CE doesn't support stat() */ + fseek(stream, 0, SEEK_END); + filesize = ftell(stream); + *buf = (uint8_t *)SSL_MALLOC(filesize); + fseek(stream, 0, SEEK_SET); + + do + { + bytes_read = fread(*buf+total_bytes, 1, filesize-total_bytes, stream); + total_bytes += bytes_read; + } while (total_bytes < filesize && bytes_read > 0); + + fclose(stream); + return filesize; +#else + int total_bytes = 0; + int bytes_read = 0; + int filesize; + int stream = -1; + struct stat stream_stat; + + stream = open(filename, 0x18); + if (stream < 0) { +#ifdef CONFIG_SSL_FULL_MODE + os_printf("file '%s' does not exist\n", filename); +#endif + return -1; + } + + filesize = fstat(stream, &stream_stat); + if (filesize < 0) { + close(stream); + return filesize; + } + + if (stream_stat.st_size == 0) { + close(stream); + return 0; + } + filesize = stream_stat.st_size; + *buf = (uint8_t *) SSL_ZALLOC(filesize); + + do { + bytes_read = read(stream, *buf + total_bytes, filesize - total_bytes); + total_bytes += bytes_read; + } while (total_bytes < filesize && bytes_read > 0); + + close(stream); + return filesize; +#endif +} +#endif + +/** + * Initialise the Random Number Generator engine. + * - On Win32 use the platform SDK's crypto engine. + * - On Linux use /dev/urandom + * - If none of these work then use a custom RNG. + */ +EXP_FUNC void STDCALL ICACHE_FLASH_ATTR RNG_initialize() +{ +#if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM) +// rng_fd = ax_open("/dev/urandom", O_RDONLY); +#elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB) + if (!CryptAcquireContext(&gCryptProv, + NULL, NULL, PROV_RSA_FULL, 0)) + { + if (GetLastError() == NTE_BAD_KEYSET && + !CryptAcquireContext(&gCryptProv, + NULL, + NULL, + PROV_RSA_FULL, + CRYPT_NEWKEYSET)) + { + printf("CryptoLib: %x\n", unsupported_str, GetLastError()); + exit(1); + } + } +#else + /* start of with a stack to copy across */ + int i; + memcpy(entropy_pool, &i, ENTROPY_POOL_SIZE); + srand((unsigned int)&i); +#endif +} + +/** + * If no /dev/urandom, then initialise the RNG with something interesting. + */ +EXP_FUNC void STDCALL ICACHE_FLASH_ATTR RNG_custom_init(const uint8_t *seed_buf, int size) +{ +#if defined(WIN32) || defined(CONFIG_WIN32_USE_CRYPTO_LIB) + int i; + + for (i = 0; i < ENTROPY_POOL_SIZE && i < size; i++) + entropy_pool[i] ^= seed_buf[i]; +#endif +} + +/** + * Terminate the RNG engine. + */ +EXP_FUNC void STDCALL ICACHE_FLASH_ATTR RNG_terminate(void) +{ +#ifndef WIN32 +// close(rng_fd); +#elif defined(CONFIG_WIN32_USE_CRYPTO_LIB) + CryptReleaseContext(gCryptProv, 0); +#endif +} + +/** + * Set a series of bytes with a random number. Individual bytes can be 0 + */ +EXP_FUNC int STDCALL ICACHE_FLASH_ATTR get_random(int num_rand_bytes, uint8_t *rand_data) +{ +#if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM) +// /* use the Linux default */ +// read(rng_fd, rand_data, num_rand_bytes); /* read from /dev/urandom */ + os_get_random(rand_data, num_rand_bytes); + +#elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB) + /* use Microsoft Crypto Libraries */ + CryptGenRandom(gCryptProv, num_rand_bytes, rand_data); +#else /* nothing else to use, so use a custom RNG */ + /* The method we use when we've got nothing better. Use RC4, time + and a couple of random seeds to generate a random sequence */ + RC4_CTX rng_ctx; + struct timeval tv; + MD5_CTX rng_digest_ctx; + uint8_t digest[MD5_SIZE]; + uint64_t *ep; + int i; + + /* A proper implementation would use counters etc for entropy */ +// gettimeofday(&tv, NULL); + ep = (uint64_t *)entropy_pool; + ep[0] ^= ENTROPY_COUNTER1; + ep[1] ^= ENTROPY_COUNTER2; + + /* use a digested version of the entropy pool as a key */ + MD5_Init(&rng_digest_ctx); + MD5_Update(&rng_digest_ctx, entropy_pool, ENTROPY_POOL_SIZE); + MD5_Final(digest, &rng_digest_ctx); + + /* come up with the random sequence */ + RC4_setup(&rng_ctx, digest, MD5_SIZE); /* use as a key */ + memcpy(rand_data, entropy_pool, num_rand_bytes < ENTROPY_POOL_SIZE ? + num_rand_bytes : ENTROPY_POOL_SIZE); + RC4_crypt(&rng_ctx, rand_data, rand_data, num_rand_bytes); + + /* move things along */ + for (i = ENTROPY_POOL_SIZE-1; i >= MD5_SIZE ; i--) + entropy_pool[i] = entropy_pool[i-MD5_SIZE]; + + /* insert the digest at the start of the entropy pool */ + memcpy(entropy_pool, digest, MD5_SIZE); +#endif + return 0; +} + +/** + * Set a series of bytes with a random number. Individual bytes are not zero. + */ +int ICACHE_FLASH_ATTR get_random_NZ(int num_rand_bytes, uint8_t *rand_data) +{ + int i; + if (get_random(num_rand_bytes, rand_data)) + return -1; + + for (i = 0; i < num_rand_bytes; i++) + { + while (rand_data[i] == 0) /* can't be 0 */ + rand_data[i] = (uint8_t)(os_random()); + } + + return 0; +} + +/** + * Some useful diagnostic routines + */ +#if defined(CONFIG_SSL_FULL_MODE) || defined(CONFIG_DEBUG) +int hex_finish; +int hex_index; + +static void ICACHE_FLASH_ATTR print_hex_init(int finish) +{ + hex_finish = finish; + hex_index = 0; +} + +static void ICACHE_FLASH_ATTR print_hex(uint8_t hex) +{ + static int column; + + if (hex_index == 0) + { + column = 0; + } + + ssl_printf("%02x ", hex); + if (++column == 8) + { + ssl_printf(": "); + } + else if (column >= 16) + { + ssl_printf("\n"); + column = 0; + } + + if (++hex_index >= hex_finish && column > 0) + { + ssl_printf("\n"); + } +} + +/** + * Spit out a blob of data for diagnostics. The data is is a nice column format + * for easy reading. + * + * @param format [in] The string (with possible embedded format characters) + * @param size [in] The number of numbers to print + * @param data [in] The start of data to use + * @param ... [in] Any additional arguments + */ +EXP_FUNC void STDCALL ICACHE_FLASH_ATTR print_blob(const char *format, + const uint8_t *data, int size, ...) +{ +// int i; +// char tmp[80]; +// va_list(ap); + +// va_start(ap, size); +// sprintf(tmp, "%s\n", format); +// vprintf(tmp, ap); +// print_hex_init(size); +// for (i = 0; i < size; i++) +// { +// print_hex(data[i]); +// } + +// va_end(ap); +// TTY_FLUSH(); +} +#elif defined(WIN32) +/* VC6.0 doesn't handle variadic macros */ +EXP_FUNC void STDCALL print_blob(const char *format, const unsigned char *data, + int size, ...) {} +#endif + +#if defined(CONFIG_SSL_HAS_PEM) || defined(CONFIG_HTTP_HAS_AUTHORIZATION) +/* base64 to binary lookup table */ +static const uint8_t map[128] ICACHE_RODATA_ATTR STORE_ATTR = +{ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, + 255, 254, 255, 255, 255, 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, 255, 255, 255, 255, 255, + 255, 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, 255, 255, 255, 255, 255 +}; + +EXP_FUNC int STDCALL ICACHE_FLASH_ATTR base64_decode(const char *in, int len, + uint8_t *out, int *outlen) +{ + int g, t, x, y, z; + uint8_t c; + int ret = -1; + uint8* base64_map = (uint8*)SSL_ZALLOC(128); + memcpy(base64_map, map, 128); + + g = 3; + for (x = y = z = t = 0; x < len; x++) + { + if ((c = base64_map[in[x]&0x7F]) == 0xff) + continue; + + if (c == 254) /* this is the end... */ + { + c = 0; + + if (--g < 0) + goto error; + } + else if (g != 3) /* only allow = at end */ + goto error; + + t = (t<<6) | c; + + if (++y == 4) + { + out[z++] = (uint8_t)((t>>16)&255); + + if (g > 1) + out[z++] = (uint8_t)((t>>8)&255); + + if (g > 2) + out[z++] = (uint8_t)(t&255); + + y = t = 0; + } + + /* check that we don't go past the output buffer */ + if (z > *outlen) + goto error; + } + + if (y != 0) + goto error; + + *outlen = z; + ret = 0; + +error: +#ifdef CONFIG_SSL_FULL_MODE + if (ret < 0) + ssl_printf("Error: Invalid base64\n"); //TTY_FLUSH(); +#endif + //TTY_FLUSH(); + SSL_FREE(base64_map); + return ret; + +} +#endif + diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_hmac.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_hmac.c new file mode 100644 index 0000000..0c488f2 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_hmac.c @@ -0,0 +1,113 @@ +/* + * 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. + */ + +/** + * HMAC implementation - This code was originally taken from RFC2104 + * See http://www.ietf.org/rfc/rfc2104.txt and + * http://www.faqs.org/rfcs/rfc2202.html + */ + +#include "ssl/ssl_os_port.h" +#include "ssl/ssl_crypto.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +/** + * Perform HMAC-MD5 + * NOTE: does not handle keys larger than the block size. + */ +void ICACHE_FLASH_ATTR ssl_hmac_md5(const uint8_t *msg, int length, const uint8_t *key, + int key_len, uint8_t *digest) +{ + MD5_CTX context; + uint8_t *k_ipad = (uint8_t *)SSL_ZALLOC(64); + uint8_t *k_opad = (uint8_t *)SSL_ZALLOC(64); + int i; + +// memset(k_ipad, 0, sizeof k_ipad); +// memset(k_opad, 0, sizeof k_opad); + memcpy(k_ipad, key, key_len); + memcpy(k_opad, key, key_len); + + for (i = 0; i < 64; i++) + { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + MD5_Init(&context); + MD5_Update(&context, k_ipad, 64); + MD5_Update(&context, msg, length); + MD5_Final(digest, &context); + MD5_Init(&context); + MD5_Update(&context, k_opad, 64); + MD5_Update(&context, digest, MD5_SIZE); + MD5_Final(digest, &context); + SSL_FREE(k_ipad); + SSL_FREE(k_opad); +} + +/** + * Perform HMAC-SHA1 + * NOTE: does not handle keys larger than the block size. + */ +void ICACHE_FLASH_ATTR ssl_hmac_sha1(const uint8_t *msg, int length, const uint8_t *key, + int key_len, uint8_t *digest) +{ + SHA1_CTX context; + uint8_t *k_ipad = (uint8_t *)SSL_ZALLOC(64); + uint8_t *k_opad = (uint8_t *)SSL_ZALLOC(64); + int i; + +// memset(k_ipad, 0, sizeof k_ipad); +// memset(k_opad, 0, sizeof k_opad); + memcpy(k_ipad, key, key_len); + memcpy(k_opad, key, key_len); + + for (i = 0; i < 64; i++) + { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + SHA1_Init(&context); + SHA1_Update(&context, k_ipad, 64); + SHA1_Update(&context, msg, length); + SHA1_Final(digest, &context); + SHA1_Init(&context); + SHA1_Update(&context, k_opad, 64); + SHA1_Update(&context, digest, SHA1_SIZE); + SHA1_Final(digest, &context); + + SSL_FREE(k_ipad); + SSL_FREE(k_opad); +} diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_md5.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_md5.c new file mode 100644 index 0000000..8ffc2ad --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_md5.c @@ -0,0 +1,293 @@ +/* + * 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. + */ + +/** + * This file implements the MD5 algorithm as defined in RFC1321 + */ + +#include "ssl/ssl_os_port.h" +#include "ssl/ssl_crypto.h" + +/* Constants for MD5Transform routine. + */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +/* ----- static functions ----- */ +static void MD5Transform(uint32_t state[4], const uint8_t block[64]); +static void Encode(uint8_t *output, uint32_t *input, uint32_t len); +static void Decode(uint32_t *output, const uint8_t *input, uint32_t len); + +static const uint8_t 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 +}; + +/* F, G, H and I are basic MD5 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits. */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. + Rotation is separate from addition to prevent recomputation. */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +/** + * MD5 initialization - begins an MD5 operation, writing a new ctx. + */ +EXP_FUNC void STDCALL ICACHE_FLASH_ATTR MD5_Init(MD5_CTX *ctx) +{ + ctx->count[0] = ctx->count[1] = 0; + + /* Load magic initialization constants. + */ + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xefcdab89; + ctx->state[2] = 0x98badcfe; + ctx->state[3] = 0x10325476; +} + +/** + * Accepts an array of octets as the next portion of the message. + */ +EXP_FUNC void STDCALL ICACHE_FLASH_ATTR MD5_Update(MD5_CTX *ctx, const uint8_t * msg, int len) +{ + uint32_t x; + int i, partLen; + + /* Compute number of bytes mod 64 */ + x = (uint32_t)((ctx->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((ctx->count[0] += ((uint32_t)len << 3)) < ((uint32_t)len << 3)) + ctx->count[1]++; + ctx->count[1] += ((uint32_t)len >> 29); + + partLen = 64 - x; + + /* Transform as many times as possible. */ + if (len >= partLen) + { + memcpy(&ctx->buffer[x], msg, partLen); + MD5Transform(ctx->state, ctx->buffer); + + for (i = partLen; i + 63 < len; i += 64) + MD5Transform(ctx->state, &msg[i]); + + x = 0; + } + else + i = 0; + + /* Buffer remaining input */ + memcpy(&ctx->buffer[x], &msg[i], len-i); +} + +/** + * Return the 128-bit message digest into the user's array + */ +EXP_FUNC void STDCALL ICACHE_FLASH_ATTR MD5_Final(uint8_t *digest, MD5_CTX *ctx) +{ + uint8_t bits[8]; + uint32_t x, padLen; + + /* Save number of bits */ + Encode(bits, ctx->count, 8); + + /* Pad out to 56 mod 64. + */ + x = (uint32_t)((ctx->count[0] >> 3) & 0x3f); + padLen = (x < 56) ? (56 - x) : (120 - x); + MD5_Update(ctx, PADDING, padLen); + + /* Append length (before padding) */ + MD5_Update(ctx, bits, 8); + + /* Store state in digest */ + Encode(digest, ctx->state, MD5_SIZE); +} + +/** + * MD5 basic transformation. Transforms state based on block. + */ +static void ICACHE_FLASH_ATTR MD5Transform(uint32_t state[4], const uint8_t block[64]) +{ + uint32_t a = state[0], b = state[1], c = state[2], + d = state[3], x[MD5_SIZE]; + + Decode(x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; +} + +/** + * Encodes input (uint32_t) into output (uint8_t). Assumes len is + * a multiple of 4. + */ +static void ICACHE_FLASH_ATTR Encode(uint8_t *output, uint32_t *input, uint32_t len) +{ + uint32_t i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + { + output[j] = (uint8_t)(input[i] & 0xff); + output[j+1] = (uint8_t)((input[i] >> 8) & 0xff); + output[j+2] = (uint8_t)((input[i] >> 16) & 0xff); + output[j+3] = (uint8_t)((input[i] >> 24) & 0xff); + } +} + +/** + * Decodes input (uint8_t) into output (uint32_t). Assumes len is + * a multiple of 4. + */ +static void ICACHE_FLASH_ATTR Decode(uint32_t *output, const uint8_t *input, uint32_t len) +{ + uint32_t i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((uint32_t)input[j]) | (((uint32_t)input[j+1]) << 8) | + (((uint32_t)input[j+2]) << 16) | (((uint32_t)input[j+3]) << 24); +} diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_rc4.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_rc4.c new file mode 100644 index 0000000..5a6b92b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_rc4.c @@ -0,0 +1,91 @@ +/* + * 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. + */ + +/** + * An implementation of the RC4/ARC4 algorithm. + * Originally written by Christophe Devine. + */ + +#include "ssl/ssl_os_port.h" +#include "ssl/ssl_crypto.h" + +/** + * Get ready for an encrypt/decrypt operation + */ +void ICACHE_FLASH_ATTR RC4_setup(RC4_CTX *ctx, const uint8_t *key, int length) +{ + int i, j = 0, k = 0, a; + uint8_t *m; + + ctx->x = 0; + ctx->y = 0; + m = ctx->m; + + for (i = 0; i < 256; i++) + m[i] = i; + + for (i = 0; i < 256; i++) + { + a = m[i]; + j = (uint8_t)(j + a + key[k]); + m[i] = m[j]; + m[j] = a; + + if (++k >= length) + k = 0; + } +} + +/** + * Perform the encrypt/decrypt operation (can use it for either since + * this is a stream cipher). + * NOTE: *msg and *out must be the same pointer (performance tweak) + */ +void ICACHE_FLASH_ATTR RC4_crypt(RC4_CTX *ctx, const uint8_t *msg, uint8_t *out, int length) +{ + int i; + uint8_t *m, x, y, a, b; + + x = ctx->x; + y = ctx->y; + m = ctx->m; + + for (i = 0; i < length; i++) + { + a = m[++x]; + y += a; + m[x] = b = m[y]; + m[y] = a; + out[i] ^= m[(uint8_t)(a + b)]; + } + + ctx->x = x; + ctx->y = y; +} diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_rsa.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_rsa.c new file mode 100644 index 0000000..c1707d9 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_rsa.c @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2007-2014, 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. + */ + +/** + * Implements the RSA public encryption algorithm. Uses the bigint library to + * perform its calculations. + */ + +#include "ssl/ssl_os_port.h" +#include "ssl/ssl_crypto.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +void ICACHE_FLASH_ATTR RSA_priv_key_new(RSA_CTX **ctx, + const uint8_t *modulus, int mod_len, + const uint8_t *pub_exp, int pub_len, + const uint8_t *priv_exp, int priv_len +#if 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 + ) +{ + RSA_CTX *rsa_ctx; + BI_CTX *bi_ctx; + RSA_pub_key_new(ctx, modulus, mod_len, pub_exp, pub_len); + rsa_ctx = *ctx; + bi_ctx = rsa_ctx->bi_ctx; + rsa_ctx->d = bi_import(bi_ctx, priv_exp, priv_len); + bi_permanent(rsa_ctx->d); + +#ifdef CONFIG_BIGINT_CRT + rsa_ctx->p = bi_import(bi_ctx, p, p_len); + rsa_ctx->q = bi_import(bi_ctx, q, q_len); + rsa_ctx->dP = bi_import(bi_ctx, dP, dP_len); + rsa_ctx->dQ = bi_import(bi_ctx, dQ, dQ_len); + rsa_ctx->qInv = bi_import(bi_ctx, qInv, qInv_len); + bi_permanent(rsa_ctx->dP); + bi_permanent(rsa_ctx->dQ); + bi_permanent(rsa_ctx->qInv); + bi_set_mod(bi_ctx, rsa_ctx->p, BIGINT_P_OFFSET); + bi_set_mod(bi_ctx, rsa_ctx->q, BIGINT_Q_OFFSET); +#endif +} + +void ICACHE_FLASH_ATTR RSA_pub_key_new(RSA_CTX **ctx, + const uint8_t *modulus, int mod_len, + const uint8_t *pub_exp, int pub_len) +{ + RSA_CTX *rsa_ctx; + BI_CTX *bi_ctx; + + if (*ctx) /* if we load multiple certs, dump the old one */ + RSA_free(*ctx); + + bi_ctx = bi_initialize(); + *ctx = (RSA_CTX *)SSL_ZALLOC(sizeof(RSA_CTX)); + rsa_ctx = *ctx; + rsa_ctx->bi_ctx = bi_ctx; + rsa_ctx->num_octets = mod_len; + rsa_ctx->m = bi_import(bi_ctx, modulus, mod_len); + bi_set_mod(bi_ctx, rsa_ctx->m, BIGINT_M_OFFSET); + rsa_ctx->e = bi_import(bi_ctx, pub_exp, pub_len); + bi_permanent(rsa_ctx->e); +} + +/** + * Free up any RSA context resources. + */ +void ICACHE_FLASH_ATTR RSA_free(RSA_CTX *rsa_ctx) +{ + BI_CTX *bi_ctx; + if (rsa_ctx == NULL) /* deal with ptrs that are null */ + return; + + bi_ctx = rsa_ctx->bi_ctx; + + bi_depermanent(rsa_ctx->e); + bi_free(bi_ctx, rsa_ctx->e); + bi_free_mod(rsa_ctx->bi_ctx, BIGINT_M_OFFSET); + + if (rsa_ctx->d) + { + bi_depermanent(rsa_ctx->d); + bi_free(bi_ctx, rsa_ctx->d); +#ifdef CONFIG_BIGINT_CRT + bi_depermanent(rsa_ctx->dP); + bi_depermanent(rsa_ctx->dQ); + bi_depermanent(rsa_ctx->qInv); + bi_free(bi_ctx, rsa_ctx->dP); + bi_free(bi_ctx, rsa_ctx->dQ); + bi_free(bi_ctx, rsa_ctx->qInv); + bi_free_mod(rsa_ctx->bi_ctx, BIGINT_P_OFFSET); + bi_free_mod(rsa_ctx->bi_ctx, BIGINT_Q_OFFSET); +#endif + } + + bi_terminate(bi_ctx); + SSL_FREE(rsa_ctx); +} + +/** + * @brief Use PKCS1.5 for decryption/verification. + * @param ctx [in] The context + * @param in_data [in] The data to decrypt (must be < modulus size-11) + * @param out_data [out] The decrypted data. + * @param out_len [int] The size of the decrypted buffer in bytes + * @param is_decryption [in] Decryption or verify operation. + * @return The number of bytes that were originally encrypted. -1 on error. + * @see http://www.rsasecurity.com/rsalabs/node.asp?id=2125 + */ +int ICACHE_FLASH_ATTR RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, + uint8_t *out_data, int out_len, int is_decryption) +{ + const int byte_size = ctx->num_octets; + int i = 0, size; + bigint *decrypted_bi, *dat_bi; + uint8_t *block = (uint8_t *)SSL_MALLOC(byte_size); + int pad_count = 0; + + if (out_len < byte_size) /* check output has enough size */ + return -1; + memset(out_data, 0, out_len); /* initialise */ + + /* decrypt */ + dat_bi = bi_import(ctx->bi_ctx, in_data, byte_size); +#ifdef CONFIG_SSL_CERT_VERIFICATION + decrypted_bi = is_decryption ? /* decrypt or verify? */ + RSA_private(ctx, dat_bi) : RSA_public(ctx, dat_bi); +#else /* always a decryption */ + decrypted_bi = RSA_private(ctx, dat_bi); +#endif + + /* convert to a normal block */ + bi_export(ctx->bi_ctx, decrypted_bi, block, byte_size); + + if (block[i++] != 0) /* leading 0? */ + return -1; + +#ifdef CONFIG_SSL_CERT_VERIFICATION + if (is_decryption == 0) /* PKCS1.5 signing pads with "0xff"s */ + { + if (block[i++] != 0x01) /* BT correct? */ + return -1; + + while (block[i++] == 0xff && i < byte_size) + pad_count++; + } + else /* PKCS1.5 encryption padding is random */ +#endif + { + if (block[i++] != 0x02) /* BT correct? */ + return -1; + + while (block[i++] && i < byte_size) + pad_count++; + } + + /* check separator byte 0x00 - and padding must be 8 or more bytes */ + if (i == byte_size || pad_count < 8) + return -1; + + size = byte_size - i; + + /* get only the bit we want */ + if (size > 0) + memcpy(out_data, &block[i], size); + + SSL_FREE(block); + return size ? size : -1; +} + +/** + * Performs m = c^d mod n + */ +bigint *ICACHE_FLASH_ATTR RSA_private(const RSA_CTX *c, bigint *bi_msg) +{ +#ifdef CONFIG_BIGINT_CRT + return bi_crt(c->bi_ctx, bi_msg, c->dP, c->dQ, c->p, c->q, c->qInv); +#else + BI_CTX *ctx = c->bi_ctx; + ctx->mod_offset = BIGINT_M_OFFSET; + return bi_mod_power(ctx, bi_msg, c->d); +#endif +} + +#ifdef CONFIG_SSL_FULL_MODE +#if 0 +/** + * Used for diagnostics. + */ +void ICACHE_FLASH_ATTR RSA_print(const RSA_CTX *rsa_ctx) +{ + if (rsa_ctx == NULL) + return; + + ssl_printf("----------------- RSA DEBUG ----------------\n"); + ssl_printf("Size:\t%d\n", rsa_ctx->num_octets); + bi_print("Modulus", rsa_ctx->m); + bi_print("Public Key", rsa_ctx->e); + bi_print("Private Key", rsa_ctx->d); +} +#endif +#endif + +#if defined(CONFIG_SSL_CERT_VERIFICATION) || defined(CONFIG_SSL_GENERATE_X509_CERT) +/** + * Performs c = m^e mod n + */ +bigint *ICACHE_FLASH_ATTR RSA_public(const RSA_CTX * c, bigint *bi_msg) +{ + c->bi_ctx->mod_offset = BIGINT_M_OFFSET; + return bi_mod_power(c->bi_ctx, bi_msg, c->e); +} + +/** + * Use PKCS1.5 for encryption/signing. + * see http://www.rsasecurity.com/rsalabs/node.asp?id=2125 + */ +int ICACHE_FLASH_ATTR RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len, + uint8_t *out_data, int is_signing) +{ + int byte_size = ctx->num_octets; + int num_pads_needed = byte_size-in_len-3; + bigint *dat_bi, *encrypt_bi; + + /* note: in_len+11 must be > byte_size */ + out_data[0] = 0; /* ensure encryption block is < modulus */ + + if (is_signing) + { + out_data[1] = 1; /* PKCS1.5 signing pads with "0xff"'s */ + memset(&out_data[2], 0xff, num_pads_needed); + } + else /* randomize the encryption padding with non-zero bytes */ + { + out_data[1] = 2; + if (get_random_NZ(num_pads_needed, &out_data[2]) < 0) + return -1; + } + + out_data[2+num_pads_needed] = 0; + memcpy(&out_data[3+num_pads_needed], in_data, in_len); + + /* now encrypt it */ + dat_bi = bi_import(ctx->bi_ctx, out_data, byte_size); + encrypt_bi = is_signing ? RSA_private(ctx, dat_bi) : + RSA_public(ctx, dat_bi); + bi_export(ctx->bi_ctx, encrypt_bi, out_data, byte_size); + + /* save a few bytes of memory */ + bi_clear_cache(ctx->bi_ctx); + return byte_size; +} + +#endif /* CONFIG_SSL_CERT_VERIFICATION */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_sha1.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_sha1.c new file mode 100644 index 0000000..4a1e9a5 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/crypto/ssl_sha1.c @@ -0,0 +1,248 @@ +/* + * 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. + */ + +/** + * SHA1 implementation - as defined in FIPS PUB 180-1 published April 17, 1995. + * This code was originally taken from RFC3174 + */ + +#include "ssl/ssl_os_port.h" +#include "ssl/ssl_crypto.h" + +/* + * Define the SHA1 circular left shift macro + */ +#define SHA1CircularShift(bits,word) \ + (((word) << (bits)) | ((word) >> (32-(bits)))) + +/* ----- static functions ----- */ +static void SHA1PadMessage(SHA1_CTX *ctx); +static void SHA1ProcessMessageBlock(SHA1_CTX *ctx); + +/** + * Initialize the SHA1 context + */ +void ICACHE_FLASH_ATTR SHA1_Init(SHA1_CTX *ctx) +{ + ctx->Length_Low = 0; + ctx->Length_High = 0; + ctx->Message_Block_Index = 0; + ctx->Intermediate_Hash[0] = 0x67452301; + ctx->Intermediate_Hash[1] = 0xEFCDAB89; + ctx->Intermediate_Hash[2] = 0x98BADCFE; + ctx->Intermediate_Hash[3] = 0x10325476; + ctx->Intermediate_Hash[4] = 0xC3D2E1F0; +} + +/** + * Accepts an array of octets as the next portion of the message. + */ +void ICACHE_FLASH_ATTR SHA1_Update(SHA1_CTX *ctx, const uint8_t *msg, int len) +{ + while (len--) + { + ctx->Message_Block[ctx->Message_Block_Index++] = (*msg & 0xFF); + ctx->Length_Low += 8; + + if (ctx->Length_Low == 0) + ctx->Length_High++; + + if (ctx->Message_Block_Index == 64) + SHA1ProcessMessageBlock(ctx); + + msg++; + } +} + +/** + * Return the 160-bit message digest into the user's array + */ +void ICACHE_FLASH_ATTR SHA1_Final(uint8_t *digest, SHA1_CTX *ctx) +{ + int i; + + SHA1PadMessage(ctx); + memset(ctx->Message_Block, 0, 64); + ctx->Length_Low = 0; /* and clear length */ + ctx->Length_High = 0; + + for (i = 0; i < SHA1_SIZE; i++) + { + digest[i] = ctx->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) ); + } +} + +/** + * Process the next 512 bits of the message stored in the array. + */ +static void ICACHE_FLASH_ATTR SHA1ProcessMessageBlock(SHA1_CTX *ctx) +{ + const uint32_t K[] = { /* Constants defined in SHA-1 */ + 0x5A827999, + 0x6ED9EBA1, + 0x8F1BBCDC, + 0xCA62C1D6 + }; + int t; /* Loop counter */ + uint32_t temp; /* Temporary word value */ + uint32_t W[80]; /* Word sequence */ + uint32_t A, B, C, D, E; /* Word buffers */ + + /* + * Initialize the first 16 words in the array W + */ + for (t = 0; t < 16; t++) + { + W[t] = ctx->Message_Block[t * 4] << 24; + W[t] |= ctx->Message_Block[t * 4 + 1] << 16; + W[t] |= ctx->Message_Block[t * 4 + 2] << 8; + W[t] |= ctx->Message_Block[t * 4 + 3]; + } + + for (t = 16; t < 80; t++) + { + W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); + } + + A = ctx->Intermediate_Hash[0]; + B = ctx->Intermediate_Hash[1]; + C = ctx->Intermediate_Hash[2]; + D = ctx->Intermediate_Hash[3]; + E = ctx->Intermediate_Hash[4]; + + for (t = 0; t < 20; t++) + { + temp = SHA1CircularShift(5,A) + + ((B & C) | ((~B) & D)) + E + W[t] + K[0]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + + B = A; + A = temp; + } + + for (t = 20; t < 40; t++) + { + temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for (t = 40; t < 60; t++) + { + temp = SHA1CircularShift(5,A) + + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for (t = 60; t < 80; t++) + { + temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + ctx->Intermediate_Hash[0] += A; + ctx->Intermediate_Hash[1] += B; + ctx->Intermediate_Hash[2] += C; + ctx->Intermediate_Hash[3] += D; + ctx->Intermediate_Hash[4] += E; + ctx->Message_Block_Index = 0; +} + +/* + * According to the standard, the message must be padded to an even + * 512 bits. The first padding bit must be a '1'. The last 64 + * bits represent the length of the original message. All bits in + * between should be 0. This function will pad the message + * according to those rules by filling the Message_Block array + * accordingly. It will also call the ProcessMessageBlock function + * provided appropriately. When it returns, it can be assumed that + * the message digest has been computed. + * + * @param ctx [in, out] The SHA1 context + */ +static void ICACHE_FLASH_ATTR SHA1PadMessage(SHA1_CTX *ctx) +{ + /* + * Check to see if the current message block is too small to hold + * the initial padding bits and length. If so, we will pad the + * block, process it, and then continue padding into a second + * block. + */ + if (ctx->Message_Block_Index > 55) + { + ctx->Message_Block[ctx->Message_Block_Index++] = 0x80; + while(ctx->Message_Block_Index < 64) + { + ctx->Message_Block[ctx->Message_Block_Index++] = 0; + } + + SHA1ProcessMessageBlock(ctx); + + while (ctx->Message_Block_Index < 56) + { + ctx->Message_Block[ctx->Message_Block_Index++] = 0; + } + } + else + { + ctx->Message_Block[ctx->Message_Block_Index++] = 0x80; + while(ctx->Message_Block_Index < 56) + { + + ctx->Message_Block[ctx->Message_Block_Index++] = 0; + } + } + + /* + * Store the message length as the last 8 octets + */ + ctx->Message_Block[56] = ctx->Length_High >> 24; + ctx->Message_Block[57] = ctx->Length_High >> 16; + ctx->Message_Block[58] = ctx->Length_High >> 8; + ctx->Message_Block[59] = ctx->Length_High; + ctx->Message_Block[60] = ctx->Length_Low >> 24; + ctx->Message_Block[61] = ctx->Length_Low >> 16; + ctx->Message_Block[62] = ctx->Length_Low >> 8; + ctx->Message_Block[63] = ctx->Length_Low; + SHA1ProcessMessageBlock(ctx); +} diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/Makefile b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/Makefile new file mode 100644 index 0000000..7ab2721 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/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 = libsslssl.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/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_asn1.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_asn1.c new file mode 100644 index 0000000..e520d69 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_asn1.c @@ -0,0 +1,697 @@ +/* + * 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. + */ + +/** + * Some primitive asn methods for extraction ASN.1 data. + */ + +#include "ssl/ssl_os_port.h" +#include "ssl/ssl_ssl.h" +#include "ssl/ssl_crypto.h" +#include "ssl/ssl_crypto_misc.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +struct tm +{ + int tm_sec; /* Seconds. [0-60] (1 leap second) */ + int tm_min; /* Minutes. [0-59] */ + int tm_hour; /* Hours. [0-23] */ + int tm_mday; /* Day. [1-31] */ + int tm_mon; /* Month. [0-11] */ + int tm_year; /* Year - 1900. */ + int tm_wday; /* Day of week. [0-6] */ + int tm_yday; /* Days in year.[0-365] */ + int tm_isdst; /* DST. [-1/0/1]*/ + +#ifdef __USE_BSD + long int tm_gmtoff; /* Seconds east of UTC. */ + __const char *tm_zone; /* Timezone abbreviation. */ +#else + long int __tm_gmtoff; /* Seconds east of UTC. */ + __const char *__tm_zone; /* Timezone abbreviation. */ +#endif +}; + + + /*1.2.840.113549.1.1 OID prefix - handle the following */ +/* md5WithRSAEncryption(4) */ +/* sha1WithRSAEncryption(5) */ +/* sha256WithRSAEncryption (11) */ +/* sha384WithRSAEncryption (12) */ +/* sha512WithRSAEncryption (13) */ +static const uint8_t sig_oid_prefix[] = +{ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01 +}; + +/* 1.3.14.3.2.29 SHA1 with RSA signature */ +static const uint8_t sig_sha1WithRSAEncrypt[] = +{ + 0x2b, 0x0e, 0x03, 0x02, 0x1d +}; + +/* 2.16.840.1.101.3.4.2.1 SHA-256 */ +static const uint8_t sig_sha256[] = +{ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 +}; + + +/* 2.16.840.1.101.3.4.2.2 SHA-384 */ +static const uint8_t sig_sha384[] = +{ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02 +}; + +/* 2.16.840.1.101.3.4.2.3 SHA-512 */ +static const uint8_t sig_sha512[] = +{ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03 +}; + +static const uint8_t sig_subject_alt_name[] = +{ + 0x55, 0x1d, 0x11 +}; + +/* CN, O, OU */ +static const uint8_t g_dn_types[] = { 3, 10, 11 }; + +uint32_t ICACHE_FLASH_ATTR get_asn1_length(const uint8_t *buf, int *offset) +{ + int i; + uint32_t len; + + if (!(buf[*offset] & 0x80)) /* short form */ + { + len = buf[(*offset)++]; + } + else /* long form */ + { + int length_bytes = buf[(*offset)++]&0x7f; + if (length_bytes > 4) /* limit number of bytes */ + return 0; + + len = 0; + for (i = 0; i < length_bytes; i++) + { + len <<= 8; + len += buf[(*offset)++]; + } + } + + return len; +} + +/** + * Skip the ASN1.1 object type and its length. Get ready to read the object's + * data. + */ +int ICACHE_FLASH_ATTR asn1_next_obj(const uint8_t *buf, int *offset, int obj_type) +{ + if (buf[*offset] != obj_type) + return X509_NOT_OK; + (*offset)++; + return get_asn1_length(buf, offset); +} + +/** + * Skip over an ASN.1 object type completely. Get ready to read the next + * object. + */ +int ICACHE_FLASH_ATTR asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type) +{ + int len; + + if (buf[*offset] != obj_type) + return X509_NOT_OK; + (*offset)++; + len = get_asn1_length(buf, offset); + *offset += len; + return 0; +} + +/** + * Read an integer value for ASN.1 data + * Note: This function allocates memory which must be freed by the user. + */ +int ICACHE_FLASH_ATTR asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object) +{ + int len; + + if ((len = asn1_next_obj(buf, offset, ASN1_INTEGER)) < 0) + goto end_int_array; + + if (len > 1 && buf[*offset] == 0x00) /* ignore the negative byte */ + { + len--; + (*offset)++; + } + + *object = (uint8_t *)SSL_MALLOC(len); + memcpy(*object, &buf[*offset], len); + *offset += len; + +end_int_array: + return len; +} + +/** + * Get all the RSA private key specifics from an ASN.1 encoded file + */ +int ICACHE_FLASH_ATTR asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx) +{ + int offset = 7; + uint8_t *modulus = NULL, *priv_exp = NULL, *pub_exp = NULL; + int mod_len, priv_len, pub_len; +#ifdef CONFIG_BIGINT_CRT + uint8_t *p = NULL, *q = NULL, *dP = NULL, *dQ = NULL, *qInv = NULL; + int p_len, q_len, dP_len, dQ_len, qInv_len; +#endif + + /* not in der format */ + if (buf[0] != ASN1_SEQUENCE) /* basic sanity check */ + { +#ifdef CONFIG_SSL_FULL_MODE + ssl_printf("Error: This is not a valid ASN.1 file\n"); +#endif + return X509_INVALID_PRIV_KEY; + } + + /* Use the private key to mix up the RNG if possible. */ + RNG_custom_init(buf, len); + + mod_len = asn1_get_int(buf, &offset, &modulus); + pub_len = asn1_get_int(buf, &offset, &pub_exp); + priv_len = asn1_get_int(buf, &offset, &priv_exp); + + if (mod_len <= 0 || pub_len <= 0 || priv_len <= 0) + return X509_INVALID_PRIV_KEY; + +#ifdef CONFIG_BIGINT_CRT + p_len = asn1_get_int(buf, &offset, &p); + q_len = asn1_get_int(buf, &offset, &q); + dP_len = asn1_get_int(buf, &offset, &dP); + dQ_len = asn1_get_int(buf, &offset, &dQ); + qInv_len = asn1_get_int(buf, &offset, &qInv); + + if (p_len <= 0 || q_len <= 0 || dP_len <= 0 || dQ_len <= 0 || qInv_len <= 0) + return X509_INVALID_PRIV_KEY; + + RSA_priv_key_new(rsa_ctx, + modulus, mod_len, pub_exp, pub_len, priv_exp, priv_len, + p, p_len, q, p_len, dP, dP_len, dQ, dQ_len, qInv, qInv_len); + + SSL_FREE(p); + SSL_FREE(q); + SSL_FREE(dP); + SSL_FREE(dQ); + SSL_FREE(qInv); +#else + RSA_priv_key_new(rsa_ctx, + modulus, mod_len, pub_exp, pub_len, priv_exp, priv_len); +#endif + + SSL_FREE(modulus); + SSL_FREE(priv_exp); + SSL_FREE(pub_exp); + return X509_OK; +} + +static time_t ICACHE_FLASH_ATTR mktime(struct tm *ptm) +{ + uint16 year = 0,mon = 0,day = 0,hour = 0,min = 0,sec = 0; + if (ptm == NULL) + return 0; + + year = ptm->tm_year; + mon = ptm->tm_mon; + day = ptm->tm_mday; + hour = ptm->tm_hour; + min = ptm->tm_min; + sec = ptm->tm_sec; + + if (0 >= (int)(mon -= 2)){/*1..12 ->11,12,1..10*/ + mon += 12; /*Puts Feb last since it has leap day*/ + year -= 1; + } + + return ((( + (unsigned long)(year/4 - year/100 + year/400 +367*mon/12 +day) + + year*365 -719499 + )*24 + hour/*now have hours*/ + )*60 + min/*now have minutes*/ + )*60 + sec;/*finally seconds*/ +} + +/** + * Get the time of a certificate. Ignore hours/minutes/seconds. + */ +static int ICACHE_FLASH_ATTR asn1_get_utc_time(const uint8_t *buf, int *offset, time_t *t) +{ + int ret = X509_NOT_OK, len, t_offset, abs_year; + struct tm tm; + + /* see http://tools.ietf.org/html/rfc5280#section-4.1.2.5 */ + if (buf[*offset] == ASN1_UTC_TIME) + { + (*offset)++; + + len = get_asn1_length(buf, offset); + t_offset = *offset; + + memset(&tm, 0, sizeof(struct tm)); + tm.tm_year = (buf[t_offset] - '0')*10 + (buf[t_offset+1] - '0'); + + if (tm.tm_year <= 50) /* 1951-2050 thing */ + { + tm.tm_year += 100; + } + + tm.tm_mon = (buf[t_offset+2] - '0')*10 + (buf[t_offset+3] - '0') - 1; + tm.tm_mday = (buf[t_offset+4] - '0')*10 + (buf[t_offset+5] - '0'); + // LiuH : add mktime interface in function at 2015.06.11 + *t = mktime(&tm); + *offset += len; + ret = X509_OK; + } + else if (buf[*offset] == ASN1_GENERALIZED_TIME) + { + (*offset)++; + + len = get_asn1_length(buf, offset); + t_offset = *offset; + + memset(&tm, 0, sizeof(struct tm)); + abs_year = ((buf[t_offset] - '0')*1000 + + (buf[t_offset+1] - '0')*100 + (buf[t_offset+2] - '0')*10 + + (buf[t_offset+3] - '0')); + + if (abs_year <= 1901) + { + tm.tm_year = 1; + tm.tm_mon = 0; + tm.tm_mday = 1; + } + else + { + tm.tm_year = abs_year - 1900; + tm.tm_mon = (buf[t_offset+4] - '0')*10 + (buf[t_offset+5] - '0') - 1; + tm.tm_mday = (buf[t_offset+6] - '0')*10 + (buf[t_offset+7] - '0'); + tm.tm_hour = (buf[t_offset+8] - '0')*10 + (buf[t_offset+9] - '0'); + tm.tm_min = (buf[t_offset+10] - '0')*10 + (buf[t_offset+11] - '0'); + tm.tm_sec = (buf[t_offset+12] - '0')*10 + (buf[t_offset+13] - '0'); + *t = mktime(&tm); + } + + *offset += len; + ret = X509_OK; + } + + return ret; +} + +/** + * Get the version type of a certificate (which we don't actually care about) + */ +int ICACHE_FLASH_ATTR asn1_version(const uint8_t *cert, int *offset, X509_CTX *x509_ctx) +{ + int ret = X509_NOT_OK; + + (*offset) += 2; /* get past explicit tag */ + if (asn1_skip_obj(cert, offset, ASN1_INTEGER)) + goto end_version; + + ret = X509_OK; +end_version: + return ret; +} + +/** + * Retrieve the notbefore and notafter certificate times. + */ +int ICACHE_FLASH_ATTR asn1_validity(const uint8_t *cert, int *offset, X509_CTX *x509_ctx) +{ + return (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 || + asn1_get_utc_time(cert, offset, &x509_ctx->not_before) || + asn1_get_utc_time(cert, offset, &x509_ctx->not_after)); +} + +/** + * Get the components of a distinguished name + */ +static int ICACHE_FLASH_ATTR asn1_get_oid_x520(const uint8_t *buf, int *offset) +{ + int dn_type = 0; + int len; + + if ((len = asn1_next_obj(buf, offset, ASN1_OID)) < 0) + goto end_oid; + + /* expect a sequence of 2.5.4.[x] where x is a one of distinguished name + components we are interested in. */ + if (len == 3 && buf[(*offset)++] == 0x55 && buf[(*offset)++] == 0x04) + dn_type = buf[(*offset)++]; + else + { + *offset += len; /* skip over it */ + } + +end_oid: + return dn_type; +} + +/** + * Obtain an ASN.1 printable string type. + */ +static int ICACHE_FLASH_ATTR asn1_get_printable_str(const uint8_t *buf, int *offset, char **str) +{ + int len = X509_NOT_OK; + int asn1_type = buf[*offset]; + + /* some certs have this awful crud in them for some reason */ + if (asn1_type != ASN1_PRINTABLE_STR && + asn1_type != ASN1_PRINTABLE_STR2 && + asn1_type != ASN1_TELETEX_STR && + asn1_type != ASN1_IA5_STR && + asn1_type != ASN1_UNICODE_STR) + goto end_pnt_str; + + (*offset)++; + len = get_asn1_length(buf, offset); + + if (asn1_type == ASN1_UNICODE_STR) + { + int i; + *str = (char *)SSL_MALLOC(len/2+1); /* allow for null */ + + for (i = 0; i < len; i += 2) + (*str)[i/2] = buf[*offset + i + 1]; + + (*str)[len/2] = 0; /* null terminate */ + } + else + { + *str = (char *)SSL_MALLOC(len+1); /* allow for null */ + memcpy(*str, &buf[*offset], len); + (*str)[len] = 0; /* null terminate */ + } + + *offset += len; + +end_pnt_str: + return len; +} + +/** + * Get the subject name (or the issuer) of a certificate. + */ +int ICACHE_FLASH_ATTR asn1_name(const uint8_t *cert, int *offset, char *dn[]) +{ + int ret = X509_NOT_OK; + int dn_type; + char *tmp; + + if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0) + goto end_name; + + while (asn1_next_obj(cert, offset, ASN1_SET) >= 0) + { + int i, found = 0; + + if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 || + (dn_type = asn1_get_oid_x520(cert, offset)) < 0) + goto end_name; + + tmp = NULL; + + if (asn1_get_printable_str(cert, offset, &tmp) < 0) + { + SSL_FREE(tmp); + goto end_name; + } + + /* find the distinguished named type */ + for (i = 0; i < X509_NUM_DN_TYPES; i++) + { + if (dn_type == g_dn_types[i]) + { + if (dn[i] == NULL) + { + dn[i] = tmp; + found = 1; + break; + } + } + } + + if (found == 0) /* not found so get rid of it */ + { + SSL_FREE(tmp); + } + } + + ret = X509_OK; +end_name: + return ret; +} + +/** + * Read the modulus and public exponent of a certificate. + */ +int ICACHE_FLASH_ATTR asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx) +{ + int ret = X509_NOT_OK, mod_len, pub_len; + uint8_t *modulus = NULL, *pub_exp = NULL; + + if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 || + asn1_skip_obj(cert, offset, ASN1_SEQUENCE) || + asn1_next_obj(cert, offset, ASN1_BIT_STRING) < 0) + goto end_pub_key; + + (*offset)++; /* ignore the padding bit field */ + + if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0) + goto end_pub_key; + + mod_len = asn1_get_int(cert, offset, &modulus); + pub_len = asn1_get_int(cert, offset, &pub_exp); + + RSA_pub_key_new(&x509_ctx->rsa_ctx, modulus, mod_len, pub_exp, pub_len); + + SSL_FREE(modulus); + SSL_FREE(pub_exp); + ret = X509_OK; + +end_pub_key: + return ret; +} + +#ifdef CONFIG_SSL_CERT_VERIFICATION +/** + * Read the signature of the certificate. + */ +int ICACHE_FLASH_ATTR asn1_signature(const uint8_t *cert, int *offset, X509_CTX *x509_ctx) +{ + int ret = X509_NOT_OK; + + if (cert[(*offset)++] != ASN1_BIT_STRING) + goto end_sig; + + x509_ctx->sig_len = get_asn1_length(cert, offset)-1; + (*offset)++; /* ignore bit string padding bits */ + x509_ctx->signature = (uint8_t *)SSL_MALLOC(x509_ctx->sig_len); + memcpy(x509_ctx->signature, &cert[*offset], x509_ctx->sig_len); + *offset += x509_ctx->sig_len; + ret = X509_OK; + +end_sig: + return ret; +} + +/* + * Compare 2 distinguished name components for equality + * @return 0 if a match + */ +static int ICACHE_FLASH_ATTR asn1_compare_dn_comp(const char *dn1, const char *dn2) +{ + int ret; + + if (dn1 == NULL && dn2 == NULL) + ret = 0; + else + ret = (dn1 && dn2) ? strcmp(dn1, dn2) : 1; + + return ret; +} + +/** + * Clean up all of the CA certificates. + */ +void ICACHE_FLASH_ATTR remove_ca_certs(CA_CERT_CTX *ca_cert_ctx) +{ + int i = 0; + + if (ca_cert_ctx == NULL) + return; + + while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i]) + { + x509_free(ca_cert_ctx->cert[i]); + ca_cert_ctx->cert[i++] = NULL; + } + + SSL_FREE(ca_cert_ctx); +} + +/* + * Compare 2 distinguished names for equality + * @return 0 if a match + */ +int ICACHE_FLASH_ATTR asn1_compare_dn(char * const dn1[], char * const dn2[]) +{ + int i; + + for (i = 0; i < X509_NUM_DN_TYPES; i++) + { +#if CONFIG_SSL_DISPLAY_MODE + os_printf("distinguished names: [%s], [%s]\n", dn1[i], dn2[i]); +#endif + if (asn1_compare_dn_comp(dn1[i], dn2[i])) + return 1; + } + + return 0; /* all good */ +} + +int ICACHE_FLASH_ATTR asn1_find_oid(const uint8_t* cert, int* offset, + const uint8_t* oid, int oid_length) +{ + int seqlen; + if ((seqlen = asn1_next_obj(cert, offset, ASN1_SEQUENCE))> 0) + { + int end = *offset + seqlen; + + while (*offset < end) + { + int type = cert[(*offset)++]; + int length = get_asn1_length(cert, offset); + int noffset = *offset + length; + + if (type == ASN1_SEQUENCE) + { + type = cert[(*offset)++]; + length = get_asn1_length(cert, offset); + + if (type == ASN1_OID && length == oid_length && + memcmp(cert + *offset, oid, oid_length) == 0) + { + *offset += oid_length; + return 1; + } + } + + *offset = noffset; + } + } + + return 0; +} + +int ICACHE_FLASH_ATTR asn1_find_subjectaltname(const uint8_t* cert, int offset) +{ + if (asn1_find_oid(cert, &offset, sig_subject_alt_name, + sizeof(sig_subject_alt_name))) + { + return offset; + } + + return 0; +} + +#endif /* CONFIG_SSL_CERT_VERIFICATION */ + +/** + * Read the signature type of the certificate. We only support RSA-MD5 and + * RSA-SHA1 signature types. + */ +int ICACHE_FLASH_ATTR asn1_signature_type(const uint8_t *cert, + int *offset, X509_CTX *x509_ctx) +{ + int ret = X509_NOT_OK, len; + + if (cert[(*offset)++] != ASN1_OID) + goto end_check_sig; + + len = get_asn1_length(cert, offset); + + if (len == sizeof(sig_sha1WithRSAEncrypt) && + memcmp(sig_sha1WithRSAEncrypt, &cert[*offset], + sizeof(sig_sha1WithRSAEncrypt)) == 0) + { + x509_ctx->sig_type = SIG_TYPE_SHA1; + } + else if (len == sizeof(sig_sha256) && + memcmp(sig_sha256, &cert[*offset], + sizeof(sig_sha256)) == 0) + { + x509_ctx->sig_type = SIG_TYPE_SHA256; + } + else if (len == sizeof(sig_sha384) && + memcmp(sig_sha384, &cert[*offset], + sizeof(sig_sha384)) == 0) + { + x509_ctx->sig_type = SIG_TYPE_SHA384; + } + else if (len == sizeof(sig_sha512) && + memcmp(sig_sha512, &cert[*offset], + sizeof(sig_sha512)) == 0) + { + x509_ctx->sig_type = SIG_TYPE_SHA512; + } + else + { + if (memcmp(sig_oid_prefix, &cert[*offset], sizeof(sig_oid_prefix))) + goto end_check_sig; /* unrecognised cert type */ + + x509_ctx->sig_type = cert[*offset + sizeof(sig_oid_prefix)]; + } + + *offset += len; + asn1_skip_obj(cert, offset, ASN1_NULL); /* if it's there */ + ret = X509_OK; + +end_check_sig: + return ret; +} + diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_gen_cert.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_gen_cert.c new file mode 100644 index 0000000..43e2dcd --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_gen_cert.c @@ -0,0 +1,374 @@ +/* + * Copyright (c) 2007-2014, 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. + */ + +#include "ssl/ssl_config.h" + +#ifdef CONFIG_SSL_GENERATE_X509_CERT +#include +#include +#include "ssl/ssl_os_port.h" +#include "ssl/ssl_ssl.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +/** + * Generate a basic X.509 certificate + */ + +static uint8_t ICACHE_FLASH_ATTR set_gen_length(int len, uint8_t *buf, int *offset) +{ + if (len < 0x80) /* short form */ + { + buf[(*offset)++] = len; + return 1; + } + else /* long form */ + { + int i, length_bytes = 0; + + if (len & 0x00FF0000) + length_bytes = 3; + else if (len & 0x0000FF00) + length_bytes = 2; + else if (len & 0x000000FF) + length_bytes = 1; + + buf[(*offset)++] = 0x80 + length_bytes; + + for (i = length_bytes-1; i >= 0; i--) + { + buf[*offset+i] = len & 0xFF; + len >>= 8; + } + + *offset += length_bytes; + return length_bytes+1; + } +} + +static int ICACHE_FLASH_ATTR pre_adjust_with_size(uint8_t type, + int *seq_offset, uint8_t *buf, int *offset) +{ + buf[(*offset)++] = type; + *seq_offset = *offset; + *offset += 4; /* fill in later */ + return *offset; +} + +static void ICACHE_FLASH_ATTR adjust_with_size(int seq_size, int seq_start, + uint8_t *buf, int *offset) +{ + uint8_t seq_byte_size; + int orig_seq_size = seq_size; + int orig_seq_start = seq_start; + + seq_size = *offset-seq_size; + seq_byte_size = set_gen_length(seq_size, buf, &seq_start); + + if (seq_byte_size != 4) + { + memmove(&buf[orig_seq_start+seq_byte_size], + &buf[orig_seq_size], seq_size); + *offset -= 4-seq_byte_size; + } +} + +static void ICACHE_FLASH_ATTR gen_serial_number(uint8_t *buf, int *offset) +{ + static const uint8_t ser_oid[] = { ASN1_INTEGER, 1, 0x7F }; + memcpy(&buf[*offset], ser_oid , sizeof(ser_oid)); + *offset += sizeof(ser_oid); +} + +static void ICACHE_FLASH_ATTR gen_signature_alg(uint8_t *buf, int *offset) +{ + /* OBJECT IDENTIFIER sha1withRSAEncryption (1 2 840 113549 1 1 5) */ + static const uint8_t sig_oid[] = + { + ASN1_SEQUENCE, 0x0d, ASN1_OID, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, + ASN1_NULL, 0x00 + }; + + memcpy(&buf[*offset], sig_oid, sizeof(sig_oid)); + *offset += sizeof(sig_oid); +} + +static int ICACHE_FLASH_ATTR gen_dn(const char *name, uint8_t dn_type, + uint8_t *buf, int *offset) +{ + int ret = X509_OK; + int name_size = strlen(name); + + if (name_size > 0x70) /* just too big */ + { + ret = X509_NOT_OK; + goto error; + } + + buf[(*offset)++] = ASN1_SET; + set_gen_length(9+name_size, buf, offset); + buf[(*offset)++] = ASN1_SEQUENCE; + set_gen_length(7+name_size, buf, offset); + buf[(*offset)++] = ASN1_OID; + buf[(*offset)++] = 3; + buf[(*offset)++] = 0x55; + buf[(*offset)++] = 0x04; + buf[(*offset)++] = dn_type; + buf[(*offset)++] = ASN1_PRINTABLE_STR; + buf[(*offset)++] = name_size; + strcpy(&buf[*offset], name); + *offset += name_size; + +error: + return ret; +} + +static int ICACHE_FLASH_ATTR gen_issuer(const char * dn[], uint8_t *buf, int *offset) +{ + int ret = X509_OK; + int seq_offset; + int seq_size = pre_adjust_with_size( + ASN1_SEQUENCE, &seq_offset, buf, offset); + char fqdn[128]; + + /* we need the common name, so if not configured, work out the fully + * qualified domain name */ + if (dn[X509_COMMON_NAME] == NULL || strlen(dn[X509_COMMON_NAME]) == 0) + { + int fqdn_len; + gethostname(fqdn, sizeof(fqdn)); + fqdn_len = strlen(fqdn); + fqdn[fqdn_len++] = '.'; + + if (getdomainname(&fqdn[fqdn_len], sizeof(fqdn)-fqdn_len) < 0) + { + ret = X509_NOT_OK; + goto error; + } + + fqdn_len = strlen(fqdn); + + if (fqdn[fqdn_len-1] == '.') /* ensure '.' is not last char */ + fqdn[fqdn_len-1] = 0; + + dn[X509_COMMON_NAME] = fqdn; + } + + if ((ret = gen_dn(dn[X509_COMMON_NAME], 3, buf, offset))) + goto error; + + if (dn[X509_ORGANIZATION] != NULL && strlen(dn[X509_ORGANIZATION]) > 0) + { + if ((ret = gen_dn(dn[X509_ORGANIZATION], 10, buf, offset))) + goto error; + } + + if (dn[X509_ORGANIZATIONAL_UNIT] != NULL && + strlen(dn[X509_ORGANIZATIONAL_UNIT]) > 0) + { + if ((ret = gen_dn(dn[X509_ORGANIZATIONAL_UNIT], 11, buf, offset))) + goto error; + } + + adjust_with_size(seq_size, seq_offset, buf, offset); + +error: + return ret; +} + +static void ICACHE_FLASH_ATTR gen_utc_time(uint8_t *buf, int *offset) +{ + static const uint8_t time_seq[] = + { + ASN1_SEQUENCE, 30, + ASN1_UTC_TIME, 13, + '0', '7', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', 'Z', + ASN1_UTC_TIME, 13, /* make it good for 30 or so years */ + '3', '8', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', 'Z' + }; + + /* fixed time */ + memcpy(&buf[*offset], time_seq, sizeof(time_seq)); + *offset += sizeof(time_seq); +} + +static void ICACHE_FLASH_ATTR gen_pub_key2(const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset) +{ + static const uint8_t pub_key_seq[] = + { + ASN1_INTEGER, 0x03, 0x01, 0x00, 0x01 /* INTEGER 65537 */ + }; + + int seq_offset; + int pub_key_size = rsa_ctx->num_octets; + uint8_t *block = (uint8_t *)alloca(pub_key_size); + int seq_size = pre_adjust_with_size( + ASN1_SEQUENCE, &seq_offset, buf, offset); + buf[(*offset)++] = ASN1_INTEGER; + bi_export(rsa_ctx->bi_ctx, rsa_ctx->m, block, pub_key_size); + + if (*block & 0x80) /* make integer positive */ + { + set_gen_length(pub_key_size+1, buf, offset); + buf[(*offset)++] = 0; + } + else + set_gen_length(pub_key_size, buf, offset); + + memcpy(&buf[*offset], block, pub_key_size); + *offset += pub_key_size; + memcpy(&buf[*offset], pub_key_seq, sizeof(pub_key_seq)); + *offset += sizeof(pub_key_seq); + adjust_with_size(seq_size, seq_offset, buf, offset); +} + +static void ICACHE_FLASH_ATTR gen_pub_key1(const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset) +{ + int seq_offset; + int seq_size = pre_adjust_with_size( + ASN1_BIT_STRING, &seq_offset, buf, offset); + buf[(*offset)++] = 0; /* bit string is multiple of 8 */ + gen_pub_key2(rsa_ctx, buf, offset); + adjust_with_size(seq_size, seq_offset, buf, offset); +} + +static void ICACHE_FLASH_ATTR gen_pub_key(const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset) +{ + /* OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1) */ + static const uint8_t rsa_enc_oid[] = + { + ASN1_SEQUENCE, 0x0d, ASN1_OID, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + ASN1_NULL, 0x00 + }; + + int seq_offset; + int seq_size = pre_adjust_with_size( + ASN1_SEQUENCE, &seq_offset, buf, offset); + + memcpy(&buf[*offset], rsa_enc_oid, sizeof(rsa_enc_oid)); + *offset += sizeof(rsa_enc_oid); + gen_pub_key1(rsa_ctx, buf, offset); + adjust_with_size(seq_size, seq_offset, buf, offset); +} + +static void ICACHE_FLASH_ATTR gen_signature(const RSA_CTX *rsa_ctx, const uint8_t *sha_dgst, + uint8_t *buf, int *offset) +{ + static const uint8_t asn1_sig[] = + { + ASN1_SEQUENCE, 0x21, ASN1_SEQUENCE, 0x09, ASN1_OID, 0x05, + 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* sha1 (1 3 14 3 2 26) */ + ASN1_NULL, 0x00, ASN1_OCTET_STRING, 0x14 + }; + + uint8_t *enc_block = (uint8_t *)alloca(rsa_ctx->num_octets); + uint8_t *block = (uint8_t *)alloca(sizeof(asn1_sig) + SHA1_SIZE); + int sig_size; + + /* add the digest as an embedded asn.1 sequence */ + memcpy(block, asn1_sig, sizeof(asn1_sig)); + memcpy(&block[sizeof(asn1_sig)], sha_dgst, SHA1_SIZE); + + sig_size = RSA_encrypt(rsa_ctx, block, + sizeof(asn1_sig) + SHA1_SIZE, enc_block, 1); + + buf[(*offset)++] = ASN1_BIT_STRING; + set_gen_length(sig_size+1, buf, offset); + buf[(*offset)++] = 0; /* bit string is multiple of 8 */ + memcpy(&buf[*offset], enc_block, sig_size); + *offset += sig_size; +} + +static int ICACHE_FLASH_ATTR gen_tbs_cert(const char * dn[], + const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset, + uint8_t *sha_dgst) +{ + int ret = X509_OK; + SHA1_CTX sha_ctx; + int seq_offset; + int begin_tbs = *offset; + int seq_size = pre_adjust_with_size( + ASN1_SEQUENCE, &seq_offset, buf, offset); + + gen_serial_number(buf, offset); + gen_signature_alg(buf, offset); + + /* CA certicate issuer */ + if ((ret = gen_issuer(dn, buf, offset))) + goto error; + + gen_utc_time(buf, offset); + + /* certificate issuer */ + if ((ret = gen_issuer(dn, buf, offset))) + goto error; + + gen_pub_key(rsa_ctx, buf, offset); + adjust_with_size(seq_size, seq_offset, buf, offset); + + SHA1_Init(&sha_ctx); + SHA1_Update(&sha_ctx, &buf[begin_tbs], *offset-begin_tbs); + SHA1_Final(sha_dgst, &sha_ctx); + +error: + return ret; +} + +/** + * Create a new certificate. + */ +EXP_FUNC int ICACHE_FLASH_ATTR STDCALL ssl_x509_create(SSL_CTX *ssl_ctx, uint32_t options, const char * dn[], uint8_t **cert_data) +{ + int ret = X509_OK, offset = 0, seq_offset; + /* allocate enough space to load a new certificate */ + uint8_t *buf = (uint8_t *)alloca(ssl_ctx->rsa_ctx->num_octets*2 + 512); + uint8_t sha_dgst[SHA1_SIZE]; + int seq_size = pre_adjust_with_size(ASN1_SEQUENCE, + &seq_offset, buf, &offset); + + if ((ret = gen_tbs_cert(dn, ssl_ctx->rsa_ctx, buf, &offset, sha_dgst)) < 0) + goto error; + + gen_signature_alg(buf, &offset); + gen_signature(ssl_ctx->rsa_ctx, sha_dgst, buf, &offset); + adjust_with_size(seq_size, seq_offset, buf, &offset); + *cert_data = (uint8_t *)SSL_MALLOC(offset); /* create the exact memory for it */ + memcpy(*cert_data, buf, offset); + +error: + return ret < 0 ? ret : offset; +} + +#endif + diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_loader.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_loader.c new file mode 100644 index 0000000..0a2c17d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_loader.c @@ -0,0 +1,519 @@ +/* + * Copyright (c) 2007-2014, 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. + */ + +/** + * Load certificates/keys into memory. These can be in many different formats. + * PEM support and other formats can be processed here. + * + * The PEM private keys may be optionally encrypted with AES128 or AES256. + * The encrypted PEM keys were generated with something like: + * + * openssl genrsa -aes128 -passout pass:abcd -out axTLS.key_aes128.pem 512 + */ + +#include "ssl/ssl_os_port.h" +#include "ssl/ssl_ssl.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +static int do_obj(SSL_CTX *ssl_ctx, int obj_type, + SSLObjLoader *ssl_obj, const char *password); +#ifdef CONFIG_SSL_HAS_PEM +static int ssl_obj_PEM_load(SSL_CTX *ssl_ctx, int obj_type, + SSLObjLoader *ssl_obj, const char *password); +#endif + +/* + * Load a file into memory that is in binary DER (or ascii PEM) format. + */ +EXP_FUNC int STDCALL ICACHE_FLASH_ATTR ssl_obj_load(SSL_CTX *ssl_ctx, int obj_type, + const char *filename, const char *password) +{ +#ifndef CONFIG_SSL_SKELETON_MODE + static const char * const begin = "-----BEGIN"; + int ret = SSL_OK; + SSLObjLoader *ssl_obj = NULL; + + if (filename == NULL) + { + ret = SSL_ERROR_INVALID_KEY; + goto error; + } + + ssl_obj = (SSLObjLoader *)SSL_ZALLOC(sizeof(SSLObjLoader)); + ssl_obj->len = get_file(filename, &ssl_obj->buf); + if (ssl_obj->len <= 0) + { + ret = SSL_ERROR_INVALID_KEY; + goto error; + } + + /* is the file a PEM file? */ + if ((char *)strstr((const char *)ssl_obj->buf, begin) != NULL) + { +#ifdef CONFIG_SSL_HAS_PEM +#if CONFIG_SSL_DISPLAY_MODE + os_printf("the file is a PEM file.\n"); +#endif + ret = ssl_obj_PEM_load(ssl_ctx, obj_type, ssl_obj, password); +#else + ssl_printf(unsupported_str); + ret = SSL_ERROR_NOT_SUPPORTED; +#endif + } + else { +#if CONFIG_SSL_DISPLAY_MODE + os_printf("the file is not a PEM file.\n"); +#endif + ret = do_obj(ssl_ctx, obj_type, ssl_obj, password); + } + +error: + ssl_obj_free(ssl_obj); + return ret; +#else + ssl_printf(unsupported_str); + return SSL_ERROR_NOT_SUPPORTED; +#endif /* CONFIG_SSL_SKELETON_MODE */ +} + +/* + * Transfer binary data into the object loader. + */ +EXP_FUNC int STDCALL ICACHE_FLASH_ATTR ssl_obj_memory_load(SSL_CTX *ssl_ctx, int mem_type, + const uint8_t *data, int len, const char *password) +{ + int ret; + SSLObjLoader *ssl_obj; + uint32 sign_len = (len + 3)&(~3); + + ssl_obj = (SSLObjLoader *)SSL_ZALLOC(sizeof(SSLObjLoader)); + ssl_obj->buf = (uint8_t *)SSL_MALLOC(sign_len); + memcpy(ssl_obj->buf, data, sign_len); + ssl_obj->len = len; + ret = do_obj(ssl_ctx, mem_type, ssl_obj, password); + ssl_obj_free(ssl_obj); + return ret; +} + +/* + * Actually work out what we are doing + */ +static int ICACHE_FLASH_ATTR do_obj(SSL_CTX *ssl_ctx, int obj_type, + SSLObjLoader *ssl_obj, const char *password) +{ + int ret = SSL_OK; + + switch (obj_type) + { + case SSL_OBJ_RSA_KEY: + ret = add_private_key(ssl_ctx, ssl_obj); + break; + + case SSL_OBJ_X509_CERT: + ret = add_cert(ssl_ctx, ssl_obj->buf, ssl_obj->len); + break; + +#ifdef CONFIG_SSL_CERT_VERIFICATION + case SSL_OBJ_X509_CACERT: + add_cert_auth(ssl_ctx, ssl_obj->buf, ssl_obj->len); + break; +#endif + +#ifdef CONFIG_SSL_USE_PKCS12 + case SSL_OBJ_PKCS8: + ret = pkcs8_decode(ssl_ctx, ssl_obj, password); + break; + + case SSL_OBJ_PKCS12: + ret = pkcs12_decode(ssl_ctx, ssl_obj, password); + break; +#endif + default: + ssl_printf(unsupported_str); + ret = SSL_ERROR_NOT_SUPPORTED; + break; + } + + return ret; +} + +/* + * Clean up our mess. + */ +void ICACHE_FLASH_ATTR ssl_obj_free(SSLObjLoader *ssl_obj) +{ + if (ssl_obj) + { + SSL_FREE(ssl_obj->buf); + SSL_FREE(ssl_obj); + } +} + +/* + * Support for PEM encoded keys/certificates. + */ +#ifdef CONFIG_SSL_HAS_PEM + +#define NUM_PEM_TYPES 4 +#define IV_SIZE 16 +#define IS_RSA_PRIVATE_KEY 0 +#define IS_ENCRYPTED_PRIVATE_KEY 1 +#define IS_PRIVATE_KEY 2 +#define IS_CERTIFICATE 3 + +static const char begins[NUM_PEM_TYPES][40] ICACHE_RODATA_ATTR STORE_ATTR = +{ + "-----BEGIN RSA PRIVATE KEY-----", + "-----BEGIN ENCRYPTED PRIVATE KEY-----", + "-----BEGIN PRIVATE KEY-----", + "-----BEGIN CERTIFICATE-----", +}; + +static const char ends[NUM_PEM_TYPES][40] ICACHE_RODATA_ATTR STORE_ATTR = +{ + "-----END RSA PRIVATE KEY-----", + "-----END ENCRYPTED PRIVATE KEY-----", + "-----END PRIVATE KEY-----", + "-----END CERTIFICATE-----", +}; + +static const char aes_str[2][24] ICACHE_RODATA_ATTR STORE_ATTR = +{ + "DEK-Info: AES-128-CBC,", + "DEK-Info: AES-256-CBC," +}; + +/** + * Take a base64 blob of data and decrypt it (using AES) into its + * proper ASN.1 form. + */ +static int ICACHE_FLASH_ATTR pem_decrypt(const char *where, const char *end, + const char *password, SSLObjLoader *ssl_obj) +{ + int ret = -1; + int is_aes_256 = 0; + char *start = NULL; + uint8_t iv[IV_SIZE]; + int i, pem_size; + MD5_CTX md5_ctx; + AES_CTX aes_ctx; + uint8_t key[32]; /* AES256 size */ + + if (password == NULL || strlen(password) == 0) + { +#ifdef CONFIG_SSL_FULL_MODE + ssl_printf("Error: Need a password for this PEM file\n"); //TTY_FLUSH(); +#endif + goto error; + } + + char *aes_str_0_ram = (char *)SSL_MALLOC(24); + char *aes_str_1_ram = (char *)SSL_MALLOC(24); + + system_get_string_from_flash(aes_str[0], aes_str_0_ram, 24); + system_get_string_from_flash(aes_str[1], aes_str_1_ram, 24); + + if ((start = (char *)strstr((const char *)where, aes_str_0_ram))) /* AES128? */ + { + start += strlen(aes_str_0_ram); + } + else if ((start = (char *)strstr((const char *)where, aes_str_1_ram))) /* AES256? */ + { + is_aes_256 = 1; + start += strlen(aes_str_1_ram); + } + else + { +#ifdef CONFIG_SSL_FULL_MODE + ssl_printf("Error: Unsupported password cipher\n"); //TTY_FLUSH(); +#endif + goto error; + } + + /* convert from hex to binary - assumes uppercase hex */ + for (i = 0; i < IV_SIZE; i++) + { + char c = *start++ - '0'; + iv[i] = (c > 9 ? c + '0' - 'A' + 10 : c) << 4; + c = *start++ - '0'; + iv[i] += (c > 9 ? c + '0' - 'A' + 10 : c); + } + + while (*start == '\r' || *start == '\n') + start++; + + /* turn base64 into binary */ + pem_size = (int)(end-start); + if (base64_decode(start, pem_size, ssl_obj->buf, &ssl_obj->len) != 0) + goto error; + + /* work out the key */ + MD5_Init(&md5_ctx); + MD5_Update(&md5_ctx, (const uint8_t *)password, strlen(password)); + MD5_Update(&md5_ctx, iv, SALT_SIZE); + MD5_Final(key, &md5_ctx); + + if (is_aes_256) + { + MD5_Init(&md5_ctx); + MD5_Update(&md5_ctx, key, MD5_SIZE); + MD5_Update(&md5_ctx, (const uint8_t *)password, strlen(password)); + MD5_Update(&md5_ctx, iv, SALT_SIZE); + MD5_Final(&key[MD5_SIZE], &md5_ctx); + } + + /* decrypt using the key/iv */ + AES_set_key(&aes_ctx, key, iv, is_aes_256 ? AES_MODE_256 : AES_MODE_128); + AES_convert_key(&aes_ctx); + AES_cbc_decrypt(&aes_ctx, ssl_obj->buf, ssl_obj->buf, ssl_obj->len); + ret = 0; + +error: + SSL_FREE(aes_str_0_ram); + SSL_FREE(aes_str_1_ram); + return ret; +} + +/** + * Take a base64 blob of data and turn it into its proper ASN.1 form. + */ +static int ICACHE_FLASH_ATTR new_pem_obj(SSL_CTX *ssl_ctx, int is_cacert, char *where, + int remain, const char *password) +{ + int ret = SSL_ERROR_BAD_CERTIFICATE; + SSLObjLoader *ssl_obj = NULL; + char *begins_ram = (char *)SSL_MALLOC(40); + char *ends_ram = (char *)SSL_MALLOC(40); + + while (remain > 0) + { + int i, pem_size, obj_type; + char *start = NULL, *end = NULL; + + for (i = 0; i < NUM_PEM_TYPES; i++) + { + system_get_string_from_flash(begins[i], begins_ram, 40); + system_get_string_from_flash(ends[i], ends_ram, 40); + if ((start = (char *)strstr(where, begins_ram)) && + (end = (char *)strstr(where, ends_ram))) + { + remain -= (int)(end-where); + start += strlen(begins_ram); + pem_size = (int)(end-start); + + ssl_obj = (SSLObjLoader *)SSL_ZALLOC(sizeof(SSLObjLoader)); + + /* 4/3 bigger than what we need but so what */ + ssl_obj->buf = (uint8_t *)SSL_ZALLOC(pem_size); + ssl_obj->len = pem_size; + + if (i == IS_RSA_PRIVATE_KEY && + strstr(start, "Proc-Type:") && + strstr(start, "4,ENCRYPTED")) + { + /* check for encrypted PEM file */ + if (pem_decrypt(start, end, password, ssl_obj) < 0) + { + ret = SSL_ERROR_BAD_CERTIFICATE; + goto error; + } + } + else + { + ssl_obj->len = pem_size; + if (base64_decode(start, pem_size, + ssl_obj->buf, &ssl_obj->len) != 0) + { + ret = SSL_ERROR_BAD_CERTIFICATE; + goto error; + } + } + + switch (i) + { + case IS_RSA_PRIVATE_KEY: + obj_type = SSL_OBJ_RSA_KEY; + break; + + case IS_ENCRYPTED_PRIVATE_KEY: + case IS_PRIVATE_KEY: + obj_type = SSL_OBJ_PKCS8; + break; + + case IS_CERTIFICATE: + obj_type = is_cacert ? + SSL_OBJ_X509_CACERT : SSL_OBJ_X509_CERT; + break; + + default: + ret = SSL_ERROR_BAD_CERTIFICATE; + goto error; + } + + /* In a format we can now understand - so process it */ + if ((ret = do_obj(ssl_ctx, obj_type, ssl_obj, password))) + goto error; + + end += strlen(ends_ram); + remain -= strlen(ends_ram); + while (remain > 0 && (*end == '\r' || *end == '\n')) + { + end++; + remain--; + } + + where = end; + break; + } + } + + ssl_obj_free(ssl_obj); + ssl_obj = NULL; + if (start == NULL) + break; + } +error: + SSL_FREE(begins_ram); + SSL_FREE(ends_ram); + ssl_obj_free(ssl_obj); + return ret; +} + +/* + * Load a file into memory that is in ASCII PEM format. + */ +static int ICACHE_FLASH_ATTR ssl_obj_PEM_load(SSL_CTX *ssl_ctx, int obj_type, + SSLObjLoader *ssl_obj, const char *password) +{ + char *start; + + /* add a null terminator */ + ssl_obj->len++; + ssl_obj->buf = (uint8_t *)SSL_REALLOC(ssl_obj->buf, ssl_obj->len); + ssl_obj->buf[ssl_obj->len-1] = 0; + start = (char *)ssl_obj->buf; + return new_pem_obj(ssl_ctx, obj_type == SSL_OBJ_X509_CACERT, + start, ssl_obj->len, password); +} +#endif /* CONFIG_SSL_HAS_PEM */ + +/** + * Load the key/certificates in memory depending on compile-time and user + * options. + */ +int ICACHE_FLASH_ATTR load_key_certs(SSL_CTX *ssl_ctx) +{ + int ret = SSL_OK; + uint32_t options = ssl_ctx->options; +#ifdef CONFIG_SSL_GENERATE_X509_CERT + uint8_t *cert_data = NULL; + int cert_size; + static const char *dn[] = + { + CONFIG_SSL_X509_COMMON_NAME, + CONFIG_SSL_X509_ORGANIZATION_NAME, + CONFIG_SSL_X509_ORGANIZATION_UNIT_NAME + }; +#endif + + /* do the private key first */ + if (strlen(CONFIG_SSL_PRIVATE_KEY_LOCATION) > 0) + { + if ((ret = ssl_obj_load(ssl_ctx, SSL_OBJ_RSA_KEY, + CONFIG_SSL_PRIVATE_KEY_LOCATION, + CONFIG_SSL_PRIVATE_KEY_PASSWORD)) < 0) + goto error; + } + else if (!(options & SSL_NO_DEFAULT_KEY)) + { +#if defined(CONFIG_SSL_USE_DEFAULT_KEY) || defined(CONFIG_SSL_SKELETON_MODE) + // static const /* saves a few more bytes */ +//#include "private_key.h" + + extern unsigned int def_private_key_len; + extern unsigned char *def_private_key; + if (def_private_key == NULL){ + ret = SSL_NOT_OK; + goto error; + } + ssl_obj_memory_load(ssl_ctx, SSL_OBJ_RSA_KEY, def_private_key, + def_private_key_len, NULL); +#endif + } + + /* now load the certificate */ +#ifdef CONFIG_SSL_GENERATE_X509_CERT + if ((cert_size = ssl_x509_create(ssl_ctx, 0, dn, &cert_data)) < 0) + { + ret = cert_size; + goto error; + } + + ssl_obj_memory_load(ssl_ctx, SSL_OBJ_X509_CERT, cert_data, cert_size, NULL); + SSL_FREE(cert_data); +#else + if (strlen(CONFIG_SSL_X509_CERT_LOCATION)) + { + if ((ret = ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, + CONFIG_SSL_X509_CERT_LOCATION, NULL)) < 0) + goto error; + } + else if (!(options & SSL_NO_DEFAULT_KEY)) + { +#if defined(CONFIG_SSL_USE_DEFAULT_KEY) || defined(CONFIG_SSL_SKELETON_MODE) +// static const /* saves a few bytes and RAM */ +//#include "cert.h" + extern unsigned char *def_certificate; + extern unsigned int def_certificate_len; + if (def_certificate == NULL){ + ret = SSL_NOT_OK; + goto error; + } + ssl_obj_memory_load(ssl_ctx, SSL_OBJ_X509_CERT, + def_certificate, def_certificate_len, NULL); +#endif + } +#endif + +error: +#ifdef CONFIG_SSL_FULL_MODE + if (ret) + { + ssl_printf("Error: Certificate or key not loaded\n"); //TTY_FLUSH(); + } +#endif + + return ret; + +} + diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_openssl.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_openssl.c new file mode 100644 index 0000000..f4656a6 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_openssl.c @@ -0,0 +1,326 @@ +/* + * 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. + */ + +/* + * Enable a subset of openssl compatible functions. We don't aim to be 100% + * compatible - just to be able to do basic ports etc. + * + * Only really tested on mini_httpd, so I'm not too sure how extensive this + * port is. + */ + +#include "ssl/ssl_config.h" + +#ifdef CONFIG_OPENSSL_COMPATIBLE +#include +#include +#include +#include "ssl/ssl_os_port.h" +#include "ssl/ssl_ssl.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +#define OPENSSL_CTX_ATTR ((OPENSSL_CTX *)ssl_ctx->bonus_attr) + +static char *key_password = NULL; + +void *SSLv23_server_method(void) { return NULL; } +void *SSLv3_server_method(void) { return NULL; } +void *TLSv1_server_method(void) { return NULL; } +void *SSLv23_client_method(void) { return NULL; } +void *SSLv3_client_method(void) { return NULL; } +void *TLSv1_client_method(void) { return NULL; } + +typedef void * (*ssl_func_type_t)(void); +typedef void * (*bio_func_type_t)(void); + +typedef struct +{ + ssl_func_type_t ssl_func_type; +} OPENSSL_CTX; + +SSL_CTX *ICACHE_FLASH_ATTR SSL_CTX_new(ssl_func_type_t meth) +{ + SSL_CTX *ssl_ctx = ssl_ctx_new(0, 5); + ssl_ctx->bonus_attr = SSL_MALLOC(sizeof(OPENSSL_CTX)); + OPENSSL_CTX_ATTR->ssl_func_type = meth; + return ssl_ctx; +} + +void ICACHE_FLASH_ATTR SSL_CTX_free(SSL_CTX *ssl_ctx) +{ + SSL_FREE(ssl_ctx->bonus_attr); + ssl_ctx_free(ssl_ctx); +} + +SSL *ICACHE_FLASH_ATTR SSL_new(SSL_CTX *ssl_ctx) +{ + SSL *ssl; + ssl_func_type_t ssl_func_type; + + ssl = ssl_new(ssl_ctx, -1); /* fd is set later */ + ssl_func_type = OPENSSL_CTX_ATTR->ssl_func_type; + +#ifdef CONFIG_SSL_ENABLE_CLIENT + if (ssl_func_type == SSLv23_client_method || + ssl_func_type == SSLv3_client_method || + ssl_func_type == TLSv1_client_method) + { + SET_SSL_FLAG(SSL_IS_CLIENT); + } + else +#endif + { + ssl->next_state = HS_CLIENT_HELLO; + } + + return ssl; +} + +int ICACHE_FLASH_ATTR SSL_set_fd(SSL *s, int fd) +{ + s->client_fd = fd; + return 1; /* always succeeds */ +} + +int ICACHE_FLASH_ATTR SSL_accept(SSL *ssl) +{ + while (ssl_read(ssl, NULL) == SSL_OK) + { + if (ssl->next_state == HS_CLIENT_HELLO) + return 1; /* we're done */ + } + + return -1; +} + +#ifdef CONFIG_SSL_ENABLE_CLIENT +int ICACHE_FLASH_ATTR SSL_connect(SSL *ssl) +{ + return do_client_connect(ssl) == SSL_OK ? 1 : -1; +} +#endif + +void ICACHE_FLASH_ATTR SSL_free(SSL *ssl) +{ + ssl_free(ssl); +} + +int ICACHE_FLASH_ATTR SSL_read(SSL *ssl, void *buf, int num) +{ + uint8_t *read_buf; + int ret; + + while ((ret = ssl_read(ssl, &read_buf)) == SSL_OK); + + if (ret > SSL_OK) + { + memcpy(buf, read_buf, ret > num ? num : ret); + } + + return ret; +} + +int ICACHE_FLASH_ATTR SSL_write(SSL *ssl, const void *buf, int num) +{ + return ssl_write(ssl, buf, num); +} + +int ICACHE_FLASH_ATTR SSL_CTX_use_certificate_file(SSL_CTX *ssl_ctx, const char *file, int type) +{ + return (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, file, NULL) == SSL_OK); +} + +int ICACHE_FLASH_ATTR SSL_CTX_use_PrivateKey_file(SSL_CTX *ssl_ctx, const char *file, int type) +{ + return (ssl_obj_load(ssl_ctx, SSL_OBJ_RSA_KEY, file, key_password) == SSL_OK); +} + +int ICACHE_FLASH_ATTR SSL_CTX_use_certificate_ASN1(SSL_CTX *ssl_ctx, int len, const uint8_t *d) +{ + return (ssl_obj_memory_load(ssl_ctx, + SSL_OBJ_X509_CERT, d, len, NULL) == SSL_OK); +} + +int ICACHE_FLASH_ATTR SSL_CTX_set_session_id_context(SSL_CTX *ctx, const unsigned char *sid_ctx, + unsigned int sid_ctx_len) +{ + return 1; +} + +int ICACHE_FLASH_ATTR SSL_CTX_set_default_verify_paths(SSL_CTX *ctx) +{ + return 1; +} + +int ICACHE_FLASH_ATTR SSL_CTX_use_certificate_chain_file(SSL_CTX *ssl_ctx, const char *file) +{ + return (ssl_obj_load(ssl_ctx, + SSL_OBJ_X509_CERT, file, NULL) == SSL_OK); +} + +int ICACHE_FLASH_ATTR SSL_shutdown(SSL *ssl) +{ + return 1; +} + +/*** get/set session ***/ +SSL_SESSION *ICACHE_FLASH_ATTR SSL_get1_session(SSL *ssl) +{ + return (SSL_SESSION *)ssl_get_session_id(ssl); /* note: wrong cast */ +} + +int ICACHE_FLASH_ATTR SSL_set_session(SSL *ssl, SSL_SESSION *session) +{ + memcpy(ssl->session_id, (uint8_t *)session, SSL_SESSION_ID_SIZE); + return 1; +} + +void ICACHE_FLASH_ATTR SSL_SESSION_free(SSL_SESSION *session) { } +/*** end get/set session ***/ + +long ICACHE_FLASH_ATTR SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) +{ + return 0; +} + +void ICACHE_FLASH_ATTR SSL_CTX_set_verify(SSL_CTX *ctx, int mode, + int (*verify_callback)(int, void *)) { } + +void ICACHE_FLASH_ATTR SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth) { } + +int ICACHE_FLASH_ATTR SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, + const char *CApath) +{ + return 1; +} + +void *ICACHE_FLASH_ATTR SSL_load_client_CA_file(const char *file) +{ + return (void *)file; +} + +void ICACHE_FLASH_ATTR SSL_CTX_set_client_CA_list(SSL_CTX *ssl_ctx, void *file) +{ + ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, (const char *)file, NULL); +} + +void ICACHE_FLASH_ATTR SSLv23_method(void) { } + +void ICACHE_FLASH_ATTR SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, void *cb) { } + +void ICACHE_FLASH_ATTR SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u) +{ + key_password = (char *)u; +} + +int ICACHE_FLASH_ATTR SSL_peek(SSL *ssl, void *buf, int num) +{ + memcpy(buf, ssl->bm_data, num); + return num; +} + +void ICACHE_FLASH_ATTR SSL_set_bio(SSL *ssl, void *rbio, void *wbio) { } + +long ICACHE_FLASH_ATTR SSL_get_verify_result(const SSL *ssl) +{ + return ssl_handshake_status(ssl); +} + +int ICACHE_FLASH_ATTR SSL_state(SSL *ssl) +{ + return 0x03; // ok state +} + +/** end of could do better list */ + +void *ICACHE_FLASH_ATTR SSL_get_peer_certificate(const SSL *ssl) +{ + return &ssl->ssl_ctx->certs[0]; +} + +int ICACHE_FLASH_ATTR SSL_clear(SSL *ssl) +{ + return 1; +} + + +int ICACHE_FLASH_ATTR SSL_CTX_check_private_key(const SSL_CTX *ctx) +{ + return 1; +} + +int ICACHE_FLASH_ATTR SSL_CTX_set_cipher_list(SSL *s, const char *str) +{ + return 1; +} + +int ICACHE_FLASH_ATTR SSL_get_error(const SSL *ssl, int ret) +{ + ssl_display_error(ret); + return 0; /* TODO: return proper return code */ +} + +void ICACHE_FLASH_ATTR SSL_CTX_set_options(SSL_CTX *ssl_ctx, int option) {} +int ICACHE_FLASH_ATTR SSL_library_init(void ) { return 1; } +void ICACHE_FLASH_ATTR SSL_load_error_strings(void ) {} +void ICACHE_FLASH_ATTR ERR_print_errors_fp(FILE *fp) {} + +#ifndef CONFIG_SSL_SKELETON_MODE +long ICACHE_FLASH_ATTR SSL_CTX_get_timeout(const SSL_CTX *ssl_ctx) { + return CONFIG_SSL_EXPIRY_TIME*3600; } +long ICACHE_FLASH_ATTR SSL_CTX_set_timeout(SSL_CTX *ssl_ctx, long t) { + return SSL_CTX_get_timeout(ssl_ctx); } +#endif +void ICACHE_FLASH_ATTR BIO_printf(FILE *f, const char *format, ...) +{ + va_list(ap); + va_start(ap, format); + vfprintf(f, format, ap); + va_end(ap); +} + +void* ICACHE_FLASH_ATTR BIO_s_null(void) { return NULL; } +FILE *ICACHE_FLASH_ATTR BIO_new(bio_func_type_t func) +{ + if (func == BIO_s_null) + return fopen("/dev/null", "r"); + else + return NULL; +} + +FILE *ICACHE_FLASH_ATTR BIO_new_fp(FILE *stream, int close_flag) { return stream; } +int ICACHE_FLASH_ATTR BIO_free(FILE *a) { if (a != stdout && a != stderr) fclose(a); return 1; } + + + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_os_port.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_os_port.c new file mode 100644 index 0000000..182c787 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_os_port.c @@ -0,0 +1,341 @@ +/* + * 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 os_port.c + * + * OS specific functions. + */ + +#include "ssl/ssl_os_port.h" +#include "lwip/sockets.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +#ifdef WIN32 +/** + * gettimeofday() not in Win32 + */ +EXP_FUNC void STDCALL gettimeofday(struct timeval* t, void* timezone) +{ +#if defined(_WIN32_WCE) + t->tv_sec = time(NULL); + t->tv_usec = 0; /* 1sec precision only */ +#else + struct _timeb timebuffer; + _ftime(&timebuffer); + t->tv_sec = (long)timebuffer.time; + t->tv_usec = 1000 * timebuffer.millitm; /* 1ms precision */ +#endif +} + +/** + * strcasecmp() not in Win32 + */ +EXP_FUNC int STDCALL strcasecmp(const char *s1, const char *s2) +{ + while (tolower(*s1) == tolower(*s2++)) + { + if (*s1++ == '\0') + { + return 0; + } + } + + return *(unsigned char *)s1 - *(unsigned char *)(s2 - 1); +} + + +EXP_FUNC int STDCALL getdomainname(char *buf, int buf_size) +{ + HKEY hKey; + unsigned long datatype; + unsigned long bufferlength = buf_size; + + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, + TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), + 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS) + return -1; + + RegQueryValueEx(hKey, "Domain", NULL, &datatype, buf, &bufferlength); + RegCloseKey(hKey); + return 0; +} +#endif + +static const char * out_of_mem_str = "out of memory %s %d\n"; + +#define exit_now os_printf +//#define SSL_LOG +#ifdef SSL_LOG +#define debug_now os_printf +#else +#define debug_now +#endif + +#if 0 +static MEM_LEAK * ptr_start = NULL; +static MEM_LEAK * ptr_next = NULL; +xTaskHandle mem_mutex; +#define name_length 128 + +extern int mem_flag; +void add(MEM_INFO alloc_info) +{ + + MEM_LEAK * mem_leak_info = NULL; + mem_leak_info = (MEM_LEAK *)malloc(sizeof(MEM_LEAK)); + mem_leak_info->mem_info.address = alloc_info.address; + mem_leak_info->mem_info.size = alloc_info.size; + strcpy(mem_leak_info->mem_info.file_name, alloc_info.file_name); + mem_leak_info->mem_info.line = alloc_info.line; + mem_leak_info->next = NULL; + + if (ptr_start == NULL) + { + ptr_start = mem_leak_info; + ptr_next = ptr_start; + } + else { + ptr_next->next = mem_leak_info; + ptr_next = ptr_next->next; + } + if(mem_flag) { + os_printf("mem_leak_info =%p\n",mem_leak_info); + mem_flag = 0; + report_mem_leak(); + } + +} +void erase(unsigned pos) +{ + + unsigned index = 0; + MEM_LEAK * alloc_info, * temp; + + if(pos == 0) + { + MEM_LEAK * temp = ptr_start; + ptr_start = ptr_start->next; + free(temp); + } + else + { + for(index = 0, alloc_info = ptr_start; index < pos; + alloc_info = alloc_info->next, ++index) + { + if(pos == index + 1) + { + temp = alloc_info->next; + alloc_info->next = temp->next; + free(temp); + break; + } + } + } +} + +void clear() +{ + MEM_LEAK * temp = ptr_start; + MEM_LEAK * alloc_info = ptr_start; + + while(alloc_info != NULL) + { + alloc_info = alloc_info->next; + free(temp); + temp = alloc_info; + } + +} + +void add_mem_info (void * mem_ref, unsigned int size, const char * file, unsigned int line) +{ + sys_mutex_lock(&mem_mutex); + + MEM_INFO mem_alloc_info; + memset( &mem_alloc_info, 0, sizeof ( mem_alloc_info ) ); + mem_alloc_info.address = mem_ref; + mem_alloc_info.size = size; + strncpy(mem_alloc_info.file_name, file, FILE_NAME_LENGTH); + mem_alloc_info.line = line; + add(mem_alloc_info); + sys_mutex_unlock(&mem_mutex); +} +void remove_mem_info (void * mem_ref) +{ + unsigned short index; + MEM_LEAK * leak_info = ptr_start; + + sys_mutex_lock(&mem_mutex); + for(index = 0; leak_info != NULL; ++index, leak_info = leak_info->next) + { + if ( leak_info->mem_info.address == mem_ref ) + { + erase ( index ); + break; + } + } + + sys_mutex_unlock(&mem_mutex); +} +#endif + +EXP_FUNC void * ICACHE_FLASH_ATTR ax_malloc(size_t s, const char* file, int line) +{ + void *x; + + if ((x = malloc(s)) == NULL) + exit_now("out of memory %s %d\n", file, line); + else { + debug_now("%s %d point[%p] size[%d] heap[%d]\n", file, line, x, s, system_get_free_heap_size()); + //add_mem_info(x, s, file, line); + } + + return x; +} +EXP_FUNC void * ICACHE_FLASH_ATTR ax_realloc(void *y, size_t s, const char* file, int line) +{ + void *x; + + if ((x = realloc(y, s)) == NULL) + exit_now("out of memory %s %d\n", file, line); + else { + debug_now("%s %d point[%p] size[%d] heap[%d]\n", file, line, x, s, system_get_free_heap_size()); + //add_mem_info(x, s, file, line); + } + + return x; +} +EXP_FUNC void * ICACHE_FLASH_ATTR ax_calloc(size_t n, size_t s, const char* file, int line) +{ + void *x; + //unsigned total_size =0; + if ((x = calloc(n, s)) == NULL) + exit_now("out of memory %s %d\n", file, line); + else { + debug_now("%s %d point[%p] size[%d] heap[%d]\n", file, line, x, s, system_get_free_heap_size()); + //total_size = n * s; + //add_mem_info (x, total_size, file, line); + } + + return x; +} +EXP_FUNC void * ICACHE_FLASH_ATTR ax_zalloc(size_t s, const char* file, int line) +{ + void *x; + + if ((x = (void*)zalloc(s)) == NULL) + exit_now("out of memory %s %d\n", file, line); + else { + debug_now("%s %d point[%p] size[%d] heap[%d]\n", file, line, x, s, system_get_free_heap_size()); + //add_mem_info(x, s, file, line); + } + + return x; +} +EXP_FUNC void ICACHE_FLASH_ATTR ax_free(void *p, const char* file, int line) +{ + if(p) { + debug_now("%s %d point[%p] size[%d] heap[%d]\n", file, line, p,0, system_get_free_heap_size()); + free(p); + p = NULL; + } + return ; +} + +#if 0 +void report_mem_leak(void) +{ + unsigned short index; + MEM_LEAK * leak_info; + + char *info; + sys_mutex_lock(&mem_mutex); + os_printf("ptr_start =%p\n",ptr_start); + info = (char *)zalloc(name_length); + if(info) { + for(leak_info = ptr_start; leak_info != NULL; leak_info = leak_info->next) + { + os_printf("%p\n",leak_info); + sprintf(info, "address : %p\n", leak_info->mem_info.address); + os_printf("%s\n",info); + sprintf(info, "size : %d bytes\n", leak_info->mem_info.size); + os_printf("%s\n",info); + snprintf(info,name_length,"file : %s\n", leak_info->mem_info.file_name); + os_printf("%s\n",info); + sprintf(info, "line : %d\n", leak_info->mem_info.line); + os_printf("%s\n",info); + } + clear(); + free(info); + } + sys_mutex_unlock(&mem_mutex); + sys_mutex_free(&mem_mutex); + +} + + +/* +void exit_now(const char *format, ...) +{ + va_list argp; + + va_start(argp, format); + vfprintf(stderr, format, argp); + va_end(argp); + abort(); +}*/ +/** + * gettimeofday() not in Win32 + */ +EXP_FUNC void STDCALL gettimeofday(struct timeval* t, void* timezone) +{ +#if defined(_WIN32_WCE) + t->tv_sec = time(NULL); + t->tv_usec = 0; /* 1sec precision only */ +#else + /* wujg : pass compile first */ + if (timezone != NULL) + t->tv_sec = *(time_t*)timezone + system_get_time()/1000000; + else + t->tv_sec = system_get_time() + system_get_time()/1000000; + t->tv_usec = 0; /* 1ms precision */ +#endif +} +#endif + +unsigned int def_private_key_len = 0; +unsigned char *def_private_key = NULL; +unsigned char *def_certificate = NULL; +unsigned int def_certificate_len = 0; + diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_p12.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_p12.c new file mode 100644 index 0000000..e7a85d5 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_p12.c @@ -0,0 +1,484 @@ +/* + * 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. + */ + +/** + * Process PKCS#8/PKCS#12 keys. + * + * The decoding of a PKCS#12 key is fairly specific - this code was tested on a + * key generated with: + * + * openssl pkcs12 -export -in axTLS.x509_1024.pem -inkey axTLS.key_1024.pem + * -keypbe PBE-SHA1-RC4-128 -certpbe PBE-SHA1-RC4-128 + * -name "p12_withoutCA" -out axTLS.withoutCA.p12 -password pass:abcd + * + * or with a certificate chain: + * + * openssl pkcs12 -export -in axTLS.x509_1024.pem -inkey axTLS.key_1024.pem + * -certfile axTLS.ca_x509.pem -keypbe PBE-SHA1-RC4-128 -certpbe + * PBE-SHA1-RC4-128 -name "p12_withCA" -out axTLS.withCA.p12 -password pass:abcd + * + * Note that the PBE has to be specified with PBE-SHA1-RC4-128. The + * private/public keys/certs have to use RSA encryption. Both the integrity + * and privacy passwords are the same. + * + * The PKCS#8 files were generated with something like: + * + * PEM format: + * openssl pkcs8 -in axTLS.key_512.pem -passout pass:abcd -topk8 -v1 + * PBE-SHA1-RC4-128 -out axTLS.encrypted_pem.p8 + * + * DER format: + * openssl pkcs8 -in axTLS.key_512.pem -passout pass:abcd -topk8 -outform DER + * -v1 PBE-SHA1-RC4-128 -out axTLS.encrypted.p8 + */ + +#include "ssl/ssl_os_port.h" +#include "ssl/ssl_ssl.h" + +/* all commented out if not used */ +#ifdef CONFIG_SSL_USE_PKCS12 + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +#define BLOCK_SIZE 64 +#define PKCS12_KEY_ID 1 +#define PKCS12_IV_ID 2 +#define PKCS12_MAC_ID 3 + +static char *make_uni_pass(const char *password, int *uni_pass_len); +static int p8_decrypt(const char *uni_pass, int uni_pass_len, + const uint8_t *salt, int iter, + uint8_t *priv_key, int priv_key_len, int id); +static int p8_add_key(SSL_CTX *ssl_ctx, uint8_t *priv_key); +static int get_pbe_params(uint8_t *buf, int *offset, + const uint8_t **salt, int *iterations); + +/* + * Take a raw pkcs8 block and then decrypt it and turn it into a normal key. + */ +int ICACHE_FLASH_ATTR pkcs8_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password) +{ + uint8_t *buf = ssl_obj->buf; + int len, offset = 0; + int iterations; + int ret = SSL_NOT_OK; + uint8_t *version = NULL; + const uint8_t *salt; + uint8_t *priv_key; + int uni_pass_len; + char *uni_pass = make_uni_pass(password, &uni_pass_len); + + if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0) + { +#ifdef CONFIG_SSL_FULL_MODE + ssl_printf("Error: Invalid p8 ASN.1 file\n"); +#endif + goto error; + } + + /* unencrypted key? */ + if (asn1_get_int(buf, &offset, &version) > 0 && *version == 0) + { + ret = p8_add_key(ssl_ctx, buf); + goto error; + } + + if (get_pbe_params(buf, &offset, &salt, &iterations) < 0) + goto error; + + if ((len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0) + goto error; + + priv_key = &buf[offset]; + + p8_decrypt(uni_pass, uni_pass_len, salt, + iterations, priv_key, len, PKCS12_KEY_ID); + ret = p8_add_key(ssl_ctx, priv_key); + +error: + SSL_FREE(version); + SSL_FREE(uni_pass); + return ret; +} + +/* + * Take the unencrypted pkcs8 and turn it into a private key + */ +static int ICACHE_FLASH_ATTR p8_add_key(SSL_CTX *ssl_ctx, uint8_t *priv_key) +{ + uint8_t *buf = priv_key; + int len, offset = 0; + int ret = SSL_NOT_OK; + + /* Skip the preamble and go straight to the private key. + We only support rsaEncryption (1.2.840.113549.1.1.1) */ + if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || + asn1_skip_obj(buf, &offset, ASN1_INTEGER) < 0 || + asn1_skip_obj(buf, &offset, ASN1_SEQUENCE) < 0 || + (len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0) + goto error; + + ret = asn1_get_private_key(&buf[offset], len, &ssl_ctx->rsa_ctx); + +error: + return ret; +} + +/* + * Create the unicode password + */ +static char * ICACHE_FLASH_ATTR make_uni_pass(const char *password, int *uni_pass_len) +{ + int pass_len = 0, i; + char *uni_pass; + + if (password == NULL) + { + password = ""; + } + + uni_pass = (char *)SSL_MALLOC((strlen(password)+1)*2); + + /* modify the password into a unicode version */ + for (i = 0; i < (int)strlen(password); i++) + { + uni_pass[pass_len++] = 0; + uni_pass[pass_len++] = password[i]; + } + + uni_pass[pass_len++] = 0; /* null terminate */ + uni_pass[pass_len++] = 0; + *uni_pass_len = pass_len; + return uni_pass; +} + +/* + * Decrypt a pkcs8 block. + */ +static int ICACHE_FLASH_ATTR p8_decrypt(const char *uni_pass, int uni_pass_len, + const uint8_t *salt, int iter, + uint8_t *priv_key, int priv_key_len, int id) +{ + uint8_t p[BLOCK_SIZE*2]; + uint8_t d[BLOCK_SIZE]; + uint8_t Ai[SHA1_SIZE]; + SHA1_CTX sha_ctx; + RC4_CTX rc4_ctx; + int i; + + for (i = 0; i < BLOCK_SIZE; i++) + { + p[i] = salt[i % SALT_SIZE]; + p[BLOCK_SIZE+i] = uni_pass[i % uni_pass_len]; + d[i] = id; + } + + /* get the key - no IV since we are using RC4 */ + SHA1_Init(&sha_ctx); + SHA1_Update(&sha_ctx, d, sizeof(d)); + SHA1_Update(&sha_ctx, p, sizeof(p)); + SHA1_Final(Ai, &sha_ctx); + + for (i = 1; i < iter; i++) + { + SHA1_Init(&sha_ctx); + SHA1_Update(&sha_ctx, Ai, SHA1_SIZE); + SHA1_Final(Ai, &sha_ctx); + } + + /* do the decryption */ + if (id == PKCS12_KEY_ID) + { + RC4_setup(&rc4_ctx, Ai, 16); + RC4_crypt(&rc4_ctx, priv_key, priv_key, priv_key_len); + } + else /* MAC */ + memcpy(priv_key, Ai, SHA1_SIZE); + + return 0; +} + +/* + * Take a raw pkcs12 block and the decrypt it and turn it into a certificate(s) + * and keys. + */ +int ICACHE_FLASH_ATTR pkcs12_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password) +{ + uint8_t *buf = ssl_obj->buf; + int len, iterations, auth_safes_start, + auth_safes_end, auth_safes_len, key_offset, offset = 0; + int all_certs = 0; + uint8_t *version = NULL, *auth_safes = NULL, *cert, *orig_mac; + uint8_t key[SHA1_SIZE]; + uint8_t mac[SHA1_SIZE]; + const uint8_t *salt; + int uni_pass_len, ret = SSL_OK; + char *uni_pass = make_uni_pass(password, &uni_pass_len); + static const uint8_t pkcs_data[] = /* pkc7 data */ + { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01 }; + static const uint8_t pkcs_encrypted[] = /* pkc7 encrypted */ + { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x06 }; + static const uint8_t pkcs8_key_bag[] = /* 1.2.840.113549.1.12.10.1.2 */ + { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x02 }; + + if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0) + { +#ifdef CONFIG_SSL_FULL_MODE + ssl_printf("Error: Invalid p12 ASN.1 file\n"); +#endif + goto error; + } + + if (asn1_get_int(buf, &offset, &version) < 0 || *version != 3) + { + ret = SSL_ERROR_INVALID_VERSION; + goto error; + } + + /* remove all the boring pcks7 bits */ + if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || + (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 || + len != sizeof(pkcs_data) || + memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data))) + goto error; + + offset += len; + + if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 || + asn1_next_obj(buf, &offset, ASN1_OCTET_STRING) < 0) + goto error; + + /* work out the MAC start/end points (done on AuthSafes) */ + auth_safes_start = offset; + auth_safes_end = offset; + if (asn1_skip_obj(buf, &auth_safes_end, ASN1_SEQUENCE) < 0) + goto error; + + auth_safes_len = auth_safes_end - auth_safes_start; + auth_safes = SSL_MALLOC(auth_safes_len); + + memcpy(auth_safes, &buf[auth_safes_start], auth_safes_len); + + if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || + asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || + (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 || + (len != sizeof(pkcs_encrypted) || + memcmp(&buf[offset], pkcs_encrypted, sizeof(pkcs_encrypted)))) + goto error; + + offset += len; + + if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 || + asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || + asn1_skip_obj(buf, &offset, ASN1_INTEGER) < 0 || + asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || + (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 || + len != sizeof(pkcs_data) || + memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data))) + goto error; + + offset += len; + + /* work out the salt for the certificate */ + if (get_pbe_params(buf, &offset, &salt, &iterations) < 0 || + (len = asn1_next_obj(buf, &offset, ASN1_IMPLICIT_TAG)) < 0) + goto error; + + /* decrypt the certificate */ + cert = &buf[offset]; + if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations, cert, + len, PKCS12_KEY_ID)) < 0) + goto error; + + offset += len; + + /* load the certificate */ + key_offset = 0; + all_certs = asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE); + + /* keep going until all certs are loaded */ + while (key_offset < all_certs) + { + int cert_offset = key_offset; + + if (asn1_skip_obj(cert, &cert_offset, ASN1_SEQUENCE) < 0 || + asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE) < 0 || + asn1_skip_obj(cert, &key_offset, ASN1_OID) < 0 || + asn1_next_obj(cert, &key_offset, ASN1_EXPLICIT_TAG) < 0 || + asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE) < 0 || + asn1_skip_obj(cert, &key_offset, ASN1_OID) < 0 || + asn1_next_obj(cert, &key_offset, ASN1_EXPLICIT_TAG) < 0 || + (len = asn1_next_obj(cert, &key_offset, ASN1_OCTET_STRING)) < 0) + goto error; + + if ((ret = add_cert(ssl_ctx, &cert[key_offset], len)) < 0) + goto error; + + key_offset = cert_offset; + } + + if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || + (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 || + len != sizeof(pkcs_data) || + memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data))) + goto error; + + offset += len; + + if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 || + asn1_next_obj(buf, &offset, ASN1_OCTET_STRING) < 0 || + asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || + asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || + (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 || + (len != sizeof(pkcs8_key_bag)) || + memcmp(&buf[offset], pkcs8_key_bag, sizeof(pkcs8_key_bag))) + goto error; + + offset += len; + + /* work out the salt for the private key */ + if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 || + asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || + get_pbe_params(buf, &offset, &salt, &iterations) < 0 || + (len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0) + goto error; + + /* decrypt the private key */ + cert = &buf[offset]; + if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations, cert, + len, PKCS12_KEY_ID)) < 0) + goto error; + + offset += len; + + /* load the private key */ + if ((ret = p8_add_key(ssl_ctx, cert)) < 0) + goto error; + + /* miss out on friendly name, local key id etc */ + if (asn1_skip_obj(buf, &offset, ASN1_SET) < 0) + goto error; + + /* work out the MAC */ + if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || + asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || + asn1_skip_obj(buf, &offset, ASN1_SEQUENCE) < 0 || + (len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0 || + len != SHA1_SIZE) + goto error; + + orig_mac = &buf[offset]; + offset += len; + + /* get the salt */ + if ((len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0 || len != 8) + goto error; + + salt = &buf[offset]; + + /* work out what the mac should be */ + if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations, + key, SHA1_SIZE, PKCS12_MAC_ID)) < 0) + goto error; + + ssl_hmac_sha1(auth_safes, auth_safes_len, key, SHA1_SIZE, mac); + + if (memcmp(mac, orig_mac, SHA1_SIZE)) + { + ret = SSL_ERROR_INVALID_HMAC; + goto error; + } + +error: + SSL_FREE(version); + SSL_FREE(uni_pass); + SSL_FREE(auth_safes); + return ret; +} + +/* + * Retrieve the salt/iteration details from a PBE block. + */ +static int ICACHE_FLASH_ATTR get_pbe_params(uint8_t *buf, int *offset, + const uint8_t **salt, int *iterations) +{ + static const uint8_t pbeSH1RC4[] = /* pbeWithSHAAnd128BitRC4 */ + { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x01 }; + + int i, len; + uint8_t *iter = NULL; + int error_code = SSL_ERROR_NOT_SUPPORTED; + + /* Get the PBE type */ + if (asn1_next_obj(buf, offset, ASN1_SEQUENCE) < 0 || + (len = asn1_next_obj(buf, offset, ASN1_OID)) < 0) + goto error; + + /* we expect pbeWithSHAAnd128BitRC4 (1.2.840.113549.1.12.1.1) + which is the only algorithm we support */ + if (len != sizeof(pbeSH1RC4) || + memcmp(&buf[*offset], pbeSH1RC4, sizeof(pbeSH1RC4))) + { +#ifdef CONFIG_SSL_FULL_MODE + ssl_printf("Error: pkcs8/pkcs12 must use \"PBE-SHA1-RC4-128\"\n"); +#endif + goto error; + } + + *offset += len; + + if (asn1_next_obj(buf, offset, ASN1_SEQUENCE) < 0 || + (len = asn1_next_obj(buf, offset, ASN1_OCTET_STRING)) < 0 || + len != 8) + goto error; + + *salt = &buf[*offset]; + *offset += len; + + if ((len = asn1_get_int(buf, offset, &iter)) < 0) + goto error; + + *iterations = 0; + for (i = 0; i < len; i++) + { + (*iterations) <<= 8; + (*iterations) += iter[i]; + } + + SSL_FREE(iter); + error_code = SSL_OK; /* got here - we are ok */ + +error: + return error_code; +} + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_platform.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_platform.c new file mode 100644 index 0000000..655623b --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_platform.c @@ -0,0 +1,1114 @@ +/* + * 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. + */ + +/* + * Enable a subset of espressif platom ssl compatible functions. We don't aim to be 100% + * compatible - just to be able to do basic ports etc. + * + * Only really tested on mini_httpd, so I'm not too sure how extensive this + * port is. + */ +#include "ssl/ssl_platform.h" +#include "lwip/err.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +/****************************************************************************** + * FunctionName : esp_EVP_DigestInit + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR esp_EVP_DigestInit(MD5_CTX *ctx, uint8 *out) +{ + return ; +} + +/****************************************************************************** + * FunctionName : esp_EVP_DigestUpdate + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR esp_EVP_DigestUpdate(MD5_CTX *ctx, const uint8_t *input, int ilen) +{ + return; +} + +/****************************************************************************** + * FunctionName : esp_EVP_DigestFinal + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR esp_EVP_DigestFinal(MD5_CTX *ctx, uint8_t *output, uint16* olen) +{ + return ; +} + +/****************************************************************************** + * FunctionName : esp_EVP_sha1 + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +char *ICACHE_FLASH_ATTR esp_EVP_sha1(void) +{ + return NULL; +} + +/****************************************************************************** + * FunctionName : esp_EVP_cleanup + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +char *ICACHE_FLASH_ATTR esp_EVP_cleanup(void) +{ + return NULL; +} + +static const unsigned char base64_enc_map[64] ICACHE_RODATA_ATTR STORE_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', '+', '/' +}; + +/****************************************************************************** + * FunctionName : esp_base64_encode + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +EXP_FUNC int STDCALL ICACHE_FLASH_ATTR esp_base64_encode(uint8 *dst, size_t dlen, size_t *olen, + const uint8_t *src, size_t slen) +{ + size_t i, n; + int C1, C2, C3; + unsigned char *p = NULL; + if (slen == 0){ + *olen = 0; + return 0; + } + + n = (slen<<3)/6; + switch ((slen<<3) - (n * 6)){ + case 2: + n += 3; + break; + case 4: + n += 2; + break; + default: + break; + } + + if (dlen < (n + 1)){ + *olen = n + 1; + return -42; + } + + 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; + } +} + +static char *key_password = NULL; + +/****************************************************************************** + * FunctionName : esp_SSLv23_server_method + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void *ICACHE_FLASH_ATTR esp_SSLv23_server_method(void) { return NULL; } + +/****************************************************************************** + * FunctionName : esp_SSLv3_server_method + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void *ICACHE_FLASH_ATTR esp_SSLv3_server_method(void) { return NULL; } + +/****************************************************************************** + * FunctionName : esp_TLSv1_server_method + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void *ICACHE_FLASH_ATTR esp_TLSv1_server_method(void) { return NULL; } + +/****************************************************************************** + * FunctionName : esp_TLSv1_1_server_method + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void *ICACHE_FLASH_ATTR esp_TLSv1_1_server_method(void) { return NULL; } + +/****************************************************************************** + * FunctionName : esp_TLSv1_1_client_method + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void *ICACHE_FLASH_ATTR esp_TLSv1_1_client_method(void) { return NULL; } + +/****************************************************************************** + * FunctionName : esp_SSLv23_client_method + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void *ICACHE_FLASH_ATTR esp_SSLv23_client_method(void) { return NULL; } + +/****************************************************************************** + * FunctionName : esp_SSLv3_client_method + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void *ICACHE_FLASH_ATTR esp_SSLv3_client_method(void) { return NULL; } + +/****************************************************************************** + * FunctionName : esp_TLSv1_client_method + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void *ICACHE_FLASH_ATTR esp_TLSv1_client_method(void) { return NULL; } + +/****************************************************************************** + * FunctionName : esp_ssl_CTX_new + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +SSL_CTX *ICACHE_FLASH_ATTR esp_ssl_CTX_new(ssl_func_type_t meth) +{ + uint32_t options; + options = SSL_SERVER_VERIFY_LATER | SSL_DISPLAY_CERTS | SSL_NO_DEFAULT_KEY; + SSL_CTX *ssl_ctx = ssl_ctx_new(options, SSL_DEFAULT_CLNT_SESS); + ssl_ctx->bonus_attr = os_malloc(sizeof(PLATOM_CTX)); + PLATOM_CTX_ATTR->ssl_func_type = meth; + return ssl_ctx; +} + +/****************************************************************************** + * FunctionName : esp_ssl_CTX_set_option + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +int ICACHE_FLASH_ATTR esp_ssl_CTX_set_option(SSL_CTX *ssl_ctx, uint32_t options) +{ + ssl_ctx->options = options; + return 1; +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR esp_ssl_CTX_free(SSL_CTX *ssl_ctx) +{ + os_free(ssl_ctx->bonus_attr); + ssl_ctx_free(ssl_ctx); +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +SSL *ICACHE_FLASH_ATTR esp_ssl_new(SSL_CTX *ssl_ctx) +{ + SSL *ssl; + ssl_func_type_t ssl_func_type; + + ssl = ssl_new(ssl_ctx, -1); /* fd is set later */ + ssl_func_type = PLATOM_CTX_ATTR->ssl_func_type; + +#ifdef CONFIG_SSL_ENABLE_CLIENT + if (ssl_func_type == esp_SSLv23_client_method || + ssl_func_type == esp_SSLv3_client_method || + ssl_func_type == esp_TLSv1_client_method) + { + SET_SSL_FLAG(SSL_IS_CLIENT); + } + else +#endif + { + ssl->next_state = HS_CLIENT_HELLO; + } + + return ssl; +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +int ICACHE_FLASH_ATTR esp_ssl_set_fd(SSL *s, int fd) +{ + s->client_fd = fd; + return 1; /* always succeeds */ +} + +/* + * Do the handshaking from the beginning. + */ +int ICACHE_FLASH_ATTR do_server_accept(SSL *ssl) +{ + int ret = SSL_OK; + + ssl->bm_read_index = 0; + ssl->next_state = HS_CLIENT_HELLO; + ssl->hs_status = SSL_NOT_OK; /* not connected */ + + /* sit in a loop until it all looks good */ + if (!IS_SET_SSL_FLAG(SSL_CONNECT_IN_PARTS)) + { + while (ssl->hs_status != SSL_OK) + { + ret = ssl_read(ssl, NULL); + + if (ret < SSL_OK) + break; + } + + ssl->hs_status = ret; /* connected? */ + } + + return ret; +} + + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +int ICACHE_FLASH_ATTR esp_ssl_accept(SSL *ssl) +{ + return do_server_accept(ssl) == SSL_OK ? 1 : -1; +} + +#ifdef CONFIG_SSL_ENABLE_CLIENT +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +int ICACHE_FLASH_ATTR esp_ssl_connect(SSL *ssl) +{ + ssl->version = SSL_PROTOCOL_VERSION_MAX; + SET_SSL_FLAG(SSL_IS_CLIENT); + return do_client_connect(ssl) == SSL_OK ? 1 : -1; +} +#endif + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR esp_ssl_free(SSL *ssl) +{ + ssl_free(ssl); +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +int ICACHE_FLASH_ATTR esp_ssl_read(SSL *ssl, void *buf, int num) +{ + uint8_t *read_buf = NULL; + int ret; + static uint8_t *in_offt = NULL; + static int in_msg_len = 0; + + if (in_offt == NULL){ + while ((ret = ssl_read(ssl, &read_buf)) == SSL_OK); + + if (ret > SSL_OK){ + in_offt = read_buf; + in_msg_len = ret; + } + } + ret = (num < in_msg_len) ? num : in_msg_len; + memcpy(buf, in_offt, ret); + in_msg_len -= ret; + if (in_msg_len == 0) + in_offt = NULL; + else + in_offt += ret; + return ret; +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +int ICACHE_FLASH_ATTR esp_ssl_write(SSL *ssl, const void *buf, int num) +{ + return ssl_write(ssl, buf, num); +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +int ICACHE_FLASH_ATTR esp_ssl_CTX_use_certificate_file(SSL_CTX *ssl_ctx, const char *file, int type) +{ + return (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, file, NULL) == SSL_OK); +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +int ICACHE_FLASH_ATTR esp_ssl_CTX_use_certificate_auth_file(SSL_CTX *ssl_ctx, const char *file, int type) +{ + return (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CACERT, file, NULL) == SSL_OK); +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +int ICACHE_FLASH_ATTR esp_ssl_CTX_use_PrivateKey_file(SSL_CTX *ssl_ctx, const char *file, int type) +{ + return (ssl_obj_load(ssl_ctx, SSL_OBJ_RSA_KEY, file, key_password) == SSL_OK); +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +int ICACHE_FLASH_ATTR SSL_CTX_use_certificate_ASN1(SSL_CTX *ssl_ctx, int len, const uint8_t *d) +{ + return (ssl_obj_memory_load(ssl_ctx, + SSL_OBJ_X509_CERT, d, len, NULL) == SSL_OK); +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +int ICACHE_FLASH_ATTR SSL_CTX_set_session_id_context(SSL_CTX *ctx, const unsigned char *sid_ctx, + unsigned int sid_ctx_len) +{ + return 1; +} + +//int ICACHE_FLASH_ATTR esp_ssl_CTX_set_verify_depth(SSL_CTX *ctx) +//{ +// return 1; +//} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +int ICACHE_FLASH_ATTR esp_ssl_CTX_use_certificate_chain_file(SSL_CTX *ssl_ctx, const char *file) +{ + return (ssl_obj_load(ssl_ctx,SSL_OBJ_X509_CERT, file, NULL) == SSL_OK); +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +int ICACHE_FLASH_ATTR SSL_shutdown(SSL *ssl) +{ + return 1; +} + +/*** get/set session ***/ +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +SSL_SESSION *ICACHE_FLASH_ATTR SSL_get1_session(SSL *ssl) +{ + return (SSL_SESSION *)ssl_get_session_id(ssl); /* note: wrong cast */ +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +int ICACHE_FLASH_ATTR SSL_set_session(SSL *ssl, SSL_SESSION *session) +{ + memcpy(ssl->session_id, (uint8_t *)session, SSL_SESSION_ID_SIZE); + return 1; +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR SSL_SESSION_free(SSL_SESSION *session) { } +/*** end get/set session ***/ + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +long ICACHE_FLASH_ATTR SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) +{ + return 0; +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR esp_ssl_CTX_set_verify(SSL_CTX *ctx, int mode, + int (*verify_callback)(int, void *)) { } + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR esp_ssl_CTX_set_verify_depth(SSL_CTX *ctx, int depth) { } + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +int ICACHE_FLASH_ATTR esp_ssl_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, + const char *CApath) +{ + return 1; +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void *ICACHE_FLASH_ATTR SSL_load_client_CA_file(const char *file) +{ + return (void *)file; +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR SSL_CTX_set_client_CA_list(SSL_CTX *ssl_ctx, void *file) +{ + ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, (const char *)file, NULL); +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR SSLv23_method(void) { } + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, void *cb) { } + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u) +{ + key_password = (char *)u; +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +int ICACHE_FLASH_ATTR SSL_peek(SSL *ssl, void *buf, int num) +{ + memcpy(buf, ssl->bm_data, num); + return num; +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR SSL_set_bio(SSL *ssl, void *rbio, void *wbio) { } + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +long ICACHE_FLASH_ATTR esp_ssl_get_verify_result(const SSL *ssl) +{ + return ssl_handshake_status(ssl); +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +int ICACHE_FLASH_ATTR SSL_state(SSL *ssl) +{ + return 0x03; // ok state +} + +/** end of could do better list */ +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void *ICACHE_FLASH_ATTR esp_ssl_get_peer_certificate(const SSL *ssl) +{ + return &ssl->ssl_ctx->certs[0]; +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +int ICACHE_FLASH_ATTR SSL_clear(SSL *ssl) +{ + return 1; +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +int ICACHE_FLASH_ATTR esp_ssl_CTX_check_private_key(const SSL_CTX *ctx) +{ + return 1; +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +int ICACHE_FLASH_ATTR SSL_CTX_set_cipher_list(SSL *s, const char *str) +{ + return 1; +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +int ICACHE_FLASH_ATTR esp_ssl_get_error(const SSL *ssl, int ret) +{ +// ssl_display_error(ret); + return 0; /* TODO: return proper return code */ +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR SSL_CTX_set_options(SSL_CTX *ssl_ctx, int option) {} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +int ICACHE_FLASH_ATTR esp_ssl_library_init(void ) { return 1; } + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR SSL_load_error_strings(void ) {} +//void ICACHE_FLASH_ATTR ERR_print_errors_fp(FILE *fp) {} +// +//#ifndef CONFIG_SSL_SKELETON_MODE +//long ICACHE_FLASH_ATTR SSL_CTX_get_timeout(const SSL_CTX *ssl_ctx) { +// return CONFIG_SSL_EXPIRY_TIME*3600; } +//long ICACHE_FLASH_ATTR SSL_CTX_set_timeout(SSL_CTX *ssl_ctx, long t) { +// return SSL_CTX_get_timeout(ssl_ctx); } +//#endif +//void ICACHE_FLASH_ATTR BIO_printf(FILE *f, const char *format, ...) +//{ +// va_list(ap); +// va_start(ap, format); +// vfprintf(f, format, ap); +// va_end(ap); +//} +// +//void* ICACHE_FLASH_ATTR BIO_s_null(void) { return NULL; } +//FILE *ICACHE_FLASH_ATTR BIO_new(bio_func_type_t func) +//{ +// if (func == BIO_s_null) +// return fopen("/dev/null", "r"); +// else +// return NULL; +//} +// +//FILE *ICACHE_FLASH_ATTR BIO_new_fp(FILE *stream, int close_flag) { return stream; } +//int ICACHE_FLASH_ATTR BIO_free(FILE *a) { if (a != stdout && a != stderr) fclose(a); return 1; } +// + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +int ICACHE_FLASH_ATTR esp_ssl_CTX_set_default_verify_paths(SSL_CTX *ssl_ctx) +{ + return 1; +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +X509_CTX * ICACHE_FLASH_ATTR esp_X509_store_ctx_get_current_cert(X509_CTX * store) +{ + return NULL; +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR esp_X509_free(X509_CTX * x509_CTX) +{ +// x509_free(x509_CTX); +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR esp_X509_NAME_oneline(X509_CTX * x509_CTX) +{ + x509_free(x509_CTX); +} + + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +char* ICACHE_FLASH_ATTR esp_X509_get_issuer_name(X509_CTX * x509_CTX) +{ + return NULL; +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +char* ICACHE_FLASH_ATTR esp_X509_get_subject_name(X509_CTX * x509_CTX) +{ + return NULL; +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR esp_X509_STORE_CTX_get_error_depth(X509_CTX * x509_CTX) +{ +// x509_free(x509_CTX); +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +char* ICACHE_FLASH_ATTR esp_X509_STORE_CTX_get_error(X509_CTX * x509_CTX) +{ + return NULL; +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +char* ICACHE_FLASH_ATTR esp_X509_verify_cert_error_string(X509_CTX * x509_CTX) +{ + return NULL; +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +int ICACHE_FLASH_ATTR esp_ERR_get_error(void) +{ + return 0; +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR esp_ERR_error_string_n(uint32 error, char* out, uint32 olen) +{ + return; +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR esp_ERR_error_string(uint32 error, char* out) +{ + return; +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR esp_ERR_free_strings(void) +{ + +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR esp_CRYPTO_cleanup_all_ex_data(void) +{ + +} + +/****************************************************************************** + * FunctionName : esp_ssl_set_fd + * Description : sent data for client or server + * Parameters : s -- espconn to set for client or server + * fd -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +const char* ICACHE_FLASH_ATTR esp_ERR_strerror(uint32 error) +{ + return lwip_strerr(error); +} + +void ICACHE_FLASH_ATTR esp_ssl_sleep(uint16 mseconds) +{ + vTaskDelay(mseconds / portTICK_RATE_MS); +} + +esp_ssl_CTX_set_client_cert_cb(){} + +esp_ssl_CTX_set_mode(){} + +esp_ssl_pending() +{ + +} + +bool ICACHE_FLASH_ATTR esp_ssl_fragment_length_negotiation(SSL* ssl, int fragmet_level) +{ + return ssl_fragment_length_negotiation(ssl, fragmet_level); +} diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_tls1.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_tls1.c new file mode 100644 index 0000000..e919168 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_tls1.c @@ -0,0 +1,2316 @@ +/* + * 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. + */ + +/** + * Common ssl/tlsv1 code to both the client and server implementations. + */ + +#include "ssl/ssl_os_port.h" +#include "ssl/ssl_ssl.h" + +#include "lwip/sockets.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +/* The session expiry time */ +#define SSL_EXPIRY_TIME (CONFIG_SSL_EXPIRY_TIME*3600) + +static const uint8_t g_hello_request[] ICACHE_RODATA_ATTR STORE_ATTR = { HS_HELLO_REQUEST, 0, 0, 0 }; +static const uint8_t g_chg_cipher_spec_pkt[] ICACHE_RODATA_ATTR STORE_ATTR = { 1 }; +static const char server_finished[] ICACHE_RODATA_ATTR STORE_ATTR = "server finished"; +static const char client_finished[] ICACHE_RODATA_ATTR STORE_ATTR = "client finished"; + +static int do_handshake(SSL *ssl, uint8_t *buf, int read_len); +static int set_key_block(SSL *ssl, int is_write); +static int verify_digest(SSL *ssl, int mode, const uint8_t *buf, int read_len); +static void *crypt_new(SSL *ssl, uint8_t *key, uint8_t *iv, int is_decrypt); +static int send_raw_packet(SSL *ssl, uint8_t protocol); + +/** + * The server will pick the cipher based on the order that the order that the + * ciphers are listed. This order is defined at compile time. + */ +#ifdef CONFIG_SSL_SKELETON_MODE +const uint8_t ssl_prot_prefs[NUM_PROTOCOLS] = +{ SSL_RC4_128_SHA }; +#else +static void session_free(SSL_SESSION *ssl_sessions[], int sess_index); + +const uint8_t ssl_prot_prefs[NUM_PROTOCOLS] ICACHE_RODATA_ATTR STORE_ATTR = +#ifdef CONFIG_SSL_PROT_LOW /* low security, fast speed */ +{ SSL_RC4_128_SHA, SSL_AES128_SHA, SSL_AES256_SHA, SSL_RC4_128_MD5 }; +#elif CONFIG_SSL_PROT_MEDIUM /* medium security, medium speed */ +{ SSL_AES128_SHA, SSL_AES256_SHA, SSL_RC4_128_SHA, SSL_RC4_128_MD5 }; +#else /* CONFIG_SSL_PROT_HIGH */ /* high security, low speed */ +{ SSL_AES256_SHA, SSL_AES128_SHA, SSL_RC4_128_SHA, SSL_RC4_128_MD5 }; +#endif +#endif /* CONFIG_SSL_SKELETON_MODE */ + +/** + * The cipher map containing all the essentials for each cipher. + */ +#ifdef CONFIG_SSL_SKELETON_MODE +static const cipher_info_t cipher_info[NUM_PROTOCOLS] = +{ + { /* RC4-SHA */ + SSL_RC4_128_SHA, /* RC4-SHA */ + 16, /* key size */ + 0, /* iv size */ + 2*(SHA1_SIZE+16), /* key block size */ + 0, /* no padding */ + SHA1_SIZE, /* digest size */ + ssl_hmac_sha1, /* hmac algorithm */ + (crypt_func)RC4_crypt, /* encrypt */ + (crypt_func)RC4_crypt /* decrypt */ + }, +}; +#else +static const cipher_info_t cipher_info[NUM_PROTOCOLS] = +{ + { /* AES128-SHA */ + SSL_AES128_SHA, /* AES128-SHA */ + 16, /* key size */ + 16, /* iv size */ + 2*(SHA1_SIZE+16+16), /* key block size */ + 16, /* block padding size */ + SHA1_SIZE, /* digest size */ + ssl_hmac_sha1, /* hmac algorithm */ + (crypt_func)AES_cbc_encrypt, /* encrypt */ + (crypt_func)AES_cbc_decrypt /* decrypt */ + }, + { /* AES256-SHA */ + SSL_AES256_SHA, /* AES256-SHA */ + 32, /* key size */ + 16, /* iv size */ + 2*(SHA1_SIZE+32+16), /* key block size */ + 16, /* block padding size */ + SHA1_SIZE, /* digest size */ + ssl_hmac_sha1, /* hmac algorithm */ + (crypt_func)AES_cbc_encrypt, /* encrypt */ + (crypt_func)AES_cbc_decrypt /* decrypt */ + }, + { /* RC4-SHA */ + SSL_RC4_128_SHA, /* RC4-SHA */ + 16, /* key size */ + 0, /* iv size */ + 2*(SHA1_SIZE+16), /* key block size */ + 0, /* no padding */ + SHA1_SIZE, /* digest size */ + ssl_hmac_sha1, /* hmac algorithm */ + (crypt_func)RC4_crypt, /* encrypt */ + (crypt_func)RC4_crypt /* decrypt */ + }, + /* + * This protocol is from SSLv2 days and is unlikely to be used - but was + * useful for testing different possible digest algorithms. + */ + { /* RC4-MD5 */ + SSL_RC4_128_MD5, /* RC4-MD5 */ + 16, /* key size */ + 0, /* iv size */ + 2*(MD5_SIZE+16), /* key block size */ + 0, /* no padding */ + MD5_SIZE, /* digest size */ + ssl_hmac_md5, /* hmac algorithm */ + (crypt_func)RC4_crypt, /* encrypt */ + (crypt_func)RC4_crypt /* decrypt */ + }, +}; +#endif + +static void prf(const uint8_t *sec, int sec_len, uint8_t *seed, int seed_len, + uint8_t *out, int olen); +static const cipher_info_t *get_cipher_info(uint8_t cipher); +static void increment_read_sequence(SSL *ssl); +static void increment_write_sequence(SSL *ssl); +static void add_hmac_digest(SSL *ssl, int snd, uint8_t *hmac_header, + const uint8_t *buf, int buf_len, uint8_t *hmac_buf); + +/* win32 VC6.0 doesn't have variadic macros */ +#if defined(WIN32) && !defined(CONFIG_SSL_FULL_MODE) +void DISPLAY_BYTES(SSL *ssl, const char *format, + const uint8_t *data, int size, ...) {} +#endif + +/** + * Establish a new client/server context. + */ +EXP_FUNC SSL_CTX *STDCALL ICACHE_FLASH_ATTR ssl_ctx_new(uint32_t options, int num_sessions) +{ + SSL_CTX *ssl_ctx = (SSL_CTX *)SSL_ZALLOC(sizeof(SSL_CTX)); + ssl_ctx->options = options; + RNG_initialize(); + + if (load_key_certs(ssl_ctx) < 0) + { + SSL_FREE(ssl_ctx); /* can't load our key/certificate pair, so die */ + return NULL; + } + +#ifndef CONFIG_SSL_SKELETON_MODE + ssl_ctx->num_sessions = num_sessions; +#endif + + SSL_CTX_MUTEX_INIT(ssl_ctx->mutex); + +#ifndef CONFIG_SSL_SKELETON_MODE + if (num_sessions) + { + ssl_ctx->ssl_sessions = (SSL_SESSION **) + SSL_ZALLOC(num_sessions*sizeof(SSL_SESSION *)); + } +#endif + + return ssl_ctx; +} + +/* + * Remove a client/server context. + */ +EXP_FUNC void STDCALL ICACHE_FLASH_ATTR ssl_ctx_free(SSL_CTX *ssl_ctx) +{ + SSL *ssl; + int i; + + if (ssl_ctx == NULL) + return; + + ssl = ssl_ctx->head; + + /* clear out all the ssl entries */ + while (ssl) + { + SSL *next = ssl->next; + ssl_free(ssl); + ssl = next; + } + +#ifndef CONFIG_SSL_SKELETON_MODE + /* clear out all the sessions */ + for (i = 0; i < ssl_ctx->num_sessions; i++) + session_free(ssl_ctx->ssl_sessions, i); + + SSL_FREE(ssl_ctx->ssl_sessions); +#endif + + i = 0; + while (i < CONFIG_SSL_MAX_CERTS && ssl_ctx->certs[i].buf) + { + SSL_FREE(ssl_ctx->certs[i].buf); + ssl_ctx->certs[i++].buf = NULL; + } + +#ifdef CONFIG_SSL_CERT_VERIFICATION + remove_ca_certs(ssl_ctx->ca_cert_ctx); +#endif + ssl_ctx->chain_length = 0; + SSL_CTX_MUTEX_DESTROY(ssl_ctx->mutex); +// ssl_printf("%s %p\n", __func__,ssl_ctx->rsa_ctx); + RSA_free(ssl_ctx->rsa_ctx); + RNG_terminate(); +// ssl_printf("%s %p\n", __func__,ssl_ctx); + SSL_FREE(ssl_ctx); +} + +/* + * Free any used resources used by this connection. + */ +EXP_FUNC void STDCALL ICACHE_FLASH_ATTR ssl_free(SSL *ssl) +{ + SSL_CTX *ssl_ctx; + os_printf("ssl_free:Aviable Memory|%d\n",system_get_free_heap_size()); + if (ssl == NULL) /* just ignore null pointers */ + return; + + /* only notify if we weren't notified first */ + /* spec says we must notify when we are dying */ + if (!IS_SET_SSL_FLAG(SSL_SENT_CLOSE_NOTIFY)){ + send_alert(ssl, SSL_ALERT_CLOSE_NOTIFY); + kill_ssl_session(ssl->ssl_ctx->ssl_sessions, ssl); + } +// ssl_printf("%s %d\n", __func__, __LINE__); + + ssl_ctx = ssl->ssl_ctx; + + SSL_CTX_LOCK(ssl_ctx->mutex); + + /* adjust the server SSL list */ + if (ssl->prev) + ssl->prev->next = ssl->next; + else + ssl_ctx->head = ssl->next; + + if (ssl->next) + ssl->next->prev = ssl->prev; + else + ssl_ctx->tail = ssl->prev; + + SSL_CTX_UNLOCK(ssl_ctx->mutex); + + /* may already be free - but be sure */ + SSL_FREE(ssl->encrypt_ctx); + SSL_FREE(ssl->decrypt_ctx); + disposable_free(ssl); +#ifdef CONFIG_SSL_CERT_VERIFICATION + x509_free(ssl->x509_ctx); +#endif + + SSL_FREE(ssl->bm_all_data); + SSL_FREE(ssl); +} + +/* + * Read the SSL connection and send any alerts for various errors. + */ +EXP_FUNC int STDCALL ICACHE_FLASH_ATTR ssl_read(SSL *ssl, uint8_t **in_data) +{ + int ret = basic_read(ssl, in_data); + + /* check for return code so we can send an alert */ + if (ret < SSL_OK && ret != SSL_CLOSE_NOTIFY) + { + if (ret != SSL_ERROR_CONN_LOST) + { + send_alert(ssl, ret); +#ifndef CONFIG_SSL_SKELETON_MODE + /* something nasty happened, so get rid of this session */ + kill_ssl_session(ssl->ssl_ctx->ssl_sessions, ssl); +#endif + } + } + + return ret; +} + +/* + * Write application data to the client + */ +EXP_FUNC int STDCALL ICACHE_FLASH_ATTR ssl_write(SSL *ssl, const uint8_t *out_data, int out_len) +{ + int n = out_len, nw, i, tot = 0; + + /* maximum size of a TLS packet is around 16kB, so fragment */ + do + { + nw = n; + + if (nw > ssl->max_fragme_length) /* fragment if necessary */ + nw = ssl->max_fragme_length; + + if ((i = send_packet(ssl, PT_APP_PROTOCOL_DATA, + &out_data[tot], nw)) <= 0) + { + out_len = i; /* an error */ + break; + } + + tot += i; + n -= i; + } while (n > 0); + + return out_len; +} + +/** + * Add a certificate to the certificate chain. + */ +int ICACHE_FLASH_ATTR add_cert(SSL_CTX *ssl_ctx, const uint8_t *buf, int len) +{ + int ret = SSL_ERROR_NO_CERT_DEFINED, i = 0; + SSL_CERT *ssl_cert; + X509_CTX *cert = NULL; + int offset; + + while (i < CONFIG_SSL_MAX_CERTS && ssl_ctx->certs[i].buf) + i++; + + if (i == CONFIG_SSL_MAX_CERTS) /* too many certs */ + { +#ifdef CONFIG_SSL_FULL_MODE + ssl_printf("Error: maximum number of certs added (%d) - change of " + "compile-time configuration required\n", + CONFIG_SSL_MAX_CERTS); +#endif + goto error; + } + + if ((ret = x509_new(buf, &offset, &cert))) + goto error; + +#if defined (CONFIG_SSL_FULL_MODE) + if (ssl_ctx->options & SSL_DISPLAY_CERTS) + x509_print(cert, NULL); +#endif + + ssl_cert = &ssl_ctx->certs[i]; + ssl_cert->size = len; + ssl_cert->buf = (uint8_t *)SSL_MALLOC(len); + memcpy(ssl_cert->buf, buf, len); + ssl_ctx->chain_length++; + len -= offset; + ret = SSL_OK; /* ok so far */ + + /* recurse? */ + if (len > 0) + { + ret = add_cert(ssl_ctx, &buf[offset], len); + } + +error: + x509_free(cert); /* don't need anymore */ + return ret; +} + +#ifdef CONFIG_SSL_CERT_VERIFICATION +/** + * Add a certificate authority. + */ +int ICACHE_FLASH_ATTR add_cert_auth(SSL_CTX *ssl_ctx, const uint8_t *buf, int len) +{ + int ret = X509_OK; /* ignore errors for now */ + int i = 0; + CA_CERT_CTX *ca_cert_ctx; + + if (ssl_ctx->ca_cert_ctx == NULL) + ssl_ctx->ca_cert_ctx = (CA_CERT_CTX *)SSL_ZALLOC(sizeof(CA_CERT_CTX)); + + ca_cert_ctx = ssl_ctx->ca_cert_ctx; + + while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i]) + i++; + + while (len > 0) + { + int offset; + if (i >= CONFIG_X509_MAX_CA_CERTS) + { +#ifdef CONFIG_SSL_FULL_MODE + ssl_printf("Error: maximum number of CA certs added (%d) - change of " + "compile-time configuration required\n", + CONFIG_X509_MAX_CA_CERTS); +#endif + ret = X509_MAX_CERTS; + break; + } + + /* ignore the return code */ + if (x509_new(buf, &offset, &ca_cert_ctx->cert[i]) == X509_OK) + { +#if defined (CONFIG_SSL_FULL_MODE) + if (ssl_ctx->options & SSL_DISPLAY_CERTS) + x509_print(ca_cert_ctx->cert[i], NULL); +#endif + } + + i++; + len -= offset; + } + + return ret; +} + +/* + * Retrieve an X.509 distinguished name component + */ +EXP_FUNC const char * STDCALL ICACHE_FLASH_ATTR ssl_get_cert_dn(const SSL *ssl, int component) +{ + if (ssl->x509_ctx == NULL) + return NULL; + + switch (component) + { + case SSL_X509_CERT_COMMON_NAME: + return ssl->x509_ctx->cert_dn[X509_COMMON_NAME]; + + case SSL_X509_CERT_ORGANIZATION: + return ssl->x509_ctx->cert_dn[X509_ORGANIZATION]; + + case SSL_X509_CERT_ORGANIZATIONAL_NAME: + return ssl->x509_ctx->cert_dn[X509_ORGANIZATIONAL_UNIT]; + + case SSL_X509_CA_CERT_COMMON_NAME: + return ssl->x509_ctx->ca_cert_dn[X509_COMMON_NAME]; + + case SSL_X509_CA_CERT_ORGANIZATION: + return ssl->x509_ctx->ca_cert_dn[X509_ORGANIZATION]; + + case SSL_X509_CA_CERT_ORGANIZATIONAL_NAME: + return ssl->x509_ctx->ca_cert_dn[X509_ORGANIZATIONAL_UNIT]; + + default: + return NULL; + } +} + +/* + * Retrieve a "Subject Alternative Name" from a v3 certificate + */ +EXP_FUNC const char * STDCALL ICACHE_FLASH_ATTR ssl_get_cert_subject_alt_dnsname(const SSL *ssl, + int dnsindex) +{ + int i; + + if (ssl->x509_ctx == NULL || ssl->x509_ctx->subject_alt_dnsnames == NULL) + return NULL; + + for (i = 0; i < dnsindex; ++i) + { + if (ssl->x509_ctx->subject_alt_dnsnames[i] == NULL) + return NULL; + } + + return ssl->x509_ctx->subject_alt_dnsnames[dnsindex]; +} + +#endif /* CONFIG_SSL_CERT_VERIFICATION */ +#if 0 +/* + * Find an ssl object based on the client's file descriptor. + */ +EXP_FUNC SSL * STDCALL ICACHE_FLASH_ATTR ssl_find(SSL_CTX *ssl_ctx, int client_fd) +{ + SSL *ssl; + + SSL_CTX_LOCK(ssl_ctx->mutex); + ssl = ssl_ctx->head; + + /* search through all the ssl entries */ + while (ssl) + { + if (ssl->client_fd == client_fd) + { + SSL_CTX_UNLOCK(ssl_ctx->mutex); + return ssl; + } + + ssl = ssl->next; + } + + SSL_CTX_UNLOCK(ssl_ctx->mutex); + return NULL; +} +#endif +/* + * Force the client to perform its handshake again. + */ +EXP_FUNC int STDCALL ICACHE_FLASH_ATTR ssl_renegotiate(SSL *ssl) +{ + int ret = SSL_OK; + + disposable_new(ssl); +#ifdef CONFIG_SSL_ENABLE_CLIENT + if (IS_SET_SSL_FLAG(SSL_IS_CLIENT)) + { + ret = do_client_connect(ssl); + } + else +#endif + { + uint8 g_hello_request_ram[4]; + memcpy(g_hello_request_ram, g_hello_request, sizeof(g_hello_request)); + + send_packet(ssl, PT_HANDSHAKE_PROTOCOL, + g_hello_request_ram, sizeof(g_hello_request_ram)); + SET_SSL_FLAG(SSL_NEED_RECORD); + } + + return ret; +} + +/** + * @brief Get what we need for key info. + * @param cipher [in] The cipher information we are after + * @param key_size [out] The key size for the cipher + * @param iv_size [out] The iv size for the cipher + * @return The amount of key information we need. + */ +static const cipher_info_t *ICACHE_FLASH_ATTR get_cipher_info(uint8_t cipher) +{ + int i; + + for (i = 0; i < NUM_PROTOCOLS; i++) + { + if (cipher_info[i].cipher == cipher) + { + return &cipher_info[i]; + } + } + + return NULL; /* error */ +} + +/* + * Get a new ssl context for a new connection. + */ +SSL *ICACHE_FLASH_ATTR ssl_new(SSL_CTX *ssl_ctx, int client_fd) +{ + SSL *ssl = (SSL *)SSL_ZALLOC(sizeof(SSL)); + ssl_fragment_length_negotiation(ssl, SSL_MAX_FRAG_LEN_2048); + ssl->ssl_ctx = ssl_ctx; + ssl->need_bytes = SSL_RECORD_SIZE; /* need a record */ + ssl->client_fd = client_fd; + ssl->flag = SSL_NEED_RECORD; + ssl->bm_data = ssl->bm_all_data+BM_RECORD_OFFSET; /* space at the start */ + ssl->hs_status = SSL_NOT_OK; /* not connected */ +#ifdef CONFIG_ENABLE_VERIFICATION + ssl->ca_cert_ctx = ssl_ctx->ca_cert_ctx; +#endif + disposable_new(ssl); + + /* a bit hacky but saves a few bytes of memory */ + ssl->flag |= ssl_ctx->options; + SSL_CTX_LOCK(ssl_ctx->mutex); + + if (ssl_ctx->head == NULL) + { + ssl_ctx->head = ssl; + ssl_ctx->tail = ssl; + } + else + { + ssl->prev = ssl_ctx->tail; + ssl_ctx->tail->next = ssl; + ssl_ctx->tail = ssl; + } + + SSL_CTX_UNLOCK(ssl_ctx->mutex); + return ssl; +} + +/* + * Add a private key to a context. + */ +int ICACHE_FLASH_ATTR add_private_key(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj) +{ + int ret = SSL_OK; + + /* get the private key details */ + if (asn1_get_private_key(ssl_obj->buf, ssl_obj->len, &ssl_ctx->rsa_ctx)) + { + ret = SSL_ERROR_INVALID_KEY; + goto error; + } + +error: + return ret; +} + +/** + * Increment the read sequence number (as a 64 bit endian indepenent #) + */ +static void ICACHE_FLASH_ATTR increment_read_sequence(SSL *ssl) +{ + int i; + + for (i = 7; i >= 0; i--) + { + if (++ssl->read_sequence[i]) + break; + } +} + +/** + * Increment the read sequence number (as a 64 bit endian indepenent #) + */ +static void ICACHE_FLASH_ATTR increment_write_sequence(SSL *ssl) +{ + int i; + + for (i = 7; i >= 0; i--) + { + if (++ssl->write_sequence[i]) + break; + } +} + +/** + * Work out the HMAC digest in a packet. + */ +static void ICACHE_FLASH_ATTR add_hmac_digest(SSL *ssl, int mode, uint8_t *hmac_header, + const uint8_t *buf, int buf_len, uint8_t *hmac_buf) +{ + int hmac_len = buf_len + 8 + SSL_RECORD_SIZE; + uint8_t *t_buf = (uint8_t *)SSL_ZALLOC(hmac_len+10); + + memcpy(t_buf, (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_WRITE) ? + ssl->write_sequence : ssl->read_sequence, 8); + memcpy(&t_buf[8], hmac_header, SSL_RECORD_SIZE); + memcpy(&t_buf[8+SSL_RECORD_SIZE], buf, buf_len); + + ssl->cipher_info->hmac(t_buf, hmac_len, + (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_READ) ? + ssl->server_mac : ssl->client_mac, + ssl->cipher_info->digest_size, hmac_buf); + + /* add by wujg */ + SSL_FREE(t_buf); + +#if 0 + print_blob("record", hmac_header, SSL_RECORD_SIZE); + print_blob("buf", buf, buf_len); + if (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_WRITE) + { + print_blob("write seq", ssl->write_sequence, 8); + } + else + { + print_blob("read seq", ssl->read_sequence, 8); + } + + if (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_READ) + { + print_blob("server mac", + ssl->server_mac, ssl->cipher_info->digest_size); + } + else + { + print_blob("client mac", + ssl->client_mac, ssl->cipher_info->digest_size); + } + print_blob("hmac", hmac_buf, SHA1_SIZE); +#endif +} + +/** + * Verify that the digest of a packet is correct. + */ +static int ICACHE_FLASH_ATTR verify_digest(SSL *ssl, int mode, const uint8_t *buf, int read_len) +{ + uint8_t hmac_buf[SHA1_SIZE]; + int hmac_offset; + + if (ssl->cipher_info->padding_size) + { + int last_blk_size = buf[read_len-1], i; + hmac_offset = read_len-last_blk_size-ssl->cipher_info->digest_size-1; + + /* guard against a timing attack - make sure we do the digest */ + if (hmac_offset < 0) + { + hmac_offset = 0; + } + else + { + /* already looked at last byte */ + for (i = 1; i < last_blk_size; i++) + { + if (buf[read_len-i] != last_blk_size) + { + hmac_offset = 0; + break; + } + } + } + } + else /* stream cipher */ + { + hmac_offset = read_len - ssl->cipher_info->digest_size; + + if (hmac_offset < 0) + { + hmac_offset = 0; + } + } + + /* sanity check the offset */ + ssl->hmac_header[3] = hmac_offset >> 8; /* insert size */ + ssl->hmac_header[4] = hmac_offset & 0xff; + add_hmac_digest(ssl, mode, ssl->hmac_header, buf, hmac_offset, hmac_buf); + + if (memcmp(hmac_buf, &buf[hmac_offset], ssl->cipher_info->digest_size)) + { + return SSL_ERROR_INVALID_HMAC; + } + + return hmac_offset; +} + +/** + * Add a packet to the end of our sent and received packets, so that we may use + * it to calculate the hash at the end. + */ +void ICACHE_FLASH_ATTR add_packet(SSL *ssl, const uint8_t *pkt, int len) +{ + MD5_Update(&ssl->dc->md5_ctx, pkt, len); + SHA1_Update(&ssl->dc->sha1_ctx, pkt, len); +} + +/** + * Work out the MD5 PRF. + */ +static void ICACHE_FLASH_ATTR p_hash_md5(const uint8_t *sec, int sec_len, + uint8_t *seed, int seed_len, uint8_t *out, int olen) +{ + uint8_t* a1 = (uint8_t *)SSL_ZALLOC(128); + + /* A(1) */ + ssl_hmac_md5(seed, seed_len, sec, sec_len, a1); + memcpy(&a1[MD5_SIZE], seed, seed_len); + ssl_hmac_md5(a1, MD5_SIZE+seed_len, sec, sec_len, out); + + while (olen > MD5_SIZE) + { + uint8_t a2[MD5_SIZE]; + out += MD5_SIZE; + olen -= MD5_SIZE; + + /* A(N) */ + ssl_hmac_md5(a1, MD5_SIZE, sec, sec_len, a2); + memcpy(a1, a2, MD5_SIZE); + + /* work out the actual hash */ + ssl_hmac_md5(a1, MD5_SIZE+seed_len, sec, sec_len, out); + } + SSL_FREE (a1); +} + +/** + * Work out the SHA1 PRF. + */ +static void ICACHE_FLASH_ATTR p_hash_sha1(const uint8_t *sec, int sec_len, + uint8_t *seed, int seed_len, uint8_t *out, int olen) +{ + uint8_t* a1 = (uint8_t *)SSL_ZALLOC(128); + + /* A(1) */ + ssl_hmac_sha1(seed, seed_len, sec, sec_len, a1); + memcpy(&a1[SHA1_SIZE], seed, seed_len); + ssl_hmac_sha1(a1, SHA1_SIZE+seed_len, sec, sec_len, out); + + while (olen > SHA1_SIZE) + { + uint8_t a2[SHA1_SIZE]; + out += SHA1_SIZE; + olen -= SHA1_SIZE; + + /* A(N) */ + ssl_hmac_sha1(a1, SHA1_SIZE, sec, sec_len, a2); + memcpy(a1, a2, SHA1_SIZE); + + /* work out the actual hash */ + ssl_hmac_sha1(a1, SHA1_SIZE+seed_len, sec, sec_len, out); + } + SSL_FREE(a1); +} + +/** + * Work out the PRF. + */ +static void ICACHE_FLASH_ATTR prf(const uint8_t *sec, int sec_len, uint8_t *seed, int seed_len, + uint8_t *out, int olen) +{ + int len, i; + const uint8_t *S1, *S2; + uint8_t *xbuf = (uint8_t *)SSL_ZALLOC(256); /* needs to be > the amount of key data */ + uint8_t *ybuf = (uint8_t *)SSL_ZALLOC(256); /* needs to be > the amount of key data */ + + len = sec_len/2; + S1 = sec; + S2 = &sec[len]; + len += (sec_len & 1); /* add for odd, make longer */ + + p_hash_md5(S1, len, seed, seed_len, xbuf, olen); + p_hash_sha1(S2, len, seed, seed_len, ybuf, olen); + + for (i = 0; i < olen; i++) + out[i] = xbuf[i] ^ ybuf[i]; + SSL_FREE(xbuf); + SSL_FREE(ybuf); +} + +/** + * Generate a master secret based on the client/server random data and the + * premaster secret. + */ +void ICACHE_FLASH_ATTR generate_master_secret(SSL *ssl, const uint8_t *premaster_secret) +{ + // uint8_t buf[128]; /* needs to be > 13+32+32 in size */ + uint8_t* buf = (uint8_t *)SSL_ZALLOC(128); + + strcpy((char *)buf, "master secret"); + memcpy(&buf[13], ssl->dc->client_random, SSL_RANDOM_SIZE); + memcpy(&buf[45], ssl->dc->server_random, SSL_RANDOM_SIZE); + prf(premaster_secret, SSL_SECRET_SIZE, buf, 77, ssl->dc->master_secret, + SSL_SECRET_SIZE); + SSL_FREE(buf); +} + +/** + * Generate a 'random' blob of data used for the generation of keys. + */ +static void ICACHE_FLASH_ATTR generate_key_block(uint8_t *client_random, uint8_t *server_random, + uint8_t *master_secret, uint8_t *key_block, int key_block_size) +{ + uint8_t* buf = (uint8_t *)SSL_ZALLOC(128); + + strcpy((char *)buf, "key expansion"); + memcpy(&buf[13], server_random, SSL_RANDOM_SIZE); + memcpy(&buf[45], client_random, SSL_RANDOM_SIZE); + prf(master_secret, SSL_SECRET_SIZE, buf, 77, key_block, key_block_size); + SSL_FREE(buf); +} + +/** + * Calculate the digest used in the finished message. This function also + * doubles up as a certificate verify function. + */ +void ICACHE_FLASH_ATTR finished_digest(SSL *ssl, const char *label, uint8_t *digest) +{ + uint8_t* mac_buf = (uint8_t *)SSL_ZALLOC(128); + + uint8_t *q = mac_buf; + MD5_CTX md5_ctx = ssl->dc->md5_ctx; + SHA1_CTX sha1_ctx = ssl->dc->sha1_ctx; + + if (label) + { + strcpy((char *)q, label); + q += strlen(label); + } + + MD5_Final(q, &md5_ctx); + q += MD5_SIZE; + + SHA1_Final(q, &sha1_ctx); + q += SHA1_SIZE; + + if (label) + { + prf(ssl->dc->master_secret, SSL_SECRET_SIZE, mac_buf, (int)(q-mac_buf), + digest, SSL_FINISHED_HASH_SIZE); + } + else /* for use in a certificate verify */ + { + memcpy(digest, mac_buf, MD5_SIZE + SHA1_SIZE); + } + +#if 0 + printf("label: %s\n", label); + print_blob("master secret", ssl->dc->master_secret, 48); + print_blob("mac_buf", mac_buf, q-mac_buf); + print_blob("finished digest", digest, SSL_FINISHED_HASH_SIZE); +#endif + SSL_FREE(mac_buf); +} + +/** + * Retrieve (and initialise) the context of a cipher. + */ +static void *ICACHE_FLASH_ATTR crypt_new(SSL *ssl, uint8_t *key, uint8_t *iv, int is_decrypt) +{ + switch (ssl->cipher) + { +#ifndef CONFIG_SSL_SKELETON_MODE + case SSL_AES128_SHA: + { + AES_CTX *aes_ctx = (AES_CTX *)SSL_MALLOC(sizeof(AES_CTX)); + AES_set_key(aes_ctx, key, iv, AES_MODE_128); + + if (is_decrypt) + { + AES_convert_key(aes_ctx); + } + + return (void *)aes_ctx; + } + + case SSL_AES256_SHA: + { + AES_CTX *aes_ctx = (AES_CTX *)SSL_MALLOC(sizeof(AES_CTX)); + AES_set_key(aes_ctx, key, iv, AES_MODE_256); + + if (is_decrypt) + { + AES_convert_key(aes_ctx); + } + + return (void *)aes_ctx; + } + + case SSL_RC4_128_MD5: +#endif + case SSL_RC4_128_SHA: + { + RC4_CTX *rc4_ctx = (RC4_CTX *)SSL_MALLOC(sizeof(RC4_CTX)); + RC4_setup(rc4_ctx, key, 16); + return (void *)rc4_ctx; + } + } + + return NULL; /* its all gone wrong */ +} + +/** + * Send a packet over the socket. + */ +static int ICACHE_FLASH_ATTR send_raw_packet(SSL *ssl, uint8_t protocol) +{ + uint8_t *rec_buf = ssl->bm_all_data; + int pkt_size = SSL_RECORD_SIZE+ssl->bm_index; + int sent = 0; + int ret = SSL_OK; + + rec_buf[0] = protocol; + rec_buf[1] = 0x03; /* version = 3.1 or higher */ + rec_buf[2] = ssl->version & 0x0f; + rec_buf[3] = ssl->bm_index >> 8; + rec_buf[4] = ssl->bm_index & 0xff; + +// DISPLAY_BYTES(ssl, "sending %d bytes", ssl->bm_all_data, +// pkt_size, pkt_size); + + while (sent < pkt_size) + { + ret = write(ssl->client_fd, + &ssl->bm_all_data[sent], pkt_size-sent); + + if (ret >= 0) + sent += ret; + else + { + +#ifdef WIN32 + if (GetLastError() != WSAEWOULDBLOCK) +#else + if (errno != EAGAIN && errno != EWOULDBLOCK) +#endif + return SSL_ERROR_CONN_LOST; + } + + /* keep going until the write buffer has some space */ + if (sent != pkt_size) + { + fd_set wfds; + FD_ZERO(&wfds); + FD_SET(ssl->client_fd, &wfds); + + /* block and wait for it */ + if (select(ssl->client_fd + 1, NULL, &wfds, NULL, NULL) < 0) + return SSL_ERROR_CONN_LOST; + } + } + + SET_SSL_FLAG(SSL_NEED_RECORD); /* reset for next time */ + ssl->bm_index = 0; + + if (protocol != PT_APP_PROTOCOL_DATA) + { + /* always return SSL_OK during handshake */ + ret = SSL_OK; + } + + return ret; +} + +/** + * Send an encrypted packet with padding bytes if necessary. + */ +int ICACHE_FLASH_ATTR send_packet(SSL *ssl, uint8_t protocol, const uint8_t *in, int length) +{ + int ret, msg_length = 0; + + /* if our state is bad, don't bother */ + if (ssl->hs_status == SSL_ERROR_DEAD) + return SSL_ERROR_CONN_LOST; + + if (in) /* has the buffer already been initialised? */ + { + memcpy(ssl->bm_data, in, length); + } + + msg_length += length; + + if (IS_SET_SSL_FLAG(SSL_TX_ENCRYPTED)) + { + int mode = IS_SET_SSL_FLAG(SSL_IS_CLIENT) ? + SSL_CLIENT_WRITE : SSL_SERVER_WRITE; + uint8_t hmac_header[SSL_RECORD_SIZE] = + { + protocol, + 0x03, /* version = 3.1 or higher */ + ssl->version & 0x0f, + msg_length >> 8, + msg_length & 0xff + }; + + if (protocol == PT_HANDSHAKE_PROTOCOL) + { + //DISPLAY_STATE(ssl, 1, ssl->bm_data[0], 0); + + if (ssl->bm_data[0] != HS_HELLO_REQUEST) + { + add_packet(ssl, ssl->bm_data, msg_length); + } + } + + /* add the packet digest */ + add_hmac_digest(ssl, mode, hmac_header, ssl->bm_data, msg_length, + &ssl->bm_data[msg_length]); + msg_length += ssl->cipher_info->digest_size; + + /* add padding? */ + if (ssl->cipher_info->padding_size) + { + int last_blk_size = msg_length%ssl->cipher_info->padding_size; + int pad_bytes = ssl->cipher_info->padding_size - last_blk_size; + + /* ensure we always have at least 1 padding byte */ + if (pad_bytes == 0) + pad_bytes += ssl->cipher_info->padding_size; + + memset(&ssl->bm_data[msg_length], pad_bytes-1, pad_bytes); + msg_length += pad_bytes; + } + + //DISPLAY_BYTES(ssl, "unencrypted write", ssl->bm_data, msg_length); + increment_write_sequence(ssl); + + /* add the explicit IV for TLS1.1 */ + if (ssl->version >= SSL_PROTOCOL_VERSION1_1 && + ssl->cipher_info->iv_size) + { + uint8_t iv_size = ssl->cipher_info->iv_size; + uint8_t *t_buf = (uint8_t *)SSL_ZALLOC(msg_length + iv_size); + memcpy(t_buf + iv_size, ssl->bm_data, msg_length); + if (get_random(iv_size, t_buf) < 0) + return SSL_NOT_OK; + msg_length += iv_size; + memcpy(ssl->bm_data, t_buf, msg_length); + SSL_FREE(t_buf); /* add by wujg */ + } + + /* now encrypt the packet */ + ssl->cipher_info->encrypt(ssl->encrypt_ctx, ssl->bm_data, + ssl->bm_data, msg_length); + } + else if (protocol == PT_HANDSHAKE_PROTOCOL) + { + //DISPLAY_STATE(ssl, 1, ssl->bm_data[0], 0); + + if (ssl->bm_data[0] != HS_HELLO_REQUEST) + { + add_packet(ssl, ssl->bm_data, length); + } + } + + ssl->bm_index = msg_length; + if ((ret = send_raw_packet(ssl, protocol)) <= 0) + return ret; + + return length; /* just return what we wanted to send */ +} + +/** + * Work out the cipher keys we are going to use for this session based on the + * master secret. + */ +static int ICACHE_FLASH_ATTR set_key_block(SSL *ssl, int is_write) +{ + const cipher_info_t *ciph_info = get_cipher_info(ssl->cipher); + uint8_t *q; + uint8_t client_key[32], server_key[32]; /* big enough for AES256 */ + uint8_t client_iv[16], server_iv[16]; /* big enough for AES128/256 */ + int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT); + + if (ciph_info == NULL) + return -1; + + /* only do once in a handshake */ + if (ssl->dc->key_block == NULL) + { + ssl->dc->key_block = (uint8_t *)SSL_MALLOC(ciph_info->key_block_size); + +#if 0 + print_blob("client", ssl->dc->client_random, 32); + print_blob("server", ssl->dc->server_random, 32); + print_blob("master", ssl->dc->master_secret, SSL_SECRET_SIZE); +#endif + generate_key_block(ssl->dc->client_random, ssl->dc->server_random, + ssl->dc->master_secret, ssl->dc->key_block, + ciph_info->key_block_size); +#if 0 + print_blob("keyblock", ssl->dc->key_block, ciph_info->key_block_size); +#endif + } + + q = ssl->dc->key_block; + + if ((is_client && is_write) || (!is_client && !is_write)) + { + memcpy(ssl->client_mac, q, ciph_info->digest_size); + } + + q += ciph_info->digest_size; + + if ((!is_client && is_write) || (is_client && !is_write)) + { + memcpy(ssl->server_mac, q, ciph_info->digest_size); + } + + q += ciph_info->digest_size; + memcpy(client_key, q, ciph_info->key_size); + q += ciph_info->key_size; + memcpy(server_key, q, ciph_info->key_size); + q += ciph_info->key_size; + +#ifndef CONFIG_SSL_SKELETON_MODE + if (ciph_info->iv_size) /* RC4 has no IV, AES does */ + { + memcpy(client_iv, q, ciph_info->iv_size); + q += ciph_info->iv_size; + memcpy(server_iv, q, ciph_info->iv_size); + q += ciph_info->iv_size; + } +#endif + + SSL_FREE(is_write ? ssl->encrypt_ctx : ssl->decrypt_ctx); + + /* now initialise the ciphers */ + if (is_client) + { + char *server_finished_ram = (char *)SSL_ZALLOC(24); + + system_get_string_from_flash(server_finished, server_finished_ram, 24); + + finished_digest(ssl, server_finished_ram, ssl->dc->final_finish_mac); + + SSL_FREE(server_finished_ram); + + if (is_write) + ssl->encrypt_ctx = crypt_new(ssl, client_key, client_iv, 0); + else + ssl->decrypt_ctx = crypt_new(ssl, server_key, server_iv, 1); + } + else + { + char *client_finished_ram = (char *)SSL_ZALLOC(24); + + system_get_string_from_flash(client_finished, client_finished_ram, 24); + + finished_digest(ssl, client_finished_ram, ssl->dc->final_finish_mac); + + SSL_FREE(client_finished_ram); + + if (is_write) + ssl->encrypt_ctx = crypt_new(ssl, server_key, server_iv, 0); + else + ssl->decrypt_ctx = crypt_new(ssl, client_key, client_iv, 1); + } + + ssl->cipher_info = ciph_info; + return 0; +} + +/** + * Read the SSL connection. + */ +int ICACHE_FLASH_ATTR basic_read(SSL *ssl, uint8_t **in_data) +{ + int ret = SSL_OK; + int read_len, is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT); + uint8_t *buf = ssl->bm_data; + +begain: + /* do we violate the spec with the message size? */ + //os_printf("basic_read index %u\n", ssl->bm_read_index); + + if (ssl->bm_read_index > ssl->max_fragme_length + RT_EXTRA) { + ret = SSL_ERROR_INVALID_PROT_MSG; + goto error; + } + + read_len = read(ssl->client_fd, &buf[ssl->bm_read_index], + ssl->need_bytes-ssl->got_bytes); + + if (read_len < 0) + { +#ifdef WIN32 + if (GetLastError() == WSAEWOULDBLOCK) +#else + if (errno == EAGAIN || errno == EWOULDBLOCK){ +#endif + ret = SSL_OK; + goto finish; + } + } + + /* connection has gone, so die */ + if (read_len <= 0) + { + ret = SSL_ERROR_CONN_LOST; + ssl->hs_status = SSL_ERROR_DEAD; /* make sure it stays dead */ + goto error; + } + +// DISPLAY_BYTES(ssl, "received %d bytes", +// &ssl->bm_data[ssl->bm_read_index], read_len, read_len); + + ssl->got_bytes += read_len; + ssl->bm_read_index += read_len; + + /* haven't quite got what we want, so try again later */ + if (ssl->got_bytes < ssl->need_bytes) + { + ret = SSL_OK; + goto finish; + } + + read_len = ssl->got_bytes; + ssl->got_bytes = 0; + + if (IS_SET_SSL_FLAG(SSL_NEED_RECORD)) + { + /* check for sslv2 "client hello" */ + if (buf[0] & 0x80 && buf[2] == 1) + { +#ifdef CONFIG_SSL_ENABLE_V23_HANDSHAKE + uint8_t version = (buf[3] << 4) + buf[4]; + DISPLAY_BYTES(ssl, "ssl2 record", buf, 5); + + /* should be v3.1 (TLSv1) or better */ + ssl->version = ssl->client_version = version; + + if (version > SSL_PROTOCOL_VERSION_MAX) + { + /* use client's version */ + ssl->version = SSL_PROTOCOL_VERSION_MAX; + } + else if (version < SSL_PROTOCOL_MIN_VERSION) + { + ret = SSL_ERROR_INVALID_VERSION; + ssl_display_error(ret); + return ret; + } + + add_packet(ssl, &buf[2], 3); + ret = process_sslv23_client_hello(ssl); +#else + ssl_printf("Error: no SSLv23 handshaking allowed\n"); //TTY_FLUSH(); + ret = SSL_ERROR_NOT_SUPPORTED; +#endif + goto error; /* not an error - just get out of here */ + } + + ssl->need_bytes = (buf[3] << 8) + buf[4]; + + /* do we violate the spec with the message size? */ + if (ssl->need_bytes > ssl->max_fragme_length+RT_EXTRA-BM_RECORD_OFFSET) + { + ret = SSL_ERROR_INVALID_PROT_MSG; + goto error; + } + + CLR_SSL_FLAG(SSL_NEED_RECORD); + memcpy(ssl->hmac_header, buf, 3); /* store for hmac */ + ssl->record_type = buf[0]; + goto error; /* no error, we're done */ + } + + /* for next time - just do it now in case of an error */ + SET_SSL_FLAG(SSL_NEED_RECORD); + ssl->need_bytes = SSL_RECORD_SIZE; + + /* decrypt if we need to */ + if (IS_SET_SSL_FLAG(SSL_RX_ENCRYPTED)) + { + ssl->cipher_info->decrypt(ssl->decrypt_ctx, buf, buf, read_len); + + if (ssl->version >= SSL_PROTOCOL_VERSION1_1 && + ssl->cipher_info->iv_size) + { + buf += ssl->cipher_info->iv_size; + read_len -= ssl->cipher_info->iv_size; + } + + read_len = verify_digest(ssl, + is_client ? SSL_CLIENT_READ : SSL_SERVER_READ, buf, read_len); + + /* does the hmac work? */ + if (read_len < 0) + { + ret = read_len; + goto error; + } + + //DISPLAY_BYTES(ssl, "decrypted", buf, read_len); + increment_read_sequence(ssl); + } + + /* The main part of the SSL packet */ + //ssl_printf("basic_read %d %x %p\n", __LINE__, ssl->record_type, in_data); + switch (ssl->record_type) + { + case PT_HANDSHAKE_PROTOCOL: + if (ssl->dc != NULL) + { + ssl->dc->bm_proc_index = 0; + ret = do_handshake(ssl, buf, read_len); + } + else /* no client renegotiation allowed */ + { + ret = SSL_ERROR_NO_CLIENT_RENOG; + goto error; + } + break; + + case PT_CHANGE_CIPHER_SPEC: + if (ssl->next_state != HS_FINISHED) + { + ret = SSL_ERROR_INVALID_HANDSHAKE; + goto error; + } + + if (set_key_block(ssl, 0) < 0) + { + ret = SSL_ERROR_INVALID_HANDSHAKE; + goto error; + } + + /* all encrypted from now on */ + SET_SSL_FLAG(SSL_RX_ENCRYPTED); + memset(ssl->read_sequence, 0, 8); + break; + + case PT_APP_PROTOCOL_DATA: + if (in_data && ssl->hs_status == SSL_OK) + { + *in_data = buf; /* point to the work buffer */ + (*in_data)[read_len] = 0; /* null terminate just in case */ + ret = read_len; + } + else + ret = SSL_ERROR_INVALID_PROT_MSG; + break; + + case PT_ALERT_PROTOCOL: + /* return the alert # with alert bit set */ + if(buf[0] == SSL_ALERT_TYPE_WARNING && + buf[1] == SSL_ALERT_CLOSE_NOTIFY) + { + ret = SSL_CLOSE_NOTIFY; + send_alert(ssl, SSL_ALERT_CLOSE_NOTIFY); + SET_SSL_FLAG(SSL_SENT_CLOSE_NOTIFY); + } + else + { + ret = -buf[1]; + //DISPLAY_ALERT(ssl, buf[1]); + } + + break; + + default: + ret = SSL_ERROR_INVALID_PROT_MSG; + break; + } + +error: + ssl->bm_read_index = 0; /* reset to go again */ + + if (ret < SSL_OK && in_data)/* if all wrong, then clear this buffer ptr */ + *in_data = NULL; + +finish: + if (ssl->record_type == PT_APP_PROTOCOL_DATA){ + if (ret == SSL_OK) + goto begain; + } + + return ret; +} + +/** + * Do some basic checking of data and then perform the appropriate handshaking. + */ +static int ICACHE_FLASH_ATTR do_handshake(SSL *ssl, uint8_t *buf, int read_len) +{ + int hs_len = (buf[2]<<8) + buf[3]; + uint8_t handshake_type = buf[0]; + int ret = SSL_OK; + int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT); + + /* some integrity checking on the handshake */ + PARANOIA_CHECK(read_len-SSL_HS_HDR_SIZE, hs_len); + + if (handshake_type != ssl->next_state) + { + /* handle a special case on the client */ + if (!is_client || handshake_type != HS_CERT_REQ || + ssl->next_state != HS_SERVER_HELLO_DONE) + { + ret = SSL_ERROR_INVALID_HANDSHAKE; + goto error; + } + } + + hs_len += SSL_HS_HDR_SIZE; /* adjust for when adding packets */ + ssl->bm_index = hs_len; /* store the size and check later */ + //DISPLAY_STATE(ssl, 0, handshake_type, 0); + + if (handshake_type != HS_CERT_VERIFY && handshake_type != HS_HELLO_REQUEST) + add_packet(ssl, buf, hs_len); + +#if defined(CONFIG_SSL_ENABLE_CLIENT) + ret = is_client ? + do_clnt_handshake(ssl, handshake_type, buf, hs_len) : + do_svr_handshake(ssl, handshake_type, buf, hs_len); +#else + ret = do_svr_handshake(ssl, handshake_type, buf, hs_len); +#endif + + /* just use recursion to get the rest */ + if (hs_len < read_len && ret == SSL_OK) + ret = do_handshake(ssl, &buf[hs_len], read_len-hs_len); + +error: + return ret; +} + +/** + * Sends the change cipher spec message. We have just read a finished message + * from the client. + */ +int ICACHE_FLASH_ATTR send_change_cipher_spec(SSL *ssl) +{ + uint8 g_chg_cipher_spec_pkt_ram[4]; + memcpy(g_chg_cipher_spec_pkt_ram, g_chg_cipher_spec_pkt, 4); + + int ret = send_packet(ssl, PT_CHANGE_CIPHER_SPEC, + g_chg_cipher_spec_pkt_ram, sizeof(g_chg_cipher_spec_pkt)); + + if (ret >= 0 && set_key_block(ssl, 1) < 0) + ret = SSL_ERROR_INVALID_HANDSHAKE; + + if (ssl->cipher_info) + SET_SSL_FLAG(SSL_TX_ENCRYPTED); + if (ssl->cipher_info) + SET_SSL_FLAG(SSL_TX_ENCRYPTED); + + memset(ssl->write_sequence, 0, 8); + return ret; +} + +/** + * Send a "finished" message + */ +int ICACHE_FLASH_ATTR send_finished(SSL *ssl) +{ + uint8_t buf[SSL_FINISHED_HASH_SIZE+4] = { + HS_FINISHED, 0, 0, SSL_FINISHED_HASH_SIZE }; + + char *client_finished_ram = (char *)SSL_ZALLOC(24); + char *server_finished_ram = (char *)SSL_ZALLOC(24); + + system_get_string_from_flash(client_finished, client_finished_ram, 24); + system_get_string_from_flash(server_finished, server_finished_ram, 24); + + /* now add the finished digest mac (12 bytes) */ + finished_digest(ssl, + IS_SET_SSL_FLAG(SSL_IS_CLIENT) ? + client_finished_ram : server_finished_ram, &buf[4]); + + SSL_FREE(client_finished_ram); + SSL_FREE(server_finished_ram); + +#ifndef CONFIG_SSL_SKELETON_MODE + /* store in the session cache */ + if (!IS_SET_SSL_FLAG(SSL_SESSION_RESUME) && ssl->ssl_ctx->num_sessions) + { + memcpy(ssl->session->master_secret, + ssl->dc->master_secret, SSL_SECRET_SIZE); + } +#endif + + return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, + buf, SSL_FINISHED_HASH_SIZE+4); +} + +/** + * Send an alert message. + * Return 1 if the alert was an "error". + */ +int ICACHE_FLASH_ATTR send_alert(SSL *ssl, int error_code) +{ + int alert_num = 0; + int is_warning = 0; + uint8_t buf[2]; + + /* Don't bother we're already dead */ + if (ssl->hs_status == SSL_ERROR_DEAD) + { + return SSL_ERROR_CONN_LOST; + } + +#ifdef CONFIG_SSL_FULL_MODE + //if (IS_SET_SSL_FLAG(SSL_DISPLAY_STATES)) + //ssl_display_error(error_code); +#endif + + switch (error_code) + { + case SSL_ALERT_CLOSE_NOTIFY: + is_warning = 1; + alert_num = SSL_ALERT_CLOSE_NOTIFY; + break; + + case SSL_ERROR_CONN_LOST: /* don't send alert just yet */ + is_warning = 1; + break; + + case SSL_ERROR_INVALID_HANDSHAKE: + case SSL_ERROR_INVALID_PROT_MSG: + alert_num = SSL_ALERT_HANDSHAKE_FAILURE; + break; + + case SSL_ERROR_INVALID_HMAC: + case SSL_ERROR_FINISHED_INVALID: + alert_num = SSL_ALERT_BAD_RECORD_MAC; + break; + + case SSL_ERROR_INVALID_VERSION: + alert_num = SSL_ALERT_INVALID_VERSION; + break; + + case SSL_ERROR_INVALID_SESSION: + case SSL_ERROR_NO_CIPHER: + case SSL_ERROR_INVALID_KEY: + alert_num = SSL_ALERT_ILLEGAL_PARAMETER; + break; + + case SSL_ERROR_BAD_CERTIFICATE: + alert_num = SSL_ALERT_BAD_CERTIFICATE; + break; + + case SSL_ERROR_NO_CLIENT_RENOG: + alert_num = SSL_ALERT_NO_RENEGOTIATION; + break; + + default: + /* a catch-all for any badly verified certificates */ + alert_num = (error_code <= SSL_X509_OFFSET) ? + SSL_ALERT_BAD_CERTIFICATE : SSL_ALERT_UNEXPECTED_MESSAGE; + break; + } + + buf[0] = is_warning ? 1 : 2; + buf[1] = alert_num; + send_packet(ssl, PT_ALERT_PROTOCOL, buf, sizeof(buf)); + //DISPLAY_ALERT(ssl, alert_num); + return is_warning ? 0 : 1; +} + +/** + * Process a client finished message. + */ +int ICACHE_FLASH_ATTR process_finished(SSL *ssl, uint8_t *buf, int hs_len) +{ + int ret = SSL_OK; + int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT); + int resume = IS_SET_SSL_FLAG(SSL_SESSION_RESUME); + + PARANOIA_CHECK(ssl->bm_index, SSL_FINISHED_HASH_SIZE+4); + + /* check that we all work before we continue */ + if (memcmp(ssl->dc->final_finish_mac, &buf[4], SSL_FINISHED_HASH_SIZE)) + return SSL_ERROR_FINISHED_INVALID; + + if ((!is_client && !resume) || (is_client && resume)) + { + if ((ret = send_change_cipher_spec(ssl)) == SSL_OK) + ret = send_finished(ssl); + } + + /* if we ever renegotiate */ + ssl->next_state = is_client ? HS_HELLO_REQUEST : HS_CLIENT_HELLO; + ssl->hs_status = ret; /* set the final handshake status */ + +error: + return ret; +} + +/** + * Send a certificate. + */ +int ICACHE_FLASH_ATTR send_certificate(SSL *ssl) +{ + int i = 0; + uint8_t *buf = ssl->bm_data; + int offset = 7; + int chain_length; + + buf[0] = HS_CERTIFICATE; + buf[1] = 0; + buf[4] = 0; + + while (i < ssl->ssl_ctx->chain_length) + { + SSL_CERT *cert = &ssl->ssl_ctx->certs[i]; + buf[offset++] = 0; + buf[offset++] = cert->size >> 8; /* cert 1 length */ + buf[offset++] = cert->size & 0xff; + memcpy(&buf[offset], cert->buf, cert->size); + offset += cert->size; + i++; + } + + chain_length = offset - 7; + buf[5] = chain_length >> 8; /* cert chain length */ + buf[6] = chain_length & 0xff; + chain_length += 3; + buf[2] = chain_length >> 8; /* handshake length */ + buf[3] = chain_length & 0xff; + ssl->bm_index = offset; + return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, offset); +} + +/** + * Create a blob of memory that we'll get rid of once the handshake is + * complete. + */ +void ICACHE_FLASH_ATTR disposable_new(SSL *ssl) +{ + if (ssl->dc == NULL) + { + ssl->dc = (DISPOSABLE_CTX *)SSL_ZALLOC(sizeof(DISPOSABLE_CTX)); + MD5_Init(&ssl->dc->md5_ctx); + SHA1_Init(&ssl->dc->sha1_ctx); + } +} + +/** + * Remove the temporary blob of memory. + */ +void ICACHE_FLASH_ATTR disposable_free(SSL *ssl) +{ + if (ssl->dc) + { + SSL_FREE(ssl->dc->key_block); + memset(ssl->dc, 0, sizeof(DISPOSABLE_CTX)); + SSL_FREE(ssl->dc); + ssl->dc = NULL; + } + +} + +#ifndef CONFIG_SSL_SKELETON_MODE /* no session resumption in this mode */ +/** + * Find if an existing session has the same session id. If so, use the + * master secret from this session for session resumption. + */ +SSL_SESSION *ICACHE_FLASH_ATTR ssl_session_update(int max_sessions, SSL_SESSION *ssl_sessions[], + SSL *ssl, const uint8_t *session_id) +{ + time_t tm = 0; //time(NULL); wujg + time_t oldest_sess_time = tm; + SSL_SESSION *oldest_sess = NULL; + int i; + + /* no sessions? Then bail */ + if (max_sessions == 0) + return NULL; + + SSL_CTX_LOCK(ssl->ssl_ctx->mutex); + if (session_id) + { + for (i = 0; i < max_sessions; i++) + { + if (ssl_sessions[i]) + { + /* kill off any expired sessions (including those in + the future) */ + if ((tm > ssl_sessions[i]->conn_time + SSL_EXPIRY_TIME) || + (tm < ssl_sessions[i]->conn_time)) + { + session_free(ssl_sessions, i); + continue; + } + + /* if the session id matches, it must still be less than + the expiry time */ + if (memcmp(ssl_sessions[i]->session_id, session_id, + SSL_SESSION_ID_SIZE) == 0) + { + ssl->session_index = i; + memcpy(ssl->dc->master_secret, + ssl_sessions[i]->master_secret, SSL_SECRET_SIZE); + SET_SSL_FLAG(SSL_SESSION_RESUME); + SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); + return ssl_sessions[i]; /* a session was found */ + } + } + } + } + + /* If we've got here, no matching session was found - so create one */ + for (i = 0; i < max_sessions; i++) + { + if (ssl_sessions[i] == NULL) + { + /* perfect, this will do */ + ssl_sessions[i] = (SSL_SESSION *)SSL_ZALLOC(sizeof(SSL_SESSION));// 84KB + ssl_sessions[i]->conn_time = tm; + ssl->session_index = i; + SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); + return ssl_sessions[i]; /* return the session object */ + } + else if (ssl_sessions[i]->conn_time <= oldest_sess_time) + { + /* find the oldest session */ + oldest_sess_time = ssl_sessions[i]->conn_time; + oldest_sess = ssl_sessions[i]; + ssl->session_index = i; + } + } + + /* ok, we've used up all of our sessions. So blow the oldest session away */ + oldest_sess->conn_time = tm; + memset(oldest_sess->session_id, 0, sizeof(SSL_SESSION_ID_SIZE)); + memset(oldest_sess->master_secret, 0, sizeof(SSL_SECRET_SIZE)); + SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); + return oldest_sess; +} + +/** + * Free an existing session. + */ +static void ICACHE_FLASH_ATTR session_free(SSL_SESSION *ssl_sessions[], int sess_index) +{ + if (ssl_sessions[sess_index]) + { + SSL_FREE(ssl_sessions[sess_index]); + ssl_sessions[sess_index] = NULL; + } +} + +/** + * This ssl object doesn't want this session anymore. + */ +void ICACHE_FLASH_ATTR kill_ssl_session(SSL_SESSION **ssl_sessions, SSL *ssl) +{ + SSL_CTX_LOCK(ssl->ssl_ctx->mutex); + + if (ssl->ssl_ctx->num_sessions) + { + session_free(ssl_sessions, ssl->session_index); + ssl->session = NULL; + } + + SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); +} +#endif /* CONFIG_SSL_SKELETON_MODE */ + +/* + * Get the session id for a handshake. This will be a 32 byte sequence. + */ +EXP_FUNC const uint8_t * STDCALL ICACHE_FLASH_ATTR ssl_get_session_id(const SSL *ssl) +{ + return ssl->session_id; +} + +/* + * Get the session id size for a handshake. + */ +EXP_FUNC uint8_t STDCALL ICACHE_FLASH_ATTR ssl_get_session_id_size(const SSL *ssl) +{ + return ssl->sess_id_size; +} + +/* + * Return the cipher id (in the SSL form). + */ +EXP_FUNC uint8_t STDCALL ICACHE_FLASH_ATTR ssl_get_cipher_id(const SSL *ssl) +{ + return ssl->cipher; +} + +/* + * Return the status of the handshake. + */ +EXP_FUNC int STDCALL ICACHE_FLASH_ATTR ssl_handshake_status(const SSL *ssl) +{ + return ssl->hs_status; +} + +/* + * Retrieve various parameters about the SSL engine. + */ +EXP_FUNC int STDCALL ICACHE_FLASH_ATTR ssl_get_config(int offset) +{ + switch (offset) + { + /* return the appropriate build mode */ + case SSL_BUILD_MODE: +#if defined(CONFIG_SSL_FULL_MODE) + return SSL_BUILD_FULL_MODE; +#elif defined(CONFIG_SSL_ENABLE_CLIENT) + return SSL_BUILD_ENABLE_CLIENT; +#elif defined(CONFIG_ENABLE_VERIFICATION) + return SSL_BUILD_ENABLE_VERIFICATION; +#elif defined(CONFIG_SSL_SERVER_ONLY ) + return SSL_BUILD_SERVER_ONLY; +#else + return SSL_BUILD_SKELETON_MODE; +#endif + + case SSL_MAX_CERT_CFG_OFFSET: + return CONFIG_SSL_MAX_CERTS; + +#ifdef CONFIG_SSL_CERT_VERIFICATION + case SSL_MAX_CA_CERT_CFG_OFFSET: + return CONFIG_X509_MAX_CA_CERTS; +#endif +#ifdef CONFIG_SSL_HAS_PEM + case SSL_HAS_PEM: + return 1; +#endif + default: + return 0; + } +} + +#ifdef CONFIG_SSL_CERT_VERIFICATION +/** + * Authenticate a received certificate. + */ +EXP_FUNC int STDCALL ICACHE_FLASH_ATTR ssl_verify_cert(const SSL *ssl) +{ + int ret; + SSL_CTX_LOCK(ssl->ssl_ctx->mutex); + ret = x509_verify(ssl->ssl_ctx->ca_cert_ctx, ssl->x509_ctx); + SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); + + if (ret) /* modify into an SSL error type */ + { + ret = SSL_X509_ERROR(ret); + } + + return ret; +} + +/** + * Process a certificate message. + */ +int ICACHE_FLASH_ATTR process_certificate(SSL *ssl, X509_CTX **x509_ctx) +{ + int ret = SSL_OK; + uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index]; + int pkt_size = ssl->bm_index; + int cert_size, offset = 5; + int total_cert_size = (buf[offset]<<8) + buf[offset+1]; + int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT); + X509_CTX **chain = x509_ctx; + offset += 2; + + PARANOIA_CHECK(total_cert_size, offset); + + while (offset < total_cert_size) + { + offset++; /* skip empty char */ + cert_size = (buf[offset]<<8) + buf[offset+1]; + offset += 2; + + if (x509_new(&buf[offset], NULL, chain)) + { + ret = SSL_ERROR_BAD_CERTIFICATE; + goto error; + } + + chain = &((*chain)->next); + offset += cert_size; + } + + PARANOIA_CHECK(pkt_size, offset); + + /* if we are client we can do the verify now or later */ + if (is_client && !IS_SET_SSL_FLAG(SSL_SERVER_VERIFY_LATER)) + { + ret = ssl_verify_cert(ssl); + } + + ssl->next_state = is_client ? HS_SERVER_HELLO_DONE : HS_CLIENT_KEY_XCHG; + ssl->dc->bm_proc_index += offset; +error: + return ret; +} + +#endif /* CONFIG_SSL_CERT_VERIFICATION */ + +/** + * Debugging routine to display SSL handshaking stuff. + */ +#ifdef CONFIG_SSL_FULL_MODE +/** + * Debugging routine to display SSL states. + */ +#if CONFIG_SSL_DISPLAY_MODE +void ICACHE_FLASH_ATTR DISPLAY_STATE(SSL *ssl, int is_send, uint8_t state, int not_ok) +{ + const char *str; + + if (!IS_SET_SSL_FLAG(SSL_DISPLAY_STATES)) + return; + + ssl_printf(not_ok ? "Error - invalid State:\t" : "State:\t"); + ssl_printf(is_send ? "sending " : "receiving "); + + switch (state) + { + case HS_HELLO_REQUEST: + str = "Hello Request (0)"; + break; + + case HS_CLIENT_HELLO: + str = "Client Hello (1)"; + break; + + case HS_SERVER_HELLO: + str = "Server Hello (2)"; + break; + + case HS_CERTIFICATE: + str = "Certificate (11)"; + break; + + case HS_SERVER_KEY_XCHG: + str = "Certificate Request (12)"; + break; + + case HS_CERT_REQ: + str = "Certificate Request (13)"; + break; + + case HS_SERVER_HELLO_DONE: + str = "Server Hello Done (14)"; + break; + + case HS_CERT_VERIFY: + str = "Certificate Verify (15)"; + break; + + case HS_CLIENT_KEY_XCHG: + str = "Client Key Exchange (16)"; + break; + + case HS_FINISHED: + str = "Finished (16)"; + break; + + default: + str = "Error (Unknown)"; + + break; + } + + ssl_printf("%s\n", str); + //TTY_FLUSH(); +} + +/** + * Debugging routine to display RSA objects + */ +void ICACHE_FLASH_ATTR DISPLAY_RSA(SSL *ssl, const RSA_CTX *rsa_ctx) +{ + if (!IS_SET_SSL_FLAG(SSL_DISPLAY_RSA)) + return; + + RSA_print(rsa_ctx); + //TTY_FLUSH(); +} + +/** + * Debugging routine to display SSL handshaking bytes. + */ +void ICACHE_FLASH_ATTR DISPLAY_BYTES(SSL *ssl, const char *format, + const uint8_t *data, int size, ...) +{ +// wujg : pass compile first +// va_list(ap); + +// if (!IS_SET_SSL_FLAG(SSL_DISPLAY_BYTES)) +// return; + +// va_start(ap, size); +// print_blob(format, data, size, va_arg(ap, char *)); +// va_end(ap); +// TTY_FLUSH(); +} + +/** + * Debugging routine to display SSL handshaking errors. + */ +EXP_FUNC void STDCALL ICACHE_FLASH_ATTR ssl_display_error(int error_code) +{ + if (error_code == SSL_OK) + return; + + ssl_printf("Error: "); + + /* X509 error? */ + if (error_code < SSL_X509_OFFSET) + { + ssl_printf("%s\n", x509_display_error(error_code - SSL_X509_OFFSET)); + return; + } + + /* SSL alert error code */ + if (error_code > SSL_ERROR_CONN_LOST) + { + ssl_printf("SSL error %d\n", -error_code); + return; + } + + switch (error_code) + { + case SSL_ERROR_DEAD: + ssl_printf("connection dead"); + break; + + case SSL_ERROR_INVALID_HANDSHAKE: + ssl_printf("invalid handshake"); + break; + + case SSL_ERROR_INVALID_PROT_MSG: + ssl_printf("invalid protocol message"); + break; + + case SSL_ERROR_INVALID_HMAC: + ssl_printf("invalid mac"); + break; + + case SSL_ERROR_INVALID_VERSION: + ssl_printf("invalid version"); + break; + + case SSL_ERROR_INVALID_SESSION: + ssl_printf("invalid session"); + break; + + case SSL_ERROR_NO_CIPHER: + ssl_printf("no cipher"); + break; + + case SSL_ERROR_CONN_LOST: + ssl_printf("connection lost"); + break; + + case SSL_ERROR_BAD_CERTIFICATE: + ssl_printf("bad certificate"); + break; + + case SSL_ERROR_INVALID_KEY: + ssl_printf("invalid key"); + break; + + case SSL_ERROR_FINISHED_INVALID: + ssl_printf("finished invalid"); + break; + + case SSL_ERROR_NO_CERT_DEFINED: + ssl_printf("no certificate defined"); + break; + + case SSL_ERROR_NO_CLIENT_RENOG: + ssl_printf("client renegotiation not supported"); + break; + + case SSL_ERROR_NOT_SUPPORTED: + ssl_printf("Option not supported"); + break; + + default: + ssl_printf("undefined as yet - %d", error_code); + break; + } + + ssl_printf("\n"); + //TTY_FLUSH(); +} + +/** + * Debugging routine to display alerts. + */ +void ICACHE_FLASH_ATTR DISPLAY_ALERT(SSL *ssl, int alert) +{ + if (!IS_SET_SSL_FLAG(SSL_DISPLAY_STATES)) + return; + + ssl_printf("Alert: "); + + switch (alert) + { + case SSL_ALERT_CLOSE_NOTIFY: + ssl_printf("close notify"); + break; + + case SSL_ALERT_INVALID_VERSION: + ssl_printf("invalid version"); + break; + + case SSL_ALERT_BAD_CERTIFICATE: + ssl_printf("bad certificate"); + break; + + case SSL_ALERT_UNEXPECTED_MESSAGE: + ssl_printf("unexpected message"); + break; + + case SSL_ALERT_BAD_RECORD_MAC: + ssl_printf("bad record mac"); + break; + + case SSL_ALERT_HANDSHAKE_FAILURE: + ssl_printf("handshake failure"); + break; + + case SSL_ALERT_ILLEGAL_PARAMETER: + ssl_printf("illegal parameter"); + break; + + case SSL_ALERT_DECODE_ERROR: + ssl_printf("decode error"); + break; + + case SSL_ALERT_DECRYPT_ERROR: + ssl_printf("decrypt error"); + break; + + case SSL_ALERT_NO_RENEGOTIATION: + ssl_printf("no renegotiation"); + break; + + default: + ssl_printf("alert - (unknown %d)", alert); + break; + } + + ssl_printf("\n"); + //TTY_FLUSH(); +} +#endif +#endif /* CONFIG_SSL_FULL_MODE */ + +/** + * Return the version of this library. + */ +EXP_FUNC const char * STDCALL ICACHE_FLASH_ATTR ssl_version() +{ + static const char * axtls_version = AXTLS_VERSION; + return axtls_version; +} + +/** + * Enable the various language bindings to work regardless of the + * configuration - they just return an error statement and a bad return code. + */ +#if !defined(CONFIG_SSL_FULL_MODE) +EXP_FUNC void STDCALL ssl_display_error(int error_code) {} +#endif + +#ifdef CONFIG_BINDINGS +#if !defined(CONFIG_SSL_ENABLE_CLIENT) +EXP_FUNC SSL * STDCALL ICACHE_FLASH_ATTR ssl_client_new(SSL_CTX *ssl_ctx, int client_fd, const + uint8_t *session_id, uint8_t sess_id_size) +{ + ssl_printf(unsupported_str); + return NULL; +} +#endif + +#if !defined(CONFIG_SSL_CERT_VERIFICATION) +EXP_FUNC int STDCALL ICACHE_FLASH_ATTR ssl_verify_cert(const SSL *ssl) +{ + ssl_printf(unsupported_str); + return -1; +} + + +EXP_FUNC const char * STDCALL ICACHE_FLASH_ATTR ssl_get_cert_dn(const SSL *ssl, int component) +{ + ssl_printf(unsupported_str); + return NULL; +} + +EXP_FUNC const char * STDCALL ICACHE_FLASH_ATTR ssl_get_cert_subject_alt_dnsname(const SSL *ssl, int index) +{ + ssl_printf(unsupported_str); + return NULL; +} + +#endif /* CONFIG_SSL_CERT_VERIFICATION */ + +#endif /* CONFIG_BINDINGS */ + +/** + * Negotiation the maximal fragment length + * @Parameters ssl The client/server context + * @Parameters fragmet_level The negotiation level of the fragment + * @Returns result true or false +*/ +bool ICACHE_FLASH_ATTR ssl_fragment_length_negotiation(SSL* ssl, int fragmet_level) +{ + bool nago_flag = true; + if (NULL == ssl) + return false; + + switch (fragmet_level){ + case SSL_MAX_FRAG_LEN_512: + ssl->max_fragme_length = 512; + break; + case SSL_MAX_FRAG_LEN_1024: + ssl->max_fragme_length = 1024; + break; + case SSL_MAX_FRAG_LEN_2048: + ssl->max_fragme_length = 2048; + break; + case SSL_MAX_FRAG_LEN_4096: + ssl->max_fragme_length = 4096; + break; + case SSL_MAX_FRAG_LEN_8192: + ssl->max_fragme_length = 8192; + break; + default: + nago_flag = false; + break; + } + + if (nago_flag){ + if (ssl->bm_all_data != NULL){ + SSL_FREE(ssl->bm_all_data); + ssl->bm_all_data = NULL; + } + ssl->bm_all_data = (uint8_t*)SSL_ZALLOC(ssl->max_fragme_length + RT_EXTRA); + if (NULL == ssl->bm_all_data) + nago_flag = false; + } + return nago_flag; +} + diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_tls1_clnt.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_tls1_clnt.c new file mode 100644 index 0000000..cbc5e6d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_tls1_clnt.c @@ -0,0 +1,397 @@ +/* + * 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. + */ + +#include "ssl/ssl_os_port.h" +#include "ssl/ssl_ssl.h" +//#include "lwip/tcp.h" + +#ifdef CONFIG_SSL_ENABLE_CLIENT /* all commented out if no client */ + +static int send_client_hello(SSL *ssl); +static int process_server_hello(SSL *ssl); +static int process_server_hello_done(SSL *ssl); +static int send_client_key_xchg(SSL *ssl); +static int process_cert_req(SSL *ssl); +static int send_cert_verify(SSL *ssl); + +/* + * Establish a new SSL connection to an SSL server. + */ +EXP_FUNC SSL * STDCALL ICACHE_FLASH_ATTR ssl_client_new(SSL_CTX *ssl_ctx, int client_fd, const + uint8_t *session_id, uint8_t sess_id_size) +{ + SSL *ssl = ssl_new(ssl_ctx, client_fd); + ssl->version = SSL_PROTOCOL_VERSION_MAX; /* try top version first */ + + if (session_id && ssl_ctx->num_sessions) + { + if (sess_id_size > SSL_SESSION_ID_SIZE) /* validity check */ + { + ssl_free(ssl); + return NULL; + } + + memcpy(ssl->session_id, session_id, sess_id_size); + ssl->sess_id_size = sess_id_size; + SET_SSL_FLAG(SSL_SESSION_RESUME); /* just flag for later */ + } + + SET_SSL_FLAG(SSL_IS_CLIENT); + do_client_connect(ssl); + return ssl; +} + +/* + * Process the handshake record. + */ +int ICACHE_FLASH_ATTR do_clnt_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len) +{ + int ret; + + /* To get here the state must be valid */ +// ssl_printf("do_clnt_handshake: %d %d\n",__LINE__, handshake_type); + switch (handshake_type) + { + case HS_SERVER_HELLO: + ret = process_server_hello(ssl); + break; + + case HS_CERTIFICATE: + ret = process_certificate(ssl, &ssl->x509_ctx); + break; + + case HS_SERVER_HELLO_DONE: + if ((ret = process_server_hello_done(ssl)) == SSL_OK) + { + if (IS_SET_SSL_FLAG(SSL_HAS_CERT_REQ)) + { + if ((ret = send_certificate(ssl)) == SSL_OK && + (ret = send_client_key_xchg(ssl)) == SSL_OK) + { + send_cert_verify(ssl); + } + } + else + { + ret = send_client_key_xchg(ssl); + } + + if (ret == SSL_OK && + (ret = send_change_cipher_spec(ssl)) == SSL_OK) + { + ret = send_finished(ssl); + } + } + break; + + case HS_CERT_REQ: + ret = process_cert_req(ssl); + break; + + case HS_FINISHED: + ret = process_finished(ssl, buf, hs_len); + disposable_free(ssl); /* free up some memory */ + /* note: client renegotiation is not allowed after this */ + break; + + case HS_HELLO_REQUEST: + disposable_new(ssl); + ret = do_client_connect(ssl); + break; + + default: + ret = SSL_ERROR_INVALID_HANDSHAKE; + break; + } + + return ret; +} + +/* + * Do the handshaking from the beginning. + */ +int ICACHE_FLASH_ATTR do_client_connect(SSL *ssl) +{ + int ret = SSL_OK; + + send_client_hello(ssl); /* send the client hello */ + ssl->bm_read_index = 0; + ssl->next_state = HS_SERVER_HELLO; + ssl->hs_status = SSL_NOT_OK; /* not connected */ + + /* sit in a loop until it all looks good */ + if (!IS_SET_SSL_FLAG(SSL_CONNECT_IN_PARTS)) + { + while (ssl->hs_status != SSL_OK) + { +// esp_ssl_sleep(100); + ret = ssl_read(ssl, NULL); + ssl_printf("%s %d %d\n", __func__, __LINE__,ret); + if (ret < SSL_OK) + break; + } + + ssl->hs_status = ret; /* connected? */ + } + + return ret; +} + +/* + * Send the initial client hello. + */ +static int ICACHE_FLASH_ATTR send_client_hello(SSL *ssl) +{ + uint8_t *buf = ssl->bm_data; + time_t tm = 0; //time(NULL); wujg : pass compile first + uint8_t *tm_ptr = &buf[6]; /* time will go here */ + int i, offset; + + buf[0] = HS_CLIENT_HELLO; + buf[1] = 0; + buf[2] = 0; + /* byte 3 is calculated later */ + buf[4] = 0x03; + buf[5] = ssl->version & 0x0f; + + /* client random value - spec says that 1st 4 bytes are big endian time */ + *tm_ptr++ = (uint8_t)(((long)tm & 0xff000000) >> 24); + *tm_ptr++ = (uint8_t)(((long)tm & 0x00ff0000) >> 16); + *tm_ptr++ = (uint8_t)(((long)tm & 0x0000ff00) >> 8); + *tm_ptr++ = (uint8_t)(((long)tm & 0x000000ff)); + if (get_random(SSL_RANDOM_SIZE-4, &buf[10]) < 0) + return SSL_NOT_OK; + + memcpy(ssl->dc->client_random, &buf[6], SSL_RANDOM_SIZE); + offset = 6 + SSL_RANDOM_SIZE; + + /* give session resumption a go */ + if (IS_SET_SSL_FLAG(SSL_SESSION_RESUME)) /* set initially by user */ + { + buf[offset++] = ssl->sess_id_size; + memcpy(&buf[offset], ssl->session_id, ssl->sess_id_size); + offset += ssl->sess_id_size; + CLR_SSL_FLAG(SSL_SESSION_RESUME); /* clear so we can set later */ + } + else + { + /* no session id - because no session resumption just yet */ + buf[offset++] = 0; + } + + buf[offset++] = 0; /* number of ciphers */ + buf[offset++] = NUM_PROTOCOLS*2;/* number of ciphers */ + + /* put all our supported protocols in our request */ + for (i = 0; i < NUM_PROTOCOLS; i++) + { + buf[offset++] = 0; /* cipher we are using */ + buf[offset++] = system_get_data_of_array_8(ssl_prot_prefs, i); + } + + buf[offset++] = 1; /* no compression */ + buf[offset++] = 0; + buf[3] = offset - 4; /* handshake size */ + + return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, offset); +} + +/* + * Process the server hello. + */ +static int ICACHE_FLASH_ATTR process_server_hello(SSL *ssl) +{ + uint8_t *buf = ssl->bm_data; + int pkt_size = ssl->bm_index; + int num_sessions = ssl->ssl_ctx->num_sessions; + uint8_t sess_id_size; + int offset, ret = SSL_OK; + + /* check that we are talking to a TLSv1 server */ + uint8_t version = (buf[4] << 4) + buf[5]; + if (version > SSL_PROTOCOL_VERSION_MAX) + { + version = SSL_PROTOCOL_VERSION_MAX; + } + else if (ssl->version < SSL_PROTOCOL_MIN_VERSION) + { + ret = SSL_ERROR_INVALID_VERSION; + //ssl_display_error(ret); + goto error; + } + + ssl->version = version; + + /* get the server random value */ + memcpy(ssl->dc->server_random, &buf[6], SSL_RANDOM_SIZE); + offset = 6 + SSL_RANDOM_SIZE; /* skip of session id size */ + sess_id_size = buf[offset++]; + + if (sess_id_size > SSL_SESSION_ID_SIZE) + { + ret = SSL_ERROR_INVALID_SESSION; + goto error; + } + + if (num_sessions) + { + ssl->session = ssl_session_update(num_sessions, + ssl->ssl_ctx->ssl_sessions, ssl, &buf[offset]); + memcpy(ssl->session->session_id, &buf[offset], sess_id_size); + + /* pad the rest with 0's */ + if (sess_id_size < SSL_SESSION_ID_SIZE) + { + memset(&ssl->session->session_id[sess_id_size], 0, + SSL_SESSION_ID_SIZE-sess_id_size); + } + } + + memcpy(ssl->session_id, &buf[offset], sess_id_size); + ssl->sess_id_size = sess_id_size; + offset += sess_id_size; + + /* get the real cipher we are using */ + ssl->cipher = buf[++offset]; + ssl->next_state = IS_SET_SSL_FLAG(SSL_SESSION_RESUME) ? + HS_FINISHED : HS_CERTIFICATE; + + offset++; // skip the compr + PARANOIA_CHECK(pkt_size, offset); + ssl->dc->bm_proc_index = offset+1; + +error: + return ret; +} + +/** + * Process the server hello done message. + */ +static int ICACHE_FLASH_ATTR process_server_hello_done(SSL *ssl) +{ + ssl->next_state = HS_FINISHED; + return SSL_OK; +} + +/* + * Send a client key exchange message. + */ +static int ICACHE_FLASH_ATTR send_client_key_xchg(SSL *ssl) +{ + uint8_t *buf = ssl->bm_data; + uint8_t premaster_secret[SSL_SECRET_SIZE]; + int enc_secret_size = -1; + + buf[0] = HS_CLIENT_KEY_XCHG; + buf[1] = 0; + + premaster_secret[0] = 0x03; /* encode the version number */ + premaster_secret[1] = SSL_PROTOCOL_MINOR_VERSION; /* must be TLS 1.1 */ + if (get_random(SSL_SECRET_SIZE-2, &premaster_secret[2]) < 0) + return SSL_NOT_OK; + //DISPLAY_RSA(ssl, ssl->x509_ctx->rsa_ctx); + + /* rsa_ctx->bi_ctx is not thread-safe */ + SSL_CTX_LOCK(ssl->ssl_ctx->mutex); + enc_secret_size = RSA_encrypt(ssl->x509_ctx->rsa_ctx, premaster_secret, + SSL_SECRET_SIZE, &buf[6], 0); + SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); + + buf[2] = (enc_secret_size + 2) >> 8; + buf[3] = (enc_secret_size + 2) & 0xff; + buf[4] = enc_secret_size >> 8; + buf[5] = enc_secret_size & 0xff; + + generate_master_secret(ssl, premaster_secret); + return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, enc_secret_size+6); +} + +/* + * Process the certificate request. + */ +static int ICACHE_FLASH_ATTR process_cert_req(SSL *ssl) +{ + uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index]; + int ret = SSL_OK; + int offset = (buf[2] << 4) + buf[3]; + int pkt_size = ssl->bm_index; + + /* don't do any processing - we will send back an RSA certificate anyway */ + ssl->next_state = HS_SERVER_HELLO_DONE; + SET_SSL_FLAG(SSL_HAS_CERT_REQ); + ssl->dc->bm_proc_index += offset; + PARANOIA_CHECK(pkt_size, offset); +error: + return ret; +} + +/* + * Send a certificate verify message. + */ +static int ICACHE_FLASH_ATTR send_cert_verify(SSL *ssl) +{ + uint8_t *buf = ssl->bm_data; + uint8_t dgst[MD5_SIZE+SHA1_SIZE]; + RSA_CTX *rsa_ctx = ssl->ssl_ctx->rsa_ctx; + int n = 0, ret; + + //DISPLAY_RSA(ssl, rsa_ctx); + + buf[0] = HS_CERT_VERIFY; + buf[1] = 0; + + finished_digest(ssl, NULL, dgst); /* calculate the digest */ + + /* rsa_ctx->bi_ctx is not thread-safe */ + if (rsa_ctx) + { + SSL_CTX_LOCK(ssl->ssl_ctx->mutex); + n = RSA_encrypt(rsa_ctx, dgst, sizeof(dgst), &buf[6], 1); + SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); + + if (n == 0) + { + ret = SSL_ERROR_INVALID_KEY; + goto error; + } + } + + buf[4] = n >> 8; /* add the RSA size (not officially documented) */ + buf[5] = n & 0xff; + n += 2; + buf[2] = n >> 8; + buf[3] = n & 0xff; + ret = send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, n+4); + +error: + return ret; +} + +#endif /* CONFIG_SSL_ENABLE_CLIENT */ diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_tls1_svr.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_tls1_svr.c new file mode 100644 index 0000000..33995a5 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_tls1_svr.c @@ -0,0 +1,495 @@ +/* + * 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. + */ + +#include "ssl/ssl_os_port.h" +#include "ssl/ssl_ssl.h" + +static const uint8_t g_hello_done[] ICACHE_RODATA_ATTR STORE_ATTR = { HS_SERVER_HELLO_DONE, 0, 0, 0 }; + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +static int process_client_hello(SSL *ssl); +static int send_server_hello_sequence(SSL *ssl); +static int send_server_hello(SSL *ssl); +static int send_server_hello_done(SSL *ssl); +static int process_client_key_xchg(SSL *ssl); +#ifdef CONFIG_SSL_CERT_VERIFICATION +static int send_certificate_request(SSL *ssl); +static int process_cert_verify(SSL *ssl); +#endif + +/* + * Establish a new SSL connection to an SSL client. + */ +EXP_FUNC SSL * ICACHE_FLASH_ATTR STDCALL ICACHE_FLASH_ATTR ssl_server_new(SSL_CTX *ssl_ctx, int client_fd) +{ + SSL *ssl; + + ssl = ssl_new(ssl_ctx, client_fd); + ssl->next_state = HS_CLIENT_HELLO; + +#ifdef CONFIG_SSL_FULL_MODE + if (ssl_ctx->chain_length == 0) + ssl_printf("Warning - no server certificate defined\n"); //TTY_FLUSH(); +#endif + + return ssl; +} + +/* + * Process the handshake record. + */ +int ICACHE_FLASH_ATTR do_svr_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len) +{ + int ret = SSL_OK; + ssl->hs_status = SSL_NOT_OK; /* not connected */ + + /* To get here the state must be valid */ +// ssl_printf("%d %s %d\n",handshake_type, __func__, __LINE__); + switch (handshake_type) + { + case HS_CLIENT_HELLO: + if ((ret = process_client_hello(ssl)) == SSL_OK) + ret = send_server_hello_sequence(ssl); + break; + +#ifdef CONFIG_SSL_CERT_VERIFICATION + case HS_CERTIFICATE:/* the client sends its cert */ + ret = process_certificate(ssl, &ssl->x509_ctx); + + if (ret == SSL_OK) /* verify the cert */ + { + int cert_res; + cert_res = x509_verify( + ssl->ssl_ctx->ca_cert_ctx, ssl->x509_ctx); + ret = (cert_res == 0) ? SSL_OK : SSL_X509_ERROR(cert_res); + } + break; + + case HS_CERT_VERIFY: + ret = process_cert_verify(ssl); + add_packet(ssl, buf, hs_len); /* needs to be done after */ + break; +#endif + case HS_CLIENT_KEY_XCHG: + ret = process_client_key_xchg(ssl); + break; + + case HS_FINISHED: + ret = process_finished(ssl, buf, hs_len); + disposable_free(ssl); /* free up some memory */ + break; + } + + return ret; +} + +/* + * Process a client hello message. + */ +static int ICACHE_FLASH_ATTR process_client_hello(SSL *ssl) +{ + uint8_t *buf = ssl->bm_data; + int pkt_size = ssl->bm_index; + int i, j, cs_len, id_len, offset = 6 + SSL_RANDOM_SIZE; + int ret = SSL_OK; + + uint8_t version = (buf[4] << 4) + buf[5]; + ssl->version = ssl->client_version = version; + + if (version > SSL_PROTOCOL_VERSION_MAX) + { + /* use client's version instead */ + ssl->version = SSL_PROTOCOL_VERSION_MAX; + } + else if (version < SSL_PROTOCOL_MIN_VERSION) /* old version supported? */ + { + ret = SSL_ERROR_INVALID_VERSION; + //ssl_display_error(ret); + goto error; + } + + memcpy(ssl->dc->client_random, &buf[6], SSL_RANDOM_SIZE); + + /* process the session id */ + id_len = buf[offset++]; + if (id_len > SSL_SESSION_ID_SIZE) + { + return SSL_ERROR_INVALID_SESSION; + } + +#ifndef CONFIG_SSL_SKELETON_MODE + ssl->session = ssl_session_update(ssl->ssl_ctx->num_sessions, + ssl->ssl_ctx->ssl_sessions, ssl, id_len ? &buf[offset] : NULL); +#endif + + offset += id_len; + cs_len = (buf[offset]<<8) + buf[offset+1]; + offset += 3; /* add 1 due to all cipher suites being 8 bit */ + + PARANOIA_CHECK(pkt_size, offset); + + /* work out what cipher suite we are going to use - client defines + the preference */ + for (i = 0; i < cs_len; i += 2) + { + for (j = 0; j < NUM_PROTOCOLS; j++) + { + if (system_get_data_of_array_8(ssl_prot_prefs, j) == ((buf[offset+i]<<8) + buf[offset+i+1])) /* got a match? */ + { + ssl->cipher = system_get_data_of_array_8(ssl_prot_prefs, j); + goto do_state; + } + } + } + + /* ouch! protocol is not supported */ + ret = SSL_ERROR_NO_CIPHER; + +do_state: +error: + return ret; +} + +#ifdef CONFIG_SSL_ENABLE_V23_HANDSHAKE +/* + * Some browsers use a hybrid SSLv2 "client hello" + */ +int process_sslv23_client_hello(SSL *ssl) +{ + uint8_t *buf = ssl->bm_data; + int bytes_needed = ((buf[0] & 0x7f) << 8) + buf[1]; + int ret = SSL_OK; + + /* we have already read 3 extra bytes so far */ + int read_len = SOCKET_READ(ssl->client_fd, buf, bytes_needed-3); + int cs_len = buf[1]; + int id_len = buf[3]; + int ch_len = buf[5]; + int i, j, offset = 8; /* start at first cipher */ + int random_offset = 0; + + DISPLAY_BYTES(ssl, "received %d bytes", buf, read_len, read_len); + + /* connection has gone, so die */ + if (read_len < 0) + { + return SSL_ERROR_CONN_LOST; + } + + add_packet(ssl, buf, read_len); + + /* now work out what cipher suite we are going to use */ + for (j = 0; j < NUM_PROTOCOLS; j++) + { + for (i = 0; i < cs_len; i += 3) + { + if (ssl_prot_prefs[j] == buf[offset+i]) + { + ssl->cipher = ssl_prot_prefs[j]; + goto server_hello; + } + } + } + + /* ouch! protocol is not supported */ + ret = SSL_ERROR_NO_CIPHER; + goto error; + +server_hello: + /* get the session id */ + offset += cs_len - 2; /* we've gone 2 bytes past the end */ +#ifndef CONFIG_SSL_SKELETON_MODE + ssl->session = ssl_session_update(ssl->ssl_ctx->num_sessions, + ssl->ssl_ctx->ssl_sessions, ssl, id_len ? &buf[offset] : NULL); +#endif + + /* get the client random data */ + offset += id_len; + + /* random can be anywhere between 16 and 32 bytes long - so it is padded + * with 0's to the left */ + if (ch_len == 0x10) + { + random_offset += 0x10; + } + + memcpy(&ssl->dc->client_random[random_offset], &buf[offset], ch_len); + ret = send_server_hello_sequence(ssl); + +error: + return ret; +} +#endif + +/* + * Send the entire server hello sequence + */ +static int ICACHE_FLASH_ATTR send_server_hello_sequence(SSL *ssl) +{ + int ret; + + if ((ret = send_server_hello(ssl)) == SSL_OK) + { +#ifndef CONFIG_SSL_SKELETON_MODE + /* resume handshake? */ + if (IS_SET_SSL_FLAG(SSL_SESSION_RESUME)) + { + if ((ret = send_change_cipher_spec(ssl)) == SSL_OK) + { + ret = send_finished(ssl); + ssl->next_state = HS_FINISHED; + } + } + else +#endif + if ((ret = send_certificate(ssl)) == SSL_OK) + { +#ifdef CONFIG_SSL_CERT_VERIFICATION + /* ask the client for its certificate */ + if (IS_SET_SSL_FLAG(SSL_CLIENT_AUTHENTICATION)) + { + if ((ret = send_certificate_request(ssl)) == SSL_OK) + { + ret = send_server_hello_done(ssl); + ssl->next_state = HS_CERTIFICATE; + } + } + else +#endif + { + ret = send_server_hello_done(ssl); + ssl->next_state = HS_CLIENT_KEY_XCHG; + } + } + } + + return ret; +} + +/* + * Send a server hello message. + */ +static int ICACHE_FLASH_ATTR send_server_hello(SSL *ssl) +{ + uint8_t *buf = ssl->bm_data; + int offset = 0; + + buf[0] = HS_SERVER_HELLO; + buf[1] = 0; + buf[2] = 0; + /* byte 3 is calculated later */ + buf[4] = 0x03; + buf[5] = ssl->version & 0x0f; + + /* server random value */ + if (get_random(SSL_RANDOM_SIZE, &buf[6]) < 0) + return SSL_NOT_OK; + memcpy(ssl->dc->server_random, &buf[6], SSL_RANDOM_SIZE); + offset = 6 + SSL_RANDOM_SIZE; + +#ifndef CONFIG_SSL_SKELETON_MODE + if (IS_SET_SSL_FLAG(SSL_SESSION_RESUME)) + { + /* retrieve id from session cache */ + buf[offset++] = SSL_SESSION_ID_SIZE; + memcpy(&buf[offset], ssl->session->session_id, SSL_SESSION_ID_SIZE); + memcpy(ssl->session_id, ssl->session->session_id, SSL_SESSION_ID_SIZE); + ssl->sess_id_size = SSL_SESSION_ID_SIZE; + offset += SSL_SESSION_ID_SIZE; + } + else /* generate our own session id */ +#endif + { +#ifndef CONFIG_SSL_SKELETON_MODE + buf[offset++] = SSL_SESSION_ID_SIZE; + get_random(SSL_SESSION_ID_SIZE, &buf[offset]); + memcpy(ssl->session_id, &buf[offset], SSL_SESSION_ID_SIZE); + ssl->sess_id_size = SSL_SESSION_ID_SIZE; + + /* store id in session cache */ + if (ssl->ssl_ctx->num_sessions) + { + memcpy(ssl->session->session_id, + ssl->session_id, SSL_SESSION_ID_SIZE); + } + + offset += SSL_SESSION_ID_SIZE; +#else + buf[offset++] = 0; /* don't bother with session id in skelton mode */ +#endif + } + + buf[offset++] = 0; /* cipher we are using */ + buf[offset++] = ssl->cipher; + buf[offset++] = 0; /* no compression */ + buf[3] = offset - 4; /* handshake size */ + return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, offset); +} + +/* + * Send the server hello done message. + */ +static int ICACHE_FLASH_ATTR send_server_hello_done(SSL *ssl) +{ + uint8_t g_hello_done_ram[4]; + + memcpy(g_hello_done_ram, g_hello_done, sizeof(g_hello_done)); + + return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, + g_hello_done_ram, sizeof(g_hello_done)); +} + +/* + * Pull apart a client key exchange message. Decrypt the pre-master key (using + * our RSA private key) and then work out the master key. Initialise the + * ciphers. + */ +static int ICACHE_FLASH_ATTR process_client_key_xchg(SSL *ssl) +{ + uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index]; + int pkt_size = ssl->bm_index; + int premaster_size, secret_length = (buf[2] << 8) + buf[3]; +// uint8_t premaster_secret[MAX_KEY_BYTE_SIZE]; + uint8* premaster_secret = (uint8*)SSL_ZALLOC(MAX_KEY_BYTE_SIZE); + RSA_CTX *rsa_ctx = ssl->ssl_ctx->rsa_ctx; + int offset = 4; + int ret = SSL_OK; + + if (rsa_ctx == NULL) + { + ret = SSL_ERROR_NO_CERT_DEFINED; + goto error; + } + + /* is there an extra size field? */ + if ((secret_length - 2) == rsa_ctx->num_octets) + offset += 2; + + PARANOIA_CHECK(pkt_size, rsa_ctx->num_octets+offset); + + /* rsa_ctx->bi_ctx is not thread-safe */ + SSL_CTX_LOCK(ssl->ssl_ctx->mutex); + premaster_size = RSA_decrypt(rsa_ctx, &buf[offset], premaster_secret, + MAX_KEY_BYTE_SIZE, 1); + SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); + + if (premaster_size != SSL_SECRET_SIZE || + premaster_secret[0] != 0x03 || /* must be the same as client + offered version */ + premaster_secret[1] != (ssl->client_version & 0x0f)) + { + /* guard against a Bleichenbacher attack */ + if (get_random(SSL_SECRET_SIZE, premaster_secret) < 0) + return SSL_NOT_OK; + + /* and continue - will die eventually when checking the mac */ + } + +#if 0 + print_blob("pre-master", premaster_secret, SSL_SECRET_SIZE); +#endif + + generate_master_secret(ssl, premaster_secret); + +#ifdef CONFIG_SSL_CERT_VERIFICATION + ssl->next_state = IS_SET_SSL_FLAG(SSL_CLIENT_AUTHENTICATION) ? + HS_CERT_VERIFY : HS_FINISHED; +#else + ssl->next_state = HS_FINISHED; +#endif + + ssl->dc->bm_proc_index += rsa_ctx->num_octets+offset; +error: + SSL_FREE(premaster_secret); + return ret; +} + +#ifdef CONFIG_SSL_CERT_VERIFICATION +static const uint8_t g_cert_request[] ICACHE_RODATA_ATTR STORE_ATTR = { HS_CERT_REQ, 0, 0, 4, 1, 0, 0, 0 }; + +/* + * Send the certificate request message. + */ +static int ICACHE_FLASH_ATTR send_certificate_request(SSL *ssl) +{ + uint8_t g_cert_request_ram[8]; + + memcpy(g_cert_request_ram, g_cert_request, sizeof(g_cert_request)); + + return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, + g_cert_request_ram, sizeof(g_cert_request)); +} + +/* + * Ensure the client has the private key by first decrypting the packet and + * then checking the packet digests. + */ +static int ICACHE_FLASH_ATTR process_cert_verify(SSL *ssl) +{ + uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index]; + int pkt_size = ssl->bm_index; +// uint8_t dgst_buf[MAX_KEY_BYTE_SIZE]; + uint8* dgst_buf = (uint8*)SSL_ZALLOC(MAX_KEY_BYTE_SIZE); + uint8_t dgst[MD5_SIZE+SHA1_SIZE]; + X509_CTX *x509_ctx = ssl->x509_ctx; + int ret = SSL_OK; + int n; + + PARANOIA_CHECK(pkt_size, x509_ctx->rsa_ctx->num_octets+6); + //DISPLAY_RSA(ssl, x509_ctx->rsa_ctx); + + /* rsa_ctx->bi_ctx is not thread-safe */ + SSL_CTX_LOCK(ssl->ssl_ctx->mutex); + n = RSA_decrypt(x509_ctx->rsa_ctx, &buf[6], dgst_buf, MAX_KEY_BYTE_SIZE, 0); + SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); + + if (n != SHA1_SIZE + MD5_SIZE) + { + ret = SSL_ERROR_INVALID_KEY; + goto end_cert_vfy; + } + + finished_digest(ssl, NULL, dgst); /* calculate the digest */ + if (memcmp(dgst_buf, dgst, MD5_SIZE + SHA1_SIZE)) + { + ret = SSL_ERROR_INVALID_KEY; + } + +end_cert_vfy: + ssl->next_state = HS_FINISHED; +error: + SSL_FREE(dgst_buf); + return ret; +} + +#endif diff --git a/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_x509.c b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_x509.c new file mode 100644 index 0000000..f4f3a36 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/third_party/ssl/ssl/ssl_x509.c @@ -0,0 +1,621 @@ +/* + * 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 x509.c + * + * Certificate processing. + */ + +#include "ssl/ssl_os_port.h" +#include "ssl/ssl_ssl.h" +#include "ssl/ssl_crypto_misc.h" + +#include "lwip/sockets.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; +#endif + +#ifdef CONFIG_SSL_CERT_VERIFICATION +/** + * Retrieve the signature from a certificate. + */ +static const uint8_t * ICACHE_FLASH_ATTR get_signature(const uint8_t *asn1_sig, int *len) +{ + int offset = 0; + const uint8_t *ptr = NULL; + + if (asn1_next_obj(asn1_sig, &offset, ASN1_SEQUENCE) < 0 || + asn1_skip_obj(asn1_sig, &offset, ASN1_SEQUENCE)) + goto end_get_sig; + + if (asn1_sig[offset++] != ASN1_OCTET_STRING) + goto end_get_sig; + *len = get_asn1_length(asn1_sig, &offset); + ptr = &asn1_sig[offset]; /* all ok */ + +end_get_sig: + return ptr; +} + +#endif + +/** + * Construct a new x509 object. + * @return 0 if ok. < 0 if there was a problem. + */ +int ICACHE_FLASH_ATTR x509_new(const uint8_t *cert, int *len, X509_CTX **ctx) +{ + int begin_tbs, end_tbs; + int ret = X509_NOT_OK, offset = 0, cert_size = 0; + X509_CTX *x509_ctx; + BI_CTX *bi_ctx; + + *ctx = (X509_CTX *)SSL_ZALLOC(sizeof(X509_CTX)); + x509_ctx = *ctx; + + /* get the certificate size */ + asn1_skip_obj(cert, &cert_size, ASN1_SEQUENCE); + + if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0) + goto end_cert; + + begin_tbs = offset; /* start of the tbs */ + end_tbs = begin_tbs; /* work out the end of the tbs */ + asn1_skip_obj(cert, &end_tbs, ASN1_SEQUENCE); + + if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0) + goto end_cert; + + if (cert[offset] == ASN1_EXPLICIT_TAG) /* optional version */ + { + if (asn1_version(cert, &offset, x509_ctx)) + goto end_cert; + } + + if (asn1_skip_obj(cert, &offset, ASN1_INTEGER) || /* serial number */ + asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0) + goto end_cert; + + /* make sure the signature is ok */ + if (asn1_signature_type(cert, &offset, x509_ctx)) + { + ret = X509_VFY_ERROR_UNSUPPORTED_DIGEST; + goto end_cert; + } + + if (asn1_name(cert, &offset, x509_ctx->ca_cert_dn) || + asn1_validity(cert, &offset, x509_ctx) || + asn1_name(cert, &offset, x509_ctx->cert_dn) || + asn1_public_key(cert, &offset, x509_ctx)) + { + goto end_cert; + } + + bi_ctx = x509_ctx->rsa_ctx->bi_ctx; +#ifdef CONFIG_SSL_CERT_VERIFICATION /* only care if doing verification */ + /* use the appropriate signature algorithm */ + switch (x509_ctx->sig_type) + { + case SIG_TYPE_MD5: + { + MD5_CTX md5_ctx; + uint8_t md5_dgst[MD5_SIZE]; + MD5_Init(&md5_ctx); + MD5_Update(&md5_ctx, &cert[begin_tbs], end_tbs-begin_tbs); + MD5_Final(md5_dgst, &md5_ctx); + x509_ctx->digest = bi_import(bi_ctx, md5_dgst, MD5_SIZE); + } + break; + + case SIG_TYPE_SHA1: + { + SHA1_CTX sha_ctx; + uint8_t sha_dgst[SHA1_SIZE]; + SHA1_Init(&sha_ctx); + SHA1_Update(&sha_ctx, &cert[begin_tbs], end_tbs-begin_tbs); + SHA1_Final(sha_dgst, &sha_ctx); + x509_ctx->digest = bi_import(bi_ctx, sha_dgst, SHA1_SIZE); + } + break; + + case SIG_TYPE_SHA256: + { + SHA256_CTX sha256_ctx; + uint8_t sha256_dgst[SHA256_SIZE]; + SHA256_Init(&sha256_ctx); + SHA256_Update(&sha256_ctx, &cert[begin_tbs], end_tbs-begin_tbs); + SHA256_Final(sha256_dgst, &sha256_ctx); + x509_ctx->digest = bi_import(bi_ctx, sha256_dgst, SHA256_SIZE); + } + break; + + case SIG_TYPE_SHA384: + { + SHA384_CTX sha384_ctx; + uint8_t sha384_dgst[SHA384_SIZE]; + SHA384_Init(&sha384_ctx); + SHA384_Update(&sha384_ctx, &cert[begin_tbs], end_tbs-begin_tbs); + SHA384_Final(sha384_dgst, &sha384_ctx); + x509_ctx->digest = bi_import(bi_ctx, sha384_dgst, SHA384_SIZE); + } + break; + + case SIG_TYPE_SHA512: + { + SHA512_CTX sha512_ctx; + uint8_t sha512_dgst[SHA512_SIZE]; + SHA512_Init(&sha512_ctx); + SHA512_Update(&sha512_ctx, &cert[begin_tbs], end_tbs-begin_tbs); + SHA512_Final(sha512_dgst, &sha512_ctx); + x509_ctx->digest = bi_import(bi_ctx, sha512_dgst, SHA512_SIZE); + } + break; + } + + if (cert[offset] == ASN1_V3_DATA) + { + int suboffset; + + ++offset; + get_asn1_length(cert, &offset); + + if ((suboffset = asn1_find_subjectaltname(cert, offset)) > 0) + { + if (asn1_next_obj(cert, &suboffset, ASN1_OCTET_STRING) > 0) + { + int altlen; + + if ((altlen = asn1_next_obj(cert, + &suboffset, ASN1_SEQUENCE)) > 0) + { + int endalt = suboffset + altlen; + int totalnames = 0; + + while (suboffset < endalt) + { + int type = cert[suboffset++]; + int dnslen = get_asn1_length(cert, &suboffset); + + if (type == ASN1_CONTEXT_DNSNAME) + { + x509_ctx->subject_alt_dnsnames = (char**) + SSL_REALLOC(x509_ctx->subject_alt_dnsnames, + (totalnames + 2) * sizeof(char*)); + x509_ctx->subject_alt_dnsnames[totalnames] = + (char*)SSL_MALLOC(dnslen + 1); + x509_ctx->subject_alt_dnsnames[totalnames+1] = NULL; + memcpy(x509_ctx->subject_alt_dnsnames[totalnames], + cert + suboffset, dnslen); + x509_ctx->subject_alt_dnsnames[ + totalnames][dnslen] = 0; + ++totalnames; + } + + suboffset += dnslen; + } + } + } + } + } + + offset = end_tbs; /* skip the rest of v3 data */ + if (asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) || + asn1_signature(cert, &offset, x509_ctx)) + goto end_cert; +#endif + ret = X509_OK; +end_cert: + if (len) + { + *len = cert_size; + } + + if (ret) + { +#ifdef CONFIG_SSL_FULL_MODE + ssl_printf("Error: Invalid X509 ASN.1 file (%s)\n", + x509_display_error(ret)); +#endif + x509_free(x509_ctx); + *ctx = NULL; + } + + return ret; +} + +/** + * Free an X.509 object's resources. + */ +void ICACHE_FLASH_ATTR x509_free(X509_CTX *x509_ctx) +{ + X509_CTX *next; + int i; + + if (x509_ctx == NULL) /* if already null, then don't bother */ + return; + + for (i = 0; i < X509_NUM_DN_TYPES; i++) + { + SSL_FREE(x509_ctx->ca_cert_dn[i]); + SSL_FREE(x509_ctx->cert_dn[i]); + } + + SSL_FREE(x509_ctx->signature); + +#ifdef CONFIG_SSL_CERT_VERIFICATION + if (x509_ctx->digest) + { + bi_free(x509_ctx->rsa_ctx->bi_ctx, x509_ctx->digest); + } + + if (x509_ctx->subject_alt_dnsnames) + { + for (i = 0; x509_ctx->subject_alt_dnsnames[i]; ++i) + SSL_FREE(x509_ctx->subject_alt_dnsnames[i]); + + SSL_FREE(x509_ctx->subject_alt_dnsnames); + } +#endif + + RSA_free(x509_ctx->rsa_ctx); + next = x509_ctx->next; + SSL_FREE(x509_ctx); + x509_free(next); /* clear the chain */ +} + +#ifdef CONFIG_SSL_CERT_VERIFICATION +/** + * Take a signature and decrypt it. + */ +static bigint *ICACHE_FLASH_ATTR sig_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len, + bigint *modulus, bigint *pub_exp) +{ + int i, size; + bigint *decrypted_bi, *dat_bi; + bigint *bir = NULL; + uint8_t *block = (uint8_t *)SSL_MALLOC(sig_len); + + /* decrypt */ + dat_bi = bi_import(ctx, sig, sig_len); + ctx->mod_offset = BIGINT_M_OFFSET; + + /* convert to a normal block */ + decrypted_bi = bi_mod_power2(ctx, dat_bi, modulus, pub_exp); + + bi_export(ctx, decrypted_bi, block, sig_len); + ctx->mod_offset = BIGINT_M_OFFSET; + + i = 10; /* start at the first possible non-padded byte */ + while (block[i++] && i < sig_len); + size = sig_len - i; + + /* get only the bit we want */ + if (size > 0) + { + int len; + const uint8_t *sig_ptr = get_signature(&block[i], &len); + + if (sig_ptr) + { + bir = bi_import(ctx, sig_ptr, len); + } + } + + /* save a few bytes of memory */ + bi_clear_cache(ctx); + + SSL_FREE(block); + return bir; +} + +/** + * Do some basic checks on the certificate chain. + * + * Certificate verification consists of a number of checks: + * - The date of the certificate is after the start date. + * - The date of the certificate is before the finish date. + * - A root certificate exists in the certificate store. + * - That the certificate(s) are not self-signed. + * - The certificate chain is valid. + * - The signature of the certificate is valid. + */ +int ICACHE_FLASH_ATTR x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert) +{ + int ret = X509_OK, i = 0; + bigint *cert_sig; + X509_CTX *next_cert = NULL; + BI_CTX *ctx = NULL; + bigint *mod = NULL, *expn = NULL; + int match_ca_cert = 0; + struct timeval tv; + uint8_t is_self_signed = 0; + + if (cert == NULL) + { + ret = X509_VFY_ERROR_NO_TRUSTED_CERT; + goto end_verify; + } + + /* a self-signed certificate that is not in the CA store - use this + to check the signature */ + if (asn1_compare_dn(cert->ca_cert_dn, cert->cert_dn) == 0) + { +#if CONFIG_SSL_DISPLAY_MODE + os_printf("a self-signed certificate that is not in the CA store\n"); +#endif + is_self_signed = 1; + ctx = cert->rsa_ctx->bi_ctx; + mod = cert->rsa_ctx->m; + expn = cert->rsa_ctx->e; + } + + gettimeofday(&tv, (void*)&cert->not_before); +#if CONFIG_SSL_DISPLAY_MODE + os_printf("before %u, tv_sec %u, after %u\n",cert->not_before, tv.tv_sec, cert->not_after); +#endif + /* check the not before date */ + if (tv.tv_sec < cert->not_before) + { + ret = X509_VFY_ERROR_NOT_YET_VALID; + goto end_verify; + } + + /* check the not after date */ + if (tv.tv_sec > cert->not_after) + { + ret = X509_VFY_ERROR_EXPIRED; + goto end_verify; + } + + next_cert = cert->next; + + /* last cert in the chain - look for a trusted cert */ + if (next_cert == NULL) + { + if (ca_cert_ctx != NULL) + { +#if CONFIG_SSL_DISPLAY_MODE + os_printf("look for a trusted cert\n"); +#endif + /* go thu the CA store */ + while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i]) + { + if (asn1_compare_dn(cert->ca_cert_dn, + ca_cert_ctx->cert[i]->cert_dn) == 0) + { + /* use this CA certificate for signature verification */ +#if CONFIG_SSL_DISPLAY_MODE + os_printf("use the CA certificate for signature verification\n"); +#endif + match_ca_cert = 1; + ctx = ca_cert_ctx->cert[i]->rsa_ctx->bi_ctx; + mod = ca_cert_ctx->cert[i]->rsa_ctx->m; + expn = ca_cert_ctx->cert[i]->rsa_ctx->e; + break; + } + + i++; + } + } + + /* couldn't find a trusted cert (& let self-signed errors + be returned) */ + if (!match_ca_cert && !is_self_signed) + { + ret = X509_VFY_ERROR_NO_TRUSTED_CERT; + goto end_verify; + } + } + else if (asn1_compare_dn(cert->ca_cert_dn, next_cert->cert_dn) != 0) + { + /* check the chain */ + ret = X509_VFY_ERROR_INVALID_CHAIN; + goto end_verify; + } + else /* use the next certificate in the chain for signature verify */ + { + ctx = next_cert->rsa_ctx->bi_ctx; + mod = next_cert->rsa_ctx->m; + expn = next_cert->rsa_ctx->e; + } + + /* cert is self signed */ + if (!match_ca_cert && is_self_signed) + { + ret = X509_VFY_ERROR_SELF_SIGNED; + goto end_verify; + } + + /* check the signature */ + cert_sig = sig_verify(ctx, cert->signature, cert->sig_len, + bi_clone(ctx, mod), bi_clone(ctx, expn)); + + if (cert_sig && cert->digest) + { + if (bi_compare(cert_sig, cert->digest) != 0) + ret = X509_VFY_ERROR_BAD_SIGNATURE; + +#if CONFIG_SSL_DISPLAY_MODE + os_printf("check the signature ok\n"); +#endif +// bi_free(ctx, cert_sig);//comment the line for check signature by LiuH at 20150.06.11 + } + else + { + ret = X509_VFY_ERROR_BAD_SIGNATURE; + } + + if (cert_sig != NULL) + bi_free(ctx, cert_sig);//add the line for check signature by LiuH at 2015.06.11 + + if (ret) + goto end_verify; + + /* go down the certificate chain using recursion. */ + if (next_cert != NULL) + { + ret = x509_verify(ca_cert_ctx, next_cert); + } + +end_verify: + return ret; +} +#endif + +#if defined (CONFIG_SSL_FULL_MODE) +/** + * Used for diagnostics. + */ +static const char *not_part_of_cert = ""; +void ICACHE_FLASH_ATTR x509_print(const X509_CTX *cert, CA_CERT_CTX *ca_cert_ctx) +{ + if (cert == NULL) + return; + + ssl_printf("=== CERTIFICATE ISSUED TO ===\n"); + ssl_printf("Common Name (CN):\t\t"); + ssl_printf("%s\n", cert->cert_dn[X509_COMMON_NAME] ? + cert->cert_dn[X509_COMMON_NAME] : not_part_of_cert); + + ssl_printf("Organization (O):\t\t"); + ssl_printf("%s\n", cert->cert_dn[X509_ORGANIZATION] ? + cert->cert_dn[X509_ORGANIZATION] : not_part_of_cert); + + ssl_printf("Organizational Unit (OU):\t"); + ssl_printf("%s\n", cert->cert_dn[X509_ORGANIZATIONAL_UNIT] ? + cert->cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert); + + ssl_printf("=== CERTIFICATE ISSUED BY ===\n"); + ssl_printf("Common Name (CN):\t\t"); + ssl_printf("%s\n", cert->ca_cert_dn[X509_COMMON_NAME] ? + cert->ca_cert_dn[X509_COMMON_NAME] : not_part_of_cert); + + ssl_printf("Organization (O):\t\t"); + ssl_printf("%s\n", cert->ca_cert_dn[X509_ORGANIZATION] ? + cert->ca_cert_dn[X509_ORGANIZATION] : not_part_of_cert); + + ssl_printf("Organizational Unit (OU):\t"); + ssl_printf("%s\n", cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT] ? + cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert); + + ssl_printf("Not Before:\t\t\t%d\n", cert->not_before); + ssl_printf("Not After:\t\t\t%d\n", cert->not_after); + ssl_printf("RSA bitsize:\t\t\t%d\n", cert->rsa_ctx->num_octets*8); + ssl_printf("Sig Type:\t\t\t"); + switch (cert->sig_type) + { + case SIG_TYPE_MD2: + ssl_printf("MD2\n"); + break; + case SIG_TYPE_MD5: + ssl_printf("MD5\n"); + break; + case SIG_TYPE_SHA1: + ssl_printf("SHA1\n"); + break; + case SIG_TYPE_SHA256: + ssl_printf("SHA256\n"); + break; + case SIG_TYPE_SHA384: + ssl_printf("SHA384\n"); + break; + case SIG_TYPE_SHA512: + ssl_printf("SHA512\n"); + break; + default: + ssl_printf("Unrecognized: %d\n", cert->sig_type); + break; + } + + if (ca_cert_ctx) + { + ssl_printf("Verify:\t\t\t\t%s\n", + x509_display_error(x509_verify(ca_cert_ctx, cert))); + } + +#if 0 + print_blob("Signature", cert->signature, cert->sig_len); + bi_print("Modulus", cert->rsa_ctx->m); + bi_print("Pub Exp", cert->rsa_ctx->e); +#endif + + if (ca_cert_ctx) + { + x509_print(cert->next, ca_cert_ctx); + } + + //TTY_FLUSH(); +} + +#if 0 +const char * ICACHE_FLASH_ATTR x509_display_error(int error) +{ + switch (error) + { + case X509_OK: + return "Certificate verify successful"; + + case X509_NOT_OK: + return "X509 not ok"; + + case X509_VFY_ERROR_NO_TRUSTED_CERT: + return "No trusted cert is available"; + + case X509_VFY_ERROR_BAD_SIGNATURE: + return "Bad signature"; + + case X509_VFY_ERROR_NOT_YET_VALID: + return "Cert is not yet valid"; + + case X509_VFY_ERROR_EXPIRED: + return "Cert has expired"; + + case X509_VFY_ERROR_SELF_SIGNED: + return "Cert is self-signed"; + + case X509_VFY_ERROR_INVALID_CHAIN: + return "Chain is invalid (check order of certs)"; + + case X509_VFY_ERROR_UNSUPPORTED_DIGEST: + return "Unsupported digest"; + + case X509_INVALID_PRIV_KEY: + return "Invalid private key"; + + default: + return "Unknown"; + } +} +#endif + +#endif /* CONFIG_SSL_FULL_MODE */ + diff --git a/Distrib/ESPressif/RTOS/1.5.0/tools/gen_appbin.py b/Distrib/ESPressif/RTOS/1.5.0/tools/gen_appbin.py new file mode 100644 index 0000000..26a510c --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/tools/gen_appbin.py @@ -0,0 +1,272 @@ +#!/usr/bin/python +# +# File : gen_appbin.py +# This file is part of Espressif's generate bin script. +# Copyright (C) 2013 - 2016, Espressif Systems +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of version 3 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . + +"""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 = 'xtensa-lx106-elf-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) + + 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/Distrib/ESPressif/RTOS/1.5.0/tools/make_cacert.py b/Distrib/ESPressif/RTOS/1.5.0/tools/make_cacert.py new file mode 100644 index 0000000..e7faf4d --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/tools/make_cacert.py @@ -0,0 +1,41 @@ +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/Distrib/ESPressif/RTOS/1.5.0/tools/make_cert.py b/Distrib/ESPressif/RTOS/1.5.0/tools/make_cert.py new file mode 100644 index 0000000..9a5b057 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/tools/make_cert.py @@ -0,0 +1,53 @@ +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/Distrib/ESPressif/RTOS/1.5.0/tools/makefile.sh b/Distrib/ESPressif/RTOS/1.5.0/tools/makefile.sh new file mode 100644 index 0000000..df37d51 --- /dev/null +++ b/Distrib/ESPressif/RTOS/1.5.0/tools/makefile.sh @@ -0,0 +1,92 @@ +# * Redistributions in binary form must 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. +# + +# +# Generate the certificates and keys for testing. +# + +PROJECT_NAME="TLS Project" + +# 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 + +cat > certs.conf << EOF +[ req ] +distinguished_name = req_distinguished_name +prompt = no + +[ req_distinguished_name ] + O = $PROJECT_NAME + CN = 127.0.0.1 +EOF + +cat > device_cert.conf << EOF +[ req ] +distinguished_name = req_distinguished_name +prompt = no + +[ req_distinguished_name ] + O = $PROJECT_NAME Device Certificate +EOF + +# private key generation +openssl genrsa -out TLS.ca_key.pem 1024 +openssl genrsa -out TLS.key_1024.pem 1024 + +# convert private keys into DER format +openssl rsa -in TLS.key_1024.pem -out TLS.key_1024 -outform DER + +# cert requests +openssl req -out TLS.ca_x509.req -key TLS.ca_key.pem -new \ + -config ./ca_cert.conf +openssl req -out TLS.x509_1024.req -key TLS.key_1024.pem -new \ + -config ./certs.conf + +# generate the actual certs. +openssl x509 -req -in TLS.ca_x509.req -out TLS.ca_x509.pem \ + -sha1 -days 5000 -signkey TLS.ca_key.pem +openssl x509 -req -in TLS.x509_1024.req -out TLS.x509_1024.pem \ + -sha1 -CAcreateserial -days 5000 \ + -CA TLS.ca_x509.pem -CAkey TLS.ca_key.pem + +# some cleanup +rm TLS*.req +rm *.conf + +openssl x509 -in TLS.ca_x509.pem -outform DER -out TLS.ca_x509.cer +openssl x509 -in TLS.x509_1024.pem -outform DER -out TLS.x509_1024.cer + +# +# Generate the certificates and keys for encrypt. +# + +# 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

    Z;RzC>78ZqM{emj72mgiawrx% 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 literal 0 HcmV?d00001 diff --git a/Distrib/ESPressif/RTOS/1.5.0/lib/libmain.a b/Distrib/ESPressif/RTOS/1.5.0/lib/libmain.a new file mode 100644 index 0000000000000000000000000000000000000000..6a984b5c6dd942b05b73553a60ebc043aba6c570 GIT binary patch literal 199374 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 fw&#oaZ?Trme~Y!}jt3jd=D)?-^T_GoRVn z&14hW#h#y%(XDbDt9yuQ7ZVfJv2FY4D67>bvh@F2tx-`iZQBWbQe}g|xYA%~{b%{{ z;pYs7e>HCGU@-hU@#_$Sf$>7G|L3FervSsh6HRqKHHg>(>Fvgh0E5X_oK?eMnpv7pJ~!@V{AH@|?kc|3X7R)lvT&|HU?_ z5WBW4xh)XFQ#5sPHeuiVv+fc*U1qGgSOf#B;k06>lR} zs*-H*h}p?$sgA6IM0;96VrEXJ!=P8B=clE)DGJgY6Vs+8rsbsgQm3Z5t6`QuEzjL0 zY`kU{f@#N@*C^t62Us%W`ht*EKJn@H2= zW~Tb`f|kfd)iSaZGgH%Y9GU5vzR%{}y_#FE4%XCp=t+k?IV&yESEtIN_V(rE-ef$; zi%D@{aQbpx;K(=mIvS4QYuW0{Uqvhxz{$pvn9 z)FIDHrypu8YfnX+d6X?EO!m^z&eI?5Jax45JO}MOb=iekUS+BCv=fcyF-BSM)Xd3V z<*D;5pPlPnZ|Xelv`+AGqO_@K$XplpJo$ta_v7@;tgOU*droR@wp)W|=Ae=uWityB z!F9I#(3p^xbzW+HZgOur#3%L&zUqW%)|Y`tNNJ#GYc|29T34h3@zN**q~mekYDJU z5#$Nn@7$__g?V|o`HnPK2g;1pG@ja#nVX|)5=VYwYJTzrj23;PD6M<5D6Ob#ep+f~ z3Y~%a0^H>6xU;%0N^gq$MLy;?x4T-3-hhpVn<)ltT0XkW+lyyIs=``9Z+qeH7N^y> zkJFzR;E7XkqvN#U?bw3=bqcq}Q%bkCQ%X)A1-XU!y0%hT+C?U2+j9zaZJ=@|*d3t7 zStF%RFVwC4fJ0h-ey+q4x5p zIdP|2y4Ke-568F64|ryXvamQ&Ru(V3bRw&dp2o%uQuh{$fLd5 zW1{t}R(tP8gmd?q2k%%ajjOU!#cv%-&ELBQqpu!HB@nmO3unnaV@iyHYYd7JEO25D=p16z0x*6 zEyXp^11zXT|JxmyWePGdGrM=Y%AeZa)+sSA)3r*e^j zvtW|s(_UeLeS&M;C=;v-6ZycBnpWU?Li5OUHn!3;O`e7UE6RFh=S`$bFSRUnlU#Yb z@l_BA`BF=NI*e8QatgE4@-vCE+cRHY8XiRScPuKj)u;P|5cO`|L4{n7dRR{M@Ho+< zAoG1LOVAAN6Pr>b<`>v;y{^%Mj1+rLVybJiuh33~wt#j&Q?CV|Qv>rt2bDbylVIwct9cLDHn}Dd`!;n{(>t6xj_RHI)Zh#4m zn9H0PI*%m*bbxpRrFSK%^-)Qxy(>wrcO{{9Rk9!}QM*eP6!Lwac+~Z{ z#TEFn(Y>5wK3^{C9k~{w%;nUtKa1N;?#sZ#yJvYW5-?ZmZ{VJlEG)pJlULwcb5kD-#bcXkXo0%iW>?Pk?wS;AMdsJ9Baxp>e-PoQtzL^YZf3vh677n)B&8 zJPL!0oi`peCCtuk4H%RF3s8WwQbSo7UE8b9T$FE= zn};PX9$&P(RzacbW~kMjH#u=b^UTt!ppARov$gBQKC>`h3iuAeeXhgxdMWTEkdE6_ zYF@7X#TMO*90wlF3;5o{9WoZO7vjCO{*{WekjEtM)aUDdyx>%(CcD-~REkH8OxIG* zX(&3_^FcwCpguoQ_mdT8G1U|)cC@eeRp>}|M?hS@J~uHvH=p+~Hmnan9Ke{%@J7$a zS#qc3Byy1XD9442J=5JI+aLqW3}2;WUP?LTZr(GVbBJ{2sTSAHIlyOwV!q0-7i8$( z0IFWd$SrVqO^3o+L5}N;U_qaj-9+SAQl3wG4Wn`uC zZWvtos!m=S$Fb*7an1E!Q@AtBtqz36O(EtHHx2I5cy7o+!{{E9cx{4t40ex4JZ3ph z=5f~-+-g&f`*Ogo%#?h4p6+cc9by1_YoHar+^Wmg^QBjOyT4STZ?BqgBx3OToCBf9 zi(EVU*?Ss5o|iA)wZ-}(&;72f-O05q*tlJS_L#2aks!BBDzq$*r+HqA_N>EmdX>|% zIAT0rV6dEa_wY4oiP_XMLmrFKjaLN8x|_Z}%VSC9ot2ob|4FgR*J_%cW_RfC-Qop} z*17qax;L~=Jr+jpKP}ehIGfO^ben&iTHYVLZS@`GG-WI67h}#0{bRjQrslAvT;oM3 zvDCt4_{z}y`pDt4Gv93{W~621>DpZQW6cx!vmY$N+^<08q!)TOsMbY^j$H9p%&UqH zzN1KUpMk{Lv;o65^eCfccr}=&b~^JYl#eg8DEY5=B=NF#0c&CxfP_u}4rGSBcrgau{n~t1X zUroUuW$|5)kEW1W-e*G^~A3ZzIqw;gSMt4d89j+UQgV{}*4>@kl=Sbr#YCXNwxI;?~nn1Vm z!`%oEG~6-gwm(j%<_0-K8_#X$?wioPjyh;t&Y@4LoSl}Pn?Fr%>B1czKgMdE+orNu zUWrG0F+~LwvlUURcM)SCFN72-VX6$-g1n4^`T{ch#{)=Vo4?G_1H} zbdAc*t^`?LY<9YGzygEiNys?xiZ)Qne^7*jh%#E=^%E z2*sgDt8oW4G4+eWjMg@`hyk`RTTH8naZI{IWFd)|(f?wrSv&SuYyRB)UU%bq4sYSf zH_DUOyk>%zc)P*4S)IO?^YpK3XRGZz{d!GNLpwd{^OD=yc|M$dhIaP(Oa?@(WHK&d z1Coes{V(p=U#HoprhxCt0x%v9FJN8f%epjh)@8A(OG9T}p3qL+$XS=iG(~-9UFK22 zcIa*kuit6DwXH3@Ri~9qx^&urq|>&@Ae+r`xs{*s0j+E#TA6KlpLW>V>3gcCXyf!< zNJY#z*~i43sJUPobt-6#aZhkb)8Mf|E%t|7E+4295gA@TaAZW+ z@K!tamqrW>pAj+s@bR);O<93xiy<-yZim_XCfobv+xr`j(@)eFWwx;5Sz*XGqOoS# z`xw6x`a@;2Li->q+!SpwS?6JRGVid++o#JjJM%sfc{`nXs4w!8L;F4A*MEQigkhn5 z^F#YjsBfBkyzKJ9YJnqn>@Hnfv+}^I_gj+pSL^jv8QLwPYIyyKM&Yd@+JtwB=#FcB zn?6mUqtQ%}Rd$4q`Yd$hsn8LZLx(>d98?rmPMT*;HXFu-h}4{K_Ag2|LeB6nnu0uAvN>R}xf1OrSo6((m^kv% zAyimx4l0^rggmuo(R%1?`R2;uCc~8AylK|O=8D$P(1lYV1O|o`tuR7d-ZTP0(3YkDlOc^BWqjcT{FkDFPi7D zb+;AIE524CDXDO3#ZBqO83CnjZFy~NNo{S1@*K8|LhF>`h3UofDr5wd zXfqrhYHP!lm9(|(F^FC7gkLA&kIIw!BxfnM8F6PJZFPxjum zs_a#`VgI2MM8|3cHoaY3QfAxJ6m5&tCJW$-a8x8qSQ{6Y9JF0Cg$JTDaEl3VU%alE zY2}5>iuW2JZEsr^UTI!WNGENMNK4}x3cEjP04nnu@dt$ zf=go@Ny+d{mA|H`l&eKsD)H^eHY?Sd2 zE$d{AV+d~D7UOR`rqf?>ad2uZrGgH>MfM(JNlc;fJXQ1J`V1|KiJO&Rh)ysT*?upY zR~VgOnw4PY1sn5X;_?&xq7(e{Y`>#>qZ0!16Dni`TO(~rF>%oem6B|~M<-Oa#>6Ej zR18b7L?;9#0UF!y*6_mQguv*8Dq#s#D_+|3{n5i`w_n>FvOQM22l4)c+Bok))o}1X z3?bY9|2QvVrt=46NoroitR+E#);TZ2K%k6Sv}VZxTi(&ag(r%S1|8aOD>~}HY#>D2 zp~6j4%sb=&!`Fh2VqSC{`VNzcHZKCcQp~*9w0V&;;R)xwhOXiGPYzC%Ps_&XaN~#RZ{v_cZ0~$G+EYgx5?sz{H4-*tE4cJh1pBF%z~I zQ!C~_^o5ufVU=OTw8&`^Gh>pC6Q^@#Y|WWtUL0l^F*9NY6ceME7BSI@35L_9+q{Sw z=KspP=$aM9WIipFlUikMuESjJoD&16T5ik;#sszyb9p+h&vRB3b2*fMYZITZIq|BN z<(w0*@K`@5UZTQ%PP{=7)MT%|!ya<|QmnPzv*r{27Xn7b2ll%gSr}x zKhWgVr`52KFKJT}X7?M_>Mx6_S53pd@%!S3`5WT>4EthYd)nfA80zg$-*z^9XxB;u zD~_+2xoFy?6*C{P8;{VzJUg6K9B9$j?NcW$pP8{Je|KqKvy!|8CAGf#(_-oMOPL{T zN`S1J_`*#6##EKY;ScF&)5x=f(xbo7F zp>b)$AE>?NqdS`4v#j$g6F<50*`Ajg{W<294L_Kd^tb&v(mFZ&k5~6kUNp}%py}^F zesyDTi%-7#xP3xVv*Z^Ryt(A!q9Z0y%helR=oh$Hm#F()%4`tIG6@WhTs?k#*`+SDs!x=md1 z&ZHB~zaRY82lHO7U25HszW3A4Z`}V~zd9**M9unfXxpTxhCkRdId#g(%@bdn^WMzj z`u|jHx%7IUj4^pV|E{~>+pLF|-goWoVFjNzex<+ZRDPocqkkCrN{jSg!YgcfbBDRj z$M-!ww`0W@KM#NSvhBkcw=_22`>v_htZ^3()^GXfv^N&NRN->zZ<(i74f^`Zfi(XQ zz6fZS-01Mye;(c0dib;Lej8c5`qA&B{r~u-aLw%VodT17T^~E?`G9+JsttWV^wI0x zP6Tva*3JL56F1`Wo(cAj~sh$%7nA= z?{9kKv3V8h-W_vh&&6-1&8XaaReaTRGv+khdkx)TD4ILFQp*c{qJ#4`G`uT+P*#<) zzy5wGW>nSJzG&DrvQzU8Rga}s9=A3$70KC;at5ySsZtOn$8KuH&CvxRLSJ z=}ReFqmJ+UD&?VS@lS=tR^JtDozt(${SUp@_1b6Gqk~_ISe3o|xigH0AYLSuOM4S@H7HK7R(EOAYINWB$%{rQPo+zQ5JcQEeCg8rFBv?uTOzZ$Gwg z^*{5E1a?^d`^OH3 z%f_hgjiXw;xYV|5b$UtrLEAbyX6;*hW8tAqCto^Rv#sCqewWUFeKqdDkSY%@`lC(l zfnPp8`PWSYd#oQgV*fI~?@k|n^M~i|omX!_t43S5rwx6u*F8V`Jv+bsc;my4f#V^>}-=svQ>r_<`}?)YKB)dN2d|9k!2iCuGRe3$Ue+^HLXo4GGzXSa8n zv}+afLTuuW1|Q|uI@Q#&txMm>!h@cSD_dur)XDPtw-w(wz4GX&?F&;snPa~%`mMY# zvc@_3Y#kkc2>4$C{&B#+Ht=r_{9gh7&jSBHf&UM{-v<0A1ONTN-vs=B1pY06e|zAc z4E#3(|964^&%pm5;NJ%L4*>qXfdA*fe*y4c4E(c!|1jYH0q}PK|C7LfFYw<1{GR~+ zV}SoV!2f&TKM(j@f&Zt#|2yD+2k;*X{D%YoRNy}m_|F9X6@h;r;NKJYe+&HY1O5fT zzd!JA1pG$=|6hRro525L;NKDWhXel)fxj8}*8=_rf&Vn%Ujg`M0{^dpzd!JA2mIFp z|JK0&H{ky$@c#q&&j$WUz<(0(&jJ3S!2bmB?*{yT0{$a_|4!f^0Q`pl|K-5{ec&Gp z{Eq?uv%vom;9nQ`?*aZZfPXyjpF{qEe-ZF+3H*bB|6Rbp3h;jj_`e4HBY}Ta;6D!d z-wpgb0RPIse>CvF2>hP`{w2WwIPjkW{6m2M65wA9{KJ5MJ>Xvn_&)~x-va&(f&V4o zUkLnH0RIPpzY+N71OIg3{}=G@0sI>S{|mtXH1LlC{wcu!Dd4{g`1b?;?*aeoz&`@` zKL`A`0ROqbe>?Dh9r)(~|E0kH9PqyZ{7ZrV{lLF1@b3%!V}SoY;C}@8{|@}81OK;y z|Es{iGw`1Z{1buy1Hk`r;C~eOcLM$&0sry9{}Ay10{Axt{u_XQ9pJwb_}>Zqn*sl^ z!2fCBKN$Ew3H-}||2E)X6ZoG2{<*;adEmbZ_^$!}-GTp$z<)LH9|Zho0sn=-|0Uq> z2mH?i{{z5(5%3=f{C@@h>w*6=;C~qS-wXU(0sl1Me-H4V5Bwhn{(-=M0`UI^_*Vn| zUjqNHfd4Ase+~Fo2mUVue>?E65Bz%r|IdK`W#C@}`0ob(SAqZEz`rZ-PXPWKfqw?@ zZvy;Z0R9bt|0&?#1^5R6|8>CM0{q_q{-c2ZC%``%_-6tCt-${!;GYKk*8u-}fd53` z-xK(c0sdy-|0nRz2L6+Q{{Z0s74ZKA_$L7W7l8j=z`q{wuLAr_fPW$IF9rTj0srg3 zKN0w^1pd>3|5)HZ8~BF;|4iV&2lzh%{HFo`Zoq#M@E;8PUj_affPZJ;-w*gl0spqZ z|3TnC1^B-P{ELBqOW>aY{Qn02S-}4q@c$h6n}GiU;QtEn4+s7`fd75KzasE|82G;k z{O<++vw(kn;Qt2jzYP3O0skw&{{!Hk4E+BA{=LF$ zDDV#e{{F!Kec=B%@E;HSj{yIg!2d7ce-8Nf0RGPb|9Ig481TOv_+JG6m4Sa%;NOt^ z1OK_e{{ryO1OEBIzYO@t0RJz5e<$F74EV1F{v&{YYv4Zt_@4p(%YgqP;Qul3w*vqE z!2b^5|1R)v0sKz_|JuMm2>9;?{_BAM%fP=b@UH;;PXPZU;NJ}R{|@}`1pW^I{|Ml} z3;5pv{+EFNap3@b3!zqk;b_;NJ%L+kpQt;Qs^guLbP1h_+JJ7 z8-afj@LvM_BY}Si@LvJ^?+5-V!2dnqKNa}b0se0T|EGa}4)Fg8_#XuRXMz7Sz`q0V zuLS&O0RJt(zcKJ%3jEW7|2E*i5BMJf{zrlTa^U|p@E-#F{{a490{>0Ge<1Mp1O9IU z|9QZ_5%3=h{C@`i?Sa1o_{RbN2EhL_;6DoZ_XhrU;BNu`HGqE?;NKkh?*;xp0{_jx z|2yDc0Q^4%{vCn;0pPzL_~!!uZ-D=Az<($3ZwLHif&WLqzbWwV3;dr1{zl;cI`BUY z{I>)DIl%ud;6D!dj|Tojfd6pd{}J$C2K+w({+EFNE5LsV@E-~M{{a4rfPYiqe*^e` z1^kPE{{rCO7x+&A{>y>?_rTu-{6m2M3&4LD@IM3mp9KED0ROLneTkrErI`H;9m;-R{{S6!2b*2 z-w60W3jCi1{>8vQ8u%9i|4zVvJ@5|z{zHNPb>QC>_`e4HdjbD9fxkcS&jtQvz`qIb ze+u~T2mVul|NFpy9`KI={@(!q-oXDH@ZU@Rf&Xma-v{__0RDr3|6jm=6!32d{F?*+ zRNx;9{0{^F&cJ^&@UIH|KLh^H0sq0ke>L#W1pc*ve`VnRBk=D5{2KuOK;Zu>@P7yR z?*aY~0sjHO|2^RUH}HQR_-_OL9|Qk(z<)CEKMwpefPV_`-v|7w0smOwZw3DM1OIEl zKN$FD1ONWO|2N=&9{3*u{#n3(1@Qk9_=f@ioxuMN;C~eO{|fwf1OM&7{~zGr0r(#T z{^7vC8Sq~N{7(b_AmIND@J|N*JAnUL;C~PB{~h>$0Q_eF|CfRP>%jj`;Qtcv&jJ4T z0sl(C{|fLo0{?ZuKMnXl0Q@Tg|DS;WG2s6x@IM0lzXbjpfqxY6w*mhW;NKDWuLb^_ zfPYQk-w*g-1^!ile;eTcIPf0`{6_%)?|}agz`q{w-wOO61pa=&e?0In0RF9k|6Ra; z81Qck{Hp{1`M`fV@P7jMKLY$O0{`~F{{ryu0{q7U|L(wl8u0%R`2P(2?*{%gfd5?J zKNI+O1OBamebJrZ_)d+w7F_brWHyQ6W}ivykvjQ{haK^0rCN)JEQ zWXt5cSNF|+>~PckYk#E9%~)RR$eMBc$EUruI4iHukiRdy^YuM7dyRhS@n`2OJo<`Z z{f9vZ#0}i!nxL{xRs;2E5-!~hpKRU7VqTsl}6ORA<)a8SpmcH>*!LkjG zursf=f9TZpj%Vu^ewWkx(jAi;M11^6?%T;#*4O!<-i=Y+`tSN|n)T^#O8%L8;I1o; zPONJ?ufp!A%^}ssHZMA#m^Adkm+QXSFDUZI>CZ3OyYkoKlXnh$t;O$~_Wbf*m)XNt z*lV}+d*IzEUpD(bvqs9uP|N)(DKGAtF=NiPDN|Nlyzjop|G0cPsBGfI_rJ`|-Tdvx zACFjMvkgfy8qKB&6JGwbWy||V{qs-VGhcm`{N^jK{4{X#Bm+|6@ zSBC!hW4ptbE>*lfY0{EYM~@b~5*0N(xn|AoE&Ti}6?g9*_GIJ6X}v!B=$>cm)CspO zTehmBzkk)rPe1);n+g>wRS5~{(4?s7nR=&Ab^Y#_Uz#0g-aK>AmMsS!EG&Hf=Sr38 zh0LD)T!U7v9AoadqjkG_^&&guYMh{`=a)hcn*c+;!nXtL@n95_{uDqaQYJ-ZSm)yDz+T z@4X)!`Q(#ckALvNu?d|z_0R9u@7tvV1{_&FX3W`52M_jp=+L2w@BR8~i;vf@|8ekN zf7QCsqsPZ{2M+w|>9%c0ra$!1(%_yw4?cSRdbM*VQ-I%t56=8&$dJE9afA-mJp)oOi@_zr_@6xty-=)0u*7hl1 ze_gmSG&Ci?S~Z)stn7{-fBUV<-=BS!{o#QF17=z*HR@Ea-oDxS^KCv#O#J?Xr=D8f zJ|SWMyxO%pwcfdN^pclex;*lM2WH*q+O_xe)YJ`o#*aVqZr!>qqYDb2{3$7^xMb$c z<#h)SKK$JA;}5tmsx9>NL0|F{rnl#DkGj81Jtvhy% zfBy5&bKc*u;nyC?$!m8mTC}dylTWURI(@q1=hLP=cKOVi=r8u{>G4>{j$?DOv)}&u z@yF*IzxX0`^PoYWt$g|AlYO(Y-Z(mH)Snx!T&eKe&p$Ukn3lG2-}LEETzT!abG<88 ztW)jXcfZJ;I(1%Y)26xoTDQ(0SHFIfn6+y!jeg^e-37aL4SnkD*~XuoI5A_D!?E&g zqeh|K`u9Jv?EUwT+aG&uZqTETK2$X?Z{f*q-Qs7w`R2|^>FMkD_vv$Vq1o&o@W&s< zt5vFm)VJGT*wMay;=Q9sUw`eLcMfIFox7;^_U&Uzv4a2%T{P5zM=gwL8e)?(OhewVq zTOS@ib;x($O@DFz`~~J!tFDcGZ|zpU2`%rwjPR$`)JmR z6`LX=Bd6R|wQ6v~O`ATsZ^Vcj>)w0s%j{aUI=2G;DZqaQ@Sg(w?*smqf&WC{p9}my z2L3kSZv_4mfPYKi{}1s03i!VQ{3iqdeZYSf@ZSsk?+5;W0{^kVzc=tN1^%xB|0BSE zHSpgE{8s}1HNZa~_?H0xw}JoPz<&wwZwCB30RQg5|0?j`5B%E!{}+M(kHG&D@Sg2>71@{=WeK=D>do@Gk`Z zm4N?j;NJ@P-vRvV0skD}e;4pC2L8i<|DC}9OW^-H@Q(ogKLGzWz<&<#9}fHv3;tVe zzX1HL!2bsD-wgck2LAT~|4)Gb2f)7*@b3rw2LS&u!2cldKLq@L1^(-S|6jnr2k;*V z{M!Qmhk$=i;C~(Xn}Gj=z<&tv?*jav2mb4T|4`un0`QLo{tJNrV&MNQ@Q(rhzXShm z!2d1a|26Or1^(55e;M%q4fuZs{0{(s3-GTF{LcgbMBx7v@J|5#wSoUm;Qtcve*pM* z1^%hPe?0K73;YX!e-iMY3H%2G|Kq?v4EVPI{tJQsJmB98_+JG6TY-NK;QuY~zX$jS z0{?G-|4HB<4g5O;|H{C>FYpfl{!M`YIN-kn_c%g{^x-Ir@((C@DB(6-vR&mz<(9+e+2jk0sjwy|4+a_9{6Vf|2W{k0{BM)|Ej=$ z6Yw7a{NDrqwSa#L@Sg$vrvU%^fd6ISKN0xn0{@SJzYX{sf&T>H-xB!$1N^@N{;vT4 z$-sXf@Sg?z_X7X>f&ZVte=P9t4g5=i|Es|N2=HGG{5JysmB4=u@XrVSCBXk};Qu%9 zUjqD_0sjubzdP{13jFs2|8~ItMd1G<@V^B7CjtMXz&{H3*9884z<)RJZw&lD0{(S? z|1#k35B#47{uO|K2=Ffg{-=QdFTlS!@ZSRb3xR(n;6EGqw*vlm0RMWxKL_~V1^kPF z|1jWxC-DCg_`eSPBY^)8z`qUfp9B1d1AoCk@V@~3t-${V@ZSvl?*{(&0{>5d{|CUo z6Y%c`{09L4F~I*I@IM6ne+B;Qf&X8?zX$Li2>jau|A&BoPvCzY_?v+LgTQ|X@b3cr zp9lWyfd5e7{{rxj1^x?w|6<_(Ebxy3{=WnNZNUF6;Qux74+Z|!fPWeA{|)$m2K)~I ze+%%h4*bsp|3u*b6!1>~{C%@P7dKcLn~bz<)gOuM7MOfPWJ3p9%a21OMZ| zKMeS{0R9Vs|2*K|3;16I{#${64dDMR@V^K62Lk_Zfd5J09}WCF1OLjvzc26)0RByY z|2W{k1NeUq{5JsqWZ=ID_&*8!PXqsH!2b;J-vj(R0{?8_|2Xjf0{9OC{x1XnEZ{#1 z_+J73KLh_X;6EMszXtp(0{?e`|5V`L6!^CW{`G|8BtlP2isn{QCfZGw}Zd_*Vh`cHrM0_>Ttu?*RX~z<)dNZvgzC z1ODFw|7*a1Iq(k#{+Yo481R1r_%8+i&jA01!2e<3e-8M63j9X`|8U^{9q^wI{8s`0 zM}U72@c$6_{{;Nwfqw?@j|2WIfPWw7{C@`i9|HfYz<(L=zZ>}P0RHuX|7*biUf_Qh@Q(xjCg499_>TkrSAc&z z;9n8=F9H4qz<)UK?+*Mez<(Ik|385LK;Ul&{+|N>`+$Ep;6DlYKLz}M z2mTqn{{#P4z&{E2Hv;~9fd2*H{{ist1^kZz|Ng-LTi|~L_@4#-{eb^O;NJrH{|NkR z0soJI|5w0&B=BDf{0{>EYQR4L_|F9XrNBP{_`eJMe*pf!0snu1e+lq^6!^ai{I>!B zKEU4(_8-V{A;NKGXKMDMcf&X≥D{b2>jE5{{z7P72rP``0oS$5y1a*;NJ!K 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

    aFI)X9~E`1TUgB_ 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%0DGxb13)Fb}C0@ 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 z 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