Compare commits

...
176 Commits
Author SHA1 Message Date
Sergio R. Caprile 739d78a45a update version 2025-08-21 13:13:25 -03:00
Sergio R. Caprile 8a62633b2f keep, linked by other examples 2025-08-14 11:38:48 -03:00
Sergio R. Caprile aae1a687a9 Merge pull request #3235 from cesanta/client
Refactor HTTP client
2025-08-14 11:00:23 -03:00
Sergio R. Caprile 61285ec418 cleanup 2025-08-14 10:59:07 -03:00
Sergio R. Caprile a00b3f1c6c Merge pull request #3241 from cesanta/mingw
Fixed mingw build error
2025-08-13 10:48:53 -03:00
robert 2c813f3e72 Fixed mingw build error 2025-08-13 05:17:34 -04:00
Sergio R. Caprile ea68d7a705 Merge pull request #3240 from cesanta/ppp
fix ppp driver
2025-08-12 17:51:40 -03:00
Sergio R. Caprile 654f401038 fix ppp driver 2025-08-12 17:21:36 -03:00
Sergio R. Caprile ad89122a06 Merge pull request #3237 from cesanta/tests
Fix built-in TLS CA bundle, cleanup
2025-08-12 16:34:51 -03:00
Sergio R. Caprile 73ed158e76 Fix built-in TLS CA bundle, cleanup 2025-08-12 16:10:12 -03:00
Sergio R. Caprile 548c3dc77f fix #9f76ea8 breaking bigendian 2025-08-12 15:57:26 -03:00
Sergio R. Caprile c1fa067a1f Merge pull request #3236 from cesanta/tls
Verify host against CN, too
2025-08-12 12:09:23 -03:00
Sergey Lyubka 9fd87060f9 Verify host against CN, too 2025-08-12 15:49:08 +01:00
Sergey Lyubka de0a3b035a Refactor HTTP client 2025-08-12 09:21:38 +01:00
Sergey Lyubka 9f76ea8030 CHACHA20 -> MG_ENABLE_CHACHA20 2025-08-12 08:42:20 +01:00
Sergio R. Caprile 76b7356873 Zephyr wants _DEBUG to provide mbedtls_strerror() 2025-08-11 13:23:51 -03:00
novlean c24d5aabd8 Merge pull request #3231 from cesanta/novlean-patch-2
Update README.md
2025-08-06 14:38:25 +01:00
novlean 0df6645b90 Update README.md 2025-08-06 14:38:11 +01:00
Sergey Lyubka b19cf8654f Merge pull request #3203 from cesanta/dns
Built-in TCP/IP (re-)starts DNS connection on DHCP link up
2025-08-01 12:13:39 +01:00
Sergey Lyubka 19933a4673 Merge pull request #3222 from cesanta/mbedrbose
Add verbose MbedTLS errors
2025-08-01 12:10:20 +01:00
Sergio R. Caprile 76963f7d01 Merge pull request #3229 from cesanta/tests
fix possible overflow, improve tests
2025-07-31 13:50:42 -03:00
Sergio R. Caprile e670ea3d61 fix possible overflow, improve tests 2025-07-31 13:43:18 -03:00
Sergio R. Caprile fa33b57e4f Merge pull request #3228 from cesanta/tests
mask built-in TCP/IP with WolfSSL test
2025-07-30 17:10:16 -03:00
Sergio R. Caprile 77e369bc79 mask built-in TCP/IP with WolfSSL test 2025-07-30 17:09:42 -03:00
Sergio R. Caprile 94ad9767d3 Merge pull request #3225 from cesanta/tests
ChaCha20 not working in S390 (bigendian)
2025-07-30 16:15:40 -03:00
Sergio R. Caprile aa76f5673b ChaCha20 not working in S390 (bigendian) 2025-07-30 16:13:34 -03:00
Sergio R. Caprile 81a699c801 Merge pull request #3224 from cesanta/tests
Fix tests
2025-07-29 17:26:07 -03:00
Sergio R. Caprile bd15c456b2 Fix tests
Fix Ubuntu starting Mosquitto right after install
Skip TLS on localhost on MacOS with MbedTLS
fix MQTT_LOCALHOST for built-in TCP/IP tests
2025-07-29 17:17:03 -03:00
Sergio R. Caprile 10d9e1e9ae Merge pull request #3223 from cesanta/zephyr
Improve 4.2 test time
2025-07-29 11:22:56 -03:00
Sergio R. Caprile 6a3813f633 Improve 4.2 test time
fix for intermediate releases
2025-07-29 11:19:16 -03:00
Sergio R. Caprile 51fe22a95f Add verbose MbedTLS errors 2025-07-28 16:18:53 -03:00
Sergio R. Caprile 105762416f Merge pull request #3221 from cesanta/tests
add tests for Zephyr 4.2.0
2025-07-28 15:07:50 -03:00
Sergio R. Caprile db7087f455 add tests for Zephyr 4.2.0 2025-07-28 14:43:09 -03:00
Sergio R. Caprile c5693503cb Merge pull request #3220 from cesanta/zephyr
update to Zephyr 4.2.0
2025-07-28 11:26:03 -03:00
Sergio R. Caprile b74590a4a5 update to Zephyr 4.2.0 2025-07-28 11:25:02 -03:00
Sergio R. Caprile d5eeed48eb Merge pull request #3219 from cesanta/tests
workaround GH storage
2025-07-28 10:44:53 -03:00
Sergio R. Caprile fc5c0d0964 workaround GH storage 2025-07-28 10:28:18 -03:00
robert aa2647c0bc clang format 2025-07-28 04:11:22 -04:00
robertc2000 cef0acdb40 Merge pull request #3218 from cesanta/same54-driver-update
Update same54 driver
2025-07-28 11:07:47 +03:00
robert 2140656acc Update same54 driver 2025-07-28 03:55:00 -04:00
Sergio R. Caprile fd0c969f16 Merge pull request #3217 from cesanta/tests
move Zephyr tests to their own script
2025-07-25 17:08:19 -03:00
Sergio R. Caprile dfeb929e0e move Zephyr tests to their own script 2025-07-25 17:07:06 -03:00
Sergio R. Caprile d3e67733a6 Merge pull request #3216 from cesanta/tests
Tests
2025-07-25 11:44:36 -03:00
Sergio R. Caprile eff74fdc9d Zephyr: only clean if there's a build 2025-07-25 11:38:30 -03:00
Sergio R. Caprile 5e4c40ad09 remove tailwindcss dependency 2025-07-25 11:33:49 -03:00
Sergio R. Caprile 087e6d3142 Merge pull request #3215 from cesanta/tests
fix mingw[++] tests, add local MQTTS
2025-07-24 18:43:57 -03:00
Sergio R. Caprile 587b074822 fix mingw[++] tests, add local MQTTS 2025-07-24 18:42:14 -03:00
Sergio R. Caprile 6aa8c01ac7 fix TLS text 2025-07-24 17:11:19 -03:00
Sergio R. Caprile 3bbcd5df3e Merge pull request #3214 from cesanta/tests
introduce local MQTT server, fix container calling, fill prerequisites
2025-07-24 16:10:08 -03:00
Sergio R. Caprile af512c57ef introduce local MQTT server, fix container calling, fill prerequisites 2025-07-24 15:54:58 -03:00
Sergio R. Caprile 58297a7871 remove obsolete example 2025-07-24 11:25:11 -03:00
Sergio R. Caprile 18a530048c Increase MQTT connect expected time 2025-07-24 10:15:09 -03:00
Sergio R. Caprile f9ed75d6b3 attempt to get reasons 2025-07-23 10:53:00 -03:00
Sergio R. Caprile 3c1f41e575 disable scheduled run 2025-07-23 10:33:51 -03:00
Sergio R. Caprile c772936dd1 enable manual run 2025-07-23 10:31:07 -03:00
Sergio R. Caprile 253696be45 Merge pull request #3213 from cesanta/tests
disable hw tests on quick test
2025-07-23 10:27:12 -03:00
Sergio R. Caprile 79b7accc55 disable hw tests on quick test 2025-07-23 10:26:34 -03:00
Sergio R. Caprile 7a1e846c73 Merge pull request #3211 from cesanta/ooofin
Fix ignoring SEQ on FIN
2025-07-23 08:34:05 -03:00
Sergio R. Caprile ce59ff89c3 Merge pull request #3212 from cesanta/tests
fix sh not being bash
2025-07-22 18:03:00 -03:00
Sergio R. Caprile d31d064d5e fix sh not being bash 2025-07-22 17:01:01 -03:00
Sergio R. Caprile 467fbf4bb4 Fix ignoring SEQ on FIN 2025-07-22 14:16:35 -03:00
Sergey Lyubka 6769223ce1 Nitpick: rename fn -> mqtt_ev_handler 2025-07-22 10:11:20 +01:00
Sergey Lyubka 294e483885 Nitpick: rename s_conn -> s_mqtt_conn 2025-07-22 10:10:14 +01:00
Sergey Lyubka 43513e2d56 Update MQTT client: enable keep alive, use rx/tx topics 2025-07-22 09:44:43 +01:00
Sergey Lyubka d1b7687e98 Fix comments 2025-07-21 23:01:43 +01:00
Sergey Lyubka 9ac09da1d2 Remove mg_http_run_simple_server - move to docs 2025-07-21 14:03:12 +01:00
Sergey Lyubka 24a330c750 Nits 2025-07-20 12:49:58 +01:00
Sergey Lyubka 13a9c773f2 mg_hello -> mg_http_run_simple_server() 2025-07-20 09:36:34 +01:00
Sergey Lyubka 3cd166d065 MG_ARCH_CUBE nitpicks 2025-07-19 08:33:48 +01:00
Sergio R. Caprile 490066fd17 Merge pull request #3209 from cesanta/tests
Fix misc warnings and nits
2025-07-18 17:40:53 -03:00
Sergio R. Caprile 94fce72ade Fix misc warnings and nits 2025-07-18 17:08:32 -03:00
Sergio R. Caprile eacc64bdd1 fix missing def 2025-07-18 16:44:38 -03:00
Sergio R. Caprile 7b037f4957 Merge pull request #3208 from cesanta/cube
Introduce MG_ARCH_CUBE, autodetect everything
2025-07-18 11:22:17 -03:00
Sergio R. Caprile fa841916c1 assorted nit picks 2025-07-18 11:19:58 -03:00
Sergey Lyubka 75c11436ff Introduce MG_ARCH_CUBE, autodetect everything 2025-07-17 17:29:48 +01:00
Sergio R. Caprile e07a8283ec Merge pull request #3207 from cesanta/hal
Autodetect STM32 in mg_millis()
2025-07-16 10:27:37 -03:00
Sergey Lyubka 2a174b0d3b Autodetect STM32 in mg_millis() 2025-07-16 07:38:29 +01:00
Sergey Lyubka 013993abae example configs 2025-07-16 07:37:25 +01:00
Sergey Lyubka dccc153c68 example configs 2025-07-16 07:37:07 +01:00
Sergio R. Caprile db0867f435 Merge pull request #3206 from cesanta/restrict
Avoid trashing VC++'s own proprietary restrict-like keyword
2025-07-15 16:55:52 -03:00
Sergio R. Caprile 7234121835 Avoid trashing VC++'s own propropietary restrict-like keyword 2025-07-15 16:47:06 -03:00
Sergio R. Caprile 3aafc073d8 unbreak after #8a9b1d9 2025-07-15 13:42:48 -03:00
Sergio R. Caprile b527ed313c Merge pull request #3204 from cesanta/tests
Moving tests from GH yaml to bash scripts and Makefiles
2025-07-15 11:27:24 -03:00
Sergio R. Caprile cd86559685 Move tests to bash scripts and Makefiles 2025-07-15 11:24:09 -03:00
Sergio R. Caprile f67e843be6 fix tests 2025-07-15 11:24:09 -03:00
Sergio R. Caprile 4f9ebd8092 Merge pull request #3202 from cesanta/gcc
Rename MG_ARCH_NEWLIB -> MG_ARCH_ARMGCC
2025-07-15 09:08:13 -03:00
Sergey Lyubka 6c044d6aeb Rename MG_ARCH_NEWLIB -> MG_ARCH_ARM_GCC 2025-07-15 11:22:17 +01:00
Sergio R. Caprile c6ee909aa4 uint16_t always >= 0 2025-07-14 15:12:50 -03:00
Sergio R. Caprile 393063428e Built-in TCP/IP (re-)starts DNS connection on link up 2025-07-14 15:06:31 -03:00
Sergio R. Caprile 1494f5e831 Merge pull request #3201 from cesanta/sntp
fix SNTP through proper protocol handler setup
2025-07-14 10:09:47 -03:00
Sergey Lyubka 8bfd0c2ca3 add config template 2025-07-13 07:34:48 +01:00
Sergey Lyubka e9de2f3eb1 Remove gurubase link - useless 2025-07-12 06:50:27 +01:00
Sergio R. Caprile 8bf9d09d96 fix SNTP through proper protocol handler setup 2025-07-11 16:56:12 -03:00
Sergio R. Caprile 67255ce8f5 fix broken links 2025-07-10 09:48:53 -03:00
Sergey Lyubka 5db89aa264 Update help message 2025-07-09 12:58:15 +01:00
Sergey Lyubka 8a9b1d9873 Simplify dashboard 2025-07-09 00:21:31 +01:00
Sergio R. Caprile c08c1afb1e Merge pull request #3198 from cesanta/c89
make it C89-friendly
2025-07-08 14:10:58 -03:00
Sergio R. Caprile 2c7f58aed2 test checksum primitives, enforce rx frag test 2025-07-08 13:57:03 -03:00
Sergio R. Caprile b3ee71acbe make TCP/IP C89-friendly 2025-07-08 11:15:32 -03:00
Sergio R. Caprile 52ab6bc499 make it C89-friendly 2025-07-07 15:15:31 -03:00
Sergio R. Caprile bf059ad42f Merge pull request #3197 from cesanta/select
select() minimum wait is now 1ms
2025-07-07 14:43:52 -03:00
Sergio R. Caprile 85df6a6131 select() minimum wait is now 1ms 2025-07-07 14:40:18 -03:00
Sergio R. Caprile d840b4a4ee Merge pull request #3196 from cesanta/tests
fix tests
2025-07-07 11:33:25 -03:00
Sergio R. Caprile a8c2ce544e fix tests 2025-07-07 11:32:31 -03:00
Sergio R. Caprile b95022a3b3 Merge pull request #3195 from cesanta/sanasan
remove false positive
2025-07-03 11:49:01 -03:00
Sergio R. Caprile 8c45a9d2c9 remove false positive 2025-07-03 10:53:59 -03:00
Sergio R. Caprile 0fe64fbff9 Merge pull request #3194 from cesanta/udpret
mg_send and mg_io_send now honor UDP failures
2025-07-02 17:00:50 -03:00
Sergio R. Caprile 64e806628b Merge pull request #3188 from cesanta/wintls
Fix incorrect reference to a Windows compiler
Fix memory leaks in RSA signature verificator
2025-07-02 16:49:32 -03:00
Sergio R. Caprile ccd2b2699f fix memory leaks in RSA verification function 2025-07-02 16:40:36 -03:00
Sergio R. Caprile 0b5c0c9889 mg_send now honors UDP failures 2025-07-02 10:04:24 -03:00
robertc2000 6293e7dbec Merge pull request #3193 from cesanta/driver-macro
Removed MG_DRIVER_* macros
2025-07-02 13:08:39 +03:00
robert 87325ece82 Removed MG_DRIVER_* macros 2025-07-02 05:03:32 -04:00
Sergio R. Caprile 6cbd9b3067 Merge pull request #3192 from cesanta/freeunix
fix unix detection in wrong place
2025-07-01 16:32:20 -03:00
Sergio R. Caprile aa27fde9d0 fix unix detection in wrong place 2025-07-01 16:28:13 -03:00
Sergio R. Caprile e854585802 Improve Zephyr support 2025-06-30 10:35:53 -03:00
Sergio R. Caprile 2c5aba24cc Merge pull request #3189 from cesanta/zephyrotahack
Improve Zephyr support
2025-06-27 14:13:17 -03:00
Sergio R. Caprile 806ee0f2cb Improve Zephyr support 2025-06-27 14:11:04 -03:00
Sergey Lyubka e72b95fb1c Fix tutorials/http/http-server build with windows gcc 2025-06-27 14:33:44 +01:00
Sergey Lyubka 471e7ff61a Left-align tables 2025-06-26 10:42:47 +01:00
Sergey Lyubka 3d2de154d1 Add support matrix 2025-06-26 10:40:15 +01:00
Sergio R. Caprile fc551ec2e9 Merge pull request #3182 from cesanta/calloc
Introduce mg_calloc and MG_ENABLE_CUSTOM_CALLOC
2025-06-24 16:32:28 -03:00
Sergio R. Caprile f5e2c68c8b update examples 2025-06-24 16:26:31 -03:00
Sergey Lyubka 074ef5197b Introduce mg_calloc 2025-06-24 10:52:44 +01:00
Sergey Lyubka 5f1f4a0df8 malloc -> calloc 2025-06-24 09:12:38 +01:00
Sergey Lyubka 86334e9040 Keep only one listener 2025-06-24 08:57:49 +01:00
Sergey Lyubka f71cc3ebc3 Merge pull request #3173 from cesanta/chachaleak
Avoid chacha20 header leaking its redefinitions
2025-06-18 10:47:19 +01:00
Sergio R. Caprile 00910462e7 Merge pull request #3174 from cesanta/wka
Allow KA from erroneous implementations
2025-06-17 15:17:29 -03:00
Sergio R. Caprile 2fc56dd1d0 Allow KA from erroneous implementations 2025-06-17 15:14:30 -03:00
Sergio R. Caprile a5ebe71394 Avoid chacha20 header leaking its redefinitions 2025-06-17 12:12:48 -03:00
Sergio R. Caprile 0eb8bf6b51 Merge pull request #3167 from cesanta/threadx
Add MG_ARCH_TREADX
2025-06-16 10:51:16 -03:00
Sergey Lyubka 3a0fe5288c Add MG_ARCH_TREADX 2025-06-16 11:09:41 +01:00
Sergey Lyubka bfca233160 Merge pull request #3170 from cesanta/keepack
Add Keep-Alive ACK
2025-06-12 08:37:00 +01:00
Sergio R. Caprile acf217601b Add Keep-Alive ACK 2025-06-11 14:25:05 -03:00
Sergio R. Caprile b0d0fbfd9f clarify bridging for Wi-Fi 2025-06-11 09:31:24 -03:00
Sergio R. Caprile 9411f1c7b6 Merge pull request #3165 from cesanta/wifi612
Add Wi-Fi example for RW-612
2025-06-06 18:39:35 -03:00
Sergio R. Caprile d7d7ebf99a Add Wi-Fi example for RW-612 2025-06-06 18:26:27 -03:00
novlean 8072ae2057 Update README.md 2025-06-06 16:34:19 +01:00
Sergio R. Caprile e529e644ab Merge pull request #3164 from cesanta/asan
avoid ASAN reporting read overflows
2025-06-06 09:03:02 -03:00
Sergio R. Caprile d6fdfe5b1b avoid ASAN reporting read overflows 2025-06-05 17:26:56 -03:00
Sergio R. Caprile 50e15e574f Merge pull request #3163 from cesanta/test
expand test coverage
2025-06-05 14:24:47 -03:00
Sergio R. Caprile 58f1533779 expand test coverage 2025-06-05 14:24:03 -03:00
Sergio R. Caprile f4a49829ea unbreak FreeRTOS (#3158) 2025-06-05 14:03:26 -03:00
Sergio R. Caprile 3efe6641eb Merge pull request #3161 from cesanta/fix
Unbreak MbedTLS (#3148), rollback debugging leftovers
2025-06-04 09:08:32 -03:00
Sergio R. Caprile 0459d9e106 Unbreak MbedTLS (#3148), rollback debugging leftovers 2025-06-04 09:05:27 -03:00
Sergio R. Caprile 305d69ee36 Merge pull request #3159 from cesanta/isacheese
fix error introduced in #3149
2025-06-03 15:41:13 -03:00
Sergio R. Caprile 98e744a9ad fix error introduced in #3149 2025-06-03 15:29:28 -03:00
Sergey Lyubka 1d97f2e2b5 Enable POSIX_FS on ESP32 2025-06-03 08:23:05 +01:00
Sergio R. Caprile c92bc4b4ac Merge pull request #3158 from cesanta/posiz
Redefine mkdir only if MG_ENABLE_POSIX_FS==0
2025-06-02 11:06:09 -03:00
Sergey Lyubka 6a3e1e41c4 Redefine mkdir only if MG_ENABLE_POSIX_FS==0 2025-06-02 11:04:16 -03:00
Sergio R. Caprile 650caface3 fix duplicates 2025-05-30 10:03:01 -03:00
novlean 8b6e02e985 Merge pull request #3154 from cesanta/novlean-patch-2
Update README.md - stm32 websocket article
2025-05-29 17:01:52 +01:00
novlean 3ee6fe45f9 Update README.md 2025-05-29 17:01:05 +01:00
Sergio R. Caprile e811afd397 Merge pull request #3152 from cesanta/fuzzer
fix memory leak in fuzz test itself
2025-05-28 14:36:07 -03:00
Sergio R. Caprile b197a674e1 fix memory leak in fuzz test itself 2025-05-28 13:56:04 -03:00
Sergio R. Caprile 08f6b99b13 remove conditionals from CIfuzz 2025-05-28 11:57:27 -03:00
Sergio R. Caprile b18d0301f3 Update README.md 2025-05-28 11:46:49 -03:00
Sergio R. Caprile 5596621420 Update README.md 2025-05-28 11:05:37 -03:00
Sergio R. Caprile bd8a66eee7 Update README.md
GH changes in icon stuff
2025-05-28 11:02:07 -03:00
Sergio R. Caprile b62ebb3c10 Update README.md
GH changes in build icon
2025-05-28 10:59:57 -03:00
Sergio R. Caprile 45d796fe5b Merge pull request #3151 from cesanta/wonder
Add Portenta H7 STM32CubeIDE example
2025-05-27 17:27:43 -03:00
Sergio R. Caprile d8a3b90cad Add Portenta H7 STM32CubeIDE example 2025-05-27 17:26:26 -03:00
Sergio R. Caprile 5be9e55425 Merge pull request #3142 from cesanta/wonder
Add support for SDIO
2025-05-26 10:07:41 -03:00
Sergio R. Caprile 6b6acd3967 Merge pull request #3149 from cesanta/is_tls
set is_tls at mg_listen and mg_connect level
2025-05-26 10:06:38 -03:00
Sergio R. Caprile 1b06403a19 Add support for SDIO
Add support for SDIO in CYW driver
Add Portenta H7 example
2025-05-26 10:04:44 -03:00
Sergio R. Caprile b740c80855 set is_tls at mg_listen and mg_connect level 2025-05-26 09:42:48 -03:00
Sergey Lyubka 29594283c1 Merge pull request #3148 from cesanta/iowaitormsscapped
flush TLS buffer
2025-05-26 11:38:41 +01:00
Sergio R. Caprile 51f54f9b7e Merge pull request #3147 from cesanta/ra8-eth
RA8 eth and phy support
2025-05-23 14:23:52 -03:00
Sergio R. Caprile 1f48b1ca65 flush TLS buffer 2025-05-23 14:04:59 -03:00
robert fd2d7cccf3 RA8 eth and phy support 2025-05-23 10:15:49 -04:00
Sergio R. Caprile 5726e680ec Merge pull request #3143 from cesanta/fairplay
Make built-in TLS play fair to TCP
2025-05-23 10:22:56 -03:00
Sergio R. Caprile fadf28adb4 Make built-in TLS play fair to TCP
Handshake functions in Mongoose TLS assumed data was being fully sent
after calling mg_io_send(). This was in fact the case with the usual 1460-bytes MSS, but not with the default 536-bytes MSS.
This PR removes all those calls from individual handshake functions, actual send is done at the main handshake function, keeping track of the amount of data sent, and so handling small MTUs/MSSs and possible MG_IO_WAITs when running over a socket layer.
2025-05-22 14:45:46 -03:00
novlean a321c2d096 Merge pull request #3146 from cesanta/novlean-patch-2
Update README.md
2025-05-22 17:59:06 +01:00
novlean bbb07bf6f7 Update README.md 2025-05-22 17:58:42 +01:00
Sergio R. Caprile a801160bc0 collaterals #3140
We prepend current path to the URI, so a tilde could not be the first
char in a path. However, the same would happen for double dots, and
since we're already checking for that, it doesn't hurt to be on the safe
side for future's sake.
2025-05-21 10:43:14 -03:00
Sergio R. Caprile 662cc27f4f Merge pull request #3140 from dag10/master
Fix URIs or header values containing tildes being unparsable.
2025-05-21 09:58:30 -03:00
Drew Gottlieb d01aa01a51 Fix URIs or header values containing tildes being unparsable. 2025-05-15 17:13:15 -07:00
960 changed files with 647863 additions and 9198 deletions

No files matched your search

+1 -4
View File
@@ -11,17 +11,14 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: if ./test/match_changed_files.sh '^src/' ; then echo GO=1 >> $GITHUB_ENV ; fi
- name: Build Fuzzers - name: Build Fuzzers
id: build id: build
if: ${{ env.GO == 1 }}
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with: with:
oss-fuzz-project-name: 'mongoose' oss-fuzz-project-name: 'mongoose'
dry-run: false dry-run: false
language: c++ language: c++
- name: Run Fuzzers - name: Run Fuzzers
if: ${{ env.GO == 1 }}
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with: with:
oss-fuzz-project-name: 'mongoose' oss-fuzz-project-name: 'mongoose'
@@ -30,7 +27,7 @@ jobs:
language: c++ language: c++
- name: Upload Crash - name: Upload Crash
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
if: env.GO == 1 && failure() && steps.build.outcome == 'success' if: failure() && steps.build.outcome == 'success'
with: with:
name: artifacts name: artifacts
path: ./out/artifacts path: ./out/artifacts
+2 -2
View File
@@ -2,8 +2,8 @@ name: "CodeQL Scanning"
# https://github.com/github/codeql-action # https://github.com/github/codeql-action
on: on:
schedule: #schedule:
- cron: '30 23 * * *' # run at 11:30 PM UTC # - cron: '30 23 * * *' # run at 11:30 PM UTC
# Allow manual runs # Allow manual runs
workflow_dispatch: workflow_dispatch:
+5 -1
View File
@@ -17,4 +17,8 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: make -C test ${{ matrix.target }} - run: make -C test ${{ matrix.target }} ARGS="-max_total_time=7200"
# as we're not getting access to test units causing a problem, convert from the log:
# base64 -d > dataofdeath
# then paste the base64 data, enter, Ctrl-D; maybe check with hexdump -C dataofdeath
+45 -34
View File
@@ -33,11 +33,11 @@ jobs:
env: env:
CC: ${{ matrix.cc }} CC: ${{ matrix.cc }}
SSL: ${{ matrix.ssl }} SSL: ${{ matrix.ssl }}
TFLAGS: ${{ matrix.select }} TFLAGS: ${{ matrix.select }} -DMQTT_LOCALHOST
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev && make -C test ${{ matrix.target }} - run: sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev && test/setup_mqtt_server.sh && make -C test ${{ matrix.target }}
mip: mip:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
@@ -46,14 +46,31 @@ jobs:
cc: [gcc, clang, g++, clang++] cc: [gcc, clang, g++, clang++]
target: [mip_test, mip_tap_test] target: [mip_test, mip_tap_test]
ssl: ["", BUILTIN, MBEDTLS, OPENSSL, WOLFSSL] ssl: ["", BUILTIN, MBEDTLS, OPENSSL, WOLFSSL]
# #3226: built-in TCP is currently not working with WolfSSL (builds fine)
exclude:
- ssl: WOLFSSL
target: mip_tap_test
name: ${{ matrix.target }} CC=${{ matrix.cc }} SSL=${{ matrix.ssl }} name: ${{ matrix.target }} CC=${{ matrix.cc }} SSL=${{ matrix.ssl }}
env: env:
CC: ${{ matrix.cc }} CC: ${{ matrix.cc }}
SSL: ${{ matrix.ssl }} SSL: ${{ matrix.ssl }}
TFLAGS: -DMQTT_LOCALHOST
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: if [ "${{ matrix.target }}" == "mip_tap_test" ]; then ./test/setup_ga_network.sh ; fi && sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev && make -C test ${{ matrix.target }} IPV6=0 - run: if [ "${{ matrix.target }}" == "mip_tap_test" ]; then ./test/setup_ga_network.sh ; fi && sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev && make -C test ${{ matrix.target }} IPV6=0
mip89:
runs-on: ubuntu-latest
strategy:
fail-fast: false
max-parallel: 1 # no parallel runs, to minimize MQTT errors
matrix:
target: [mip_vc98]
name: mip89 ${{ matrix.target }}
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- run: make -C test ${{ matrix.target }}
s390: s390:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
@@ -61,10 +78,12 @@ jobs:
matrix: matrix:
ssl: ["", BUILTIN] ssl: ["", BUILTIN]
name: S390 SSL=${{ matrix.ssl }} name: S390 SSL=${{ matrix.ssl }}
env:
TFLAGS: -DMQTT_LOCALHOST
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: sudo apt -y update ; sudo apt -y install binfmt-support qemu-user-static && docker run --rm --privileged multiarch/qemu-user-static --reset -p yes && make -C test s390 SSL=${{ matrix.ssl }} - run: sudo apt -y update ; sudo apt -y install binfmt-support qemu-user-static && ./test/setup_mqtt_server.sh && docker run --rm --privileged multiarch/qemu-user-static --reset -p yes && make -C test s390 SSL=${{ matrix.ssl }} MULTIREC=NO
armhf: armhf:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
@@ -72,10 +91,12 @@ jobs:
matrix: matrix:
ssl: ["", BUILTIN] ssl: ["", BUILTIN]
name: ArmHF SSL=${{ matrix.ssl }} name: ArmHF SSL=${{ matrix.ssl }}
env:
TFLAGS: -DMQTT_LOCALHOST
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: sudo apt -y update ; sudo apt -y install binfmt-support qemu-user-static && docker run --rm --privileged multiarch/qemu-user-static --reset -p yes && make -C test armhf SSL=${{ matrix.ssl }} - run: sudo apt -y update ; sudo apt -y install binfmt-support qemu-user-static && ./test/setup_mqtt_server.sh && docker run --rm --privileged multiarch/qemu-user-static --reset -p yes && make -C test armhf SSL=${{ matrix.ssl }} MULTIREC=NO
unamalgamated-mg_prefix: unamalgamated-mg_prefix:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
@@ -87,7 +108,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev - run: sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev
- run: make -C test unamalgamated && make -C test mg_prefix - run: make -C test unamalgamated SSL=${{ matrix.ssl }} && make -C test mg_prefix
valgrind: valgrind:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
@@ -95,34 +116,43 @@ jobs:
matrix: matrix:
ssl: ["", BUILTIN, MBEDTLS, OPENSSL, WOLFSSL] ssl: ["", BUILTIN, MBEDTLS, OPENSSL, WOLFSSL]
name: Valgrind SSL=${{ matrix.ssl }} name: Valgrind SSL=${{ matrix.ssl }}
env:
TFLAGS: -DMQTT_LOCALHOST
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev valgrind - run: sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev valgrind
- run: make -C test valgrind SSL=${{ matrix.ssl }} - run: ./test/setup_mqtt_server.sh && make -C test valgrind SSL=${{ matrix.ssl }}
macos: macos:
runs-on: macos-latest runs-on: macos-latest
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
ssl: ["", BUILTIN, MBEDTLS, OPENSSL, WOLFSSL] # Mongoose does not work with WolfSSL version in MacOS
ssl: ["", BUILTIN, MBEDTLS, OPENSSL] # , WOLFSSL]
select: [-DMG_ENABLE_POLL=0, -DMG_ENABLE_POLL=1] select: [-DMG_ENABLE_POLL=0, -DMG_ENABLE_POLL=1]
include:
- ssl: MBEDTLS
env:
# MbedTLS version in MacOS refuses to validate a certificate without a hostname, causing MQTT tests to fail when using MQTT_LOCALHOST
tflags: -DNO_MQTT_TESTS
exclude: exclude:
- ssl: MBEDTLS - ssl: MBEDTLS
select: -DMG_ENABLE_POLL=0 select: -DMG_ENABLE_POLL=0
- ssl: OPENSSL - ssl: OPENSSL
select: -DMG_ENABLE_POLL=0 select: -DMG_ENABLE_POLL=0
- ssl: WOLFSSL #- ssl: WOLFSSL
select: -DMG_ENABLE_POLL=0 # select: -DMG_ENABLE_POLL=0
name: macos SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }} name: macos SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }}
env: env:
SSL: ${{ matrix.ssl }} SSL: ${{ matrix.ssl }}
TFLAGS: ${{ matrix.select }} -Wno-sign-conversion # Workaround for MbedTLS 3.5.0 TFLAGS: ${{ matrix.select }} -DMQTT_LOCALHOST ${{ matrix.env.tflags }} -Wno-sign-conversion # Workaround for MbedTLS 3.5.0
HOMEBREW_NO_AUTO_UPDATE: 1 HOMEBREW_NO_AUTO_UPDATE: 1
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: brew install mbedtls wolfssl # jq openssl already pre-installed - run: brew install mbedtls wolfssl mosquitto # jq openssl already pre-installed
- run: /opt/homebrew/opt/mosquitto/sbin/mosquitto -c /Users/runner/work/mongoose/mongoose/test/mosquitto.conf.macos &
- run: make -C test test ASAN_OPTIONS= MBEDTLS=$(echo $(brew --cellar)/mbedtls*/*) OPENSSL=$(echo $(brew --cellar)/openssl*/*) WOLFSSL=$(echo $(brew --cellar)/wolfssl*/*) - run: make -C test test ASAN_OPTIONS= MBEDTLS=$(echo $(brew --cellar)/mbedtls*/*) OPENSSL=$(echo $(brew --cellar)/openssl*/*) WOLFSSL=$(echo $(brew --cellar)/wolfssl*/*)
windows: windows:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -138,12 +168,12 @@ jobs:
select: -DMG_ENABLE_POLL=1 select: -DMG_ENABLE_POLL=1
name: windows ${{ matrix.target }} SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }} name: windows ${{ matrix.target }} SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }}
env: env:
SSL: SSL=${{ matrix.ssl }} SSL: ${{ matrix.ssl }}
TFLAGS: ${{ matrix.select }} TFLAGS: ${{ matrix.select }} -DMQTT_LOCALHOST
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: make -C test ${{ matrix.target }} - run: ./test/setup_mqtt_server.sh && make -C test ${{ matrix.target }}
arm: arm:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
@@ -303,7 +333,6 @@ jobs:
matrix: matrix:
example: example:
- path: mqtt/mqtt-client/microchip/same54-xpro - path: mqtt/mqtt-client/microchip/same54-xpro
- path: nxp/nxp-mimxrt1020-azurertos
- path: nxp/nxp-frdmk66f-freertos - path: nxp/nxp-frdmk66f-freertos
- path: nxp/nxp-lpcxpresso54s018m-freertos - path: nxp/nxp-lpcxpresso54s018m-freertos
- path: nxp/nxp-mimxrt1020-freertos - path: nxp/nxp-mimxrt1020-freertos
@@ -357,7 +386,7 @@ jobs:
matrix: matrix:
ssl: ["", -DMG_TLS=MG_TLS_BUILTIN] ssl: ["", -DMG_TLS=MG_TLS_BUILTIN]
example: example:
- path: tutorials/http/device-dashboard/microchip/same54-xpro - path: http/device-dashboard/microchip/same54-xpro
- path: nxp/rt1020-evk-make-freertos-builtin - path: nxp/rt1020-evk-make-freertos-builtin
- path: nxp/rt1060-evk-make-freertos-builtin - path: nxp/rt1060-evk-make-freertos-builtin
- path: nxp/rt1170-evk-make-freertos-builtin - path: nxp/rt1170-evk-make-freertos-builtin
@@ -425,24 +454,6 @@ jobs:
- run: sudo pip install yq - run: sudo pip install yq
- run: cd test/cube && make - run: cd test/cube && make
zephyr_examples:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/zephyr init REPO=zephyrprojectrtos/ci:v0.26.14 # "no space left on device" with newers
- name: minify manifest
uses: mikefarah/yq@master
with:
cmd: yq -i eval '(.manifest.defaults, .manifest.remotes, .manifest.projects[] | select(.name == "cmsis" or .name == "hal_stm32" or .name == "mbedtls" or .name == "mcuboot" or .name == "picolibc" | del(.null) ), .manifest.self) as $i ireduce({};setpath($i | path; $i)) | del(.manifest.projects.[].null) | del(..|select(length==0))' tutorials/zephyr/zephyrproject/zephyr/west.yml
- run: make -C tutorials/zephyr update
- run: make -C tutorials/zephyr/device-dashboard build
- run: make -C tutorials/zephyr/http-client build
- run: make -C tutorials/zephyr/http-server build
- run: make -C tutorials/zephyr/mqtt-aws-client build
- run: make -C tutorials/zephyr/websocket-server build
test_f7: test_f7:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
+351 -339
View File
@@ -5,6 +5,8 @@ on:
- "**Makefile" - "**Makefile"
- "**.c" - "**.c"
- "**.h" - "**.h"
# Allow manual runs
workflow_dispatch:
env: env:
IPV6: 0 IPV6: 0
jobs: jobs:
@@ -20,28 +22,33 @@ jobs:
env: env:
CC: ${{ matrix.cc }} CC: ${{ matrix.cc }}
SSL: ${{ matrix.ssl }} SSL: ${{ matrix.ssl }}
TFLAGS: -DMQTT_LOCALHOST
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: if ./test/match_changed_files.sh '^test|^src/.*.[ch]' ; then echo GO=1 >> $GITHUB_ENV ; fi - run: if ./test/match_changed_files.sh '^test|^src/.*.[ch]' ; then echo GO=1 >> $GITHUB_ENV ; fi
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
run: make -C test ${{ matrix.target }} run: if [ "${{ matrix.target }}" == "test" ]; then ./test/setup_mqtt_server.sh ; fi && make -C test ${{ matrix.target }}
s390: s390:
runs-on: ubuntu-latest runs-on: ubuntu-latest
env:
TFLAGS: -DMQTT_LOCALHOST
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: if ./test/match_changed_files.sh '^test|^src/.*.[ch]' ; then echo GO=1 >> $GITHUB_ENV ; fi - run: if ./test/match_changed_files.sh '^test|^src/.*.[ch]' ; then echo GO=1 >> $GITHUB_ENV ; fi
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
run: sudo apt -y update ; sudo apt -y install binfmt-support qemu-user-static && docker run --rm --privileged multiarch/qemu-user-static --reset -p yes && make -C test s390 run: sudo apt -y update ; sudo apt -y install binfmt-support qemu-user-static && ./test/setup_mqtt_server.sh && docker run --rm --privileged multiarch/qemu-user-static --reset -p yes && make -C test s390
armhf: armhf:
runs-on: ubuntu-latest runs-on: ubuntu-latest
env:
TFLAGS: -DMQTT_LOCALHOST
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: if ./test/match_changed_files.sh '^test|^src/.*.[ch]' ; then echo GO=1 >> $GITHUB_ENV ; fi - run: if ./test/match_changed_files.sh '^test|^src/.*.[ch]' ; then echo GO=1 >> $GITHUB_ENV ; fi
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
run: sudo apt -y update ; sudo apt -y install binfmt-support qemu-user-static && docker run --rm --privileged multiarch/qemu-user-static --reset -p yes && make -C test armhf run: sudo apt -y update ; sudo apt -y install binfmt-support qemu-user-static && ./test/setup_mqtt_server.sh && docker run --rm --privileged multiarch/qemu-user-static --reset -p yes && make -C test armhf
unamalgamated-mg_prefix: unamalgamated-mg_prefix:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -59,14 +66,17 @@ jobs:
name: macos SSL=${{ matrix.ssl }} name: macos SSL=${{ matrix.ssl }}
env: env:
SSL: ${{ matrix.ssl }} SSL: ${{ matrix.ssl }}
#TFLAGS: -DNO_SNTP_CHECK TFLAGS: -DMQTT_LOCALHOST # -DNO_SNTP_CHECK
HOMEBREW_NO_AUTO_UPDATE: 1 HOMEBREW_NO_AUTO_UPDATE: 1
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: if ./test/match_changed_files.sh '^test|^src/.*.[ch]' ; then echo GO=1 >> $GITHUB_ENV ; fi - run: if ./test/match_changed_files.sh '^test|^src/.*.[ch]' ; then echo GO=1 >> $GITHUB_ENV ; fi
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
run: make -C test test ASAN_OPTIONS= run: |
brew install mosquitto
/opt/homebrew/opt/mosquitto/sbin/mosquitto -c /Users/runner/work/mongoose/mongoose/test/mosquitto.conf.macos &
make -C test test ASAN_OPTIONS=
windows: windows:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
@@ -74,12 +84,14 @@ jobs:
matrix: matrix:
target: [vc98, vc22, mingw++] target: [vc98, vc22, mingw++]
name: windows ${{ matrix.target }} name: windows ${{ matrix.target }}
env:
TFLAGS: -DMQTT_LOCALHOST
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: if ./test/match_changed_files.sh '^test|^src/.*.[ch]' ; then echo GO=1 >> $GITHUB_ENV ; fi - run: if ./test/match_changed_files.sh '^test|^src/.*.[ch]' ; then echo GO=1 >> $GITHUB_ENV ; fi
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
run: make -C test ${{ matrix.target }} run: ./test/setup_mqtt_server.sh && make -C test ${{ matrix.target }}
arm: arm:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -335,360 +347,360 @@ jobs:
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
run: cd test/cube && make run: cd test/cube && make
test_f7: # test_f7:
runs-on: ubuntu-latest # runs-on: ubuntu-latest
env: # env:
GO: 0 # GO: 0
steps: # steps:
- uses: actions/checkout@v4 # - uses: actions/checkout@v4
with: { fetch-depth: 2 } # with: { fetch-depth: 2 }
- name: baremetal # - name: baremetal
run: |
if ./test/match_changed_files.sh "^src|tutorials/http/device-dashboard|tutorials/stm32/nucleo-f7.*-make-" ; then
echo GO=1 >> $GITHUB_ENV
sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
fi
# always run baremetal on core or dashboard or specific example changes; other examples only on specific example changes
- if: ${{ env.GO == 1 }}
continue-on-error: true # continue so next test has a chance to re-flash and exit from collisions and flash failures
run: |
if ./test/match_changed_files.sh '^src|tutorials/http/device-dashboard|tutorials/stm32/nucleo-f746zg-make-baremetal-builtin'; then
make -C tutorials/stm32/nucleo-f746zg-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
fi
- if: ${{ env.GO == 1 }}
run: |
if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-f746zg-make-freertos-builtin'; then
make -C tutorials/stm32/nucleo-f746zg-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
fi
- if: ${{ env.GO == 1 }}
run: |
if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-f746zg-make-freertos-tcp'; then
make -C tutorials/stm32/nucleo-f746zg-make-freertos-tcp test VCON_API_KEY=${{secrets.VCON_API_KEY}}
fi
- name: Cube
run: |
echo GO=0 >> $GITHUB_ENV
if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-f7.*-cube-'; then
echo GO=1 >> $GITHUB_ENV
# nothing specific to install or do
fi
# - if: ${{ env.GO == 1 }}
# run: | # run: |
# if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-f746zg-cube-baremetal-builtin'; then # if ./test/match_changed_files.sh "^src|tutorials/http/device-dashboard|tutorials/stm32/nucleo-f7.*-make-" ; then
# make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-f746zg-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5 # echo GO=1 >> $GITHUB_ENV
# sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
# fi
# # always run baremetal on core or dashboard or specific example changes; other examples only on specific example changes
# - if: ${{ env.GO == 1 }}
# continue-on-error: true # continue so next test has a chance to re-flash and exit from collisions and flash failures
# run: |
# if ./test/match_changed_files.sh '^src|tutorials/http/device-dashboard|tutorials/stm32/nucleo-f746zg-make-baremetal-builtin'; then
# make -C tutorials/stm32/nucleo-f746zg-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
# fi # fi
# - if: ${{ env.GO == 1 }} # - if: ${{ env.GO == 1 }}
# run: | # run: |
# if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-f746zg-cube-freertos-builtin'; then # if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-f746zg-make-freertos-builtin'; then
# make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-f746zg-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5 # make -C tutorials/stm32/nucleo-f746zg-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
# fi
- if: ${{ env.GO == 1 }}
run: |
if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-f746zg-cube-freertos-lwip'; then
make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-f746zg-cube-freertos-lwip VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5
fi
test_f4:
runs-on: ubuntu-latest
env:
GO: 0
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- name: baremetal
run: |
if ./test/match_changed_files.sh "^src|tutorials/http/device-dashboard|tutorials/stm32/nucleo-f4.*-make-" ; then
echo GO=1 >> $GITHUB_ENV
sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
fi
- if: ${{ env.GO == 1 }}
continue-on-error: true
run: |
if ./test/match_changed_files.sh '^src|tutorials/http/device-dashboard|tutorials/stm32/nucleo-f429zi-make-baremetal-builtin'; then
make -C tutorials/stm32/nucleo-f429zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
fi
- if: ${{ env.GO == 1 }}
run: |
if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-f429zi-make-freertos-builtin'; then
make -C tutorials/stm32/nucleo-f429zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
fi
- name: Cube
run: |
echo GO=0 >> $GITHUB_ENV
if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-f4.*-cube-'; then
echo GO=1 >> $GITHUB_ENV
# nothing specific to install or do
fi
# - if: ${{ env.GO == 1 }}
# run: |
# if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-f429zi-cube-baremetal-builtin'; then
# make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-f429zi-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
# fi # fi
# - if: ${{ env.GO == 1 }} # - if: ${{ env.GO == 1 }}
# run: | # run: |
# if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-f429zi-cube-freertos-builtin'; then # if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-f746zg-make-freertos-tcp'; then
# make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-f429zi-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2 # make -C tutorials/stm32/nucleo-f746zg-make-freertos-tcp test VCON_API_KEY=${{secrets.VCON_API_KEY}}
# fi # fi
- if: ${{ env.GO == 1 }}
run: |
if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-f429zi-cube-freertos-lwip'; then
make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-f429zi-cube-freertos-lwip VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
fi
test_h743:
runs-on: ubuntu-latest
env:
GO: 0
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: |
if ./test/match_changed_files.sh "^src|tutorials/http/device-dashboard|tutorials/stm32/nucleo-h74.*-make-" ; then
echo GO=1 >> $GITHUB_ENV
sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
fi
- if: ${{ env.GO == 1 }}
continue-on-error: true
run: |
if ./test/match_changed_files.sh '^src|tutorials/http/device-dashboard|tutorials/stm32/nucleo-h743zi-make-baremetal-builtin'; then
make -C tutorials/stm32/nucleo-h743zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
fi
- if: ${{ env.GO == 1 }}
run: |
if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-h743zi-make-freertos-builtin'; then
make -C tutorials/stm32/nucleo-h743zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
fi
# - name: Cube # - name: Cube
# run: | # run: |
# echo GO=0 >> $GITHUB_ENV # echo GO=0 >> $GITHUB_ENV
# if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-h74.*-cube-'; then # if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-f7.*-cube-'; then
# echo GO=1 >> $GITHUB_ENV # echo GO=1 >> $GITHUB_ENV
# # nothing specific to install or do # # nothing specific to install or do
# fi # fi
## - if: ${{ env.GO == 1 }}
## run: |
## if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-f746zg-cube-baremetal-builtin'; then
## make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-f746zg-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5
## fi
## - if: ${{ env.GO == 1 }}
## run: |
## if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-f746zg-cube-freertos-builtin'; then
## make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-f746zg-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5
## fi
# - if: ${{ env.GO == 1 }} # - if: ${{ env.GO == 1 }}
# run: | # run: |
# if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-h743zi-cube-baremetal-builtin'; then # if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-f746zg-cube-freertos-lwip'; then
# make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-h743zi-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=6 # make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-f746zg-cube-freertos-lwip VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5
# fi
#
#
# test_f4:
# runs-on: ubuntu-latest
# env:
# GO: 0
# steps:
# - uses: actions/checkout@v4
# with: { fetch-depth: 2 }
# - name: baremetal
# run: |
# if ./test/match_changed_files.sh "^src|tutorials/http/device-dashboard|tutorials/stm32/nucleo-f4.*-make-" ; then
# echo GO=1 >> $GITHUB_ENV
# sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
# fi
# - if: ${{ env.GO == 1 }}
# continue-on-error: true
# run: |
# if ./test/match_changed_files.sh '^src|tutorials/http/device-dashboard|tutorials/stm32/nucleo-f429zi-make-baremetal-builtin'; then
# make -C tutorials/stm32/nucleo-f429zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
# fi # fi
# - if: ${{ env.GO == 1 }} # - if: ${{ env.GO == 1 }}
# run: | # run: |
# if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-h743zi-cube-freertos-builtin'; then # if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-f429zi-make-freertos-builtin'; then
# make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-h743zi-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=6 # make -C tutorials/stm32/nucleo-f429zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
# fi # fi
# - name: Cube
test_h723: # run: |
runs-on: ubuntu-latest # echo GO=0 >> $GITHUB_ENV
env: # if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-f4.*-cube-'; then
GO: 0 # echo GO=1 >> $GITHUB_ENV
steps: # # nothing specific to install or do
- uses: actions/checkout@v4 # fi
with: { fetch-depth: 3 } ## - if: ${{ env.GO == 1 }}
- name: baremetal ## run: |
run: | ## if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-f429zi-cube-baremetal-builtin'; then
if ./test/match_changed_files.sh "^src|tutorials/http/device-dashboard|tutorials/stm32/nucleo-h72.*-make-" ; then ## make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-f429zi-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
echo GO=1 >> $GITHUB_ENV ## fi
sudo apt -y update && sudo apt -y install gcc-arm-none-eabi ## - if: ${{ env.GO == 1 }}
fi ## run: |
- if: ${{ env.GO == 1 }} ## if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-f429zi-cube-freertos-builtin'; then
continue-on-error: true ## make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-f429zi-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
run: | ## fi
if ./test/match_changed_files.sh '^src|tutorials/http/device-dashboard|tutorials/stm32/nucleo-h723zg-make-baremetal-builtin'; then
make -C tutorials/stm32/nucleo-h723zg-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
fi
- if: ${{ env.GO == 1 }}
run: |
if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-h723zg-make-freertos-builtin'; then
make -C tutorials/stm32/nucleo-h723zg-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
fi
test_h5:
runs-on: ubuntu-latest
env:
GO: 0
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: |
if ./test/match_changed_files.sh "^src|tutorials/http/device-dashboard|tutorials/stm32/nucleo-h5.*-make-" ; then
echo GO=1 >> $GITHUB_ENV
sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
fi
- if: ${{ env.GO == 1 }}
continue-on-error: true
run: |
if ./test/match_changed_files.sh '^src|tutorials/http/device-dashboard|tutorials/stm32/nucleo-h563zi-make-baremetal-builtin'; then
make -C tutorials/stm32/nucleo-h563zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
fi
- if: ${{ env.GO == 1 }}
run: |
if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-h563zi-make-freertos-builtin'; then
make -C tutorials/stm32/nucleo-h563zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
fi
test_rt1020:
runs-on: ubuntu-latest
env:
GO: 0
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: |
if ./test/match_changed_files.sh "^src|tutorials/http/device-dashboard|tutorials/nxp/rt1020.*-make-" ; then
echo GO=1 >> $GITHUB_ENV
sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
fi
- if: ${{ env.GO == 1 }}
continue-on-error: true
run: |
if ./test/match_changed_files.sh '^src|tutorials/http/device-dashboard|tutorials/nxp/rt1020-evk-make-baremetal-builtin'; then
make -C tutorials/nxp/rt1020-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
fi
- if: ${{ env.GO == 1 }}
run: |
if ./test/match_changed_files.sh 'tutorials/nxp/rt1020-evk-make-freertos-builtin'; then
make -C tutorials/nxp/rt1020-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
fi
test_rt1060:
runs-on: ubuntu-latest
env:
GO: 0
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: |
if ./test/match_changed_files.sh "^src|tutorials/http/device-dashboard|tutorials/nxp/rt1060.*-make-" ; then
echo GO=1 >> $GITHUB_ENV
sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
fi
- if: ${{ env.GO == 1 }}
continue-on-error: true
run: |
if ./test/match_changed_files.sh '^src|tutorials/http/device-dashboard|tutorials/nxp/rt1060-evk-make-baremetal-builtin'; then
make -C tutorials/nxp/rt1060-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
fi
- if: ${{ env.GO == 1 }}
run: |
if ./test/match_changed_files.sh 'tutorials/nxp/rt1060-evk-make-freertos-builtin'; then
make -C tutorials/nxp/rt1060-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
fi
test_rt1170:
runs-on: ubuntu-latest
env:
GO: 0
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: |
if ./test/match_changed_files.sh "^src|tutorials/http/device-dashboard|tutorials/nxp/rt1170.*-make-" ; then
echo GO=1 >> $GITHUB_ENV
sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
fi
- if: ${{ env.GO == 1 }}
continue-on-error: true
run: |
if ./test/match_changed_files.sh '^src|tutorials/http/device-dashboard|tutorials/nxp/rt1170-evk-make-baremetal-builtin'; then
make -C tutorials/nxp/rt1170-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
fi
- if: ${{ env.GO == 1 }}
run: |
if ./test/match_changed_files.sh 'tutorials/nxp/rt1170-evk-make-freertos-builtin'; then
make -C tutorials/nxp/rt1170-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
fi
test_ra6m4:
runs-on: ubuntu-latest
env:
GO: 0
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: |
if ./test/match_changed_files.sh "^src|tutorials/http/device-dashboard|tutorials/renesas/ek-ra6m4.*-make-" ; then
echo GO=1 >> $GITHUB_ENV
sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
fi
- if: ${{ env.GO == 1 }}
continue-on-error: true
run: |
if ./test/match_changed_files.sh '^src|tutorials/http/device-dashboard|tutorials/renesas/ek-ra6m4-make-baremetal-builtin'; then
make -C tutorials/renesas/ek-ra6m4-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
fi
# - if: ${{ env.GO == 1 }} # - if: ${{ env.GO == 1 }}
# run: | # run: |
# if ./test/match_changed_files.sh 'tutorials/renesas/ek-ra6m4-make-freertos-builtin'; then # if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-f429zi-cube-freertos-lwip'; then
# make -C tutorials/renesas/ek-ra6m4-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}} # make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-f429zi-cube-freertos-lwip VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
# fi # fi
#
test_tm4c: # test_h743:
runs-on: ubuntu-latest # runs-on: ubuntu-latest
env: # env:
GO: 0 # GO: 0
steps: # steps:
- uses: actions/checkout@v4 # - uses: actions/checkout@v4
with: { fetch-depth: 2 } # with: { fetch-depth: 3 }
- name: baremetal # - name: baremetal
run: | # run: |
if ./test/match_changed_files.sh "^src|tutorials/http/device-dashboard|tutorials/ti/ek-tm4c.*-make-" ; then # if ./test/match_changed_files.sh "^src|tutorials/http/device-dashboard|tutorials/stm32/nucleo-h74.*-make-" ; then
echo GO=1 >> $GITHUB_ENV # echo GO=1 >> $GITHUB_ENV
sudo apt -y update && sudo apt -y install gcc-arm-none-eabi # sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
fi # fi
- if: ${{ env.GO == 1 }} # - if: ${{ env.GO == 1 }}
run: | # continue-on-error: true
if ./test/match_changed_files.sh '^src|tutorials/http/device-dashboard|tutorials/ti/ek-tm4c1294xl-make-baremetal-builtin'; then # run: |
make -C tutorials/ti/ek-tm4c1294xl-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}} # if ./test/match_changed_files.sh '^src|tutorials/http/device-dashboard|tutorials/stm32/nucleo-h743zi-make-baremetal-builtin'; then
fi # make -C tutorials/stm32/nucleo-h743zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- if: ${{ env.GO == 1 }} # fi
run: | # - if: ${{ env.GO == 1 }}
if ./test/match_changed_files.sh 'tutorials/ti/ek-tm4c1294xl-make-freertos-builtin'; then # run: |
make -C tutorials/ti/ek-tm4c1294xl-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}} # if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-h743zi-make-freertos-builtin'; then
fi # make -C tutorials/stm32/nucleo-h743zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
# fi
test_same54: ## - name: Cube
runs-on: ubuntu-latest ## run: |
env: ## echo GO=0 >> $GITHUB_ENV
GO: 0 ## if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-h74.*-cube-'; then
steps: ## echo GO=1 >> $GITHUB_ENV
- uses: actions/checkout@v4 ## # nothing specific to install or do
with: { fetch-depth: 2 } ## fi
- name: baremetal ## - if: ${{ env.GO == 1 }}
run: | ## run: |
if ./test/match_changed_files.sh "^src|tutorials/http/device-dashboard|tutorials/mqtt/mqtt-client" ; then ## if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-h743zi-cube-baremetal-builtin'; then
echo GO=1 >> $GITHUB_ENV ## make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-h743zi-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=6
sudo apt -y update && sudo apt -y install gcc-arm-none-eabi ## fi
fi ## - if: ${{ env.GO == 1 }}
- if: ${{ env.GO == 1 }} ## run: |
run: | ## if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-h743zi-cube-freertos-builtin'; then
if ./test/match_changed_files.sh '^src|tutorials/http/device-dashboard'; then ## make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-h743zi-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=6
make -C tutorials/http/device-dashboard/microchip/same54-xpro test VCON_API_KEY=${{secrets.VCON_API_KEY}} ## fi
fi #
- if: ${{ env.GO == 1 }} # test_h723:
run: | # runs-on: ubuntu-latest
if ./test/match_changed_files.sh '^src|tutorials/mqtt/mqtt-client'; then # env:
make -C tutorials/mqtt/mqtt-client/microchip/same54-xpro test VCON_API_KEY=${{secrets.VCON_API_KEY}} # GO: 0
fi # steps:
# - uses: actions/checkout@v4
test_pico_w5500: # with: { fetch-depth: 3 }
runs-on: ubuntu-latest # - name: baremetal
env: # run: |
GO: 0 # if ./test/match_changed_files.sh "^src|tutorials/http/device-dashboard|tutorials/stm32/nucleo-h72.*-make-" ; then
steps: # echo GO=1 >> $GITHUB_ENV
- uses: actions/checkout@v4 # sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
with: { fetch-depth: 2 } # fi
- name: SDK # - if: ${{ env.GO == 1 }}
run: | # continue-on-error: true
if ./test/match_changed_files.sh "^src" ; then # run: |
echo GO=1 >> $GITHUB_ENV # if ./test/match_changed_files.sh '^src|tutorials/http/device-dashboard|tutorials/stm32/nucleo-h723zg-make-baremetal-builtin'; then
sudo apt -y update && sudo apt -y install gcc-arm-none-eabi # make -C tutorials/stm32/nucleo-h723zg-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
fi # fi
- if: ${{ env.GO == 1 }} # - if: ${{ env.GO == 1 }}
run: make -C tutorials/pico-sdk/w5500-evb-pico-picosdk-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}} # run: |
# if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-h723zg-make-freertos-builtin'; then
# make -C tutorials/stm32/nucleo-h723zg-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
# fi
#
# test_h5:
# runs-on: ubuntu-latest
# env:
# GO: 0
# steps:
# - uses: actions/checkout@v4
# with: { fetch-depth: 3 }
# - name: baremetal
# run: |
# if ./test/match_changed_files.sh "^src|tutorials/http/device-dashboard|tutorials/stm32/nucleo-h5.*-make-" ; then
# echo GO=1 >> $GITHUB_ENV
# sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
# fi
# - if: ${{ env.GO == 1 }}
# continue-on-error: true
# run: |
# if ./test/match_changed_files.sh '^src|tutorials/http/device-dashboard|tutorials/stm32/nucleo-h563zi-make-baremetal-builtin'; then
# make -C tutorials/stm32/nucleo-h563zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
# fi
# - if: ${{ env.GO == 1 }}
# run: |
# if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-h563zi-make-freertos-builtin'; then
# make -C tutorials/stm32/nucleo-h563zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
# fi
#
# test_rt1020:
# runs-on: ubuntu-latest
# env:
# GO: 0
# steps:
# - uses: actions/checkout@v4
# with: { fetch-depth: 3 }
# - name: baremetal
# run: |
# if ./test/match_changed_files.sh "^src|tutorials/http/device-dashboard|tutorials/nxp/rt1020.*-make-" ; then
# echo GO=1 >> $GITHUB_ENV
# sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
# fi
# - if: ${{ env.GO == 1 }}
# continue-on-error: true
# run: |
# if ./test/match_changed_files.sh '^src|tutorials/http/device-dashboard|tutorials/nxp/rt1020-evk-make-baremetal-builtin'; then
# make -C tutorials/nxp/rt1020-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
# fi
# - if: ${{ env.GO == 1 }}
# run: |
# if ./test/match_changed_files.sh 'tutorials/nxp/rt1020-evk-make-freertos-builtin'; then
# make -C tutorials/nxp/rt1020-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
# fi
#
# test_rt1060:
# runs-on: ubuntu-latest
# env:
# GO: 0
# steps:
# - uses: actions/checkout@v4
# with: { fetch-depth: 3 }
# - name: baremetal
# run: |
# if ./test/match_changed_files.sh "^src|tutorials/http/device-dashboard|tutorials/nxp/rt1060.*-make-" ; then
# echo GO=1 >> $GITHUB_ENV
# sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
# fi
# - if: ${{ env.GO == 1 }}
# continue-on-error: true
# run: |
# if ./test/match_changed_files.sh '^src|tutorials/http/device-dashboard|tutorials/nxp/rt1060-evk-make-baremetal-builtin'; then
# make -C tutorials/nxp/rt1060-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
# fi
# - if: ${{ env.GO == 1 }}
# run: |
# if ./test/match_changed_files.sh 'tutorials/nxp/rt1060-evk-make-freertos-builtin'; then
# make -C tutorials/nxp/rt1060-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
# fi
#
# test_rt1170:
# runs-on: ubuntu-latest
# env:
# GO: 0
# steps:
# - uses: actions/checkout@v4
# with: { fetch-depth: 3 }
# - name: baremetal
# run: |
# if ./test/match_changed_files.sh "^src|tutorials/http/device-dashboard|tutorials/nxp/rt1170.*-make-" ; then
# echo GO=1 >> $GITHUB_ENV
# sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
# fi
# - if: ${{ env.GO == 1 }}
# continue-on-error: true
# run: |
# if ./test/match_changed_files.sh '^src|tutorials/http/device-dashboard|tutorials/nxp/rt1170-evk-make-baremetal-builtin'; then
# make -C tutorials/nxp/rt1170-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
# fi
# - if: ${{ env.GO == 1 }}
# run: |
# if ./test/match_changed_files.sh 'tutorials/nxp/rt1170-evk-make-freertos-builtin'; then
# make -C tutorials/nxp/rt1170-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
# fi
#
# test_ra6m4:
# runs-on: ubuntu-latest
# env:
# GO: 0
# steps:
# - uses: actions/checkout@v4
# with: { fetch-depth: 3 }
# - name: baremetal
# run: |
# if ./test/match_changed_files.sh "^src|tutorials/http/device-dashboard|tutorials/renesas/ek-ra6m4.*-make-" ; then
# echo GO=1 >> $GITHUB_ENV
# sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
# fi
# - if: ${{ env.GO == 1 }}
# continue-on-error: true
# run: |
# if ./test/match_changed_files.sh '^src|tutorials/http/device-dashboard|tutorials/renesas/ek-ra6m4-make-baremetal-builtin'; then
# make -C tutorials/renesas/ek-ra6m4-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
# fi
## - if: ${{ env.GO == 1 }}
## run: |
## if ./test/match_changed_files.sh 'tutorials/renesas/ek-ra6m4-make-freertos-builtin'; then
## make -C tutorials/renesas/ek-ra6m4-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
## fi
#
# test_tm4c:
# runs-on: ubuntu-latest
# env:
# GO: 0
# steps:
# - uses: actions/checkout@v4
# with: { fetch-depth: 2 }
# - name: baremetal
# run: |
# if ./test/match_changed_files.sh "^src|tutorials/http/device-dashboard|tutorials/ti/ek-tm4c.*-make-" ; then
# echo GO=1 >> $GITHUB_ENV
# sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
# fi
# - if: ${{ env.GO == 1 }}
# run: |
# if ./test/match_changed_files.sh '^src|tutorials/http/device-dashboard|tutorials/ti/ek-tm4c1294xl-make-baremetal-builtin'; then
# make -C tutorials/ti/ek-tm4c1294xl-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
# fi
# - if: ${{ env.GO == 1 }}
# run: |
# if ./test/match_changed_files.sh 'tutorials/ti/ek-tm4c1294xl-make-freertos-builtin'; then
# make -C tutorials/ti/ek-tm4c1294xl-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
# fi
#
# test_same54:
# runs-on: ubuntu-latest
# env:
# GO: 0
# steps:
# - uses: actions/checkout@v4
# with: { fetch-depth: 2 }
# - name: baremetal
# run: |
# if ./test/match_changed_files.sh "^src|tutorials/http/device-dashboard|tutorials/mqtt/mqtt-client" ; then
# echo GO=1 >> $GITHUB_ENV
# sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
# fi
# - if: ${{ env.GO == 1 }}
# run: |
# if ./test/match_changed_files.sh '^src|tutorials/http/device-dashboard'; then
# make -C tutorials/http/device-dashboard/microchip/same54-xpro test VCON_API_KEY=${{secrets.VCON_API_KEY}}
# fi
# - if: ${{ env.GO == 1 }}
# run: |
# if ./test/match_changed_files.sh '^src|tutorials/mqtt/mqtt-client'; then
# make -C tutorials/mqtt/mqtt-client/microchip/same54-xpro test VCON_API_KEY=${{secrets.VCON_API_KEY}}
# fi
#
# test_pico_w5500:
# runs-on: ubuntu-latest
# env:
# GO: 0
# steps:
# - uses: actions/checkout@v4
# with: { fetch-depth: 2 }
# - name: SDK
# run: |
# if ./test/match_changed_files.sh "^src" ; then
# echo GO=1 >> $GITHUB_ENV
# sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
# fi
# - if: ${{ env.GO == 1 }}
# run: make -C tutorials/pico-sdk/w5500-evb-pico-picosdk-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
+26
View File
@@ -0,0 +1,26 @@
name: Zephyr
on:
schedule:
- cron: '0 0 * * *' # run at 12 AM UTC
# Allow manual runs
workflow_dispatch:
jobs:
zephyr_examples:
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
revno: ["--mr v3.7-branch", "--mr v4.2.0"] # LTS, latest stable
name: Zephyr ${{ matrix.revno }}
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- run: test/setup_ga_docker_filesystem.sh
- run: make -C tutorials/zephyr init REPO=zephyrprojectrtos/ci REVNO="${{ matrix.revno }}"
- run: make -C tutorials/zephyr minify REVNO="${{ matrix.revno }}"
- run: make -C tutorials/zephyr update
- run: make -C tutorials/zephyr/device-dashboard build
- run: make -C tutorials/zephyr/http-client build
- run: make -C tutorials/zephyr/http-server build
- run: make -C tutorials/zephyr/mqtt-aws-client build
- run: make -C tutorials/zephyr/websocket-server build
+35 -3
View File
@@ -1,10 +1,9 @@
# Mongoose - Embedded Web Server / Embedded Network Library # Mongoose - Embedded Web Server / Embedded Network Library
[![License: GPLv2/Commercial](https://img.shields.io/badge/License-GPLv2%20or%20Commercial-green.svg)](https://opensource.org/licenses/gpl-2.0.php) [![License: GPLv2/Commercial](https://img.shields.io/badge/License-GPLv2%20or%20Commercial-green.svg)](https://opensource.org/licenses/gpl-2.0.php)
[![Build Status]( https://github.com/cesanta/mongoose/workflows/build/badge.svg)](https://github.com/cesanta/mongoose/actions) [![Build Status]( https://github.com/cesanta/mongoose/actions/workflows/quicktest.yml/badge.svg)](https://github.com/cesanta/mongoose/actions)
[![Code Coverage](https://codecov.io/gh/cesanta/mongoose/branch/master/graph/badge.svg)](https://codecov.io/gh/cesanta/mongoose) [![Code Coverage](https://codecov.io/gh/cesanta/mongoose/branch/master/graph/badge.svg)](https://codecov.io/gh/cesanta/mongoose)
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/mongoose.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:mongoose) [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/mongoose.svg)](https://issues.oss-fuzz.com/issues?sort=-opened&can=1&q=proj:mongoose)
[![Gurubase](https://img.shields.io/badge/Gurubase-Ask%20Mongoose%20Guru-006BFF)](https://gurubase.io/g/mongoose)
Mongoose is a network library for C/C++. It provides event-driven non-blocking Mongoose is a network library for C/C++. It provides event-driven non-blocking
APIs for TCP, UDP, HTTP, WebSocket, MQTT, and other protocols. It is designed APIs for TCP, UDP, HTTP, WebSocket, MQTT, and other protocols. It is designed
@@ -35,6 +34,35 @@ robust, and easy. Features include:
See https://mongoose.ws/ for complete documentation, videos, case studies, etc. See https://mongoose.ws/ for complete documentation, videos, case studies, etc.
## Supported platforms
Mongoose can work on top of any TCP/IP stack that supports BSD sockets API.
Platforms supported by the 3rd party TCP/IP stacks:
| TCP/IP stack | Notes |
| :-------------- | :------- |
| **lwIP** | All devices running lwIP, for example ESP32, ESP32S3, ESP32C3, ESP32C6, etc |
| **Zephyr** | All devices supported by Zephyr |
| **Other** | Any other TCP/IP stack that supports BSD socket API, for example Amazon FreeRTOS-TCP |
| **Linux, Mac, Windows** | Workstations, server, single board computers, embedded Linux devices running on MPUs or FPGAs |
Optionally, Mongoose provides its own built-in TCP/IP stack, eliminating the
need for additional software to implement networking functionality. The
built-in stack supports operation in both bare-metal and RTOS environments.
Platforms supported by the Mongoose built-in TCP/IP stack:
| Hardware | Notes |
| :------------- | :------- |
| **STM32** | All STM32 MCUs with built-in Ethernet: STM32Fxx, STM32H5xx, STM32H7xx |
| **NXP** | All NXP MCUs with built-in Ethernet: IMXRT102x, IMXRT104x, IMXRT105x, IMXRT106x, IMXRT117x, RW612, MCXN94x |
| **Microchip** | ATSAME54 MCUs with built-int Ethernet |
| **Renesas** | RA5M, RA6M, RA8M MCUs with built-in Ethernet |
| **Infineon** | XMC4, XMC7 MCUs with built-in Ethernet |
| **Texas Instruments** | TM4C, TMS570 MCUs with built-in Ethernet |
| **Cypress WiFi** | Any MCU with CY43xx WiFi chips, like RP2040 Pico-W, RP2350 Pico2-W, Arduino Portenta |
| **Wiznet Ethernet** | Any MCU that use Wiznet W5500 or Wiznet 5100 MAC+PHY chips |
| **Cellular** | NRF9160, SIM800 |
## Usage Examples ## Usage Examples
Below are quick snippets that should give an idea how simple the API is and Below are quick snippets that should give an idea how simple the API is and
@@ -177,6 +205,10 @@ Technical guides and deep dives into embedded web servers, WebUI integration and
- [Embedded Web Server: A Comprehensive Guide for Modern Connected Devices](https://mongoose.ws/articles/embedded-web-server-a-comprehensive-guide-for-modern-connected-devices/) - [Embedded Web Server: A Comprehensive Guide for Modern Connected Devices](https://mongoose.ws/articles/embedded-web-server-a-comprehensive-guide-for-modern-connected-devices/)
- [Building Embedded Web Device Dashboards](https://mongoose.ws/articles/building-embedded-web-device-dashboard/) - [Building Embedded Web Device Dashboards](https://mongoose.ws/articles/building-embedded-web-device-dashboard/)
- [ESP32 Device Dashboard: A Step-by-Step Guide for Developers](https://mongoose.ws/articles/esp32-device-dashboard/) - [ESP32 Device Dashboard: A Step-by-Step Guide for Developers](https://mongoose.ws/articles/esp32-device-dashboard/)
- [How to build an STM32 Web Dashboard](https://mongoose.ws/articles/stm32-device-dashboard/)
- [STM32 WebSocket Guide](https://mongoose.ws/articles/stm32-websocket-guide/)
- [Web File Manager on STM32, ESP32 and Embedded Linux](https://mongoose.ws/articles/building-a-web-file-manager-on-stm32-esp32-embedded-linux/)
- [Web dashboard on Zephyr RTOS](https://mongoose.ws/articles/web-dashboard-on-zephyr-rtos/)
## Contributions ## Contributions
+1229 -666
View File
File diff suppressed because it is too large. Load diff
+620 -383
View File
File diff suppressed because it is too large. Load diff
+9 -4
View File
@@ -6,9 +6,9 @@
#define MG_ARCH_ESP32 3 // ESP32 #define MG_ARCH_ESP32 3 // ESP32
#define MG_ARCH_ESP8266 4 // ESP8266 #define MG_ARCH_ESP8266 4 // ESP8266
#define MG_ARCH_FREERTOS 5 // FreeRTOS #define MG_ARCH_FREERTOS 5 // FreeRTOS
#define MG_ARCH_AZURERTOS 6 // MS Azure RTOS #define MG_ARCH_THREADX 6 // Eclipse ThreadX (former MS Azure RTOS)
#define MG_ARCH_ZEPHYR 7 // Zephyr RTOS #define MG_ARCH_ZEPHYR 7 // Zephyr RTOS
#define MG_ARCH_NEWLIB 8 // Bare metal ARM #define MG_ARCH_ARMGCC 8 // Plain ARM GCC
#define MG_ARCH_CMSIS_RTOS1 9 // CMSIS-RTOS API v1 (Keil RTX) #define MG_ARCH_CMSIS_RTOS1 9 // CMSIS-RTOS API v1 (Keil RTX)
#define MG_ARCH_TIRTOS 10 // Texas Semi TI-RTOS #define MG_ARCH_TIRTOS 10 // Texas Semi TI-RTOS
#define MG_ARCH_PICOSDK 11 // Raspberry Pi Pico-SDK (RP2040, RP2350) #define MG_ARCH_PICOSDK 11 // Raspberry Pi Pico-SDK (RP2040, RP2350)
@@ -16,6 +16,9 @@
#define MG_ARCH_CMSIS_RTOS2 13 // CMSIS-RTOS API v2 (Keil RTX5, FreeRTOS) #define MG_ARCH_CMSIS_RTOS2 13 // CMSIS-RTOS API v2 (Keil RTX5, FreeRTOS)
#define MG_ARCH_RTTHREAD 14 // RT-Thread RTOS #define MG_ARCH_RTTHREAD 14 // RT-Thread RTOS
#define MG_ARCH_ARMCGT 15 // Texas Semi ARM-CGT #define MG_ARCH_ARMCGT 15 // Texas Semi ARM-CGT
#define MG_ARCH_CUBE 16 // STM32Cube environment
#define MG_ARCH_NEWLIB MG_ARCH_ARMGCC // Alias, deprecate in 2025
#if !defined(MG_ARCH) #if !defined(MG_ARCH)
#if defined(__unix__) || defined(__APPLE__) #if defined(__unix__) || defined(__APPLE__)
@@ -30,17 +33,19 @@
#endif #endif
#if !defined(MG_ARCH) #if !defined(MG_ARCH)
#error "MG_ARCH is not specified and we couldn't guess it. Define MG_ARCH=... in your compiler" #error "MG_ARCH is not specified and we couldn't guess it. Define MG_ARCH=... in mongoose_config.h"
#endif #endif
// http://esr.ibiblio.org/?p=5095 // http://esr.ibiblio.org/?p=5095
#define MG_BIG_ENDIAN (*(uint16_t *) "\0\xff" < 0x100) #define MG_BIG_ENDIAN (*(uint16_t *) "\0\xff" < 0x100)
#include "arch_armgcc.h"
#include "arch_cube.h"
#include "arch_esp32.h" #include "arch_esp32.h"
#include "arch_esp8266.h" #include "arch_esp8266.h"
#include "arch_freertos.h" #include "arch_freertos.h"
#include "arch_newlib.h"
#include "arch_rtx.h" #include "arch_rtx.h"
#include "arch_threadx.h"
#include "arch_unix.h" #include "arch_unix.h"
#include "arch_win32.h" #include "arch_win32.h"
#include "arch_zephyr.h" #include "arch_zephyr.h"
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once #pragma once
#if MG_ARCH == MG_ARCH_NEWLIB #if MG_ARCH == MG_ARCH_ARMGCC
#define _POSIX_TIMERS #define _POSIX_TIMERS
#include <ctype.h> #include <ctype.h>
-27
View File
@@ -1,27 +0,0 @@
#pragma once
#if MG_ARCH == MG_ARCH_AZURERTOS
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#include <fx_api.h>
#include <tx_api.h>
#include <nx_api.h>
#include <nx_bsd.h>
#include <nx_port.h>
#include <tx_port.h>
#define PATH_MAX FX_MAXIMUM_PATH
#define MG_DIRSEP '\\'
#define socklen_t int
#define closesocket(x) soc_close(x)
#undef FOPEN_MAX
#endif
+85
View File
@@ -0,0 +1,85 @@
#pragma once
#if MG_ARCH == MG_ARCH_CUBE
#include <ctype.h>
#include <errno.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
// Cube-generated header, includes ST Cube HAL
// NOTE: use angle brackets to prevent amalgamator ditching it
#include <main.h>
#ifndef MG_PATH_MAX
#define MG_PATH_MAX 100
#endif
#ifndef MG_ENABLE_DIRLIST
#define MG_ENABLE_DIRLIST 0
#endif
#ifndef MG_ENABLE_SOCKET
#define MG_ENABLE_SOCKET 0
#endif
#ifndef MG_ENABLE_TCPIP
#define MG_ENABLE_TCPIP 1 // Enable built-in TCP/IP stack
#endif
#if MG_ENABLE_TCPIP && !defined(MG_ENABLE_DRIVER_STM32F) && !defined(MG_ENABLE_DRIVER_STM32H)
#if defined(STM32F1) || defined(STM32F2) || defined(STM32F4) || defined(STM32F7)
#define MG_ENABLE_DRIVER_STM32F 1
#elif defined(STM32H5) || defined(STM32H7)
#define MG_ENABLE_DRIVER_STM32H 1
#else
#error Select a driver in mongoose_config.h
#endif
#endif
#ifndef MG_TLS
#define MG_TLS MG_TLS_BUILTIN
#endif
#if !defined(MG_OTA) && defined(STM32F1) || defined(STM32F2) || defined(STM32F4) || defined(STM32F7)
#define MG_OTA MG_OTA_STM32F
#elif !defined(MG_OTA) && defined(STM32H5)
#define MG_OTA MG_OTA_STM32H5
#elif !defined(MG_OTA) && defined(STM32H7)
#define MG_OTA MG_OTA_STM32H7
#endif
// use HAL-defined execute-in-ram section
#define MG_IRAM __attribute__((section(".RamFunc")))
#ifndef HAL_ICACHE_MODULE_ENABLED
#define HAL_ICACHE_IsEnabled() 0
#define HAL_ICACHE_Enable() (void) 0
#define HAL_ICACHE_Disable() (void) 0
#endif
#ifndef MG_SET_MAC_ADDRESS
// Construct MAC address from UUID
#define MGUID ((uint32_t *) UID_BASE) // Unique 96-bit chip ID
#define MG_SET_MAC_ADDRESS(mac) \
do { \
int icache_enabled_ = HAL_ICACHE_IsEnabled(); \
if (icache_enabled_) HAL_ICACHE_Disable(); \
mac[0] = 42; \
mac[1] = ((MGUID[0] >> 0) & 255) ^ ((MGUID[2] >> 19) & 255); \
mac[2] = ((MGUID[0] >> 10) & 255) ^ ((MGUID[1] >> 10) & 255); \
mac[3] = (MGUID[0] >> 19) & 255; \
mac[4] = ((MGUID[1] >> 0) & 255) ^ ((MGUID[2] >> 10) & 255); \
mac[5] = ((MGUID[2] >> 0) & 255) ^ ((MGUID[1] >> 19) & 255); \
if (icache_enabled_) HAL_ICACHE_Enable(); \
} while (0)
#endif
#endif
+8
View File
@@ -22,4 +22,12 @@
#define MG_PATH_MAX 128 #define MG_PATH_MAX 128
#ifndef MG_ENABLE_POSIX_FS
#define MG_ENABLE_POSIX_FS 1
#endif
#ifndef MG_ENABLE_DIRLIST
#define MG_ENABLE_DIRLIST 1
#endif
#endif #endif
+8 -4
View File
@@ -25,10 +25,11 @@
#include <FreeRTOS.h> #include <FreeRTOS.h>
#include <task.h> #include <task.h>
#define calloc(a, b) mg_calloc(a, b) #define MG_ENABLE_CUSTOM_CALLOC 1
#define free(a) vPortFree(a)
#define malloc(a) pvPortMalloc(a) static inline void mg_free(void *ptr) {
#define strdup(s) ((char *) mg_strdup(mg_str(s)).buf) vPortFree(ptr);
}
// Re-route calloc/free to the FreeRTOS's functions, don't use stdlib // Re-route calloc/free to the FreeRTOS's functions, don't use stdlib
static inline void *mg_calloc(size_t cnt, size_t size) { static inline void *mg_calloc(size_t cnt, size_t size) {
@@ -37,10 +38,13 @@ static inline void *mg_calloc(size_t cnt, size_t size) {
return p; return p;
} }
#if !defined(MG_ENABLE_POSIX_FS) || !MG_ENABLE_POSIX_FS
#else
#define mkdir(a, b) mg_mkdir(a, b) #define mkdir(a, b) mg_mkdir(a, b)
static inline int mg_mkdir(const char *path, mode_t mode) { static inline int mg_mkdir(const char *path, mode_t mode) {
(void) path, (void) mode; (void) path, (void) mode;
return -1; return -1;
} }
#endif
#endif // MG_ARCH == MG_ARCH_FREERTOS #endif // MG_ARCH == MG_ARCH_FREERTOS
+43
View File
@@ -0,0 +1,43 @@
#pragma once
#if MG_ARCH == MG_ARCH_THREADX
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
// Do not include time.h and stdlib.h, since they conflict with nxd_bsd.h
// extern time_t time(time_t *);
#include <nxd_bsd.h>
#define MG_DIRSEP '\\'
#undef FOPEN_MAX
#ifndef MG_PATH_MAX
#define MG_PATH_MAX 32
#endif
#ifndef MG_SOCK_LISTEN_BACKLOG_SIZE
#define MG_SOCK_LISTEN_BACKLOG_SIZE 3
#endif
#ifndef MG_ENABLE_IPV6
#define MG_ENABLE_IPV6 0
#endif
#define socklen_t int
#define closesocket(x) soc_close(x)
// In order to enable BSD support in NetxDuo, do the following (assuming Cube):
// 1. Add nxd_bsd.h and nxd_bsd.c to the repo:
// https://github.com/eclipse-threadx/netxduo/blob/v6.1.12_rel/addons/BSD/nxd_bsd.c
// https://github.com/eclipse-threadx/netxduo/blob/v6.1.12_rel/addons/BSD/nxd_bsd.h
// 2. Add to tx_user.h
// #define TX_THREAD_USER_EXTENSION int bsd_errno;
// 3. Add to nx_user.h
// #define NX_ENABLE_EXTENDED_NOTIFY_SUPPORT
// 4. Add __CCRX__ build preprocessor constant
// Project -> Properties -> C/C++ -> Settings -> MCU Compiler -> Preprocessor
#endif
+13 -4
View File
@@ -18,6 +18,17 @@
#define _CRT_RAND_S #define _CRT_RAND_S
#endif #endif
#ifndef _WIN32_WINNT
#if defined(_MSC_VER) && _MSC_VER < 1700
#define _WIN32_WINNT 0x0400 // Let vc98 pick up wincrypt.h
#else
#define _WIN32_WINNT 0x0600
#endif
#endif
#ifndef WINVER
#define WINVER _WIN32_WINNT
#endif
#ifndef WIN32_LEAN_AND_MEAN #ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#endif #endif
@@ -45,6 +56,8 @@
#include <sys/types.h> #include <sys/types.h>
#include <time.h> #include <time.h>
#include <winsock2.h> // fix missing macros and types
#if defined(_MSC_VER) && _MSC_VER < 1700 #if defined(_MSC_VER) && _MSC_VER < 1700
#define __func__ "" #define __func__ ""
typedef __int64 int64_t; typedef __int64 int64_t;
@@ -66,13 +79,9 @@ typedef enum { false = 0, true = 1 } bool;
#include <process.h> #include <process.h>
#include <winerror.h> #include <winerror.h>
#include <winsock2.h> // fix missing macros and types
// For mg_random() // For mg_random()
#if defined(_MSC_VER) && _MSC_VER < 1700 #if defined(_MSC_VER) && _MSC_VER < 1700
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x400 // Let vc98 pick up wincrypt.h
#endif
#include <wincrypt.h> #include <wincrypt.h>
#pragma comment(lib, "advapi32.lib") #pragma comment(lib, "advapi32.lib")
#endif #endif
+1
View File
@@ -3,6 +3,7 @@
#if MG_ARCH == MG_ARCH_ZEPHYR #if MG_ARCH == MG_ARCH_ZEPHYR
#include <zephyr/kernel.h> #include <zephyr/kernel.h>
#include <zephyr/version.h>
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
+8
View File
@@ -4,6 +4,10 @@
#define MG_ENABLE_LOG 1 #define MG_ENABLE_LOG 1
#endif #endif
#ifndef MG_ENABLE_CUSTOM_CALLOC
#define MG_ENABLE_CUSTOM_CALLOC 0
#endif
#ifndef MG_ENABLE_CUSTOM_LOG #ifndef MG_ENABLE_CUSTOM_LOG
#define MG_ENABLE_CUSTOM_LOG 0 // Let user define their own MG_LOG #define MG_ENABLE_CUSTOM_LOG 0 // Let user define their own MG_LOG
#endif #endif
@@ -182,3 +186,7 @@
#ifndef MG_ENABLE_TCPIP_PRINT_DEBUG_STATS #ifndef MG_ENABLE_TCPIP_PRINT_DEBUG_STATS
#define MG_ENABLE_TCPIP_PRINT_DEBUG_STATS 0 #define MG_ENABLE_TCPIP_PRINT_DEBUG_STATS 0
#endif #endif
#ifndef MG_ENABLE_CHACHA20
#define MG_ENABLE_CHACHA20 1 // When set to 0, GCM is used. For MG_TLS_BUILTIN
#endif
+18 -12
View File
@@ -18,7 +18,7 @@ static void mg_sendnsreq(struct mg_connection *, struct mg_str *, int,
static void mg_dns_free(struct dns_data **head, struct dns_data *d) { static void mg_dns_free(struct dns_data **head, struct dns_data *d) {
LIST_DELETE(struct dns_data, head, d); LIST_DELETE(struct dns_data, head, d);
free(d); mg_free(d);
} }
void mg_resolve_cancel(struct mg_connection *c) { void mg_resolve_cancel(struct mg_connection *c) {
@@ -232,21 +232,26 @@ static bool mg_dns_send(struct mg_connection *c, const struct mg_str *name,
return mg_send(c, &pkt, sizeof(pkt.header) + n); return mg_send(c, &pkt, sizeof(pkt.header) + n);
} }
bool mg_dnsc_init(struct mg_mgr *mgr, struct mg_dns *dnsc);
bool mg_dnsc_init(struct mg_mgr *mgr, struct mg_dns *dnsc) {
if (dnsc->url == NULL) {
mg_error(0, "DNS server URL is NULL. Call mg_mgr_init()");
return false;
}
if (dnsc->c == NULL) {
dnsc->c = mg_connect(mgr, dnsc->url, NULL, NULL);
if (dnsc->c == NULL) return false;
dnsc->c->pfn = dns_cb;
}
return true;
}
static void mg_sendnsreq(struct mg_connection *c, struct mg_str *name, int ms, static void mg_sendnsreq(struct mg_connection *c, struct mg_str *name, int ms,
struct mg_dns *dnsc, bool ipv6) { struct mg_dns *dnsc, bool ipv6) {
struct dns_data *d = NULL; struct dns_data *d = NULL;
if (dnsc->url == NULL) { if (!mg_dnsc_init(c->mgr, dnsc)) {
mg_error(c, "DNS server URL is NULL. Call mg_mgr_init()");
} else if (dnsc->c == NULL) {
dnsc->c = mg_connect(c->mgr, dnsc->url, NULL, NULL);
if (dnsc->c != NULL) {
dnsc->c->pfn = dns_cb;
// dnsc->c->is_hexdumping = 1;
}
}
if (dnsc->c == NULL) {
mg_error(c, "resolver"); mg_error(c, "resolver");
} else if ((d = (struct dns_data *) calloc(1, sizeof(*d))) == NULL) { } else if ((d = (struct dns_data *) mg_calloc(1, sizeof(*d))) == NULL) {
mg_error(c, "resolve OOM"); mg_error(c, "resolve OOM");
} else { } else {
struct dns_data *reqs = (struct dns_data *) c->mgr->active_dns_requests; struct dns_data *reqs = (struct dns_data *) c->mgr->active_dns_requests;
@@ -345,3 +350,4 @@ struct mg_connection *mg_mdns_listen(struct mg_mgr *mgr, char *name) {
if (c != NULL) mg_multicast_add(c, (char *)"224.0.0.251"); if (c != NULL) mg_multicast_add(c, (char *)"224.0.0.251");
return c; return c;
} }
+330 -135
View File
@@ -1,8 +1,16 @@
#include "cyw.h" #include "cyw.h"
#include "net.h" #include "net.h"
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_CYW) && MG_ENABLE_DRIVER_CYW #if MG_ENABLE_TCPIP && \
((defined(MG_ENABLE_DRIVER_CYW) && MG_ENABLE_DRIVER_CYW) || \
(defined(MG_ENABLE_DRIVER_CYW_SDIO) && MG_ENABLE_DRIVER_CYW_SDIO))
#ifndef MG_ENABLE_DRIVER_CYW
#define MG_ENABLE_DRIVER_CYW 0
#endif
#ifndef MG_ENABLE_DRIVER_CYW_SDIO
#define MG_ENABLE_DRIVER_CYW_SDIO 0
#endif
static struct mg_tcpip_if *s_ifp; static struct mg_tcpip_if *s_ifp;
static bool s_link, s_auth, s_join; static bool s_link, s_auth, s_join;
@@ -68,10 +76,12 @@ struct mg_tcpip_driver mg_tcpip_driver_cyw = {mg_tcpip_driver_cyw_init,
// SPI | SDIO <-- padded to 32-bit | 64-bytes // SPI | SDIO <-- padded to 32-bit | 64-bytes
// //
// - SDPCM has 3 channels (control, data, and asynchronous data) // - SDPCM has 3 channels (control, data, and asynchronous data)
// - SPI (and SDIO) has 4 "functions", F0 to F3, to access different // - SPI has 4 "functions", F0 to F3, to access different blocks in the chip,
// blocks in the chip, like the SPI/SDIO controller, chip backplane, and 2 DMA // like the SPI/SDIO controller, chip backplane, and 2 DMA I/Os; these are
// I/Os; these are usually handled by SDPCM but we need to explicitly access // usually handled by SDPCM but we need to explicitly access the I/O controller
// the I/O controller and chip backplane during initialization // and chip backplane during initialization
// - SDIO has 3 functions (proper SDIO terminology), F0 to F2, coincident with
// those for SPI, accessed through standard SDIO practices. There is no F3.
// Processor core firmware is loaded to TCM RAM, along with module-dependent // Processor core firmware is loaded to TCM RAM, along with module-dependent
// (hardware design) NVRAM data, via the chip backplane access through the bus // (hardware design) NVRAM data, via the chip backplane access through the bus
@@ -121,10 +131,15 @@ struct data_hdr {
struct bdc_hdr bdc; struct bdc_hdr bdc;
}; };
// gSPI, DS 4.2.1 Fig.12, 2-bit field // gSPI, CYW43439 DS 4.2.1 Fig.12, 2-bit field
#define CYW_SD_FUNC_BUS 0 // F0 #define CYW_SPID_FUNC_BUS 0 // F0
#define CYW_SD_FUNC_CHIP 1 // F1 #define CYW_SPID_FUNC_CHIP 1 // F1
#define CYW_SD_FUNC_WLAN 2 // F2 #define CYW_SPID_FUNC_WLAN 2 // F2
// SDIO functions, 3-bit field; CYW4343W and CYW43439 DS 4.1
#define CYW_SDIO_FUNC_BUS 0 // F0
#define CYW_SDIO_FUNC_CHIP 1 // F1
#define CYW_SDIO_FUNC_WLAN 2 // F2
#define CYW_SDPCM_CTRL_HDR 0 #define CYW_SDPCM_CTRL_HDR 0
#define CYW_SDPCM_ASYNC_HDR 1 #define CYW_SDPCM_ASYNC_HDR 1
@@ -139,7 +154,7 @@ static void cyw_handle_cdc(struct cdc_hdr *cdc, size_t len);
static void cyw_handle_bdc(struct bdc_hdr *bdc, size_t len); static void cyw_handle_bdc(struct bdc_hdr *bdc, size_t len);
static void cyw_handle_bdc_evnt(struct bdc_hdr *bdc, size_t len); static void cyw_handle_bdc_evnt(struct bdc_hdr *bdc, size_t len);
static size_t cyw_spi_poll(uint8_t *dest); static size_t cyw_bus_specific_poll(uint32_t *dest);
static void cyw_update_hash_table(void); static void cyw_update_hash_table(void);
// High-level comm stuff // High-level comm stuff
@@ -152,7 +167,7 @@ static void cyw_poll(void) {
cyw_update_hash_table(); cyw_update_hash_table();
s_ifp->update_mac_hash_table = false; s_ifp->update_mac_hash_table = false;
} }
if (cyw_spi_poll((uint8_t *) resp) == 0) return; // BUS DEPENDENCY if (cyw_bus_specific_poll(resp) == 0) return;
if ((sdpcm->len ^ sdpcm->_len) != 0xffff || sdpcm->len < sizeof(*sdpcm) || if ((sdpcm->len ^ sdpcm->_len) != 0xffff || sdpcm->len < sizeof(*sdpcm) ||
sdpcm->len > 2048 - sizeof(*sdpcm)) sdpcm->len > 2048 - sizeof(*sdpcm))
return; return;
@@ -185,7 +200,7 @@ static void cyw_handle_bdc(struct bdc_hdr *bdc, size_t len) {
mg_tcpip_qwrite(payload, len - (payload - (uint8_t *) bdc), s_ifp); mg_tcpip_qwrite(payload, len - (payload - (uint8_t *) bdc), s_ifp);
} }
static size_t cyw_bus_tx(uint32_t *data, uint16_t len); static size_t cyw_bus_specific_tx(uint32_t *data, uint16_t len);
// WLAN frame transmission // WLAN frame transmission
static size_t mg_cyw_tx(unsigned int ifc, void *data, size_t len) { static size_t mg_cyw_tx(unsigned int ifc, void *data, size_t len) {
@@ -194,15 +209,15 @@ static size_t mg_cyw_tx(unsigned int ifc, void *data, size_t len) {
memset(txdata, 0, sizeof(*hdr)); memset(txdata, 0, sizeof(*hdr));
memcpy((uint8_t *) txdata + sizeof(*hdr), data, len); memcpy((uint8_t *) txdata + sizeof(*hdr), data, len);
// TODO(): hdr->bdc.priority = map IP to TOS if supporting QoS/ToS // TODO(): hdr->bdc.priority = map IP to TOS if supporting QoS/ToS
hdr->bdc.flags = 2 << 4; // BDC version 2 hdr->bdc.flags = 2 << 4; // BDC version 2
hdr->bdc.flags2 = ifc; // 0 -> STA, 1 -> AP hdr->bdc.flags2 = (uint8_t) ifc; // 0 -> STA, 1 -> AP
// hdr->bdc.data_offset = 0; // actually zeroed above // hdr->bdc.data_offset = 0; // actually zeroed above
hdr->sdpcm.len = txlen; hdr->sdpcm.len = txlen;
hdr->sdpcm._len = (uint16_t) ~txlen; hdr->sdpcm._len = (uint16_t) ~txlen;
hdr->sdpcm.sw_hdr.sequence = ++s_tx_seqno; hdr->sdpcm.sw_hdr.sequence = ++s_tx_seqno;
hdr->sdpcm.sw_hdr.channel_and_flags = CYW_SDPCM_DATA_HDR, hdr->sdpcm.sw_hdr.channel_and_flags = CYW_SDPCM_DATA_HDR,
hdr->sdpcm.sw_hdr.header_length = offsetof(struct data_hdr, bdc); hdr->sdpcm.sw_hdr.header_length = offsetof(struct data_hdr, bdc);
return cyw_bus_tx(txdata, txlen); return cyw_bus_specific_tx(txdata, txlen);
} }
// WLAN event handling // WLAN event handling
@@ -250,6 +265,7 @@ struct scan_result;
static void cyw_handle_scan_result(uint32_t status, struct scan_result *data, static void cyw_handle_scan_result(uint32_t status, struct scan_result *data,
size_t len); size_t len);
// Do not call any IOCTL functions here, otherwise revise cyw_ioctl_wait()
static void cyw_handle_bdc_evnt(struct bdc_hdr *bdc, size_t len) { static void cyw_handle_bdc_evnt(struct bdc_hdr *bdc, size_t len) {
struct evnt_msg *msg = (struct evnt_msg *) &bdc[bdc->data_offset + 1]; struct evnt_msg *msg = (struct evnt_msg *) &bdc[bdc->data_offset + 1];
MG_VERBOSE(("%u bytes event", len)); MG_VERBOSE(("%u bytes event", len));
@@ -313,7 +329,7 @@ static bool cyw_ioctl_iovar_set_(unsigned int ifc, char *var, void *data,
size_t len); size_t len);
// clang-format off // clang-format off
// convenience: ioctl funcs on default ifc (0), as only AP needs ifc 1 // convenience: ioctl funcs on default ifc (0), as only AP needs ifc 1
static bool cyw_ioctl_get(unsigned int cmd, void *data, size_t len) { return cyw_ioctl_get_(0, cmd, data, len); } __attribute__((unused)) static bool cyw_ioctl_get(unsigned int cmd, void *data, size_t len) { return cyw_ioctl_get_(0, cmd, data, len); }
static bool cyw_ioctl_set(unsigned int cmd, void *data, size_t len) { return cyw_ioctl_set_(0, cmd, data, len); } static bool cyw_ioctl_set(unsigned int cmd, void *data, size_t len) { return cyw_ioctl_set_(0, cmd, data, len); }
static bool cyw_ioctl_iovar_get(char *var, void *data, size_t len) { return cyw_ioctl_iovar_get_(0, var, data, len); } static bool cyw_ioctl_iovar_get(char *var, void *data, size_t len) { return cyw_ioctl_iovar_get_(0, var, data, len); }
static bool cyw_ioctl_iovar_set(char *var, void *data, size_t len) { return cyw_ioctl_iovar_set_(0, var, data, len); } static bool cyw_ioctl_iovar_set(char *var, void *data, size_t len) { return cyw_ioctl_iovar_set_(0, var, data, len); }
@@ -324,9 +340,10 @@ static bool cyw_ioctl_iovar_set(char *var, void *data, size_t len) { return cyw_
// clang-format off // clang-format off
static bool cyw_wifi_connect(char *ssid, char *pass) { static bool cyw_wifi_connect(char *ssid, char *pass) {
uint32_t sup_wpa[2] = {0, 1}; // bss index 0 = STA, not open uint32_t sup_wpa[2] = {0, 1}; // bss index 0 = STA, not open
static const uint32_t const eapver[2] = {0, (uint32_t) -1}, // accept AP version static const uint32_t eapver[2] = {0, (uint32_t) -1}, // accept AP version
tmo[2] = {0, 2500}; tmo[2] = {0, 2500};
uint32_t data[64/4 + 1]; // max pass length: 64 for WPA, 128 for WPA3 SAE uint32_t data[64/4 + 1]; // max pass length: 64 for WPA, 128 for WPA3 SAE
uint16_t *da = (uint16_t *) data;
unsigned int len; unsigned int len;
uint32_t val; uint32_t val;
val = 4; // security type: 0 for none, 2 for WPA, 4 for WPA2/WPA3, 6 for mixed WPA/WPA2 val = 4; // security type: 0 for none, 2 for WPA, 4 for WPA2/WPA3, 6 for mixed WPA/WPA2
@@ -340,8 +357,8 @@ static bool cyw_wifi_connect(char *ssid, char *pass) {
// skip if not using auth // skip if not using auth
memset(data, 0, sizeof(data)); memset(data, 0, sizeof(data));
len = strlen(pass); len = strlen(pass);
((uint16_t *)data)[0] = (uint16_t) len; da[0] = (uint16_t) len;
((uint16_t *)data)[1] = 1; // indicates wireless security key, skip for WPA3 SAE da[1] = 1; // indicates wireless security key, skip for WPA3 SAE
memcpy((uint8_t *)data + 2 * sizeof(uint16_t), pass, len); // skip for WPA3 SAE memcpy((uint8_t *)data + 2 * sizeof(uint16_t), pass, len); // skip for WPA3 SAE
if (!cyw_ioctl_set(268 /* SET_WSEC_PMK */, data, sizeof(data))) return false; // skip for WPA3 SAE, sizeof/2 if supporting SAE but using WPA if (!cyw_ioctl_set(268 /* SET_WSEC_PMK */, data, sizeof(data))) return false; // skip for WPA3 SAE, sizeof/2 if supporting SAE but using WPA
// for WPA3 SAE: memcpy((uint8_t *)data + sizeof(uint16_t), pass, len); cyw_ioctl_iovar_set("sae_password", data, sizeof(data)); // for WPA3 SAE: memcpy((uint8_t *)data + sizeof(uint16_t), pass, len); cyw_ioctl_iovar_set("sae_password", data, sizeof(data));
@@ -368,6 +385,7 @@ static bool cyw_wifi_disconnect(void) {
static bool cyw_wifi_ap_start(char *ssid, char *pass, unsigned int channel) { static bool cyw_wifi_ap_start(char *ssid, char *pass, unsigned int channel) {
uint32_t data[64/4 + 2]; // max pass length: 64 for WPA, 128 for WPA3 SAE uint32_t data[64/4 + 2]; // max pass length: 64 for WPA, 128 for WPA3 SAE
uint16_t *da = (uint16_t *) data;
unsigned int len; unsigned int len;
uint32_t val; uint32_t val;
// CHIP DEPENDENCY // CHIP DEPENDENCY
@@ -394,8 +412,8 @@ static bool cyw_wifi_ap_start(char *ssid, char *pass, unsigned int channel) {
// NOTE(): WHD does not set SAE password for shared WPA2/WPA3, same do we // NOTE(): WHD does not set SAE password for shared WPA2/WPA3, same do we
memset(data, 0, sizeof(data)); memset(data, 0, sizeof(data));
len = strlen(pass); len = strlen(pass);
((uint16_t *)data)[0] = (uint16_t) len; // skip for WPA3 SAE da[0] = (uint16_t) len; // skip for WPA3 SAE (43430 does NOT support WPA3 in AP)
((uint16_t *)data)[1] = 1; // indicates wireless security key, skip for WPA3 SAE da[1] = 1; // indicates wireless security key, skip for WPA3 SAE
memcpy((uint8_t *)data + 2 * sizeof(uint16_t), pass, len); // skip for WPA3 SAE memcpy((uint8_t *)data + 2 * sizeof(uint16_t), pass, len); // skip for WPA3 SAE
if (!cyw_ioctl_set_(1, 268 /* SET_WSEC_PMK */, data, sizeof(data))) return false; // skip for WPA3 SAE, sizeof/2 if supporting SAE but using WPA if (!cyw_ioctl_set_(1, 268 /* SET_WSEC_PMK */, data, sizeof(data))) return false; // skip for WPA3 SAE, sizeof/2 if supporting SAE but using WPA
/* for WPA3 SAE: /* for WPA3 SAE:
@@ -539,8 +557,8 @@ static void cyw_handle_scan_result(uint32_t status, struct scan_result *data, si
if (sbss->length > len - offsetof(struct scan_result, bss) || sbss->SSID_len > sizeof(sbss->SSID) || sbss->ie_offset < sizeof(*sbss) || sbss->ie_offset > (sizeof(*sbss) + sbss->ie_length) || sbss->ie_offset + sbss->ie_length > sbss->length) if (sbss->length > len - offsetof(struct scan_result, bss) || sbss->SSID_len > sizeof(sbss->SSID) || sbss->ie_offset < sizeof(*sbss) || sbss->ie_offset > (sizeof(*sbss) + sbss->ie_length) || sbss->ie_offset + sbss->ie_length > sbss->length)
return; // silently discard malformed data return; // silently discard malformed data
if (!(sbss->flags & MG_BIT(2))) return; // RSSI_ONCHANNEL, ignore off-channel results if (!(sbss->flags & MG_BIT(2))) return; // RSSI_ONCHANNEL, ignore off-channel results
bss.SSID = mg_str_n(sbss->SSID, sbss->SSID_len); bss.SSID = mg_str_n((char *)sbss->SSID, sbss->SSID_len);
bss.BSSID = sbss->BSSID; bss.BSSID = (char *)sbss->BSSID;
bss.RSSI = (int8_t)sbss->RSSI; bss.RSSI = (int8_t)sbss->RSSI;
bss.has_n = sbss->n_cap != 0; bss.has_n = sbss->n_cap != 0;
bss.channel = bss.has_n ? sbss->ctl_ch : (uint8_t)(sbss->chanspec & 0xff); // n 40MHz vs a/b/g and 20MHz bss.channel = bss.has_n ? sbss->ctl_ch : (uint8_t)(sbss->chanspec & 0xff); // n 40MHz vs a/b/g and 20MHz
@@ -575,7 +593,7 @@ static uint8_t *s_ioctl_resp;
static bool s_ioctl_err; static bool s_ioctl_err;
static void cyw_handle_cdc(struct cdc_hdr *cdc, size_t len) { static void cyw_handle_cdc(struct cdc_hdr *cdc, size_t len) {
uint8_t *resp = (uint8_t *) cdc + sizeof(*cdc); uint8_t *r = (uint8_t *) cdc + sizeof(*cdc);
MG_VERBOSE(("%u bytes CDC frame", len)); MG_VERBOSE(("%u bytes CDC frame", len));
if ((cdc->flags >> 16) != s_ioctl_reqid) return; if ((cdc->flags >> 16) != s_ioctl_reqid) return;
if (cdc->flags & 1) { if (cdc->flags & 1) {
@@ -584,9 +602,8 @@ static void cyw_handle_cdc(struct cdc_hdr *cdc, size_t len) {
return; return;
} }
if (mg_log_level >= MG_LL_VERBOSE) mg_hexdump((void *) cdc, len); if (mg_log_level >= MG_LL_VERBOSE) mg_hexdump((void *) cdc, len);
MG_DEBUG(("IOCTL result: %02x %02x %02x %02x ...", resp[0], resp[1], resp[2], MG_DEBUG(("IOCTL result: %02x %02x %02x %02x ...", r[0], r[1], r[2], r[3]));
resp[3])); s_ioctl_resp = r;
s_ioctl_resp = resp;
} }
// NOTE(): alt no loop handler dispatching IOCTL response to current handler: // NOTE(): alt no loop handler dispatching IOCTL response to current handler:
// static void *s_ioctl_hnd; *s_ioctl_hnd(ioctl, len); // static void *s_ioctl_hnd; *s_ioctl_hnd(ioctl, len);
@@ -618,7 +635,7 @@ static void cyw_ioctl_send_cmd(unsigned int ifc, unsigned int cmd, bool set,
hdr->sdpcm.sw_hdr.sequence = ++s_tx_seqno; hdr->sdpcm.sw_hdr.sequence = ++s_tx_seqno;
hdr->sdpcm.sw_hdr.channel_and_flags = CYW_SDPCM_CTRL_HDR; hdr->sdpcm.sw_hdr.channel_and_flags = CYW_SDPCM_CTRL_HDR;
hdr->sdpcm.sw_hdr.header_length = offsetof(struct ctrl_hdr, cdc); hdr->sdpcm.sw_hdr.header_length = offsetof(struct ctrl_hdr, cdc);
cyw_bus_tx(txdata, txlen); cyw_bus_specific_tx(txdata, txlen);
} }
// just send respective commands, response handled via CDC handler // just send respective commands, response handled via CDC handler
@@ -652,20 +669,29 @@ static void cyw_ioctl_send_iovar_set2(unsigned int ifc, char *var, void *data1,
cyw_ioctl_send_cmd(ifc, 263, true, txlen); // cmd = SET IOVAR cyw_ioctl_send_cmd(ifc, 263, true, txlen); // cmd = SET IOVAR
} }
static void cyw_ioctl_send_iovar_set(unsigned int ifc, char *var, void *data, __attribute__((unused)) static void cyw_ioctl_send_iovar_set(unsigned int ifc,
size_t len) { char *var,
void *data,
size_t len) {
cyw_ioctl_send_iovar_set2(ifc, var, data, len, NULL, 0); cyw_ioctl_send_iovar_set2(ifc, var, data, len, NULL, 0);
} }
static inline bool delayms(unsigned int ms) {
mg_delayms(ms);
return true;
}
// wait for a response, meanwhile delivering received frames and events // wait for a response, meanwhile delivering received frames and events
static bool cyw_ioctl_wait(void) { static bool cyw_ioctl_wait(void) {
unsigned int times = 6000; unsigned int times = 100;
s_ioctl_resp = NULL; s_ioctl_resp = NULL;
s_ioctl_err = false; s_ioctl_err = false;
while (s_ioctl_resp == NULL && !s_ioctl_err && times-- > 0) do { // IOCTL response processing does not call any other IOCTL function
cyw_poll(); // TODO(scaprile): review wait/sleep strategy (this loop is executed only when initializing/acting on the chip) cyw_poll(); // otherwise we can't allow them to pile up here
MG_DEBUG(("resp: %lp, err: %c, times: %d", s_ioctl_resp, // network frames will be pushed to the queue so that is safe
s_ioctl_err ? '1' : '0', (int) times)); } while (s_ioctl_resp == NULL && !s_ioctl_err && times-- > 0 && delayms(1));
MG_VERBOSE(("resp: %lp, err: %c, times: %d", s_ioctl_resp,
s_ioctl_err ? '1' : '0', (int) times));
return s_ioctl_resp != NULL; return s_ioctl_resp != NULL;
} }
@@ -723,15 +749,22 @@ struct clm_hdr {
#pragma pack(pop) #pragma pack(pop)
// worlwide rev0, try rev 17 for 4343W // worlwide rev0, TODO(): try rev 17 for 4343W
static const uint32_t country_code = 'X' + ('X' << 8) + (0 << 16); static const uint32_t country_code = 'X' + ('X' << 8) + (0 << 16);
static bool cyw_spi_init(); static bool cyw_bus_specific_init();
static bool cyw_load_clmll(void *data, size_t len);
static bool cyw_load_clm(struct mg_tcpip_driver_cyw_firmware *fw) {
return cyw_load_clmll((void *) fw->clm_addr, fw->clm_len);
}
// clang-format off // clang-format off
static bool cyw_init(uint8_t *mac) { static bool cyw_init(uint8_t *mac) {
struct mg_tcpip_driver_cyw_data *d = (struct mg_tcpip_driver_cyw_data *) s_ifp->driver_data;
uint32_t val = 0; uint32_t val = 0;
if (!cyw_spi_init()) return false; // BUS DEPENDENCY if (!cyw_bus_specific_init()) return false;
if (!cyw_load_clm(d->fw)) return false; // Load CLM blob
// BT-ENABLED DEPENDENCY // BT-ENABLED DEPENDENCY
// set Wi-Fi up // set Wi-Fi up
val = 0 /* disable */; cyw_ioctl_iovar_set("bus:txglom", (uint8_t *)&val, sizeof(val)); val = 0 /* disable */; cyw_ioctl_iovar_set("bus:txglom", (uint8_t *)&val, sizeof(val));
@@ -759,7 +792,7 @@ static bool cyw_init(uint8_t *mac) {
unsigned int times = 100; unsigned int times = 100;
while (times --) while (times --)
if (cyw_ioctl_iovar_set("bsscfg:event_msgs", (uint8_t *)data, sizeof(data))) break; if (cyw_ioctl_iovar_set("bsscfg:event_msgs", (uint8_t *)data, sizeof(data))) break;
if (times == ~0) return false; if (times == (unsigned int) ~0) return false;
} }
val = 0; if (!cyw_ioctl_set(64 /* SET_ANTDIV */, (uint8_t *)&val, sizeof(val))) return false; val = 0; if (!cyw_ioctl_set(64 /* SET_ANTDIV */, (uint8_t *)&val, sizeof(val))) return false;
if (!cyw_ioctl_set(2 /* UP, interface up */, NULL, 0)) return false; if (!cyw_ioctl_set(2 /* UP, interface up */, NULL, 0)) return false;
@@ -818,20 +851,18 @@ static bool cyw_load_clmll(void *data, size_t len) {
break; break;
sent += bytes; sent += bytes;
offset += bytes; offset += bytes;
hdr.flag &= ~MG_BIT(1); // DL_BEGIN hdr.flag &= (uint16_t)~MG_BIT(1); // DL_BEGIN
} }
return sent >= len; return sent >= len;
} }
// clang-format on // clang-format on
static bool cyw_load_clm(struct mg_tcpip_driver_cyw_firmware *fw) {
return cyw_load_clmll((void *) fw->clm_addr, fw->clm_len);
}
static void cyw_update_hash_table(void) { static void cyw_update_hash_table(void) {
// TODO(): read database, rebuild hash table // TODO(): read database, rebuild hash table
uint32_t val = 0; uint32_t val = 0;
val = 1; cyw_ioctl_iovar_set2_(0, "mcast_list", (uint8_t *)&val, sizeof(val), (uint8_t *)mcast_addr, sizeof(mcast_addr)); val = 1;
cyw_ioctl_iovar_set2_(0, "mcast_list", (uint8_t *) &val, sizeof(val),
(uint8_t *) mcast_addr, sizeof(mcast_addr));
mg_delayms(50); mg_delayms(50);
} }
@@ -848,8 +879,16 @@ static void cyw_update_hash_table(void) {
#define CYW_CHIP_BCKPLN_ADDRMSK 0x7fff #define CYW_CHIP_BCKPLN_ADDRMSK 0x7fff
#define CYW_CHIP_BCKPLN_ACCSS4B MG_BIT(15) #define CYW_CHIP_BCKPLN_ACCSS4B MG_BIT(15)
#define CYW_CHIP_BCKPLN_WRAPPOFF 0x100000 #define CYW_CHIP_BCKPLN_WRAPPOFF 0x100000
// BUS DEPENDENCY: max bus to backplane transfer size, bus function id
#define CYW_CHIP_BCKPLN_SPIMAX 64 #define CYW_CHIP_BCKPLN_SPIMAX 64
#define CYW_CHIP_BCKPLN_SDIOMAX 1536 #define CYW_CHIP_BCKPLN_SDIOMAX 1536
#if MG_ENABLE_DRIVER_CYW_SDIO
#define CYW_CHIP_BCKPLN_BUSMAX CYW_CHIP_BCKPLN_SDIOMAX
#define CYW_BUS_FUNC_CHIP CYW_SDIO_FUNC_CHIP
#else
#define CYW_CHIP_BCKPLN_BUSMAX CYW_CHIP_BCKPLN_SPIMAX
#define CYW_BUS_FUNC_CHIP CYW_SPID_FUNC_CHIP
#endif
// CHIP DEPENDENCY // CHIP DEPENDENCY
#define CYW_CHIP_ARMCORE_BASE (CYW_CHIP_CHIPCOMMON + 0x3000) #define CYW_CHIP_ARMCORE_BASE (CYW_CHIP_CHIPCOMMON + 0x3000)
@@ -874,9 +913,9 @@ static void cyw_update_hash_table(void) {
#define CYW_CHIP_AI_IOCTRL 0x408 #define CYW_CHIP_AI_IOCTRL 0x408
#define CYW_CHIP_AI_RESETCTRL 0x800 #define CYW_CHIP_AI_RESETCTRL 0x800
static bool cyw_spi_write(unsigned int f, uint32_t addr, void *data, static bool cyw_bus_write(unsigned int f, uint32_t addr, void *data,
uint16_t len); uint16_t len);
static void cyw_spi_read(unsigned int f, uint32_t addr, void *data, static bool cyw_bus_read(unsigned int f, uint32_t addr, void *data,
uint16_t len); uint16_t len);
// clang-format off // clang-format off
@@ -884,9 +923,9 @@ static void cyw_spi_read(unsigned int f, uint32_t addr, void *data,
static void cyw_set_backplane_window(uint32_t addr) { static void cyw_set_backplane_window(uint32_t addr) {
uint32_t val; uint32_t val;
addr &= ~CYW_CHIP_BCKPLN_ADDRMSK; addr &= ~CYW_CHIP_BCKPLN_ADDRMSK;
val = (addr >> 24) & 0xff; cyw_spi_write(CYW_SD_FUNC_CHIP, CYW_CHIP_ADDRHIGH, &val, 1); val = (addr >> 24) & 0xff; cyw_bus_write(CYW_BUS_FUNC_CHIP, CYW_CHIP_ADDRHIGH, &val, 1);
val = (addr >> 16) & 0xff; cyw_spi_write(CYW_SD_FUNC_CHIP, CYW_CHIP_ADDRMID, &val, 1); val = (addr >> 16) & 0xff; cyw_bus_write(CYW_BUS_FUNC_CHIP, CYW_CHIP_ADDRMID, &val, 1);
val = (addr >> 8) & 0xff; cyw_spi_write(CYW_SD_FUNC_CHIP, CYW_CHIP_ADDRLOW, &val, 1); val = (addr >> 8) & 0xff; cyw_bus_write(CYW_BUS_FUNC_CHIP, CYW_CHIP_ADDRLOW, &val, 1);
} }
static bool cyw_core_reset(uint32_t core_base, bool check) { static bool cyw_core_reset(uint32_t core_base, bool check) {
@@ -894,21 +933,21 @@ static bool cyw_core_reset(uint32_t core_base, bool check) {
// core disabled after chip reset // core disabled after chip reset
cyw_set_backplane_window(core_base); // set backplane window for requested area; we do know offsets fall within that window cyw_set_backplane_window(core_base); // set backplane window for requested area; we do know offsets fall within that window
// possible CHIP DEPENDENCY: AI_RESETSTATUS check and wait (instead of these cool reads) to ensure backplane operations end // possible CHIP DEPENDENCY: AI_RESETSTATUS check and wait (instead of these cool reads) to ensure backplane operations end
cyw_spi_read(CYW_SD_FUNC_CHIP, (core_base + CYW_CHIP_AI_IOCTRL) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 1); // ensure backplane operations end cyw_bus_read(CYW_BUS_FUNC_CHIP, (core_base + CYW_CHIP_AI_IOCTRL) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 1); // ensure backplane operations end
val = MG_BIT(1) | MG_BIT(0) /* SICF_FGC | SICF_CLOCK_EN */; cyw_spi_write(CYW_SD_FUNC_CHIP, (core_base + CYW_CHIP_AI_IOCTRL) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 1); // reset val = MG_BIT(1) | MG_BIT(0) /* SICF_FGC | SICF_CLOCK_EN */; cyw_bus_write(CYW_BUS_FUNC_CHIP, (core_base + CYW_CHIP_AI_IOCTRL) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 1); // reset
cyw_spi_read(CYW_SD_FUNC_CHIP, (core_base + CYW_CHIP_AI_IOCTRL) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 1); // ensure backplane operations end cyw_bus_read(CYW_BUS_FUNC_CHIP, (core_base + CYW_CHIP_AI_IOCTRL) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 1); // ensure backplane operations end
val = 0x00; cyw_spi_write(CYW_SD_FUNC_CHIP, (core_base + CYW_CHIP_AI_RESETCTRL) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 1); // release reset val = 0x00; cyw_bus_write(CYW_BUS_FUNC_CHIP, (core_base + CYW_CHIP_AI_RESETCTRL) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 1); // release reset
mg_delayms(1); mg_delayms(1);
val = MG_BIT(0) /* SICF_CLOCK_EN */; cyw_spi_write(CYW_SD_FUNC_CHIP, (core_base + CYW_CHIP_AI_IOCTRL) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 1); val = MG_BIT(0) /* SICF_CLOCK_EN */; cyw_bus_write(CYW_BUS_FUNC_CHIP, (core_base + CYW_CHIP_AI_IOCTRL) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 1);
cyw_spi_read(CYW_SD_FUNC_CHIP, (core_base + CYW_CHIP_AI_IOCTRL) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 1); // ensure backplane operations end cyw_bus_read(CYW_BUS_FUNC_CHIP, (core_base + CYW_CHIP_AI_IOCTRL) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 1); // ensure backplane operations end
mg_delayms(1); mg_delayms(1);
if (check) { if (check) {
// Verify only clock is enabled // Verify only clock is enabled
cyw_spi_read(CYW_SD_FUNC_CHIP, (core_base + CYW_CHIP_AI_IOCTRL) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 1); cyw_bus_read(CYW_BUS_FUNC_CHIP, (core_base + CYW_CHIP_AI_IOCTRL) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 1);
if ((val & (MG_BIT(1) | MG_BIT(0)) /* SICF_FGC | SICF_CLOCK_EN) */) != MG_BIT(0)) return false; if ((val & (MG_BIT(1) | MG_BIT(0)) /* SICF_FGC | SICF_CLOCK_EN) */) != MG_BIT(0)) return false;
// Verify it is not in reset state // Verify it is not in reset state
cyw_spi_read(CYW_SD_FUNC_CHIP, (core_base + CYW_CHIP_AI_RESETCTRL) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 1); cyw_bus_read(CYW_BUS_FUNC_CHIP, (core_base + CYW_CHIP_AI_RESETCTRL) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 1);
if (val & MG_BIT(0)) return false; // AIRC_RESET if (val & MG_BIT(0)) return false; // AIRC_RESET
} }
return true; return true;
@@ -916,29 +955,28 @@ static bool cyw_core_reset(uint32_t core_base, bool check) {
static void cyw_socram_init(void) { static void cyw_socram_init(void) {
uint32_t val; uint32_t val;
// CHIP DEPENDENCY: disable remap for SRAM_3 // CHIP DEPENDENCY: disable remap for SRAM_3: 43430 and 43439 only
cyw_set_backplane_window(CYW_CHIP_SOCSRAM_BASE); // set backplane window for requested area; we do know offsets fall within that window cyw_set_backplane_window(CYW_CHIP_SOCSRAM_BASE); // set backplane window for requested area; we do know offsets fall within that window
val = 0x03; cyw_spi_write(CYW_SD_FUNC_CHIP, ((CYW_CHIP_SOCSRAM_BASE + CYW_CHIP_SOCSRAM_BANKXIDX) & CYW_CHIP_BCKPLN_ADDRMSK) | CYW_CHIP_BCKPLN_ACCSS4B, &val, sizeof(val)); val = 0x03; cyw_bus_write(CYW_BUS_FUNC_CHIP, ((CYW_CHIP_SOCSRAM_BASE + CYW_CHIP_SOCSRAM_BANKXIDX) & CYW_CHIP_BCKPLN_ADDRMSK), &val, sizeof(val));
val = 0x00; cyw_spi_write(CYW_SD_FUNC_CHIP, ((CYW_CHIP_SOCSRAM_BASE + CYW_CHIP_SOCSRAM_BANKXPDA) & CYW_CHIP_BCKPLN_ADDRMSK) | CYW_CHIP_BCKPLN_ACCSS4B, &val, sizeof(val)); val = 0x00; cyw_bus_write(CYW_BUS_FUNC_CHIP, ((CYW_CHIP_SOCSRAM_BASE + CYW_CHIP_SOCSRAM_BANKXPDA) & CYW_CHIP_BCKPLN_ADDRMSK), &val, sizeof(val));
} }
// transfer is fractioned in bus-to-backplane-size units within backplane windows // transfer is fractioned in bus-to-backplane-size units within backplane windows
static void cyw_load_data(uint32_t dest, void *data, size_t len) { static void cyw_load_data(uint32_t dest, void *data, size_t len) {
size_t sent = 0, offset = 0; size_t sent = 0, offset = 0;
uint32_t last_addr = ~0; uint32_t last_addr = (uint32_t) ~0;
while (sent < len) { while (sent < len) {
size_t bytes = len - sent, avail; size_t bytes = len - sent, avail;
uint32_t addr = dest + offset; uint32_t addr = dest + offset;
if (addr - last_addr >= CYW_CHIP_BCKPLN_WINSZ || last_addr == ~0) { if (addr - last_addr >= CYW_CHIP_BCKPLN_WINSZ || last_addr == (uint32_t) ~0) {
cyw_set_backplane_window(addr); // set backplane window for requested area cyw_set_backplane_window(addr); // set backplane window for requested area
last_addr = addr & ~CYW_CHIP_BCKPLN_ADDRMSK; last_addr = addr & ~CYW_CHIP_BCKPLN_ADDRMSK;
} }
addr &= CYW_CHIP_BCKPLN_ADDRMSK; addr &= CYW_CHIP_BCKPLN_ADDRMSK;
avail = CYW_CHIP_BCKPLN_WINSZ - (unsigned int) addr; avail = CYW_CHIP_BCKPLN_WINSZ - (unsigned int) addr; // internal backplane limit
if (bytes > avail) bytes = avail; if (bytes > avail) bytes = avail;
// BUS DEPENDENCY: max bus to backplane transfer size if (bytes > CYW_CHIP_BCKPLN_BUSMAX) bytes = CYW_CHIP_BCKPLN_BUSMAX; // bus to backplane transfer limit
if (bytes > CYW_CHIP_BCKPLN_SPIMAX) bytes = CYW_CHIP_BCKPLN_SPIMAX; cyw_bus_write(CYW_BUS_FUNC_CHIP, addr, (uint8_t *)data + offset, (uint16_t) bytes);
cyw_spi_write(CYW_SD_FUNC_CHIP, addr | CYW_CHIP_BCKPLN_ACCSS4B, (uint8_t *)data + offset, bytes);
sent += bytes; sent += bytes;
offset += bytes; offset += bytes;
} }
@@ -950,13 +988,13 @@ static bool cyw_load_fwll(void *fwdata, size_t fwlen, void *nvramdata, size_t nv
cyw_core_reset(CYW_CHIP_SOCSRAM, false); // cores were disabled at chip reset cyw_core_reset(CYW_CHIP_SOCSRAM, false); // cores were disabled at chip reset
cyw_socram_init(); cyw_socram_init();
cyw_load_data(CYW_CHIP_ATCMRAM_BASE, fwdata, fwlen); cyw_load_data(CYW_CHIP_ATCMRAM_BASE, fwdata, fwlen);
mg_delayms(5); // ************ CHECK IF THIS IS ACTUALLY NEEDED mg_delayms(5); // TODO(scaprile): CHECK IF THIS IS ACTUALLY NEEDED
// Load NVRAM and place 'length ~length' at the end; end of chip RAM // Load NVRAM and place 'length ~length' at the end; end of chip RAM
{ {
const uint32_t start = CYW_CHIP_RAM_SIZE - 4 - nvramlen; const uint32_t start = CYW_CHIP_RAM_SIZE - 4 - nvramlen;
cyw_load_data(start, nvramdata, nvramlen); // nvramlen must be a multiple of 4 cyw_load_data(start, nvramdata, nvramlen); // nvramlen must be a multiple of 4
// RAM_SIZE is a multiple of WINSZ, so the place for len ~len will be at the end of the window // RAM_SIZE is a multiple of WINSZ, so the place for len ~len will be at the end of the window
cyw_spi_write(CYW_SD_FUNC_CHIP, (CYW_CHIP_BCKPLN_WINSZ - 4) | CYW_CHIP_BCKPLN_ACCSS4B, &val, sizeof(val)); cyw_bus_write(CYW_BUS_FUNC_CHIP, (CYW_CHIP_BCKPLN_WINSZ - 4), &val, sizeof(val));
} }
// Reset ARM core and check it starts // Reset ARM core and check it starts
if (!cyw_core_reset(CYW_CHIP_ARMCORE, true)) return false; if (!cyw_core_reset(CYW_CHIP_ARMCORE, true)) return false;
@@ -964,6 +1002,8 @@ static bool cyw_load_fwll(void *fwdata, size_t fwlen, void *nvramdata, size_t nv
} }
// clang-format on // clang-format on
#if !MG_ENABLE_DRIVER_CYW_SDIO
// CYW43 SPI bus specifics // CYW43 SPI bus specifics
#define CYW_BUS_SPI_BUSCTRL 0x00 // 4 regs, 0 to 3 #define CYW_BUS_SPI_BUSCTRL 0x00 // 4 regs, 0 to 3
@@ -975,29 +1015,33 @@ static bool cyw_load_fwll(void *fwdata, size_t fwlen, void *nvramdata, size_t nv
#define CYW_BUS_STS_LEN(x) ((x >> 9) & 0x7ff) #define CYW_BUS_STS_LEN(x) ((x >> 9) & 0x7ff)
static bool cyw_spi_write(unsigned int f, uint32_t addr, void *data,
uint16_t len);
static void cyw_spi_read(unsigned int f, uint32_t addr, void *data,
uint16_t len);
// clang-format off // clang-format off
static size_t cyw_spi_poll(uint8_t *response) { static size_t cyw_spi_poll(uint8_t *response) {
size_t len; size_t len;
uint32_t res; uint32_t res;
// SPI poll // SPI poll
cyw_spi_read(CYW_SD_FUNC_BUS, CYW_BUS_SPI_STATUS, &res, sizeof(res)); cyw_spi_read(CYW_SPID_FUNC_BUS, CYW_BUS_SPI_STATUS, &res, sizeof(res));
if (res == ~0 || !(res & MG_BIT(8) /* packet available */ )) return 0; if (res == (uint32_t) ~0 || !(res & MG_BIT(8) /* packet available */ )) return 0;
len = CYW_BUS_STS_LEN(res); len = CYW_BUS_STS_LEN(res);
if (len == 0) { // just ack IRQ if (len == 0) { // just ack IRQ
uint16_t val = 1; uint16_t val = 1;
cyw_spi_write(CYW_SD_FUNC_CHIP, CYW_CHIP_SPIFRCTRL, &val, 1); cyw_spi_write(CYW_SPID_FUNC_CHIP, CYW_CHIP_SPIFRCTRL, &val, 1);
cyw_spi_read(CYW_SD_FUNC_BUS, CYW_BUS_SPI_INT, &val, sizeof(val)); cyw_spi_read(CYW_SPID_FUNC_BUS, CYW_BUS_SPI_INT, &val, sizeof(val));
cyw_spi_write(CYW_SD_FUNC_BUS, CYW_BUS_SPI_INT, &val, sizeof(val)); cyw_spi_write(CYW_SPID_FUNC_BUS, CYW_BUS_SPI_INT, &val, sizeof(val));
return 0; return 0;
} }
cyw_spi_read(CYW_SD_FUNC_WLAN, 0, response, len); cyw_spi_read(CYW_SPID_FUNC_WLAN, 0, response, len);
return len; return len;
} }
// BUS DEPENDENCY: name is generic but function is bus dependent static size_t cyw_spi_tx(uint32_t *data, uint16_t len) {
static size_t cyw_bus_tx(uint32_t *data, uint16_t len) { while (len & 3) data[len++] = 0; // SPI 32-bit padding
while (len & 3) data[len++] = 0; // SPI 32-bit padding (SDIO->64-byte) return cyw_spi_write(CYW_SPID_FUNC_WLAN, 0, data, len) ? len: 0;
return cyw_spi_write(CYW_SD_FUNC_WLAN, 0, data, len) ? len: 0;
} }
// this can be integrated in lowest level SPI read/write _driver_ functions // this can be integrated in lowest level SPI read/write _driver_ functions
@@ -1007,20 +1051,19 @@ uint32_t sw16_2(uint32_t data) {
} }
// DS 4.2.2 Table 6: signal we're working in 16-bit mode // DS 4.2.2 Table 6: signal we're working in 16-bit mode
#define CYW_SD_16bMODE MG_BIT(2) // arbitrary bit out of the FUNC space #define CYW_SPI_16bMODE MG_BIT(2) // arbitrary bit out of the FUNC space
static bool cyw_spi_init() { static bool cyw_spi_init() {
struct mg_tcpip_driver_cyw_data *d = struct mg_tcpip_driver_cyw_data *d = (struct mg_tcpip_driver_cyw_data *) s_ifp->driver_data;
(struct mg_tcpip_driver_cyw_data *) s_ifp->driver_data;
uint32_t val = 0; uint32_t val = 0;
// DS 4.2.3 Boot-Up Sequence; WHD: other chips might require more effort // DS 4.2.3 Boot-Up Sequence; WHD: other chips might require more effort
unsigned int times = 51; unsigned int times = 51;
while (times--) { while (times--) {
cyw_spi_read(CYW_SD_FUNC_BUS | CYW_SD_16bMODE, CYW_BUS_SPI_TEST, &val, sizeof(val)); cyw_spi_read(CYW_SPID_FUNC_BUS | CYW_SPI_16bMODE, CYW_BUS_SPI_TEST, &val, sizeof(val));
if (sw16_2(val) == 0xFEEDBEAD) break; if (sw16_2(val) == 0xFEEDBEAD) break;
mg_delayms(1); mg_delayms(1);
} }
if (times == ~0) return false; if (times == (unsigned int) ~0) return false;
// DS 4.2.3 Table 6. Chip starts in 16-bit little-endian mode. // DS 4.2.3 Table 6. Chip starts in 16-bit little-endian mode.
// Configure SPI and switch to 32-bit big-endian mode: // Configure SPI and switch to 32-bit big-endian mode:
// - High-speed mode: d->hs true // - High-speed mode: d->hs true
@@ -1028,33 +1071,34 @@ static bool cyw_spi_init() {
// - SPI RESPONSE DELAY 4 bytes time [not in DS] TODO(scaprile): logic ana // - SPI RESPONSE DELAY 4 bytes time [not in DS] TODO(scaprile): logic ana
// - Status not sent after command, IRQ with status // - Status not sent after command, IRQ with status
val = sw16_2(0x000204a3 | (d->hs ? MG_BIT(4) : 0)); // 4 reg content val = sw16_2(0x000204a3 | (d->hs ? MG_BIT(4) : 0)); // 4 reg content
cyw_spi_write(CYW_SD_FUNC_BUS | CYW_SD_16bMODE, CYW_BUS_SPI_BUSCTRL, &val, sizeof(val)); cyw_spi_write(CYW_SPID_FUNC_BUS | CYW_SPI_16bMODE, CYW_BUS_SPI_BUSCTRL, &val, sizeof(val));
mg_tcpip_call(s_ifp, MG_TCPIP_EV_DRIVER, NULL); mg_tcpip_call(s_ifp, MG_TCPIP_EV_DRIVER, NULL);
cyw_spi_read(CYW_SD_FUNC_BUS, CYW_BUS_SPI_TEST, &val, sizeof(val)); cyw_spi_read(CYW_SPID_FUNC_BUS, CYW_BUS_SPI_TEST, &val, sizeof(val));
if (val != 0xFEEDBEAD) return false; if (val != 0xFEEDBEAD) return false;
val = 4; cyw_spi_write(CYW_SD_FUNC_BUS, CYW_BUS_SPI_RESPDLY_F1, &val, 1); val = 4; cyw_spi_write(CYW_SPID_FUNC_BUS, CYW_BUS_SPI_RESPDLY_F1, &val, 1);
val = 0x99; // clear error bits DATA_UNAVAILABLE, COMMAND_ERROR, DATA_ERROR, F1_OVERFLOW val = 0x99; // clear error bits DATA_UNAVAILABLE, COMMAND_ERROR, DATA_ERROR, F1_OVERFLOW
cyw_spi_write(CYW_SD_FUNC_BUS, CYW_BUS_SPI_INT, &val, 1); cyw_spi_write(CYW_SPID_FUNC_BUS, CYW_BUS_SPI_INT, &val, 1);
val = 0x00be; // Enable IRQs F2_F3_FIFO_RD_UNDERFLOW, F2_F3_FIFO_WR_OVERFLOW, COMMAND_ERROR, DATA_ERROR, F2_PACKET_AVAILABLE, F1_OVERFLOW val = 0x00be; // Enable IRQs F2_F3_FIFO_RD_UNDERFLOW, F2_F3_FIFO_WR_OVERFLOW, COMMAND_ERROR, DATA_ERROR, F2_PACKET_AVAILABLE, F1_OVERFLOW
// BT-ENABLED DEPENDENCY: add F1_INTR (bit 13) // BT-ENABLED DEPENDENCY: add F1_INTR (bit 13)
cyw_spi_write(CYW_SD_FUNC_BUS, CYW_BUS_SPI_INTEN, &val, sizeof(uint16_t)); cyw_spi_write(CYW_SPID_FUNC_BUS, CYW_BUS_SPI_INTEN, &val, sizeof(uint16_t));
// chip backplane is ready, initialize it // chip backplane is ready, initialize it
// request ALP (Active Low Power) clock // request ALP (Active Low Power) clock
val = MG_BIT(3) /* ALP_REQ */; cyw_spi_write(CYW_SD_FUNC_CHIP, CYW_CHIP_CLOCKCSR, &val, 1); val = MG_BIT(3) /* ALP_REQ */; cyw_spi_write(CYW_SPID_FUNC_CHIP, CYW_CHIP_CLOCKCSR, &val, 1);
// BT-ENABLED DEPENDENCY // BT-ENABLED DEPENDENCY
times = 10; times = 10;
while (times--) { while (times--) {
cyw_spi_read(CYW_SD_FUNC_CHIP, CYW_CHIP_CLOCKCSR, &val, 1); cyw_spi_read(CYW_SPID_FUNC_CHIP, CYW_CHIP_CLOCKCSR, &val, 1);
if (val & MG_BIT(6)) break; // ALP_AVAIL if (val & MG_BIT(6)) break; // ALP_AVAIL
mg_delayms(1); mg_delayms(1);
} }
if (times == ~0) return false; if (times == (unsigned int) ~0) return false;
// clear request // clear request
val = 0; cyw_spi_write(CYW_SD_FUNC_CHIP, CYW_CHIP_CLOCKCSR, &val, 1); val = 0; cyw_spi_write(CYW_SPID_FUNC_CHIP, CYW_CHIP_CLOCKCSR, &val, 1);
cyw_set_backplane_window(CYW_CHIP_CHIPCOMMON); // set backplane window to start of CHIPCOMMON area cyw_set_backplane_window(CYW_CHIP_CHIPCOMMON); // set backplane window to start of CHIPCOMMON area
cyw_spi_read(CYW_SD_FUNC_CHIP, (CYW_CHIP_CHIPCOMMON + 0x00) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 2); cyw_spi_read(CYW_SPID_FUNC_CHIP, (CYW_CHIP_CHIPCOMMON + 0x00) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 2);
MG_INFO(("WLAN chip is CYW%u", *((uint16_t *)&val))); if (val == 43430) val = 4343;
MG_INFO(("WLAN chip is CYW%u%c", val), val == 4343 ? 'W' : ' '));
// Load firmware (code and NVRAM) // Load firmware (code and NVRAM)
if (!cyw_load_firmware(d->fw)) return false; if (!cyw_load_firmware(d->fw)) return false;
@@ -1062,77 +1106,74 @@ static bool cyw_spi_init() {
// Wait for High Throughput (HT) clock ready // Wait for High Throughput (HT) clock ready
times = 50; times = 50;
while (times--) { while (times--) {
cyw_spi_read(CYW_SD_FUNC_CHIP, CYW_CHIP_CLOCKCSR, &val, 1); cyw_spi_read(CYW_SPID_FUNC_CHIP, CYW_CHIP_CLOCKCSR, &val, 1);
if (val & MG_BIT(7)) break; // HT_AVAIL if (val & MG_BIT(7)) break; // HT_AVAIL
mg_delayms(1); mg_delayms(1);
} }
if (times == ~0) return false; if (times == (unsigned int) ~0) return false;
// Wait for backplane ready // Wait for backplane ready
times = 1000; times = 1000;
while (times--) { while (times--) {
cyw_spi_read(CYW_SD_FUNC_BUS, CYW_BUS_SPI_STATUS, &val, sizeof(val)); cyw_spi_read(CYW_SPID_FUNC_BUS, CYW_BUS_SPI_STATUS, &val, sizeof(val));
if (val & MG_BIT(5)) break; // F2_RX_READY if (val & MG_BIT(5)) break; // F2_RX_READY
mg_delayms(1); mg_delayms(1);
} }
if (times == ~0) return false; if (times == (unsigned int) ~0) return false;
// CHIP DEPENDENCY // CHIP DEPENDENCY
// Enable save / restore // Enable save / restore
// Configure WakeupCtrl, set HT_AVAIL in CLOCK_CSR // Configure WakeupCtrl, set HT_AVAIL in CLOCK_CSR
cyw_spi_read(CYW_SD_FUNC_CHIP, CYW_CHIP_WAKEUPCTL, &val, 1); cyw_spi_read(CYW_SPID_FUNC_CHIP, CYW_CHIP_WAKEUPCTL, &val, 1);
val |= MG_BIT(1) /* WAKE_TILL_HT_AVAIL */; cyw_spi_write(CYW_SD_FUNC_CHIP, CYW_CHIP_WAKEUPCTL, &val, 1); val |= MG_BIT(1) /* WAKE_TILL_HT_AVAIL */; cyw_spi_write(CYW_SPID_FUNC_CHIP, CYW_CHIP_WAKEUPCTL, &val, 1);
#if 0 #if 0
// Set BRCM_CARDCAP to CMD_NODEC. NOTE(): This is probably only necessary for SDIO, not SPI // Set BRCM_CARDCAP to CMD_NODEC. NOTE(): This is probably only necessary for SDIO, not SPI
val = MG_BIT(3); cyw_spi_write(CYW_SD_FUNC_BUS, 0xf0 /* SDIOD_CCCR_BRCM_CARDCAP */, &val, 1); val = MG_BIT(3); cyw_spi_write(CYW_SPID_FUNC_BUS, 0xf0 /* SDIOD_CCCR_BRCM_CARDCAP */, &val, 1);
#endif #endif
// Force HT request to chip backplane // Force HT request to chip backplane
val = MG_BIT(1) /* FORCE_HT */; cyw_spi_write(CYW_SD_FUNC_CHIP, CYW_CHIP_CLOCKCSR, &val, 1); val = MG_BIT(1) /* FORCE_HT */; cyw_spi_write(CYW_SPID_FUNC_CHIP, CYW_CHIP_CLOCKCSR, &val, 1);
// Enable Keep SDIO On (KSO) // Enable Keep SDIO On (KSO)
cyw_spi_read(CYW_SD_FUNC_CHIP, CYW_CHIP_SLEEPCSR, &val, 1); cyw_spi_read(CYW_SPID_FUNC_CHIP, CYW_CHIP_SLEEPCSR, &val, 1);
if (!(val & MG_BIT(0))) { if (!(val & MG_BIT(0))) {
val |= MG_BIT(0); cyw_spi_write(CYW_SD_FUNC_CHIP, CYW_CHIP_SLEEPCSR, &val, 1); val |= MG_BIT(0); cyw_spi_write(CYW_SPID_FUNC_CHIP, CYW_CHIP_SLEEPCSR, &val, 1);
} }
// The SPI bus can be configured for sleep (KSO controls wlan block sleep) // The SPI bus can be configured for sleep (KSO controls wlan block sleep)
cyw_spi_read(CYW_SD_FUNC_BUS, CYW_BUS_SPI_BUSCTRL, &val, sizeof(val)); cyw_spi_read(CYW_SPID_FUNC_BUS, CYW_BUS_SPI_BUSCTRL, &val, sizeof(val));
val &= ~MG_BIT(7) /* WAKE_UP */; cyw_spi_write(CYW_SD_FUNC_BUS, CYW_BUS_SPI_BUSCTRL, &val, sizeof(val)); val &= ~MG_BIT(7) /* WAKE_UP */; cyw_spi_write(CYW_SPID_FUNC_BUS, CYW_BUS_SPI_BUSCTRL, &val, sizeof(val));
// Set SPI bus sleep // Set SPI bus sleep
val = 0x0f; cyw_spi_write(CYW_SD_FUNC_CHIP, CYW_CHIP_PULLUP, &val, 1); val = 0x0f; cyw_spi_write(CYW_SPID_FUNC_CHIP, CYW_CHIP_PULLUP, &val, 1);
// Clear pullups. NOTE(): ? // Clear pullups. NOTE(): ?
val = 0x00; cyw_spi_write(CYW_SD_FUNC_CHIP, CYW_CHIP_PULLUP, &val, 1); val = 0x00; cyw_spi_write(CYW_SPID_FUNC_CHIP, CYW_CHIP_PULLUP, &val, 1);
cyw_spi_read(CYW_SD_FUNC_CHIP, CYW_CHIP_PULLUP, &val, 1); cyw_spi_read(CYW_SPID_FUNC_CHIP, CYW_CHIP_PULLUP, &val, 1);
// Clear possible data unavailable error // Clear possible data unavailable error
cyw_spi_read(CYW_SD_FUNC_BUS, CYW_BUS_SPI_INTEN, &val, sizeof(uint16_t)); cyw_spi_read(CYW_SPID_FUNC_BUS, CYW_BUS_SPI_INTEN, &val, sizeof(uint16_t));
if (val & MG_BIT(0)) cyw_spi_write(CYW_SD_FUNC_BUS, CYW_BUS_SPI_INTEN, &val, sizeof(uint16_t)); if (val & MG_BIT(0)) cyw_spi_write(CYW_SPID_FUNC_BUS, CYW_BUS_SPI_INTEN, &val, sizeof(uint16_t));
// Load CLM blob
if (!cyw_load_clm(d->fw)) return false;
return true; return true;
} }
// clang-format on // clang-format on
// gSPI, DS 4.2.1 Fig.12 // gSPI, CYW43439 DS 4.2.1 Fig.12
#define CYW_SD_LEN(x) ((x) &0x7FF) // bits 0-10 #define CYW_SPID_LEN(x) ((x) &0x7FF) // bits 0-10
#define CYW_SD_ADDR(x) (((x) &0x1FFFF) << 11) // bits 11-27, #define CYW_SPID_ADDR(x) (((x) &0x1FFFF) << 11) // bits 11-27,
#define CYW_SD_FUNC(x) (((x) &3) << 28) // bits 28-29 #define CYW_SPID_FUNC(x) (((x) &3) << 28) // bits 28-29
#define CYW_SD_INC MG_BIT(30) #define CYW_SPID_INC MG_BIT(30)
#define CYW_SD_WR MG_BIT(31) #define CYW_SPID_WR MG_BIT(31)
static bool cyw_spi_write(unsigned int f, uint32_t addr, void *data, static bool cyw_spi_write(unsigned int f, uint32_t addr, void *data,
uint16_t len) { uint16_t len) {
struct mg_tcpip_driver_cyw_data *d = struct mg_tcpip_driver_cyw_data *d =
(struct mg_tcpip_driver_cyw_data *) s_ifp->driver_data; (struct mg_tcpip_driver_cyw_data *) s_ifp->driver_data;
struct mg_tcpip_spi_ *s = (struct mg_tcpip_spi_ *) d->spi; struct mg_tcpip_spi_ *s = (struct mg_tcpip_spi_ *) d->bus;
uint32_t hdr = CYW_SD_WR | CYW_SD_INC | CYW_SD_FUNC(f) | CYW_SD_ADDR(addr) | uint32_t hdr = CYW_SPID_WR | CYW_SPID_INC | CYW_SPID_FUNC(f) |
CYW_SD_LEN(len); // gSPI header CYW_SPID_ADDR(addr) | CYW_SPID_LEN(len); // gSPI header
// TODO(scaprile): check spin in between and timeout values, return false // TODO(scaprile): check spin in between and timeout values, return false
if (f == CYW_SD_FUNC_WLAN) { if (f == CYW_SPID_FUNC_WLAN) {
uint32_t val = 0; uint32_t val = 0;
while ((val & MG_BIT(5)) != MG_BIT(5)) // F2 rx ready (FIFO ready) while ((val & MG_BIT(5)) != MG_BIT(5)) // F2 rx ready (FIFO ready)
cyw_spi_read(CYW_SD_FUNC_BUS, CYW_BUS_SPI_STATUS, &val, sizeof(val)); cyw_spi_read(CYW_SPID_FUNC_BUS, CYW_BUS_SPI_STATUS, &val, sizeof(val));
} }
if (f & CYW_SD_16bMODE) if (f & CYW_SPI_16bMODE)
hdr = sw16_2(hdr); // swap half-words in 16-bit little-endian mode hdr = sw16_2(hdr); // swap half-words in 16-bit little-endian mode
s->begin(NULL); s->begin(NULL);
@@ -1148,26 +1189,26 @@ static bool cyw_spi_write(unsigned int f, uint32_t addr, void *data,
return true; return true;
} }
// will write 32-bit aligned quantities to data if f == CYW_SD_FUNC_WLAN // will write 32-bit aligned quantities to data if f == CYW_SPID_FUNC_WLAN
static void cyw_spi_read(unsigned int f, uint32_t addr, void *data, static void cyw_spi_read(unsigned int f, uint32_t addr, void *data,
uint16_t len) { uint16_t len) {
struct mg_tcpip_driver_cyw_data *d = struct mg_tcpip_driver_cyw_data *d =
(struct mg_tcpip_driver_cyw_data *) s_ifp->driver_data; (struct mg_tcpip_driver_cyw_data *) s_ifp->driver_data;
struct mg_tcpip_spi_ *s = (struct mg_tcpip_spi_ *) d->spi; struct mg_tcpip_spi_ *s = (struct mg_tcpip_spi_ *) d->bus;
uint32_t padding = uint32_t padding =
f == CYW_SD_FUNC_CHIP f == CYW_SPID_FUNC_CHIP
? 4 ? 4
: 0; // add padding to chip backplane reads as a response delay : 0; // add padding to chip backplane reads as a response delay
uint32_t hdr = CYW_SD_INC | CYW_SD_FUNC(f) | CYW_SD_ADDR(addr) | uint32_t hdr = CYW_SPID_INC | CYW_SPID_FUNC(f) | CYW_SPID_ADDR(addr) |
CYW_SD_LEN(len + padding); // gSPI header CYW_SPID_LEN(len + padding); // gSPI header
if (f == CYW_SD_FUNC_WLAN && (len & 3)) if (f == CYW_SPID_FUNC_WLAN && (len & 3))
len = (len + 4) & ~3; // align WLAN transfers to 32-bit len = (len + 4) & ~3; // align WLAN transfers to 32-bit
if (f & CYW_SD_16bMODE) if (f & CYW_SPI_16bMODE)
hdr = sw16_2(hdr); // swap half-words in 16-bit little-endian mode hdr = sw16_2(hdr); // swap half-words in 16-bit little-endian mode
s->begin(NULL); s->begin(NULL);
s->txn(NULL, (uint8_t *) &hdr, NULL, sizeof(hdr)); s->txn(NULL, (uint8_t *) &hdr, NULL, sizeof(hdr));
if (f == CYW_SD_FUNC_CHIP) { if (f == CYW_SPID_FUNC_CHIP) {
uint32_t pad; uint32_t pad;
s->txn(NULL, NULL, (uint8_t *) &pad, 4); // read padding back and discard s->txn(NULL, NULL, (uint8_t *) &pad, 4); // read padding back and discard
} }
@@ -1175,6 +1216,160 @@ static void cyw_spi_read(unsigned int f, uint32_t addr, void *data,
s->end(NULL); s->end(NULL);
} }
static bool cyw_bus_specific_init(void) {
return cyw_spi_init();
}
static size_t cyw_bus_specific_poll(uint32_t *response) {
return cyw_spi_poll((uint8_t *) response);
}
static size_t cyw_bus_specific_tx(uint32_t *data, uint16_t len) {
return cyw_spi_tx(data, len);
}
static bool cyw_bus_write(unsigned int f, uint32_t addr, void *data,
uint16_t len) {
if (f == CYW_SPID_FUNC_CHIP && len >= 4) addr |= CYW_CHIP_BCKPLN_ACCSS4B;
return cyw_spi_write(f, addr, data, len);
}
static bool cyw_bus_read(unsigned int f, uint32_t addr, void *data,
uint16_t len) {
cyw_spi_read(f, addr, data, len);
return true;
}
#else // MG_ENABLE_DRIVER_CYW_SDIO
#include "sdio.h"
// CYW43 SDIO bus specifics
// CYW4343W and CYW43439 DS 4.1 SDIO v2.0:
//- F0: max block size is 32 bytes
//- F1: max block size is 64 bytes
//- F2: max block size is 512 bytes
// clang-format off
static bool cyw_sdio_transfer(bool write, unsigned int f, uint32_t addr, void *data, uint32_t len) {
struct mg_tcpip_driver_cyw_data *d = (struct mg_tcpip_driver_cyw_data *) s_ifp->driver_data;
struct mg_tcpip_sdio *s = (struct mg_tcpip_sdio *) d->bus;
uint32_t *ptr = (uint32_t *) data; // assume 32-bit aligned data (all except firmware)
if (write && (size_t) data & 3) { // missed, source data is not 32-bit aligned
memcpy(txdata, data, len); // copy to an aligned buffer, we know it fits
ptr = txdata;
} // all possible read destinations are 32-bit aligned
// mg_sdio_transfer requires 32-bit alignment for > 1 byte transfers
return mg_sdio_transfer(s, write, f, addr, ptr, len);
}
static size_t cyw_sdio_poll(uint32_t *response) {
uint32_t res;
uint16_t *len = (uint16_t *)&res;
// WHD: internal docs, "tag" hinting a possible packet.
// This is actually the len / ~len field of a possible struct sdpcm_hdr, if there is a packet available, or 0 if there is none.
cyw_sdio_transfer(false, CYW_SDIO_FUNC_WLAN, 0, &res, sizeof(res)); // read "the tag"
if ((len[0] | len[1]) == 0 || (len[0] ^ len[1]) != 0xffff || *len <= 4) return 0;
response[0] = res; // copy what we already read, then read the rest
cyw_sdio_transfer(false, CYW_SDIO_FUNC_WLAN, 0, response + 1, *len - sizeof(res));
return (size_t)*len;
}
static size_t cyw_sdio_tx(uint32_t *data, uint16_t len) {
return cyw_sdio_transfer(true, CYW_SDIO_FUNC_WLAN, 0, data, len) ? len: 0;
}
static bool cyw_sdio_init() {
struct mg_tcpip_driver_cyw_data *d = (struct mg_tcpip_driver_cyw_data *) s_ifp->driver_data;
struct mg_tcpip_sdio *s = (struct mg_tcpip_sdio *) d->bus;
uint32_t val = 0;
if (!mg_sdio_init(s)) return false;
// no block transfers on F0. if (!mg_sdio_set_blksz(s, CYW_SDIO_FUNC_BUS, 32)) return false;
if (!mg_sdio_set_blksz(s, CYW_SDIO_FUNC_CHIP, 64)) return false;
if (!mg_sdio_set_blksz(s, CYW_SDIO_FUNC_WLAN, 64)) return false;
// TODO(scaprile): we don't handle SDIO interrupts, study CCCR INTEN and SDIO support (SDIO 6.3, 8)
// Enable chip backplane (F1)
if (!mg_sdio_enable_f(s, CYW_SDIO_FUNC_CHIP)) return false;
// Wait for F1 to be ready
if (!mg_sdio_waitready_f(s, CYW_SDIO_FUNC_CHIP)) return false;
// chip backplane is ready, initialize it
// request ALP (Active Low Power) clock
val = MG_BIT(5) | MG_BIT(3) | MG_BIT(0); // HW_CLKREQ_OFF ALP_REQ FORCE_ALP
cyw_sdio_transfer(true, CYW_SDIO_FUNC_CHIP, CYW_CHIP_CLOCKCSR, &val, 1);
// BT-ENABLED DEPENDENCY
unsigned int times = 10;
while (times--) {
if(!cyw_sdio_transfer(false, CYW_SDIO_FUNC_CHIP, CYW_CHIP_CLOCKCSR, &val, 1)) return false;
if (val & MG_BIT(6)) break; // ALP_AVAIL
mg_delayms(1);
}
if (times == (unsigned int) ~0) return false;
// clear request
val = 0; cyw_sdio_transfer(true, CYW_SDIO_FUNC_CHIP, CYW_CHIP_CLOCKCSR, &val, 1);
// Enable WLAN (F2)
if (!mg_sdio_enable_f(s, CYW_SDIO_FUNC_WLAN)) return false;
// Clear pullups. NOTE(): ?
val = 0x00; cyw_sdio_transfer(true, CYW_SDIO_FUNC_CHIP, CYW_CHIP_PULLUP, &val, 1);
// we don't handle wake nor OOB interrupts; SEP_INT_CTL is a vendor specific SDIO register
// SDIO interrupts: enable F2 interrupt only
cyw_set_backplane_window(CYW_CHIP_CHIPCOMMON); // set backplane window to start of CHIPCOMMON area
cyw_sdio_transfer(false, CYW_SDIO_FUNC_CHIP, (CYW_CHIP_CHIPCOMMON + 0x00) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 2);
if (val == 43430) val = 4343;
MG_INFO(("WLAN chip is CYW%u%c", val, val == 4343 ? 'W' : ' '));
// Load firmware (code and NVRAM)
if (!cyw_load_firmware(d->fw)) return false;
// Wait for High Throughput (HT) clock ready
times = 50;
while (times--) {
if(!cyw_sdio_transfer(false, CYW_SDIO_FUNC_CHIP, CYW_CHIP_CLOCKCSR, &val, 1)) return false;
if (val & MG_BIT(7)) break; // HT_AVAIL
mg_delayms(1);
}
if (times == (unsigned int) ~0) return false;
// Wait for WLAN ready
if (!mg_sdio_waitready_f(s, CYW_SDIO_FUNC_WLAN)) return false;
// CHIP DEPENDENCY
// Enable save / restore
// Configure WakeupCtrl, set HT_AVAIL in CLOCK_CSR
if(!cyw_sdio_transfer(false, CYW_SDIO_FUNC_CHIP, CYW_CHIP_WAKEUPCTL, &val, 1)) return false;
val |= MG_BIT(1) /* WAKE_TILL_HT_AVAIL */; cyw_sdio_transfer(true, CYW_SDIO_FUNC_CHIP, CYW_CHIP_WAKEUPCTL, &val, 1);
#if 0 // TODO(scaprile): Check if this is actually necessary
// Set BRCM_CARDCAP to CMD_NODEC. This is a vendor specific SDIO register
val = MG_BIT(3); cyw_sdio_transfer(true, CYW_SDIO_FUNC_BUS, 0xf0 /* SDIOD_CCCR_BRCM_CARDCAP */, &val, 1);
#endif
// Force HT request to chip backplane
val = MG_BIT(1) /* FORCE_HT */; if(!cyw_sdio_transfer(true, CYW_SDIO_FUNC_CHIP, CYW_CHIP_CLOCKCSR, &val, 1)) return false;
// Enable Keep SDIO On (KSO)
cyw_sdio_transfer(false, CYW_SDIO_FUNC_CHIP, CYW_CHIP_SLEEPCSR, &val, 1);
if (!(val & MG_BIT(0))) {
val |= MG_BIT(0); cyw_sdio_transfer(true, CYW_SDIO_FUNC_CHIP, CYW_CHIP_SLEEPCSR, &val, 1);
}
return true;
}
// clang-format on
static bool cyw_bus_specific_init(void) {
return cyw_sdio_init();
}
static size_t cyw_bus_specific_poll(uint32_t *response) {
return cyw_sdio_poll(response);
}
static size_t cyw_bus_specific_tx(uint32_t *data, uint16_t len) {
return cyw_sdio_tx(data, len);
}
static bool cyw_bus_write(unsigned int f, uint32_t addr, void *data,
uint16_t len) {
if (f == CYW_SDIO_FUNC_CHIP && len == 4) addr |= CYW_CHIP_BCKPLN_ACCSS4B;
return cyw_sdio_transfer(true, f, addr, data, (uint32_t) len);
}
static bool cyw_bus_read(unsigned int f, uint32_t addr, void *data,
uint16_t len) {
return cyw_sdio_transfer(false, f, addr, data, (uint32_t) len);
}
#endif
// Mongoose Wi-Fi API functions // Mongoose Wi-Fi API functions
bool mg_wifi_scan(void) { bool mg_wifi_scan(void) {
+4 -2
View File
@@ -1,6 +1,8 @@
#pragma once #pragma once
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_CYW) && MG_ENABLE_DRIVER_CYW #if MG_ENABLE_TCPIP && \
((defined(MG_ENABLE_DRIVER_CYW) && MG_ENABLE_DRIVER_CYW) || \
(defined(MG_ENABLE_DRIVER_CYW_SDIO) && MG_ENABLE_DRIVER_CYW_SDIO))
struct mg_tcpip_spi_ { struct mg_tcpip_spi_ {
void *spi; // Opaque SPI bus descriptor void *spi; // Opaque SPI bus descriptor
@@ -20,7 +22,7 @@ struct mg_tcpip_driver_cyw_firmware {
}; };
struct mg_tcpip_driver_cyw_data { struct mg_tcpip_driver_cyw_data {
struct mg_tcpip_spi_ *spi; void *bus;
struct mg_tcpip_driver_cyw_firmware *fw; struct mg_tcpip_driver_cyw_firmware *fw;
char *ssid; char *ssid;
char *pass; char *pass;
+4 -2
View File
@@ -1,6 +1,8 @@
#include "net_builtin.h" #include "net_builtin.h"
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_IMXRT) && MG_ENABLE_DRIVER_IMXRT #if MG_ENABLE_TCPIP && \
(defined(MG_ENABLE_DRIVER_IMXRT10) && MG_ENABLE_DRIVER_IMXRT10) || \
(defined(MG_ENABLE_DRIVER_IMXRT11) && MG_ENABLE_DRIVER_IMXRT11)
struct imxrt_enet { struct imxrt_enet {
volatile uint32_t RESERVED0, EIR, EIMR, RESERVED1, RDAR, TDAR, RESERVED2[3], volatile uint32_t RESERVED0, EIR, EIMR, RESERVED1, RDAR, TDAR, RESERVED2[3],
ECR, RESERVED3[6], MMFR, MSCR, RESERVED4[7], MIBC, RESERVED5[7], RCR, ECR, RESERVED3[6], MMFR, MSCR, RESERVED4[7], MIBC, RESERVED5[7], RCR,
@@ -26,7 +28,7 @@ struct imxrt_enet {
}; };
#undef ENET #undef ENET
#if defined(MG_DRIVER_IMXRT_RT11) && MG_DRIVER_IMXRT_RT11 #if defined(MG_ENABLE_DRIVER_IMXRT11) && MG_ENABLE_DRIVER_IMXRT11
#define ENET ((struct imxrt_enet *) (uintptr_t) 0x40424000U) #define ENET ((struct imxrt_enet *) (uintptr_t) 0x40424000U)
#define ETH_DESC_CNT 5 // Descriptors count #define ETH_DESC_CNT 5 // Descriptors count
#else #else
+3 -1
View File
@@ -1,6 +1,8 @@
#pragma once #pragma once
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_IMXRT) && MG_ENABLE_DRIVER_IMXRT #if MG_ENABLE_TCPIP && \
(defined(MG_ENABLE_DRIVER_IMXRT10) && MG_ENABLE_DRIVER_IMXRT10) || \
(defined(MG_ENABLE_DRIVER_IMXRT11) && MG_ENABLE_DRIVER_IMXRT11)
struct mg_tcpip_driver_imxrt_data { struct mg_tcpip_driver_imxrt_data {
// MDC clock divider. MDC clock is derived from IPS Bus clock (ipg_clk), // MDC clock divider. MDC clock is derived from IPS Bus clock (ipg_clk),
+20 -9
View File
@@ -1,13 +1,15 @@
#include "phy.h" #include "phy.h"
enum { // ID1 ID2 enum { // ID1 ID2
MG_PHY_KSZ8x = 0x22, // 0022 1561 - KSZ8081RNB MG_PHY_KSZ8x = 0x22, // 0022 1561 - KSZ8081RNB
MG_PHY_DP83x = 0x2000, MG_PHY_DP83x = 0x2000,
MG_PHY_DP83867 = 0xa231, // 2000 a231 - TI DP83867I MG_PHY_DP83867 = 0xa231, // 2000 a231 - TI DP83867I
MG_PHY_DP83825 = 0xa140, // 2000 a140 - TI DP83825I MG_PHY_DP83825 = 0xa140, // 2000 a140 - TI DP83825I
MG_PHY_DP83848 = 0x5ca2, // 2000 5ca2 - TI DP83848I MG_PHY_DP83848 = 0x5ca2, // 2000 5ca2 - TI DP83848I
MG_PHY_LAN87x = 0x7, // 0007 c0fx - LAN8720 MG_PHY_LAN87x = 0x7, // 0007 c0fx - LAN8720
MG_PHY_RTL8201 = 0x1C // 001c c816 - RTL8201 MG_PHY_RTL8201 = 0x1C, // 001c c816 - RTL8201,
MG_PHY_ICS1894x = 0x15,
MG_PHY_ICS189432 = 0xf450 // 0015 f450 - ICS1894
}; };
enum { enum {
@@ -23,7 +25,8 @@ enum {
MG_PHY_KSZ8x_REG_PC2R = 31, MG_PHY_KSZ8x_REG_PC2R = 31,
MG_PHY_LAN87x_REG_SCSR = 31, MG_PHY_LAN87x_REG_SCSR = 31,
MG_PHY_RTL8201_REG_RMSR = 16, // in page 7 MG_PHY_RTL8201_REG_RMSR = 16, // in page 7
MG_PHY_RTL8201_REG_PAGESEL = 31 MG_PHY_RTL8201_REG_PAGESEL = 31,
MG_PHY_ICS189432_REG_POLL = 17
}; };
static const char *mg_phy_id_to_str(uint16_t id1, uint16_t id2) { static const char *mg_phy_id_to_str(uint16_t id1, uint16_t id2) {
@@ -45,6 +48,8 @@ static const char *mg_phy_id_to_str(uint16_t id1, uint16_t id2) {
return "LAN87x"; return "LAN87x";
case MG_PHY_RTL8201: case MG_PHY_RTL8201:
return "RTL8201"; return "RTL8201";
case MG_PHY_ICS1894x:
return "ICS1894x";
default: default:
return "unknown"; return "unknown";
} }
@@ -77,11 +82,13 @@ void mg_phy_init(struct mg_phy *phy, uint8_t phy_addr, uint8_t config) {
phy->write_reg(phy_addr, MG_PHY_DP83x_REG_RCSR, MG_BIT(7) | MG_BIT(0)); phy->write_reg(phy_addr, MG_PHY_DP83x_REG_RCSR, MG_BIT(7) | MG_BIT(0));
} else if (id1 == MG_PHY_KSZ8x) { } else if (id1 == MG_PHY_KSZ8x) {
// Disable isolation (override hw, it doesn't make sense at this point) // Disable isolation (override hw, it doesn't make sense at this point)
phy->write_reg( // #2848, some NXP boards set ISO, even though // - #2848, some NXP boards set ISO, even though docs say they don't
phy_addr, MG_PHY_REG_BCR, // docs say they don't phy->write_reg(phy_addr, MG_PHY_REG_BCR,
phy->read_reg(phy_addr, MG_PHY_REG_BCR) & (uint16_t) ~MG_BIT(10)); (uint16_t) (phy->read_reg(phy_addr, MG_PHY_REG_BCR) &
phy->write_reg(phy_addr, MG_PHY_KSZ8x_REG_PC2R, // now do clock stuff (uint16_t) ~MG_BIT(10)));
MG_BIT(15) | MG_BIT(8) | MG_BIT(7)); // now do clock stuff
phy->write_reg(phy_addr, MG_PHY_KSZ8x_REG_PC2R,
(uint16_t) (MG_BIT(15) | MG_BIT(8) | MG_BIT(7)));
} else if (id1 == MG_PHY_LAN87x) { } else if (id1 == MG_PHY_LAN87x) {
// nothing to do // nothing to do
} else if (id1 == MG_PHY_RTL8201) { } else if (id1 == MG_PHY_RTL8201) {
@@ -134,6 +141,10 @@ bool mg_phy_up(struct mg_phy *phy, uint8_t phy_addr, bool *full_duplex,
uint16_t bcr = phy->read_reg(phy_addr, MG_PHY_REG_BCR); uint16_t bcr = phy->read_reg(phy_addr, MG_PHY_REG_BCR);
*full_duplex = bcr & MG_BIT(8); *full_duplex = bcr & MG_BIT(8);
*speed = (bcr & MG_BIT(13)) ? MG_PHY_SPEED_100M : MG_PHY_SPEED_10M; *speed = (bcr & MG_BIT(13)) ? MG_PHY_SPEED_100M : MG_PHY_SPEED_10M;
} else if (id1 == MG_PHY_ICS1894x) {
uint16_t poll_reg = phy->read_reg(phy_addr, MG_PHY_ICS189432_REG_POLL);
*full_duplex = poll_reg & MG_BIT(14);
*speed = (poll_reg & MG_BIT(15)) ? MG_PHY_SPEED_100M : MG_PHY_SPEED_10M;
} }
} }
return up; return up;
+1 -1
View File
@@ -323,6 +323,6 @@ static size_t mg_ppp_rx(void *ethbuf, size_t ethlen, struct mg_tcpip_if *ifp) {
} }
struct mg_tcpip_driver mg_tcpip_driver_ppp = {mg_ppp_init, mg_ppp_tx, mg_ppp_rx, struct mg_tcpip_driver mg_tcpip_driver_ppp = {mg_ppp_init, mg_ppp_tx, mg_ppp_rx,
mg_ppp_up}; mg_ppp_poll};
#endif #endif
+13 -4
View File
@@ -1,6 +1,8 @@
#include "net_builtin.h" #include "net_builtin.h"
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_RA) && MG_ENABLE_DRIVER_RA #if MG_ENABLE_TCPIP && \
(defined(MG_ENABLE_DRIVER_RA6) && MG_ENABLE_DRIVER_RA6) || \
(defined(MG_ENABLE_DRIVER_RA8) && MG_ENABLE_DRIVER_RA8)
struct ra_etherc { struct ra_etherc {
volatile uint32_t ECMR, RESERVED, RFLR, RESERVED1, ECSR, RESERVED2, ECSIPR, volatile uint32_t ECMR, RESERVED, RFLR, RESERVED1, ECSR, RESERVED2, ECSIPR,
RESERVED3, PIR, RESERVED4, PSR, RESERVED5[5], RDMLR, RESERVED6[3], IPGR, RESERVED3, PIR, RESERVED4, PSR, RESERVED5[5], RDMLR, RESERVED6[3], IPGR,
@@ -18,13 +20,20 @@ struct ra_edmac {
}; };
#undef ETHERC #undef ETHERC
#define ETHERC ((struct ra_etherc *) (uintptr_t) 0x40114100U)
#undef EDMAC #undef EDMAC
#define EDMAC ((struct ra_edmac *) (uintptr_t) 0x40114000U)
#undef RASYSC #undef RASYSC
#define RASYSC ((uint32_t *) (uintptr_t) 0x4001E000U)
#undef ICU_IELSR #undef ICU_IELSR
#if defined(MG_ENABLE_DRIVER_RA8) && MG_ENABLE_DRIVER_RA8
#define ETHERC ((struct ra_etherc *) (uintptr_t) 0x40354100U)
#define EDMAC ((struct ra_edmac *) (uintptr_t) 0x40354000U)
#define RASYSC ((uint32_t *) (uintptr_t) 0x4001E000U)
#define ICU_IELSR ((uint32_t *) (uintptr_t) 0x4000C300U)
#else
#define ETHERC ((struct ra_etherc *) (uintptr_t) 0x40114100U)
#define EDMAC ((struct ra_edmac *) (uintptr_t) 0x40114000U)
#define RASYSC ((uint32_t *) (uintptr_t) 0x4001E000U)
#define ICU_IELSR ((uint32_t *) (uintptr_t) 0x40006300U) #define ICU_IELSR ((uint32_t *) (uintptr_t) 0x40006300U)
#endif
#define ETH_PKT_SIZE 1536 // Max frame size, multiple of 32 #define ETH_PKT_SIZE 1536 // Max frame size, multiple of 32
#define ETH_DESC_CNT 4 // Descriptors count #define ETH_DESC_CNT 4 // Descriptors count
+3 -1
View File
@@ -1,6 +1,8 @@
#pragma once #pragma once
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_RA) && MG_ENABLE_DRIVER_RA #if MG_ENABLE_TCPIP && \
(defined(MG_ENABLE_DRIVER_RA6) && MG_ENABLE_DRIVER_RA6) || \
(defined(MG_ENABLE_DRIVER_RA8) && MG_ENABLE_DRIVER_RA8)
struct mg_tcpip_driver_ra_data { struct mg_tcpip_driver_ra_data {
// MDC clock "divider". MDC clock is software generated, // MDC clock "divider". MDC clock is software generated,
+100 -82
View File
@@ -3,7 +3,35 @@
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_SAME54) && \ #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_SAME54) && \
MG_ENABLE_DRIVER_SAME54 MG_ENABLE_DRIVER_SAME54
#include <sam.h> struct GMAC_REGS_ {
uint32_t GMAC_NCR, GMAC_NCFGR, GMAC_NSR, GMAC_UR, GMAC_DCFGR, GMAC_TSR,
GMAC_RBQB, GMAC_TBQB, GMAC_RSR, GMAC_ISR, GMAC_IER, GMAC_IDR, GMAC_IMR,
GMAC_MAN, GMAC_RPQ, GMAC_TPQ, GMAC_TPSF, GMAC_RPSF, GMAC_RJFML,
Reserved1[13], GMAC_HRB, GMAC_HRT, GMAC_SAB0, GMAC_SAT0, GMAC_SAB1,
GMAC_SAT1, GMAC_SAB2, GMAC_SAT2, GMAC_SAB3, GMAC_SAT3, GMAC_TIDM[4],
GMAC_WOL, GMAC_IPGS, GMAC_SVLAN, GMAC_TPFCP, GMAC_SAMB1, GMAC_SAMT1,
Reserved2[3], GMAC_NSC, GMAC_SCL, GMAC_SCH, GMAC_EFTSH, GMAC_EFRSH,
GMAC_PEFTSH, GMAC_PEFRSH, Reserved3[2], GMAC_OTLO, GMAC_OTHI, GMAC_FT,
GMAC_BCFT, GMAC_MFT, GMAC_PFT, GMAC_BFT64, GMAC_TBFT127, GMAC_TBFT255,
GMAC_TBFT511, GMAC_TBFT1023, GMAC_TBFT1518, GMAC_GTBFT1518, GMAC_TUR,
GMAC_SCF, GMAC_MCF, GMAC_EC, GMAC_LC, GMAC_DTF, GMAC_CSE, GMAC_ORLO,
GMAC_ORHI, GMAC_FR, GMAC_BCFR, GMAC_MFR, GMAC_PFR, GMAC_BFR64,
GMAC_TBFR127, GMAC_TBFR255, GMAC_TBFR511, GMAC_TBFR1023, GMAC_TBFR1518,
GMAC_TMXBFR, GMAC_UFR, GMAC_OFR, GMAC_JR, GMAC_FCSE, GMAC_LFFE, GMAC_RSE,
GMAC_AE, GMAC_RRE, GMAC_ROE, GMAC_IHCE, GMAC_TCE, GMAC_UCE, Reserved4[2],
GMAC_TISUBN, GMAC_TSH, Reserved5, GMAC_TSSSL, GMAC_TSSN, GMAC_TSL,
GMAC_TN, GMAC_TA, GMAC_TI, GMAC_EFTSL, GMAC_EFTN, GMAC_EFRSL, GMAC_EFRN,
GMAC_PEFTSL, GMAC_PEFTN, GMAC_PEFRSL, GMAC_PEFRN, Reserved6[28],
GMAC_RLPITR, GMAC_RLPITI, GMAC_TLPITR, GMAC_TLPITI;
};
struct GCLK_REGS_ {
uint32_t GCLK_CTRLA_RESERVED, GCLK_SYNCBUSY, Reserved2[6], GCLK_GENCTRL[12],
Reserved3[12], GCLK_PCHCTRL[48];
};
#define GMAC_REGS ((struct GMAC_REGS_ *) 0x42000800)
#define GCLK_REGS ((struct GCLK_REGS_ *) 0x40001c00)
#define ETH_PKT_SIZE 1536 // Max frame size #define ETH_PKT_SIZE 1536 // Max frame size
#define ETH_DESC_CNT 4 // Descriptors count #define ETH_DESC_CNT 4 // Descriptors count
@@ -17,72 +45,67 @@ static uint8_t s_txno; // Current TX descriptor
static uint8_t s_rxno; // Current RX descriptor static uint8_t s_rxno; // Current RX descriptor
static struct mg_tcpip_if *s_ifp; // MIP interface static struct mg_tcpip_if *s_ifp; // MIP interface
enum { MG_PHY_ADDR = 0, MG_PHYREG_BCR = 0, MG_PHYREG_BSR = 1 };
#define MG_PHYREGBIT_BCR_DUPLEX_MODE MG_BIT(8)
#define MG_PHYREGBIT_BCR_SPEED MG_BIT(13)
#define MG_PHYREGBIT_BSR_LINK_STATUS MG_BIT(2)
static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) { static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) {
GMAC_REGS->GMAC_MAN = GMAC_MAN_CLTTO_Msk | GMAC_REGS->GMAC_MAN = MG_BIT(30) | // Clause 22
GMAC_MAN_OP(2) | // Setting the read operation MG_BIT(29) | // Setting the read operation
GMAC_MAN_WTN(2) | GMAC_MAN_PHYA(addr) | // PHY address MG_BIT(17) | ((addr & 0x1f) << 23) | // PHY address
GMAC_MAN_REGA(reg); // Setting the register ((reg & 0x1f) << 18); // Setting the register
while (!(GMAC_REGS->GMAC_NSR & GMAC_NSR_IDLE_Msk)) (void) 0; while (!(GMAC_REGS->GMAC_NSR & MG_BIT(2))) (void) 0;
return GMAC_REGS->GMAC_MAN & GMAC_MAN_DATA_Msk; // Getting the read value return GMAC_REGS->GMAC_MAN & 0xffff; // Getting the read value
} }
#if 0
static void eth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) { static void eth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) {
GMAC_REGS->GMAC_MAN = GMAC_MAN_CLTTO_Msk | GMAC_MAN_OP(1) | // Setting the write operation GMAC_REGS->GMAC_MAN = MG_BIT(30) |
GMAC_MAN_WTN(2) | GMAC_MAN_PHYA(addr) | // PHY address MG_BIT(28) | // Setting the write operation
GMAC_MAN_REGA(reg) | GMAC_MAN_DATA(val); // Setting the register MG_BIT(17) | ((addr & 0x1f) << 23) | // PHY address
while (!(GMAC_REGS->GMAC_NSR & GMAC_NSR_IDLE_Msk)); // Waiting until the write op is complete ((reg & 0x1f) << 18) | val; // Setting the register
while (!(GMAC_REGS->GMAC_NSR & MG_BIT(2)))
; // Waiting until the write op is complete
} }
#endif
int get_clock_rate(struct mg_tcpip_driver_same54_data *d) { uint32_t get_clock_rate(struct mg_tcpip_driver_same54_data *d) {
if (d && d->mdc_cr >= 0 && d->mdc_cr <= 5) { if (d && d->mdc_cr >= 0 && d->mdc_cr <= 5) {
return d->mdc_cr; return d->mdc_cr;
} else { } else {
// get MCLK from GCLK_GENERATOR 0 // get MCLK from GCLK_GENERATOR 0
uint32_t div = 512; uint32_t div = 512;
uint32_t mclk; uint32_t mclk;
if (!(GCLK_REGS->GCLK_GENCTRL[0] & GCLK_GENCTRL_DIVSEL_Msk)) { if (!(GCLK_REGS->GCLK_GENCTRL[0] & MG_BIT(12))) {
div = ((GCLK_REGS->GCLK_GENCTRL[0] & 0x00FF0000) >> 16); div = ((GCLK_REGS->GCLK_GENCTRL[0] & 0x00FF0000) >> 16);
if (div == 0) div = 1; if (div == 0) div = 1;
} }
switch (GCLK_REGS->GCLK_GENCTRL[0] & GCLK_GENCTRL_SRC_Msk) { switch (GCLK_REGS->GCLK_GENCTRL[0] & 0xF) {
case GCLK_GENCTRL_SRC_XOSC0_Val: case 0: // GCLK_GENCTRL_SRC_XOSC0_Val
mclk = 32000000UL; /* 32MHz */ mclk = 32000000UL; // 32MHz
break; break;
case GCLK_GENCTRL_SRC_XOSC1_Val: case 1: // GCLK_GENCTRL_SRC_XOSC1_Val
mclk = 32000000UL; /* 32MHz */ mclk = 32000000UL; // 32MHz
break; break;
case GCLK_GENCTRL_SRC_OSCULP32K_Val: case 4: // GCLK_GENCTRL_SRC_OSCULP32K_Val
mclk = 32000UL; mclk = 32000UL; // 32Khz
break; break;
case GCLK_GENCTRL_SRC_XOSC32K_Val: case 5: // GCLK_GENCTRL_SRC_XOSC32K_Val
mclk = 32000UL; mclk = 32000UL; // 32Khz
break; break;
case GCLK_GENCTRL_SRC_DFLL_Val: case 6: // GCLK_GENCTRL_SRC_DFLL_Val
mclk = 48000000UL; /* 48MHz */ mclk = 48000000UL; // 48MHz
break; break;
case GCLK_GENCTRL_SRC_DPLL0_Val: case 7: // GCLK_GENCTRL_SRC_DPLL0_Val:
mclk = 200000000UL; /* 200MHz */ mclk = 200000000UL; // 200MHz
break; break;
case GCLK_GENCTRL_SRC_DPLL1_Val: case 8: // GCLK_GENCTRL_SRC_DPLL1_Val
mclk = 200000000UL; /* 200MHz */ mclk = 200000000UL; // 200MHz
break; break;
default: default:
mclk = 200000000UL; /* 200MHz */ mclk = 200000000UL; // 200MHz
} }
mclk /= div; mclk /= div;
uint8_t crs[] = {0, 1, 2, 3, 4, 5}; // GMAC->NCFGR::CLK values uint8_t crs[] = {0, 1, 2, 3, 4, 5}; // GMAC->NCFGR::CLK values
uint8_t dividers[] = {8, 16, 32, 48, 64, 96}; // Respective CLK dividers uint8_t dividers[] = {8, 16, 32, 48, 64, 96}; // Respective CLK dividers
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
if (mclk / dividers[i] <= 2375000UL /* 2.5MHz - 5% */) { if (mclk / dividers[i] <= 2375000UL) { // 2.5MHz - 5%
return crs[i]; return crs[i];
} }
} }
@@ -96,11 +119,12 @@ static bool mg_tcpip_driver_same54_init(struct mg_tcpip_if *ifp) {
(struct mg_tcpip_driver_same54_data *) ifp->driver_data; (struct mg_tcpip_driver_same54_data *) ifp->driver_data;
s_ifp = ifp; s_ifp = ifp;
MCLK_REGS->MCLK_APBCMASK |= MCLK_APBCMASK_GMAC_Msk; GMAC_REGS->GMAC_NCFGR = get_clock_rate(d) << 18; // Set MDC divider
MCLK_REGS->MCLK_AHBMASK |= MCLK_AHBMASK_GMAC_Msk; GMAC_REGS->GMAC_NCR = 0; // Disable RX & TX
GMAC_REGS->GMAC_NCFGR = GMAC_NCFGR_CLK(get_clock_rate(d)); // Set MDC divider GMAC_REGS->GMAC_NCR |= MG_BIT(4); // Enable MDC & MDIO
GMAC_REGS->GMAC_NCR = 0; // Disable RX & TX
GMAC_REGS->GMAC_NCR |= GMAC_NCR_MPE_Msk; // Enable MDC & MDIO struct mg_phy phy = {eth_read_phy, eth_write_phy};
mg_phy_init(&phy, d->phy_addr, 0);
for (int i = 0; i < ETH_DESC_CNT; i++) { // Init TX descriptors for (int i = 0; i < ETH_DESC_CNT; i++) { // Init TX descriptors
s_txdesc[i][0] = (uint32_t) s_txbuf[i]; // Point to data buffer s_txdesc[i][0] = (uint32_t) s_txbuf[i]; // Point to data buffer
@@ -108,38 +132,33 @@ static bool mg_tcpip_driver_same54_init(struct mg_tcpip_if *ifp) {
} }
s_txdesc[ETH_DESC_CNT - 1][1] |= MG_BIT(30); // Last tx descriptor - wrap s_txdesc[ETH_DESC_CNT - 1][1] |= MG_BIT(30); // Last tx descriptor - wrap
GMAC_REGS->GMAC_DCFGR = GMAC_DCFGR_DRBS(0x18) // DMA recv buf 1536 GMAC_REGS->GMAC_DCFGR = (0x18 << 16) | // DMA recv buf 1536
| GMAC_DCFGR_RXBMS(GMAC_DCFGR_RXBMS_FULL_Val) | (3 << 8) | // RXBMS
GMAC_DCFGR_TXPBMS(1); // See #2487 MG_BIT(10); // See #2487
for (int i = 0; i < ETH_DESC_CNT; i++) { // Init RX descriptors for (int i = 0; i < ETH_DESC_CNT; i++) { // Init RX descriptors
s_rxdesc[i][0] = (uint32_t) s_rxbuf[i]; // Address of the data buffer s_rxdesc[i][0] = (uint32_t) s_rxbuf[i]; // Address of the data buffer
s_rxdesc[i][1] = 0; // Clear status s_rxdesc[i][1] = 0; // Clear status
} }
s_rxdesc[ETH_DESC_CNT - 1][0] |= MG_BIT(1); // Last rx descriptor - wrap s_rxdesc[ETH_DESC_CNT - 1][0] |= MG_BIT(1); // Last rx descriptor - wrap
GMAC_REGS->GMAC_TBQB = (uint32_t) s_txdesc; // about the descriptor addresses GMAC_REGS->GMAC_TBQB = (uint32_t) s_txdesc; // about the descriptor addresses
GMAC_REGS->GMAC_RBQB = (uint32_t) s_rxdesc; // Let the controller know GMAC_REGS->GMAC_RBQB = (uint32_t) s_rxdesc; // Let the controller know
GMAC_REGS->SA[0].GMAC_SAB = GMAC_REGS->GMAC_SAB0 =
MG_U32(ifp->mac[3], ifp->mac[2], ifp->mac[1], ifp->mac[0]); MG_U32(ifp->mac[3], ifp->mac[2], ifp->mac[1], ifp->mac[0]);
GMAC_REGS->SA[0].GMAC_SAT = MG_U32(0, 0, ifp->mac[5], ifp->mac[4]); GMAC_REGS->GMAC_SAT0 = MG_U32(0, 0, ifp->mac[5], ifp->mac[4]);
GMAC_REGS->GMAC_UR &= ~GMAC_UR_MII_Msk; // Disable MII, use RMII GMAC_REGS->GMAC_UR &= ~MG_BIT(0); // Disable MII, use RMII
GMAC_REGS->GMAC_NCFGR |= GMAC_NCFGR_MAXFS_Msk | GMAC_NCFGR_MTIHEN_Msk | GMAC_REGS->GMAC_NCFGR |= MG_BIT(8) | MG_BIT(6) | // MAXFX, MTIHEN
GMAC_NCFGR_EFRHD_Msk | GMAC_NCFGR_CAF_Msk; MG_BIT(25) | MG_BIT(4); // EFRHD, CAF
GMAC_REGS->GMAC_TSR = GMAC_TSR_HRESP_Msk | GMAC_TSR_UND_Msk | GMAC_REGS->GMAC_TSR = 0x17f; // all transmit statuses
GMAC_TSR_TXCOMP_Msk | GMAC_TSR_TFC_Msk | GMAC_REGS->GMAC_RSR = 0xf; // all recv statuses
GMAC_TSR_TXGO_Msk | GMAC_TSR_RLE_Msk |
GMAC_TSR_COL_Msk | GMAC_TSR_UBR_Msk;
GMAC_REGS->GMAC_RSR = GMAC_RSR_HNO_Msk | GMAC_RSR_RXOVR_Msk |
GMAC_RSR_REC_Msk | GMAC_RSR_BNA_Msk;
GMAC_REGS->GMAC_IDR = ~0U; // Disable interrupts, then enable required GMAC_REGS->GMAC_IDR = ~0U; // Disable interrupts, then enable required
GMAC_REGS->GMAC_IER = GMAC_IER_HRESP_Msk | GMAC_IER_ROVR_Msk | GMAC_REGS->GMAC_IER = MG_BIT(11) | MG_BIT(10) | // HRESP, ROVR
GMAC_IER_TCOMP_Msk | GMAC_IER_TFC_Msk | MG_BIT(7) | MG_BIT(6) | // TCOMP, TFC
GMAC_IER_RLEX_Msk | GMAC_IER_TUR_Msk | MG_BIT(5) | MG_BIT(4) | // RLEX, TUR
GMAC_IER_RXUBR_Msk | GMAC_IER_RCOMP_Msk; MG_BIT(2) | MG_BIT(1); // RXUBR, RCOMP
GMAC_REGS->GMAC_NCR |= GMAC_NCR_TXEN_Msk | GMAC_NCR_RXEN_Msk; GMAC_REGS->GMAC_NCR |= MG_BIT(3) | MG_BIT(2); // TXEN, RXEN
NVIC_EnableIRQ(GMAC_IRQn);
return true; return true;
} }
@@ -160,8 +179,8 @@ static size_t mg_tcpip_driver_same54_tx(const void *buf, size_t len,
s_txdesc[s_txno][1] = status; s_txdesc[s_txno][1] = status;
if (++s_txno >= ETH_DESC_CNT) s_txno = 0; if (++s_txno >= ETH_DESC_CNT) s_txno = 0;
} }
__DSB(); // Ensure descriptors have been written MG_DSB(); // Ensure descriptors have been written
GMAC_REGS->GMAC_NCR |= GMAC_NCR_TSTART_Msk; // Enable transmission GMAC_REGS->GMAC_NCR |= MG_BIT(9); // Enable transmission
return len; return len;
} }
@@ -172,7 +191,7 @@ static void mg_tcpip_driver_same54_update_hash_table(struct mg_tcpip_if *ifp) {
// computed hash is 55, which means bit 23 (55 - 32) in // computed hash is 55, which means bit 23 (55 - 32) in
// HRT register must be set // HRT register must be set
GMAC_REGS->GMAC_HRT = MG_BIT(23); GMAC_REGS->GMAC_HRT = MG_BIT(23);
GMAC_REGS->GMAC_NCFGR |= MG_BIT(6); // enable multicast hash filtering GMAC_REGS->GMAC_NCFGR |= MG_BIT(6); // enable multicast hash filtering
(void) ifp; (void) ifp;
} }
@@ -181,21 +200,22 @@ static bool mg_tcpip_driver_same54_poll(struct mg_tcpip_if *ifp, bool s1) {
mg_tcpip_driver_same54_update_hash_table(ifp); mg_tcpip_driver_same54_update_hash_table(ifp);
ifp->update_mac_hash_table = false; ifp->update_mac_hash_table = false;
} }
bool up = false;
if (s1) { if (s1) {
uint16_t bsr = eth_read_phy(MG_PHY_ADDR, MG_PHYREG_BSR); uint8_t speed = MG_PHY_SPEED_10M;
bool up = bsr & MG_PHYREGBIT_BSR_LINK_STATUS ? 1 : 0; bool full_duplex = false;
struct mg_phy phy = {eth_read_phy, eth_write_phy};
up = mg_phy_up(&phy, 0, &full_duplex, &speed);
// If PHY is ready, update NCFGR accordingly // If PHY is ready, update NCFGR accordingly
if (ifp->state == MG_TCPIP_STATE_DOWN && up) { if (ifp->state == MG_TCPIP_STATE_DOWN && up) {
uint16_t bcr = eth_read_phy(MG_PHY_ADDR, MG_PHYREG_BCR); GMAC_REGS->GMAC_NCFGR =
bool fd = bcr & MG_PHYREGBIT_BCR_DUPLEX_MODE ? 1 : 0; (GMAC_REGS->GMAC_NCFGR & ~(MG_BIT(0) | MG_BIT(1))) | (speed & 1) |
bool spd = bcr & MG_PHYREGBIT_BCR_SPEED ? 1 : 0; (full_duplex << 1);
GMAC_REGS->GMAC_NCFGR = (GMAC_REGS->GMAC_NCFGR &
~(GMAC_NCFGR_SPD_Msk | MG_PHYREGBIT_BCR_SPEED)) |
GMAC_NCFGR_SPD(spd) | GMAC_NCFGR_FD(fd);
} }
} }
return false; return up;
} }
void GMAC_Handler(void); void GMAC_Handler(void);
@@ -203,8 +223,8 @@ void GMAC_Handler(void) {
uint32_t isr = GMAC_REGS->GMAC_ISR; uint32_t isr = GMAC_REGS->GMAC_ISR;
uint32_t rsr = GMAC_REGS->GMAC_RSR; uint32_t rsr = GMAC_REGS->GMAC_RSR;
uint32_t tsr = GMAC_REGS->GMAC_TSR; uint32_t tsr = GMAC_REGS->GMAC_TSR;
if (isr & GMAC_ISR_RCOMP_Msk) { if (isr & MG_BIT(1)) {
if (rsr & GMAC_ISR_RCOMP_Msk) { if (rsr & MG_BIT(1)) {
for (uint8_t i = 0; i < ETH_DESC_CNT; i++) { for (uint8_t i = 0; i < ETH_DESC_CNT; i++) {
if ((s_rxdesc[s_rxno][0] & MG_BIT(0)) == 0) break; if ((s_rxdesc[s_rxno][0] & MG_BIT(0)) == 0) break;
size_t len = s_rxdesc[s_rxno][1] & (MG_BIT(13) - 1); size_t len = s_rxdesc[s_rxno][1] & (MG_BIT(13) - 1);
@@ -215,9 +235,7 @@ void GMAC_Handler(void) {
} }
} }
if ((tsr & (GMAC_TSR_HRESP_Msk | GMAC_TSR_UND_Msk | GMAC_TSR_TXCOMP_Msk | if (tsr != 0) {
GMAC_TSR_TFC_Msk | GMAC_TSR_TXGO_Msk | GMAC_TSR_RLE_Msk |
GMAC_TSR_COL_Msk | GMAC_TSR_UBR_Msk)) != 0) {
// MG_INFO((" --> %#x %#x", s_txdesc[s_txno][1], tsr)); // MG_INFO((" --> %#x %#x", s_txdesc[s_txno][1], tsr));
if (!(s_txdesc[s_txno][1] & MG_BIT(31))) s_txdesc[s_txno][1] |= MG_BIT(31); if (!(s_txdesc[s_txno][1] & MG_BIT(31))) s_txdesc[s_txno][1] |= MG_BIT(31);
} }
+27 -5
View File
@@ -1,13 +1,35 @@
#pragma once #pragma once
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_SAME54) && MG_ENABLE_DRIVER_SAME54 #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_SAME54) && \
MG_ENABLE_DRIVER_SAME54
struct mg_tcpip_driver_same54_data {
int mdc_cr;
};
#ifndef MG_DRIVER_MDC_CR #ifndef MG_DRIVER_MDC_CR
#define MG_DRIVER_MDC_CR 5 #define MG_DRIVER_MDC_CR 5
#endif #endif
#ifndef MG_DRIVER_PHY_ADDR
#define MG_DRIVER_PHY_ADDR 0
#endif
struct mg_tcpip_driver_same54_data {
int mdc_cr;
uint8_t phy_addr;
};
#define MG_TCPIP_DRIVER_INIT(mgr) \
do { \
static struct mg_tcpip_driver_same54_data driver_data_; \
static struct mg_tcpip_if mif_; \
driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \
driver_data_.phy_addr = MG_DRIVER_PHY_ADDR; \
mif_.ip = MG_TCPIP_IP; \
mif_.mask = MG_TCPIP_MASK; \
mif_.gw = MG_TCPIP_GW; \
mif_.driver = &mg_tcpip_driver_same54; \
mif_.driver_data = &driver_data_; \
MG_SET_MAC_ADDRESS(mif_.mac); \
mg_tcpip_init(mgr, &mif_); \
MG_INFO(("Driver: same54, MAC: %M", mg_print_mac, mif_.mac)); \
} while (0)
#endif #endif
+169
View File
@@ -0,0 +1,169 @@
#include "sdio.h"
#if MG_ENABLE_TCPIP && \
(defined(MG_ENABLE_DRIVER_CYW_SDIO) && MG_ENABLE_DRIVER_CYW_SDIO)
// SDIO 6.9 Table 6-1 CCCR (Common Card Control Registers)
#define MG_SDIO_CCCR_SDIOREV 0x000
#define MG_SDIO_CCCR_SDREV 0x001
#define MG_SDIO_CCCR_IOEN 0x002
#define MG_SDIO_CCCR_IORDY 0x003
#define MG_SDIO_CCCR_INTEN 0x004
#define MG_SDIO_CCCR_BIC 0x007
#define MG_SDIO_CCCR_CCAP 0x008
#define MG_SDIO_CCCR_CCIS 0x009 // 3 registers
#define MG_SDIO_CCCR_F0BLKSZ 0x010 // 2 registers
#define MG_SDIO_CCCR_HISPD 0x013
// SDIO 6.10 Table 6-3 FBR (Function Basic Registers)
#define MG_SDIO_FBR_FnBLKSZ(n) (((n) &7) * 0x100 + 0x10) // 2 registers
// SDIO 5.1 IO_RW_DIRECT Command (CMD52)
#define MG_SDIO_DATA(x) ((x) &0xFF) // bits 0-7
#define MG_SDIO_ADDR(x) (((x) &0x1FFFF) << 9) // bits 9-25
#define MG_SDIO_FUNC(x) (((x) &3) << 28) // bits 28-30 (30 unused here)
#define MG_SDIO_WR MG_BIT(31)
// SDIO 5.3 IO_RW_EXTENDED Command (CMD53)
#define MG_SDIO_LEN(x) ((x) &0x1FF) // bits 0-8
#define MG_SDIO_OPINC MG_BIT(26)
#define MG_SDIO_BLKMODE MG_BIT(27)
// - Drivers set blocksize, drivers request transfers. Requesting a read
// transfer > blocksize means block transfer will be used.
// - To simplify the use of DMA transfers and avoid intermediate buffers,
// drivers must have room to accomodate a whole block transfer, e.g.: blocksize
// = 64, read 65 => 2 blocks = 128 bytes
// - Transfers of more than 1 byte assume (uint32_t *) data. 1-byte transfers
// use (uint8_t *) data
// - 'len' is the number of _bytes_ to transfer
bool mg_sdio_transfer(struct mg_tcpip_sdio *sdio, bool write, unsigned int f,
uint32_t addr, void *data, uint32_t len) {
uint32_t arg, val = 0;
unsigned int blksz = 64; // TODO(): mg_sdio_set_blksz() stores in an array,
// index on f, skip if 0
if (len == 1) {
arg = (write ? MG_SDIO_WR : 0) | MG_SDIO_FUNC(f) | MG_SDIO_ADDR(addr) |
(write ? MG_SDIO_DATA(*(uint8_t *) data) : 0);
bool res = sdio->txn(sdio, 52, arg, &val); // IO_RW_DIRECT
if (!write) *(uint8_t *) data = (uint8_t) val;
return res;
}
// IO_RW_EXTENDED
arg = (write ? MG_SDIO_WR : 0) | MG_SDIO_OPINC | MG_SDIO_FUNC(f) |
MG_SDIO_ADDR(addr);
if (len > 512 || (blksz != 0 && len > blksz)) { // SDIO 5.3 512 -> len=0
unsigned int blkcnt;
if (blksz == 0) return false; // > 512 requires block size set
blkcnt = (len + blksz - 1) / blksz;
if (blkcnt > 511) return false; // we don't support "infinite" blocks
arg |= MG_SDIO_BLKMODE | MG_SDIO_LEN(blkcnt); // block transfer
len = blksz * blkcnt;
} else {
arg |= MG_SDIO_LEN(len); // multi-byte transfer
}
return sdio->xfr(sdio, write, arg,
(arg & MG_SDIO_BLKMODE) ? (uint16_t) blksz : 0,
(uint32_t *) data, len, &val);
}
bool mg_sdio_set_blksz(struct mg_tcpip_sdio *sdio, unsigned int f,
uint16_t blksz) {
uint32_t val = blksz & 0xff;
if (!mg_sdio_transfer(sdio, true, 0, MG_SDIO_FBR_FnBLKSZ(f), &val, 1))
return false;
val = (blksz >> 8) & 0x0f; // SDIO 6.10 Table 6-4, max 2048
if (!mg_sdio_transfer(sdio, true, 0, MG_SDIO_FBR_FnBLKSZ(f) + 1, &val, 1))
return false;
// TODO(): store in an array, index on f. Static 8-element array
MG_VERBOSE(("F%c block size set", (f & 7) + '0'));
return true;
}
// Enable Fx
bool mg_sdio_enable_f(struct mg_tcpip_sdio *sdio, unsigned int f) {
uint8_t bit = 1U << (f & 7), bits;
uint32_t val = 0;
if (!mg_sdio_transfer(sdio, false, 0, MG_SDIO_CCCR_IOEN, &val, 1))
return false;
bits = (uint8_t) val | bit;
unsigned int times = 501;
while (times--) {
val = bits; /* IOEf */
;
if (!mg_sdio_transfer(sdio, true, 0, MG_SDIO_CCCR_IOEN, &val, 1))
return false;
mg_delayms(1);
val = 0;
if (!mg_sdio_transfer(sdio, false, 0, MG_SDIO_CCCR_IOEN, &val, 1))
return false;
if (val & bit) break;
}
if (times == (unsigned int) ~0) return false;
MG_VERBOSE(("F%c enabled", (f & 7) + '0'));
return true;
}
// Wait for Fx to be ready
bool mg_sdio_waitready_f(struct mg_tcpip_sdio *sdio, unsigned int f) {
uint8_t bit = 1U << (f & 7);
unsigned int times = 501;
while (times--) {
uint32_t val;
if (!mg_sdio_transfer(sdio, false, 0, MG_SDIO_CCCR_IORDY, &val, 1))
return false;
if (val & bit) break; // IORf
mg_delayms(1);
}
if (times == (unsigned int) ~0) return false;
MG_VERBOSE(("F%c ready", (f & 7) + '0'));
return true;
}
// SDIO 6.14 Bus State Diagram
bool mg_sdio_init(struct mg_tcpip_sdio *sdio) {
uint32_t val = 0;
if (!sdio->txn(sdio, 0, 0, NULL)) return false; // GO_IDLE_STATE
sdio->txn(sdio, 5, 0, &val); // IO_SEND_OP_COND, no CRC
MG_VERBOSE(("IO Functions: %u, Memory: %c", 1 + ((val >> 28) & 7),
(val & MG_BIT(27)) ? 'Y' : 'N'));
if (!sdio->txn(sdio, 3, 0, &val)) return false; // SEND_RELATIVE_ADDR
val = ((uint32_t) val) >> 16; // RCA
if (!sdio->txn(sdio, 7, val << 16, &val))
return false; // SELECT/DESELECT_CARD
mg_sdio_transfer(sdio, false, 0, MG_SDIO_CCCR_SDIOREV, &val, 1);
MG_DEBUG(("CCCR: %u.%u, SDIO: %u.%u", 1 + ((val >> 2) & 3), (val >> 0) & 3,
1 + ((val >> 6) & 3), (val >> 4) & 3));
mg_sdio_transfer(sdio, false, 0, MG_SDIO_CCCR_SDREV, &val, 1);
MG_VERBOSE(("SD: %u.%u", 1 + ((val >> 2) & 3), (val >> 0) & 3));
mg_sdio_transfer(sdio, false, 0, MG_SDIO_CCCR_BIC, &val, 1);
MG_SET_BITS(val, 3,
MG_BIT(7) | MG_BIT(1)); // SDIO 6.9 Tables 6-1 6-2, 4-bit bus
mg_sdio_transfer(sdio, true, 0, MG_SDIO_CCCR_BIC, &val, 1);
// All Full-Speed SDIO cards support a 4-bit bus. Skip for Low-Speed SDIO
// cards, we don't provide separate low-level functions for width and speed
sdio->cfg(sdio, 0); // set DS;
if (!mg_sdio_transfer(sdio, false, 0, MG_SDIO_CCCR_HISPD, &val, 1))
return false;
if (val & MG_BIT(0) /* SHS */) {
val = MG_BIT(1); /* EHS */
if (!mg_sdio_transfer(sdio, true, 0, MG_SDIO_CCCR_HISPD, &val, 1))
return false;
sdio->cfg(sdio, 1); // set HS;
MG_VERBOSE(("Bus set to 4-bit @50MHz"));
} else {
MG_VERBOSE(("Bus set to 4-bit @25MHz"));
}
return true;
}
// - 6.11 Card Information Structure (CIS): 0x0001000-0x017FF; for card common
// and all functions
// - 16.5 SDIO Card Metaformat
// - 16.7.2 CISTPL_FUNCE (0x22): Function Extension Tuple, provides standard
// information about the card (common) and each individual function. One
// CISTPL_FUNCE in each function’s CIS, immediately following the CISTPL_FUNCID
// tuple
// - 16.7.3 CISTPL_FUNCE Tuple for Function 0 (common)
// - 16.7.4 CISTPL_FUNCE Tuple for Function 1-7
#endif
+39
View File
@@ -0,0 +1,39 @@
#pragma once
#if MG_ENABLE_TCPIP && \
(defined(MG_ENABLE_DRIVER_CYW_SDIO) && MG_ENABLE_DRIVER_CYW_SDIO)
// Specific chip/card driver --> SDIO driver --> HAL --> SDIO hw controller
// API with HAL for hardware controller
// - Provide a function to init the controller (external)
// - Provide these functions:
struct mg_tcpip_sdio {
void *sdio; // Opaque SDIO bus descriptor
void (*cfg)(void *, uint8_t); // select operating parameters
// SDIO transaction: send cmd with a possible 1-byte read or write
bool (*txn)(void *, uint8_t cmd, uint32_t arg, uint32_t *r);
// SDIO extended transaction: write or read len bytes, using blksz blocks
bool (*xfr)(void *, bool write, uint32_t arg, uint16_t blksz, uint32_t *,
uint32_t len, uint32_t *r);
};
// API with driver (e.g.: cyw.c)
// Once the hardware controller has been initialized:
// - Init card: selects the card, sets F0 block size, sets bus width and speed
bool mg_sdio_init(struct mg_tcpip_sdio *sdio);
// - Enable other possible functions (F1 to F7)
bool mg_sdio_enable_f(struct mg_tcpip_sdio *sdio, unsigned int f);
// - Wait for them to be ready
bool mg_sdio_waitready_f(struct mg_tcpip_sdio *sdio, unsigned int f);
// - Set their transfer block length
bool mg_sdio_set_blksz(struct mg_tcpip_sdio *sdio, unsigned int f,
uint16_t blksz);
// - Transfer data to/from a function (abstracts from transaction type)
// - Requesting a read transfer > blocksize means block transfer will be used.
// - Drivers must have room to accomodate a whole block transfer, see sdio.c
// - Transfers of > 1 byte --> (uint32_t *) data. 1-byte --> (uint8_t *) data
bool mg_sdio_transfer(struct mg_tcpip_sdio *sdio, bool write, unsigned int f,
uint32_t addr, void *data, uint32_t len);
#endif
+7
View File
@@ -28,6 +28,12 @@ struct mg_tcpip_driver_stm32f_data {
#define MG_DRIVER_MDC_CR 4 #define MG_DRIVER_MDC_CR 4
#endif #endif
#if MG_ARCH == MG_ARCH_CUBE
#define MG_ENABLE_ETH_IRQ() NVIC_EnableIRQ(ETH_IRQn)
#else
#define MG_ENABLE_ETH_IRQ()
#endif
#define MG_TCPIP_DRIVER_INIT(mgr) \ #define MG_TCPIP_DRIVER_INIT(mgr) \
do { \ do { \
static struct mg_tcpip_driver_stm32f_data driver_data_; \ static struct mg_tcpip_driver_stm32f_data driver_data_; \
@@ -40,6 +46,7 @@ struct mg_tcpip_driver_stm32f_data {
mif_.driver = &mg_tcpip_driver_stm32f; \ mif_.driver = &mg_tcpip_driver_stm32f; \
mif_.driver_data = &driver_data_; \ mif_.driver_data = &driver_data_; \
MG_SET_MAC_ADDRESS(mif_.mac); \ MG_SET_MAC_ADDRESS(mif_.mac); \
MG_ENABLE_ETH_IRQ(); \
mg_tcpip_init(mgr, &mif_); \ mg_tcpip_init(mgr, &mif_); \
MG_INFO(("Driver: stm32f, MAC: %M", mg_print_mac, mif_.mac)); \ MG_INFO(("Driver: stm32f, MAC: %M", mg_print_mac, mif_.mac)); \
} while (0) } while (0)
+7
View File
@@ -40,6 +40,12 @@ struct mg_tcpip_driver_stm32h_data {
#define MG_DRIVER_MDC_CR 4 #define MG_DRIVER_MDC_CR 4
#endif #endif
#if MG_ENABLE_DRIVER_STM32H && MG_ARCH == MG_ARCH_CUBE
#define MG_ENABLE_ETH_IRQ() NVIC_EnableIRQ(ETH_IRQn)
#else
#define MG_ENABLE_ETH_IRQ()
#endif
#define MG_TCPIP_DRIVER_INIT(mgr) \ #define MG_TCPIP_DRIVER_INIT(mgr) \
do { \ do { \
static struct mg_tcpip_driver_stm32h_data driver_data_; \ static struct mg_tcpip_driver_stm32h_data driver_data_; \
@@ -54,6 +60,7 @@ struct mg_tcpip_driver_stm32h_data {
mif_.driver_data = &driver_data_; \ mif_.driver_data = &driver_data_; \
MG_SET_MAC_ADDRESS(mif_.mac); \ MG_SET_MAC_ADDRESS(mif_.mac); \
mg_tcpip_init(mgr, &mif_); \ mg_tcpip_init(mgr, &mif_); \
MG_ENABLE_ETH_IRQ(); \
MG_INFO(("Driver: stm32h, MAC: %M", mg_print_mac, mif_.mac)); \ MG_INFO(("Driver: stm32h, MAC: %M", mg_print_mac, mif_.mac)); \
} while (0) } while (0)
+7 -6
View File
@@ -1,14 +1,15 @@
#include "fs.h" #include "fs.h"
#include "printf.h" #include "printf.h"
#include "str.h" #include "str.h"
#include "util.h"
struct mg_fd *mg_fs_open(struct mg_fs *fs, const char *path, int flags) { struct mg_fd *mg_fs_open(struct mg_fs *fs, const char *path, int flags) {
struct mg_fd *fd = (struct mg_fd *) calloc(1, sizeof(*fd)); struct mg_fd *fd = (struct mg_fd *) mg_calloc(1, sizeof(*fd));
if (fd != NULL) { if (fd != NULL) {
fd->fd = fs->op(path, flags); fd->fd = fs->op(path, flags);
fd->fs = fs; fd->fs = fs;
if (fd->fd == NULL) { if (fd->fd == NULL) {
free(fd); mg_free(fd);
fd = NULL; fd = NULL;
} }
} }
@@ -18,7 +19,7 @@ struct mg_fd *mg_fs_open(struct mg_fs *fs, const char *path, int flags) {
void mg_fs_close(struct mg_fd *fd) { void mg_fs_close(struct mg_fd *fd) {
if (fd != NULL) { if (fd != NULL) {
fd->fs->cl(fd->fd); fd->fs->cl(fd->fd);
free(fd); mg_free(fd);
} }
} }
@@ -27,10 +28,10 @@ struct mg_str mg_file_read(struct mg_fs *fs, const char *path) {
void *fp; void *fp;
fs->st(path, &result.len, NULL); fs->st(path, &result.len, NULL);
if ((fp = fs->op(path, MG_FS_READ)) != NULL) { if ((fp = fs->op(path, MG_FS_READ)) != NULL) {
result.buf = (char *) calloc(1, result.len + 1); result.buf = (char *) mg_calloc(1, result.len + 1);
if (result.buf != NULL && if (result.buf != NULL &&
fs->rd(fp, (void *) result.buf, result.len) != result.len) { fs->rd(fp, (void *) result.buf, result.len) != result.len) {
free((void *) result.buf); mg_free((void *) result.buf);
result.buf = NULL; result.buf = NULL;
} }
fs->cl(fp); fs->cl(fp);
@@ -66,7 +67,7 @@ bool mg_file_printf(struct mg_fs *fs, const char *path, const char *fmt, ...) {
data = mg_vmprintf(fmt, &ap); data = mg_vmprintf(fmt, &ap);
va_end(ap); va_end(ap);
result = mg_file_write(fs, path, data, strlen(data)); result = mg_file_write(fs, path, data, strlen(data));
free(data); mg_free(data);
return result; return result;
} }
+2 -2
View File
@@ -74,7 +74,7 @@ static void *ff_open(const char *path, int flags) {
if (flags & MG_FS_WRITE) mode |= FA_WRITE | FA_OPEN_ALWAYS | FA_OPEN_APPEND; if (flags & MG_FS_WRITE) mode |= FA_WRITE | FA_OPEN_ALWAYS | FA_OPEN_APPEND;
if (f_open(&f, path, mode) == 0) { if (f_open(&f, path, mode) == 0) {
FIL *fp; FIL *fp;
if ((fp = calloc(1, sizeof(*fp))) != NULL) { if ((fp = mg_calloc(1, sizeof(*fp))) != NULL) {
memcpy(fp, &f, sizeof(*fp)); memcpy(fp, &f, sizeof(*fp));
return fp; return fp;
} }
@@ -85,7 +85,7 @@ static void *ff_open(const char *path, int flags) {
static void ff_close(void *fp) { static void ff_close(void *fp) {
if (fp != NULL) { if (fp != NULL) {
f_close((FIL *) fp); f_close((FIL *) fp);
free(fp); mg_free(fp);
} }
} }
+3 -2
View File
@@ -1,6 +1,7 @@
#include "fs.h" #include "fs.h"
#include "printf.h" #include "printf.h"
#include "str.h" #include "str.h"
#include "util.h"
struct packed_file { struct packed_file {
const char *data; const char *data;
@@ -72,7 +73,7 @@ static void *packed_open(const char *path, int flags) {
struct packed_file *fp = NULL; struct packed_file *fp = NULL;
if (data == NULL) return NULL; if (data == NULL) return NULL;
if (flags & MG_FS_WRITE) return NULL; if (flags & MG_FS_WRITE) return NULL;
if ((fp = (struct packed_file *) calloc(1, sizeof(*fp))) != NULL) { if ((fp = (struct packed_file *) mg_calloc(1, sizeof(*fp))) != NULL) {
fp->size = size; fp->size = size;
fp->data = data; fp->data = data;
} }
@@ -80,7 +81,7 @@ static void *packed_open(const char *path, int flags) {
} }
static void packed_close(void *fp) { static void packed_close(void *fp) {
if (fp != NULL) free(fp); if (fp != NULL) mg_free(fp);
} }
static size_t packed_read(void *fd, void *buf, size_t len) { static size_t packed_read(void *fd, void *buf, size_t len) {
+3 -3
View File
@@ -99,7 +99,7 @@ DIR *opendir(const char *name) {
if (name == NULL) { if (name == NULL) {
SetLastError(ERROR_BAD_ARGUMENTS); SetLastError(ERROR_BAD_ARGUMENTS);
} else if ((d = (DIR *) calloc(1, sizeof(*d))) == NULL) { } else if ((d = (DIR *) mg_calloc(1, sizeof(*d))) == NULL) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY); SetLastError(ERROR_NOT_ENOUGH_MEMORY);
} else { } else {
to_wchar(name, wpath, sizeof(wpath) / sizeof(wpath[0])); to_wchar(name, wpath, sizeof(wpath) / sizeof(wpath[0]));
@@ -109,7 +109,7 @@ DIR *opendir(const char *name) {
d->handle = FindFirstFileW(wpath, &d->info); d->handle = FindFirstFileW(wpath, &d->info);
d->result.d_name[0] = '\0'; d->result.d_name[0] = '\0';
} else { } else {
free(d); mg_free(d);
d = NULL; d = NULL;
} }
} }
@@ -121,7 +121,7 @@ int closedir(DIR *d) {
if (d != NULL) { if (d != NULL) {
if (d->handle != INVALID_HANDLE_VALUE) if (d->handle != INVALID_HANDLE_VALUE)
result = FindClose(d->handle) ? 0 : -1; result = FindClose(d->handle) ? 0 : -1;
free(d); mg_free(d);
} else { } else {
result = -1; result = -1;
SetLastError(ERROR_BAD_ARGUMENTS); SetLastError(ERROR_BAD_ARGUMENTS);
+16 -47
View File
@@ -216,7 +216,7 @@ static bool vcb(uint8_t c) {
static size_t clen(const char *s, const char *end) { static size_t clen(const char *s, const char *end) {
const unsigned char *u = (unsigned char *) s, c = *u; const unsigned char *u = (unsigned char *) s, c = *u;
long n = (long) (end - s); long n = (long) (end - s);
if (c > ' ' && c < '~') return 1; // Usual ascii printed char if (c > ' ' && c <= '~') return 1; // Usual ascii printed char
if ((c & 0xe0) == 0xc0 && n > 1 && vcb(u[1])) return 2; // 2-byte UTF8 if ((c & 0xe0) == 0xc0 && n > 1 && vcb(u[1])) return 2; // 2-byte UTF8
if ((c & 0xf0) == 0xe0 && n > 2 && vcb(u[1]) && vcb(u[2])) return 3; if ((c & 0xf0) == 0xe0 && n > 2 && vcb(u[1]) && vcb(u[2])) return 3;
if ((c & 0xf8) == 0xf0 && n > 3 && vcb(u[1]) && vcb(u[2]) && vcb(u[3])) if ((c & 0xf8) == 0xf0 && n > 3 && vcb(u[1]) && vcb(u[2]) && vcb(u[3]))
@@ -280,17 +280,17 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) {
hm->uri.buf = (char *) s; hm->uri.buf = (char *) s;
while (s < end && (n = clen(s, end)) > 0) s += n, hm->uri.len += n; while (s < end && (n = clen(s, end)) > 0) s += n, hm->uri.len += n;
while (s < end && s[0] == ' ') s++; // Skip spaces while (s < end && s[0] == ' ') s++; // Skip spaces
is_response = hm->method.len > 5 && is_response =
(mg_ncasecmp(hm->method.buf, "HTTP/", 5) == 0); hm->method.len > 5 && (mg_ncasecmp(hm->method.buf, "HTTP/", 5) == 0);
if ((s = skiptorn(s, end, &hm->proto)) == NULL) return false; if ((s = skiptorn(s, end, &hm->proto)) == NULL) return false;
// If we're given a version, check that it is HTTP/x.x // If we're given a version, check that it is HTTP/x.x
version_prefix_valid = hm->proto.len > 5 && version_prefix_valid =
(mg_ncasecmp(hm->proto.buf, "HTTP/", 5) == 0); hm->proto.len > 5 && (mg_ncasecmp(hm->proto.buf, "HTTP/", 5) == 0);
if (!is_response && hm->proto.len > 0 && if (!is_response && hm->proto.len > 0 &&
(!version_prefix_valid || hm->proto.len != 8 || (!version_prefix_valid || hm->proto.len != 8 ||
(hm->proto.buf[5] < '0' || hm->proto.buf[5] > '9') || (hm->proto.buf[5] < '0' || hm->proto.buf[5] > '9') ||
(hm->proto.buf[6] != '.') || (hm->proto.buf[6] != '.') ||
(hm->proto.buf[7] < '0' || hm->proto.buf[7] > '9'))) { (hm->proto.buf[7] < '0' || hm->proto.buf[7] > '9'))) {
return -1; return -1;
} }
@@ -589,13 +589,11 @@ void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm,
// If a browser sends us "Accept-Encoding: gzip", try to open .gz first // If a browser sends us "Accept-Encoding: gzip", try to open .gz first
struct mg_str *ae = mg_http_get_header(hm, "Accept-Encoding"); struct mg_str *ae = mg_http_get_header(hm, "Accept-Encoding");
if (ae != NULL) { if (ae != NULL) {
char *ae_ = mg_mprintf("%.*s", ae->len, ae->buf); if (mg_match(*ae, mg_str("*gzip*"), NULL)) {
if (ae_ != NULL && strstr(ae_, "gzip") != NULL) {
mg_snprintf(tmp, sizeof(tmp), "%s.gz", path); mg_snprintf(tmp, sizeof(tmp), "%s.gz", path);
fd = mg_fs_open(fs, tmp, MG_FS_READ); fd = mg_fs_open(fs, tmp, MG_FS_READ);
if (fd != NULL) gzip = true, path = tmp; if (fd != NULL) gzip = true, path = tmp;
} }
free(ae_);
} }
// No luck opening .gz? Open what we've told to open // No luck opening .gz? Open what we've told to open
if (fd == NULL) fd = mg_fs_open(fs, path, MG_FS_READ); if (fd == NULL) fd = mg_fs_open(fs, path, MG_FS_READ);
@@ -686,7 +684,7 @@ static void printdirentry(const char *name, void *userdata) {
sizeof(path)) { sizeof(path)) {
MG_ERROR(("%s truncated", name)); MG_ERROR(("%s truncated", name));
} else if ((flags = fs->st(path, &size, &t)) == 0) { } else if ((flags = fs->st(path, &size, &t)) == 0) {
MG_ERROR(("%lu stat(%s): %d", d->c->id, path, errno)); MG_ERROR(("%lu stat(%s)", d->c->id, path));
} else { } else {
const char *slash = flags & MG_FS_DIR ? "/" : ""; const char *slash = flags & MG_FS_DIR ? "/" : "";
if (flags & MG_FS_DIR) { if (flags & MG_FS_DIR) {
@@ -977,7 +975,7 @@ long mg_http_upload(struct mg_connection *c, struct mg_http_message *hm,
mg_http_reply(c, 400, "", "%s: offset mismatch", path); mg_http_reply(c, 400, "", "%s: offset mismatch", path);
res = -5; res = -5;
} else if ((fd = mg_fs_open(fs, path, MG_FS_WRITE)) == NULL) { } else if ((fd = mg_fs_open(fs, path, MG_FS_WRITE)) == NULL) {
mg_http_reply(c, 400, "", "open(%s): %d", path, errno); mg_http_reply(c, 400, "", "open(%s)", path);
res = -6; res = -6;
} else { } else {
res = offset + (long) fs->wr(fd->fd, hm->body.buf, hm->body.len); res = offset + (long) fs->wr(fd->fd, hm->body.buf, hm->body.len);
@@ -1042,7 +1040,7 @@ static void http_cb(struct mg_connection *c, int ev, void *ev_data) {
c->pfn = NULL; c->pfn = NULL;
return; return;
} }
if (ev == MG_EV_CLOSE) { // If client did not set Content-Length if (ev == MG_EV_CLOSE) { // If client did not set Content-Length
hm.message.len = c->recv.len - ofs; // and closes now, deliver MSG hm.message.len = c->recv.len - ofs; // and closes now, deliver MSG
hm.body.len = hm.message.len - (size_t) (hm.body.buf - hm.message.buf); hm.body.len = hm.message.len - (size_t) (hm.body.buf - hm.message.buf);
} }
@@ -1073,7 +1071,8 @@ static void http_cb(struct mg_connection *c, int ev, void *ev_data) {
} }
if (require_content_len) { if (require_content_len) {
if (!c->is_client) mg_http_reply(c, 411, "", ""); if (!c->is_client) mg_http_reply(c, 411, "", "");
MG_ERROR(("Content length missing from %s", is_response ? "response" : "request")); MG_ERROR(("Content length missing from %s",
is_response ? "response" : "request"));
} }
} }
@@ -1120,39 +1119,9 @@ static void http_cb(struct mg_connection *c, int ev, void *ev_data) {
(void) ev_data; (void) ev_data;
} }
static void mg_hfn(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/quit"), NULL)) {
mg_http_reply(c, 200, "", "ok\n");
c->is_draining = 1;
c->data[0] = 'X';
} else if (mg_match(hm->uri, mg_str("/debug"), NULL)) {
int level = (int) mg_json_get_long(hm->body, "$.level", MG_LL_DEBUG);
mg_log_set(level);
mg_http_reply(c, 200, "", "Debug level set to %d\n", level);
} else {
mg_http_reply(c, 200, "", "hi\n");
}
} else if (ev == MG_EV_CLOSE) {
if (c->data[0] == 'X') *(bool *) c->fn_data = true;
}
}
void mg_hello(const char *url) {
struct mg_mgr mgr;
bool done = false;
mg_mgr_init(&mgr);
if (mg_http_listen(&mgr, url, mg_hfn, &done) == NULL) done = true;
while (done == false) mg_mgr_poll(&mgr, 100);
mg_mgr_free(&mgr);
}
struct mg_connection *mg_http_connect(struct mg_mgr *mgr, const char *url, struct mg_connection *mg_http_connect(struct mg_mgr *mgr, const char *url,
mg_event_handler_t fn, void *fn_data) { mg_event_handler_t fn, void *fn_data) {
struct mg_connection *c = mg_connect(mgr, url, fn, fn_data); return mg_connect_svc(mgr, url, fn, fn_data, http_cb, NULL);
if (c != NULL) c->pfn = http_cb;
return c;
} }
struct mg_connection *mg_http_listen(struct mg_mgr *mgr, const char *url, struct mg_connection *mg_http_listen(struct mg_mgr *mgr, const char *url,
-1
View File
@@ -63,4 +63,3 @@ void mg_http_bauth(struct mg_connection *, const char *user, const char *pass);
struct mg_str mg_http_get_header_var(struct mg_str s, struct mg_str v); struct mg_str mg_http_get_header_var(struct mg_str s, struct mg_str v);
size_t mg_http_next_multipart(struct mg_str, size_t, struct mg_http_part *); size_t mg_http_next_multipart(struct mg_str, size_t, struct mg_http_part *);
int mg_http_status(const struct mg_http_message *hm); int mg_http_status(const struct mg_http_message *hm);
void mg_hello(const char *url);
+4 -5
View File
@@ -12,18 +12,17 @@ int mg_iobuf_resize(struct mg_iobuf *io, size_t new_size) {
new_size = roundup(new_size, io->align); new_size = roundup(new_size, io->align);
if (new_size == 0) { if (new_size == 0) {
mg_bzero(io->buf, io->size); mg_bzero(io->buf, io->size);
free(io->buf); mg_free(io->buf);
io->buf = NULL; io->buf = NULL;
io->len = io->size = 0; io->len = io->size = 0;
} else if (new_size != io->size) { } else if (new_size != io->size) {
// NOTE(lsm): do not use realloc here. Use calloc/free only, to ease the // NOTE(lsm): do not use realloc here. Use mg_calloc/mg_free only
// porting to some obscure platforms like FreeRTOS void *p = mg_calloc(1, new_size);
void *p = calloc(1, new_size);
if (p != NULL) { if (p != NULL) {
size_t len = new_size < io->len ? new_size : io->len; size_t len = new_size < io->len ? new_size : io->len;
if (len > 0 && io->buf != NULL) memmove(p, io->buf, len); if (len > 0 && io->buf != NULL) memmove(p, io->buf, len);
mg_bzero(io->buf, io->size); mg_bzero(io->buf, io->size);
free(io->buf); mg_free(io->buf);
io->buf = (unsigned char *) p; io->buf = (unsigned char *) p;
io->size = new_size; io->size = new_size;
} else { } else {
+5 -4
View File
@@ -1,6 +1,7 @@
#include "json.h" #include "json.h"
#include "base64.h" #include "base64.h"
#include "fmt.h" #include "fmt.h"
#include "util.h"
static const char *escapeseq(int esc) { static const char *escapeseq(int esc) {
return esc ? "\b\f\n\r\t\\\"" : "bfnrt\\\""; return esc ? "\b\f\n\r\t\\\"" : "bfnrt\\\"";
@@ -320,10 +321,10 @@ char *mg_json_get_str(struct mg_str json, const char *path) {
char *result = NULL; char *result = NULL;
int len = 0, off = mg_json_get(json, path, &len); int len = 0, off = mg_json_get(json, path, &len);
if (off >= 0 && len > 1 && json.buf[off] == '"') { if (off >= 0 && len > 1 && json.buf[off] == '"') {
if ((result = (char *) calloc(1, (size_t) len)) != NULL && if ((result = (char *) mg_calloc(1, (size_t) len)) != NULL &&
!mg_json_unescape(mg_str_n(json.buf + off + 1, (size_t) (len - 2)), !mg_json_unescape(mg_str_n(json.buf + off + 1, (size_t) (len - 2)),
result, (size_t) len)) { result, (size_t) len)) {
free(result); mg_free(result);
result = NULL; result = NULL;
} }
} }
@@ -334,7 +335,7 @@ char *mg_json_get_b64(struct mg_str json, const char *path, int *slen) {
char *result = NULL; char *result = NULL;
int len = 0, off = mg_json_get(json, path, &len); int len = 0, off = mg_json_get(json, path, &len);
if (off >= 0 && json.buf[off] == '"' && len > 1 && if (off >= 0 && json.buf[off] == '"' && len > 1 &&
(result = (char *) calloc(1, (size_t) len)) != NULL) { (result = (char *) mg_calloc(1, (size_t) len)) != NULL) {
size_t k = mg_base64_decode(json.buf + off + 1, (size_t) (len - 2), result, size_t k = mg_base64_decode(json.buf + off + 1, (size_t) (len - 2), result,
(size_t) len); (size_t) len);
if (slen != NULL) *slen = (int) k; if (slen != NULL) *slen = (int) k;
@@ -346,7 +347,7 @@ char *mg_json_get_hex(struct mg_str json, const char *path, int *slen) {
char *result = NULL; char *result = NULL;
int len = 0, off = mg_json_get(json, path, &len); int len = 0, off = mg_json_get(json, path, &len);
if (off >= 0 && json.buf[off] == '"' && len > 1 && if (off >= 0 && json.buf[off] == '"' && len > 1 &&
(result = (char *) calloc(1, (size_t) len / 2)) != NULL) { (result = (char *) mg_calloc(1, (size_t) len / 2)) != NULL) {
int i; int i;
for (i = 0; i < len - 2; i += 2) { for (i = 0; i < len - 2; i += 2) {
mg_str_to_num(mg_str_n(json.buf + off + 1 + i, 2), 16, &result[i >> 1], mg_str_to_num(mg_str_n(json.buf + off + 1 + i, 2), 16, &result[i >> 1],
+1 -1
View File
@@ -3,7 +3,7 @@
#include "str.h" #include "str.h"
#include "util.h" #include "util.h"
int mg_log_level = MG_LL_INFO; int mg_log_level = MG_LL_DEBUG;
static mg_pfn_t s_log_func = mg_pfn_stdout; static mg_pfn_t s_log_func = mg_pfn_stdout;
static void *s_log_func_param = NULL; static void *s_log_func_param = NULL;
+1 -2
View File
@@ -529,12 +529,11 @@ void mg_mqtt_disconnect(struct mg_connection *c,
struct mg_connection *mg_mqtt_connect(struct mg_mgr *mgr, const char *url, struct mg_connection *mg_mqtt_connect(struct mg_mgr *mgr, const char *url,
const struct mg_mqtt_opts *opts, const struct mg_mqtt_opts *opts,
mg_event_handler_t fn, void *fn_data) { mg_event_handler_t fn, void *fn_data) {
struct mg_connection *c = mg_connect(mgr, url, fn, fn_data); struct mg_connection *c = mg_connect_svc(mgr, url, fn, fn_data, mqtt_cb, NULL);
if (c != NULL) { if (c != NULL) {
struct mg_mqtt_opts empty; struct mg_mqtt_opts empty;
memset(&empty, 0, sizeof(empty)); memset(&empty, 0, sizeof(empty));
mg_mqtt_login(c, opts == NULL ? &empty : opts); mg_mqtt_login(c, opts == NULL ? &empty : opts);
c->pfn = mqtt_cb;
} }
return c; return c;
} }
+29 -13
View File
@@ -1,7 +1,7 @@
#include "net.h"
#include "dns.h" #include "dns.h"
#include "fmt.h" #include "fmt.h"
#include "log.h" #include "log.h"
#include "net.h"
#include "printf.h" #include "printf.h"
#include "profile.h" #include "profile.h"
#include "timer.h" #include "timer.h"
@@ -126,7 +126,7 @@ bool mg_aton(struct mg_str str, struct mg_addr *addr) {
struct mg_connection *mg_alloc_conn(struct mg_mgr *mgr) { struct mg_connection *mg_alloc_conn(struct mg_mgr *mgr) {
struct mg_connection *c = struct mg_connection *c =
(struct mg_connection *) calloc(1, sizeof(*c) + mgr->extraconnsize); (struct mg_connection *) mg_calloc(1, sizeof(*c) + mgr->extraconnsize);
if (c != NULL) { if (c != NULL) {
c->mgr = mgr; c->mgr = mgr;
c->send.align = c->recv.align = c->rtls.align = MG_IO_SIZE; c->send.align = c->recv.align = c->rtls.align = MG_IO_SIZE;
@@ -153,11 +153,12 @@ void mg_close_conn(struct mg_connection *c) {
mg_iobuf_free(&c->send); mg_iobuf_free(&c->send);
mg_iobuf_free(&c->rtls); mg_iobuf_free(&c->rtls);
mg_bzero((unsigned char *) c, sizeof(*c)); mg_bzero((unsigned char *) c, sizeof(*c));
free(c); mg_free(c);
} }
struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *url, struct mg_connection *mg_connect_svc(struct mg_mgr *mgr, const char *url,
mg_event_handler_t fn, void *fn_data) { mg_event_handler_t fn, void *fn_data,
mg_event_handler_t pfn, void *pfn_data) {
struct mg_connection *c = NULL; struct mg_connection *c = NULL;
if (url == NULL || url[0] == '\0') { if (url == NULL || url[0] == '\0') {
MG_ERROR(("null url")); MG_ERROR(("null url"));
@@ -170,22 +171,30 @@ struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *url,
c->fn = fn; c->fn = fn;
c->is_client = true; c->is_client = true;
c->fn_data = fn_data; c->fn_data = fn_data;
MG_DEBUG(("%lu %ld %s", c->id, c->fd, url)); c->is_tls = (mg_url_is_ssl(url) != 0);
c->pfn = pfn;
c->pfn_data = pfn_data;
mg_call(c, MG_EV_OPEN, (void *) url); mg_call(c, MG_EV_OPEN, (void *) url);
MG_DEBUG(("%lu %ld %s", c->id, c->fd, url));
mg_resolve(c, url); mg_resolve(c, url);
} }
return c; return c;
} }
struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *url,
mg_event_handler_t fn, void *fn_data) {
return mg_connect_svc(mgr, url, fn, fn_data, NULL, NULL);
}
struct mg_connection *mg_listen(struct mg_mgr *mgr, const char *url, struct mg_connection *mg_listen(struct mg_mgr *mgr, const char *url,
mg_event_handler_t fn, void *fn_data) { mg_event_handler_t fn, void *fn_data) {
struct mg_connection *c = NULL; struct mg_connection *c = NULL;
if ((c = mg_alloc_conn(mgr)) == NULL) { if ((c = mg_alloc_conn(mgr)) == NULL) {
MG_ERROR(("OOM %s", url)); MG_ERROR(("OOM %s", url));
} else if (!mg_open_listener(c, url)) { } else if (!mg_open_listener(c, url)) {
MG_ERROR(("Failed: %s, errno %d", url, errno)); MG_ERROR(("Failed: %s", url));
MG_PROF_FREE(c); MG_PROF_FREE(c);
free(c); mg_free(c);
c = NULL; c = NULL;
} else { } else {
c->is_listening = 1; c->is_listening = 1;
@@ -193,8 +202,8 @@ struct mg_connection *mg_listen(struct mg_mgr *mgr, const char *url,
LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c); LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c);
c->fn = fn; c->fn = fn;
c->fn_data = fn_data; c->fn_data = fn_data;
c->is_tls = (mg_url_is_ssl(url) != 0);
mg_call(c, MG_EV_OPEN, NULL); mg_call(c, MG_EV_OPEN, NULL);
if (mg_url_is_ssl(url)) c->is_tls = 1; // Accepted connection must
MG_DEBUG(("%lu %ld %s", c->id, c->fd, url)); MG_DEBUG(("%lu %ld %s", c->id, c->fd, url));
} }
return c; return c;
@@ -216,9 +225,9 @@ struct mg_connection *mg_wrapfd(struct mg_mgr *mgr, int fd,
struct mg_timer *mg_timer_add(struct mg_mgr *mgr, uint64_t milliseconds, struct mg_timer *mg_timer_add(struct mg_mgr *mgr, uint64_t milliseconds,
unsigned flags, void (*fn)(void *), void *arg) { unsigned flags, void (*fn)(void *), void *arg) {
struct mg_timer *t = (struct mg_timer *) calloc(1, sizeof(*t)); struct mg_timer *t = (struct mg_timer *) mg_calloc(1, sizeof(*t));
if (t != NULL) { if (t != NULL) {
flags |= MG_TIMER_AUTODELETE; // We have calloc-ed it, so autodelete flags |= MG_TIMER_AUTODELETE; // We have alloc'ed it, so autodelete
mg_timer_init(&mgr->timers, t, milliseconds, flags, fn, arg); mg_timer_init(&mgr->timers, t, milliseconds, flags, fn, arg);
} }
return t; return t;
@@ -235,7 +244,7 @@ long mg_io_recv(struct mg_connection *c, void *buf, size_t len) {
void mg_mgr_free(struct mg_mgr *mgr) { void mg_mgr_free(struct mg_mgr *mgr) {
struct mg_connection *c; struct mg_connection *c;
struct mg_timer *tmp, *t = mgr->timers; struct mg_timer *tmp, *t = mgr->timers;
while (t != NULL) tmp = t->next, free(t), t = tmp; while (t != NULL) tmp = t->next, mg_free(t), t = tmp;
mgr->timers = NULL; // Important. Next call to poll won't touch timers mgr->timers = NULL; // Important. Next call to poll won't touch timers
for (c = mgr->conns; c != NULL; c = c->next) c->is_closing = 1; for (c = mgr->conns; c != NULL; c = c->next) c->is_closing = 1;
mg_mgr_poll(mgr, 0); mg_mgr_poll(mgr, 0);
@@ -266,7 +275,7 @@ void mg_mgr_init(struct mg_mgr *mgr) {
// clang-format on // clang-format on
#elif MG_ENABLE_FREERTOS_TCP #elif MG_ENABLE_FREERTOS_TCP
mgr->ss = FreeRTOS_CreateSocketSet(); mgr->ss = FreeRTOS_CreateSocketSet();
#elif defined(__unix) || defined(__unix__) || defined(__APPLE__) #elif MG_ARCH == MG_ARCH_UNIX
// Ignore SIGPIPE signal, so if client cancels the request, it // Ignore SIGPIPE signal, so if client cancels the request, it
// won't kill the whole process. // won't kill the whole process.
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
@@ -278,4 +287,11 @@ void mg_mgr_init(struct mg_mgr *mgr) {
mgr->dns4.url = "udp://8.8.8.8:53"; mgr->dns4.url = "udp://8.8.8.8:53";
mgr->dns6.url = "udp://[2001:4860:4860::8888]:53"; mgr->dns6.url = "udp://[2001:4860:4860::8888]:53";
mg_tls_ctx_init(mgr); mg_tls_ctx_init(mgr);
MG_DEBUG(("MG_IO_SIZE: %lu, TLS: %s", MG_IO_SIZE,
MG_TLS == MG_TLS_NONE ? "none"
: MG_TLS == MG_TLS_MBED ? "MbedTLS"
: MG_TLS == MG_TLS_OPENSSL ? "OpenSSL"
: MG_TLS == MG_TLS_BUILTIN ? "builtin"
: MG_TLS == MG_TLS_WOLFSSL ? "WolfSSL"
: "custom"));
} }
+3
View File
@@ -105,3 +105,6 @@ bool mg_wakeup(struct mg_mgr *, unsigned long id, const void *buf, size_t len);
bool mg_wakeup_init(struct mg_mgr *); bool mg_wakeup_init(struct mg_mgr *);
struct mg_timer *mg_timer_add(struct mg_mgr *mgr, uint64_t milliseconds, struct mg_timer *mg_timer_add(struct mg_mgr *mgr, uint64_t milliseconds,
unsigned flags, void (*fn)(void *), void *arg); unsigned flags, void (*fn)(void *), void *arg);
struct mg_connection *mg_connect_svc(struct mg_mgr *mgr, const char *url,
mg_event_handler_t fn, void *fn_data,
mg_event_handler_t pfn, void *pfn_data);
+95 -46
View File
@@ -161,7 +161,7 @@ static uint32_t csumup(uint32_t sum, const void *buf, size_t len) {
static uint16_t csumfin(uint32_t sum) { static uint16_t csumfin(uint32_t sum) {
while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16); while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16);
return mg_htons(~sum & 0xffff); return mg_htons((uint16_t) ((uint16_t) ~sum & 0xffff));
} }
static uint16_t ipcsum(const void *buf, size_t len) { static uint16_t ipcsum(const void *buf, size_t len) {
@@ -177,7 +177,7 @@ static void settmout(struct mg_connection *c, uint8_t type) {
: type == MIP_TTYPE_SYN ? MIP_TCP_SYN_MS : type == MIP_TTYPE_SYN ? MIP_TCP_SYN_MS
: type == MIP_TTYPE_FIN ? MIP_TCP_FIN_MS : type == MIP_TTYPE_FIN ? MIP_TCP_FIN_MS
: MIP_TCP_KEEPALIVE_MS; : MIP_TCP_KEEPALIVE_MS;
if (s->ttype == MIP_TTYPE_FIN) return; // skip if 3-way closing if (s->ttype == MIP_TTYPE_FIN) return; // skip if 3-way closing
s->timer = ifp->now + n; s->timer = ifp->now + n;
s->ttype = type; s->ttype = type;
MG_VERBOSE(("%lu %d -> %llx", c->id, type, s->timer)); MG_VERBOSE(("%lu %d -> %llx", c->id, type, s->timer));
@@ -210,10 +210,8 @@ static void onstatechange(struct mg_tcpip_if *ifp) {
MG_INFO((" GW: %M", mg_print_ip4, &ifp->gw)); MG_INFO((" GW: %M", mg_print_ip4, &ifp->gw));
MG_INFO((" MAC: %M", mg_print_mac, &ifp->mac)); MG_INFO((" MAC: %M", mg_print_mac, &ifp->mac));
} else if (ifp->state == MG_TCPIP_STATE_IP) { } else if (ifp->state == MG_TCPIP_STATE_IP) {
MG_ERROR(("Got IP"));
mg_tcpip_arp_request(ifp, ifp->gw, NULL); // unsolicited GW ARP request mg_tcpip_arp_request(ifp, ifp->gw, NULL); // unsolicited GW ARP request
} else if (ifp->state == MG_TCPIP_STATE_UP) { } else if (ifp->state == MG_TCPIP_STATE_UP) {
MG_ERROR(("Link up"));
srand((unsigned int) mg_millis()); srand((unsigned int) mg_millis());
} else if (ifp->state == MG_TCPIP_STATE_DOWN) { } else if (ifp->state == MG_TCPIP_STATE_DOWN) {
MG_ERROR(("Link down")); MG_ERROR(("Link down"));
@@ -241,18 +239,20 @@ static struct ip *tx_ip(struct mg_tcpip_if *ifp, uint8_t *mac_dst,
return ip; return ip;
} }
static void tx_udp(struct mg_tcpip_if *ifp, uint8_t *mac_dst, uint32_t ip_src, static bool tx_udp(struct mg_tcpip_if *ifp, uint8_t *mac_dst, uint32_t ip_src,
uint16_t sport, uint32_t ip_dst, uint16_t dport, uint16_t sport, uint32_t ip_dst, uint16_t dport,
const void *buf, size_t len) { const void *buf, size_t len) {
struct ip *ip = struct ip *ip =
tx_ip(ifp, mac_dst, 17, ip_src, ip_dst, len + sizeof(struct udp)); tx_ip(ifp, mac_dst, 17, ip_src, ip_dst, len + sizeof(struct udp));
struct udp *udp = (struct udp *) (ip + 1); struct udp *udp = (struct udp *) (ip + 1);
size_t eth_len;
uint32_t cs;
// MG_DEBUG(("UDP XX LEN %d %d", (int) len, (int) ifp->tx.len)); // MG_DEBUG(("UDP XX LEN %d %d", (int) len, (int) ifp->tx.len));
udp->sport = sport; udp->sport = sport;
udp->dport = dport; udp->dport = dport;
udp->len = mg_htons((uint16_t) (sizeof(*udp) + len)); udp->len = mg_htons((uint16_t) (sizeof(*udp) + len));
udp->csum = 0; udp->csum = 0;
uint32_t cs = csumup(0, udp, sizeof(*udp)); cs = csumup(0, udp, sizeof(*udp));
cs = csumup(cs, buf, len); cs = csumup(cs, buf, len);
cs = csumup(cs, &ip->src, sizeof(ip->src)); cs = csumup(cs, &ip->src, sizeof(ip->src));
cs = csumup(cs, &ip->dst, sizeof(ip->dst)); cs = csumup(cs, &ip->dst, sizeof(ip->dst));
@@ -260,7 +260,8 @@ static void tx_udp(struct mg_tcpip_if *ifp, uint8_t *mac_dst, uint32_t ip_src,
udp->csum = csumfin(cs); udp->csum = csumfin(cs);
memmove(udp + 1, buf, len); memmove(udp + 1, buf, len);
// MG_DEBUG(("UDP LEN %d %d", (int) len, (int) ifp->frame_len)); // MG_DEBUG(("UDP LEN %d %d", (int) len, (int) ifp->frame_len));
ether_output(ifp, sizeof(struct eth) + sizeof(*ip) + sizeof(*udp) + len); eth_len = sizeof(struct eth) + sizeof(*ip) + sizeof(*udp) + len;
return (ether_output(ifp, eth_len) == eth_len);
} }
static void tx_dhcp(struct mg_tcpip_if *ifp, uint8_t *mac_dst, uint32_t ip_src, static void tx_dhcp(struct mg_tcpip_if *ifp, uint8_t *mac_dst, uint32_t ip_src,
@@ -335,7 +336,8 @@ static struct mg_connection *getpeer(struct mg_mgr *mgr, struct pkt *pkt,
break; break;
if (c->is_udp && pkt->udp && c->loc.port == pkt->udp->dport) break; if (c->is_udp && pkt->udp && c->loc.port == pkt->udp->dport) break;
if (!c->is_udp && pkt->tcp && c->loc.port == pkt->tcp->dport && if (!c->is_udp && pkt->tcp && c->loc.port == pkt->tcp->dport &&
lsn == c->is_listening && (lsn || c->rem.port == pkt->tcp->sport)) lsn == (bool) c->is_listening &&
(lsn || c->rem.port == pkt->tcp->sport))
break; break;
} }
return c; return c;
@@ -390,10 +392,12 @@ static void rx_icmp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
if (pkt->icmp->type == 8 && pkt->ip != NULL && pkt->ip->dst == ifp->ip) { if (pkt->icmp->type == 8 && pkt->ip != NULL && pkt->ip->dst == ifp->ip) {
size_t hlen = sizeof(struct eth) + sizeof(struct ip) + sizeof(struct icmp); size_t hlen = sizeof(struct eth) + sizeof(struct ip) + sizeof(struct icmp);
size_t space = ifp->tx.len - hlen, plen = pkt->pay.len; size_t space = ifp->tx.len - hlen, plen = pkt->pay.len;
struct ip *ip;
struct icmp *icmp;
if (plen > space) plen = space; if (plen > space) plen = space;
struct ip *ip = tx_ip(ifp, pkt->eth->src, 1, ifp->ip, pkt->ip->src, ip = tx_ip(ifp, pkt->eth->src, 1, ifp->ip, pkt->ip->src,
sizeof(struct icmp) + plen); sizeof(*icmp) + plen);
struct icmp *icmp = (struct icmp *) (ip + 1); icmp = (struct icmp *) (ip + 1);
memset(icmp, 0, sizeof(*icmp)); // Set csum to 0 memset(icmp, 0, sizeof(*icmp)); // Set csum to 0
memcpy(icmp + 1, pkt->pay.buf, plen); // Copy RX payload to TX memcpy(icmp + 1, pkt->pay.buf, plen); // Copy RX payload to TX
icmp->csum = ipcsum(icmp, sizeof(*icmp) + plen); icmp->csum = ipcsum(icmp, sizeof(*icmp) + plen);
@@ -401,6 +405,8 @@ static void rx_icmp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
} }
} }
static void setdns4(struct mg_tcpip_if *ifp, uint32_t *ip);
static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) {
uint32_t ip = 0, gw = 0, mask = 0, lease = 0, dns = 0, sntp = 0; uint32_t ip = 0, gw = 0, mask = 0, lease = 0, dns = 0, sntp = 0;
uint8_t msgtype = 0, state = ifp->state; uint8_t msgtype = 0, state = ifp->state;
@@ -440,17 +446,19 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) {
ifp->state = MG_TCPIP_STATE_REQ; // REQUESTING state ifp->state = MG_TCPIP_STATE_REQ; // REQUESTING state
} else if (msgtype == 5) { // DHCPACK } else if (msgtype == 5) { // DHCPACK
if (ifp->state == MG_TCPIP_STATE_REQ && ip && gw && lease) { // got an IP if (ifp->state == MG_TCPIP_STATE_REQ && ip && gw && lease) { // got an IP
uint64_t rand;
ifp->lease_expire = ifp->now + lease * 1000; ifp->lease_expire = ifp->now + lease * 1000;
MG_INFO(("Lease: %u sec (%lld)", lease, ifp->lease_expire / 1000)); MG_INFO(("Lease: %u sec (%lld)", lease, ifp->lease_expire / 1000));
// assume DHCP server = router until ARP resolves // assume DHCP server = router until ARP resolves
memcpy(ifp->gwmac, pkt->eth->src, sizeof(ifp->gwmac)); memcpy(ifp->gwmac, pkt->eth->src, sizeof(ifp->gwmac));
ifp->ip = ip, ifp->gw = gw, ifp->mask = mask; ifp->ip = ip, ifp->gw = gw, ifp->mask = mask;
ifp->state = MG_TCPIP_STATE_IP; // BOUND state ifp->state = MG_TCPIP_STATE_IP; // BOUND state
uint64_t rand;
mg_random(&rand, sizeof(rand)); mg_random(&rand, sizeof(rand));
srand((unsigned int) (rand + mg_millis())); srand((unsigned int) (rand + mg_millis()));
if (ifp->enable_req_dns && dns != 0) if (ifp->enable_req_dns && dns != 0) {
setdns4(ifp, &dns);
mg_tcpip_call(ifp, MG_TCPIP_EV_DHCP_DNS, &dns); mg_tcpip_call(ifp, MG_TCPIP_EV_DHCP_DNS, &dns);
}
if (ifp->enable_req_sntp && sntp != 0) if (ifp->enable_req_sntp && sntp != 0)
mg_tcpip_call(ifp, MG_TCPIP_EV_DHCP_SNTP, &sntp); mg_tcpip_call(ifp, MG_TCPIP_EV_DHCP_SNTP, &sntp);
} else if (ifp->state == MG_TCPIP_STATE_READY && ifp->ip == ip) { // renew } else if (ifp->state == MG_TCPIP_STATE_READY && ifp->ip == ip) { // renew
@@ -465,9 +473,9 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) {
static void rx_dhcp_server(struct mg_tcpip_if *ifp, struct pkt *pkt) { static void rx_dhcp_server(struct mg_tcpip_if *ifp, struct pkt *pkt) {
uint8_t op = 0, *p = pkt->dhcp->options, uint8_t op = 0, *p = pkt->dhcp->options,
*end = (uint8_t *) &pkt->raw.buf[pkt->raw.len]; *end = (uint8_t *) &pkt->raw.buf[pkt->raw.len];
if (end < (uint8_t *) (pkt->dhcp + 1)) return;
// struct dhcp *req = pkt->dhcp; // struct dhcp *req = pkt->dhcp;
struct dhcp res = {2, 1, 6, 0, 0, 0, 0, 0, 0, 0, 0, {0}, 0, {0}}; struct dhcp res = {2, 1, 6, 0, 0, 0, 0, 0, 0, 0, 0, {0}, 0, {0}};
if (end < (uint8_t *) (pkt->dhcp + 1)) return;
res.yiaddr = ifp->ip; res.yiaddr = ifp->ip;
((uint8_t *) (&res.yiaddr))[3]++; // Offer our IP + 1 ((uint8_t *) (&res.yiaddr))[3]++; // Offer our IP + 1
while (p + 1 < end && p[0] != 255) { // Parse options while (p + 1 < end && p[0] != 255) { // Parse options
@@ -506,9 +514,9 @@ static void rx_udp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
if (c == NULL) { if (c == NULL) {
// No UDP listener on this port. Should send ICMP, but keep silent. // No UDP listener on this port. Should send ICMP, but keep silent.
} else { } else {
struct connstate *s = (struct connstate *) (c + 1);
c->rem.port = pkt->udp->sport; c->rem.port = pkt->udp->sport;
memcpy(c->rem.ip, &pkt->ip->src, sizeof(uint32_t)); memcpy(c->rem.ip, &pkt->ip->src, sizeof(uint32_t));
struct connstate *s = (struct connstate *) (c + 1);
memcpy(s->mac, pkt->eth->src, sizeof(s->mac)); memcpy(s->mac, pkt->eth->src, sizeof(s->mac));
if (c->recv.len >= MG_MAX_RECV_SIZE) { if (c->recv.len >= MG_MAX_RECV_SIZE) {
mg_error(c, "max_recv_buf_size reached"); mg_error(c, "max_recv_buf_size reached");
@@ -529,9 +537,9 @@ static size_t tx_tcp(struct mg_tcpip_if *ifp, uint8_t *dst_mac, uint32_t dst_ip,
struct ip *ip; struct ip *ip;
struct tcp *tcp; struct tcp *tcp;
uint16_t opts[4 / 2]; uint16_t opts[4 / 2];
if (flags & TH_SYN) { // Send MSS, RFC-9293 3.7.1 if (flags & TH_SYN) { // Send MSS, RFC-9293 3.7.1
opts[0] = mg_htons(0x0204); // RFC-9293 3.2 opts[0] = mg_htons(0x0204); // RFC-9293 3.2
opts[1] = mg_htons(ifp->mtu - 40); // RFC-6691 opts[1] = mg_htons((uint16_t) (ifp->mtu - 40)); // RFC-6691
buf = opts; buf = opts;
len = sizeof(opts); len = sizeof(opts);
} }
@@ -547,15 +555,16 @@ static size_t tx_tcp(struct mg_tcpip_if *ifp, uint8_t *dst_mac, uint32_t dst_ip,
tcp->win = mg_htons(MIP_TCP_WIN); tcp->win = mg_htons(MIP_TCP_WIN);
tcp->off = (uint8_t) (sizeof(*tcp) / 4 << 4); tcp->off = (uint8_t) (sizeof(*tcp) / 4 << 4);
if (flags & TH_SYN) tcp->off += (uint8_t) (sizeof(opts) / 4 << 4); if (flags & TH_SYN) tcp->off += (uint8_t) (sizeof(opts) / 4 << 4);
{
uint32_t cs = 0; uint32_t cs = 0;
uint16_t n = (uint16_t) (sizeof(*tcp) + len); uint16_t n = (uint16_t) (sizeof(*tcp) + len);
uint8_t pseudo[] = {0, ip->proto, (uint8_t) (n >> 8), (uint8_t) (n & 255)}; uint8_t pseudo[] = {0, ip->proto, (uint8_t) (n >> 8), (uint8_t) (n & 255)};
cs = csumup(cs, tcp, n); cs = csumup(cs, tcp, n);
cs = csumup(cs, &ip->src, sizeof(ip->src)); cs = csumup(cs, &ip->src, sizeof(ip->src));
cs = csumup(cs, &ip->dst, sizeof(ip->dst)); cs = csumup(cs, &ip->dst, sizeof(ip->dst));
cs = csumup(cs, pseudo, sizeof(pseudo)); cs = csumup(cs, pseudo, sizeof(pseudo));
tcp->csum = csumfin(cs); tcp->csum = csumfin(cs);
}
MG_VERBOSE(("TCP %M:%hu -> %M:%hu fl %x len %u", mg_print_ip4, &ip->src, MG_VERBOSE(("TCP %M:%hu -> %M:%hu fl %x len %u", mg_print_ip4, &ip->src,
mg_ntohs(tcp->sport), mg_print_ip4, &ip->dst, mg_ntohs(tcp->sport), mg_print_ip4, &ip->dst,
mg_ntohs(tcp->dport), tcp->flags, len)); mg_ntohs(tcp->dport), tcp->flags, len));
@@ -575,12 +584,13 @@ static size_t tx_tcp_pkt(struct mg_tcpip_if *ifp, struct pkt *pkt,
static struct mg_connection *accept_conn(struct mg_connection *lsn, static struct mg_connection *accept_conn(struct mg_connection *lsn,
struct pkt *pkt) { struct pkt *pkt) {
struct mg_connection *c = mg_alloc_conn(lsn->mgr); struct mg_connection *c = mg_alloc_conn(lsn->mgr);
struct connstate *s;
if (c == NULL) { if (c == NULL) {
MG_ERROR(("OOM")); MG_ERROR(("OOM"));
return NULL; return NULL;
} }
struct connstate *s = (struct connstate *) (c + 1); s = (struct connstate *) (c + 1);
s->dmss = 1460; // TODO(scaprile): 536; // assume default, RFC-9293 3.7.1 s->dmss = 536; // assume default, RFC-9293 3.7.1
s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq); s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq);
memcpy(s->mac, pkt->eth->src, sizeof(s->mac)); memcpy(s->mac, pkt->eth->src, sizeof(s->mac));
settmout(c, MIP_TTYPE_KEEPALIVE); settmout(c, MIP_TTYPE_KEEPALIVE);
@@ -595,8 +605,10 @@ static struct mg_connection *accept_conn(struct mg_connection *lsn,
c->pfn_data = lsn->pfn_data; c->pfn_data = lsn->pfn_data;
c->fn = lsn->fn; c->fn = lsn->fn;
c->fn_data = lsn->fn_data; c->fn_data = lsn->fn_data;
c->is_tls = lsn->is_tls;
mg_call(c, MG_EV_OPEN, NULL); mg_call(c, MG_EV_OPEN, NULL);
mg_call(c, MG_EV_ACCEPT, NULL); mg_call(c, MG_EV_ACCEPT, NULL);
if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init()
return c; return c;
} }
@@ -633,7 +645,9 @@ long mg_io_send(struct mg_connection *c, const void *buf, size_t len) {
uint32_t dst_ip = *(uint32_t *) c->rem.ip; uint32_t dst_ip = *(uint32_t *) c->rem.ip;
len = trim_len(c, len); len = trim_len(c, len);
if (c->is_udp) { if (c->is_udp) {
tx_udp(ifp, s->mac, ifp->ip, c->loc.port, dst_ip, c->rem.port, buf, len); if (!tx_udp(ifp, s->mac, ifp->ip, c->loc.port, dst_ip, c->rem.port, buf,
len))
return MG_IO_WAIT;
} else { // TCP, cap to peer's MSS } else { // TCP, cap to peer's MSS
size_t sent; size_t sent;
if (len > s->dmss) len = s->dmss; // RFC-6691: reduce if sending opts if (len > s->dmss) len = s->dmss; // RFC-6691: reduce if sending opts
@@ -678,10 +692,16 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) {
uint32_t rem_ip; uint32_t rem_ip;
memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
if (pkt->tcp->flags & TH_FIN) { if (pkt->tcp->flags & TH_FIN) {
uint8_t flags = TH_ACK;
if (mg_ntohl(pkt->tcp->seq) != s->ack) {
MG_VERBOSE(("ignoring FIN, SEQ != ACK: %x %x", mg_ntohl(pkt->tcp->seq), s->ack));
tx_tcp(c->mgr->ifp, s->mac, rem_ip, TH_ACK, c->loc.port, c->rem.port,
mg_htonl(s->seq), mg_htonl(s->ack), "", 0);
return;
}
// If we initiated the closure, we reply with ACK upon receiving FIN // If we initiated the closure, we reply with ACK upon receiving FIN
// If we didn't initiate it, we reply with FIN as part of the normal TCP // If we didn't initiate it, we reply with FIN as part of the normal TCP
// closure process // closure process
uint8_t flags = TH_ACK;
s->ack = (uint32_t) (mg_htonl(pkt->tcp->seq) + pkt->pay.len + 1); s->ack = (uint32_t) (mg_htonl(pkt->tcp->seq) + pkt->pay.len + 1);
s->fin_rcvd = true; s->fin_rcvd = true;
if (c->is_draining && s->ttype == MIP_TTYPE_FIN) { if (c->is_draining && s->ttype == MIP_TTYPE_FIN) {
@@ -699,7 +719,13 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) {
tx_tcp(c->mgr->ifp, s->mac, rem_ip, flags, c->loc.port, c->rem.port, tx_tcp(c->mgr->ifp, s->mac, rem_ip, flags, c->loc.port, c->rem.port,
mg_htonl(s->seq), mg_htonl(s->ack), "", 0); mg_htonl(s->seq), mg_htonl(s->ack), "", 0);
if (pkt->pay.len == 0) return; // if no data, we're done if (pkt->pay.len == 0) return; // if no data, we're done
} else if (pkt->pay.len == 0) { // this is an ACK } else if (pkt->pay.len <= 1 && mg_ntohl(pkt->tcp->seq) == s->ack - 1) {
// Keep-Alive (RFC-9293 3.8.4, allow erroneous implementations)
MG_VERBOSE(("%lu keepalive ACK", c->id));
tx_tcp(c->mgr->ifp, s->mac, rem_ip, TH_ACK, c->loc.port, c->rem.port,
mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0);
return; // no data to process
} else if (pkt->pay.len == 0) { // this is an ACK
if (s->fin_rcvd && s->ttype == MIP_TTYPE_FIN) s->twclosure = true; if (s->fin_rcvd && s->ttype == MIP_TTYPE_FIN) s->twclosure = true;
return; // no data to process return; // no data to process
} else if (seq != s->ack) { } else if (seq != s->ack) {
@@ -784,6 +810,7 @@ static void rx_tcp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
settmout(c, MIP_TTYPE_KEEPALIVE); settmout(c, MIP_TTYPE_KEEPALIVE);
mg_call(c, MG_EV_CONNECT, NULL); // Let user know mg_call(c, MG_EV_CONNECT, NULL); // Let user know
if (c->is_tls_hs) mg_tls_handshake(c); if (c->is_tls_hs) mg_tls_handshake(c);
if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init()
} else if (c != NULL && c->is_connecting && pkt->tcp->flags != TH_ACK) { } else if (c != NULL && c->is_connecting && pkt->tcp->flags != TH_ACK) {
// mg_hexdump(pkt->raw.buf, pkt->raw.len); // mg_hexdump(pkt->raw.buf, pkt->raw.len);
tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0); tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0);
@@ -826,9 +853,10 @@ static void rx_tcp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
static void rx_ip(struct mg_tcpip_if *ifp, struct pkt *pkt) { static void rx_ip(struct mg_tcpip_if *ifp, struct pkt *pkt) {
uint16_t frag = mg_ntohs(pkt->ip->frag); uint16_t frag = mg_ntohs(pkt->ip->frag);
if (frag & IP_MORE_FRAGS_MSK || frag & IP_FRAG_OFFSET_MSK) { if (frag & IP_MORE_FRAGS_MSK || frag & IP_FRAG_OFFSET_MSK) {
struct mg_connection *c;
if (pkt->ip->proto == 17) pkt->udp = (struct udp *) (pkt->ip + 1); if (pkt->ip->proto == 17) pkt->udp = (struct udp *) (pkt->ip + 1);
if (pkt->ip->proto == 6) pkt->tcp = (struct tcp *) (pkt->ip + 1); if (pkt->ip->proto == 6) pkt->tcp = (struct tcp *) (pkt->ip + 1);
struct mg_connection *c = getpeer(ifp->mgr, pkt, false); c = getpeer(ifp->mgr, pkt, false);
if (c) mg_error(c, "Received fragmented packet"); if (c) mg_error(c, "Received fragmented packet");
} else if (pkt->ip->proto == 1) { } else if (pkt->ip->proto == 1) {
pkt->icmp = (struct icmp *) (pkt->ip + 1); pkt->icmp = (struct icmp *) (pkt->ip + 1);
@@ -854,11 +882,12 @@ static void rx_ip(struct mg_tcpip_if *ifp, struct pkt *pkt) {
rx_udp(ifp, pkt); rx_udp(ifp, pkt);
} }
} else if (pkt->ip->proto == 6) { } else if (pkt->ip->proto == 6) {
uint16_t iplen, off;
pkt->tcp = (struct tcp *) (pkt->ip + 1); pkt->tcp = (struct tcp *) (pkt->ip + 1);
if (pkt->pay.len < sizeof(*pkt->tcp)) return; if (pkt->pay.len < sizeof(*pkt->tcp)) return;
mkpay(pkt, pkt->tcp + 1); mkpay(pkt, pkt->tcp + 1);
uint16_t iplen = mg_ntohs(pkt->ip->len); iplen = mg_ntohs(pkt->ip->len);
uint16_t off = (uint16_t) (sizeof(*pkt->ip) + ((pkt->tcp->off >> 4) * 4U)); off = (uint16_t) (sizeof(*pkt->ip) + ((pkt->tcp->off >> 4) * 4U));
if (iplen >= off) pkt->pay.len = (size_t) (iplen - off); if (iplen >= off) pkt->pay.len = (size_t) (iplen - off);
MG_VERBOSE(("TCP %M:%hu -> %M:%hu len %u", mg_print_ip4, &pkt->ip->src, MG_VERBOSE(("TCP %M:%hu -> %M:%hu len %u", mg_print_ip4, &pkt->ip->src,
mg_ntohs(pkt->tcp->sport), mg_print_ip4, &pkt->ip->dst, mg_ntohs(pkt->tcp->sport), mg_print_ip4, &pkt->ip->dst,
@@ -896,8 +925,9 @@ static void mg_tcpip_rx(struct mg_tcpip_if *ifp, void *buf, size_t len) {
memcmp(pkt.eth->dst, broadcast, sizeof(pkt.eth->dst)) != 0) memcmp(pkt.eth->dst, broadcast, sizeof(pkt.eth->dst)) != 0)
return; return;
if (ifp->enable_crc32_check && len > 4) { if (ifp->enable_crc32_check && len > 4) {
uint32_t crc;
len -= 4; // TODO(scaprile): check on bigendian len -= 4; // TODO(scaprile): check on bigendian
uint32_t crc = mg_crc32(0, (const char *) buf, len); crc = mg_crc32(0, (const char *) buf, len);
if (memcmp((void *) ((size_t) buf + len), &crc, sizeof(crc))) return; if (memcmp((void *) ((size_t) buf + len), &crc, sizeof(crc))) return;
} }
if (pkt.eth->type == mg_htons(0x806)) { if (pkt.eth->type == mg_htons(0x806)) {
@@ -1006,10 +1036,10 @@ static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t now) {
// Process timeouts // Process timeouts
for (c = ifp->mgr->conns; c != NULL; c = c->next) { for (c = ifp->mgr->conns; c != NULL; c = c->next) {
if ((c->is_udp && !c->is_arplooking) || c->is_listening || c->is_resolving)
continue;
struct connstate *s = (struct connstate *) (c + 1); struct connstate *s = (struct connstate *) (c + 1);
uint32_t rem_ip; uint32_t rem_ip;
if ((c->is_udp && !c->is_arplooking) || c->is_listening || c->is_resolving)
continue;
memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
if (ifp->now > s->timer) { if (ifp->now > s->timer) {
if (s->ttype == MIP_TTYPE_ARP) { if (s->ttype == MIP_TTYPE_ARP) {
@@ -1074,10 +1104,10 @@ void mg_tcpip_init(struct mg_mgr *mgr, struct mg_tcpip_if *ifp) {
MG_ERROR(("driver init failed")); MG_ERROR(("driver init failed"));
} else { } else {
size_t framesize = 1540; size_t framesize = 1540;
ifp->tx.buf = (char *) calloc(1, framesize), ifp->tx.len = framesize; ifp->tx.buf = (char *) mg_calloc(1, framesize), ifp->tx.len = framesize;
if (ifp->recv_queue.size == 0) if (ifp->recv_queue.size == 0)
ifp->recv_queue.size = ifp->driver->rx ? framesize : 8192; ifp->recv_queue.size = ifp->driver->rx ? framesize : 8192;
ifp->recv_queue.buf = (char *) calloc(1, ifp->recv_queue.size); ifp->recv_queue.buf = (char *) mg_calloc(1, ifp->recv_queue.size);
ifp->timer_1000ms = mg_millis(); ifp->timer_1000ms = mg_millis();
mgr->ifp = ifp; mgr->ifp = ifp;
ifp->mgr = mgr; ifp->mgr = mgr;
@@ -1093,8 +1123,9 @@ void mg_tcpip_init(struct mg_mgr *mgr, struct mg_tcpip_if *ifp) {
} }
void mg_tcpip_free(struct mg_tcpip_if *ifp) { void mg_tcpip_free(struct mg_tcpip_if *ifp) {
free(ifp->recv_queue.buf); mg_free(ifp->recv_queue.buf);
free(ifp->tx.buf); mg_free(ifp->tx.buf);
mg_free(ifp->dns4_url);
} }
static void send_syn(struct mg_connection *c) { static void send_syn(struct mg_connection *c) {
@@ -1207,17 +1238,20 @@ void mg_mgr_poll(struct mg_mgr *mgr, int ms) {
if (mgr->ifp == NULL || mgr->ifp->driver == NULL) return; if (mgr->ifp == NULL || mgr->ifp->driver == NULL) return;
mg_tcpip_poll(mgr->ifp, now); mg_tcpip_poll(mgr->ifp, now);
for (c = mgr->conns; c != NULL; c = tmp) { for (c = mgr->conns; c != NULL; c = tmp) {
tmp = c->next;
struct connstate *s = (struct connstate *) (c + 1); struct connstate *s = (struct connstate *) (c + 1);
bool is_tls = c->is_tls && !c->is_resolving && !c->is_arplooking &&
!c->is_listening && !c->is_connecting;
tmp = c->next;
mg_call(c, MG_EV_POLL, &now); mg_call(c, MG_EV_POLL, &now);
MG_VERBOSE(("%lu .. %c%c%c%c%c %lu %lu", c->id, c->is_tls ? 'T' : 't', MG_VERBOSE(("%lu .. %c%c%c%c%c %lu %lu", c->id, c->is_tls ? 'T' : 't',
c->is_connecting ? 'C' : 'c', c->is_tls_hs ? 'H' : 'h', c->is_connecting ? 'C' : 'c', c->is_tls_hs ? 'H' : 'h',
c->is_resolving ? 'R' : 'r', c->is_closing ? 'C' : 'c', c->is_resolving ? 'R' : 'r', c->is_closing ? 'C' : 'c',
mg_tls_pending(c), c->rtls.len)); mg_tls_pending(c), c->rtls.len));
// order is important, TLS conn close with > 1 record in buffer (below) // order is important, TLS conn close with > 1 record in buffer (below)
if (c->is_tls && (c->rtls.len > 0 || mg_tls_pending(c) > 0)) if (is_tls && (c->rtls.len > 0 || mg_tls_pending(c) > 0))
handle_tls_recv(c); handle_tls_recv(c);
if (can_write(c)) write_conn(c); if (can_write(c)) write_conn(c);
if (is_tls && c->send.len == 0) mg_tls_flush(c);
if (c->is_draining && c->send.len == 0 && s->ttype != MIP_TTYPE_FIN) if (c->is_draining && c->send.len == 0 && s->ttype != MIP_TTYPE_FIN)
init_closure(c); init_closure(c);
// For non-TLS, close immediately upon completing the 3-way closure // For non-TLS, close immediately upon completing the 3-way closure
@@ -1243,8 +1277,8 @@ bool mg_send(struct mg_connection *c, const void *buf, size_t len) {
} else if (c->is_udp) { } else if (c->is_udp) {
struct connstate *s = (struct connstate *) (c + 1); struct connstate *s = (struct connstate *) (c + 1);
len = trim_len(c, len); // Trimming length if necessary len = trim_len(c, len); // Trimming length if necessary
tx_udp(ifp, s->mac, ifp->ip, c->loc.port, rem_ip, c->rem.port, buf, len); res = tx_udp(ifp, s->mac, ifp->ip, c->loc.port, rem_ip, c->rem.port, buf,
res = true; len);
} else { } else {
res = mg_iobuf_add(&c->send, c->send.len, buf, len); res = mg_iobuf_add(&c->send, c->send.len, buf, len);
} }
@@ -1258,4 +1292,19 @@ void mg_multicast_add(struct mg_connection *c, char *ip) {
c->mgr->ifp->update_mac_hash_table = true; // mark dirty c->mgr->ifp->update_mac_hash_table = true; // mark dirty
} }
bool mg_dnsc_init(struct mg_mgr *mgr, struct mg_dns *dnsc);
static void setdns4(struct mg_tcpip_if *ifp, uint32_t *ip) {
struct mg_dns *dnsc;
mg_free(ifp->dns4_url);
ifp->dns4_url = mg_mprintf("udp://%M:53", mg_print_ip4, ip);
dnsc = &ifp->mgr->dns4;
dnsc->url = (const char *) ifp->dns4_url;
MG_DEBUG(("Set DNS URL to %s", dnsc->url));
if (ifp->mgr->use_dns6) return;
if (dnsc->c != NULL) mg_close_conn(dnsc->c);
if (!mg_dnsc_init(ifp->mgr, dnsc)) // create DNS connection
MG_ERROR(("DNS connection creation failed"));
}
#endif // MG_ENABLE_TCPIP #endif // MG_ENABLE_TCPIP
+2
View File
@@ -57,6 +57,7 @@ struct mg_tcpip_if {
// Internal state, user can use it but should not change it // Internal state, user can use it but should not change it
uint8_t gwmac[6]; // Router's MAC uint8_t gwmac[6]; // Router's MAC
char *dns4_url; // DNS server URL
uint64_t now; // Current time uint64_t now; // Current time
uint64_t timer_1000ms; // 1000 ms timer: for DHCP and link state uint64_t timer_1000ms; // 1000 ms timer: for DHCP and link state
uint64_t lease_expire; // Lease expiration time, in ms uint64_t lease_expire; // Lease expiration time, in ms
@@ -103,4 +104,5 @@ struct mg_tcpip_spi {
uint8_t (*txn)(void *, uint8_t); // SPI transaction: write 1 byte, read reply uint8_t (*txn)(void *, uint8_t); // SPI transaction: write 1 byte, read reply
}; };
#endif #endif
+1 -1
View File
@@ -150,7 +150,7 @@ fwxit:
// try to swap (honor dual image), otherwise just overwrite // try to swap (honor dual image), otherwise just overwrite
MG_IRAM static void single_bank_swap(char *p1, char *p2, size_t s, size_t ss) { MG_IRAM static void single_bank_swap(char *p1, char *p2, size_t s, size_t ss) {
char *tmp = malloc(ss); char *tmp = mg_calloc(1, ss);
// no stdlib calls here // no stdlib calls here
for (size_t ofs = 0; ofs < s; ofs += ss) { for (size_t ofs = 0; ofs < s; ofs += ss) {
if (tmp != NULL) if (tmp != NULL)
+1 -1
View File
@@ -100,7 +100,7 @@ static bool __no_inline_not_in_flash_func(mg_picosdk_write)(void *addr,
static void __no_inline_not_in_flash_func(single_bank_swap)(char *p1, char *p2, static void __no_inline_not_in_flash_func(single_bank_swap)(char *p1, char *p2,
size_t s, size_t s,
size_t ss) { size_t ss) {
char *tmp = malloc(ss); char *tmp = mg_calloc(1, ss);
if (tmp == NULL) return; if (tmp == NULL) return;
#if PICO_RP2040 #if PICO_RP2040
uint32_t xip[256 / sizeof(uint32_t)]; uint32_t xip[256 / sizeof(uint32_t)];
+4
View File
@@ -200,6 +200,10 @@ MG_IRAM void single_bank_swap(char *p1, char *p2, size_t size) {
bool mg_ota_begin(size_t new_firmware_size) { bool mg_ota_begin(size_t new_firmware_size) {
s_mg_flash_stm32f.size = flash_size(); s_mg_flash_stm32f.size = flash_size();
#ifdef __ZEPHYR__
*((uint32_t *)0xE000ED94) = 0;
MG_DEBUG(("Jailbreak %s", *((uint32_t *)0xE000ED94) == 0 ? "successful" : "failed"));
#endif
return mg_ota_flash_begin(new_firmware_size, &s_mg_flash_stm32f); return mg_ota_flash_begin(new_firmware_size, &s_mg_flash_stm32f);
} }
+4
View File
@@ -135,6 +135,10 @@ static bool mg_stm32h5_write(void *addr, const void *buf, size_t len) {
} }
bool mg_ota_begin(size_t new_firmware_size) { bool mg_ota_begin(size_t new_firmware_size) {
#ifdef __ZEPHYR__
*((uint32_t *)0xE000ED94) = 0;
MG_DEBUG(("Jailbreak %s", *((uint32_t *)0xE000ED94) == 0 ? "successful" : "failed"));
#endif
return mg_ota_flash_begin(new_firmware_size, &s_mg_flash_stm32h5); return mg_ota_flash_begin(new_firmware_size, &s_mg_flash_stm32h5);
} }
+4
View File
@@ -184,6 +184,10 @@ bool mg_ota_begin(size_t new_firmware_size) {
// Using only the 1st bank (mapped to CM7) // Using only the 1st bank (mapped to CM7)
s_mg_flash_stm32h7.size /= 2; s_mg_flash_stm32h7.size /= 2;
} }
#ifdef __ZEPHYR__
*((uint32_t *)0xE000ED94) = 0;
MG_DEBUG(("Jailbreak %s", *((uint32_t *)0xE000ED94) == 0 ? "successful" : "failed"));
#endif
return mg_ota_flash_begin(new_firmware_size, &s_mg_flash_stm32h7); return mg_ota_flash_begin(new_firmware_size, &s_mg_flash_stm32h7);
} }
+4 -3
View File
@@ -1,9 +1,10 @@
#include "rpc.h" #include "rpc.h"
#include "printf.h" #include "printf.h"
#include "util.h"
void mg_rpc_add(struct mg_rpc **head, struct mg_str method, void mg_rpc_add(struct mg_rpc **head, struct mg_str method,
void (*fn)(struct mg_rpc_req *), void *fn_data) { void (*fn)(struct mg_rpc_req *), void *fn_data) {
struct mg_rpc *rpc = (struct mg_rpc *) calloc(1, sizeof(*rpc)); struct mg_rpc *rpc = (struct mg_rpc *) mg_calloc(1, sizeof(*rpc));
if (rpc != NULL) { if (rpc != NULL) {
rpc->method = mg_strdup(method); rpc->method = mg_strdup(method);
rpc->fn = fn; rpc->fn = fn;
@@ -17,8 +18,8 @@ void mg_rpc_del(struct mg_rpc **head, void (*fn)(struct mg_rpc_req *)) {
while ((r = *head) != NULL) { while ((r = *head) != NULL) {
if (r->fn == fn || fn == NULL) { if (r->fn == fn || fn == NULL) {
*head = r->next; *head = r->next;
free((void *) r->method.buf); mg_free((void *) r->method.buf);
free(r); mg_free(r);
} else { } else {
head = &(*head)->next; head = &(*head)->next;
} }
+2 -7
View File
@@ -82,12 +82,7 @@ void mg_sntp_request(struct mg_connection *c) {
} }
struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr, const char *url, struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr, const char *url,
mg_event_handler_t fn, void *fnd) { mg_event_handler_t fn, void *fn_data) {
struct mg_connection *c = NULL;
if (url == NULL) url = "udp://time.google.com:123"; if (url == NULL) url = "udp://time.google.com:123";
if ((c = mg_connect(mgr, url, fn, fnd)) != NULL) { return mg_connect_svc(mgr, url, fn, fn_data, sntp_cb, NULL);
c->pfn = sntp_cb;
sntp_cb(c, MG_EV_OPEN, (void *) url);
}
return c;
} }
+28 -14
View File
@@ -160,8 +160,10 @@ static void mg_set_non_blocking_mode(MG_SOCKET_TYPE fd) {
if (setsockopt(fd, 0, FREERTOS_SO_SNDTIMEO, &off, sizeof(off)) != 0) (void) 0; if (setsockopt(fd, 0, FREERTOS_SO_SNDTIMEO, &off, sizeof(off)) != 0) (void) 0;
#elif MG_ENABLE_LWIP #elif MG_ENABLE_LWIP
lwip_fcntl(fd, F_SETFL, O_NONBLOCK); lwip_fcntl(fd, F_SETFL, O_NONBLOCK);
#elif MG_ARCH == MG_ARCH_AZURERTOS #elif MG_ARCH == MG_ARCH_THREADX
fcntl(fd, F_SETFL, O_NONBLOCK); // NetxDuo fails to send large blocks of data to the non-blocking sockets
(void) fd;
//fcntl(fd, F_SETFL, O_NONBLOCK);
#elif MG_ARCH == MG_ARCH_TIRTOS #elif MG_ARCH == MG_ARCH_TIRTOS
int val = 0; int val = 0;
setsockopt(fd, SOL_SOCKET, SO_BLOCKING, &val, sizeof(val)); setsockopt(fd, SOL_SOCKET, SO_BLOCKING, &val, sizeof(val));
@@ -183,15 +185,19 @@ void mg_multicast_add(struct mg_connection *c, char *ip) {
#elif MG_ENABLE_FREERTOS_TCP #elif MG_ENABLE_FREERTOS_TCP
// TODO(): prvAllowIPPacketIPv4() // TODO(): prvAllowIPPacketIPv4()
#else #else
// lwIP, Unix, Windows, Zephyr(, AzureRTOS ?) // lwIP, Unix, Windows, Zephyr 4+(, AzureRTOS ?)
#if MG_ENABLE_LWIP && !LWIP_IGMP #if MG_ENABLE_LWIP && !LWIP_IGMP
MG_ERROR(("LWIP_IGMP not defined, no multicast support")); MG_ERROR(("LWIP_IGMP not defined, no multicast support"));
#else
#if defined(__ZEPHYR__) && ZEPHYR_VERSION_CODE < 0x40000
MG_ERROR(("struct ip_mreq not defined"));
#else #else
struct ip_mreq mreq; struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(ip); mreq.imr_multiaddr.s_addr = inet_addr(ip);
mreq.imr_interface.s_addr = mg_htonl(INADDR_ANY); mreq.imr_interface.s_addr = mg_htonl(INADDR_ANY);
setsockopt(FD(c), IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq)); setsockopt(FD(c), IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq));
#endif #endif // !Zephyr
#endif // !lwIP
#endif #endif
} }
@@ -361,13 +367,14 @@ static void connect_conn(struct mg_connection *c) {
mg_call(c, MG_EV_CONNECT, NULL); mg_call(c, MG_EV_CONNECT, NULL);
MG_EPOLL_MOD(c, 0); MG_EPOLL_MOD(c, 0);
if (c->is_tls_hs) mg_tls_handshake(c); if (c->is_tls_hs) mg_tls_handshake(c);
if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init()
} else { } else {
mg_error(c, "socket error"); mg_error(c, "socket error");
} }
} }
static void setsockopts(struct mg_connection *c) { static void setsockopts(struct mg_connection *c) {
#if MG_ENABLE_FREERTOS_TCP || MG_ARCH == MG_ARCH_AZURERTOS || \ #if MG_ENABLE_FREERTOS_TCP || MG_ARCH == MG_ARCH_THREADX || \
MG_ARCH == MG_ARCH_TIRTOS MG_ARCH == MG_ARCH_TIRTOS
(void) c; (void) c;
#else #else
@@ -413,6 +420,7 @@ void mg_connect_resolved(struct mg_connection *c) {
if (rc == 0) { // Success if (rc == 0) { // Success
setlocaddr(FD(c), &c->loc); setlocaddr(FD(c), &c->loc);
mg_call(c, MG_EV_CONNECT, NULL); // Send MG_EV_CONNECT to the user mg_call(c, MG_EV_CONNECT, NULL); // Send MG_EV_CONNECT to the user
if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init()
} else if (MG_SOCK_PENDING(rc)) { // Need to wait for TCP handshake } else if (MG_SOCK_PENDING(rc)) { // Need to wait for TCP handshake
MG_DEBUG(("%lu %ld -> %M pend", c->id, c->fd, mg_print_ip_port, &c->rem)); MG_DEBUG(("%lu %ld -> %M pend", c->id, c->fd, mg_print_ip_port, &c->rem));
c->is_connecting = 1; c->is_connecting = 1;
@@ -438,8 +446,8 @@ static void accept_conn(struct mg_mgr *mgr, struct mg_connection *lsn) {
socklen_t sa_len = sizeof(usa); socklen_t sa_len = sizeof(usa);
MG_SOCKET_TYPE fd = raccept(FD(lsn), &usa, &sa_len); MG_SOCKET_TYPE fd = raccept(FD(lsn), &usa, &sa_len);
if (fd == MG_INVALID_SOCKET) { if (fd == MG_INVALID_SOCKET) {
#if MG_ARCH == MG_ARCH_AZURERTOS || defined(__ECOS) #if MG_ARCH == MG_ARCH_THREADX || defined(__ECOS)
// AzureRTOS, in non-block socket mode can mark listening socket readable // NetxDuo, in non-block socket mode can mark listening socket readable
// even it is not. See comment for 'select' func implementation in // even it is not. See comment for 'select' func implementation in
// nx_bsd.c That's not an error, just should try later // nx_bsd.c That's not an error, just should try later
if (errno != EAGAIN) if (errno != EAGAIN)
@@ -468,10 +476,12 @@ static void accept_conn(struct mg_mgr *mgr, struct mg_connection *lsn) {
c->pfn_data = lsn->pfn_data; c->pfn_data = lsn->pfn_data;
c->fn = lsn->fn; c->fn = lsn->fn;
c->fn_data = lsn->fn_data; c->fn_data = lsn->fn_data;
c->is_tls = lsn->is_tls;
MG_DEBUG(("%lu %ld accepted %M -> %M", c->id, c->fd, mg_print_ip_port, MG_DEBUG(("%lu %ld accepted %M -> %M", c->id, c->fd, mg_print_ip_port,
&c->rem, mg_print_ip_port, &c->loc)); &c->rem, mg_print_ip_port, &c->loc));
mg_call(c, MG_EV_OPEN, NULL); mg_call(c, MG_EV_OPEN, NULL);
mg_call(c, MG_EV_ACCEPT, NULL); mg_call(c, MG_EV_ACCEPT, NULL);
if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init()
} }
} }
@@ -577,7 +587,7 @@ static void mg_iotest(struct mg_mgr *mgr, int ms) {
} }
} }
#else #else
struct timeval tv = {ms / 1000, (ms % 1000) * 1000}, tv_zero = {0, 0}, *tvp; struct timeval tv = {ms / 1000, (ms % 1000) * 1000}, tv_1ms = {0, 1000}, *tvp;
struct mg_connection *c; struct mg_connection *c;
fd_set rset, wset, eset; fd_set rset, wset, eset;
MG_SOCKET_TYPE maxfd = 0; MG_SOCKET_TYPE maxfd = 0;
@@ -593,16 +603,16 @@ static void mg_iotest(struct mg_mgr *mgr, int ms) {
FD_SET(FD(c), &eset); FD_SET(FD(c), &eset);
if (can_read(c)) FD_SET(FD(c), &rset); if (can_read(c)) FD_SET(FD(c), &rset);
if (can_write(c)) FD_SET(FD(c), &wset); if (can_write(c)) FD_SET(FD(c), &wset);
if (c->rtls.len > 0 || mg_tls_pending(c) > 0) tvp = &tv_zero; if (c->rtls.len > 0 || mg_tls_pending(c) > 0) tvp = &tv_1ms;
if (FD(c) > maxfd) maxfd = FD(c); if (FD(c) > maxfd) maxfd = FD(c);
if (c->is_closing) tvp = &tv_zero; if (c->is_closing) tvp = &tv_1ms;
} }
if ((rc = select((int) maxfd + 1, &rset, &wset, &eset, tvp)) < 0) { if ((rc = select((int) maxfd + 1, &rset, &wset, &eset, tvp)) <= 0) {
#if MG_ARCH == MG_ARCH_WIN32 #if MG_ARCH == MG_ARCH_WIN32
if (maxfd == 0) Sleep(ms); // On Windows, select fails if no sockets if (maxfd == 0) Sleep(ms); // On Windows, select fails if no sockets
#else #else
MG_ERROR(("select: %d %d", rc, MG_SOCK_ERR(rc))); if (rc < 0) MG_ERROR(("select: %d %d", rc, MG_SOCK_ERR(rc)));
#endif #endif
FD_ZERO(&rset); FD_ZERO(&rset);
FD_ZERO(&wset); FD_ZERO(&wset);
@@ -611,7 +621,12 @@ static void mg_iotest(struct mg_mgr *mgr, int ms) {
for (c = mgr->conns; c != NULL; c = c->next) { for (c = mgr->conns; c != NULL; c = c->next) {
if (FD(c) != MG_INVALID_SOCKET && FD_ISSET(FD(c), &eset)) { if (FD(c) != MG_INVALID_SOCKET && FD_ISSET(FD(c), &eset)) {
#if MG_ARCH == MG_ARCH_THREADX
// NetxDuo stack returns exceptions for listening connection after accept
if (c->is_listening == 0) mg_error(c, "socket error");
#else
mg_error(c, "socket error"); mg_error(c, "socket error");
#endif
} else { } else {
c->is_readable = FD(c) != MG_INVALID_SOCKET && FD_ISSET(FD(c), &rset); c->is_readable = FD(c) != MG_INVALID_SOCKET && FD_ISSET(FD(c), &rset);
c->is_writable = FD(c) != MG_INVALID_SOCKET && FD_ISSET(FD(c), &wset); c->is_writable = FD(c) != MG_INVALID_SOCKET && FD_ISSET(FD(c), &wset);
@@ -734,11 +749,10 @@ void mg_mgr_poll(struct mg_mgr *mgr, int ms) {
if (c->is_readable) accept_conn(mgr, c); if (c->is_readable) accept_conn(mgr, c);
} else if (c->is_connecting) { } else if (c->is_connecting) {
if (c->is_readable || c->is_writable) connect_conn(c); if (c->is_readable || c->is_writable) connect_conn(c);
//} else if (c->is_tls_hs) {
// if ((c->is_readable || c->is_writable)) mg_tls_handshake(c);
} else { } else {
if (c->is_readable) read_conn(c); if (c->is_readable) read_conn(c);
if (c->is_writable) write_conn(c); if (c->is_writable) write_conn(c);
if (c->is_tls && !c->is_tls_hs && c->send.len == 0) mg_tls_flush(c);
} }
if (c->is_draining && c->send.len == 0) c->is_closing = 1; if (c->is_draining && c->send.len == 0) c->is_closing = 1;
+4 -3
View File
@@ -1,6 +1,7 @@
#include "log.h" #include "log.h"
#include "printf.h" #include "printf.h"
#include "ssi.h" #include "ssi.h"
#include "util.h"
#ifndef MG_MAX_SSI_DEPTH #ifndef MG_MAX_SSI_DEPTH
#define MG_MAX_SSI_DEPTH 5 #define MG_MAX_SSI_DEPTH 5
@@ -31,7 +32,7 @@ static char *mg_ssi(const char *path, const char *root, int depth) {
if (depth < MG_MAX_SSI_DEPTH && if (depth < MG_MAX_SSI_DEPTH &&
(data = mg_ssi(tmp, root, depth + 1)) != NULL) { (data = mg_ssi(tmp, root, depth + 1)) != NULL) {
mg_iobuf_add(&b, b.len, data, strlen(data)); mg_iobuf_add(&b, b.len, data, strlen(data));
free(data); mg_free(data);
} else { } else {
MG_ERROR(("%s: file=%s error or too deep", path, arg)); MG_ERROR(("%s: file=%s error or too deep", path, arg));
} }
@@ -41,7 +42,7 @@ static char *mg_ssi(const char *path, const char *root, int depth) {
if (depth < MG_MAX_SSI_DEPTH && if (depth < MG_MAX_SSI_DEPTH &&
(data = mg_ssi(tmp, root, depth + 1)) != NULL) { (data = mg_ssi(tmp, root, depth + 1)) != NULL) {
mg_iobuf_add(&b, b.len, data, strlen(data)); mg_iobuf_add(&b, b.len, data, strlen(data));
free(data); mg_free(data);
} else { } else {
MG_ERROR(("%s: virtual=%s error or too deep", path, arg)); MG_ERROR(("%s: virtual=%s error or too deep", path, arg));
} }
@@ -87,7 +88,7 @@ void mg_http_serve_ssi(struct mg_connection *c, const char *root,
const char *headers = "Content-Type: text/html; charset=utf-8\r\n"; const char *headers = "Content-Type: text/html; charset=utf-8\r\n";
char *data = mg_ssi(fullpath, root, 0); char *data = mg_ssi(fullpath, root, 0);
mg_http_reply(c, 200, headers, "%s", data == NULL ? "" : data); mg_http_reply(c, 200, headers, "%s", data == NULL ? "" : data);
free(data); mg_free(data);
} }
#else #else
void mg_http_serve_ssi(struct mg_connection *c, const char *root, void mg_http_serve_ssi(struct mg_connection *c, const char *root,
+2 -1
View File
@@ -1,4 +1,5 @@
#include "str.h" #include "str.h"
#include "util.h"
struct mg_str mg_str_s(const char *s) { struct mg_str mg_str_s(const char *s) {
struct mg_str str = {(char *) s, s == NULL ? 0 : strlen(s)}; struct mg_str str = {(char *) s, s == NULL ? 0 : strlen(s)};
@@ -26,7 +27,7 @@ int mg_casecmp(const char *s1, const char *s2) {
struct mg_str mg_strdup(const struct mg_str s) { struct mg_str mg_strdup(const struct mg_str s) {
struct mg_str r = {NULL, 0}; struct mg_str r = {NULL, 0};
if (s.len > 0 && s.buf != NULL) { if (s.len > 0 && s.buf != NULL) {
char *sc = (char *) calloc(1, s.len + 1); char *sc = (char *) mg_calloc(1, s.len + 1);
if (sc != NULL) { if (sc != NULL) {
memcpy(sc, s.buf, s.len); memcpy(sc, s.buf, s.len);
sc[s.len] = '\0'; sc[s.len] = '\0';
+2 -1
View File
@@ -1,5 +1,6 @@
#include "arch.h" #include "arch.h"
#include "timer.h" #include "timer.h"
#include "util.h"
void mg_timer_init(struct mg_timer **head, struct mg_timer *t, uint64_t ms, void mg_timer_init(struct mg_timer **head, struct mg_timer *t, uint64_t ms,
unsigned flags, void (*fn)(void *), void *arg) { unsigned flags, void (*fn)(void *), void *arg) {
@@ -38,7 +39,7 @@ void mg_timer_poll(struct mg_timer **head, uint64_t now_ms) {
// If this timer is not repeating and marked AUTODELETE, remove it // If this timer is not repeating and marked AUTODELETE, remove it
if (!(t->flags & MG_TIMER_REPEAT) && (t->flags & MG_TIMER_AUTODELETE)) { if (!(t->flags & MG_TIMER_REPEAT) && (t->flags & MG_TIMER_AUTODELETE)) {
mg_timer_free(head, t); mg_timer_free(head, t);
free(t); mg_free(t);
} }
} }
} }
+1 -1
View File
@@ -10,7 +10,7 @@ struct mg_timer {
#define MG_TIMER_REPEAT 1 // Call function periodically #define MG_TIMER_REPEAT 1 // Call function periodically
#define MG_TIMER_RUN_NOW 2 // Call immediately when timer is set #define MG_TIMER_RUN_NOW 2 // Call immediately when timer is set
#define MG_TIMER_CALLED 4 // Timer function was called at least once #define MG_TIMER_CALLED 4 // Timer function was called at least once
#define MG_TIMER_AUTODELETE 8 // free() timer when done #define MG_TIMER_AUTODELETE 8 // mg_free() timer when done
void (*fn)(void *); // Function to call void (*fn)(void *); // Function to call
void *arg; // Function argument void *arg; // Function argument
struct mg_timer *next; // Linkage struct mg_timer *next; // Linkage
+1
View File
@@ -28,6 +28,7 @@ void mg_tls_free(struct mg_connection *);
long mg_tls_send(struct mg_connection *, const void *buf, size_t len); long mg_tls_send(struct mg_connection *, const void *buf, size_t len);
long mg_tls_recv(struct mg_connection *, void *buf, size_t len); long mg_tls_recv(struct mg_connection *, void *buf, size_t len);
size_t mg_tls_pending(struct mg_connection *); size_t mg_tls_pending(struct mg_connection *);
void mg_tls_flush(struct mg_connection *);
void mg_tls_handshake(struct mg_connection *); void mg_tls_handshake(struct mg_connection *);
// Private // Private
+3 -3
View File
@@ -20,6 +20,9 @@
* *
*******************************************************************************/ *******************************************************************************/
#include "arch.h"
#include "tls.h"
#if MG_TLS == MG_TLS_BUILTIN
/******************************************************************************/ /******************************************************************************/
#define AES_DECRYPTION 1 // whether AES decryption is supported #define AES_DECRYPTION 1 // whether AES decryption is supported
/******************************************************************************/ /******************************************************************************/
@@ -27,11 +30,8 @@
#define MG_ENCRYPT 1 // specify whether we're encrypting #define MG_ENCRYPT 1 // specify whether we're encrypting
#define MG_DECRYPT 0 // or decrypting #define MG_DECRYPT 0 // or decrypting
#include "arch.h"
#include "tls.h"
#include "tls_aes128.h" #include "tls_aes128.h"
#if MG_TLS == MG_TLS_BUILTIN
/****************************************************************************** /******************************************************************************
* AES_INIT_KEYGEN_TABLES : MUST be called once before any AES use * AES_INIT_KEYGEN_TABLES : MUST be called once before any AES use
******************************************************************************/ ******************************************************************************/
+242 -215
View File
@@ -12,8 +12,6 @@
#if MG_TLS == MG_TLS_BUILTIN #if MG_TLS == MG_TLS_BUILTIN
#define CHACHA20 1
/* TLS 1.3 Record Content Type (RFC8446 B.1) */ /* TLS 1.3 Record Content Type (RFC8446 B.1) */
#define MG_TLS_CHANGE_CIPHER 20 #define MG_TLS_CHANGE_CIPHER 20
#define MG_TLS_ALERT 21 #define MG_TLS_ALERT 21
@@ -34,17 +32,17 @@
// refer to RFC8446#A.1 // refer to RFC8446#A.1
enum mg_tls_hs_state { enum mg_tls_hs_state {
// Client state machine: // Client state machine:
MG_TLS_STATE_CLIENT_START, // Send ClientHello MG_TLS_STATE_CLIENT_START, // Send ClientHello
MG_TLS_STATE_CLIENT_WAIT_SH, // Wait for ServerHello MG_TLS_STATE_CLIENT_WAIT_SH, // Wait for ServerHello
MG_TLS_STATE_CLIENT_WAIT_EE, // Wait for EncryptedExtensions MG_TLS_STATE_CLIENT_WAIT_EE, // Wait for EncryptedExtensions
MG_TLS_STATE_CLIENT_WAIT_CERT, // Wait for Certificate MG_TLS_STATE_CLIENT_WAIT_CERT, // Wait for Certificate
MG_TLS_STATE_CLIENT_WAIT_CV, // Wait for CertificateVerify MG_TLS_STATE_CLIENT_WAIT_CV, // Wait for CertificateVerify
MG_TLS_STATE_CLIENT_WAIT_FINISHED, // Wait for Finished MG_TLS_STATE_CLIENT_WAIT_FINISH, // Wait for Finish
MG_TLS_STATE_CLIENT_CONNECTED, // Done MG_TLS_STATE_CLIENT_CONNECTED, // Done
// Server state machine: // Server state machine:
MG_TLS_STATE_SERVER_START, // Wait for ClientHello MG_TLS_STATE_SERVER_START, // Wait for ClientHello
MG_TLS_STATE_SERVER_NEGOTIATED, // Wait for Finished MG_TLS_STATE_SERVER_NEGOTIATED, // Wait for Finish
MG_TLS_STATE_SERVER_CONNECTED // Done MG_TLS_STATE_SERVER_CONNECTED // Done
}; };
@@ -150,10 +148,10 @@ static int mg_der_parse(uint8_t *der, size_t dersz, struct mg_der_tlv *tlv) {
if (dersz < 2) return -1; // Invalid DER if (dersz < 2) return -1; // Invalid DER
tlv->type = der[0]; tlv->type = der[0];
if (len > 0x7F) { // long-form length if (len > 0x7F) { // long-form length
uint8_t len_bytes = len & 0x7F; uint8_t len_bytes = len & 0x7F, i;
if (dersz < (size_t) (2 + len_bytes)) return -1; if (dersz < (size_t) (2 + len_bytes)) return -1;
len = 0; len = 0;
for (uint8_t i = 0; i < len_bytes; i++) { for (i = 0; i < len_bytes; i++) {
len = (len << 8) | der[2 + i]; len = (len << 8) | der[2 + i];
} }
header_len += len_bytes; header_len += len_bytes;
@@ -165,8 +163,9 @@ static int mg_der_parse(uint8_t *der, size_t dersz, struct mg_der_tlv *tlv) {
} }
static int mg_der_next(struct mg_der_tlv *parent, struct mg_der_tlv *child) { static int mg_der_next(struct mg_der_tlv *parent, struct mg_der_tlv *child) {
int consumed;
if (parent->len == 0) return 0; if (parent->len == 0) return 0;
int consumed = mg_der_parse(parent->value, parent->len, child); consumed = mg_der_parse(parent->value, parent->len, child);
if (consumed < 0) return -1; if (consumed < 0) return -1;
parent->value += consumed; parent->value += consumed;
parent->len -= (uint32_t) consumed; parent->len -= (uint32_t) consumed;
@@ -288,7 +287,7 @@ static void mg_tls_generate_handshake_keys(struct mg_connection *c) {
uint8_t hello_hash[32]; uint8_t hello_hash[32];
uint8_t server_hs_secret[32]; uint8_t server_hs_secret[32];
uint8_t client_hs_secret[32]; uint8_t client_hs_secret[32];
#if CHACHA20 #if MG_ENABLE_CHACHA20
const size_t keysz = 32; const size_t keysz = 32;
#else #else
const size_t keysz = 16; const size_t keysz = 16;
@@ -352,7 +351,7 @@ static void mg_tls_generate_application_keys(struct mg_connection *c) {
uint8_t master_secret[32]; uint8_t master_secret[32];
uint8_t server_secret[32]; uint8_t server_secret[32];
uint8_t client_secret[32]; uint8_t client_secret[32];
#if CHACHA20 #if MG_ENABLE_CHACHA20
const size_t keysz = 32; const size_t keysz = 32;
#else #else
const size_t keysz = 16; const size_t keysz = 16;
@@ -416,7 +415,8 @@ static void mg_tls_encrypt(struct mg_connection *c, const uint8_t *msg,
uint8_t *iv = uint8_t *iv =
c->is_client ? tls->enc.client_write_iv : tls->enc.server_write_iv; c->is_client ? tls->enc.client_write_iv : tls->enc.server_write_iv;
#if !CHACHA20 #if MG_ENABLE_CHACHA20
#else
mg_gcm_initialize(); mg_gcm_initialize();
#endif #endif
@@ -424,7 +424,7 @@ static void mg_tls_encrypt(struct mg_connection *c, const uint8_t *msg,
nonce[8] ^= (uint8_t) ((seq >> 24) & 255U); nonce[8] ^= (uint8_t) ((seq >> 24) & 255U);
nonce[9] ^= (uint8_t) ((seq >> 16) & 255U); nonce[9] ^= (uint8_t) ((seq >> 16) & 255U);
nonce[10] ^= (uint8_t) ((seq >> 8) & 255U); nonce[10] ^= (uint8_t) ((seq >> 8) & 255U);
nonce[11] ^= (uint8_t) ((seq) &255U); nonce[11] ^= (uint8_t) ((seq) & 255U);
mg_iobuf_add(wio, wio->len, hdr, sizeof(hdr)); mg_iobuf_add(wio, wio->len, hdr, sizeof(hdr));
mg_iobuf_resize(wio, wio->len + encsz); mg_iobuf_resize(wio, wio->len + encsz);
@@ -432,11 +432,11 @@ static void mg_tls_encrypt(struct mg_connection *c, const uint8_t *msg,
tag = wio->buf + wio->len + msgsz + 1; tag = wio->buf + wio->len + msgsz + 1;
memmove(outmsg, msg, msgsz); memmove(outmsg, msg, msgsz);
outmsg[msgsz] = msgtype; outmsg[msgsz] = msgtype;
#if CHACHA20 #if MG_ENABLE_CHACHA20
(void) tag; // tag is only used in aes gcm (void) tag; // tag is only used in aes gcm
{ {
size_t maxlen = MG_IO_SIZE > 16384 ? 16384 : MG_IO_SIZE; size_t maxlen = MG_IO_SIZE > 16384 ? 16384 : MG_IO_SIZE;
uint8_t *enc = (uint8_t *) calloc(1, maxlen + 256 + 1); uint8_t *enc = (uint8_t *) mg_calloc(1, maxlen + 256 + 1);
if (enc == NULL) { if (enc == NULL) {
mg_error(c, "TLS OOM"); mg_error(c, "TLS OOM");
return; return;
@@ -445,7 +445,7 @@ static void mg_tls_encrypt(struct mg_connection *c, const uint8_t *msg,
sizeof(associated_data), outmsg, sizeof(associated_data), outmsg,
msgsz + 1); msgsz + 1);
memmove(outmsg, enc, n); memmove(outmsg, enc, n);
free(enc); mg_free(enc);
} }
} }
#else #else
@@ -503,10 +503,10 @@ static int mg_tls_recv_record(struct mg_connection *c) {
nonce[8] ^= (uint8_t) ((seq >> 24) & 255U); nonce[8] ^= (uint8_t) ((seq >> 24) & 255U);
nonce[9] ^= (uint8_t) ((seq >> 16) & 255U); nonce[9] ^= (uint8_t) ((seq >> 16) & 255U);
nonce[10] ^= (uint8_t) ((seq >> 8) & 255U); nonce[10] ^= (uint8_t) ((seq >> 8) & 255U);
nonce[11] ^= (uint8_t) ((seq) &255U); nonce[11] ^= (uint8_t) ((seq) & 255U);
#if CHACHA20 #if MG_ENABLE_CHACHA20
{ {
uint8_t *dec = (uint8_t *) calloc(1, msgsz); uint8_t *dec = (uint8_t *) mg_calloc(1, msgsz);
size_t n; size_t n;
if (dec == NULL) { if (dec == NULL) {
mg_error(c, "TLS OOM"); mg_error(c, "TLS OOM");
@@ -514,7 +514,7 @@ static int mg_tls_recv_record(struct mg_connection *c) {
} }
n = mg_chacha20_poly1305_decrypt(dec, key, nonce, msg, msgsz); n = mg_chacha20_poly1305_decrypt(dec, key, nonce, msg, msgsz);
memmove(msg, dec, n); memmove(msg, dec, n);
free(dec); mg_free(dec);
} }
#else #else
mg_gcm_initialize(); mg_gcm_initialize();
@@ -594,6 +594,7 @@ static int mg_tls_server_recv_hello(struct mg_connection *c) {
uint16_t key_exchange_len; uint16_t key_exchange_len;
uint8_t *key_exchange; uint8_t *key_exchange;
uint16_t n = MG_LOAD_BE16(ext + j + 2); uint16_t n = MG_LOAD_BE16(ext + j + 2);
if (((uint32_t) n + j + 4) > ext_len) goto fail;
if (MG_LOAD_BE16(ext + j) != 0x0033) { // not a key share extension, ignore if (MG_LOAD_BE16(ext + j) != 0x0033) { // not a key share extension, ignore
j += (uint16_t) (n + 4); j += (uint16_t) (n + 4);
continue; continue;
@@ -637,7 +638,7 @@ static void mg_tls_server_send_hello(struct mg_connection *c) {
PLACEHOLDER_32B, PLACEHOLDER_32B,
// session ID length + session ID (32 bytes) // session ID length + session ID (32 bytes)
0x20, PLACEHOLDER_32B, 0x20, PLACEHOLDER_32B,
#if defined(CHACHA20) && CHACHA20 #if MG_ENABLE_CHACHA20
// TLS_CHACHA20_POLY1305_SHA256 + no compression // TLS_CHACHA20_POLY1305_SHA256 + no compression
0x13, 0x03, 0x00, 0x13, 0x03, 0x00,
#else #else
@@ -687,7 +688,7 @@ static void mg_tls_server_send_cert(struct mg_connection *c) {
int send_ca = !c->is_client && tls->ca_der.len > 0; int send_ca = !c->is_client && tls->ca_der.len > 0;
// server DER certificate + CA (optional) // server DER certificate + CA (optional)
size_t n = tls->cert_der.len + (send_ca ? tls->ca_der.len + 5 : 0); size_t n = tls->cert_der.len + (send_ca ? tls->ca_der.len + 5 : 0);
uint8_t *cert = (uint8_t *) calloc(1, 13 + n); uint8_t *cert = (uint8_t *) mg_calloc(1, 13 + n);
if (cert == NULL) { if (cert == NULL) {
mg_error(c, "tls cert oom"); mg_error(c, "tls cert oom");
return; return;
@@ -710,7 +711,7 @@ static void mg_tls_server_send_cert(struct mg_connection *c) {
} }
mg_sha256_update(&tls->sha256, cert, 13 + n); mg_sha256_update(&tls->sha256, cert, 13 + n);
mg_tls_encrypt(c, cert, 13 + n, MG_TLS_HANDSHAKE); mg_tls_encrypt(c, cert, 13 + n, MG_TLS_HANDSHAKE);
free(cert); mg_free(cert);
} }
// type adapter between uECC hash context and our sha256 implementation // type adapter between uECC hash context and our sha256 implementation
@@ -774,7 +775,6 @@ static void mg_tls_send_cert_verify(struct mg_connection *c, int is_client) {
static void mg_tls_server_send_finish(struct mg_connection *c) { static void mg_tls_server_send_finish(struct mg_connection *c) {
struct tls_data *tls = (struct tls_data *) c->tls; struct tls_data *tls = (struct tls_data *) c->tls;
struct mg_iobuf *wio = &tls->send;
mg_sha256_ctx sha256; mg_sha256_ctx sha256;
uint8_t hash[32]; uint8_t hash[32];
uint8_t finish[36] = {0x14, 0, 0, 32}; uint8_t finish[36] = {0x14, 0, 0, 32};
@@ -782,9 +782,6 @@ static void mg_tls_server_send_finish(struct mg_connection *c) {
mg_sha256_final(hash, &sha256); mg_sha256_final(hash, &sha256);
mg_hmac_sha256(finish + 4, tls->enc.server_finished_key, 32, hash, 32); mg_hmac_sha256(finish + 4, tls->enc.server_finished_key, 32, hash, 32);
mg_tls_encrypt(c, finish, sizeof(finish), MG_TLS_HANDSHAKE); mg_tls_encrypt(c, finish, sizeof(finish), MG_TLS_HANDSHAKE);
mg_io_send(c, wio->buf, wio->len);
wio->len = 0;
mg_sha256_update(&tls->sha256, finish, sizeof(finish)); mg_sha256_update(&tls->sha256, finish, sizeof(finish));
} }
@@ -840,7 +837,7 @@ static void mg_tls_client_send_hello(struct mg_connection *c) {
// session ID length + session ID (32 bytes) // session ID length + session ID (32 bytes)
0x20, PLACEHOLDER_32B, 0x00, 0x20, PLACEHOLDER_32B, 0x00,
0x02, // size = 2 bytes 0x02, // size = 2 bytes
#if defined(CHACHA20) && CHACHA20 #if MG_ENABLE_CHACHA20
// TLS_CHACHA20_POLY1305_SHA256 // TLS_CHACHA20_POLY1305_SHA256
0x13, 0x03, 0x13, 0x03,
#else #else
@@ -909,8 +906,6 @@ static void mg_tls_client_send_hello(struct mg_connection *c) {
// change cipher message // change cipher message
mg_iobuf_add(wio, wio->len, (const char *) "\x14\x03\x03\x00\x01\x01", 6); mg_iobuf_add(wio, wio->len, (const char *) "\x14\x03\x03\x00\x01\x01", 6);
mg_io_send(c, wio->buf, wio->len);
wio->len = 0;
} }
static int mg_tls_client_recv_hello(struct mg_connection *c) { static int mg_tls_client_recv_hello(struct mg_connection *c) {
@@ -994,6 +989,7 @@ struct mg_tls_cert {
int is_ec_pubkey; int is_ec_pubkey;
struct mg_str sn; struct mg_str sn;
struct mg_str pubkey; struct mg_str pubkey;
struct mg_der_tlv subj;
struct mg_str sig; // signature struct mg_str sig; // signature
uint8_t tbshash[48]; // 32b for sha256/secp256, 48b for sha384/secp384 uint8_t tbshash[48]; // 32b for sha256/secp256, 48b for sha384/secp384
size_t tbshashsz; // actual TBS hash size size_t tbshashsz; // actual TBS hash size
@@ -1050,22 +1046,25 @@ static int mg_tls_parse_cert_der(void *buf, size_t dersz,
MG_VERBOSE(("sig algo (oid): %M", mg_print_hex, algo.len, algo.value)); MG_VERBOSE(("sig algo (oid): %M", mg_print_hex, algo.len, algo.value));
// Signature algorithm OID mapping // Signature algorithm OID mapping
if (memcmp(algo.value, "\x2A\x86\x48\xCE\x3D\x04\x03\x02", algo.len) == 0) { if (algo.len == 8 &&
memcmp(algo.value, "\x2A\x86\x48\xCE\x3D\x04\x03\x02", 8) == 0) {
MG_VERBOSE(("sig algo: ECDSA with SHA256")); MG_VERBOSE(("sig algo: ECDSA with SHA256"));
mg_sha256(cert->tbshash, tbs, tbssz); mg_sha256(cert->tbshash, tbs, tbssz);
cert->tbshashsz = 32; cert->tbshashsz = 32;
} else if (memcmp(algo.value, "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0B", } else if (algo.len == 9 &&
algo.len) == 0) { memcmp(algo.value, "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0B", 9) ==
0) {
MG_VERBOSE(("sig algo: RSA with SHA256")); MG_VERBOSE(("sig algo: RSA with SHA256"));
mg_sha256(cert->tbshash, tbs, tbssz); mg_sha256(cert->tbshash, tbs, tbssz);
cert->tbshashsz = 32; cert->tbshashsz = 32;
} else if (memcmp(algo.value, "\x2A\x86\x48\xCE\x3D\x04\x03\x03", algo.len) == } else if (algo.len == 8 &&
0) { memcmp(algo.value, "\x2A\x86\x48\xCE\x3D\x04\x03\x03", 8) == 0) {
MG_VERBOSE(("sig algo: ECDSA with SHA384")); MG_VERBOSE(("sig algo: ECDSA with SHA384"));
mg_sha384(cert->tbshash, tbs, tbssz); mg_sha384(cert->tbshash, tbs, tbssz);
cert->tbshashsz = 48; cert->tbshashsz = 48;
} else if (memcmp(algo.value, "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0C", } else if (algo.len == 9 &&
algo.len) == 0) { memcmp(algo.value, "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0C", 9) ==
0) {
MG_VERBOSE(("sig algo: RSA with SHA384")); MG_VERBOSE(("sig algo: RSA with SHA384"));
mg_sha384(cert->tbshash, tbs, tbssz); mg_sha384(cert->tbshash, tbs, tbssz);
cert->tbshashsz = 48; cert->tbshashsz = 48;
@@ -1086,7 +1085,7 @@ static int mg_tls_parse_cert_der(void *buf, size_t dersz,
struct mg_der_tlv before, after; struct mg_der_tlv before, after;
mg_der_next(&field, &before); mg_der_next(&field, &before);
mg_der_next(&field, &after); mg_der_next(&field, &after);
if (memcmp(after.value, "250101000000Z", after.len) < 0) { if (after.len == 13 && memcmp(after.value, "250101000000Z", 13) < 0) {
MG_ERROR(("invalid validity dates: before=%M after=%M", mg_print_hex, MG_ERROR(("invalid validity dates: before=%M after=%M", mg_print_hex,
before.len, before.value, mg_print_hex, after.len, before.len, before.value, mg_print_hex, after.len,
after.value)); after.value));
@@ -1096,6 +1095,7 @@ static int mg_tls_parse_cert_der(void *buf, size_t dersz,
// subject // subject
if (mg_der_next(&tbs_cert, &field) <= 0 || field.type != 0x30) return -1; if (mg_der_next(&tbs_cert, &field) <= 0 || field.type != 0x30) return -1;
cert->subj = field;
mg_der_debug_cert_name("subject", &field); mg_der_debug_cert_name("subject", &field);
// subject public key info // subject public key info
@@ -1106,20 +1106,22 @@ static int mg_tls_parse_cert_der(void *buf, size_t dersz,
// public key algorithm // public key algorithm
MG_VERBOSE(("pk algo (oid): %M", mg_print_hex, pki_algo.len, pki_algo.value)); MG_VERBOSE(("pk algo (oid): %M", mg_print_hex, pki_algo.len, pki_algo.value));
if (memcmp(pki_algo.value, "\x2A\x86\x48\xCE\x3D\x03\x01\x07", if (pki_algo.len == 8 &&
pki_algo.len) == 0) { memcmp(pki_algo.value, "\x2A\x86\x48\xCE\x3D\x03\x01\x07", 8) == 0) {
cert->is_ec_pubkey = 1; cert->is_ec_pubkey = 1;
MG_VERBOSE(("pk algo: ECDSA secp256r1")); MG_VERBOSE(("pk algo: ECDSA secp256r1"));
} else if (memcmp(pki_algo.value, "\x2A\x86\x48\xCE\x3D\x03\x01\x08", } else if (pki_algo.len == 8 &&
pki_algo.len) == 0) { memcmp(pki_algo.value, "\x2A\x86\x48\xCE\x3D\x03\x01\x08", 8) ==
0) {
cert->is_ec_pubkey = 1; cert->is_ec_pubkey = 1;
MG_VERBOSE(("pk algo: ECDSA secp384r1")); MG_VERBOSE(("pk algo: ECDSA secp384r1"));
} else if (memcmp(pki_algo.value, "\x2A\x86\x48\xCE\x3D\x02\x01", } else if (pki_algo.len == 7 &&
pki_algo.len) == 0) { memcmp(pki_algo.value, "\x2A\x86\x48\xCE\x3D\x02\x01", 7) == 0) {
cert->is_ec_pubkey = 1; cert->is_ec_pubkey = 1;
MG_VERBOSE(("pk algo: EC public key")); MG_VERBOSE(("pk algo: EC public key"));
} else if (memcmp(pki_algo.value, "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01", } else if (pki_algo.len == 9 &&
pki_algo.len) == 0) { memcmp(pki_algo.value, "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01",
9) == 0) {
cert->is_ec_pubkey = 0; cert->is_ec_pubkey = 0;
MG_VERBOSE(("pk algo: RSA")); MG_VERBOSE(("pk algo: RSA"));
} else { } else {
@@ -1154,19 +1156,22 @@ static int mg_tls_parse_cert_der(void *buf, size_t dersz,
static int mg_tls_verify_cert_san(const uint8_t *der, size_t dersz, static int mg_tls_verify_cert_san(const uint8_t *der, size_t dersz,
const char *server_name) { const char *server_name) {
struct mg_der_tlv root, field, name; struct mg_der_tlv root, field, name;
if (mg_der_parse((uint8_t *) der, dersz, &root) < 0 || if (mg_der_parse((uint8_t *) der, dersz, &root) < 0) {
mg_der_find_oid(&root, (uint8_t *) "\x55\x1d\x11", 3, &field) < 0) { MG_ERROR(("failed to parse certificate"));
MG_ERROR(("failed to parse certificate to extract SAN")); return -1;
}
if (mg_der_find_oid(&root, (uint8_t *) "\x55\x1d\x11", 3, &field) <= 0) {
MG_ERROR(("failed to extract SAN"));
return -1; return -1;
} }
if (mg_der_parse(field.value, field.len, &field) < 0) { if (mg_der_parse(field.value, field.len, &field) < 0) {
MG_ERROR( MG_ERROR(("SAN is not a constructed object"));
("certificate subject alternative names is not a constructed object"));
return -1; return -1;
} }
while (mg_der_next(&field, &name) > 0) { while (mg_der_next(&field, &name) > 0) {
if (mg_match(mg_str(server_name), MG_DEBUG(("Found SAN: %.*s", name.len, name.value));
mg_str_n((const char *) name.value, name.len), NULL)) { if (mg_match(mg_str(server_name), mg_str_n((char *) name.value, name.len),
NULL)) {
// Found SAN that matches the host name // Found SAN that matches the host name
return 1; return 1;
} }
@@ -1222,11 +1227,19 @@ static int mg_tls_verify_cert_signature(const struct mg_tls_cert *cert,
} }
} }
static int mg_tls_verify_cert_cn(struct mg_der_tlv *subj, const char *host) {
struct mg_der_tlv v;
int matched = 0;
if (mg_der_find_oid(subj, (uint8_t *) "\x55\x04\x03", 3, &v) > 0) {
MG_DEBUG(("using CN: %.*s <-> %s", v.len, v.value, host));
matched = mg_match(mg_str(host), mg_str_n((char *) v.value, v.len), NULL);
}
return matched;
}
static int mg_tls_client_recv_cert(struct mg_connection *c) { static int mg_tls_client_recv_cert(struct mg_connection *c) {
int subj_match = 0;
struct tls_data *tls = (struct tls_data *) c->tls; struct tls_data *tls = (struct tls_data *) c->tls;
unsigned char *recv_buf; unsigned char *recv_buf;
(void) subj_match;
if (mg_tls_recv_record(c) < 0) { if (mg_tls_recv_record(c) < 0) {
return -1; return -1;
@@ -1251,91 +1264,92 @@ static int mg_tls_client_recv_cert(struct mg_connection *c) {
return -1; return -1;
} }
uint32_t full_cert_chain_len = MG_LOAD_BE24(recv_buf + 1); {
uint32_t cert_chain_len = MG_LOAD_BE24(recv_buf + 5); // Normally, there are 2-3 certs in a chain
if (cert_chain_len != full_cert_chain_len - 4) { struct mg_tls_cert certs[8];
MG_ERROR(("full chain length: %d, chain length: %d", full_cert_chain_len, int certnum = 0;
cert_chain_len)); uint32_t full_cert_chain_len = MG_LOAD_BE24(recv_buf + 1);
mg_error(c, "certificate chain length mismatch"); uint32_t cert_chain_len = MG_LOAD_BE24(recv_buf + 5);
return -1; uint8_t *p = recv_buf + 8;
} uint8_t *endp = recv_buf + cert_chain_len;
bool found_ca = false;
struct mg_tls_cert ca;
// Normally, there are 2-3 certs in a chain if (cert_chain_len != full_cert_chain_len - 4) {
struct mg_tls_cert certs[8]; MG_ERROR(("full chain length: %d, chain length: %d", full_cert_chain_len,
int certnum = 0; cert_chain_len));
uint8_t *p = recv_buf + 8; mg_error(c, "certificate chain length mismatch");
// uint8_t *endp = recv_buf + tls->recv_len;
uint8_t *endp = recv_buf + cert_chain_len;
int found_ca = 0;
struct mg_tls_cert ca;
memset(certs, 0, sizeof(certs));
memset(&ca, 0, sizeof(ca));
if (tls->ca_der.len > 0) {
if (mg_tls_parse_cert_der(tls->ca_der.buf, tls->ca_der.len, &ca) < 0) {
mg_error(c, "failed to parse CA certificate");
return -1;
}
MG_VERBOSE(("CA serial: %M", mg_print_hex, ca.sn.len, ca.sn.buf));
}
while (p < endp) {
struct mg_tls_cert *ci = &certs[certnum++];
uint32_t certsz = MG_LOAD_BE24(p);
uint8_t *cert = p + 3;
uint16_t certext = MG_LOAD_BE16(cert + certsz);
if (certext != 0) {
mg_error(c, "certificate extensions are not supported");
return -1;
}
p = cert + certsz + 2;
if (mg_tls_parse_cert_der(cert, certsz, ci) < 0) {
mg_error(c, "failed to parse certificate");
return -1; return -1;
} }
if (ci == certs) { memset(certs, 0, sizeof(certs));
// First certificate in the chain is peer cert, check SAN and store memset(&ca, 0, sizeof(ca));
// public key for further CertVerify step
if (mg_tls_verify_cert_san(cert, certsz, tls->hostname) <= 0) { if (tls->ca_der.len > 0) {
mg_error(c, "failed to verify hostname"); if (mg_tls_parse_cert_der(tls->ca_der.buf, tls->ca_der.len, &ca) < 0) {
mg_error(c, "failed to parse CA certificate");
return -1; return -1;
} }
memmove(tls->pubkey, ci->pubkey.buf, ci->pubkey.len); MG_VERBOSE(("CA serial: %M", mg_print_hex, ca.sn.len, ca.sn.buf));
tls->pubkeysz = ci->pubkey.len; }
} else {
if (!mg_tls_verify_cert_signature(ci - 1, ci)) { while (p < endp) {
mg_error(c, "failed to verify certificate chain"); struct mg_tls_cert *ci = &certs[certnum++];
uint32_t certsz = MG_LOAD_BE24(p);
uint8_t *cert = p + 3;
uint16_t certext = MG_LOAD_BE16(cert + certsz);
if (certext != 0) {
mg_error(c, "certificate extensions are not supported");
return -1;
}
p = cert + certsz + 2;
if (mg_tls_parse_cert_der(cert, certsz, ci) < 0) {
mg_error(c, "failed to parse certificate");
return -1;
}
if (ci == certs) {
// First certificate in the chain is peer cert, check SAN and store
// public key for further CertVerify step
if (mg_tls_verify_cert_san(cert, certsz, tls->hostname) <= 0 &&
mg_tls_verify_cert_cn(&ci->subj, tls->hostname) <= 0) {
mg_error(c, "failed to verify hostname");
return -1;
}
memmove(tls->pubkey, ci->pubkey.buf, ci->pubkey.len);
tls->pubkeysz = ci->pubkey.len;
} else {
if (!mg_tls_verify_cert_signature(ci - 1, ci)) {
mg_error(c, "failed to verify certificate chain");
return -1;
}
}
if (ca.pubkey.len == ci->pubkey.len &&
memcmp(ca.pubkey.buf, ci->pubkey.buf, ca.pubkey.len) == 0) {
found_ca = true;
break;
}
if (certnum == sizeof(certs) / sizeof(certs[0]) - 1) {
mg_error(c, "too many certificates in the chain");
return -1; return -1;
} }
} }
if (ca.pubkey.len == ci->pubkey.len && if (!found_ca && tls->ca_der.len > 0) {
memcmp(ca.pubkey.buf, ci->pubkey.buf, ca.pubkey.len) == 0) { if (certnum < 1 ||
found_ca = 1; !mg_tls_verify_cert_signature(&certs[certnum - 1], &ca)) {
break; mg_error(c, "failed to verify CA");
} return -1;
} else {
if (certnum == sizeof(certs) / sizeof(certs[0]) - 1) { MG_VERBOSE(
mg_error(c, "too many certificates in the chain"); ("CA was not in the chain, but verification with builtin CA "
return -1; "passed"));
}
} }
} }
if (!found_ca && tls->ca_der.len > 0) {
if (certnum < 1 ||
!mg_tls_verify_cert_signature(&certs[certnum - 1], &ca)) {
mg_error(c, "failed to verify CA");
return -1;
} else {
MG_VERBOSE(
("CA was not in the chain, but verification with builtin CA passed"));
}
}
mg_tls_drop_message(c); mg_tls_drop_message(c);
mg_tls_calc_cert_verify_hash(c, tls->sighash, 0); mg_tls_calc_cert_verify_hash(c, tls->sighash, 0);
return 0; return 0;
@@ -1365,78 +1379,80 @@ static int mg_tls_client_recv_cert_verify(struct mg_connection *c) {
return 0; return 0;
} }
uint16_t sigalg = MG_LOAD_BE16(recv_buf + 4); {
uint16_t siglen = MG_LOAD_BE16(recv_buf + 6); uint16_t sigalg = MG_LOAD_BE16(recv_buf + 4);
uint8_t *sigbuf = recv_buf + 8; uint16_t siglen = MG_LOAD_BE16(recv_buf + 6);
if (siglen > tls->recv_len - 8) { uint8_t *sigbuf = recv_buf + 8;
mg_error(c, "invalid certverify signature length: %d, expected %d", siglen, if (siglen > tls->recv_len - 8) {
tls->recv_len - 8); mg_error(c, "invalid certverify signature length: %d, expected %d",
return -1; siglen, tls->recv_len - 8);
}
MG_VERBOSE(
("certificate verification, algo=%04x, siglen=%d", sigalg, siglen));
if (sigalg == 0x0804) { // rsa_pss_rsae_sha256
uint8_t sig2[512]; // 2048 or 4096 bits
struct mg_der_tlv seq, modulus, exponent;
if (mg_der_parse(tls->pubkey, tls->pubkeysz, &seq) <= 0 ||
mg_der_next(&seq, &modulus) <= 0 || modulus.type != 2 ||
mg_der_next(&seq, &exponent) <= 0 || exponent.type != 2) {
mg_error(c, "invalid public key");
return -1; return -1;
} }
MG_VERBOSE(
("certificate verification, algo=%04x, siglen=%d", sigalg, siglen));
mg_rsa_mod_pow(modulus.value, modulus.len, exponent.value, exponent.len, if (sigalg == 0x0804) { // rsa_pss_rsae_sha256
sigbuf, siglen, sig2, sizeof(sig2)); uint8_t sig2[512]; // 2048 or 4096 bits
struct mg_der_tlv seq, modulus, exponent;
if (sig2[sizeof(sig2) - 1] != 0xbc) { if (mg_der_parse(tls->pubkey, tls->pubkeysz, &seq) <= 0 ||
mg_error(c, "failed to verify RSA certificate (certverify)"); mg_der_next(&seq, &modulus) <= 0 || modulus.type != 2 ||
return -1; mg_der_next(&seq, &exponent) <= 0 || exponent.type != 2) {
} mg_error(c, "invalid public key");
MG_DEBUG(("certificate verification successful (RSA)")); return -1;
} else if (sigalg == 0x0403) { // ecdsa_secp256r1_sha256 }
// Extract certificate signature and verify it using pubkey and sighash
uint8_t sig[64];
struct mg_der_tlv seq, r, s;
if (mg_der_to_tlv(sigbuf, siglen, &seq) < 0) {
mg_error(c, "verification message is not an ASN.1 DER sequence");
return -1;
}
if (mg_der_to_tlv(seq.value, seq.len, &r) < 0) {
mg_error(c, "missing first part of the signature");
return -1;
}
if (mg_der_to_tlv(r.value + r.len, seq.len - r.len, &s) < 0) {
mg_error(c, "missing second part of the signature");
return -1;
}
// Integers may be padded with zeroes
if (r.len > 32) r.value = r.value + (r.len - 32), r.len = 32;
if (s.len > 32) s.value = s.value + (s.len - 32), s.len = 32;
memmove(sig, r.value, r.len); mg_rsa_mod_pow(modulus.value, modulus.len, exponent.value, exponent.len,
memmove(sig + 32, s.value, s.len); sigbuf, siglen, sig2, sizeof(sig2));
if (mg_uecc_verify(tls->pubkey, tls->sighash, sizeof(tls->sighash), sig, if (sig2[sizeof(sig2) - 1] != 0xbc) {
mg_uecc_secp256r1()) != 1) { mg_error(c, "failed to verify RSA certificate (certverify)");
mg_error(c, "failed to verify EC certificate (certverify)"); return -1;
}
MG_DEBUG(("certificate verification successful (RSA)"));
} else if (sigalg == 0x0403) { // ecdsa_secp256r1_sha256
// Extract certificate signature and verify it using pubkey and sighash
uint8_t sig[64];
struct mg_der_tlv seq, r, s;
if (mg_der_to_tlv(sigbuf, siglen, &seq) < 0) {
mg_error(c, "verification message is not an ASN.1 DER sequence");
return -1;
}
if (mg_der_to_tlv(seq.value, seq.len, &r) < 0) {
mg_error(c, "missing first part of the signature");
return -1;
}
if (mg_der_to_tlv(r.value + r.len, seq.len - r.len, &s) < 0) {
mg_error(c, "missing second part of the signature");
return -1;
}
// Integers may be padded with zeroes
if (r.len > 32) r.value = r.value + (r.len - 32), r.len = 32;
if (s.len > 32) s.value = s.value + (s.len - 32), s.len = 32;
memmove(sig, r.value, r.len);
memmove(sig + 32, s.value, s.len);
if (mg_uecc_verify(tls->pubkey, tls->sighash, sizeof(tls->sighash), sig,
mg_uecc_secp256r1()) != 1) {
mg_error(c, "failed to verify EC certificate (certverify)");
return -1;
}
MG_DEBUG(("certificate verification successful (EC)"));
} else {
// From
// https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml:
// 0805 = rsa_pss_rsae_sha384
// 0806 = rsa_pss_rsae_sha512
// 0807 = ed25519
// 0808 = ed448
// 0809 = rsa_pss_pss_sha256
// 080A = rsa_pss_pss_sha384
// 080B = rsa_pss_pss_sha512
MG_ERROR(("unsupported certverify signature scheme: %x of %d bytes",
sigalg, siglen));
return -1; return -1;
} }
MG_DEBUG(("certificate verification successful (EC)"));
} else {
// From
// https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml:
// 0805 = rsa_pss_rsae_sha384
// 0806 = rsa_pss_rsae_sha512
// 0807 = ed25519
// 0808 = ed448
// 0809 = rsa_pss_pss_sha256
// 080A = rsa_pss_pss_sha384
// 080B = rsa_pss_pss_sha512
MG_ERROR(("unsupported certverify signature scheme: %x of %d bytes", sigalg,
siglen));
return -1;
} }
mg_tls_drop_message(c); mg_tls_drop_message(c);
return 0; return 0;
@@ -1459,7 +1475,6 @@ static int mg_tls_client_recv_finish(struct mg_connection *c) {
static void mg_tls_client_send_finish(struct mg_connection *c) { static void mg_tls_client_send_finish(struct mg_connection *c) {
struct tls_data *tls = (struct tls_data *) c->tls; struct tls_data *tls = (struct tls_data *) c->tls;
struct mg_iobuf *wio = &tls->send;
mg_sha256_ctx sha256; mg_sha256_ctx sha256;
uint8_t hash[32]; uint8_t hash[32];
uint8_t finish[36] = {0x14, 0, 0, 32}; uint8_t finish[36] = {0x14, 0, 0, 32};
@@ -1467,8 +1482,6 @@ static void mg_tls_client_send_finish(struct mg_connection *c) {
mg_sha256_final(hash, &sha256); mg_sha256_final(hash, &sha256);
mg_hmac_sha256(finish + 4, tls->enc.client_finished_key, 32, hash, 32); mg_hmac_sha256(finish + 4, tls->enc.client_finished_key, 32, hash, 32);
mg_tls_encrypt(c, finish, sizeof(finish), MG_TLS_HANDSHAKE); mg_tls_encrypt(c, finish, sizeof(finish), MG_TLS_HANDSHAKE);
mg_io_send(c, wio->buf, wio->len);
wio->len = 0;
} }
static void mg_tls_client_handshake(struct mg_connection *c) { static void mg_tls_client_handshake(struct mg_connection *c) {
@@ -1500,9 +1513,9 @@ static void mg_tls_client_handshake(struct mg_connection *c) {
if (mg_tls_client_recv_cert_verify(c) < 0) { if (mg_tls_client_recv_cert_verify(c) < 0) {
break; break;
} }
tls->state = MG_TLS_STATE_CLIENT_WAIT_FINISHED; tls->state = MG_TLS_STATE_CLIENT_WAIT_FINISH;
// Fallthrough // Fallthrough
case MG_TLS_STATE_CLIENT_WAIT_FINISHED: case MG_TLS_STATE_CLIENT_WAIT_FINISH:
if (mg_tls_client_recv_finish(c) < 0) { if (mg_tls_client_recv_finish(c) < 0) {
break; break;
} }
@@ -1527,9 +1540,7 @@ static void mg_tls_client_handshake(struct mg_connection *c) {
c->is_tls_hs = 0; c->is_tls_hs = 0;
mg_call(c, MG_EV_TLS_HS, NULL); mg_call(c, MG_EV_TLS_HS, NULL);
break; break;
default: default: mg_error(c, "unexpected client state: %d", tls->state); break;
mg_error(c, "unexpected client state: %d", tls->state);
break;
} }
} }
@@ -1556,18 +1567,24 @@ static void mg_tls_server_handshake(struct mg_connection *c) {
tls->state = MG_TLS_STATE_SERVER_CONNECTED; tls->state = MG_TLS_STATE_SERVER_CONNECTED;
c->is_tls_hs = 0; c->is_tls_hs = 0;
return; return;
default: default: mg_error(c, "unexpected server state: %d", tls->state); break;
mg_error(c, "unexpected server state: %d", tls->state);
break;
} }
} }
void mg_tls_handshake(struct mg_connection *c) { void mg_tls_handshake(struct mg_connection *c) {
struct tls_data *tls = (struct tls_data *) c->tls;
long n;
if (c->is_client) { if (c->is_client) {
// will clear is_hs when sending last chunk
mg_tls_client_handshake(c); mg_tls_client_handshake(c);
} else { } else {
mg_tls_server_handshake(c); mg_tls_server_handshake(c);
} }
while (tls->send.len > 0 &&
(n = mg_io_send(c, tls->send.buf, tls->send.len)) > 0) {
mg_iobuf_del(&tls->send, 0, (size_t) n);
} // if last chunk fails to be sent, it will be sent with first app data,
// otherwise, it needs to be flushed
} }
static int mg_parse_pem(const struct mg_str pem, const struct mg_str label, static int mg_parse_pem(const struct mg_str pem, const struct mg_str label,
@@ -1583,7 +1600,7 @@ static int mg_parse_pem(const struct mg_str pem, const struct mg_str label,
if (mg_strcmp(caps[1], label) != 0 || mg_strcmp(caps[3], label) != 0) { if (mg_strcmp(caps[1], label) != 0 || mg_strcmp(caps[3], label) != 0) {
return -1; // bad label return -1; // bad label
} }
if ((s = (char *) calloc(1, caps[2].len)) == NULL) { if ((s = (char *) mg_calloc(1, caps[2].len)) == NULL) {
return -1; return -1;
} }
@@ -1595,7 +1612,7 @@ static int mg_parse_pem(const struct mg_str pem, const struct mg_str label,
} }
m = mg_base64_decode(s, n, s, n); m = mg_base64_decode(s, n, s, n);
if (m == 0) { if (m == 0) {
free(s); mg_free(s);
return -1; return -1;
} }
der->buf = s; der->buf = s;
@@ -1605,7 +1622,8 @@ static int mg_parse_pem(const struct mg_str pem, const struct mg_str label,
void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) { void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
struct mg_str key; struct mg_str key;
struct tls_data *tls = (struct tls_data *) calloc(1, sizeof(struct tls_data)); struct tls_data *tls =
(struct tls_data *) mg_calloc(1, sizeof(struct tls_data));
if (tls == NULL) { if (tls == NULL) {
mg_error(c, "tls oom"); mg_error(c, "tls oom");
return; return;
@@ -1670,7 +1688,7 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
MG_ERROR(("EC private key: ASN.1 bad data")); MG_ERROR(("EC private key: ASN.1 bad data"));
} }
memmove(tls->ec_key, key.buf + 7, 32); memmove(tls->ec_key, key.buf + 7, 32);
free((void *) key.buf); mg_free((void *) key.buf);
} else if (mg_parse_pem(opts->key, mg_str_s("PRIVATE KEY"), &key) == 0) { } else if (mg_parse_pem(opts->key, mg_str_s("PRIVATE KEY"), &key) == 0) {
mg_error(c, "PKCS8 private key format is not supported"); mg_error(c, "PKCS8 private key format is not supported");
} else { } else {
@@ -1682,10 +1700,10 @@ void mg_tls_free(struct mg_connection *c) {
struct tls_data *tls = (struct tls_data *) c->tls; struct tls_data *tls = (struct tls_data *) c->tls;
if (tls != NULL) { if (tls != NULL) {
mg_iobuf_free(&tls->send); mg_iobuf_free(&tls->send);
free((void *) tls->cert_der.buf); mg_free((void *) tls->cert_der.buf);
free((void *) tls->ca_der.buf); mg_free((void *) tls->ca_der.buf);
} }
free(c->tls); mg_free(c->tls);
c->tls = NULL; c->tls = NULL;
} }
@@ -1701,7 +1719,7 @@ long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
while (tls->send.len > 0 && while (tls->send.len > 0 &&
(n = mg_io_send(c, tls->send.buf, tls->send.len)) > 0) { (n = mg_io_send(c, tls->send.buf, tls->send.len)) > 0) {
mg_iobuf_del(&tls->send, 0, (size_t) n); mg_iobuf_del(&tls->send, 0, (size_t) n);
} } // if last chunk fails to be sent, it needs to be flushed
c->is_tls_throttled = (tls->send.len > 0 && n == MG_IO_WAIT); c->is_tls_throttled = (tls->send.len > 0 && n == MG_IO_WAIT);
MG_VERBOSE(("%lu %ld %ld %ld %c %c", c->id, (long) len, (long) tls->send.len, MG_VERBOSE(("%lu %ld %ld %ld %c %c", c->id, (long) len, (long) tls->send.len,
n, was_throttled ? 'T' : 't', c->is_tls_throttled ? 'T' : 't')); n, was_throttled ? 'T' : 't', c->is_tls_throttled ? 'T' : 't'));
@@ -1743,6 +1761,15 @@ size_t mg_tls_pending(struct mg_connection *c) {
return tls != NULL ? tls->recv_len : 0; return tls != NULL ? tls->recv_len : 0;
} }
void mg_tls_flush(struct mg_connection *c) {
struct tls_data *tls = (struct tls_data *) c->tls;
long n;
while (tls->send.len > 0 &&
(n = mg_io_send(c, tls->send.buf, tls->send.len)) > 0) {
mg_iobuf_del(&tls->send, 0, (size_t) n);
}
}
void mg_tls_ctx_init(struct mg_mgr *mgr) { void mg_tls_ctx_init(struct mg_mgr *mgr) {
(void) mgr; (void) mgr;
} }
+2 -2
View File
@@ -20,8 +20,8 @@
#if defined(_MSC_VER) || defined(__cplusplus) #if defined(_MSC_VER) || defined(__cplusplus)
// add restrict support // add restrict support
#if (defined(_MSC_VER) && _MSC_VER >= 1900) || defined(__clang__) || \ #if ((defined(_MSC_VER) && _MSC_VER >= 1900) && !defined(__cplusplus)) || \
defined(__GNUC__) defined(__clang__) || defined(__GNUC__)
#define restrict __restrict #define restrict __restrict
#else #else
#define restrict #define restrict
+3
View File
@@ -6,7 +6,9 @@
#include "arch.h" #include "arch.h"
#include "config.h" #include "config.h"
#include "tls.h"
#if MG_TLS == MG_TLS_BUILTIN
#ifndef __PORTABLE_8439_H #ifndef __PORTABLE_8439_H
#define __PORTABLE_8439_H #define __PORTABLE_8439_H
#if defined(__cplusplus) #if defined(__cplusplus)
@@ -108,3 +110,4 @@ PORTABLE_8439_DECL size_t mg_chacha20_poly1305_decrypt(
} }
#endif #endif
#endif #endif
#endif
+3
View File
@@ -21,6 +21,9 @@ size_t mg_tls_pending(struct mg_connection *c) {
(void) c; (void) c;
return 0; return 0;
} }
void mg_tls_flush(struct mg_connection *c) {
(void) c;
}
void mg_tls_ctx_init(struct mg_mgr *mgr) { void mg_tls_ctx_init(struct mg_mgr *mgr) {
(void) mgr; (void) mgr;
} }
+28 -10
View File
@@ -1,5 +1,8 @@
#include "log.h" #include "log.h"
#include "printf.h"
#include "profile.h"
#include "tls.h" #include "tls.h"
#include "util.h"
#if MG_TLS == MG_TLS_MBED #if MG_TLS == MG_TLS_MBED
@@ -9,6 +12,13 @@
#define MG_MBEDTLS_RNG_GET #define MG_MBEDTLS_RNG_GET
#endif #endif
static int mg_tls_err(struct mg_connection *c, int rc) {
char s[80];
mbedtls_strerror(rc, s, sizeof(s));
MG_ERROR(("%lu %s", ((struct mg_connection *) c)->id, s));
return rc;
}
static int mg_mbed_rng(void *ctx, unsigned char *buf, size_t len) { static int mg_mbed_rng(void *ctx, unsigned char *buf, size_t len) {
mg_random(buf, len); mg_random(buf, len);
(void) ctx; (void) ctx;
@@ -49,7 +59,7 @@ void mg_tls_free(struct mg_connection *c) {
#ifdef MBEDTLS_SSL_SESSION_TICKETS #ifdef MBEDTLS_SSL_SESSION_TICKETS
mbedtls_ssl_ticket_free(&tls->ticket); mbedtls_ssl_ticket_free(&tls->ticket);
#endif #endif
free(tls); mg_free(tls);
c->tls = NULL; c->tls = NULL;
} }
} }
@@ -84,7 +94,7 @@ void mg_tls_handshake(struct mg_connection *c) {
MG_VERBOSE(("%lu pending, %d%d %d (-%#x)", c->id, c->is_connecting, MG_VERBOSE(("%lu pending, %d%d %d (-%#x)", c->id, c->is_connecting,
c->is_tls_hs, rc, -rc)); c->is_tls_hs, rc, -rc));
} else { } else {
mg_error(c, "TLS handshake: -%#x", -rc); // Error mg_error(c, "TLS handshake: -%#x", -mg_tls_err(c, rc)); // Error
} }
} }
@@ -95,7 +105,7 @@ static void debug_cb(void *c, int lev, const char *s, int n, const char *s2) {
} }
void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) { void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls)); struct mg_tls *tls = (struct mg_tls *) mg_calloc(1, sizeof(*tls));
int rc = 0; int rc = 0;
c->tls = tls; c->tls = tls;
if (c->tls == NULL) { if (c->tls == NULL) {
@@ -122,7 +132,7 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
&tls->conf, &tls->conf,
c->is_client ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER, c->is_client ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER,
MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
mg_error(c, "tls defaults %#x", -rc); mg_error(c, "tls defaults %#x", -mg_tls_err(c, rc));
goto fail; goto fail;
} }
mbedtls_ssl_conf_rng(&tls->conf, mg_mbed_rng, c); mbedtls_ssl_conf_rng(&tls->conf, mg_mbed_rng, c);
@@ -138,7 +148,7 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
char *host = mg_mprintf("%.*s", opts->name.len, opts->name.buf); char *host = mg_mprintf("%.*s", opts->name.len, opts->name.buf);
mbedtls_ssl_set_hostname(&tls->ssl, host); mbedtls_ssl_set_hostname(&tls->ssl, host);
MG_DEBUG(("%lu hostname verification: %s", c->id, host)); MG_DEBUG(("%lu hostname verification: %s", c->id, host));
free(host); mg_free(host);
} }
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED); mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
} }
@@ -146,7 +156,7 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
if (!mg_load_key(opts->key, &tls->pk)) goto fail; if (!mg_load_key(opts->key, &tls->pk)) goto fail;
if (tls->cert.version && if (tls->cert.version &&
(rc = mbedtls_ssl_conf_own_cert(&tls->conf, &tls->cert, &tls->pk)) != 0) { (rc = mbedtls_ssl_conf_own_cert(&tls->conf, &tls->cert, &tls->pk)) != 0) {
mg_error(c, "own cert %#x", -rc); mg_error(c, "own cert %#x", -mg_tls_err(c, rc));
goto fail; goto fail;
} }
@@ -157,7 +167,7 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
#endif #endif
if ((rc = mbedtls_ssl_setup(&tls->ssl, &tls->conf)) != 0) { if ((rc = mbedtls_ssl_setup(&tls->ssl, &tls->conf)) != 0) {
mg_error(c, "setup err %#x", -rc); mg_error(c, "setup err %#x", -mg_tls_err(c, rc));
goto fail; goto fail;
} }
c->is_tls = 1; c->is_tls = 1;
@@ -204,13 +214,21 @@ long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
tls->throttled_buf = (unsigned char *)buf; // MbedTLS code actually ignores tls->throttled_buf = (unsigned char *)buf; // MbedTLS code actually ignores
tls->throttled_len = len; // these, but let's play API rules tls->throttled_len = len; // these, but let's play API rules
return (long) len; // already encripted that when throttled return (long) len; // already encripted that when throttled
} } // if last chunk fails to be sent, it needs to be flushed
if (n <= 0) return MG_IO_ERR; if (n <= 0) return MG_IO_ERR;
return n; return n;
} }
void mg_tls_flush(struct mg_connection *c) {
struct mg_tls *tls = (struct mg_tls *) c->tls;
if (c->is_tls_throttled) {
long n = mbedtls_ssl_write(&tls->ssl, tls->throttled_buf, tls->throttled_len);
c->is_tls_throttled = (n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE);
}
}
void mg_tls_ctx_init(struct mg_mgr *mgr) { void mg_tls_ctx_init(struct mg_mgr *mgr) {
struct mg_tls_ctx *ctx = (struct mg_tls_ctx *) calloc(1, sizeof(*ctx)); struct mg_tls_ctx *ctx = (struct mg_tls_ctx *) mg_calloc(1, sizeof(*ctx));
if (ctx == NULL) { if (ctx == NULL) {
MG_ERROR(("TLS context init OOM")); MG_ERROR(("TLS context init OOM"));
} else { } else {
@@ -233,7 +251,7 @@ void mg_tls_ctx_free(struct mg_mgr *mgr) {
#ifdef MBEDTLS_SSL_SESSION_TICKETS #ifdef MBEDTLS_SSL_SESSION_TICKETS
mbedtls_ssl_ticket_free(&ctx->tickets); mbedtls_ssl_ticket_free(&ctx->tickets);
#endif #endif
free(ctx); mg_free(ctx);
mgr->tls_ctx = NULL; mgr->tls_ctx = NULL;
} }
} }
+1
View File
@@ -7,6 +7,7 @@
#if MG_TLS == MG_TLS_MBED #if MG_TLS == MG_TLS_MBED
#include <mbedtls/debug.h> #include <mbedtls/debug.h>
#include <mbedtls/error.h>
#include <mbedtls/net_sockets.h> #include <mbedtls/net_sockets.h>
#include <mbedtls/ssl.h> #include <mbedtls/ssl.h>
#include <mbedtls/ssl_ticket.h> #include <mbedtls/ssl_ticket.h>
+9 -3
View File
@@ -1,5 +1,6 @@
#include "printf.h" #include "printf.h"
#include "tls.h" #include "tls.h"
#include "util.h"
#if MG_TLS == MG_TLS_OPENSSL || MG_TLS == MG_TLS_WOLFSSL #if MG_TLS == MG_TLS_OPENSSL || MG_TLS == MG_TLS_WOLFSSL
@@ -104,6 +105,7 @@ static void ssl_keylog_cb(const SSL *ssl, const char *line) {
fprintf(f, "%s\n", line); fprintf(f, "%s\n", line);
fflush(f); fflush(f);
fclose(f); fclose(f);
(void) ssl;
} }
#endif #endif
@@ -113,12 +115,12 @@ void mg_tls_free(struct mg_connection *c) {
SSL_free(tls->ssl); SSL_free(tls->ssl);
SSL_CTX_free(tls->ctx); SSL_CTX_free(tls->ctx);
BIO_meth_free(tls->bm); BIO_meth_free(tls->bm);
free(tls); mg_free(tls);
c->tls = NULL; c->tls = NULL;
} }
void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) { void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls)); struct mg_tls *tls = (struct mg_tls *) mg_calloc(1, sizeof(*tls));
const char *id = "mongoose"; const char *id = "mongoose";
static unsigned char s_initialised = 0; static unsigned char s_initialised = 0;
BIO *bio = NULL; BIO *bio = NULL;
@@ -211,7 +213,7 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
X509_VERIFY_PARAM_set1_host(SSL_get0_param(tls->ssl), s, 0); X509_VERIFY_PARAM_set1_host(SSL_get0_param(tls->ssl), s, 0);
#endif #endif
SSL_set_tlsext_host_name(tls->ssl, s); SSL_set_tlsext_host_name(tls->ssl, s);
free(s); mg_free(s);
} }
#endif #endif
#if MG_TLS == MG_TLS_WOLFSSL #if MG_TLS == MG_TLS_WOLFSSL
@@ -270,6 +272,10 @@ long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
return n; return n;
} }
void mg_tls_flush(struct mg_connection *c) {
(void) c;
}
void mg_tls_ctx_init(struct mg_mgr *mgr) { void mg_tls_ctx_init(struct mg_mgr *mgr) {
(void) mgr; (void) mgr;
} }
+36 -25
View File
@@ -1,5 +1,6 @@
#include "tls.h" #include "tls.h"
#include "tls_rsa.h" #include "tls_rsa.h"
#include "util.h"
#if MG_TLS == MG_TLS_BUILTIN #if MG_TLS == MG_TLS_BUILTIN
@@ -62,7 +63,7 @@ typedef uint16_t comp; /**< A single precision component. */
typedef uint32_t long_comp; /**< A double precision component. */ typedef uint32_t long_comp; /**< A double precision component. */
typedef int32_t slong_comp; /**< A signed double precision component. */ typedef int32_t slong_comp; /**< A signed double precision component. */
#else /* regular 32 bit */ #else /* regular 32 bit */
#ifdef WIN32 #ifdef _MSC_VER
#define COMP_RADIX 4294967296i64 #define COMP_RADIX 4294967296i64
#define COMP_MAX 0xFFFFFFFFFFFFFFFFui64 #define COMP_MAX 0xFFFFFFFFFFFFFFFFui64
#else #else
@@ -158,10 +159,10 @@ typedef struct _BI_CTX BI_CTX;
*/ */
NS_INTERNAL BI_CTX *bi_initialize(void); NS_INTERNAL BI_CTX *bi_initialize(void);
//NS_INTERNAL void bi_terminate(BI_CTX *ctx); NS_INTERNAL void bi_terminate(BI_CTX *ctx);
NS_INTERNAL void bi_permanent(bigint *bi); NS_INTERNAL void bi_permanent(bigint *bi);
NS_INTERNAL void bi_depermanent(bigint *bi); NS_INTERNAL void bi_depermanent(bigint *bi);
//NS_INTERNAL void bi_clear_cache(BI_CTX *ctx); NS_INTERNAL void bi_clear_cache(BI_CTX *ctx);
NS_INTERNAL void bi_free(BI_CTX *ctx, bigint *bi); NS_INTERNAL void bi_free(BI_CTX *ctx, bigint *bi);
NS_INTERNAL bigint *bi_copy(bigint *bi); NS_INTERNAL bigint *bi_copy(bigint *bi);
NS_INTERNAL bigint *bi_clone(BI_CTX *ctx, const bigint *bi); NS_INTERNAL bigint *bi_clone(BI_CTX *ctx, const bigint *bi);
@@ -183,7 +184,7 @@ NS_INTERNAL bigint *bi_mod_power2(BI_CTX *ctx, bigint *bi,
#endif #endif
NS_INTERNAL int bi_compare(bigint *bia, bigint *bib); NS_INTERNAL int bi_compare(bigint *bia, bigint *bib);
NS_INTERNAL void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset); NS_INTERNAL void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset);
//NS_INTERNAL void bi_free_mod(BI_CTX *ctx, int mod_offset); NS_INTERNAL void bi_free_mod(BI_CTX *ctx, int mod_offset);
#ifdef CONFIG_SSL_FULL_MODE #ifdef CONFIG_SSL_FULL_MODE
NS_INTERNAL void bi_print(const char *label, bigint *bi); NS_INTERNAL void bi_print(const char *label, bigint *bi);
@@ -309,8 +310,8 @@ static void check(const bigint *bi);
* @return A bigint context. * @return A bigint context.
*/ */
NS_INTERNAL BI_CTX *bi_initialize(void) { NS_INTERNAL BI_CTX *bi_initialize(void) {
/* calloc() sets everything to zero */ /* mg_calloc() sets everything to zero */
BI_CTX *ctx = (BI_CTX *) calloc(1, sizeof(BI_CTX)); BI_CTX *ctx = (BI_CTX *) mg_calloc(1, sizeof(BI_CTX));
/* the radix */ /* the radix */
ctx->bi_radix = alloc(ctx, 2); ctx->bi_radix = alloc(ctx, 2);
@@ -320,7 +321,6 @@ NS_INTERNAL BI_CTX *bi_initialize(void) {
return ctx; return ctx;
} }
#if 0
/** /**
* @brief Close the bigint context and free any resources. * @brief Close the bigint context and free any resources.
* *
@@ -340,7 +340,7 @@ NS_INTERNAL void bi_terminate(BI_CTX *ctx) {
} }
bi_clear_cache(ctx); bi_clear_cache(ctx);
free(ctx); mg_free(ctx);
} }
/** /**
@@ -353,14 +353,13 @@ NS_INTERNAL void bi_clear_cache(BI_CTX *ctx) {
for (p = ctx->free_list; p != NULL; p = pn) { for (p = ctx->free_list; p != NULL; p = pn) {
pn = p->next; pn = p->next;
free(p->comps); mg_free(p->comps);
free(p); mg_free(p);
} }
ctx->free_count = 0; ctx->free_count = 0;
ctx->free_list = NULL; ctx->free_list = NULL;
} }
#endif
/** /**
* @brief Increment the number of references to this object. * @brief Increment the number of references to this object.
@@ -930,7 +929,6 @@ NS_INTERNAL void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset) {
#endif #endif
} }
#if 0
/** /**
* @brief Used when cleaning various bigints at the end of a session. * @brief Used when cleaning various bigints at the end of a session.
* @param ctx [in] The bigint session context. * @param ctx [in] The bigint session context.
@@ -952,7 +950,6 @@ void bi_free_mod(BI_CTX *ctx, int mod_offset) {
bi_depermanent(ctx->bi_normalised_mod[mod_offset]); bi_depermanent(ctx->bi_normalised_mod[mod_offset]);
bi_free(ctx, ctx->bi_normalised_mod[mod_offset]); bi_free(ctx, ctx->bi_normalised_mod[mod_offset]);
} }
#endif
/** /**
* Perform a standard multiplication between two bigints. * Perform a standard multiplication between two bigints.
@@ -1192,9 +1189,9 @@ NS_INTERNAL int bi_compare(bigint *bia, bigint *bib) {
static void more_comps(bigint *bi, int n) { static void more_comps(bigint *bi, int n) {
if (n > bi->max_comps) { if (n > bi->max_comps) {
int max = MAX(bi->max_comps * 2, n); int max = MAX(bi->max_comps * 2, n);
void *p = calloc(1, (size_t) max * COMP_BYTE_SIZE); void *p = mg_calloc(1, (size_t) max * COMP_BYTE_SIZE);
if (p != NULL && bi->size > 0) memcpy(p, bi->comps, (size_t) bi->max_comps * COMP_BYTE_SIZE); if (p != NULL && bi->size > 0) memcpy(p, bi->comps, (size_t) bi->max_comps * COMP_BYTE_SIZE);
free(bi->comps); mg_free(bi->comps);
bi->max_comps = (short) max; bi->max_comps = (short) max;
bi->comps = (comp *) p; bi->comps = (comp *) p;
} }
@@ -1229,8 +1226,8 @@ static bigint *alloc(BI_CTX *ctx, int size) {
more_comps(biR, size); more_comps(biR, size);
} else { } else {
/* No free bigints available - create a new one. */ /* No free bigints available - create a new one. */
biR = (bigint *) calloc(1, sizeof(bigint)); biR = (bigint *) mg_calloc(1, sizeof(bigint));
biR->comps = (comp *) calloc(1, (size_t) size * COMP_BYTE_SIZE); biR->comps = (comp *) mg_calloc(1, (size_t) size * COMP_BYTE_SIZE);
biR->max_comps = (short) size; /* give some space to spare */ biR->max_comps = (short) size; /* give some space to spare */
} }
@@ -1419,7 +1416,7 @@ static void precompute_slide_window(BI_CTX *ctx, int window, bigint *g1) {
k <<= 1; k <<= 1;
} }
ctx->g = (bigint **) calloc(1, k * sizeof(bigint *)); ctx->g = (bigint **) mg_calloc(1, k * sizeof(bigint *));
ctx->g[0] = bi_clone(ctx, g1); ctx->g[0] = bi_clone(ctx, g1);
bi_permanent(ctx->g[0]); bi_permanent(ctx->g[0]);
g2 = bi_residue(ctx, bi_square(ctx, ctx->g[0])); /* g^2 */ g2 = bi_residue(ctx, bi_square(ctx, ctx->g[0])); /* g^2 */
@@ -1470,7 +1467,7 @@ NS_INTERNAL bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp) {
/* work out the slide constants */ /* work out the slide constants */
precompute_slide_window(ctx, window_size, bi); precompute_slide_window(ctx, window_size, bi);
#else /* just one constant */ #else /* just one constant */
ctx->g = (bigint **) calloc(1, sizeof(bigint *)); ctx->g = (bigint **) mg_calloc(1, sizeof(bigint *));
ctx->g[0] = bi_clone(ctx, bi); ctx->g[0] = bi_clone(ctx, bi);
ctx->window = 1; ctx->window = 1;
bi_permanent(ctx->g[0]); bi_permanent(ctx->g[0]);
@@ -1513,7 +1510,7 @@ NS_INTERNAL bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp) {
bi_free(ctx, ctx->g[i]); bi_free(ctx, ctx->g[i]);
} }
free(ctx->g); mg_free(ctx->g);
bi_free(ctx, bi); bi_free(ctx, bi);
bi_free(ctx, biexp); bi_free(ctx, biexp);
#if defined CONFIG_BIGINT_MONTGOMERY #if defined CONFIG_BIGINT_MONTGOMERY
@@ -1562,18 +1559,32 @@ NS_INTERNAL bigint *bi_crt(BI_CTX *ctx, bigint *bi, bigint *dP, bigint *dQ,
} }
#endif #endif
// Proper lib usage:
// - BI_CTX *c = bi_initialize()
// - allocate bigints (e.g.: calling bi_import(), int_to_bi(), ...)
// - function calls, allocate bigints, etc.
// - bigint *n = bi_import(c, indata, insize)
// - bi_set_mod(c, n, x)
// - mod function calls
// - bigint *nn = bi_mod_pwr(c, m, e) <-- frees m, e
// - bi_free_mod(c, x) <-- frees n
// - bi_export(c, nn, outdata, outsize) <-- frees nn
// - function calls
// - free bigints calling bi_free()
// - bi_terminate(c) <-- frees c
int mg_rsa_mod_pow(const uint8_t *mod, size_t modsz, const uint8_t *exp, size_t expsz, const uint8_t *msg, size_t msgsz, uint8_t *out, size_t outsz) { int mg_rsa_mod_pow(const uint8_t *mod, size_t modsz, const uint8_t *exp, size_t expsz, const uint8_t *msg, size_t msgsz, uint8_t *out, size_t outsz) {
BI_CTX *bi_ctx = bi_initialize(); BI_CTX *bi_ctx = bi_initialize();
bigint *m1;
bigint *n = bi_import(bi_ctx, mod, (int) modsz); bigint *n = bi_import(bi_ctx, mod, (int) modsz);
bigint *e = bi_import(bi_ctx, exp, (int) expsz); bigint *e = bi_import(bi_ctx, exp, (int) expsz);
bigint *h = bi_import(bi_ctx, msg, (int) msgsz); bigint *h = bi_import(bi_ctx, msg, (int) msgsz);
bi_set_mod(bi_ctx, n, 0); bi_set_mod(bi_ctx, n, 0);
bigint *m1 = bi_mod_power(bi_ctx, h, e); m1 = bi_mod_power(bi_ctx, h, e);
bi_free_mod(bi_ctx, 0);
bi_export(bi_ctx, m1, out, (int) outsz); bi_export(bi_ctx, m1, out, (int) outsz);
bi_free(bi_ctx, n); bi_terminate(bi_ctx);
bi_free(bi_ctx, e);
bi_free(bi_ctx, h);
bi_free(bi_ctx, m1);
return 0; return 0;
} }
+23 -1
View File
@@ -17,6 +17,13 @@ bool mg_random(void *buf, size_t len) {
#if MG_ARCH == MG_ARCH_ESP32 #if MG_ARCH == MG_ARCH_ESP32
while (len--) *p++ = (unsigned char) (esp_random() & 255); while (len--) *p++ = (unsigned char) (esp_random() & 255);
success = true; success = true;
#elif MG_ARCH == MG_ARCH_CUBE && defined(HAL_RNG_MODULE_ENABLED)
extern RNG_HandleTypeDef hrng;
for (size_t n = 0; n < len; n += sizeof(uint32_t)) {
uint32_t r = HAL_RNG_ReadLastRandomNumber(&hrng);
memcpy((char *) buf + n, &r, n + sizeof(r) > len ? len - n : sizeof(r));
}
success = true;
#elif MG_ARCH == MG_ARCH_PICOSDK #elif MG_ARCH == MG_ARCH_PICOSDK
while (len--) *p++ = (unsigned char) (get_rand_32() & 255); while (len--) *p++ = (unsigned char) (get_rand_32() & 255);
success = true; success = true;
@@ -127,6 +134,7 @@ int mg_check_ip_acl(struct mg_str acl, struct mg_addr *remote_ip) {
bool mg_path_is_sane(const struct mg_str path) { bool mg_path_is_sane(const struct mg_str path) {
const char *s = path.buf; const char *s = path.buf;
size_t n = path.len; size_t n = path.len;
if (path.buf[0] == '~') return false; // Starts with ~
if (path.buf[0] == '.' && path.buf[1] == '.') return false; // Starts with .. if (path.buf[0] == '.' && path.buf[1] == '.') return false; // Starts with ..
for (; s[0] != '\0' && n > 0; s++, n--) { for (; s[0] != '\0' && n > 0; s++, n--) {
if ((s[0] == '/' || s[0] == '\\') && n >= 2) { // Subdir? if ((s[0] == '/' || s[0] == '\\') && n >= 2) { // Subdir?
@@ -146,7 +154,9 @@ uint64_t mg_millis(void) {
#elif MG_ARCH == MG_ARCH_ESP8266 || MG_ARCH == MG_ARCH_ESP32 || \ #elif MG_ARCH == MG_ARCH_ESP8266 || MG_ARCH == MG_ARCH_ESP32 || \
MG_ARCH == MG_ARCH_FREERTOS MG_ARCH == MG_ARCH_FREERTOS
return xTaskGetTickCount() * portTICK_PERIOD_MS; return xTaskGetTickCount() * portTICK_PERIOD_MS;
#elif MG_ARCH == MG_ARCH_AZURERTOS #elif MG_ARCH == MG_ARCH_CUBE
return (uint64_t) HAL_GetTick();
#elif MG_ARCH == MG_ARCH_THREADX
return tx_time_get() * (1000 /* MS per SEC */ / TX_TIMER_TICKS_PER_SECOND); return tx_time_get() * (1000 /* MS per SEC */ / TX_TIMER_TICKS_PER_SECOND);
#elif MG_ARCH == MG_ARCH_TIRTOS #elif MG_ARCH == MG_ARCH_TIRTOS
return (uint64_t) Clock_getTicks(); return (uint64_t) Clock_getTicks();
@@ -198,3 +208,15 @@ void mg_delayms(unsigned int ms) {
uint64_t to = mg_millis() + ms + 1; uint64_t to = mg_millis() + ms + 1;
while (mg_millis() < to) (void) 0; while (mg_millis() < to) (void) 0;
} }
#if MG_ENABLE_CUSTOM_CALLOC
#else
void *mg_calloc(size_t count, size_t size) {
return calloc(count, size);
}
void mg_free(void *ptr) {
free(ptr);
}
#endif
+12 -1
View File
@@ -11,6 +11,8 @@
#define assert(x) #define assert(x)
#endif #endif
void *mg_calloc(size_t count, size_t size);
void mg_free(void *ptr);
void mg_bzero(volatile unsigned char *buf, size_t len); void mg_bzero(volatile unsigned char *buf, size_t len);
bool mg_random(void *buf, size_t len); bool mg_random(void *buf, size_t len);
char *mg_random_str(char *buf, size_t len); char *mg_random_str(char *buf, size_t len);
@@ -70,9 +72,14 @@ uint32_t mg_ntohl(uint32_t net);
#define MG_ROUND_UP(x, a) ((a) == 0 ? (x) : ((((x) + (a) -1) / (a)) * (a))) #define MG_ROUND_UP(x, a) ((a) == 0 ? (x) : ((((x) + (a) -1) / (a)) * (a)))
#define MG_ROUND_DOWN(x, a) ((a) == 0 ? (x) : (((x) / (a)) * (a))) #define MG_ROUND_DOWN(x, a) ((a) == 0 ? (x) : (((x) / (a)) * (a)))
#if defined(__GNUC__) #if defined(__GNUC__) && defined(__arm__)
#ifdef __ZEPHYR__
#define MG_ARM_DISABLE_IRQ() __asm__ __volatile__("cpsid i" : : : "memory")
#define MG_ARM_ENABLE_IRQ() __asm__ __volatile__("cpsie i" : : : "memory")
#else
#define MG_ARM_DISABLE_IRQ() asm volatile("cpsid i" : : : "memory") #define MG_ARM_DISABLE_IRQ() asm volatile("cpsid i" : : : "memory")
#define MG_ARM_ENABLE_IRQ() asm volatile("cpsie i" : : : "memory") #define MG_ARM_ENABLE_IRQ() asm volatile("cpsie i" : : : "memory")
#endif // !ZEPHYR
#elif defined(__CCRH__) #elif defined(__CCRH__)
#define MG_RH850_DISABLE_IRQ() __DI() #define MG_RH850_DISABLE_IRQ() __DI()
#define MG_RH850_ENABLE_IRQ() __EI() #define MG_RH850_ENABLE_IRQ() __EI()
@@ -86,7 +93,11 @@ uint32_t mg_ntohl(uint32_t net);
#elif defined(__ARMCC_VERSION) #elif defined(__ARMCC_VERSION)
#define MG_DSB() __builtin_arm_dsb(0xf) #define MG_DSB() __builtin_arm_dsb(0xf)
#elif defined(__GNUC__) && defined(__arm__) && defined(__thumb__) #elif defined(__GNUC__) && defined(__arm__) && defined(__thumb__)
#ifdef __ZEPHYR__
#define MG_DSB() __asm__("DSB 0xf")
#else
#define MG_DSB() asm("DSB 0xf") #define MG_DSB() asm("DSB 0xf")
#endif // !ZEPHYR
#elif defined(__ICCARM__) #elif defined(__ICCARM__)
#define MG_DSB() __iar_builtin_DSB() #define MG_DSB() __iar_builtin_DSB()
#else #else
+1 -1
View File
@@ -1 +1 @@
#define MG_VERSION "7.18" #define MG_VERSION "7.19"
+3 -1
View File
@@ -1,7 +1,9 @@
#include "wifi.h" #include "wifi.h"
#if (!defined(MG_ENABLE_DRIVER_PICO_W) || !MG_ENABLE_DRIVER_PICO_W) && \ #if (!defined(MG_ENABLE_DRIVER_PICO_W) || !MG_ENABLE_DRIVER_PICO_W) && \
(!defined(MG_ENABLE_DRIVER_CYW) || !MG_ENABLE_DRIVER_CYW) (!defined(MG_ENABLE_DRIVER_CYW) || !MG_ENABLE_DRIVER_CYW) && \
(!defined(MG_ENABLE_DRIVER_CYW_SDIO) || !MG_ENABLE_DRIVER_CYW_SDIO)
bool mg_wifi_scan(void) { bool mg_wifi_scan(void) {
MG_ERROR(("No Wi-Fi driver enabled")); MG_ERROR(("No Wi-Fi driver enabled"));
+34 -17
View File
@@ -9,12 +9,12 @@ CWD ?= $(realpath $(CURDIR))
ROOT_DIR = $(realpath $(CWD)/..) ROOT_DIR = $(realpath $(CWD)/..)
ENV ?= -e Tmp=. -e WINEDEBUG=-all ENV ?= -e Tmp=. -e WINEDEBUG=-all
DOCKER_BIN ?= docker DOCKER_BIN ?= docker
DOCKER ?= $(DOCKER_BIN) run --platform linux/amd64 --rm $(ENV) -v $(ROOT_DIR):$(ROOT_DIR) -w $(CWD) # use net=host so all tests have the same network and can access localhost and ad hoc services
VCFLAGS = /nologo /W3 /O2 /MD /I. $(DEFS) $(TFLAGS) DOCKER ?= $(DOCKER_BIN) run --platform linux/amd64 --net=host --rm $(ENV) -v $(ROOT_DIR):$(ROOT_DIR) -w $(CWD)
VCFLAGS ?= /nologo /W3 /O2 /MD /I.
IPV6 ?= 1 IPV6 ?= 1
ASAN ?= -fsanitize=address,undefined,alignment -fno-sanitize-recover=all -fno-omit-frame-pointer -fno-common ASAN ?= -fsanitize=address,undefined,alignment -fno-sanitize-recover=all -fno-omit-frame-pointer -fno-common
ASAN_OPTIONS ?= detect_leaks=1 ASAN_OPTIONS ?= detect_leaks=1
REFPROJS := $(dir $(wildcard ../reference-projects/windows-macos-linux/*/Makefile))
# This does not include ESP32, ESP8266, Microchip; all examples that are directly placed under an OS tutorial. Also, it is needed that way... # This does not include ESP32, ESP8266, Microchip; all examples that are directly placed under an OS tutorial. Also, it is needed that way...
TUTORIALS_EMBEDDED := $(dir $(wildcard ../tutorials/infineon/*/Makefile)) $(dir $(wildcard ../tutorials/nxp/*/Makefile)) $(dir $(wildcard ../tutorials/pico-sdk/*/Makefile)) $(dir $(wildcard ../tutorials/renesas/*/Makefile)) $(dir $(wildcard ../tutorials/stm32/*/Makefile)) $(dir $(wildcard ../tutorials/ti/*/Makefile)) $(dir $(wildcard ../tutorials/wch/*/Makefile)) TUTORIALS_EMBEDDED := $(dir $(wildcard ../tutorials/infineon/*/Makefile)) $(dir $(wildcard ../tutorials/nxp/*/Makefile)) $(dir $(wildcard ../tutorials/pico-sdk/*/Makefile)) $(dir $(wildcard ../tutorials/renesas/*/Makefile)) $(dir $(wildcard ../tutorials/stm32/*/Makefile)) $(dir $(wildcard ../tutorials/ti/*/Makefile)) $(dir $(wildcard ../tutorials/wch/*/Makefile))
TUTORIALS := ../tutorials/micropython/ $(filter-out $(TUTORIALS_EMBEDDED), $(dir $(wildcard ../tutorials/*/*/Makefile))) TUTORIALS := ../tutorials/micropython/ $(filter-out $(TUTORIALS_EMBEDDED), $(dir $(wildcard ../tutorials/*/*/Makefile)))
@@ -75,13 +75,13 @@ LDFLAGS += -L$(WOLFSSL)/lib -lwolfssl
endif endif
ifeq "$(SSL)" "BUILTIN" ifeq "$(SSL)" "BUILTIN"
CFLAGS += -DMG_TLS=MG_TLS_BUILTIN DEFS += -DMG_TLS=MG_TLS_BUILTIN
endif endif
all: all:
$(MAKE) -C ../tutorials/http/http-server $(MAKE) -C ../tutorials/http/http-server
tall: mg_prefix unamalgamated test mip_test arm tutorials vc98 vc17 vc22 mingw mingw++ fuzz tall: mg_prefix unamalgamated test valgrind fuzz fuzz_tls vc98 vc17 vc22 mingw mingw++ arm armhf riscv s390 tutorials tutorials_win tutorials_embedded mip_test mip_vc98
mip_test: mip_test.c mongoose.c mongoose.h packed_fs.c Makefile mip_test: mip_test.c mongoose.c mongoose.h packed_fs.c Makefile
$(CC) mip_test.c packed_fs.c $(CFLAGS) $(LDFLAGS) -o $@ $(CC) mip_test.c packed_fs.c $(CFLAGS) $(LDFLAGS) -o $@
@@ -91,6 +91,10 @@ mip_tap_test: mip_tap_test.c mongoose.c mongoose.h packed_fs.c Makefile tls_mult
$(CC) mip_tap_test.c packed_fs.c $(CFLAGS) $(LDFLAGS) -o $@ $(CC) mip_tap_test.c packed_fs.c $(CFLAGS) $(LDFLAGS) -o $@
ASAN_OPTIONS=$(ASAN_OPTIONS) $(RUN) ./$@ ASAN_OPTIONS=$(ASAN_OPTIONS) $(RUN) ./$@
mip_vc98: mip_test.c mongoose.c mongoose.h packed_fs.c Makefile
$(DOCKER) mdashnet/vc98 wine cl mip_test.c packed_fs.c $(VCFLAGS) $(DEFS) $(TFLAGS) /Fe$@.exe
$(DOCKER) mdashnet/vc98 wine $@.exe
packed_fs.c: Makefile data/ssi.h fuzz.c data/a.txt data/ca.pem certs/ca.crt certs/server.crt certs/server.key packed_fs.c: Makefile data/ssi.h fuzz.c data/a.txt data/ca.pem certs/ca.crt certs/server.crt certs/server.key
$(CC) $(CFLAGS) pack.c -o pack $(CC) $(CFLAGS) pack.c -o pack
$(RUN) ./pack Makefile data/ssi.h fuzz.c data/a.txt data/range.txt data/ca.pem certs/ca.crt certs/server.crt certs/server.key certs/client.key certs/client.crt > $@ $(RUN) ./pack Makefile data/ssi.h fuzz.c data/a.txt data/range.txt data/ca.pem certs/ca.crt certs/server.crt certs/server.key certs/client.key certs/client.crt > $@
@@ -113,7 +117,7 @@ unamalgamated: $(HDRS) Makefile packed_fs.c
fuzz: ASAN = -fsanitize=fuzzer,signed-integer-overflow,address,undefined fuzz: ASAN = -fsanitize=fuzzer,signed-integer-overflow,address,undefined
fuzz: mongoose.c mongoose.h Makefile fuzz.c fuzz: mongoose.c mongoose.h Makefile fuzz.c
$(CC) fuzz.c $(OPTS) $(WARN) $(INCS) $(TFLAGS) $(ASAN) -o fuzzer $(CC) fuzz.c $(OPTS) $(WARN) $(INCS) $(TFLAGS) $(ASAN) -o fuzzer
$(RUN) ./fuzzer $(RUN) ./fuzzer $(ARGS)
FUZZDATA ?= /tmp/fuzzdata FUZZDATA ?= /tmp/fuzzdata
fuzz2: mongoose.c mongoose.h Makefile fuzz.c fuzz2: mongoose.c mongoose.h Makefile fuzz.c
@@ -123,7 +127,11 @@ fuzz2: mongoose.c mongoose.h Makefile fuzz.c
fuzz_tls: ASAN = -fsanitize=fuzzer,signed-integer-overflow,address,undefined fuzz_tls: ASAN = -fsanitize=fuzzer,signed-integer-overflow,address,undefined
fuzz_tls: mongoose.c mongoose.h Makefile fuzz_tls.c fuzz_tls: mongoose.c mongoose.h Makefile fuzz_tls.c
$(CC) fuzz_tls.c $(OPTS) $(WARN) $(INCS) $(TFLAGS) $(ASAN) -o fuzzer_tls $(CC) fuzz_tls.c $(OPTS) $(WARN) $(INCS) $(TFLAGS) $(ASAN) -o fuzzer_tls
$(RUN) ./fuzzer_tls -max_len=17000 $(RUN) ./fuzzer_tls -max_len=17000 $(ARGS)
fuzz_tls2: mongoose.c mongoose.h Makefile fuzz_tls.c
$(CC) fuzz_tls.c -DMAIN $(OPTS) $(WARN) $(ASAN) $(INCS) -o fuzzer_tls
$(RUN) ./fuzzer_tls $(FUZZDATA)
@@ -132,7 +140,12 @@ test: Makefile mongoose.h $(SRCS) tls_multirec/server
ASAN_OPTIONS=$(ASAN_OPTIONS) $(RUN) ./unit_test ASAN_OPTIONS=$(ASAN_OPTIONS) $(RUN) ./unit_test
tls_multirec/server: FORCE tls_multirec/server: FORCE
ifneq "$(SSL)" ""
ifeq "$(MULTIREC)" ""
$(MAKE) -C tls_multirec CC=gcc $(MAKE) -C tls_multirec CC=gcc
endif
endif
true
FORCE: FORCE:
true true
@@ -156,44 +169,48 @@ misra:
cppcheck --addon=misra --clang -DMG_ENABLE_LINES=1 -DMG_ENABLE_SSI=1 mongoose.c >>/tmp/x 2>&1 cppcheck --addon=misra --clang -DMG_ENABLE_LINES=1 -DMG_ENABLE_SSI=1 mongoose.c >>/tmp/x 2>&1
less /tmp/x less /tmp/x
# https://ddanilov.me/how-signals-are-handled-in-a-docker-container
armhf: ASAN= armhf: ASAN=
armhf: IPV6=0 armhf: IPV6=0
armhf: CC = $(DOCKER) mdashnet/armhf cc armhf: CC = $(DOCKER) mdashnet/armhf cc
armhf: RUN = $(DOCKER) mdashnet/armhf armhf: RUN = $(DOCKER) --init mdashnet/armhf
armhf: test armhf: test
s390: ASAN= s390: ASAN=
s390: IPV6=0 s390: IPV6=0
s390: CFLAGS += -Wno-stringop-overflow
s390: DEFS += -DMG_ENABLE_CHACHA20=0
s390: CC = $(DOCKER) mdashnet/s390 cc s390: CC = $(DOCKER) mdashnet/s390 cc
s390: RUN = $(DOCKER) mdashnet/s390 s390: RUN = $(DOCKER) --init mdashnet/s390
s390: test s390: test
arm: DEFS += -DMG_ENABLE_POSIX_FS=0 -DMG_ENABLE_TCPIP=1 -DMG_ENABLE_TCPIP_DRIVER_INIT=0 -DMG_ARCH=MG_ARCH_NEWLIB -DNO_SLEEP_ABORT arm: DEFS += -DMG_ENABLE_POSIX_FS=0 -DMG_ENABLE_TCPIP=1 -DMG_ENABLE_TCPIP_DRIVER_INIT=0 -DMG_ARCH=MG_ARCH_ARMGCC -DNO_SLEEP_ABORT
arm: mongoose.h $(SRCS) arm: mongoose.h $(SRCS)
$(DOCKER) mdashnet/armgcc arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb $(SRCS) $(OPTS) $(WARN) $(INCS) $(DEFS) $(TFLAGS) -o unit_test -nostartfiles --specs nosys.specs -e 0 $(DOCKER) mdashnet/armgcc arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb $(SRCS) $(OPTS) $(WARN) $(INCS) $(DEFS) $(TFLAGS) -o unit_test -nostartfiles --specs nosys.specs -e 0
riscv: DEFS += -DMG_ENABLE_POSIX_FS=0 -DMG_ENABLE_TCPIP=1 -DMG_ENABLE_TCPIP_DRIVER_INIT=0 -DMG_ARCH=MG_ARCH_NEWLIB -DNO_SLEEP_ABORT riscv: DEFS += -DMG_ENABLE_POSIX_FS=0 -DMG_ENABLE_TCPIP=1 -DMG_ENABLE_TCPIP_DRIVER_INIT=0 -DMG_ARCH=MG_ARCH_ARMGCC -DNO_SLEEP_ABORT
riscv: mongoose.h $(SRCS) riscv: mongoose.h $(SRCS)
$(DOCKER) mdashnet/riscv riscv-none-elf-gcc -march=rv32imc -mabi=ilp32 $(SRCS) $(OPTS) $(WARN) $(INCS) $(DEFS) $(TFLAGS) -o unit_test $(DOCKER) mdashnet/riscv riscv-none-elf-gcc -march=rv32imc -mabi=ilp32 $(SRCS) $(OPTS) $(WARN) $(INCS) $(DEFS) $(TFLAGS) -o unit_test
vc98: Makefile mongoose.h $(SRCS) vc98: Makefile mongoose.h $(SRCS)
$(DOCKER) mdashnet/vc98 wine cl $(SRCS) $(VCFLAGS) /Fe$@.exe $(DOCKER) mdashnet/vc98 wine cl $(SRCS) $(VCFLAGS) $(DEFS) $(TFLAGS) /Fe$@.exe
$(DOCKER) mdashnet/vc98 wine $@.exe $(DOCKER) mdashnet/vc98 wine $@.exe
vc17: Makefile mongoose.h $(SRCS) vc17: Makefile mongoose.h $(SRCS)
$(DOCKER) mdashnet/vc17 wine64 cl $(SRCS) $(VCFLAGS) /Fe$@.exe $(DOCKER) mdashnet/vc17 wine64 cl $(SRCS) $(VCFLAGS) $(DEFS) $(TFLAGS) /Fe$@.exe
$(DOCKER) mdashnet/vc17 wine64 $@.exe $(DOCKER) mdashnet/vc17 wine64 $@.exe
vc22: Makefile mongoose.h $(SRCS) vc22: Makefile mongoose.h $(SRCS)
$(DOCKER) mdashnet/vc22 wine64 cl $(SRCS) $(VCFLAGS) /Fe$@.exe $(DOCKER) mdashnet/vc22 wine64 cl $(SRCS) $(VCFLAGS) $(DEFS) $(TFLAGS) /Fe$@.exe
$(DOCKER) mdashnet/vc22 wine64 $@.exe $(DOCKER) mdashnet/vc22 wine64 $@.exe
mingw: Makefile mongoose.h $(SRCS) mingw: Makefile mongoose.h $(SRCS)
$(DOCKER) mdashnet/mingw x86_64-w64-mingw32-gcc $(SRCS) -W -Wall -Werror -I. $(DEFS) -lwsock32 -lbcrypt -o $@.exe $(DOCKER) mdashnet/mingw x86_64-w64-mingw32-gcc $(SRCS) -W -Wall -Werror -I. $(DEFS) $(TFLAGS) -lws2_32 -lbcrypt -o $@.exe
$(DOCKER) mdashnet/mingw wine64 $@.exe $(DOCKER) mdashnet/mingw wine64 $@.exe
mingw++: Makefile mongoose.h $(SRCS) mingw++: Makefile mongoose.h $(SRCS)
$(DOCKER) mdashnet/mingw x86_64-w64-mingw32-g++ $(SRCS) -W -Wall -Werror -I. $(DEFS) -lwsock32 -lbcrypt -o $@.exe $(DOCKER) mdashnet/mingw x86_64-w64-mingw32-g++ $(SRCS) -W -Wall -Werror -I. $(DEFS) $(TFLAGS) -lws2_32 -lbcrypt -o $@.exe
@echo "NOT RUNNING"
linux-libs: CFLAGS += -fPIC linux-libs: CFLAGS += -fPIC
linux-libs: LDFLAGS += -Wl,-soname,libmongoose.so.$(VERSION) linux-libs: LDFLAGS += -Wl,-soname,libmongoose.so.$(VERSION)
@@ -213,7 +230,7 @@ mongoose.c: Makefile $(wildcard ../src/*.c) $(wildcard ../src/drivers/*.c)
cd .. && (export LC_ALL=C ; cat src/license.h; echo; echo '#include "mongoose.h"' ; (for F in src/*.c src/drivers/*.c ; do echo; echo '#ifdef MG_ENABLE_LINES'; echo "#line 1 \"$$F\""; echo '#endif'; cat $$F | sed -e 's,#include ".*,,'; done))> $@ cd .. && (export LC_ALL=C ; cat src/license.h; echo; echo '#include "mongoose.h"' ; (for F in src/*.c src/drivers/*.c ; do echo; echo '#ifdef MG_ENABLE_LINES'; echo "#line 1 \"$$F\""; echo '#endif'; cat $$F | sed -e 's,#include ".*,,'; done))> $@
mongoose.h: $(HDRS) Makefile mongoose.h: $(HDRS) Makefile
cd .. && (cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/arch.h src/arch_*.h src/net_ft.h src/net_lwip.h src/net_rl.h src/config.h src/str.h src/queue.h src/fmt.h src/printf.h src/log.h src/timer.h src/fs.h src/util.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/sha256.h src/tls_x25519.h src/tls_aes128.h src/tls_uecc.h src/tls_chacha20.h src/tls_rsa.h src/event.h src/net.h src/http.h src/ssi.h src/tls.h src/tls_mbed.h src/tls_openssl.h src/ws.h src/sntp.h src/mqtt.h src/dns.h src/json.h src/rpc.h src/ota.h src/flash.h src/wifi.h src/net_builtin.h src/profile.h src/drivers/*.h | sed -e '/keep/! s,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@ cd .. && (cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/arch.h src/arch_*.h src/net_ft.h src/net_lwip.h src/net_rl.h src/config.h src/profile.h src/str.h src/queue.h src/fmt.h src/printf.h src/log.h src/timer.h src/fs.h src/util.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/sha256.h src/event.h src/net.h src/http.h src/ssi.h src/tls.h src/tls_x25519.h src/tls_aes128.h src/tls_uecc.h src/tls_chacha20.h src/tls_rsa.h src/tls_mbed.h src/tls_openssl.h src/ws.h src/sntp.h src/mqtt.h src/dns.h src/json.h src/rpc.h src/ota.h src/flash.h src/wifi.h src/net_builtin.h src/drivers/*.h | sed -e '/keep/! s,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@
clean: clean_tutorials clean_tutorials_embedded clean: clean_tutorials clean_tutorials_embedded
+59
View File
@@ -0,0 +1,59 @@
#pragma once
// Build environment. Possible options are at https://github.com/cesanta/mongoose/blob/master/src/arch.h
// #define MG_ARCH MG_ARCH_CUSTOM
// Choice of the network stack. By default, use an external BSD-compatible stack
// #define MG_ENABLE_FREERTOS_TCP 0 // Amazon FreeRTOS-TCP
// #define MG_ENABLE_LWIP 0 // lWIP
// #define MG_ENABLE_TCPIP 0 // Mongoose built-in
// #define MG_ENABLE_RL 0 // ARM MDK
// #define MG_ENABLE_POLL 0 // Only for BSD stack. Use poll()
// #define MG_ENABLE_EPOLL 0 // Only for Linux/BSD stack. Use epoll()
// #define MG_ENABLE_WINSOCK 1 // Only for Windows stack. Use Winsock
// #define MG_ENABLE_SOCKET !MG_ENABLE_TCPIP
// #define MG_SOCK_LISTEN_BACKLOG_SIZE 3 // Only for socket-based stacks
// Only for built-in network stack, MG_ENABLE_TCPIP == 1
// #define MG_ENABLE_TCPIP_DRIVER_INIT 1 // enabled built-in driver for
// #define MG_SET_MAC_ADDRESS(mac) // set MAC address for built-in driver
// #define MG_SET_WIFI_CONFIG(data)
// #define MG_ENABLE_TCPIP_PRINT_DEBUG_STATS 0
// Choose a driver for built-in network stack, MG_ENABLE_TCPIP == 1
// #define MG_ENABLE_DRIVER_STM32H 0
// #define MG_ENABLE_DRIVER_STM32F 0
// #define MG_ENABLE_DRIVER_IMXRT 0
// #define MG_ENABLE_DRIVER_CMSIS 0
// #define MG_ENABLE_DRIVER_RA 0
// #define MG_ENABLE_DRIVER_RW612 0
// #define MG_ENABLE_DRIVER_SAME54 0
// #define MG_ENABLE_DRIVER_MCXN 0
// #define MG_ENABLE_DRIVER_TM4C 0
// #define MG_ENABLE_DRIVER_TMS570 0
// #define MG_ENABLE_DRIVER_XMC7 0
// #define MG_ENABLE_DRIVER_XMC 0
// Filesystem support
// #define MG_ENABLE_PACKED_FS 0 // Enable packed filesystem support
// #define MG_ENABLE_FATFS 0 // Enable FATFS support, mg_fs_packed
// #define MG_ENABLE_POSIX_FS 0 // Enable POSIX filesystem support, mg_fs_posix
// #define MG_PATH_MAX 128 // Maximum path length
// #define MG_DIRSEP '/' // Directory separator
// Misc options
// #define MG_ENABLE_LOG 1 // Enable logging
// #define MG_TLS MG_TLS_NONE // MG_TLS_NONE, MG_TLS_MBED, MG_TLS_OPENSSL, MG_TLS_CUSTOM
// #define MG_ENABLE_IPV6 0 // Enable IPv6 support
// #define MG_IPV6_V6ONLY 0 // IPv6 socket binds only to V6, not V4 address
// #define MG_ENABLE_CUSTOM_CALLOC 0 // Set to 1 to let user define mg_calloc() and mg_free()
// #define MG_ENABLE_CUSTOM_RANDOM 0 // Set to 1 to let user define mg_random()
// #define MG_ENABLE_CUSTOM_MILLIS 0 // Set to 1 to let user define mg_millis()
// #define MG_ENABLE_SSI 0 // Enable SSI support
// #define MG_ENABLE_DIRLIST 0 // Enable directory listing
// #define MG_IO_SIZE 512 // Granularity of the send/recv IO buffer growth
// #define MG_MAX_RECV_SIZE (3UL * 1024UL * 1024UL) // Maximum recv IO buffer size
// #define MG_DATA_SIZE 32 // struct mg_connection :: data size
// #define MG_MAX_HTTP_HEADERS 30 // Maximum number of HTTP headers
// #define MG_HTTP_INDEX "index.html" // Default HTTP index file
// #define MG_ENABLE_LINES 0 // Show unamalgamated line numbers
+7 -2
View File
@@ -7,18 +7,23 @@ IMAGE ?= scaprile/cubeozone
all: $(PROJECTS) all: $(PROJECTS)
$(DOCKER) $(IMAGE) $(PATHTO)headless-build.sh -data workspace -removeAll workspace $(DOCKER) $(IMAGE) $(PATHTO)headless-build.sh -data workspace -removeAll workspace
$(DOCKER) $(IMAGE) /bin/bash -c "rm -rf workspace/.metadata"
$(PROJECTS): FORCE $(PROJECTS): FORCE
(make -C $@ && sudo make -C $@ clean) || ( \ (make -C $@ && sudo make -C $@ clean) || ( \
COREDIRS=`find $@ -maxdepth 1 -name 'CM*' -print` && ( \ COREDIRS=`find $@ -maxdepth 1 -name 'CM*' -print` && ( \
(test "$$COREDIRS" = "" && \ (test "$$COREDIRS" = "" && \
PROJNAME=`xq -r .projectDescription.name $@/.project` && \ PROJNAME=`xq -r .projectDescription.name $@/.project` && \
$(DOCKER) $(IMAGE) $(PATHTO)headless-build.sh -data workspace -import $@ -cleanBuild $$PROJNAME/$(TARGET) ) || ( \ $(DOCKER) $(IMAGE) $(PATHTO)headless-build.sh -data workspace -import $@ -cleanBuild $$PROJNAME/$(TARGET) && \
$(DOCKER) $(IMAGE) $(PATHTO)headless-build.sh -data workspace -remove $@ && \
$(DOCKER) $(IMAGE) /bin/bash -c "rm -rf $@/.settings $@/$(TARGET)") || ( \
(test "$$COREDIRS" != "" && \ (test "$$COREDIRS" != "" && \
for core in $$COREDIRS; do \ for core in $$COREDIRS; do \
DIR=`basename $$core` \ DIR=`basename $$core` \
PROJNAME=`xq -r .projectDescription.name $@/$$DIR/.project` && \ PROJNAME=`xq -r .projectDescription.name $@/$$DIR/.project` && \
$(DOCKER) $(IMAGE) $(PATHTO)headless-build.sh -data workspace -import $@/$$DIR -cleanBuild $$PROJNAME/$(TARGET) || exit 1; \ $(DOCKER) $(IMAGE) $(PATHTO)headless-build.sh -data workspace -import $@/$$DIR -cleanBuild $$PROJNAME/$(TARGET) && \
$(DOCKER) $(IMAGE) $(PATHTO)headless-build.sh -data workspace -remove $@/$$DIR && \
$(DOCKER) $(IMAGE) /bin/bash -c "rm -rf $@/$$DIR/.settings $@/$$DIR/Drivers $@/$$DIR/Middlewares $@/$$DIR/$(TARGET)" || exit 1; \
done )))) done ))))
FORCE: FORCE:
+33
View File
@@ -0,0 +1,33 @@
- Make sure your PEM file starts with a dash -
Issuer: C=US, O=Internet Security Research Group, CN=ISRG Root X1
Not Before: Mar 13 00:00:00 2024 GMT
Not After : Mar 12 23:59:59 2027 GMT
-----BEGIN CERTIFICATE-----
MIIEVzCCAj+gAwIBAgIRAIOPbGPOsTmMYgZigxXJ/d4wDQYJKoZIhvcNAQELBQAw
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjQwMzEzMDAwMDAw
WhcNMjcwMzEyMjM1OTU5WjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg
RW5jcnlwdDELMAkGA1UEAxMCRTUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNCzqK
a2GOtu/cX1jnxkJFVKtj9mZhSAouWXW0gQI3ULc/FnncmOyhKJdyIBwsz9V8UiBO
VHhbhBRrwJCuhezAUUE8Wod/Bk3U/mDR+mwt4X2VEIiiCFQPmRpM5uoKrNijgfgw
gfUwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD
ATASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBSfK1/PPCFPnQS37SssxMZw
i9LXDTAfBgNVHSMEGDAWgBR5tFnme7bl5AFzgAiIyBpY9umbbjAyBggrBgEFBQcB
AQQmMCQwIgYIKwYBBQUHMAKGFmh0dHA6Ly94MS5pLmxlbmNyLm9yZy8wEwYDVR0g
BAwwCjAIBgZngQwBAgEwJwYDVR0fBCAwHjAcoBqgGIYWaHR0cDovL3gxLmMubGVu
Y3Iub3JnLzANBgkqhkiG9w0BAQsFAAOCAgEAH3KdNEVCQdqk0LKyuNImTKdRJY1C
2uw2SJajuhqkyGPY8C+zzsufZ+mgnhnq1A2KVQOSykOEnUbx1cy637rBAihx97r+
bcwbZM6sTDIaEriR/PLk6LKs9Be0uoVxgOKDcpG9svD33J+G9Lcfv1K9luDmSTgG
6XNFIN5vfI5gs/lMPyojEMdIzK9blcl2/1vKxO8WGCcjvsQ1nJ/Pwt8LQZBfOFyV
XP8ubAp/au3dc4EKWG9MO5zcx1qT9+NXRGdVWxGvmBFRAajciMfXME1ZuGmk3/GO
koAM7ZkjZmleyokP1LGzmfJcUd9s7eeu1/9/eg5XlXd/55GtYjAM+C4DG5i7eaNq
cm2F+yxYIPt6cbbtYVNJCGfHWqHEQ4FYStUyFnv8sjyqU8ypgZaNJ9aVcWSICLOI
E1/Qv/7oKsnZCWJ926wU6RqG1OYPGOi1zuABhLw61cuPVDT28nQS/e6z95cJXq0e
K1BcaJ6fJZsmbjRgD5p3mvEf5vdQM7MCEvU0tHbsx2I5mHHJoABHb8KVBgWp/lcX
GWiWaeOyB7RP+OfDtvi2OsapxXiV7vNVs7fMlrRjY1joKaqmmycnBvAq14AEbtyL
sVfOS66B8apkeFX2NY4XPEYV4ZSCe8VHPrdrERk2wILG3T/EGmSIkCYVUMSnjmJd
VQD9F6Na/+zmXCc=
-----END CERTIFICATE-----
+1 -1
View File
@@ -11,6 +11,6 @@ all: $(PROJECTS)
$(PROJECTS): FORCE $(PROJECTS): FORCE
(make -C $@ build && make -C $@ clean) || ( \ (make -C $@ build && make -C $@ clean) || ( \
$(DOCKER) $(IMAGE) /bin/bash -c 'cd $@ && idf.py build' && \ $(DOCKER) $(IMAGE) /bin/bash -c 'cd $@ && idf.py build' && \
rm -rf build sdkconfig ) $(DOCKER) $(IMAGE) /bin/bash -c 'rm -rf .cache && cd $@ && rm -rf build sdkconfig')
FORCE: FORCE:
+3
View File
@@ -1,3 +1,5 @@
// https://llvm.org/docs/LibFuzzer.html
#define MG_ENABLE_SOCKET 0 #define MG_ENABLE_SOCKET 0
#define MG_ENABLE_LOG 0 #define MG_ENABLE_LOG 0
#define MG_ENABLE_LINES 1 #define MG_ENABLE_LINES 1
@@ -146,6 +148,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
c->pfn(c, MG_EV_READ, NULL); // manually invoke protocol event handler c->pfn(c, MG_EV_READ, NULL); // manually invoke protocol event handler
free(pkt); free(pkt);
mg_mgr_free(&mgr);
} }
return 0; return 0;
+30 -13
View File
@@ -1,3 +1,5 @@
// https://llvm.org/docs/LibFuzzer.html
#define MG_ENABLE_SOCKET 1 #define MG_ENABLE_SOCKET 1
#define MG_ENABLE_LOG 0 #define MG_ENABLE_LOG 0
#define MG_ENABLE_LINES 1 #define MG_ENABLE_LINES 1
@@ -12,28 +14,40 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *, size_t);
#else #else
int LLVMFuzzerTestOneInput(const uint8_t *, size_t); int LLVMFuzzerTestOneInput(const uint8_t *, size_t);
#endif #endif
typedef int (*f)(struct mg_connection *);
f f_[] = { // Preprocessor magic, just add/remove functions here and leave the rest alone
mg_tls_server_recv_hello, #define TABLE(_) \
#if 0 _(mg_tls_server_recv_hello) \
mg_tls_client_recv_hello, //_(mg_tls_client_recv_hello) \
mg_tls_client_recv_ext, //_(mg_tls_client_recv_ext ) \
mg_tls_client_recv_cert, //_(mg_tls_client_recv_cert) \
mg_tls_client_recv_cert_verify //_(mg_tls_client_recv_cert_verify) \
#endif // ...
struct f {
int (*f)(struct mg_connection *);
const char *name;
}; };
struct f f_[] = {
#define ENTRY(func) { func, #func },
TABLE(ENTRY)
#undef ENTRY
};
// end of preprocessor magic
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
struct mg_connection c_[sizeof(f_)/sizeof(f)], *c = &c_[0]; struct mg_connection c_[sizeof(f_)/sizeof(struct f)], *c = &c_[0];
struct tls_data tls_[sizeof(f_)/sizeof(f)]; struct tls_data tls_[sizeof(f_)/sizeof(struct f)];
int i; int i;
if (size == 0) return 0; if (size == 0) return 0;
mg_log_set(MG_LL_INFO); mg_log_set(MG_LL_INFO);
memset(c, 0, sizeof(*c)); memset(c, 0, sizeof(*c));
c->send.align = c->recv.align = c->rtls.align = MG_IO_SIZE; c->send.align = c->recv.align = c->rtls.align = MG_IO_SIZE;
c->is_tls = c->is_tls_hs = 1; c->is_tls = c->is_tls_hs = 1;
for (i = 0; i < (int)(sizeof(f_)/sizeof(f)); i++) { for (i = 0; i < (int)(sizeof(f_)/sizeof(struct f)); i++) {
struct mg_iobuf *io; struct mg_iobuf *io;
c = &c_[i]; c = &c_[i];
io = &c->rtls; io = &c->rtls;
@@ -47,7 +61,10 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
memcpy(&io->buf[io->len], data, size); memcpy(&io->buf[io->len], data, size);
io->len += size; io->len += size;
c->tls = &tls_[i]; c->tls = &tls_[i];
f_[i](&c[i]); #ifdef PRINT_FUNCNAME
printf("CALLING %s\n", f_[i].name);
#endif
f_[i].f(&c[i]);
mg_iobuf_free(io); mg_iobuf_free(io);
} }
+3
View File
@@ -0,0 +1,3 @@
{
"data-root": "/mnt/docker"
}
+95 -20
View File
@@ -20,9 +20,13 @@
#include "driver_mock.c" #include "driver_mock.c"
#define MQTT_URL "mqtt://broker.hivemq.com:1883" // MQTT broker URL #ifdef MQTT_LOCALHOST
#define MQTT_URL "mqtt://127.0.0.1:1883"
#else
#define MQTT_URL "mqtt://broker.hivemq.com:1883"
#endif
#if MG_TLS == MG_TLS_BUILTIN #if MG_TLS == MG_TLS_BUILTIN
#define MQTTS_URL "mqtts://mongoose.ws:8883" // HiveMQ does not do TLS1.3 #define MQTTS_URL "mqtts://mongoose.ws:8883" // test requires TLS 1.3
#define MQTTS_CA mg_str(s_ca_cert) #define MQTTS_CA mg_str(s_ca_cert)
static const char *s_ca_cert = static const char *s_ca_cert =
"-----BEGIN CERTIFICATE-----\n" "-----BEGIN CERTIFICATE-----\n"
@@ -57,23 +61,42 @@ static const char *s_ca_cert =
"emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=\n" "emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=\n"
"-----END CERTIFICATE-----\n"; "-----END CERTIFICATE-----\n";
#elif MG_TLS #elif MG_TLS
#define MQTTS_URL "mqtts://broker.hivemq.com:8883" // MQTT broker URL #ifdef MQTT_LOCALHOST
// we'll generate MQTTS_URL
#define MQTTS_CA mg_str(s_ca_cert)
static const char *s_ca_cert =
"-----BEGIN CERTIFICATE-----\n"
"MIIBFTCBvAIJAMNTFtpfcq8NMAoGCCqGSM49BAMCMBMxETAPBgNVBAMMCE1vbmdv\n"
"b3NlMB4XDTI0MDUwNzE0MzczNloXDTM0MDUwNTE0MzczNlowEzERMA8GA1UEAwwI\n"
"TW9uZ29vc2UwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASuP+86T/rOWnGpEVhl\n"
"fxYZ+pjMbCmDZ+vdnP0rjoxudwRMRQCv5slRlDK7Lxue761sdvqxWr0Ma6TFGTNg\n"
"epsRMAoGCCqGSM49BAMCA0gAMEUCIQCwb2CxuAKm51s81S6BIoy1IcandXSohnqs\n"
"us64BAA7QgIgGGtUrpkgFSS0oPBlCUG6YPHFVw42vTfpTC0ySwAS0M4=\n"
"-----END CERTIFICATE-----\n";
#else
#define MQTTS_URL "mqtts://broker.hivemq.com:8883"
#define MQTTS_CA mg_unpacked("/data/ca.pem") #define MQTTS_CA mg_unpacked("/data/ca.pem")
#endif // MQTT_LOCALHOST
#endif #endif
static char *host_ip; static char *host_ip;
static int s_num_tests = 0; static int s_num_tests = 0;
#define ABORT() \ #ifdef NO_SLEEP_ABORT
usleep(500000); /* 500 ms, GH print reason */ \ #define ABORT() abort()
#else
#define ABORT() \
sleep(2); /* 2s, GH print reason */ \
abort(); abort();
#endif
#define ASSERT(expr) \ #define ASSERT(expr) \
do { \ do { \
s_num_tests++; \ s_num_tests++; \
if (!(expr)) { \ if (!(expr)) { \
printf("FAILURE %s:%d: %s\n", __FILE__, __LINE__, #expr); \ printf("FAILURE %s:%d: %s\n", __FILE__, __LINE__, #expr); \
fflush(stdout); \
ABORT(); \ ABORT(); \
} \ } \
} while (0) } while (0)
@@ -156,14 +179,22 @@ static void fcb(struct mg_connection *c, int ev, void *ev_data) {
if (mg_url_is_ssl(fd->url)) { if (mg_url_is_ssl(fd->url)) {
struct mg_tls_opts opts; struct mg_tls_opts opts;
memset(&opts, 0, sizeof(opts)); // read CA from packed_fs memset(&opts, 0, sizeof(opts)); // read CA from packed_fs
opts.name = mg_url_host(fd->url);
opts.ca = mg_unpacked("/data/ca.pem");
if (host_ip != NULL && strstr(fd->url, host_ip) != NULL) { if (host_ip != NULL && strstr(fd->url, host_ip) != NULL) {
MG_DEBUG(("Local connection, using self-signed certificates")); MG_DEBUG(("Local connection, using self-signed certificates"));
opts.name = mg_str_s("localhost"); opts.name = mg_str_s("localhost");
opts.ca = mg_unpacked("/certs/ca.crt"); opts.ca = mg_unpacked("/certs/ca.crt");
} else {
opts.name = mg_url_host(fd->url);
opts.ca = mg_unpacked("/data/ca.pem");
#if MG_TLS == MG_TLS_BUILTIN
// our TLS does not search for the proper CA in a bundle
opts.ca = mg_file_read(&mg_fs_posix, "data/e5.crt");
#endif
} }
mg_tls_init(c, &opts); mg_tls_init(c, &opts);
#if MG_TLS == MG_TLS_BUILTIN
mg_free((void *) opts.ca.buf);
#endif
} }
} else if (ev == MG_EV_HTTP_MSG) { } else if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
@@ -241,14 +272,20 @@ static void test_http_client(struct mg_mgr *mgr) {
static struct mg_connection *s_conn; static struct mg_connection *s_conn;
static char s_topic[16]; static char s_topic[16];
struct mqtt_data {
char *url;
bool passed;
};
static void mqtt_fn(struct mg_connection *c, int ev, void *ev_data) { static void mqtt_fn(struct mg_connection *c, int ev, void *ev_data) {
struct mqtt_data *data = (struct mqtt_data *) c->fn_data;
if (ev == MG_EV_CONNECT) { if (ev == MG_EV_CONNECT) {
MG_DEBUG(("CONNECT")); MG_DEBUG(("CONNECT"));
#if MG_TLS #if MG_TLS
struct mg_tls_opts opts; struct mg_tls_opts opts;
memset(&opts, 0, sizeof(opts)); memset(&opts, 0, sizeof(opts));
opts.ca = MQTTS_CA; opts.ca = MQTTS_CA;
opts.name = mg_url_host(MQTTS_URL); opts.name = mg_url_host(data->url);
mg_tls_init(c, &opts); mg_tls_init(c, &opts);
#endif #endif
} else if (ev == MG_EV_MQTT_OPEN) { } else if (ev == MG_EV_MQTT_OPEN) {
@@ -267,12 +304,32 @@ static void mqtt_fn(struct mg_connection *c, int ev, void *ev_data) {
} else if (ev == MG_EV_MQTT_MSG) { } else if (ev == MG_EV_MQTT_MSG) {
struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data; struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
MG_DEBUG(("TOPIC: %.*s, MSG: %.*s", (int) mm->topic.len, mm->topic.buf, MG_DEBUG(("TOPIC: %.*s, MSG: %.*s", (int) mm->topic.len, mm->topic.buf,
(int) mm->data.len, mm->data.buf)); mm->data.len > 10 ? 10 : (int) mm->data.len, mm->data.buf));
ASSERT(mm->topic.len == strlen(s_topic) && ASSERT(mm->topic.len == strlen(s_topic) &&
strcmp(mm->topic.buf, s_topic) == 0); strncmp(mm->topic.buf, s_topic, mm->topic.len) == 0);
ASSERT(mm->data.len == 2 && strcmp(mm->data.buf, "hi") == 0); if (mm->data.len == 2 && strncmp(mm->data.buf, "hi", 2) == 0) {
mg_mqtt_disconnect(c, NULL); struct mg_mqtt_opts pub_opts;
*(bool *) c->fn_data = true; memset(&pub_opts, 0, sizeof(pub_opts));
pub_opts.topic = mm->topic;
// send more than 1 record, content is not relevant
pub_opts.message = mg_str_n((char *)(size_t) mqtt_fn, 21098);
pub_opts.qos = 1, pub_opts.retain = false;
mg_mqtt_pub(c, &pub_opts);
} else if (mm->data.len == 8 && strncmp(mm->data.buf, "farewell", 8) == 0) {
// close on farewell
MG_INFO(("%lu CLOSING", c->id));
mg_mqtt_disconnect(c, NULL);
data->passed = true;
} else if (mm->data.len == 21098) {
struct mg_mqtt_opts pub_opts;
ASSERT(memcmp((const char *) (size_t) mqtt_fn, mm->data.buf, 21098) == 0);
// send farewell after receiving big data
memset(&pub_opts, 0, sizeof(pub_opts));
pub_opts.topic = mm->topic;
pub_opts.message = mg_str("farewell");
pub_opts.qos = 1, pub_opts.retain = false;
mg_mqtt_pub(c, &pub_opts);
}
} else if (ev == MG_EV_CLOSE) { } else if (ev == MG_EV_CLOSE) {
MG_DEBUG(("CLOSE")); MG_DEBUG(("CLOSE"));
s_conn = NULL; s_conn = NULL;
@@ -282,22 +339,40 @@ static void mqtt_fn(struct mg_connection *c, int ev, void *ev_data) {
} }
static void test_mqtt_connsubpub(struct mg_mgr *mgr) { static void test_mqtt_connsubpub(struct mg_mgr *mgr) {
bool passed = false; struct mqtt_data data;
struct mg_mqtt_opts opts; struct mg_mqtt_opts opts;
memset(&opts, 0, sizeof(opts)); memset(&opts, 0, sizeof(opts));
opts.clean = true, opts.version = 4; opts.clean = true, opts.version = 4;
#if MG_TLS data.passed = false;
s_conn = mg_mqtt_connect(mgr, MQTTS_URL, &opts, mqtt_fn, &passed); #if defined(MQTT_LOCALHOST) && MG_TLS != MG_TLS_BUILTIN
#else if (host_ip == NULL) {
s_conn = mg_mqtt_connect(mgr, MQTT_URL, &opts, mqtt_fn, &passed); printf("\nMQTT_LOCALHOST defined but no HOST_IP provided, skipping MQTTS tests\n");
return;
}
printf("HOST_IP: %s\n", host_ip);
#endif #endif
#if MG_TLS
#if defined(MQTT_LOCALHOST) && MG_TLS != MG_TLS_BUILTIN
data.url = mg_mprintf("mqtts://%s:8883", host_ip);
#else
data.url = strdup(MQTTS_URL);
#endif
#else
#ifdef MQTT_LOCALHOST
data.url = mg_mprintf("mqtt://%s:1883", host_ip);
#else
data.url = strdup(MQTT_URL);
#endif
#endif
s_conn = mg_mqtt_connect(mgr, data.url, &opts, mqtt_fn, &data);
ASSERT(s_conn != NULL); ASSERT(s_conn != NULL);
for (int i = 0; i < 500 && s_conn != NULL && !s_conn->is_closing; i++) { for (int i = 0; i < 1000 && s_conn != NULL && !s_conn->is_closing; i++) {
mg_mgr_poll(mgr, 0); mg_mgr_poll(mgr, 0);
usleep(10000); // 10 ms. Slow down poll loop to ensure packets transit usleep(10000); // 10 ms. Slow down poll loop to ensure packets transit
} }
ASSERT(passed); ASSERT(data.passed);
mg_mgr_poll(mgr, 0); mg_mgr_poll(mgr, 0);
free(data.url);
} }
#include <pthread.h> #include <pthread.h>
+97 -49
View File
@@ -1,19 +1,19 @@
#define MG_ENABLE_TCPIP 1 #define MG_ENABLE_TCPIP 1
#define MG_ENABLE_TCPIP_DRIVER_INIT 0 #define MG_ENABLE_TCPIP_DRIVER_INIT 0
#include "mongoose.c" #include "mongoose.c" // order is important, this one first
#include "driver_mock.c" #include "driver_mock.c"
static int s_num_tests = 0; static int s_num_tests = 0;
static bool s_sent_fragment = 0; static int s_sent_fragment = 0;
static int s_seg_sent = 0; static int s_seg_sent = 0;
#ifdef NO_SLEEP_ABORT #ifdef NO_SLEEP_ABORT
#define ABORT() abort() #define ABORT() abort()
#else #else
#define ABORT() \ #define ABORT() \
sleep(2); /* 2s, GH print reason */ \ sleep(2); /* 2s, GH print reason */ \
abort(); abort();
#endif #endif
#define ASSERT(expr) \ #define ASSERT(expr) \
@@ -21,10 +21,18 @@ static int s_seg_sent = 0;
s_num_tests++; \ s_num_tests++; \
if (!(expr)) { \ if (!(expr)) { \
printf("FAILURE %s:%d: %s\n", __FILE__, __LINE__, #expr); \ printf("FAILURE %s:%d: %s\n", __FILE__, __LINE__, #expr); \
fflush(stdout); \
ABORT(); \ ABORT(); \
} \ } \
} while (0) } while (0)
static void test_csum(void) {
uint8_t ip[20] = {0x45, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x28, 0x11,
0x94, 0xcf, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00, 0x00, 0x01};
ASSERT(ipcsum(ip, 20) == 0);
// UDP and TCP checksum calc funcions use the same basic calls as ipcsum()
}
static void test_statechange(void) { static void test_statechange(void) {
char tx[1540]; char tx[1540];
struct mg_tcpip_if iface; struct mg_tcpip_if iface;
@@ -47,19 +55,24 @@ static void fn(struct mg_connection *c, int ev, void *ev_data) {
static void frag_recv_fn(struct mg_connection *c, int ev, void *ev_data) { static void frag_recv_fn(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_ERROR) { if (ev == MG_EV_ERROR) {
if (s_sent_fragment) { if (s_sent_fragment > 0) {
ASSERT(strcmp((char*) ev_data, "Received fragmented packet") == 0); ASSERT(s_sent_fragment == 1);
ASSERT(strcmp((char *) ev_data, "Received fragmented packet") == 0);
s_sent_fragment = 2;
} }
} }
(void) c, (void) ev_data; (void) c, (void) ev_data;
} }
// mock send to a non-existent peer using the listener connection
static void frag_send_fn(struct mg_connection *c, int ev, void *ev_data) { static void frag_send_fn(struct mg_connection *c, int ev, void *ev_data) {
static bool s_sent; static bool s_sent;
static int s_seg_sizes[] = {416, 416, 368}; static int s_seg_sizes[] = {416, 416, 368}; // based on len=1200 and MTU=500
if (ev == MG_EV_POLL) { if (ev == MG_EV_POLL) {
if (!s_sent) { if (!s_sent) {
c->send.len = 1200; // setting TCP payload size struct connstate *s = (struct connstate *) (c + 1);
s->dmss = 1500; // mock set some destination MSS way larger
c->send.len = 1200; // setting TCP payload size
s_sent = true; s_sent = true;
} }
} else if (ev == MG_EV_WRITE) { } else if (ev == MG_EV_WRITE) {
@@ -71,9 +84,9 @@ static void frag_send_fn(struct mg_connection *c, int ev, void *ev_data) {
static void test_poll(void) { static void test_poll(void) {
int count = 0, i; int count = 0, i;
struct mg_tcpip_if mif;
struct mg_mgr mgr; struct mg_mgr mgr;
mg_mgr_init(&mgr); mg_mgr_init(&mgr);
struct mg_tcpip_if mif;
memset(&mif, 0, sizeof(mif)); memset(&mif, 0, sizeof(mif));
mif.driver = &mg_tcpip_driver_mock; mif.driver = &mg_tcpip_driver_mock;
mg_tcpip_init(&mgr, &mif); mg_tcpip_init(&mgr, &mif);
@@ -88,7 +101,7 @@ static void test_poll(void) {
struct driver_data { struct driver_data {
char buf[DRIVER_BUF_SIZE]; char buf[DRIVER_BUF_SIZE];
size_t len; size_t len;
bool tx_ready; // data can be read from tx bool tx_ready; // data can be read from tx
}; };
static struct driver_data s_driver_data; static struct driver_data s_driver_data;
@@ -108,10 +121,10 @@ static bool if_poll(struct mg_tcpip_if *ifp, bool s1) {
static size_t if_rx(void *buf, size_t len, struct mg_tcpip_if *ifp) { static size_t if_rx(void *buf, size_t len, struct mg_tcpip_if *ifp) {
struct driver_data *driver_data = (struct driver_data *) ifp->driver_data; struct driver_data *driver_data = (struct driver_data *) ifp->driver_data;
if (!driver_data->len) return 0; if (driver_data->len == 0) return 0;
if (len > driver_data->len) len = driver_data->len; if (len > driver_data->len) len = driver_data->len;
memcpy(buf, driver_data->buf, len); memcpy(buf, driver_data->buf, len);
driver_data->len = 0; // cleaning up the buffer driver_data->len = 0; // cleaning up the buffer
return len; return len;
} }
@@ -130,10 +143,10 @@ static void create_tcp_pkt(struct eth *e, struct ip *ip, uint32_t seq,
t.ack = mg_htonl(ack); t.ack = mg_htonl(ack);
t.off = 5 << 4; t.off = 5 << 4;
memcpy(s_driver_data.buf, e, sizeof(*e)); memcpy(s_driver_data.buf, e, sizeof(*e));
ip->len = mg_htons((uint16_t)(sizeof(*ip) + sizeof(struct tcp) + payload_len));
memcpy(s_driver_data.buf + sizeof(*e), ip, sizeof(*ip)); memcpy(s_driver_data.buf + sizeof(*e), ip, sizeof(*ip));
memcpy(s_driver_data.buf + sizeof(*e) + sizeof(*ip), &t, sizeof(struct tcp)); memcpy(s_driver_data.buf + sizeof(*e) + sizeof(*ip), &t, sizeof(t));
s_driver_data.len = sizeof(*e) + sizeof(*ip) s_driver_data.len = sizeof(*e) + sizeof(*ip) + sizeof(t) + payload_len;
+ sizeof(struct tcp) + payload_len;
} }
static void init_tcp_handshake(struct eth *e, struct ip *ip, struct tcp *tcp, static void init_tcp_handshake(struct eth *e, struct ip *ip, struct tcp *tcp,
@@ -143,9 +156,9 @@ static void init_tcp_handshake(struct eth *e, struct ip *ip, struct tcp *tcp,
mg_mgr_poll(mgr, 0); mg_mgr_poll(mgr, 0);
// SYN-ACK // SYN-ACK
while(!received_response(&s_driver_data)) mg_mgr_poll(mgr, 0); while (!received_response(&s_driver_data)) mg_mgr_poll(mgr, 0);
tcp = (struct tcp *) (s_driver_data.buf + sizeof(struct eth) + tcp = (struct tcp *) (s_driver_data.buf + sizeof(struct eth) +
sizeof(struct ip)); sizeof(struct ip));
ASSERT((tcp->flags == (TH_SYN | TH_ACK))); ASSERT((tcp->flags == (TH_SYN | TH_ACK)));
ASSERT((tcp->ack == mg_htonl(1001))); ASSERT((tcp->ack == mg_htonl(1001)));
@@ -154,6 +167,9 @@ static void init_tcp_handshake(struct eth *e, struct ip *ip, struct tcp *tcp,
mg_mgr_poll(mgr, 0); mg_mgr_poll(mgr, 0);
} }
// NOTE: a 1-byte payload could be an erroneous Keep-Alive, keep length > 1 in
// this operation, we're testing retransmissions and having len=1 won't work
static void test_retransmit(void) { static void test_retransmit(void) {
struct mg_mgr mgr; struct mg_mgr mgr;
struct eth e; struct eth e;
@@ -167,12 +183,13 @@ static void test_retransmit(void) {
mg_mgr_init(&mgr); mg_mgr_init(&mgr);
memset(&mif, 0, sizeof(mif)); memset(&mif, 0, sizeof(mif));
memset(&s_driver_data, 0, sizeof(struct driver_data)); memset(&s_driver_data, 0, sizeof(struct driver_data));
driver.init = NULL, driver.tx = if_tx, driver.poll = if_poll, driver.rx = if_rx; driver.init = NULL, driver.tx = if_tx, driver.poll = if_poll,
driver.rx = if_rx;
mif.driver = &driver; mif.driver = &driver;
mif.driver_data = &s_driver_data; mif.driver_data = &s_driver_data;
mg_tcpip_init(&mgr, &mif); mg_tcpip_init(&mgr, &mif);
mg_http_listen(&mgr, "http://0.0.0.0:0", fn, NULL); mg_http_listen(&mgr, "http://0.0.0.0:0", fn, NULL);
mgr.conns->pfn = NULL; // HTTP handler not needed mgr.conns->pfn = NULL; // HTTP handler not needed
mg_mgr_poll(&mgr, 0); mg_mgr_poll(&mgr, 0);
// setting the Ethernet header // setting the Ethernet header
@@ -183,26 +200,23 @@ static void test_retransmit(void) {
// setting the IP header // setting the IP header
memset(&ip, 0, sizeof(ip)); memset(&ip, 0, sizeof(ip));
ip.ver = 4 << 4, ip.proto = 6; ip.ver = 4 << 4, ip.proto = 6;
ip.len = mg_htons(sizeof(ip) + sizeof(struct tcp));
init_tcp_handshake(&e, &ip, t, &mgr); init_tcp_handshake(&e, &ip, t, &mgr);
// packet with seq_no = 1001 // packet with seq_no = 1001
ip.len = create_tcp_pkt(&e, &ip, 1001, 1, TH_PUSH | TH_ACK, 2);
mg_htons(sizeof(struct ip) + sizeof(struct tcp) + /* TCP Payload */ 1);
create_tcp_pkt(&e, &ip, 1001, 1, TH_PUSH | TH_ACK, 1);
mg_mgr_poll(&mgr, 0); mg_mgr_poll(&mgr, 0);
while(!received_response(&s_driver_data)) mg_mgr_poll(&mgr, 0); while (!received_response(&s_driver_data)) mg_mgr_poll(&mgr, 0);
t = (struct tcp *) (s_driver_data.buf + sizeof(struct eth) + t = (struct tcp *) (s_driver_data.buf + sizeof(struct eth) +
sizeof(struct ip)); sizeof(struct ip));
ASSERT((t->flags == TH_ACK)); ASSERT((t->flags == TH_ACK));
ASSERT((t->ack == mg_htonl(1002))); // OK ASSERT((t->ack == mg_htonl(1003))); // OK
// resend packet with seq_no = 1001 (e.g.: MIP ACK lost) // resend packet with seq_no = 1001 (e.g.: MIP ACK lost)
create_tcp_pkt(&e, &ip, 1001, 1, TH_PUSH | TH_ACK, 1); create_tcp_pkt(&e, &ip, 1001, 1, TH_PUSH | TH_ACK, 2);
mg_mgr_poll(&mgr, 0); mg_mgr_poll(&mgr, 0);
start = mg_millis(); start = mg_millis();
while(!received_response(&s_driver_data)) { while (!received_response(&s_driver_data)) {
mg_mgr_poll(&mgr, 0); mg_mgr_poll(&mgr, 0);
now = mg_millis() - start; now = mg_millis() - start;
// we wait enough time for a reply // we wait enough time for a reply
@@ -211,31 +225,64 @@ static void test_retransmit(void) {
break; break;
} }
} }
ASSERT((!response_recv)); // replies should not be sent for duplicate packets ASSERT((!response_recv)); // replies should not be sent for duplicate packets
// packet with seq_no = 1002 got lost/delayed, send seq_no = 1003 // packet with seq_no = 1003 got lost/delayed, send seq_no = 1005
create_tcp_pkt(&e, &ip, 1003, 1, TH_PUSH | TH_ACK, 1); create_tcp_pkt(&e, &ip, 1005, 1, TH_PUSH | TH_ACK, 2);
mg_mgr_poll(&mgr, 0); mg_mgr_poll(&mgr, 0);
start = mg_millis(); start = mg_millis();
while(!received_response(&s_driver_data)) { while (!received_response(&s_driver_data)) {
mg_mgr_poll(&mgr, 0); mg_mgr_poll(&mgr, 0);
now = mg_millis() - start; now = mg_millis() - start;
if (now > 2 * MIP_TCP_ACK_MS) if (now > 2 * MIP_TCP_ACK_MS)
ASSERT(0); // response should have been received by now ASSERT(0); // response should have been received by now
} }
t = (struct tcp *) (s_driver_data.buf + sizeof(struct eth) + t = (struct tcp *) (s_driver_data.buf + sizeof(struct eth) +
sizeof(struct ip)); sizeof(struct ip));
ASSERT((t->flags == TH_ACK)); ASSERT((t->flags == TH_ACK));
ASSERT((t->ack == mg_htonl(1002))); // dup ACK ASSERT((t->ack == mg_htonl(1003))); // dup ACK
// retransmitting packet with seq_no = 1002 // retransmitting packet with seq_no = 1003
create_tcp_pkt(&e, &ip, 1002, 1, TH_PUSH | TH_ACK, 1); create_tcp_pkt(&e, &ip, 1003, 1, TH_PUSH | TH_ACK, 2);
mg_mgr_poll(&mgr, 0); mg_mgr_poll(&mgr, 0);
while(!received_response(&s_driver_data)) mg_mgr_poll(&mgr, 0); while (!received_response(&s_driver_data)) mg_mgr_poll(&mgr, 0);
t = (struct tcp *) (s_driver_data.buf + sizeof(struct eth) + t = (struct tcp *) (s_driver_data.buf + sizeof(struct eth) +
sizeof(struct ip)); sizeof(struct ip));
ASSERT((t->flags == TH_ACK)); ASSERT((t->flags == TH_ACK));
ASSERT((t->ack == mg_htonl(1003))); // OK ASSERT((t->ack == mg_htonl(1005))); // OK
// packet with seq_no = 1005 got delayed, send FIN with seq_no = 1007
create_tcp_pkt(&e, &ip, 1007, 1, TH_FIN, 0);
mg_mgr_poll(&mgr, 0);
start = mg_millis();
while (!received_response(&s_driver_data)) {
mg_mgr_poll(&mgr, 0);
now = mg_millis() - start;
if (now > 2 * MIP_TCP_ACK_MS)
ASSERT(0); // response should have been received by now
}
t = (struct tcp *) (s_driver_data.buf + sizeof(struct eth) +
sizeof(struct ip));
ASSERT((t->flags == TH_ACK));
ASSERT((t->ack == mg_htonl(1005))); // dup ACK
// retransmitting packet with seq_no = 1005
create_tcp_pkt(&e, &ip, 1005, 1, TH_PUSH | TH_ACK, 2);
mg_mgr_poll(&mgr, 0);
while (!received_response(&s_driver_data)) mg_mgr_poll(&mgr, 0);
t = (struct tcp *) (s_driver_data.buf + sizeof(struct eth) +
sizeof(struct ip));
ASSERT((t->flags == TH_ACK));
ASSERT((t->ack == mg_htonl(1007))); // OK
// retransmitting FIN packet with seq_no = 1007
create_tcp_pkt(&e, &ip, 1007, 1, TH_FIN | TH_ACK, 0);
mg_mgr_poll(&mgr, 0);
while (!received_response(&s_driver_data)) mg_mgr_poll(&mgr, 0);
t = (struct tcp *) (s_driver_data.buf + sizeof(struct eth) +
sizeof(struct ip));
ASSERT((t->flags == (TH_FIN | TH_ACK))); // check we respond with FIN ACK
ASSERT((t->ack == mg_htonl(1008))); // OK
s_driver_data.len = 0; s_driver_data.len = 0;
mg_mgr_free(&mgr); mg_mgr_free(&mgr);
@@ -252,7 +299,8 @@ static void test_frag_recv_path(void) {
mg_mgr_init(&mgr); mg_mgr_init(&mgr);
memset(&mif, 0, sizeof(mif)); memset(&mif, 0, sizeof(mif));
memset(&s_driver_data, 0, sizeof(struct driver_data)); memset(&s_driver_data, 0, sizeof(struct driver_data));
driver.init = NULL, driver.tx = if_tx, driver.poll = if_poll, driver.rx = if_rx; driver.init = NULL, driver.tx = if_tx, driver.poll = if_poll,
driver.rx = if_rx;
mif.driver = &driver; mif.driver = &driver;
mif.driver_data = &s_driver_data; mif.driver_data = &s_driver_data;
mg_tcpip_init(&mgr, &mif); mg_tcpip_init(&mgr, &mif);
@@ -268,17 +316,15 @@ static void test_frag_recv_path(void) {
// setting the IP header // setting the IP header
memset(&ip, 0, sizeof(ip)); memset(&ip, 0, sizeof(ip));
ip.ver = 0x45, ip.proto = 6; ip.ver = 0x45, ip.proto = 6;
ip.len = mg_htons(sizeof(ip) + sizeof(struct tcp));
init_tcp_handshake(&e, &ip, t, &mgr); init_tcp_handshake(&e, &ip, t, &mgr);
// send fragmented TCP packet // send fragmented TCP packet
ip.len = ip.frag |= IP_MORE_FRAGS_MSK; // setting More Fragments bit to 1
mg_htons(sizeof(struct ip) + sizeof(struct tcp) + 1000);
ip.frag |= IP_MORE_FRAGS_MSK; // setting More Fragments bit to 1
create_tcp_pkt(&e, &ip, 1001, 1, TH_PUSH | TH_ACK, 1000); create_tcp_pkt(&e, &ip, 1001, 1, TH_PUSH | TH_ACK, 1000);
s_sent_fragment = true; s_sent_fragment = 1; // "enable" fn
mg_mgr_poll(&mgr, 0); mg_mgr_poll(&mgr, 0); // call it (process fake frag IP)
ASSERT(s_sent_fragment == 2); // check it followed the right path
s_driver_data.len = 0; s_driver_data.len = 0;
mg_mgr_free(&mgr); mg_mgr_free(&mgr);
@@ -288,19 +334,20 @@ static void test_frag_send_path(void) {
struct mg_mgr mgr; struct mg_mgr mgr;
struct mg_tcpip_driver driver; struct mg_tcpip_driver driver;
struct mg_tcpip_if mif; struct mg_tcpip_if mif;
unsigned int i;
mg_mgr_init(&mgr); mg_mgr_init(&mgr);
memset(&mif, 0, sizeof(mif)); memset(&mif, 0, sizeof(mif));
memset(&s_driver_data, 0, sizeof(struct driver_data)); memset(&s_driver_data, 0, sizeof(struct driver_data));
driver.init = NULL, driver.tx = if_tx, driver.poll = if_poll, driver.rx = if_rx; driver.init = NULL, driver.tx = if_tx, driver.poll = if_poll,
driver.rx = if_rx;
mif.driver = &driver; mif.driver = &driver;
mif.driver_data = &s_driver_data; mif.driver_data = &s_driver_data;
mg_tcpip_init(&mgr, &mif); mg_tcpip_init(&mgr, &mif);
mif.mtu = 500; mif.mtu = 500; // force ad hoc small MTU to fragment IP
mg_http_listen(&mgr, "http://0.0.0.0:0", frag_send_fn, NULL); mg_http_listen(&mgr, "http://0.0.0.0:0", frag_send_fn, NULL);
mgr.conns->pfn = NULL; mgr.conns->pfn = NULL;
for (int i = 0; i < 10; i++) for (i = 0; i < 10; i++) mg_mgr_poll(&mgr, 0);
mg_mgr_poll(&mgr, 0);
ASSERT(s_seg_sent == 3); ASSERT(s_seg_sent == 3);
s_driver_data.len = 0; s_driver_data.len = 0;
mg_mgr_free(&mgr); mg_mgr_free(&mgr);
@@ -312,6 +359,7 @@ static void test_fragmentation(void) {
} }
int main(void) { int main(void) {
test_csum();
test_statechange(); test_statechange();
test_poll(); test_poll();
test_retransmit(); test_retransmit();
+7
View File
@@ -0,0 +1,7 @@
allow_anonymous true
listener 8883 127.0.0.1
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/server.crt
keyfile /etc/mosquitto/certs/server.key
#
listener 1883 127.0.0.1
+7
View File
@@ -0,0 +1,7 @@
allow_anonymous true
listener 8883 127.0.0.1
cafile /Users/runner/work/mongoose/mongoose/test/certs/ca.crt
certfile /Users/runner/work/mongoose/mongoose/test/certs/server.crt
keyfile /Users/runner/work/mongoose/mongoose/test/certs/server.key
#
listener 1883 127.0.0.1
+1 -3
View File
@@ -47,9 +47,7 @@ int main(int argc, char *argv[]) {
int i, j, ch; int i, j, ch;
const char *strip_prefix = ""; const char *strip_prefix = "";
printf("%s", "#include <stddef.h>\n"); printf("%s", "#include \"mongoose.h\"\n");
printf("%s", "#include <string.h>\n");
printf("%s", "#include <time.h>\n");
printf("%s", "\n"); printf("%s", "\n");
printf("%s", "#if defined(__cplusplus)\nextern \"C\" {\n#endif\n"); printf("%s", "#if defined(__cplusplus)\nextern \"C\" {\n#endif\n");
printf("%s", "const char *mg_unlist(size_t no);\n"); printf("%s", "const char *mg_unlist(size_t no);\n");
+1 -3
View File
@@ -2,9 +2,7 @@
const Pack = async function(files) { const Pack = async function(files) {
let out = `// DO NOT EDIT. This file is generated let out = `// DO NOT EDIT. This file is generated
#include <stddef.h> #include "mongoose.h"
#include <string.h>
#include <time.h>
#if defined(__cplusplus) #if defined(__cplusplus)
extern "C" { extern "C" {
+8
View File
@@ -0,0 +1,8 @@
#!/bin/sh
df
ls -l /mnt
sudo systemctl stop docker
sudo mkdir -p /mnt/docker
sudo cp test/ga_docker_daemon.json /etc/docker/daemon.json
sudo systemctl start docker
+11 -10
View File
@@ -2,9 +2,9 @@
BRIDGE=mg_bridge0 BRIDGE=mg_bridge0
BRIDGE_BROADCAST=192.168.32.255 BRIDGE_BROADCAST=192.168.32.255
BRIDGE_IP=192.168.32.1 BRIDGE_IP=192.168.32.1
BRIDGE_IP_MASK=192.168.32.0/24 BRIDGE_NETWORK=192.168.32.0/24
BRIDGE_MASK=255.255.255.0 BRIDGE_MASK=255.255.255.0
PHY=eth0 // Host network is 'eth0'
TAP=tap0 TAP=tap0
# see our network configuration # see our network configuration
@@ -33,23 +33,24 @@ sudo ip link set $TAP up
echo echo
echo "Network configuration script: NAT" echo "Network configuration script: NAT"
sudo iptables -A FORWARD -d $BRIDGE_IP_MASK -o $BRIDGE -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT sudo iptables -A FORWARD -d $BRIDGE_NETWORK -o $BRIDGE -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -s $BRIDGE_IP_MASK -i $BRIDGE -j ACCEPT sudo iptables -A FORWARD -s $BRIDGE_NETWORK -i $BRIDGE -j ACCEPT
sudo iptables -A FORWARD -i $BRIDGE -o $BRIDGE -j ACCEPT sudo iptables -A FORWARD -i $BRIDGE -o $BRIDGE -j ACCEPT
sudo iptables -A FORWARD -o $BRIDGE -j REJECT --reject-with icmp-port-unreachable sudo iptables -A FORWARD -o $BRIDGE -j REJECT --reject-with icmp-port-unreachable
sudo iptables -A FORWARD -i $BRIDGE -j REJECT --reject-with icmp-port-unreachable sudo iptables -A FORWARD -i $BRIDGE -j REJECT --reject-with icmp-port-unreachable
sudo iptables -t nat -A POSTROUTING -s $BRIDGE_IP_MASK -d 224.0.0.0/24 -j RETURN sudo iptables -t nat -A POSTROUTING -s $BRIDGE_NETWORK -d 224.0.0.0/24 -j RETURN
sudo iptables -t nat -A POSTROUTING -s $BRIDGE_IP_MASK -d 255.255.255.255/32 -j RETURN sudo iptables -t nat -A POSTROUTING -s $BRIDGE_NETWORK -d 255.255.255.255/32 -j RETURN
sudo iptables -t nat -A POSTROUTING -s $BRIDGE_IP_MASK ! -d $BRIDGE_IP_MASK -p tcp -j MASQUERADE --to-ports 1024-65535 sudo iptables -t nat -A POSTROUTING -s $BRIDGE_NETWORK ! -d $BRIDGE_NETWORK -p tcp -j MASQUERADE --to-ports 1024-65535
sudo iptables -t nat -A POSTROUTING -s $BRIDGE_IP_MASK ! -d $BRIDGE_IP_MASK -p udp -j MASQUERADE --to-ports 1024-65535 sudo iptables -t nat -A POSTROUTING -s $BRIDGE_NETWORK ! -d $BRIDGE_NETWORK -p udp -j MASQUERADE --to-ports 1024-65535
sudo iptables -t nat -A POSTROUTING -s $BRIDGE_IP_MASK ! -d $BRIDGE_IP_MASK -j MASQUERADE sudo iptables -t nat -A POSTROUTING -s $BRIDGE_NETWORK ! -d $BRIDGE_NETWORK -j MASQUERADE
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
echo echo
# Setup DHCP server # Setup DHCP server
echo "Network configuration script: DHCP server" echo "Network configuration script: DHCP server"
echo "Serving from $BRIDGE_IP" echo "Serving from $BRIDGE_IP"
export HOST_IP = $BRIDGE_IP HOST_IP=$BRIDGE_IP
export HOST_IP
echo "dhcpd.conf:" echo "dhcpd.conf:"
cat test/dhcpd.conf cat test/dhcpd.conf
echo echo
+13
View File
@@ -0,0 +1,13 @@
#!/bin/sh
sudo apt-get -y install mosquitto
# "for some reason" they think starting the server is cool
sudo cp test/mosquitto.conf /etc/mosquitto/conf.d/
sudo cp test/certs/ca.crt /etc/mosquitto/certs/
sudo cp test/certs/server.crt /etc/mosquitto/certs/
sudo cp test/certs/server.key /etc/mosquitto/certs/
sudo ss -tpln | grep 883
# so we need to restart it with the actual config
sudo systemctl restart mosquitto
sudo ss -tpln | grep 883
sudo cat /var/log/mosquitto/*
+1 -1
View File
@@ -1,4 +1,4 @@
CFLAGS = -W -Wall -Wextra -g -I. # Build options CFLAGS = -g -I. # This is a known version, no need to check
CFLAGS_MONGOOSE += -DMG_ENABLE_LINES=1 -DMG_ENABLE_IPV6=1 CFLAGS_MONGOOSE += -DMG_ENABLE_LINES=1 -DMG_ENABLE_IPV6=1
CFLAGS_EXTRA ?= -DMG_TLS=MG_TLS_BUILTIN CFLAGS_EXTRA ?= -DMG_TLS=MG_TLS_BUILTIN
+1 -1
View File
@@ -63,7 +63,7 @@ static void cb(struct mg_connection *c, int ev, void *ev_data) {
mg_tls_init(c, &opts); mg_tls_init(c, &opts);
} }
if (ev == MG_EV_HTTP_MSG) { if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/upload"), NULL)) { if (mg_match(hm->uri, mg_str("/upload"), NULL)) {
// Serve file upload // Serve file upload
+2 -2
View File
@@ -35,7 +35,7 @@ extern "C" {
#define MG_ARCH_FREERTOS 5 // FreeRTOS #define MG_ARCH_FREERTOS 5 // FreeRTOS
#define MG_ARCH_AZURERTOS 6 // MS Azure RTOS #define MG_ARCH_AZURERTOS 6 // MS Azure RTOS
#define MG_ARCH_ZEPHYR 7 // Zephyr RTOS #define MG_ARCH_ZEPHYR 7 // Zephyr RTOS
#define MG_ARCH_NEWLIB 8 // Bare metal ARM #define MG_ARCH_ARMGCC 8 // Bare metal ARM
#define MG_ARCH_CMSIS_RTOS1 9 // CMSIS-RTOS API v1 (Keil RTX) #define MG_ARCH_CMSIS_RTOS1 9 // CMSIS-RTOS API v1 (Keil RTX)
#define MG_ARCH_TIRTOS 10 // Texas Semi TI-RTOS #define MG_ARCH_TIRTOS 10 // Texas Semi TI-RTOS
#define MG_ARCH_PICOSDK 11 // Raspberry Pi Pico-SDK (RP2040, RP2350) #define MG_ARCH_PICOSDK 11 // Raspberry Pi Pico-SDK (RP2040, RP2350)
@@ -220,7 +220,7 @@ static inline int mg_mkdir(const char *path, mode_t mode) {
#endif // MG_ARCH == MG_ARCH_FREERTOS #endif // MG_ARCH == MG_ARCH_FREERTOS
#if MG_ARCH == MG_ARCH_NEWLIB #if MG_ARCH == MG_ARCH_ARMGCC
#define _POSIX_TIMERS #define _POSIX_TIMERS
#include <ctype.h> #include <ctype.h>
+258 -73
View File
@@ -18,6 +18,7 @@ static int s_num_tests = 0;
s_num_tests++; \ s_num_tests++; \
if (!(expr)) { \ if (!(expr)) { \
printf("FAILURE %s:%d: %s\n", __FILE__, __LINE__, #expr); \ printf("FAILURE %s:%d: %s\n", __FILE__, __LINE__, #expr); \
fflush(stdout); \
ABORT(); \ ABORT(); \
} \ } \
} while (0) } while (0)
@@ -374,6 +375,65 @@ static void test_sntp(void) {
#endif #endif
} }
#ifdef MQTT_LOCALHOST
#define MQTT_URL "mqtt://127.0.0.1:1883"
#else
#define MQTT_URL "mqtt://broker.hivemq.com:1883"
#endif
#if MG_TLS == MG_TLS_BUILTIN
#define MQTTS_URL "mqtts://mongoose.ws:8883" // test requires TLS 1.3
#define MQTTS_CA mg_str(s_ca_cert)
static const char *s_ca_cert =
"-----BEGIN CERTIFICATE-----\n"
"MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw\n"
"TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\n"
"cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4\n"
"WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu\n"
"ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY\n"
"MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc\n"
"h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+\n"
"0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U\n"
"A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW\n"
"T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH\n"
"B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC\n"
"B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv\n"
"KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn\n"
"OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn\n"
"jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw\n"
"qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI\n"
"rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\n"
"HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq\n"
"hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL\n"
"ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ\n"
"3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK\n"
"NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5\n"
"ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur\n"
"TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC\n"
"jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc\n"
"oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq\n"
"4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA\n"
"mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d\n"
"emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=\n"
"-----END CERTIFICATE-----\n";
#elif MG_TLS
#ifdef MQTT_LOCALHOST
#define MQTTS_URL "mqtts://127.0.0.1:8883"
#define MQTTS_CA mg_str(s_ca_cert)
static const char *s_ca_cert =
"-----BEGIN CERTIFICATE-----\n"
"MIIBFTCBvAIJAMNTFtpfcq8NMAoGCCqGSM49BAMCMBMxETAPBgNVBAMMCE1vbmdv\n"
"b3NlMB4XDTI0MDUwNzE0MzczNloXDTM0MDUwNTE0MzczNlowEzERMA8GA1UEAwwI\n"
"TW9uZ29vc2UwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASuP+86T/rOWnGpEVhl\n"
"fxYZ+pjMbCmDZ+vdnP0rjoxudwRMRQCv5slRlDK7Lxue761sdvqxWr0Ma6TFGTNg\n"
"epsRMAoGCCqGSM49BAMCA0gAMEUCIQCwb2CxuAKm51s81S6BIoy1IcandXSohnqs\n"
"us64BAA7QgIgGGtUrpkgFSS0oPBlCUG6YPHFVw42vTfpTC0ySwAS0M4=\n"
"-----END CERTIFICATE-----\n";
#else
#define MQTTS_URL "mqtts://broker.hivemq.com:8883"
#define MQTTS_CA mg_unpacked("/data/ca.pem")
#endif // MQTT_LOCALHOST
#endif
struct mqtt_data { struct mqtt_data {
char *topic; char *topic;
char *msg; char *msg;
@@ -390,8 +450,20 @@ struct mqtt_data {
static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data) { static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data) {
struct mqtt_data *test_data = (struct mqtt_data *) c->fn_data; struct mqtt_data *test_data = (struct mqtt_data *) c->fn_data;
char *buf = test_data->msg; char *buf = test_data->msg;
#if MG_TLS
if (ev == MG_EV_MQTT_OPEN) { if (c->is_tls && ev == MG_EV_CONNECT) {
struct mg_tls_opts opts;
memset(&opts, 0, sizeof(opts));
opts.ca = MQTTS_CA;
#if defined( MQTT_LOCALHOST) && MG_TLS != MG_TLS_BUILTIN
MG_ERROR(("Hostname not tested"));
#else
opts.name = mg_url_host(MQTTS_URL);
#endif
mg_tls_init(c, &opts);
} else
#endif
if (ev == MG_EV_MQTT_OPEN) {
buf[0] = *(int *) ev_data == 0 ? 'X' : 'Y'; buf[0] = *(int *) ev_data == 0 ? 'X' : 'Y';
} else if (ev == MG_EV_CLOSE) { } else if (ev == MG_EV_CLOSE) {
buf[0] = 0; buf[0] = 0;
@@ -416,35 +488,34 @@ static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data) {
mm->data.buf); mm->data.buf);
if (mm->cmd == MQTT_CMD_PUBLISH && c->is_mqtt5) { if (mm->cmd == MQTT_CMD_PUBLISH && c->is_mqtt5) {
size_t pos = 0; size_t pos = 0, i = 0, j = 0;
struct mg_mqtt_prop prop; struct mg_mqtt_prop prop;
ASSERT((pos = mg_mqtt_next_prop(mm, &prop, pos)) > 0); for (i = 0; i < 5 ; i++) {
ASSERT(prop.iv == 10 && prop.id == MQTT_PROP_MESSAGE_EXPIRY_INTERVAL); ASSERT((pos = mg_mqtt_next_prop(mm, &prop, pos)) > 0);
if (prop.id == MQTT_PROP_MESSAGE_EXPIRY_INTERVAL) {
ASSERT((pos = mg_mqtt_next_prop(mm, &prop, pos)) > 0); ASSERT(prop.iv == 10);
ASSERT(prop.id == MQTT_PROP_PAYLOAD_FORMAT_INDICATOR); j += 1;
} else if (prop.id == MQTT_PROP_PAYLOAD_FORMAT_INDICATOR) {
ASSERT((pos = mg_mqtt_next_prop(mm, &prop, pos)) > 0); j += 2;
ASSERT(prop.id == MQTT_PROP_CONTENT_TYPE); continue;
ASSERT(strncmp(prop.val.buf, "test_content_val_2", prop.val.len) == 0 && } else if (prop.id == MQTT_PROP_CONTENT_TYPE) {
prop.val.len == strlen("test_content_val_2")); ASSERT(strncmp(prop.val.buf, "test_content_val_2", prop.val.len) == 0 && prop.val.len == strlen("test_content_val_2"));
j += 4;
ASSERT((pos = mg_mqtt_next_prop(mm, &prop, pos)) > 0); } else if (prop.id == MQTT_PROP_USER_PROPERTY) {
ASSERT(prop.id == MQTT_PROP_USER_PROPERTY); if (strncmp(prop.key.buf, "test_key_1", prop.key.len) == 0 && prop.key.len == strlen("test_key_1")) {
ASSERT(strncmp(prop.key.buf, "test_key_1", prop.key.len) == 0 && ASSERT(strncmp(prop.val.buf, "test_value_1", prop.val.len) == 0 && prop.val.len == strlen("test_value_1"));
prop.key.len == strlen("test_key_1")); j += 8;
ASSERT(strncmp(prop.val.buf, "test_value_1", prop.val.len) == 0 && } else if (strncmp(prop.key.buf, "test_key_2", prop.key.len) == 0 && prop.key.len == strlen("test_key_2")) {
prop.val.len == strlen("test_value_1")); ASSERT(strncmp(prop.val.buf, "test_value_2", prop.val.len) == 0 && prop.val.len == strlen("test_value_2"));
j += 16;
ASSERT((pos = mg_mqtt_next_prop(mm, &prop, pos)) > 0); } else {
ASSERT(prop.id == MQTT_PROP_USER_PROPERTY); ASSERT(0);
ASSERT(strncmp(prop.key.buf, "test_key_2", prop.key.len) == 0 && }
prop.key.len == strlen("test_key_2")); }
ASSERT(strncmp(prop.val.buf, "test_value_2", prop.val.len) == 0 && }
prop.val.len == strlen("test_value_2"));
ASSERT((pos = mg_mqtt_next_prop(mm, &prop, pos)) == 0); ASSERT((pos = mg_mqtt_next_prop(mm, &prop, pos)) == 0);
ASSERT(j == 31);
} }
} }
(void) c; (void) c;
@@ -475,7 +546,7 @@ static void test_mqtt_base(void) {
struct mqtt_data test_data = {buf, buf, 10, 10, 0}; struct mqtt_data test_data = {buf, buf, 10, 10, 0};
struct mg_mgr mgr; struct mg_mgr mgr;
struct mg_connection *c; struct mg_connection *c;
const char *url = "mqtt://broker.hivemq.com:1883"; const char *url = MQTT_URL;
int i; int i;
mg_mgr_init(&mgr); mg_mgr_init(&mgr);
@@ -517,7 +588,11 @@ static void test_mqtt_basic(void) {
struct mg_mgr mgr; struct mg_mgr mgr;
struct mg_connection *c; struct mg_connection *c;
struct mg_mqtt_opts opts; struct mg_mqtt_opts opts;
const char *url = "mqtt://broker.hivemq.com:1883"; #if MG_TLS
const char *url = MQTTS_URL;
#else
const char *url = MQTT_URL;
#endif
int i, retries; int i, retries;
// Connect with empty client ID, no options, ergo MQTT = 3.1.1 // Connect with empty client ID, no options, ergo MQTT = 3.1.1
@@ -562,6 +637,25 @@ static void test_mqtt_basic(void) {
test_data.flags = 0; test_data.flags = 0;
opts.retransmit_id = 0; opts.retransmit_id = 0;
#if MG_TLS
// send more than 1 record, content is not relevant
{
static char somedata[21098];
mg_random(somedata, sizeof(somedata));
opts.message = mg_str_n(somedata, sizeof(somedata));
}
opts.qos = 1, opts.retain = false, opts.retransmit_id = 0;
mg_mqtt_pub(c, &opts);
tbuf[0] = 0;
for (i = 0; i < 1000 && test_data.flags == 0; i++) mg_mgr_poll(&mgr, 10);
ASSERT(test_data.flags == flags_published);
for (i = 0; i < 1000 && tbuf[0] == 0; i++) mg_mgr_poll(&mgr, 10);
ASSERT(tbuf[0] != 0); // just check we were able to send and receive
memset(mbuf + 1, 0, sizeof(mbuf) - 1);
test_data.flags = 0;
opts.retransmit_id = 0;
#endif
// Clean Disconnect ! // Clean Disconnect !
mg_mqtt_disconnect(c, NULL); mg_mqtt_disconnect(c, NULL);
for (i = 0; i < 10 && mbuf[0] != 0; i++) mg_mgr_poll(&mgr, 10); for (i = 0; i < 10 && mbuf[0] != 0; i++) mg_mgr_poll(&mgr, 10);
@@ -576,7 +670,7 @@ static void test_mqtt_ver(uint8_t mqtt_version) {
struct mg_connection *c; struct mg_connection *c;
struct mg_mqtt_opts opts; struct mg_mqtt_opts opts;
struct mg_mqtt_prop properties[5]; struct mg_mqtt_prop properties[5];
const char *url = "mqtt://broker.hivemq.com:1883"; const char *url = MQTT_URL;
int i, retries; int i, retries;
MG_DEBUG(("ver: %u", mqtt_version)); MG_DEBUG(("ver: %u", mqtt_version));
@@ -593,7 +687,7 @@ static void test_mqtt_ver(uint8_t mqtt_version) {
opts.message = mg_str("mg_will_messsage"); opts.message = mg_str("mg_will_messsage");
opts.client_id = genstring(client_id, sizeof(client_id)); opts.client_id = genstring(client_id, sizeof(client_id));
c = mg_mqtt_connect(&mgr, url, &opts, mqtt_cb, &test_data); c = mg_mqtt_connect(&mgr, url, &opts, mqtt_cb, &test_data);
for (i = 0; i < 300 && mbuf[0] == 0; i++) mg_mgr_poll(&mgr, 10); for (i = 0; i < 500 && mbuf[0] == 0; i++) mg_mgr_poll(&mgr, 10);
if (mbuf[0] != 'X') MG_INFO(("[%s]", mbuf)); if (mbuf[0] != 'X') MG_INFO(("[%s]", mbuf));
ASSERT(mbuf[0] == 'X'); ASSERT(mbuf[0] == 'X');
ASSERT(test_data.flags == 0); ASSERT(test_data.flags == 0);
@@ -664,9 +758,14 @@ static void test_mqtt_ver(uint8_t mqtt_version) {
static void test_mqtt(void) { static void test_mqtt(void) {
test_mqtt_base(); test_mqtt_base();
#ifdef NO_MQTT_TESTS
MG_ERROR(("MQTT tests skipped on request"));
(void) test_mqtt_basic, (void) test_mqtt_ver;
#else
test_mqtt_basic(); test_mqtt_basic();
test_mqtt_ver(4); test_mqtt_ver(4);
test_mqtt_ver(5); test_mqtt_ver(5);
#endif
} }
static void eh1(struct mg_connection *c, int ev, void *ev_data) { static void eh1(struct mg_connection *c, int ev, void *ev_data) {
@@ -1098,7 +1197,7 @@ static void test_http_server(void) {
struct mg_str data = mg_file_read(&mg_fs_posix, "./data/ca.pem"); struct mg_str data = mg_file_read(&mg_fs_posix, "./data/ca.pem");
ASSERT(fetch(&mgr, buf, url, "GET /ca.pem HTTP/1.0\r\n\n") == 200); ASSERT(fetch(&mgr, buf, url, "GET /ca.pem HTTP/1.0\r\n\n") == 200);
ASSERT(cmpbody(buf, data.buf) == 0); ASSERT(cmpbody(buf, data.buf) == 0);
free((void *) data.buf); mg_free((void *) data.buf);
} }
{ {
@@ -1178,7 +1277,7 @@ static void test_http_server(void) {
s = mg_file_read(&mg_fs_posix, "uploaded.txt"); s = mg_file_read(&mg_fs_posix, "uploaded.txt");
ASSERT(s.buf != NULL); ASSERT(s.buf != NULL);
ASSERT(strcmp(s.buf, "hello\nworld") == 0); ASSERT(strcmp(s.buf, "hello\nworld") == 0);
free((void *) s.buf); mg_free((void *) s.buf);
remove("uploaded.txt"); remove("uploaded.txt");
} }
@@ -1311,6 +1410,9 @@ static void test_tls(void) {
char buf[FETCH_BUF_SIZE]; char buf[FETCH_BUF_SIZE];
struct mg_tls_opts opts; struct mg_tls_opts opts;
struct mg_str data = mg_unpacked("/Makefile"); struct mg_str data = mg_unpacked("/Makefile");
char bigdata[FETCH_BUF_SIZE - 256]; // leave extra room
struct mg_str bd;
ASSERT(data.buf != NULL && data.len > 0);
memset(&opts, 0, sizeof(opts)); memset(&opts, 0, sizeof(opts));
// opts.ca = mg_str(s_tls_ca); // opts.ca = mg_str(s_tls_ca);
opts.cert = mg_unpacked("/certs/server.crt"); opts.cert = mg_unpacked("/certs/server.crt");
@@ -1321,17 +1423,29 @@ static void test_tls(void) {
ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\n\n") == 200); ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\n\n") == 200);
// MG_INFO(("%s", buf)); // MG_INFO(("%s", buf));
ASSERT(cmpbody(buf, "hello\n") == 0); ASSERT(cmpbody(buf, "hello\n") == 0);
// POST a large file, make sure we drain TLS buffers and read all, #2619 // POST a large file, several MSS but less than max TLS record length
ASSERT(data.buf != NULL && data.len > 0); // make sure we drain TLS buffers and read all, #2619
ASSERT(data.len > 3100 && data.len < 16384); // pick another file on failure
ASSERT(fetch(&mgr, buf, url, ASSERT(fetch(&mgr, buf, url,
"POST /foo/bar HTTP/1.0\n" "POST /body HTTP/1.0\n"
"Content-Length: %lu\n\n" "Content-Length: %lu\n\n"
"%s", "%s",
data.len, data.buf) == 200); data.len, data.buf) == 200);
// /body returns data back, so verify contents (both server and client send
// and receive the whole file
ASSERT(cmpbody(buf, data.buf) == 0);
// repeat with a really large "file", several times max TLS record length
bd = genstring(bigdata, sizeof(bigdata));
ASSERT(fetch(&mgr, buf, url,
"POST /body HTTP/1.0\n"
"Content-Length: %lu\n\n"
"%s",
bd.len, bd.buf) == 200);
ASSERT(cmpbody(buf, bd.buf) == 0);
#if MG_TLS == MG_TLS_BUILTIN && defined(__linux__) #if MG_TLS == MG_TLS_BUILTIN && defined(__linux__)
// fire patched server, test multiple TLS records per TCP segment handling // fire patched server, test multiple TLS records per TCP segment handling
// skip other TLS stacks to avoid "bad client hello", we are 1.3 only // skip other TLS stacks to avoid "bad client hello", we are 1.3 only
{ if (access("tls_multirec/server", X_OK) == 0) {
ASSERT(system("tls_multirec/server -d tls_multirec &") == 0); ASSERT(system("tls_multirec/server -d tls_multirec &") == 0);
sleep(1); sleep(1);
// fetch() needs to loop enough times in order to process all TLS records; // fetch() needs to loop enough times in order to process all TLS records;
@@ -1340,6 +1454,8 @@ static void test_tls(void) {
"GET /thefile HTTP/1.0\n\n") == 200); "GET /thefile HTTP/1.0\n\n") == 200);
ASSERT(cmpbody(buf, data.buf) == 0); // "thefile" links to Makefile ASSERT(cmpbody(buf, data.buf) == 0); // "thefile" links to Makefile
ASSERT(system("killall tls_multirec/server") == 0); ASSERT(system("killall tls_multirec/server") == 0);
} else {
MG_ERROR(("SKIPPED TLS MULTIPLE RECORDS TEST, tls_multirec/server NOT PRESENT"));
} }
#else #else
printf( printf(
@@ -1389,21 +1505,28 @@ static void test_http_client(void) {
mg_mgr_init(&mgr); mg_mgr_init(&mgr);
c = mg_http_connect(&mgr, url, f3, &ok); c = mg_http_connect(&mgr, url, f3, &ok);
ASSERT(c != NULL); ASSERT(c != NULL);
for (i = 0; i < 500 && ok <= 0; i++) mg_mgr_poll(&mgr, 1); for (i = 0; i < 1000 && ok <= 0; i++) mg_mgr_poll(&mgr, 1);
MG_INFO(("%d", ok)); MG_INFO(("OK: %d", ok));
ASSERT(ok == 301); ASSERT(ok == 301 || ok == 200);
mg_mgr_poll(&mgr, 0); mg_mgr_poll(&mgr, 0);
ok = 0; ok = 0;
#if MG_TLS #if MG_TLS
c = mg_http_connect(&mgr, "https://cesanta.com", f3, &ok); url = "https://cesanta.com";
opts.name = mg_url_host(url);
#if MG_TLS == MG_TLS_BUILTIN
// our TLS does not search for the proper CA in a bundle
opts.ca = mg_file_read(&mg_fs_posix, "data/e5.crt");
#endif
c = mg_http_connect(&mgr, url, f3, &ok);
ASSERT(c != NULL); ASSERT(c != NULL);
mg_tls_init(c, &opts); mg_tls_init(c, &opts);
for (i = 0; i < 1500 && ok <= 0; i++) mg_mgr_poll(&mgr, 1); for (i = 0; i < 1500 && ok <= 0; i++) mg_mgr_poll(&mgr, 1);
MG_INFO(("OK: %d", ok));
ASSERT(ok == 200); ASSERT(ok == 200);
mg_mgr_poll(&mgr, 1); mg_mgr_poll(&mgr, 1);
// Test failed host validation // Make host validationfail
c = mg_http_connect(&mgr, "https://cesanta.com", f3, &ok); c = mg_http_connect(&mgr, url, f3, &ok);
ASSERT(c != NULL); ASSERT(c != NULL);
opts.name = mg_str("dummy"); // Set some invalid hostname value opts.name = mg_str("dummy"); // Set some invalid hostname value
mg_tls_init(c, &opts); mg_tls_init(c, &opts);
@@ -1412,16 +1535,19 @@ static void test_http_client(void) {
MG_INFO(("OK: %d", ok)); MG_INFO(("OK: %d", ok));
ASSERT(ok == 777); ASSERT(ok == 777);
mg_mgr_poll(&mgr, 1); mg_mgr_poll(&mgr, 1);
opts.name = mg_url_host(url);
#if MG_TLS == MG_TLS_BUILTIN
mg_free((void *) opts.ca.buf);
#endif
// Test empty CA // Test empty CA
// Disable mbedTLS: https://github.com/Mbed-TLS/mbedtls/issues/7075 // Disable mbedTLS: https://github.com/Mbed-TLS/mbedtls/issues/7075
#if MG_TLS != MG_TLS_MBED #if MG_TLS != MG_TLS_MBED
opts.name = mg_str("cesanta.com");
opts.ca = mg_str(""); opts.ca = mg_str("");
c = mg_http_connect(&mgr, "https://cesanta.com", f3, &ok); c = mg_http_connect(&mgr, url, f3, &ok);
mg_tls_init(c, &opts); mg_tls_init(c, &opts);
ok = 0; ok = 0;
for (i = 0; i < 500 && ok <= 0; i++) mg_mgr_poll(&mgr, 10); for (i = 0; i < 1000 && ok <= 0; i++) mg_mgr_poll(&mgr, 10);
MG_INFO(("OK: %d", ok)); MG_INFO(("OK: %d", ok));
ASSERT(ok == 200); ASSERT(ok == 200);
mg_mgr_poll(&mgr, 1); mg_mgr_poll(&mgr, 1);
@@ -1434,6 +1560,7 @@ static void test_http_client(void) {
// it is guaranteed to hit IPv6 resolution path. // it is guaranteed to hit IPv6 resolution path.
c = mg_http_connect(&mgr, "http://ipv6.google.com", f3, &ok); c = mg_http_connect(&mgr, "http://ipv6.google.com", f3, &ok);
for (i = 0; i < 500 && ok <= 0; i++) mg_mgr_poll(&mgr, 10); for (i = 0; i < 500 && ok <= 0; i++) mg_mgr_poll(&mgr, 10);
MG_INFO(("OK: %d", ok));
ASSERT(ok == 200); ASSERT(ok == 200);
#endif #endif
@@ -1976,7 +2103,6 @@ static void test_timer(void) {
ASSERT(mgr.timers == NULL); ASSERT(mgr.timers == NULL);
ASSERT(mgr.conns == NULL); ASSERT(mgr.conns == NULL);
} }
} }
static bool sn(const char *fmt, ...) { static bool sn(const char *fmt, ...) {
@@ -2028,7 +2154,7 @@ static void test_str(void) {
{ {
struct mg_str s = mg_strdup(mg_str("a")); struct mg_str s = mg_strdup(mg_str("a"));
ASSERT(mg_strcmp(s, mg_str("a")) == 0); ASSERT(mg_strcmp(s, mg_str("a")) == 0);
free((void *) s.buf); mg_free((void *) s.buf);
} }
{ {
@@ -2144,11 +2270,11 @@ static void test_str(void) {
p = mg_mprintf("[%s,%M,%s]", "null", pf1, 2, 3, "hi"); p = mg_mprintf("[%s,%M,%s]", "null", pf1, 2, 3, "hi");
ASSERT(strcmp(p, "[null,5,hi]") == 0); ASSERT(strcmp(p, "[null,5,hi]") == 0);
free(p); mg_free(p);
p = mg_mprintf("[%M,%d]", pf2, 10, 7); p = mg_mprintf("[%M,%d]", pf2, 10, 7);
ASSERT(strcmp(p, "[9876543210,7]") == 0); ASSERT(strcmp(p, "[9876543210,7]") == 0);
free(p); mg_free(p);
mg_xprintf(mg_pfn_iobuf, &io, "[%M", pf2, 10); mg_xprintf(mg_pfn_iobuf, &io, "[%M", pf2, 10);
mg_xprintf(mg_pfn_iobuf, &io, ","); mg_xprintf(mg_pfn_iobuf, &io, ",");
@@ -2349,7 +2475,7 @@ static void test_str(void) {
static void fn1(struct mg_connection *c, int ev, void *ev_data) { static void fn1(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_ERROR) { if (ev == MG_EV_ERROR) {
free(*(char **) c->fn_data); // See #2263 mg_free(*(char **) c->fn_data); // See #2263
*(char **) c->fn_data = mg_mprintf("%s", (char *) ev_data); *(char **) c->fn_data = mg_mprintf("%s", (char *) ev_data);
} }
(void) c; (void) c;
@@ -2370,7 +2496,7 @@ static void test_dns_error(const char *dns_server_url, const char *errstr) {
mg_mgr_free(&mgr); mg_mgr_free(&mgr);
// MG_DEBUG(("buf: [%s] [%s]", buf, errstr)); // MG_DEBUG(("buf: [%s] [%s]", buf, errstr));
ASSERT(buf != NULL && strcmp(buf, errstr) == 0); ASSERT(buf != NULL && strcmp(buf, errstr) == 0);
free(buf); mg_free(buf);
} }
static void test_dns(void) { static void test_dns(void) {
@@ -2424,14 +2550,14 @@ static void test_dns(void) {
// 0000 00 00 00 00 00 01 00 00 00 00 00 00 03 61 62 63 .............abc // 0000 00 00 00 00 00 01 00 00 00 00 00 00 03 61 62 63 .............abc
// 0010 05 6c 6f 63 61 6c 00 00 01 00 01 .local..... // 0010 05 6c 6f 63 61 6c 00 00 01 00 01 .local.....
uint8_t d[] = { uint8_t d[] = {
0x00, 0x00, // txid: 0 0x00, 0x00, // txid: 0
0x00, 0x00, // flags: 0 (Query flag = 0) 0x00, 0x00, // flags: 0 (Query flag = 0)
0x00, 0x01, // numQuestions: 1 0x00, 0x01, // numQuestions: 1
0x00, 0x00, // numAnswers: 1 0x00, 0x00, // numAnswers: 1
0x00, 0x00, 0x00, 0x00, // additional RRs 0x00, 0x00, 0x00, 0x00, // additional RRs
0x03, 0x61, 0x62, 0x63, // "abc" 0x03, 0x61, 0x62, 0x63, // "abc"
0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, // "local" 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, // "local"
0x00, 0x00, 0x01, 0x00, 0x01 // domain end, type, class 0x00, 0x00, 0x01, 0x00, 0x01 // domain end, type, class
}; };
memset(&dm, 0, sizeof(dm)); memset(&dm, 0, sizeof(dm));
ASSERT(mg_dns_parse(d, sizeof(d), &dm) == 1); ASSERT(mg_dns_parse(d, sizeof(d), &dm) == 1);
@@ -2457,7 +2583,7 @@ static void test_util(void) {
data = mg_file_read(&mg_fs_posix, "data.txt"); data = mg_file_read(&mg_fs_posix, "data.txt");
ASSERT(data.buf != NULL); ASSERT(data.buf != NULL);
ASSERT(strcmp(data.buf, "hi") == 0); ASSERT(strcmp(data.buf, "hi") == 0);
free((void *) data.buf); mg_free((void *) data.buf);
remove("data.txt"); remove("data.txt");
ASSERT(mg_aton(mg_str("0"), &a) == false); ASSERT(mg_aton(mg_str("0"), &a) == false);
ASSERT(mg_aton(mg_str("0.0.0."), &a) == false); ASSERT(mg_aton(mg_str("0.0.0."), &a) == false);
@@ -2469,15 +2595,17 @@ static void test_util(void) {
ASSERT(ipv4 == mg_htonl(0x7f000001)); ASSERT(ipv4 == mg_htonl(0x7f000001));
ASSERT(mg_ntohl(ipv4) == 0x7f000001); ASSERT(mg_ntohl(ipv4) == 0x7f000001);
MG_STORE_BE32(&ipv4, 0x5678abcd); MG_STORE_BE32(&ipv4, 0x5678abcd);
ASSERT(((uint8_t *)&ipv4)[0] == 0x56 && ((uint8_t *)&ipv4)[1] == 0x78 && ((uint8_t *)&ipv4)[2] == 0xab && ((uint8_t *)&ipv4)[3] == 0xcd); ASSERT(((uint8_t *) &ipv4)[0] == 0x56 && ((uint8_t *) &ipv4)[1] == 0x78 &&
((uint8_t *) &ipv4)[2] == 0xab && ((uint8_t *) &ipv4)[3] == 0xcd);
ASSERT(MG_LOAD_BE32(&ipv4) == 0x5678abcd); ASSERT(MG_LOAD_BE32(&ipv4) == 0x5678abcd);
MG_STORE_BE16(&port, 0x1234); MG_STORE_BE16(&port, 0x1234);
ASSERT(((uint8_t *)&port)[0] == 0x12 && ((uint8_t *)&port)[1] == 0x34); ASSERT(((uint8_t *) &port)[0] == 0x12 && ((uint8_t *) &port)[1] == 0x34);
ASSERT(MG_LOAD_BE16(&port) == 0x1234); ASSERT(MG_LOAD_BE16(&port) == 0x1234);
ASSERT(port == mg_htons(0x1234)); ASSERT(port == mg_htons(0x1234));
ASSERT(mg_ntohs(port) == 0x1234); ASSERT(mg_ntohs(port) == 0x1234);
MG_STORE_BE24(&ipv4, 0xef2345); MG_STORE_BE24(&ipv4, 0xef2345);
ASSERT(((uint8_t *)&ipv4)[0] == 0xef && ((uint8_t *)&ipv4)[1] == 0x23 && ((uint8_t *)&ipv4)[2] == 0x45); ASSERT(((uint8_t *) &ipv4)[0] == 0xef && ((uint8_t *) &ipv4)[1] == 0x23 &&
((uint8_t *) &ipv4)[2] == 0x45);
ASSERT(MG_LOAD_BE24(&ipv4) == 0xef2345); ASSERT(MG_LOAD_BE24(&ipv4) == 0xef2345);
memset(a.ip, 0xa5, sizeof(a.ip)); memset(a.ip, 0xa5, sizeof(a.ip));
@@ -2567,7 +2695,7 @@ static void test_util(void) {
{ {
s = mg_mprintf("%3d", 123); s = mg_mprintf("%3d", 123);
ASSERT(strcmp(s, "123") == 0); ASSERT(strcmp(s, "123") == 0);
free(s); mg_free(s);
} }
{ {
@@ -2991,13 +3119,13 @@ static void test_packed(void) {
// printf("---> %s\n", buf); // printf("---> %s\n", buf);
ASSERT(fetch(&mgr, buf, url, "GET /Makefile HTTP/1.0\n\n") == 200); ASSERT(fetch(&mgr, buf, url, "GET /Makefile HTTP/1.0\n\n") == 200);
ASSERT(cmpbody(buf, data.buf) == 0); ASSERT(cmpbody(buf, data.buf) == 0);
free((void *) data.buf); mg_free((void *) data.buf);
// Load file deeper in the FS tree directly // Load file deeper in the FS tree directly
data = mg_file_read(&mg_fs_posix, "data/ssi.h"); data = mg_file_read(&mg_fs_posix, "data/ssi.h");
ASSERT(fetch(&mgr, buf, url, "GET /data/ssi.h HTTP/1.0\n\n") == 200); ASSERT(fetch(&mgr, buf, url, "GET /data/ssi.h HTTP/1.0\n\n") == 200);
ASSERT(cmpbody(buf, data.buf) == 0); ASSERT(cmpbody(buf, data.buf) == 0);
free((void *) data.buf); mg_free((void *) data.buf);
// List root dir // List root dir
ASSERT(fetch(&mgr, buf, url, "GET / HTTP/1.0\n\n") == 200); ASSERT(fetch(&mgr, buf, url, "GET / HTTP/1.0\n\n") == 200);
@@ -3298,14 +3426,14 @@ static void test_json(void) {
ASSERT(str != NULL); ASSERT(str != NULL);
// printf("---> [%s]\n", str); // printf("---> [%s]\n", str);
ASSERT(strcmp(str, "b") == 0); ASSERT(strcmp(str, "b") == 0);
free(str); mg_free(str);
json = mg_str("{\"a\": \"hi\\nthere\",\"b\": [12345, true]}"); json = mg_str("{\"a\": \"hi\\nthere\",\"b\": [12345, true]}");
str = mg_json_get_str(json, "$.a"); str = mg_json_get_str(json, "$.a");
ASSERT(str != NULL); ASSERT(str != NULL);
ASSERT(strcmp(str, "hi\nthere") == 0); ASSERT(strcmp(str, "hi\nthere") == 0);
free(str); mg_free(str);
ASSERT(mg_json_get_long(json, "$.foo", -42) == -42); ASSERT(mg_json_get_long(json, "$.foo", -42) == -42);
ASSERT(mg_json_get_long(json, "$.b[0]", -42) == 12345); ASSERT(mg_json_get_long(json, "$.b[0]", -42) == 12345);
@@ -3324,10 +3452,10 @@ static void test_json(void) {
json = mg_str("[\"YWJj\", \"0100026869\"]"); json = mg_str("[\"YWJj\", \"0100026869\"]");
ASSERT((str = mg_json_get_b64(json, "$[0]", &len)) != NULL); ASSERT((str = mg_json_get_b64(json, "$[0]", &len)) != NULL);
ASSERT(len == 3 && memcmp(str, "abc", (size_t) len) == 0); ASSERT(len == 3 && memcmp(str, "abc", (size_t) len) == 0);
free(str); mg_free(str);
ASSERT((str = mg_json_get_hex(json, "$[1]", &len)) != NULL); ASSERT((str = mg_json_get_hex(json, "$[1]", &len)) != NULL);
ASSERT(len == 5 && memcmp(str, "\x01\x00\x02hi", (size_t) len) == 0); ASSERT(len == 5 && memcmp(str, "\x01\x00\x02hi", (size_t) len) == 0);
free(str); mg_free(str);
json = mg_str("{\"a\":[1,2,3], \"ab\": 2}"); json = mg_str("{\"a\":[1,2,3], \"ab\": 2}");
ASSERT(mg_json_get_long(json, "$.a[0]", -42) == 1); ASSERT(mg_json_get_long(json, "$.a[0]", -42) == 1);
@@ -3760,12 +3888,69 @@ static void test_x25519(void) {
#endif #endif
} }
static void test_rsa(void) {
#if MG_TLS == MG_TLS_BUILTIN
const unsigned char mod[] = {
0x00, 0xba, 0xee, 0x3b, 0x0b, 0x89, 0x58, 0xa6, 0x19, 0x0d, 0x4c, 0x89,
0x1a, 0x85, 0x9a, 0xf4, 0x55, 0xc2, 0xdd, 0x0d, 0xd4, 0x4a, 0xf5, 0xed,
0xda, 0x28, 0x55, 0x2f, 0x64, 0x46, 0x21, 0x9f, 0x46, 0x5c, 0xfa, 0x37,
0x88, 0x11, 0xdf, 0xcb, 0x51, 0x73, 0x42, 0x3d, 0x5e, 0x50, 0xde, 0x11,
0x30, 0x61, 0x04, 0x59, 0xd0, 0xf4, 0x57, 0xed, 0x13, 0x90, 0x32, 0xc5,
0x3f, 0xe6, 0x66, 0xfc, 0x2a, 0x12, 0xa3, 0x1f, 0xd1, 0x77, 0x21, 0x65,
0xdf, 0x9a, 0xcf, 0x04, 0x05, 0xc3, 0x1c, 0xf8, 0x79, 0xb5, 0xf5, 0x97,
0x68, 0x98, 0x2e, 0x96, 0x85, 0x3f, 0xee, 0x71, 0x91, 0xc1, 0x54, 0x71,
0x9a, 0x80, 0x1f, 0xbe, 0x21, 0xd9, 0xc1, 0x80, 0x9b, 0xd0, 0x5d, 0xb3,
0x76, 0x3e, 0xcc, 0x14, 0x3d, 0xec, 0xb7, 0x18, 0x74, 0xfb, 0xc4, 0x0e,
0x56, 0x8d, 0x3d, 0x78, 0xe6, 0xca, 0xcd, 0x9d, 0xc6, 0x20, 0x5a, 0xeb,
0x9b, 0xc8, 0x19, 0x5e, 0xeb, 0x80, 0xd2, 0xb2, 0xfe, 0x88, 0x15, 0x5c,
0x7c, 0x6b, 0x26, 0xe0, 0x43, 0xda, 0xa4, 0x07, 0x85, 0x73, 0xc4, 0x80,
0x28, 0xcb, 0xda, 0x18, 0x56, 0x37, 0x91, 0xd6, 0x41, 0xa1, 0x0b, 0xa2,
0x77, 0xd0, 0x62, 0x31, 0xc7, 0xc2, 0x67, 0x6d, 0x75, 0x08, 0x80, 0xe7,
0xb6, 0xbe, 0xc2, 0x25, 0xc9, 0xe0, 0x2c, 0x02, 0xbf, 0x39, 0x61, 0x7e,
0x32, 0xa4, 0xc9, 0xe7, 0x91, 0xe3, 0xa0, 0xcd, 0x94, 0x24, 0xbf, 0x8c,
0xeb, 0x47, 0x76, 0x53, 0x85, 0xb3, 0xb7, 0x31, 0x80, 0x3c, 0x77, 0x10,
0x69, 0xc3, 0x04, 0xd1, 0x60, 0x4c, 0x74, 0xda, 0x15, 0x18, 0x0b, 0x20,
0x6f, 0xb3, 0x03, 0x58, 0x4a, 0xfc, 0xd1, 0xd2, 0xcf, 0x37, 0x15, 0x0a,
0x63, 0xc8, 0xe9, 0xd5, 0x7d, 0xd5, 0xf2, 0x90, 0x78, 0x53, 0x49, 0xa9,
0xc5, 0x25, 0x65, 0x5c, 0x01};
const unsigned char exp[] = {1, 0, 1}; // 65537
const unsigned char sig[] = {
0x1e, 0xb1, 0x6a, 0xcb, 0x39, 0x63, 0x12, 0xed, 0x85, 0x62, 0x4b, 0x85,
0x47, 0x25, 0x67, 0xbd, 0xbd, 0x0e, 0xaa, 0x73, 0x34, 0x5f, 0x07, 0x2b,
0xbb, 0x4f, 0xf5, 0x21, 0x88, 0xb1, 0x04, 0x2c, 0xbb, 0x52, 0x72, 0x64,
0x89, 0x45, 0x50, 0x41, 0x73, 0xca, 0xda, 0x97, 0xae, 0x81, 0x89, 0x4f,
0x83, 0x8d, 0x48, 0x65, 0x63, 0xe7, 0x82, 0x03, 0xd2, 0x40, 0x07, 0x1c,
0x86, 0x58, 0xd5, 0xac, 0x89, 0xb1, 0xca, 0x5c, 0xde, 0x21, 0x06, 0x88,
0x88, 0x0c, 0xe1, 0x20, 0xc0, 0xdf, 0xf1, 0x92, 0x9b, 0xb8, 0xa5, 0xeb,
0x6d, 0x89, 0xcc, 0x5c, 0x5c, 0x24, 0x3e, 0x9b, 0x3c, 0x35, 0x32, 0xa5,
0x04, 0x9e, 0x8c, 0x49, 0x01, 0xee, 0xbf, 0x1f, 0x2c, 0xb0, 0x52, 0xa8,
0xab, 0x79, 0x11, 0xcf, 0xb5, 0x5a, 0x16, 0xa1, 0xee, 0x21, 0x6a, 0x5a,
0x2b, 0x14, 0xae, 0x32, 0x3c, 0xa2, 0x6c, 0xa2, 0x40, 0x0c, 0xcb, 0x9e,
0x8f, 0x69, 0xab, 0xd7, 0xf3, 0xd8, 0xd1, 0xfb, 0x2d, 0xfa, 0xa9, 0x13,
0x09, 0xbf, 0xa7, 0xca, 0xc8, 0x90, 0x74, 0x23, 0x7b, 0x3e, 0xdd, 0x81,
0x32, 0xa7, 0x88, 0x42, 0x56, 0x8a, 0xcb, 0xe8, 0x8f, 0xef, 0x06, 0x9f,
0x39, 0x7e, 0x8e, 0x24, 0x07, 0xb3, 0xae, 0x7e, 0x13, 0x6b, 0xf2, 0xf8,
0x35, 0xe4, 0x16, 0x3e, 0xae, 0xf2, 0x55, 0x79, 0x10, 0x39, 0xfa, 0x70,
0x3a, 0x1b, 0x02, 0xb3, 0x2b, 0x1d, 0x44, 0xac, 0x30, 0x81, 0xd3, 0x11,
0xdd, 0x34, 0x1e, 0xcd, 0x26, 0xf5, 0x89, 0xc6, 0x55, 0x23, 0x17, 0x09,
0xd2, 0xc1, 0xdc, 0x49, 0xf9, 0x99, 0x36, 0x2b, 0xf5, 0xae, 0x42, 0x5c,
0xb7, 0x80, 0xda, 0x32, 0x69, 0x28, 0xa3, 0xee, 0xb9, 0xd4, 0x90, 0xa6,
0xab, 0x34, 0x17, 0x5e, 0xa0, 0xd6, 0xc1, 0x54, 0xc6, 0x9c, 0x58, 0x3a,
0xaf, 0xbf, 0xdc, 0x64};
unsigned char v[256]; // 2048 bits
mg_rsa_mod_pow(mod, sizeof(mod), exp, sizeof(exp), sig, sizeof(sig), v,
sizeof(v));
ASSERT(v[sizeof(v) - 1] == 0xbc);
#endif
}
static void test_crypto(void) { static void test_crypto(void) {
test_md5(); test_md5();
test_sha1(); test_sha1();
test_sha256(); test_sha256();
test_sha384(); test_sha384();
test_x25519(); test_x25519();
test_rsa();
} }
int main(void) { int main(void) {
@@ -3809,7 +3994,7 @@ int main(void) {
test_http_range(); test_http_range();
#ifndef LOCALHOST_ONLY #ifndef LOCALHOST_ONLY
test_sntp(); test_sntp();
test_mqtt(); test_mqtt(); // sorry, MQTT_LOCALHOST is also skipped
test_http_client(); test_http_client();
#else #else
(void) test_sntp, (void) test_mqtt, (void) test_http_client; (void) test_sntp, (void) test_mqtt, (void) test_http_client;
+10 -3
View File
@@ -6,12 +6,15 @@ ifeq "$(IDE)" "GCC+make"
BUILD = $(MAKE) -f ../gcc+make/Makefile PROJECTS=wizard BUILD = $(MAKE) -f ../gcc+make/Makefile PROJECTS=wizard
endif endif
ifeq "$(IDE)" "CubeIDE" ifeq "$(IDE)" "CubeIDE"
BUILD = $(MAKE) -f ../cube/Makefile PROJECTS=wizard && rm -rf workspace BUILD = mkdir -p workspace && $(MAKE) -k -f ../cube/Makefile PROJECTS=wizard && rmdir workspace
endif endif
ifeq "$(IDE)" "MCUXpresso" ifeq "$(IDE)" "MCUXpresso"
BUILD = $(MAKE) -f ../xpresso/Makefile PROJECTS=wizard && rm -rf workspace BUILD = mkdir -p workspace && $(MAKE) -k -f ../xpresso/Makefile PROJECTS=wizard && rmdir workspace
endif endif
ifeq "$(IDE)" "Keil" ifeq "$(IDE)" "ModusIDE"
BUILD = true
endif
ifeq "$(IDE)" "e2studio"
BUILD = true BUILD = true
endif endif
ifeq "$(IDE)" "Pico-SDK" ifeq "$(IDE)" "Pico-SDK"
@@ -20,6 +23,9 @@ endif
ifeq "$(IDE)" "ESP-IDF" ifeq "$(IDE)" "ESP-IDF"
BUILD = $(MAKE) -f ../esp-idf/Makefile PROJECTS=wizard BUILD = $(MAKE) -f ../esp-idf/Makefile PROJECTS=wizard
endif endif
ifeq "$(IDE)" "Keil"
BUILD = true
endif
ifeq "$(IDE)" "Arduino" ifeq "$(IDE)" "Arduino"
BUILD = true BUILD = true
endif endif
@@ -32,6 +38,7 @@ endif
firmware.bin: wizard firmware.bin: wizard
(test "$(BUILD)" == "true" && echo "NOT TESTING $(BOARD) $(IDE) $(RTOS): don't know how to test $(IDE) projects" >> test.log) || true
$(BUILD) && rm -rf wizard* $(BUILD) && rm -rf wizard*
wizard: FORCE wizard: FORCE
+33 -15
View File
@@ -29,7 +29,7 @@ done
dotest h7s3l8 GCC+make baremetal dotest h7s3l8 GCC+make baremetal
NXP="mcxn947" NXP="rt1020 rt1024 rt1040 rt1060 rt1064 rt1170 mcxn947"
NXPIDES="GCC+make MCUXpresso" NXPIDES="GCC+make MCUXpresso"
for board in $NXP; do for board in $NXP; do
for ide in $NXPIDES; do for ide in $NXPIDES; do
@@ -38,16 +38,9 @@ for board in $NXP; do
done done
done done
done done
NXP="rt1020 rt1024 rt1040 rt1060 rt1064 rt1170" NXP="rw612"
for board in $NXP; do for board in $NXP; do
dotest $board "GCC+make" "baremetal" for ide in $NXPIDES; do
done
INFINEON="xmc4400 xmc4700 xmc7200"
INFINEONIDES="GCC+make"
for board in $INFINEON; do
for ide in $INFINEONIDES; do
for rtos in "baremetal"; do for rtos in "baremetal"; do
dotest $board $ide $rtos dotest $board $ide $rtos
done done
@@ -67,10 +60,13 @@ done
dotest "tms570" "CGT+make" "baremetal" dotest "tms570" "CGT+make" "baremetal"
PICO="evb-pico evb-pico2 evb-pico2-w5100 pico-w pico2-w" INFINEON="xmc4400 xmc4700 xmc7200"
for board in $PICO; do INFINEONIDES="GCC+make ModusIDE"
for rtos in "baremetal"; do for board in $INFINEON; do
dotest $board "Pico-SDK" $rtos for ide in $INFINEONIDES; do
for rtos in "baremetal"; do
dotest $board $ide $rtos
done
done done
done done
@@ -80,10 +76,32 @@ for board in $ESP; do
dotest $board "ESP-IDF" "baremetal" dotest $board "ESP-IDF" "baremetal"
done done
PICO="evb-pico evb-pico2 evb-pico2-w5100 pico-w pico2-w"
for board in $PICO; do
for rtos in "baremetal"; do
dotest $board "Pico-SDK" $rtos
done
done
#NORDIC
RENESAS="ra6 ra8m1"
RENESASIDES="GCC+make e2studio"
for board in $RENESAS; do
for ide in $RENESASIDES; do
for rtos in "baremetal"; do
dotest $board $ide $rtos
done
done
done
# f439 not supported # f439 not supported
# h755 not supported in 3.7.0 branch; master branch currently not building # h755 not supported in 3.7.0 branch; master branch currently not building
# other ST boards (PHY address != 0) might build and not work # other ST boards (PHY address != 0) might build and not work
ZEPHYR="zephyr zephyr-w5500 f207 f429 f746 f756 f767 h563 h573 h723 h735 h743 h745 h747 h753 mcxn947 rt1060 rt1064 evb-pico" ZEPHYR="zephyr zephyr-w5500 f207 f429 f746 f756 f767 h563 h573 h723 h735 h743 h745 h747 h753 mcxn947 rt1060 rt1064 evb-pico nrf91"
for board in $ZEPHYR; do for board in $ZEPHYR; do
dotest $board "Zephyr" "baremetal" dotest $board "Zephyr" "baremetal"
done done
+7 -3
View File
@@ -1,17 +1,21 @@
# NXP command line tool is useless for this task, using Eclipse headless build
ROOT ?= $(realpath $(CURDIR)/../..) ROOT ?= $(realpath $(CURDIR)/../..)
PROJECTS ?= $(wildcard ../../tutorials/nxp/*-xpresso-*) PROJECTS ?= $(wildcard ../../tutorials/nxp/*-xpresso-*)
TARGET ?= Debug TARGET ?= Debug
DOCKER = docker run --rm -v $(ROOT):$(ROOT) -v $(CURDIR):/root -w $(CURDIR) DOCKER = docker run --rm --ulimit nofile=1024:524288 -v $(ROOT):$(ROOT) -v $(CURDIR):/root -w $(CURDIR)
IMAGE ?= scaprile/xpresso IMAGE ?= scaprile/xpresso
HEADLESS_BUILD = /usr/local/mcuxpressoide/ide/mcuxpressoide --launcher.suppressErrors -nosplash -application org.eclipse.cdt.managedbuilder.core.headlessbuild HEADLESS_BUILD = /usr/local/mcuxpressoide/ide/mcuxpressoide --launcher.suppressErrors -nosplash -application org.eclipse.cdt.managedbuilder.core.headlessbuild
all: $(PROJECTS) all: $(PROJECTS)
$(DOCKER) $(IMAGE) $(HEADLESS_BUILD) -data workspace -removeAll workspace $(DOCKER) $(IMAGE) $(HEADLESS_BUILD) -data workspace -removeAll workspace
$(DOCKER) $(IMAGE) /bin/bash -c "rm -rf workspace/.metadata workspace/.mcuxpressoide* workspace/.gitignore mcuxpresso .cache .p2 .eclipse"
$(PROJECTS): FORCE $(PROJECTS): FORCE
(make -C $@ && make -C $@ clean) || ( \ (make -C $@ && make -C $@ clean) || ( \
PROJNAME=`xq -r .projectDescription.name $@/.project` && \ PROJNAME=`xq -r .projectDescription.name $@/.project` && \
($(DOCKER) $(IMAGE) $(HEADLESS_BUILD) -data workspace -import wizard -cleanBuild $$PROJNAME/$(TARGET) || true) && \ ($(DOCKER) $(IMAGE) $(HEADLESS_BUILD) -data workspace -import $@ -cleanBuild $$PROJNAME/$(TARGET) || true) && \
test -f $(@F)/$(TARGET)/$$PROJNAME.axf ) test -f $(@F)/$(TARGET)/$$PROJNAME.axf && \
$(DOCKER) $(IMAGE) /bin/bash -c "find $@/$(TARGET) -mindepth 1 ! -name '*.ld' -exec rm -rf {} +")
FORCE: FORCE:
+1 -1
View File
@@ -33,7 +33,7 @@ static void *thread_function(void *param) {
struct thread_data *p = (struct thread_data *) param; struct thread_data *p = (struct thread_data *) param;
sleep(2); // Simulate long execution sleep(2); // Simulate long execution
mg_wakeup(p->mgr, p->conn_id, "hi!", 3); // Respond to parent mg_wakeup(p->mgr, p->conn_id, "hi!", 3); // Respond to parent
free((void *) p->message.buf); // Free all resources that were mg_free((void *) p->message.buf); // Free all resources that were
free(p); // passed to us free(p); // passed to us
return NULL; return NULL;
} }
+1 -6
View File
@@ -3,7 +3,6 @@ DELETE = rm -rf # Command to remove files
OUT ?= -o $(PROG) # Compiler argument for output file OUT ?= -o $(PROG) # Compiler argument for output file
SOURCES = main.c mongoose.c net.c packed_fs.c # Source code files SOURCES = main.c mongoose.c net.c packed_fs.c # Source code files
CFLAGS = -W -Wall -Wextra -g -I. # Build options CFLAGS = -W -Wall -Wextra -g -I. # Build options
NPX ?= npx
# Mongoose build options. See https://mongoose.ws/documentation/#build-options # Mongoose build options. See https://mongoose.ws/documentation/#build-options
CFLAGS_MONGOOSE += -DMG_ENABLE_PACKED_FS=1 CFLAGS_MONGOOSE += -DMG_ENABLE_PACKED_FS=1
@@ -27,12 +26,8 @@ $(PROG): $(SOURCES)
web_root/bundle.js: web_root/bundle.js:
curl -s https://npm.reversehttp.com/preact,preact/hooks,htm/preact,preact-router -o $@ curl -s https://npm.reversehttp.com/preact,preact/hooks,htm/preact,preact-router -o $@
# Create optimised CSS. Prerequisite: npm -g i tailwindcss tailwindcss-font-inter
web_root/main.css: web_root/index.html $(wildcard web_root/*.js)
$(NPX) tailwindcss -o $@ --minify
# Generate packed filesystem for serving Web UI # Generate packed filesystem for serving Web UI
packed_fs.c: $(wildcard web_root/*) $(wildcard certs/*) Makefile web_root/main.css web_root/bundle.js packed_fs.c: $(wildcard web_root/*) $(wildcard certs/*) Makefile web_root/bundle.js
node pack.js $(addsuffix ::gzip, $(wildcard web_root/*)) certs/* > $@ node pack.js $(addsuffix ::gzip, $(wildcard web_root/*)) certs/* > $@
mbedtls: mbedtls:
Loaded 100 of 960 files, more files were not shown because too many files have changed in this diff. Show more