Compare commits

...
467 Commits
Author SHA1 Message Date
Sergio R. Caprile b1c2ffe1a0 Merge pull request #3488 from cesanta/fut
fix unit tests
2026-04-01 11:05:28 -03:00
Sergio R. Caprile 9210a762de fix unit tests 2026-04-01 10:30:59 -03:00
Sergio R. Caprile 1620110f50 update version 2026-04-01 08:59:46 -03:00
Sergio R. Caprile 0d882f1b43 patch 2026-03-31 17:38:04 -03:00
Sergio R. Caprile 1bb85799ce fix Makefile 2026-03-25 16:20:01 -03:00
Sergio R. Caprile 12207edd55 Merge pull request #3476 from cesanta/revert-3474-mem
Revert "Make packed fs always available, and manually settable"
2026-03-24 16:24:03 -03:00
Sergio R. Caprile bb37f72a63 Revert "Make packed fs always available, and manually settable" 2026-03-24 16:23:11 -03:00
Sergio R. Caprile b852e0f8c3 Merge pull request #3474 from cesanta/mem
Make packed fs always available, and manually settable
2026-03-24 16:22:33 -03:00
cpq 25dc078af7 Make packed fs always available, and manually settable 2026-03-24 15:03:22 -03:00
Sergio R. Caprile 06f525713f Merge pull request #3473 from cesanta/tests
update tests
2026-03-23 11:45:14 -03:00
Sergio R. Caprile 05ade0ba3c update tests 2026-03-23 11:44:24 -03:00
Sergio R. Caprile ec91eaf0f3 Merge pull request #3472 from cesanta/wifi
update WiFi security definitions
2026-03-20 17:19:25 -03:00
Sergio R. Caprile 8392b9407a update WiFi security definitions 2026-03-20 17:14:38 -03:00
Sergio R. Caprile 60fe567845 Merge pull request #3470 from cesanta/zephyr
fix zephyr tests
2026-03-16 16:30:11 -03:00
Sergio R. Caprile 02e83c77a4 fix zephyr tests 2026-03-16 16:08:34 -03:00
novlean 538a1a9bfa Merge pull request #3469 from cesanta/novlean-patch-1
Add lwIP vs Mongoose benchmark article link
2026-03-16 14:11:02 +00:00
novlean 862fbd0abc Add lwIP vs Mongoose benchmark article link
article
2026-03-16 14:10:46 +00:00
Sergio R. Caprile 2121be1abe Merge pull request #3449 from cesanta/mdns
Obtain IP adress for MDNS automatically
2026-03-13 13:57:14 -03:00
cpq 0c794f19d2 Obtain IP adress for MDNS automatically 2026-03-13 13:47:25 -03:00
Sergio R. Caprile 44ef3b43d2 Merge pull request #3465 from cesanta/volatile
Add volatile to make MIP work on Diab 4.3 for PowerPC
2026-03-12 14:16:40 -03:00
cpq d27e7b3e7e Add volatile to make MIP work with Diab 4.3 on PPC 2026-03-12 13:45:15 -03:00
robertc2000 f0d1800c6b Merge pull request #3462 from cesanta/http-zero-content-len
Content-length not required if request body is empty
2026-03-12 15:40:30 +02:00
robert 81b61d335f Content-length not required if request body is empty 2026-03-12 05:54:21 -04:00
Sergey Lyubka 70f14336f1 Merge pull request #3458 from cesanta/mdnsc
Introduce new mDNS API, add mDNS client example
2026-03-10 19:38:34 +00:00
Sergio R. Caprile 19ea5aba43 Merge pull request #3459 from cesanta/st67w6
Introduce ST67W6 driver
2026-03-09 09:50:19 -03:00
Sergio R. Caprile 2a7fa4cb68 Introduce new mDNS API, add mDNS client example 2026-03-06 11:27:22 -03:00
Sergio R. Caprile 3d094ec921 Introduce ST67W6 driver 2026-03-06 09:05:37 -03:00
Sergio R. Caprile abe19d2367 Merge pull request #3457 from cesanta/cleanup
cleanup source and add some more IPV6 tests
2026-03-03 11:00:56 -03:00
Sergio R. Caprile 2b408e85e9 cleanup source and add some more IPV6 tests 2026-03-03 10:19:52 -03:00
Sergey Lyubka 27897d5514 Merge pull request #3451 from cesanta/dns
add entropy to DNS txnid
2026-03-02 09:38:51 +00:00
cpq dfcfdfd0f7 fix email 2026-02-26 14:49:48 +00:00
Sergio R. Caprile ec032181c6 add entropy to DNS txnid 2026-02-25 11:35:30 -03:00
Sergey Lyubka 1cc6a48eea Merge pull request #3441 from cesanta/certs
Update http-server to load certs from files
2026-02-23 13:50:33 +00:00
cpq 17b4054ea5 Update http-server to load certs from files 2026-02-16 15:45:20 +00:00
Sergio R. Caprile 0ec11128f7 enable Mac WolfSSL tests 2026-02-16 09:38:24 -03:00
Sergio R. Caprile ed0423f79d Merge pull request #3440 from leopoldch/fix/wolfssl-ca-loading
tls: fix WolfSSL CA certificate buffer loading
2026-02-16 09:21:45 -03:00
Léopold Chappuis ba69eb248c tls: fix WolfSSL CA certificate buffer loading 2026-02-13 22:34:13 -05:00
Sergio R. Caprile eefec28b50 Merge pull request #3429 from cesanta/w55rp20
add W55RP20 example
2026-02-13 08:34:48 -03:00
novlean 564c352d0c Merge pull request #3437 from cesanta/novlean-patch-1
Add NXP RW612 OTA Firmware Update link to README
2026-02-11 14:38:37 +00:00
novlean d20eb8b280 Add NXP RW612 OTA Firmware Update link to README
NXP OTA article
2026-02-11 14:38:23 +00:00
Sergio R. Caprile cc617d537d Merge pull request #3436 from cesanta/redirect
provide local info, fix redirect example
2026-02-09 14:51:03 -03:00
Sergio R. Caprile 205d4c6832 provide local info, fix redirect example 2026-02-09 14:42:31 -03:00
robertc2000 18cea946f1 Merge pull request #3435 from cesanta/mqttprop-fix
Improve mqtt props bound checks
2026-02-09 13:11:11 +02:00
robert 0884338b2a Improve mqtt props bound checks 2026-02-09 04:54:58 -05:00
Sergey Lyubka ba768693ed Merge pull request #3432 from cesanta/fuzzbound
validate props, fuzz them
2026-02-06 15:39:14 +00:00
Sergey Lyubka 3170261876 Merge pull request #3431 from cesanta/renesas
fix RA6M4
2026-02-06 15:36:47 +00:00
Sergio R. Caprile 2d7e8aa712 validate props, fuzz them 2026-02-06 10:53:25 -03:00
Sergio R. Caprile c083f204fc fix RA6M4 2026-02-05 15:14:18 -03:00
Sergio R. Caprile e83e13d8c6 add W55RP20 example 2026-02-05 10:45:27 -03:00
Sergio R. Caprile 70d268d95f Merge pull request #3428 from cesanta/teeleese
Fix long standing certverify failure TLS bug
2026-02-03 15:55:28 -03:00
Sergio R. Caprile 71f5556de7 standardize Makefile 2026-02-03 15:41:47 -03:00
Sergio R. Caprile 8c64266f95 Fix long standing certverify failure TLS bug 2026-02-03 15:26:38 -03:00
cpq 124b4e93c7 Switch off buffering 2026-02-02 09:56:07 +00:00
cpq e01eeed303 update 2026-02-02 08:04:39 +00:00
cpq 4b3cfb4bc0 update 2026-02-02 08:03:55 +00:00
cpq e5dfbec36d update 2026-02-02 08:03:28 +00:00
cpq be1587a933 update 2026-02-02 08:03:09 +00:00
cpq 3e87f18a29 update 2026-02-02 08:02:36 +00:00
cpq 2214cf66a4 update 2026-02-02 08:02:09 +00:00
cpq 7b886ccbde update 2026-02-02 08:01:22 +00:00
cpq b69b288d6c better clean 2026-02-01 13:21:00 +00:00
cpq 37fe251d31 Update readme 2026-01-31 13:22:37 +00:00
Sergio R. Caprile 5ec7ec141a Merge pull request #3427 from cesanta/tests
split nightly tests, fix some
2026-01-30 14:00:07 -03:00
Sergio R. Caprile e31079e107 split nightly tests, fix some 2026-01-30 13:58:04 -03:00
Sergio R. Caprile 1701fb0d03 Merge pull request #3425 from cesanta/vc98
Make built-in TLS c89-friendly
2026-01-30 12:46:59 -03:00
cpq f2ce01641e Make built-in TLS vc98-friendly 2026-01-30 11:40:26 -03:00
Sergio R. Caprile b5e4eef966 Merge pull request #3424 from cesanta/tls
Read out all pending TLS data
2026-01-30 11:25:17 -03:00
cpq b93822fc50 Read out all pending TLS data 2026-01-30 10:54:06 -03:00
Sergio R. Caprile 715f98c546 Merge pull request #3426 from cesanta/checksum
Add checksum validation
2026-01-28 13:26:00 -03:00
Sergio R. Caprile b1878dc9d0 Add checksum validation 2026-01-28 13:14:48 -03:00
Sergey Lyubka fe8cf7d9d6 Merge pull request #3423 from cesanta/singleton
Add http singleton client example
2026-01-28 14:50:27 +00:00
cpq 5fa6b0a6ef Add http singleton client example 2026-01-28 14:33:34 +00:00
Sergey Lyubka d3ab638e5d Merge pull request #3422 from cesanta/redir
Add http redirect example
2026-01-28 14:29:24 +00:00
cpq 44e773af54 Add http redirect example 2026-01-28 10:29:46 +00:00
Sergio R. Caprile ece3f43f34 Merge pull request #3421 from cesanta/becksum
Becksum
2026-01-27 10:40:30 -03:00
Sergio R. Caprile edd1350864 make tests big-endian- and Docker-friendly 2026-01-27 10:32:50 -03:00
Sergio R. Caprile 8e0ef3ca5c rewrite L4 checksum calculation 2026-01-27 10:32:50 -03:00
Sergio R. Caprile b74913ded5 Merge pull request #3418 from cesanta/down
Fast fail mg_connect() if network is down
2026-01-27 09:50:54 -03:00
Sergio R. Caprile 42abbb7e55 Merge pull request #3417 from cesanta/ota
Add OTA over mqtt example
2026-01-27 09:01:56 -03:00
cpq a4869febf6 Add OTA over mqtt example 2026-01-27 10:51:37 +00:00
cpq b10355a536 Fast fail mg_connect() if network is down 2026-01-27 10:46:42 +00:00
cpq e86d4da129 Export mg_pfn_iobuf_noresize 2026-01-24 11:32:32 +00:00
cpq 46ad050cea Less noisy tls_builtin 2026-01-23 06:47:39 +00:00
robertc2000 2a7cf8d5a7 Merge pull request #3416 from cesanta/tests-xq
install xq
2026-01-22 16:39:33 +02:00
robert 07fd086230 install xq 2026-01-22 09:15:33 -05:00
Sergio R. Caprile f040d094ea Merge pull request #3414 from cesanta/addnochacha
add test for no chacha20
2026-01-21 15:08:05 -03:00
Sergio R. Caprile f101d1422a add test for no chacha20 2026-01-21 15:06:24 -03:00
Sergio R. Caprile 6631c5db87 Merge pull request #3413 from cesanta/fixbe
fix one too many checks in chacha20
2026-01-21 14:51:03 -03:00
Sergio R. Caprile c429a0dc56 fix one too many checks in chacha20 2026-01-21 14:42:55 -03:00
Sergio R. Caprile 3f59974639 Merge pull request #3412 from cesanta/unbreak
unbreak stuff after last commit
2026-01-20 18:58:12 -03:00
Sergio R. Caprile c10a88b64b unbreak stuff after last commit 2026-01-20 18:40:36 -03:00
cpq d5e5b3397d Add RSA & chain support 2026-01-20 18:23:58 +00:00
Sergio R. Caprile ab83acf2d1 Merge pull request #3411 from cesanta/rndvc98
Fix rnd stuff in vc98 image
2026-01-16 10:47:26 -03:00
Sergio R. Caprile 1db25117b0 Fix rnd stuff in vc98 image 2026-01-16 10:27:13 -03:00
novlean bd1271dd41 Merge pull request #3410 from cesanta/novlean-patch-1
Add STM32 Ethernet and caches article link
2026-01-15 13:42:12 +00:00
novlean 5dddbb3fce Add STM32 Ethernet and caches article link
new article
2026-01-15 13:42:00 +00:00
Sergio R. Caprile a28decbef4 Merge pull request #3409 from cesanta/eseenetepe
Allow more than 1 address in received DHCP options
2026-01-14 17:40:25 -03:00
Sergio R. Caprile 73d9c125c0 Allow more than 1 address in received DHCP options 2026-01-14 17:30:48 -03:00
Sergio R. Caprile 667abfb5e1 disable failing tests (issues created) 2026-01-14 16:59:24 -03:00
Sergey Lyubka 8c65c2f9af Merge pull request #3407 from cesanta/unsub
Add mg_mqtt_unsub()
2026-01-14 11:17:50 +00:00
cpq f36205e65f Add mg_mqtt_unsub() 2026-01-14 04:36:50 -05:00
Sergio R. Caprile e2c0b2b477 Merge pull request #3406 from cesanta/reserved
allow creative usage of TCP reserved space in 'flags'
2026-01-12 13:56:18 -03:00
Sergio R. Caprile 29254ce84b allow creative usage of TCP reserved space in 'flags' 2026-01-12 12:27:36 -03:00
Sergio R. Caprile 1a0716ae4d Merge pull request #3404 from cesanta/der
Allow comments in PEM
2026-01-12 11:58:41 -03:00
Sergio R. Caprile e46ee68a95 nit 2026-01-12 10:55:40 -03:00
Sergio R. Caprile db496fd7dd remove respective old comment 2026-01-12 10:54:15 -03:00
cpq 0a3e129527 Allow comments in PEM 2026-01-12 10:54:15 -03:00
Sergio R. Caprile 12491777bb Merge pull request #3405 from cesanta/cache7
Synopsys driver handles STM32H7 and N6 DCACHE
2026-01-12 10:52:49 -03:00
Sergio R. Caprile ad4b87e24a Synopsys driver handles STM32H7 and N6 DCACHE
(proper memory placement required)
2026-01-12 10:25:26 -03:00
Sergio R. Caprile 7ffc51d38e Merge pull request #3398 from cesanta/zeph
Disable dirent in zephyr
2026-01-08 09:22:36 -03:00
cpq c9243c3f47 Disable dirent in zephyr 2026-01-08 08:50:05 +00:00
Sergey Lyubka 0d6c424e62 Merge pull request #3397 from cesanta/cube
Add support for N6 in ARCH_CUBE
2026-01-07 18:16:27 +00:00
Sergio R. Caprile dc9395c904 Add support for N6 in ARCH_CUBE 2026-01-07 14:03:37 -03:00
Sergio R. Caprile 2bb750070a Merge pull request #3395 from cesanta/tests
unbreak net_builtin tests
2026-01-07 10:59:38 -03:00
Sergio R. Caprile 17b0b65cab unbreak net_builtin tests 2026-01-07 10:48:22 -03:00
Sergio R. Caprile b5b63e731c Merge pull request #3394 from cesanta/match
avoid unlikely and harmless but possible read out of bounds
2026-01-07 10:38:42 -03:00
Sergio R. Caprile 7e376bb860 avoid unlikely and harmless but possible read out of bounds 2026-01-07 10:33:34 -03:00
cpq b313d697ff Limit queue fetches 2026-01-07 06:36:44 +00:00
cpq 1cadd2b2aa Fetch multiple frames from the queue 2026-01-07 05:53:55 +00:00
cpq f40b377fff Make MG_TCPIP_WIN tunable 2026-01-07 05:46:39 +00:00
cpq 43509c1781 Enable zephyr dirent 2026-01-06 18:16:54 +00:00
novlean 209d1dd426 Merge pull request #3392 from cesanta/novlean-patch-1
Update copyright year in LICENSE file
2026-01-05 13:00:15 +00:00
novlean 1f9e1a38b5 Update copyright year in LICENSE file
2026
2026-01-05 13:00:04 +00:00
Sergio R. Caprile 69936ac9f6 Merge pull request #3391 from cesanta/lwipdoze
fix lwIP redefinition of nfds_t
2026-01-05 08:48:06 -03:00
Sergio R. Caprile 6de419d14c fix lwIP redefinition of nfds_t 2026-01-02 14:22:55 -03:00
Sergio R. Caprile 1200f50e2e Merge pull request #3382 from cesanta/mcast
Make mcast/bcast consistent across stacks
2025-12-29 14:24:51 -03:00
Sergio R. Caprile 73bec74380 Make mcast/bcast consistent across stacks
Fix net_builtin inconsistency
2025-12-29 14:22:59 -03:00
Sergio R. Caprile f70647e28e Merge pull request #3386 from cesanta/mbed
Mbedtls nits
2025-12-29 13:30:10 -03:00
cpq effa61f9b2 Mbedtls nits 2025-12-29 13:29:27 -03:00
novlean b8bde63554 Merge pull request #3385 from cesanta/novlean-patch-1
Remove RP2350 OTA Firmware Update link from README
2025-12-24 10:08:49 +01:00
novlean 409d3d388a Remove RP2350 OTA Firmware Update link from README 2025-12-24 10:08:37 +01:00
Sergio R. Caprile 2c4bf4cea4 optimize for size, as everyone else 2025-12-23 14:06:06 -03:00
Sergio R. Caprile 1b9c3a0fb0 Merge pull request #3383 from cesanta/zeph
Zephyr nits
2025-12-23 13:45:42 -03:00
cpq 71cc0cfd80 Zephyr nits 2025-12-23 13:12:56 -03:00
Sergio R. Caprile 63da5aa403 Merge pull request #3381 from cesanta/tests
add on-demand test workflow
2025-12-19 14:32:21 -03:00
Sergio R. Caprile cb13900c32 add on-demand test workflow 2025-12-19 14:31:23 -03:00
Sergio R. Caprile 926a0e2cf2 Merge pull request #3380 from cesanta/l2
fix wrong length returned from l2_eth_rx
2025-12-19 14:18:42 -03:00
Sergio R. Caprile 2bfcfeb359 fix wrong length returned from l2_eth_rx 2025-12-19 14:11:13 -03:00
Sergio R. Caprile 16d8e3b4f9 restrict fuzz run time below GH allowed time 2025-12-18 11:03:17 -03:00
Sergio R. Caprile 682fe2c9a0 try extending fuzz running time 2025-12-17 19:12:02 -03:00
Sergio R. Caprile bdd309b10b Merge pull request #3379 from cesanta/moretests
add more tests, fix NDP
2025-12-17 17:45:17 -03:00
Sergio R. Caprile 21fbf9cdc5 add more tests, fix NDP 2025-12-17 17:39:09 -03:00
Sergio R. Caprile 9ed98cecff Merge pull request #3378 from cesanta/fuzz
fix fuzz, add ICMP tests
2025-12-17 17:36:08 -03:00
Sergio R. Caprile ab4e229f57 fix fuzz, add ICMP tests 2025-12-17 13:22:24 -03:00
novlean 7feab86700 Merge pull request #3377 from cesanta/novlean-patch-1
Add STM32 OTA Firmware Update link to README
2025-12-17 15:39:23 +00:00
novlean 6bc0af5dd0 Add STM32 OTA Firmware Update link to README 2025-12-17 15:39:06 +00:00
Sergio R. Caprile 6cb685b700 fix fuzzer 2025-12-16 16:46:03 -03:00
cpq 5c582c35d8 ota_frdm -> ota_rw612 2025-12-16 05:10:34 +00:00
Sergey Lyubka 10ab9ae1ea Merge pull request #3370 from cesanta/l2
Decouple from Ethernet, introduce "l2"
2025-12-15 14:49:56 +00:00
cpq 756d127cab C89 nitpick 2025-12-15 10:03:12 +00:00
Sergio R. Caprile a49eb47a91 Merge pull request #3373 from cesanta/mbedtls4
Add support for MbedTLS 4
2025-12-12 20:23:43 -03:00
Sergio R. Caprile e15056a9e4 Add support for MbedTLS 4 2025-12-12 20:19:36 -03:00
Sergio R. Caprile 66d4069644 Decouple from Ethernet, introduce "l2" 2025-12-12 13:46:20 -03:00
novlean 9aae863956 Merge pull request #3369 from cesanta/novlean-patch-1
Remove MQTT article link from README
2025-12-11 16:39:09 +00:00
novlean 878ec8a86c Remove MQTT article link from README 2025-12-11 16:38:44 +00:00
Sergio R. Caprile 8fccfca17b Merge pull request #3368 from cesanta/1000m
Add support for GbE
2025-12-10 13:43:01 -03:00
Sergio R. Caprile 69925c774d Add support for GbE 2025-12-10 10:23:47 -03:00
Sergio R. Caprile c1298973e1 Merge pull request #3367 from cesanta/rtl8211
Add support for RTL8211
2025-12-10 09:55:40 -03:00
Sergio R. Caprile bedda34515 Add support for RTL8211 2025-12-10 09:53:55 -03:00
Sergio R. Caprile 767b0ab90b Merge pull request #3366 from cesanta/ip6
Add support for prefix, link local and global in same net
2025-12-08 16:09:35 -03:00
Sergio R. Caprile b0109c3319 Add support for prefix, link local and global in same net 2025-12-08 16:05:32 -03:00
Sergio R. Caprile a42271a088 Merge pull request #3360 from cesanta/tests
fix tests not uploading on failure
2025-12-08 10:56:33 -03:00
Sergio R. Caprile 154e471256 Merge pull request #3361 from cesanta/neats
fix IPv6
2025-12-08 10:32:28 -03:00
cpq bfc411acaf Squash warning 2025-12-07 14:31:28 +00:00
cpq 2acbb0ad62 Using mg_str 2025-12-06 18:59:45 +00:00
Sergio R. Caprile 60ce504489 fix IPv6 2025-12-05 16:22:16 -03:00
Sergio R. Caprile 22b8eda0df fix tests not uploading on failure 2025-12-05 14:19:24 -03:00
Sergio R. Caprile 80ed81583e Merge pull request #3359 from cesanta/tests
fix Wizard-depent tests (track changes)
2025-12-05 13:26:48 -03:00
Sergio R. Caprile ce0c3a0fe7 fix Wizard-depent tests (track changes) 2025-12-05 13:23:43 -03:00
Sergey Lyubka 492c6385da Merge pull request #3358 from cesanta/diab
Add support for Windriver's Diab v4 (stricter C89 w/ extensions)
2025-12-05 10:32:51 +00:00
Sergio R. Caprile 5b023cb85b Add support for Windriver's Diab v4 (stricter C89) 2025-12-04 13:58:49 -03:00
Sergio R. Caprile 4717a15c17 Merge pull request #3357 from cesanta/atonscope
fix mg_aton not setting is_ip6 with scope_ids
2025-12-04 12:22:06 -03:00
Sergio R. Caprile d6e7f8ee83 fix mg_aton not setting is_ip6 with scope_ids 2025-12-04 12:18:45 -03:00
Sergio R. Caprile 17ff656a7d Merge pull request #3354 from cesanta/closefree
do not serve files when closing
2025-12-03 15:39:21 -03:00
Sergio R. Caprile 4e8965cce5 do not serve files when closing 2025-12-03 14:25:55 -03:00
Sergey Lyubka b3d27a3c43 Merge pull request #3353 from cesanta/safety-net
Add safety nets for lousy networks
2025-12-03 15:49:41 +00:00
Sergio R. Caprile 66dcca9392 Add safety nets for lousy networks 2025-12-03 11:31:47 -03:00
Sergio R. Caprile 0f1a3cf84b Merge pull request #3348 from cesanta/dhcp
allow no options in DHCP msgs
2025-12-01 10:46:40 -03:00
Sergio R. Caprile a4b7025396 allow no options in DHCP msgs 2025-12-01 10:46:03 -03:00
Sergey Lyubka 9c148fd47e Merge pull request #3351 from cesanta/dnssd
Introduce DNS-SD using mDNS
2025-12-01 10:10:17 +00:00
Sergio R. Caprile 293d8c22e1 Introduce DNS-SD using mDNS 2025-11-28 16:12:08 -03:00
Sergio R. Caprile 5f2ff680d5 Merge pull request #3350 from cesanta/portenta
fix Portenta Cube after cyw.h updates
2025-11-27 17:09:43 -03:00
Sergio R. Caprile 8eaca9437e fix Portenta Cube after cyw.h updates 2025-11-27 17:08:00 -03:00
cpq 6e72bf4b5f less verbose cyw driver 2025-11-26 16:27:51 +00:00
cpq 710e7b2004 less verbose cyw driver 2025-11-26 16:24:16 +00:00
Sergio R. Caprile 666a3b68e9 update mip test 2025-11-24 16:11:00 -03:00
Sergio R. Caprile 02e97adbef no router => no route 2025-11-24 15:09:35 -03:00
Sergio R. Caprile 236724ea29 fix mg_send() failing on 0 length 2025-11-19 17:02:28 -03:00
Sergio R. Caprile b503915ca5 update version 2025-11-19 10:04:04 -03:00
Sergio R. Caprile 156db0bc5e enable CYW driver autoinit 2025-11-19 09:57:37 -03:00
Sergey Lyubka 11b6bd7d9c Merge pull request #3338 from cesanta/tls
Fix 2-way auth max msg size, + some neats
2025-11-18 00:46:38 +00:00
Sergio R. Caprile 7ca952faa6 Merge pull request #3342 from cesanta/lsnb4ip
Allow listeners to start before stack is ready
2025-11-17 15:38:38 -03:00
Sergio R. Caprile 4fc40f0ffb Allow listeners to start before stack is ready 2025-11-17 15:23:37 -03:00
cpq cac4b3e254 Fix TM4C warnings on TI compiler (C89) 2025-11-14 06:49:53 +00:00
robert 0d5cb5cbcc undef ENET 2025-11-13 08:02:55 -05:00
Sergio R. Caprile a35901121b Fix 2-way auth max msg size, + some neats 2025-11-12 20:13:06 -03:00
novlean e0740fc2ca Merge pull request #3337 from cesanta/novlean-patch-1
Update README.md
2025-11-10 16:30:57 +00:00
novlean 7d22b5fe18 Update README.md
article 9 added
2025-11-10 16:30:44 +00:00
Sergey Lyubka d2e66ac58d Merge pull request #3325 from cesanta/oom
Handle OOM situations
2025-11-06 14:53:46 +00:00
Sergio R. Caprile 34cc8da87e Merge pull request #3335 from cesanta/mip6
enable IPv6 fuzzing
2025-11-05 19:01:06 -03:00
Sergio R. Caprile 1957ba8ffe Merge pull request #3334 from cesanta/tls
increase TLS fuzz depth
2025-11-05 17:42:29 -03:00
Sergio R. Caprile 72758812f5 increase TLS fuzz depth 2025-11-05 17:41:39 -03:00
Sergio R. Caprile ab5a0c43de enable IPv6 fuzzing 2025-11-05 16:43:51 -03:00
Sergio R. Caprile c8291e4ae9 add OOM handling to apps 2025-11-05 14:01:49 -03:00
Sergio R. Caprile 84e9ea76db wip 2025-11-05 13:55:14 -03:00
Sergio R. Caprile b8994f8bc3 Handle OOM situations in iobuf expansion 2025-11-05 13:53:18 -03:00
Sergio R. Caprile b53d8439e5 Merge pull request #3282 from cesanta/mip6
Introduce IPv6, unit tests pass
2025-11-05 11:58:26 -03:00
Sergio R. Caprile 337e8abf2f Introduce IPv6, unit tests pass 2025-11-05 11:04:23 -03:00
Sergio R. Caprile f0bc1c031f Merge pull request #3331 from cesanta/tls2
TLS: fix resuming handshake, fix improper cert req length
2025-11-04 17:08:34 -03:00
Sergio R. Caprile 19d2b93ec7 add IPaddress type SAN elements 2025-11-04 16:55:03 -03:00
Sergio R. Caprile e0304f2b8f TLS: fix resuming handshake, cert req length, 2-way auth app key generation and handling 2025-11-04 15:35:28 -03:00
Sergey Lyubka f7a86f8cf1 Merge pull request #3328 from cesanta/memory
Add memory management example, o1heap flavor
2025-11-01 17:08:42 +00:00
Sergio R. Caprile 340f0dbf89 Merge pull request #3329 from cesanta/updtst
update cesanta.com CA cert
2025-10-30 14:50:17 -03:00
Sergio R. Caprile d90b62d911 update cesanta.com CA cert 2025-10-30 14:45:20 -03:00
Sergio R. Caprile d84aff6420 Add memory management example, o1heap flavor 2025-10-29 15:51:42 -03:00
Sergio R. Caprile b3b73f4751 Merge pull request #3327 from cesanta/printoom
close connection on OOM when printing
2025-10-29 15:48:57 -03:00
Sergio R. Caprile 3c7b2dcd6d close connection on OOM when printing 2025-10-29 15:41:00 -03:00
Sergio R. Caprile 49470f9bd2 Merge pull request #3326 from cesanta/ethram
Be less intrusive with non-ld-savvy users
2025-10-28 11:06:55 -03:00
Sergio R. Caprile f7cf4f60ef Be less intrusive with non-ld-savvy users 2025-10-28 11:03:58 -03:00
novlean 7e0d06689e Merge pull request #3323 from cesanta/novlean-patch-1
Added new article
2025-10-27 17:53:28 +00:00
novlean b843957bd2 Add link for limiting TCP/IP RAM usage on STM32 2025-10-27 17:53:07 +00:00
Sergio R. Caprile 1a0167eb6d Merge pull request #3322 from cesanta/tests
fix error logs not uploading on test failure
2025-10-27 13:53:17 -03:00
Sergio R. Caprile 6ea3b98941 fix error logs not uploading on test failure 2025-10-27 13:49:35 -03:00
Sergio R. Caprile 4b0b93d4f3 Merge pull request #3307 from cesanta/openssl
improve resiliency
2025-10-13 10:55:42 -03:00
Sergio R. Caprile 64abf061bf improve resiliency 2025-10-13 10:43:45 -03:00
Sergio R. Caprile 05d5c68982 Merge pull request #3304 from cesanta/uniram
uniformize memory attributes
2025-10-13 09:41:52 -03:00
Sergio R. Caprile 235dafe646 Merge pull request #3305 from cesanta/chacha
improve error handling with ChaCha
2025-10-10 14:00:02 -03:00
Sergio R. Caprile 0cc40b0c70 improve error handling with ChaCha 2025-10-10 13:58:53 -03:00
Sergio R. Caprile 07a0d1265b uniformize memory attributes 2025-10-10 11:07:31 -03:00
Sergio R. Caprile 967d746574 fix Espressif deprecating ESP_IF_WIFI_STA and replacing it with WIFI_IF_STA 2025-10-09 11:43:01 -03:00
Sergey Lyubka bd12cb1b87 Merge pull request #3302 from cesanta/stm32h
Allow STM32H driver DMA bufs be placed elsewhere
2025-10-09 14:15:45 +01:00
cpq a21ca5d40b Allow STM32H driver DMA bufs be placed elsewhere 2025-10-09 13:16:50 +01:00
Sergio R. Caprile 2d399107fb Merge pull request #3299 from cesanta/tests
fix Espressif deprecating ESP_IF_WIFI_STA and replacing it with WIFI_…
2025-10-08 10:44:06 -03:00
Sergio R. Caprile 03bfa3806b fix Espressif deprecating ESP_IF_WIFI_STA and replacing it with WIFI_IF_STA (ugly) 2025-10-08 10:32:32 -03:00
Sergio R. Caprile 6536ae9bcc remove corpus 2025-10-08 09:38:27 -03:00
robertc2000 e8fc817a0c Merge pull request #3295 from cesanta/mcxe247
Add NXP MCXE driver support
2025-10-06 11:16:02 +03:00
robert e621ade392 Add NXP MCXE driver support 2025-10-06 04:07:51 -04:00
Sergio R. Caprile 3273c20ca9 Merge pull request #3293 from cesanta/tests
fix for non-64-bit test platforms
2025-10-01 17:25:01 -03:00
Sergio R. Caprile a6b2124fd5 fix for non-64-bit test platforms 2025-10-01 17:06:39 -03:00
Sergio R. Caprile 5a1ff125d7 Merge pull request #3292 from cesanta/tests
fixes for C89 (remove mg_queue_vprintf())
2025-10-01 14:04:54 -03:00
Sergio R. Caprile ad58a48144 fixes for C89 2025-10-01 13:51:37 -03:00
Sergio R. Caprile a205fd7877 Merge pull request #3291 from cesanta/tests
fix fuzzers for IPv6
2025-10-01 11:55:44 -03:00
Sergio R. Caprile 776360ca93 fix fuzzers for IPv6 2025-10-01 11:39:21 -03:00
cpq af7602497d Squash warning 2025-09-30 16:43:41 +01:00
Sergio R. Caprile 0f83c2a6e5 Merge pull request #3290 from cesanta/stm32n6
Add STM32N driver support
2025-09-30 08:20:15 -03:00
robert 0d58748e63 Add STM32N driver support 2025-09-30 03:48:42 -04:00
Sergio R. Caprile 01902bb8b9 Merge pull request #3289 from hgarrereyn/master
fix wrong call and undefined use of va_args in mg_queue_vprintf
2025-09-29 14:08:57 -03:00
Sergey Lyubka e28e9aa1d7 Merge pull request #3287 from cesanta/2way
Fix 2-way auth, fix skip hostname validation
2025-09-29 11:49:18 +01:00
hgarrereyn 587e79dc05 fix use of va_args in mg_queue_vprintf, fixes #3285 2025-09-26 14:28:10 -04:00
Sergio R. Caprile acd65f2340 Merge pull request #3288 from cesanta/iobuf
fix iobuf shrink to less than current len
2025-09-26 14:37:34 -03:00
Sergio R. Caprile d55fb80746 fix iobuf shrink to less than current len 2025-09-26 14:34:17 -03:00
Sergio R. Caprile 4536694f20 Fix 2-way auth, fix skip hostname validation 2025-09-26 13:40:15 -03:00
Sergio R. Caprile 2c5a6d4df6 update tests 2025-09-23 13:32:06 -03:00
Sergio R. Caprile 4c8e219643 Merge pull request #3281 from cesanta/tls36retro
add call to mbedtls_psa_free()for MbedTLS >= 3, defaulting to TLS 1.3…
2025-09-23 13:25:34 -03:00
Sergio R. Caprile daeca8128b add call to mbedtls_psa_free()for MbedTLS >= 3, defaulting to TLS 1.3, retroactively documented in 3.6.1 2025-09-23 11:31:10 -03:00
Sergey Lyubka fe6d357858 Merge pull request #3273 from cesanta/dhcpname
Make DHCP name size configurable
2025-09-20 16:43:36 +01:00
Sergio R. Caprile a99cc3dbaf fix statechange test 2025-09-17 10:45:28 -03:00
Sergio R. Caprile 3c4c04199a fix statechange test 2025-09-17 10:29:06 -03:00
Sergio R. Caprile 8ca692100f tests 2025-09-17 10:18:01 -03:00
Sergio R. Caprile 0b9f28b8e3 Make DHCP name size configurable 2025-09-15 09:40:43 -03:00
Sergio R. Caprile 1dff394b63 unbreak ARP 2025-09-12 11:11:00 -03:00
Sergio R. Caprile f4c35d1036 Merge pull request #3269 from cesanta/wifi612
add support for NXP Wifi in RW612, in an example
2025-09-11 17:51:54 -03:00
Sergio R. Caprile 81c166ad74 add support for NXP Wifi in RW612, in an example 2025-09-11 09:36:04 -03:00
Sergio R. Caprile 1f56776050 compiler nits 2025-09-10 19:27:17 -03:00
Sergio R. Caprile b3a0e7b884 fix extension header traversal 2025-09-10 18:57:15 -03:00
Sergio R. Caprile 8594507b5b Merge pull request #3267 from cesanta/wifi
move debugging logs
2025-09-09 16:24:16 -03:00
Sergio R. Caprile fa811ce12b move debugging logs 2025-09-09 16:20:54 -03:00
Sergio R. Caprile c1ef477ff3 Merge pull request #3266 from cesanta/wifi
Move interface stuff out of user handlers
2025-09-09 14:29:29 -03:00
Sergio R. Caprile 4be3a96987 Merge pull request #3265 from cesanta/alip
align mg_addr to 32- and 64-bits
2025-09-09 10:19:58 -03:00
Sergio R. Caprile 387f875aa1 Move interface stuff out of user handlers 2025-09-08 16:00:44 -03:00
Sergio R. Caprile cc069e7e5d align mg_addr to 32- and 64-bits 2025-09-08 11:43:28 -03:00
Sergey Lyubka df994df611 Merge pull request #3264 from cesanta/opts
Fix IP opts
2025-09-07 15:53:34 +01:00
Sergio R. Caprile 8f77fd3940 fixes for Keil 2025-09-04 19:45:18 -03:00
Sergio R. Caprile 7530062e4b fixes for Keil 2025-09-04 19:43:17 -03:00
Sergio R. Caprile 0e63510708 Fix IP opts
Refactor payload handling
Refactor UDP port unreachable
Add UDP unit tests
Introduce basic IPv6 handling
2025-09-02 15:58:02 -03:00
Sergio R. Caprile 26260a1d88 Merge pull request #3263 from cesanta/tests
building health dashboard
2025-09-02 10:36:31 -03:00
Sergio R. Caprile 9e82844f10 building health dashboard 2025-09-02 10:35:44 -03:00
Sergio R. Caprile 0568b5a75b Merge pull request #3262 from cesanta/tests
Push test results for health dashboard
2025-09-01 15:17:15 -03:00
Sergio R. Caprile 3baabebb34 Push test results for health dashboard 2025-09-01 14:52:37 -03:00
Sergio R. Caprile bf4dd15317 Merge pull request #3261 from cesanta/tests
Start pushing test results for health dashboard
2025-08-29 14:29:50 -03:00
Sergio R. Caprile b0f2f9621a Start pushing test results for health dashboard 2025-08-29 14:28:44 -03:00
Sergey Lyubka 04d6d05e9e Merge pull request #3258 from cesanta/tcput
Fix TCP error handling
2025-08-29 15:18:52 +01:00
Sergio R. Caprile 7339c7dfe7 Fix TCP error handling
Add unit tests for TCP error handling
Account for options in TCP header for payload start address calculation
Take UDP payload length from UDP header
2025-08-29 10:34:17 -03:00
Sergio R. Caprile c1152f5eeb Merge pull request #3255 from cesanta/tests
add support for health dashboard
2025-08-28 14:54:28 -03:00
Sergio R. Caprile 024922d566 add support for health dashboard 2025-08-27 13:35:38 -03:00
Sergio R. Caprile 6f64c8c0de Merge pull request #3254 from cesanta/upwiz
update to new wizard backend API
2025-08-27 08:59:55 -03:00
Sergio R. Caprile 2a5ac3c2e5 update to new wizard backend API 2025-08-26 19:04:10 -03:00
Sergey Lyubka 7b0120f0c2 Merge pull request #3251 from cesanta/backlog
add TCP backlog to handle client MSS
2025-08-23 21:06:12 +01:00
Sergio R. Caprile 7ee1f14a6d add TCP backlog to handle client MSS 2025-08-22 11:42:41 -03:00
Sergio R. Caprile 3aaf7d0da7 Merge pull request #3252 from cesanta/idfbrokeit
handle IDF breaking UART API
2025-08-21 18:21:30 -03:00
Sergio R. Caprile 434f3f8415 handle IDF breaking UART API 2025-08-21 18:15:21 -03:00
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
1446 changed files with 983072 additions and 12748 deletions

No files matched your search

+1 -4
View File
@@ -11,17 +11,14 @@ jobs:
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- run: if ./test/match_changed_files.sh '^src/' ; then echo GO=1 >> $GITHUB_ENV ; fi
- name: Build Fuzzers
id: build
if: ${{ env.GO == 1 }}
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with:
oss-fuzz-project-name: 'mongoose'
dry-run: false
language: c++
- name: Run Fuzzers
if: ${{ env.GO == 1 }}
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
oss-fuzz-project-name: 'mongoose'
@@ -30,7 +27,7 @@ jobs:
language: c++
- name: Upload Crash
uses: actions/upload-artifact@v4
if: env.GO == 1 && failure() && steps.build.outcome == 'success'
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
path: ./out/artifacts
+2 -2
View File
@@ -2,8 +2,8 @@ name: "CodeQL Scanning"
# https://github.com/github/codeql-action
on:
schedule:
- cron: '30 23 * * *' # run at 11:30 PM UTC
#schedule:
# - cron: '30 23 * * *' # run at 11:30 PM UTC
# Allow manual runs
workflow_dispatch:
+5 -1
View File
@@ -17,4 +17,8 @@ jobs:
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- run: make -C test ${{ matrix.target }}
- run: make -C test ${{ matrix.target }} ARGS="-max_total_time=14400"
# 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
+99 -169
View File
@@ -1,4 +1,4 @@
name: Full build and test
name: Full build
on:
schedule:
- cron: '0 22 * * *' # run at 10 PM UTC
@@ -29,15 +29,28 @@ jobs:
select: "-DMG_ENABLE_POLL=0 -DMG_ENABLE_EPOLL=0"
- ssl: WOLFSSL
select: "-DMG_ENABLE_POLL=1 -DMG_ENABLE_EPOLL=0"
include:
- ssl: BUILTIN
cc: gcc
target: test
select: "-DMG_ENABLE_POLL=0 -DMG_ENABLE_EPOLL=1 -DMG_ENABLE_CHACHA20=0"
name: linux ${{ matrix.target }} CC=${{ matrix.cc }} SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }}
env:
CC: ${{ matrix.cc }}
SSL: ${{ matrix.ssl }}
TFLAGS: ${{ matrix.select }}
TFLAGS: ${{ matrix.select }} -DMQTT_LOCALHOST -DNO_ABORT
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- run: sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev && make -C test ${{ matrix.target }}
- uses: webfactory/ssh-agent@v0.9.1
with:
ssh-private-key: ${{ secrets.HEALTH_TESTS_SSH_KEY }}
- run: sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev && test/setup_mqtt_server.sh && make -C test ${{ matrix.target }} > log
- if: success() || failure()
run: |
cat log
test/health.awk < log > json
scp -o "StrictHostKeyChecking=no" json "root@176.9.217.245:/data/downloads/health/linux_${{ matrix.target }}_${{ matrix.cc }}_${{ matrix.ssl }}_${{ matrix.select }}_$(date +"%Y%m%d").json"
mip:
runs-on: ubuntu-latest
strategy:
@@ -46,14 +59,40 @@ jobs:
cc: [gcc, clang, g++, clang++]
target: [mip_test, mip_tap_test]
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 }}
env:
CC: ${{ matrix.cc }}
SSL: ${{ matrix.ssl }}
TFLAGS: -DMQTT_LOCALHOST -DNO_ABORT
steps:
- uses: actions/checkout@v4
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
- uses: webfactory/ssh-agent@v0.9.1
with:
ssh-private-key: ${{ secrets.HEALTH_TESTS_SSH_KEY }}
- run: if [ "${{ matrix.target }}" == "mip_tap_test" ]; then ./test/setup_ga_network.sh ; export IPV6=0; else export IPV6=1 ; fi && sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev && make -C test ${{ matrix.target }} > log
- if: success() || failure()
run: |
cat log
test/health.awk < log > json
scp -o "StrictHostKeyChecking=no" json "root@176.9.217.245:/data/downloads/health/${{ matrix.target }}_${{ matrix.cc }}_${{ matrix.ssl }}_$(date +"%Y%m%d").json"
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 }} IPV6=1
s390:
runs-on: ubuntu-latest
strategy:
@@ -61,10 +100,12 @@ jobs:
matrix:
ssl: ["", BUILTIN]
name: S390 SSL=${{ matrix.ssl }}
env:
TFLAGS: -DMQTT_LOCALHOST
steps:
- uses: actions/checkout@v4
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:
runs-on: ubuntu-latest
strategy:
@@ -72,10 +113,12 @@ jobs:
matrix:
ssl: ["", BUILTIN]
name: ArmHF SSL=${{ matrix.ssl }}
env:
TFLAGS: -DMQTT_LOCALHOST
steps:
- uses: actions/checkout@v4
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:
runs-on: ubuntu-latest
strategy:
@@ -87,7 +130,7 @@ jobs:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- 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:
runs-on: ubuntu-latest
strategy:
@@ -95,11 +138,13 @@ jobs:
matrix:
ssl: ["", BUILTIN, MBEDTLS, OPENSSL, WOLFSSL]
name: Valgrind SSL=${{ matrix.ssl }}
env:
TFLAGS: -DMQTT_LOCALHOST
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- 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:
runs-on: macos-latest
strategy:
@@ -110,6 +155,8 @@ jobs:
exclude:
- ssl: MBEDTLS
select: -DMG_ENABLE_POLL=0
- ssl: MBEDTLS # see issue#2694
select: -DMG_ENABLE_POLL=1
- ssl: OPENSSL
select: -DMG_ENABLE_POLL=0
- ssl: WOLFSSL
@@ -117,13 +164,23 @@ jobs:
name: macos SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }}
env:
SSL: ${{ matrix.ssl }}
TFLAGS: ${{ matrix.select }} -Wno-sign-conversion # Workaround for MbedTLS 3.5.0
TFLAGS: ${{ matrix.select }} -DMQTT_LOCALHOST ${{ matrix.env.tflags }} -DNO_ABORT -Wno-sign-conversion -Wno-undef # Workarounds for MbedTLS
HOMEBREW_NO_AUTO_UPDATE: 1
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- run: brew install mbedtls wolfssl # jq openssl already pre-installed
- run: make -C test test ASAN_OPTIONS= MBEDTLS=$(echo $(brew --cellar)/mbedtls*/*) OPENSSL=$(echo $(brew --cellar)/openssl*/*) WOLFSSL=$(echo $(brew --cellar)/wolfssl*/*)
- uses: webfactory/ssh-agent@v0.9.1
with:
ssh-private-key: ${{ secrets.HEALTH_TESTS_SSH_KEY }}
- run: brew install mbedtls wolfssl mosquitto gawk # 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*/*) > log
- if: success() || failure()
run: |
cat log
test/health.awk < log > json
scp -o "StrictHostKeyChecking=no" json "root@176.9.217.245:/data/downloads/health/macos_test_cc_${{ matrix.ssl }}_${{ matrix.select }}_$(date +"%Y%m%d").json"
windows:
runs-on: ubuntu-latest
strategy:
@@ -138,12 +195,21 @@ jobs:
select: -DMG_ENABLE_POLL=1
name: windows ${{ matrix.target }} SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }}
env:
SSL: SSL=${{ matrix.ssl }}
TFLAGS: ${{ matrix.select }}
SSL: ${{ matrix.ssl }}
TFLAGS: ${{ matrix.select }} -DMQTT_LOCALHOST -DNO_ABORT
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- run: make -C test ${{ matrix.target }}
- uses: webfactory/ssh-agent@v0.9.1
with:
ssh-private-key: ${{ secrets.HEALTH_TESTS_SSH_KEY }}
- run: ./test/setup_mqtt_server.sh && make -C test ${{ matrix.target }} > log
- if: success() || failure()
run: |
cat log
test/health.awk < log > json
scp -o "StrictHostKeyChecking=no" json "root@176.9.217.245:/data/downloads/health/windows_${{ matrix.target }}_${{ matrix.cc }}_${{ matrix.ssl }}_${{ matrix.select }}_$(date +"%Y%m%d").json"
arm:
runs-on: ubuntu-latest
strategy:
@@ -174,9 +240,18 @@ jobs:
name: tutorials ${{ matrix.ssl }}
steps:
- uses: actions/checkout@v4
- uses: webfactory/ssh-agent@v0.9.1
with:
ssh-private-key: ${{ secrets.HEALTH_TESTS_SSH_KEY }}
- run: sudo apt -y install libpcap-dev
- run: make -C test tutorials CFLAGS_EXTRA="${{ matrix.ssl }}"
- run: make -C test tutorials CFLAGS_EXTRA="${{ matrix.ssl }}" > log
- if: success() || failure()
run: |
cat log
test/health.awk < log > json
scp -o "StrictHostKeyChecking=no" json "root@176.9.217.245:/data/downloads/health/tutorials_${{ matrix.ssl }}_$(date +"%Y%m%d").json"
- run: make -C test clean_tutorials
tutorials_win:
runs-on: windows-latest
strategy:
@@ -254,6 +329,7 @@ jobs:
- path: pico-sdk/pico-2-w-picosdk-baremetal-builtin
- path: pico-sdk/w5500-evb-pico-picosdk-baremetal-builtin
- path: pico-sdk/w5500-evb-pico2-picosdk-baremetal-builtin
- path: pico-sdk/w55rp20-evb-pico-picosdk-baremetal-builtin
- path: stm32/nucleo-f429zi-make-baremetal-builtin
- path: stm32/nucleo-f429zi-make-freertos-builtin
- path: stm32/nucleo-f746zg-make-baremetal-builtin
@@ -303,7 +379,6 @@ jobs:
matrix:
example:
- path: mqtt/mqtt-client/microchip/same54-xpro
- path: nxp/nxp-mimxrt1020-azurertos
- path: nxp/nxp-frdmk66f-freertos
- path: nxp/nxp-lpcxpresso54s018m-freertos
- path: nxp/nxp-mimxrt1020-freertos
@@ -357,7 +432,7 @@ jobs:
matrix:
ssl: ["", -DMG_TLS=MG_TLS_BUILTIN]
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/rt1060-evk-make-freertos-builtin
- path: nxp/rt1170-evk-make-freertos-builtin
@@ -425,155 +500,10 @@ jobs:
- run: sudo pip install yq
- 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:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/stm32/nucleo-f746zg-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/stm32/nucleo-f746zg-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/stm32/nucleo-f746zg-make-freertos-tcp test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- name: Cube
run: echo # nothing specific to install or do
# - run: make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-f746zg-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5
# - run: make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-f746zg-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5
- run: make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-f746zg-cube-freertos-lwip VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5
test_f4:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/stm32/nucleo-f429zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/stm32/nucleo-f429zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- name: Cube
run: echo # nothing specific to install or do
# - run: make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-f429zi-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
# - run: make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-f429zi-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
- run: make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-f429zi-cube-freertos-lwip VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
test_h743:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/stm32/nucleo-h743zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/stm32/nucleo-h743zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
# - name: Cube
# run: echo # nothing specific to install or do
# - run: make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-h743zi-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=6
# - run: make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-h743zi-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=6
test_h723:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/stm32/nucleo-h723zg-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/stm32/nucleo-h723zg-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_h5:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/stm32/nucleo-h563zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/stm32/nucleo-h563zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_rt1020:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/nxp/rt1020-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/nxp/rt1020-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_rt1060:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/nxp/rt1060-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/nxp/rt1060-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_rt1170:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/nxp/rt1170-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/nxp/rt1170-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_ra6m4:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/renesas/ek-ra6m4-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
# - run: make -C tutorials/renesas/ek-ra6m4-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_tm4c:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/ti/ek-tm4c1294xl-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/ti/ek-tm4c1294xl-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_same54:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/http/device-dashboard/microchip/same54-xpro test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/mqtt/mqtt-client/microchip/same54-xpro test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_pico_w5500:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- name: SDK
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/pico-sdk/w5500-evb-pico-picosdk-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
# xpresso_examples:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v4
# with: { fetch-depth: 2 }
# - run: sudo pip install yq
# - run: cd test/xpresso && make
+143
View File
@@ -0,0 +1,143 @@
name: Full test
on:
schedule:
- cron: '0 23 * * *' # run at 11 PM UTC
# Allow manual runs
workflow_dispatch:
env:
IPV6: 0
jobs:
test_f7:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/stm32/nucleo-f746zg-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/stm32/nucleo-f746zg-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/stm32/nucleo-f746zg-make-freertos-tcp test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- name: Cube
run: sudo pip install yq
# - run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-f746zg-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5
# - run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-f746zg-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5
- run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-f746zg-cube-freertos-lwip VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5
test_f4:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/stm32/nucleo-f429zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/stm32/nucleo-f429zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- name: Cube
run: sudo pip install yq
# - run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-f429zi-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
# - run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-f429zi-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
- run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-f429zi-cube-freertos-lwip VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
test_h743:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/stm32/nucleo-h743zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/stm32/nucleo-h743zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
# - name: Cube
# run: echo # nothing specific to install or do
# - run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-h743zi-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=6
# - run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-h743zi-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=6
test_h723:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/stm32/nucleo-h723zg-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/stm32/nucleo-h723zg-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_h5:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/stm32/nucleo-h563zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/stm32/nucleo-h563zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_rt1020:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/nxp/rt1020-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/nxp/rt1020-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_rt1060:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/nxp/rt1060-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/nxp/rt1060-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_rt1170:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/nxp/rt1170-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/nxp/rt1170-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_ra6m4:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 3 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/renesas/ek-ra6m4-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
# - run: make -C tutorials/renesas/ek-ra6m4-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_tm4c:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/ti/ek-tm4c1294xl-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/ti/ek-tm4c1294xl-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_same54:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- name: baremetal
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/http/device-dashboard/microchip/same54-xpro test VCON_API_KEY=${{secrets.VCON_API_KEY}}
- run: make -C tutorials/mqtt/mqtt-client/microchip/same54-xpro test VCON_API_KEY=${{secrets.VCON_API_KEY}}
test_pico_w5500:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- name: SDK
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
- run: make -C tutorials/pico-sdk/w5500-evb-pico-picosdk-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
+32
View File
@@ -0,0 +1,32 @@
name: On demand ad hoc test
on:
workflow_dispatch:
env:
IPV6: 0
jobs:
macos:
runs-on: macos-latest
strategy:
fail-fast: false
matrix:
ssl: [MBEDTLS, WOLFSSL]
select: [-DMG_ENABLE_POLL=1]
name: macos SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }}
env:
SSL: ${{ matrix.ssl }}
TFLAGS: ${{ matrix.select }} -DMQTT_LOCALHOST -DNO_ABORT -Wno-sign-conversion -Wno-undef # Workarounds for MbedTLS
HOMEBREW_NO_AUTO_UPDATE: 1
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- uses: webfactory/ssh-agent@v0.9.1
with:
ssh-private-key: ${{ secrets.HEALTH_TESTS_SSH_KEY }}
- run: brew install mbedtls wolfssl mosquitto gawk # 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*/*) > log
- if: success() || failure()
run: |
cat log
test/health.awk < log > json
scp -o "StrictHostKeyChecking=no" json "root@176.9.217.245:/data/downloads/health/macos_test_cc_${{ matrix.ssl }}_${{ matrix.select }}_$(date +"%Y%m%d").json"
+369 -340
View File
@@ -5,6 +5,8 @@ on:
- "**Makefile"
- "**.c"
- "**.h"
# Allow manual runs
workflow_dispatch:
env:
IPV6: 0
jobs:
@@ -20,28 +22,33 @@ jobs:
env:
CC: ${{ matrix.cc }}
SSL: ${{ matrix.ssl }}
TFLAGS: -DMQTT_LOCALHOST
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- run: if ./test/match_changed_files.sh '^test|^src/.*.[ch]' ; then echo GO=1 >> $GITHUB_ENV ; fi
- 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:
runs-on: ubuntu-latest
env:
TFLAGS: -DMQTT_LOCALHOST
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- run: if ./test/match_changed_files.sh '^test|^src/.*.[ch]' ; then echo GO=1 >> $GITHUB_ENV ; fi
- 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:
runs-on: ubuntu-latest
env:
TFLAGS: -DMQTT_LOCALHOST
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- run: if ./test/match_changed_files.sh '^test|^src/.*.[ch]' ; then echo GO=1 >> $GITHUB_ENV ; fi
- 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:
runs-on: ubuntu-latest
steps:
@@ -59,14 +66,17 @@ jobs:
name: macos SSL=${{ matrix.ssl }}
env:
SSL: ${{ matrix.ssl }}
#TFLAGS: -DNO_SNTP_CHECK
TFLAGS: -DMQTT_LOCALHOST # -DNO_SNTP_CHECK
HOMEBREW_NO_AUTO_UPDATE: 1
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- run: if ./test/match_changed_files.sh '^test|^src/.*.[ch]' ; then echo GO=1 >> $GITHUB_ENV ; fi
- 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:
runs-on: ubuntu-latest
strategy:
@@ -74,12 +84,14 @@ jobs:
matrix:
target: [vc98, vc22, mingw++]
name: windows ${{ matrix.target }}
env:
TFLAGS: -DMQTT_LOCALHOST
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- run: if ./test/match_changed_files.sh '^test|^src/.*.[ch]' ; then echo GO=1 >> $GITHUB_ENV ; fi
- if: ${{ env.GO == 1 }}
run: make -C test ${{ matrix.target }}
run: ./test/setup_mqtt_server.sh && make -C test ${{ matrix.target }}
arm:
runs-on: ubuntu-latest
steps:
@@ -158,6 +170,7 @@ jobs:
- path: pico-sdk/pico-2-w-picosdk-baremetal-builtin
- path: pico-sdk/w5500-evb-pico-picosdk-baremetal-builtin
- path: pico-sdk/w5500-evb-pico2-picosdk-baremetal-builtin
- path: pico-sdk/w55rp20-evb-pico-picosdk-baremetal-builtin
- path: stm32/nucleo-f429zi-make-baremetal-builtin
- path: stm32/nucleo-f429zi-make-freertos-builtin
- path: stm32/nucleo-f746zg-make-baremetal-builtin
@@ -335,360 +348,376 @@ jobs:
- if: ${{ env.GO == 1 }}
run: cd test/cube && make
test_f7:
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-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: |
# 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 }}
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
# xpresso_examples:
# runs-on: ubuntu-latest
# env:
# GO: 0
# steps:
# - uses: actions/checkout@v4
# with: { fetch-depth: 2 }
# - run: |
# if ./test/match_changed_files.sh '^src|tutorials/stm32/nucleo-*-cube-*'; then
# echo GO=1 >> $GITHUB_ENV
# sudo pip install yq
# fi
# - if: ${{ env.GO == 1 }}
# run: cd test/xpresso && make
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 }}
# test_f7:
# 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 '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
# 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-f429zi-cube-freertos-builtin'; then
# make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-f429zi-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
# 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
- 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
# run: |
# 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
# # nothing specific to install or do
# 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 }}
# run: |
# if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-h743zi-cube-baremetal-builtin'; then
# make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-h743zi-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=6
# 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-h743zi-cube-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
# 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
test_h723:
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-h72.*-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-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
# - 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
## - if: ${{ env.GO == 1 }}
## run: |
## if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-f429zi-cube-freertos-builtin'; then
## make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-f429zi-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
## 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}}
# 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_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}}
#
# 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
## run: |
## echo GO=0 >> $GITHUB_ENV
## if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-h74.*-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-h743zi-cube-baremetal-builtin'; then
## make -C test/cube test PROJECTS=../../tutorials/stm32/nucleo-h743zi-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=6
## fi
## - if: ${{ env.GO == 1 }}
## run: |
## if ./test/match_changed_files.sh 'tutorials/stm32/nucleo-h743zi-cube-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
## fi
#
# test_h723:
# 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-h72.*-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-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 }}
## 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}}
+27
View File
@@ -0,0 +1,27 @@
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", "--mr v4.3.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:v0.28.8 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 REPO=zephyrprojectrtos/ci:v0.28.8
- run: make -C tutorials/zephyr/http-client build REPO=zephyrprojectrtos/ci:v0.28.8
- run: make -C tutorials/zephyr/http-server build REPO=zephyrprojectrtos/ci:v0.28.8
- run: make -C tutorials/zephyr/mqtt-aws-client build REPO=zephyrprojectrtos/ci:v0.28.8
- run: make -C tutorials/zephyr/websocket-server build REPO=zephyrprojectrtos/ci:v0.28.8
# Latest CI image does not work with pre 4.4, they changed some SDK paths
+1 -1
View File
@@ -1,5 +1,5 @@
Copyright (c) 2004-2013 Sergey Lyubka
Copyright (c) 2013-2025 Cesanta Software Limited
Copyright (c) 2013-2026 Cesanta Software Limited
All rights reserved
This software is dual-licensed: you can redistribute it and/or modify
+48 -4
View File
@@ -1,12 +1,11 @@
# 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)
[![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)
[![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)
[![Gurubase](https://img.shields.io/badge/Gurubase-Ask%20Mongoose%20Guru-006BFF)](https://gurubase.io/g/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)
Mongoose is a network library for C/C++. It provides event-driven non-blocking
<img src="https://mongoose.ws/images/logo.svg" width="48" height="48" align="left" style="float:left;" /> 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
for connecting devices and bringing them online. On the market since 2004, used
by vast number of open source and commercial products - it even runs on the
@@ -35,6 +34,35 @@ robust, and easy. Features include:
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
Below are quick snippets that should give an idea how simple the API is and
@@ -170,6 +198,10 @@ We take security seriously:
have specific security requirements and run independent security audits,
of which we get notified and in case of any issue, act similar to (3).
## How to report security vulnerabilities
Please send an email to support@cesanta.com, with the full information.
Do NOT create a github issue.
## Articles
@@ -177,6 +209,18 @@ 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/)
- [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/)
- [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/)
- [Limiting TCP/IP RAM usage on STM32](https://mongoose.ws/articles/limiting-tcpip-ram-usage-on-stm32/)
- [STM32 Ethernet explained](https://mongoose.ws/articles/stm32-ethernet-explained/)
- [MQTT on a Microcontroller](https://mongoose.ws/articles/mqtt-on-a-microcontroller/)
- [STM32 OTA Firmware Update](https://mongoose.ws/articles/stm32-ota-firmware-update/)
- [RP2350 OTA Firmware Update](https://mongoose.ws/articles/rp2350-ota-firmware-update/)
- [STM32 Ethernet and caches](https://mongoose.ws/articles/stm32-ethernet-and-cache/)
- [NXP RW612 OTA Firmware Update](https://mongoose.ws/articles/rw612-ota-firmware-update/)
- [lwIP vs Mongoose - TCP/IP Stack Integration Benchmark](https://mongoose.ws/articles/lwip-vs-mongoose-tcpip-stack-integration/)
## Contributions
+6199 -2110
View File
File diff suppressed because it is too large. Load diff
+1032 -478
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_ESP8266 4 // ESP8266
#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_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_TIRTOS 10 // Texas Semi TI-RTOS
#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_RTTHREAD 14 // RT-Thread RTOS
#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(__unix__) || defined(__APPLE__)
@@ -30,17 +33,19 @@
#endif
#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
// http://esr.ibiblio.org/?p=5095
#define MG_BIG_ENDIAN (*(uint16_t *) "\0\xff" < 0x100)
#include "arch_armgcc.h"
#include "arch_cube.h"
#include "arch_esp32.h"
#include "arch_esp8266.h"
#include "arch_freertos.h"
#include "arch_newlib.h"
#include "arch_rtx.h"
#include "arch_threadx.h"
#include "arch_unix.h"
#include "arch_win32.h"
#include "arch_zephyr.h"
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#if MG_ARCH == MG_ARCH_NEWLIB
#if MG_ARCH == MG_ARCH_ARMGCC
#define _POSIX_TIMERS
#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
+89
View File
@@ -0,0 +1,89 @@
#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) && !defined(MG_ENABLE_DRIVER_STM32N)
#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
#elif defined(STM32N6)
#define MG_ENABLE_DRIVER_STM32N 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
#ifndef MG_ENABLE_POSIX_FS
#define MG_ENABLE_POSIX_FS 1
#endif
#ifndef MG_ENABLE_DIRLIST
#define MG_ENABLE_DIRLIST 1
#endif
#endif
+9 -4
View File
@@ -17,6 +17,7 @@
#define mode_t size_t
#include <alloca.h>
#include <time.h>
#define strdup(s) ((char *) mg_strdup(mg_str(s)).buf)
#elif defined(__CCRH__)
#else
#include <sys/stat.h>
@@ -25,10 +26,11 @@
#include <FreeRTOS.h>
#include <task.h>
#define calloc(a, b) mg_calloc(a, b)
#define free(a) vPortFree(a)
#define malloc(a) pvPortMalloc(a)
#define strdup(s) ((char *) mg_strdup(mg_str(s)).buf)
#define MG_ENABLE_CUSTOM_CALLOC 1
static inline void mg_free(void *ptr) {
vPortFree(ptr);
}
// Re-route calloc/free to the FreeRTOS's functions, don't use stdlib
static inline void *mg_calloc(size_t cnt, size_t size) {
@@ -37,10 +39,13 @@ static inline void *mg_calloc(size_t cnt, size_t size) {
return p;
}
#if !defined(MG_ENABLE_POSIX_FS) || !MG_ENABLE_POSIX_FS
#else
#define mkdir(a, b) mg_mkdir(a, b)
static inline int mg_mkdir(const char *path, mode_t mode) {
(void) path, (void) mode;
return -1;
}
#endif
#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
+17 -5
View File
@@ -18,6 +18,17 @@
#define _CRT_RAND_S
#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
#define WIN32_LEAN_AND_MEAN
#endif
@@ -45,6 +56,8 @@
#include <sys/types.h>
#include <time.h>
#include <winsock2.h> // fix missing macros and types
#if defined(_MSC_VER) && _MSC_VER < 1700
#define __func__ ""
typedef __int64 int64_t;
@@ -66,13 +79,9 @@ typedef enum { false = 0, true = 1 } bool;
#include <process.h>
#include <winerror.h>
#include <winsock2.h> // fix missing macros and types
// For mg_random()
#if defined(_MSC_VER) && _MSC_VER < 1700
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x400 // Let vc98 pick up wincrypt.h
#endif
#include <wincrypt.h>
#pragma comment(lib, "advapi32.lib")
#endif
@@ -101,7 +110,10 @@ typedef enum { false = 0, true = 1 } bool;
#endif
#endif
typedef unsigned long nfds_t;
#if defined(MG_ENABLE_POLL) && MG_ENABLE_POLL && (!defined(MG_ENABLE_LWIP) || !MG_ENABLE_LWIP)
typedef unsigned long nfds_t; // see #3388
#endif
#if defined(_MSC_VER)
#if MG_ENABLE_WINSOCK
#pragma comment(lib, "ws2_32.lib")
+6 -3
View File
@@ -3,12 +3,15 @@
#if MG_ARCH == MG_ARCH_ZEPHYR
#include <zephyr/kernel.h>
#include <zephyr/net/socket.h>
// #include <zephyr/posix/dirent.h>
#include <zephyr/posix/fcntl.h>
#include <zephyr/posix/sys/select.h>
#include <zephyr/random/random.h>
#include <zephyr/version.h>
#include <ctype.h>
#include <errno.h>
#include <zephyr/net/socket.h>
#include <zephyr/posix/fcntl.h>
#include <zephyr/posix/sys/select.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
+32
View File
@@ -4,6 +4,10 @@
#define MG_ENABLE_LOG 1
#endif
#ifndef MG_ENABLE_CUSTOM_CALLOC
#define MG_ENABLE_CUSTOM_CALLOC 0
#endif
#ifndef MG_ENABLE_CUSTOM_LOG
#define MG_ENABLE_CUSTOM_LOG 0 // Let user define their own MG_LOG
#endif
@@ -171,10 +175,34 @@
#define MG_TCPIP_GW MG_IPV4(0, 0, 0, 0) // Default is 0.0.0.0 (DHCP)
#endif
#if MG_ENABLE_IPV6
#ifndef MG_TCPIP_GLOBAL
#define MG_TCPIP_GLOBAL MG_IPV6(0, 0, 0, 0, 0, 0, 0, 0)
#endif
#ifndef MG_TCPIP_IPV6_LINKLOCAL
#define MG_TCPIP_IPV6_LINKLOCAL MG_IPV6(0, 0, 0, 0, 0, 0, 0, 0)
#endif
#ifndef MG_TCPIP_PREFIX_LEN
#define MG_TCPIP_PREFIX_LEN 0
#endif
#ifndef MG_TCPIP_GW6
#define MG_TCPIP_GW6 MG_IPV6(0, 0, 0, 0, 0, 0, 0, 0)
#endif
#endif
#ifndef MG_SET_MAC_ADDRESS
#define MG_SET_MAC_ADDRESS(mac)
#endif
#ifndef MG_TCPIP_DHCPNAME_SIZE
#define MG_TCPIP_DHCPNAME_SIZE 18 // struct mg_tcpip_if :: dhcp_name size
#endif
#ifndef MG_SET_WIFI_CONFIG
#define MG_SET_WIFI_CONFIG(data)
#endif
@@ -182,3 +210,7 @@
#ifndef MG_ENABLE_TCPIP_PRINT_DEBUG_STATS
#define MG_ENABLE_TCPIP_PRINT_DEBUG_STATS 0
#endif
#ifndef MG_ENABLE_CHACHA20
#define MG_ENABLE_CHACHA20 1 // When set to 0, GCM is used. For MG_TLS_BUILTIN
#endif
+350 -69
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) {
LIST_DELETE(struct dns_data, head, d);
free(d);
mg_free(d);
}
void mg_resolve_cancel(struct mg_connection *c) {
@@ -63,7 +63,7 @@ static size_t mg_dns_parse_name_depth(const uint8_t *s, size_t len, size_t ofs,
if (j < tolen) to[j] = '\0'; // Zero-terminate this chunk
// MG_INFO(("--> [%s]", to));
}
if (tolen > 0) to[tolen - 1] = '\0'; // Make sure make sure it is nul-term
if (tolen > 0) to[tolen - 1] = '\0'; // Make sure it is nul-term
return i;
}
@@ -134,14 +134,15 @@ bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *dm) {
mg_dns_parse_name(buf, len, ofs, dm->name, sizeof(dm->name));
ofs += n;
if (rr.alen == 4 && rr.atype == 1 && rr.aclass == 1) {
if (rr.alen == 4 && rr.atype == MG_DNS_RTYPE_A && rr.aclass == 1) {
dm->addr.is_ip6 = false;
memcpy(&dm->addr.ip, &buf[ofs - 4], 4);
memcpy(&dm->addr.addr.ip, &buf[ofs - 4], 4);
dm->resolved = true;
break; // Return success
} else if (rr.alen == 16 && rr.atype == 28 && rr.aclass == 1) {
} else if (rr.alen == 16 && rr.atype == MG_DNS_RTYPE_AAAA &&
rr.aclass == 1) {
dm->addr.is_ip6 = true;
memcpy(&dm->addr.ip, &buf[ofs - 16], 16);
memcpy(&dm->addr.addr.ip, &buf[ofs - 16], 16);
dm->resolved = true;
break; // Return success
}
@@ -232,26 +233,35 @@ static bool mg_dns_send(struct mg_connection *c, const struct mg_str *name,
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,
struct mg_dns *dnsc, bool ipv6) {
struct dns_data *d = NULL;
if (dnsc->url == NULL) {
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) {
if (!mg_dnsc_init(c->mgr, dnsc)) {
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");
} else {
struct dns_data *reqs = (struct dns_data *) c->mgr->active_dns_requests;
d->txnid = reqs ? (uint16_t) (reqs->txnid + 1) : 1;
d->next = (struct dns_data *) c->mgr->active_dns_requests;
uint16_t id;
mg_random(&id, sizeof(uint16_t));
// TODO(): traverse reqs and check id != reqs->txnid; repeat otherwise
if (reqs != NULL) id = (uint16_t) (reqs->txnid + 1); // no collision
d->txnid = id;
d->next = reqs;
c->mgr->active_dns_requests = d;
d->expire = mg_millis() + (uint64_t) ms;
d->c = c;
@@ -277,6 +287,7 @@ void mg_resolve(struct mg_connection *c, const char *url) {
}
}
// Response header length is 10 bytes
static const uint8_t mdns_answer[] = {
0, 1, // 2 bytes - record type, A
0, 1, // 2 bytes - address class, INET
@@ -284,64 +295,334 @@ static const uint8_t mdns_answer[] = {
0, 4 // 2 bytes - address length
};
// A name length is name->len + '.local' + 2 = name->len + 8
static uint8_t *build_name(struct mg_str *name, uint8_t *p) {
*p++ = (uint8_t) name->len; // label 1
memcpy(p, name->buf, name->len), p += name->len;
*p++ = 5; // label 2
memcpy(p, "local", 5), p += 5;
*p++ = 0; // no more labels
return p;
}
void mg_getlocaddr(struct mg_connection *, struct mg_addr *, struct mg_addr *);
// An A record length is 10 + 4 = 14 bytes
static uint8_t *build_a_record(struct mg_connection *c, uint8_t *p,
struct mg_addr *addr) {
memcpy(p, mdns_answer, sizeof(mdns_answer)), p += sizeof(mdns_answer);
if (addr != NULL && !addr->is_ip6) {
memcpy(p, &addr->addr.ip4, 4), p += 4;
} else {
#if MG_ENABLE_TCPIP
memcpy(p, &c->mgr->ifp->ip, 4), p += 4;
#else
struct mg_addr loc, to;
memset(&loc, 0, sizeof(loc));
to.is_ip6 = false;
to.port = mg_htons(5353);
to.addr.ip4 = MG_IPV4(224, 0, 0, 51);
mg_getlocaddr(c, &to, &loc);
memcpy(p, &loc.addr.ip4, 4), p += 4;
#endif
}
return p;
}
// A srv name length is r->srvcproto.len + '.local' + 2 = r->srvcproto.len + 8
static uint8_t *build_srv_name(uint8_t *p, struct mg_dnssd_record *r) {
*p++ = (uint8_t) r->srvcproto.len - 5; // label 1, up to '._tcp'
memcpy(p, r->srvcproto.buf, r->srvcproto.len), p += r->srvcproto.len;
p[-5] = 4; // label 2, '_tcp', overwrite '.'
*p++ = 5; // label 3
memcpy(p, "local", 5), p += 5;
*p++ = 0; // no more labels
return p;
}
#if 0
// TODO(): for listing
static uint8_t *build_mysrv_name(struct mg_str *name, uint8_t *p,
struct mg_dnssd_record *r) {
*p++ = name->len; // label 1
memcpy(p, name->buf, name->len), p += name->len;
return build_srv_name(p, r);
}
#endif
// A PTR record length is 10 + name->len + 3 = name->len + 13
static uint8_t *build_ptr_record(struct mg_str *name, uint8_t *p, uint16_t o) {
uint16_t offset = mg_htons(o);
memcpy(p, mdns_answer, sizeof(mdns_answer));
p[1] = MG_DNS_RTYPE_PTR; // overwrite record type
p += sizeof(mdns_answer);
p[-1] = (uint8_t) name->len +
3; // overwrite response length, label length + label + offset
*p++ = (uint8_t) name->len; // response: label 1
memcpy(p, name->buf, name->len), p += name->len; // copy label
memcpy(p, &offset, 2);
*p |= 0xC0, p += 2;
return p;
}
// An SRV record length is 10 + name->len + 9 = name->len + 19
static uint8_t *build_srv_record(struct mg_str *name, uint8_t *p,
struct mg_dnssd_record *r, uint16_t o) {
uint16_t port = mg_htons(r->port);
uint16_t offset = mg_htons(o);
memcpy(p, mdns_answer, sizeof(mdns_answer));
p[1] = MG_DNS_RTYPE_SRV; // overwrite record type
p += sizeof(mdns_answer);
p[-1] = (uint8_t) name->len + 9; // overwrite response length (4+2+1+2)
*p++ = 0; // priority
*p++ = 0;
*p++ = 0; // weight
*p++ = 0;
memcpy(p, &port, 2), p += 2; // port
*p++ = (uint8_t) name->len; // label 1
memcpy(p, name->buf, name->len), p += name->len;
memcpy(p, &offset, 2);
*p |= 0xC0, p += 2;
return p;
}
// A TXT record length is r->txt.len (txt contents) + 10
static uint8_t *build_txt_record(uint8_t *p, struct mg_dnssd_record *r) {
uint16_t len = mg_htons((uint16_t) r->txt.len);
memcpy(p, mdns_answer, sizeof(mdns_answer));
p[1] = MG_DNS_RTYPE_TXT; // overwrite record type
p += sizeof(mdns_answer);
memcpy(p - 2, &len, 2); // overwrite response length
memcpy(p, r->txt.buf, r->txt.len), p += r->txt.len; // copy record verbatim
return p;
}
// Each additional record has a 2-byte field pointing to the name label
// RFC-6762 16: case-insensitivity --> RFC-1034, 1035
static void handle_mdns_query(struct mg_connection *c) {
struct mg_dns_header *qh = (struct mg_dns_header *) c->recv.buf;
struct mg_dns_rr rr;
size_t n;
// Parse first question, offset 12 is header size
n = mg_dns_parse_rr(c->recv.buf, c->recv.len, 12, true, &rr);
MG_VERBOSE(("mDNS request parsed, result=%d", (int) n));
if (n > 0) {
// RFC-6762 Appendix C, RFC2181 11: m(n + 1-63), max 255 + 0x0
uint8_t buf[sizeof(struct mg_dns_header) + 256 + sizeof(mdns_answer) + 4];
struct mg_dns_header *h = (struct mg_dns_header *) buf;
uint8_t *p = &buf[sizeof(*h)];
char name[256];
uint8_t name_len;
// uint16_t q = mg_ntohs(qh->num_questions);
struct mg_str defname = mg_str((const char *) c->fn_data);
struct mg_str *respname;
struct mg_mdns_req req;
memset(&req, 0, sizeof(req));
req.is_unicast = (rr.aclass & MG_BIT(15)) != 0; // QU
rr.aclass &= (uint16_t) ~MG_BIT(15); // remove "QU" (unicast response)
qh->num_questions = mg_htons(1); // parser sanity
mg_dns_parse_name(c->recv.buf, c->recv.len, 12, name, sizeof(name));
name_len = (uint8_t) strlen(name); // verify it ends in .local
if (name_len <= 6 || strcmp(".local", &name[name_len - 6]) != 0 ||
(rr.aclass != 1 && rr.aclass != 0xff))
return;
name[name_len -= 6] = '\0'; // remove .local
MG_VERBOSE(("RR %u %u %s", (unsigned int) rr.atype,
(unsigned int) rr.aclass, name));
if (rr.atype == MG_DNS_RTYPE_A) {
// TODO(): ensure c->fn_data ends in \0
// if we have a name to match, go; otherwise users will match and fill
// req.r.name and set req.is_resp
if (c->fn_data != NULL && mg_casecmp((char *) c->fn_data, name) != 0)
return;
req.is_resp = (c->fn_data != NULL);
req.reqname = mg_str_n(name, name_len);
} else // users have to match the request to something in their db, then
// fill req.r and set req.is_resp
if (rr.atype == MG_DNS_RTYPE_PTR) {
if (strcmp("_services._dns-sd._udp", name) == 0) req.is_listing = true;
MG_DEBUG(
("PTR request for %s", req.is_listing ? "services listing" : name));
req.reqname = mg_str_n(name, name_len);
} else if (rr.atype == MG_DNS_RTYPE_SRV || rr.atype == MG_DNS_RTYPE_TXT) {
MG_DEBUG(("%s request for %s",
rr.atype == MG_DNS_RTYPE_SRV ? "SRV" : "TXT", name));
// if possible, check it starts with our name, users will check it ends
// in a service name they handle
if (c->fn_data != NULL) {
if (mg_strcasecmp(defname, mg_str_n(name, defname.len)) != 0 ||
name[defname.len] != '.')
return;
req.reqname =
mg_str_n(name + defname.len + 1, name_len - defname.len - 1);
MG_DEBUG(
("That's us, handing %.*s", req.reqname.len, req.reqname.buf));
} else {
req.reqname = mg_str_n(name, name_len);
}
} else { // unhandled record
return;
}
req.rr = &rr;
mg_call(c, MG_EV_MDNS_REQ, &req);
if (!req.is_resp) return;
respname = req.respname.buf != NULL ? &req.respname : &defname;
memset(h, 0, sizeof(*h)); // clear header
h->txnid = req.is_unicast ? qh->txnid : 0; // RFC-6762 18.1
h->num_answers = mg_htons(1); // RFC-6762 6: 0 questions, 1 Answer
h->flags = mg_htons(0x8400); // Authoritative response
if (req.is_listing) {
// TODO(): RFC-6762 6: each responder SHOULD delay its response by a
// random amount of time selected with uniform random distribution in the
// range 20-120 ms.
// TODO():
return;
} else if (rr.atype == MG_DNS_RTYPE_PTR) { // serve PTR + SRV + TXT + A
// TODO(): RFC-6762 6: each responder SHOULD delay its response by a
// random amount of time selected with uniform random distribution in the
// range 20-120 ms. Response to PTR is local_name._myservice._tcp.local
uint8_t *o = p, *aux;
uint16_t offset;
if (respname->buf == NULL || respname->len == 0) return;
if ((sizeof(*h) + req.r->srvcproto.len + 8 + respname->len + 13 + 2 +
respname->len + 19 + 2 + req.r->txt.len + 10 + 2 + 14) >
sizeof(buf)) // srv name + PTR + 2 + SRV + 2 + TXT + 2 + A
return;
h->num_other_prs = mg_htons(3); // 3 additional records
p = build_srv_name(p, req.r);
aux = build_ptr_record(respname, p, (uint16_t) (o - buf));
o = p + sizeof(mdns_answer); // point to PTR response (full srvc name)
offset = mg_htons((uint16_t) (o - buf));
o = p - 7; // point to '.local' label (\x05local\x00)
p = aux;
memcpy(p, &offset, 2); // point to full srvc name, in record
*p |= 0xC0, p += 2;
aux = p;
p = build_srv_record(respname, p, req.r, (uint16_t) (o - buf));
o = aux + sizeof(mdns_answer) + 6; // point to target in SRV
memcpy(p, &offset, 2); // point to full srvc name, in record
*p |= 0xC0, p += 2;
p = build_txt_record(p, req.r);
offset = mg_htons((uint16_t) (o - buf));
memcpy(p, &offset, 2); // point to target name, in record
*p |= 0xC0, p += 2;
p = build_a_record(c, p, req.addr);
} else if (rr.atype == MG_DNS_RTYPE_TXT) {
if ((sizeof(*h) + req.r->srvcproto.len + 8 + req.r->txt.len + 10) >
sizeof(buf)) // srv name + TXT
return;
p = build_srv_name(p, req.r);
p = build_txt_record(p, req.r);
} else if (rr.atype == MG_DNS_RTYPE_SRV) { // serve SRV + A
uint8_t *o, *aux;
uint16_t offset;
if (respname->buf == NULL || respname->len == 0) return;
if ((sizeof(*h) + req.r->srvcproto.len + 8 + respname->len + 19 + 2 +
14) > sizeof(buf)) // srv name + SRV + 2 + A
return;
h->num_other_prs = mg_htons(1); // 1 additional record
p = build_srv_name(p, req.r);
o = p - 7; // point to '.local' label (\x05local\x00)
aux = p;
p = build_srv_record(respname, p, req.r, (uint16_t) (o - buf));
o = aux + sizeof(mdns_answer) + 6; // point to target in SRV
offset = mg_htons((uint16_t) (o - buf));
memcpy(p, &offset, 2); // point to target name, in record
*p |= 0xC0, p += 2;
p = build_a_record(c, p, req.addr);
} else { // A requested
// RFC-6762 6: 0 Auth, 0 Additional RRs
if (respname->buf == NULL || respname->len == 0) return;
if ((sizeof(*h) + respname->len + 8 + 14) > sizeof(buf)) // name + A
return;
p = build_name(respname, p);
p = build_a_record(c, p, req.addr);
}
if (!req.is_unicast) mg_multicast_restore(c, (uint8_t *) &c->loc);
mg_send(c, buf, (size_t) (p - buf)); // And send it!
MG_DEBUG(("%M > %M", mg_print_ip_port, &c->loc, mg_print_ip_port, &c->rem));
MG_DEBUG(("mDNS %s response sent", req.is_unicast ? "unicast" : "mcast"));
}
}
static void handle_mdns_response(struct mg_connection *c) {
struct mg_dns_header *rh = (struct mg_dns_header *) c->recv.buf;
struct mg_dns_rr rr;
size_t n;
// Parse first response, offset 12 is header size
n = mg_dns_parse_rr(c->recv.buf, c->recv.len, 12, false, &rr);
MG_VERBOSE(("mDNS response parsed, result=%d", (int) n));
if (n > 0) {
// RFC-6762 Appendix C, RFC2181 11: m(n + 1-63), max 255 + 0x0
char name[256];
uint8_t name_len;
struct mg_mdns_resp resp;
memset(&resp, 0, sizeof(resp));
if (rh->num_answers > mg_htons(1)) MG_DEBUG(("ignoring > 1 answers"));
mg_dns_parse_name(c->recv.buf, c->recv.len, 12, name, sizeof(name));
name_len = (uint8_t) strlen(name); // verify it ends in .local
MG_VERBOSE(("RR %u %u %s", (unsigned int) rr.atype,
(unsigned int) rr.aclass, name));
if (rr.alen == 4 && rr.atype == MG_DNS_RTYPE_A &&
(rr.aclass & 0x7FFF) == 1) {
resp.addr.is_ip6 = false;
memcpy(resp.addr.addr.ip, (char *) (rh + 1) + n - 4, 4);
MG_DEBUG(("A response from %.*s = %M", name_len, name, mg_print_ip,
&resp.addr));
// } else if (rr.alen == 16 && rr.atype == MG_DNS_RTYPE_AAAA &&
// (rr.aclass & 0x7FFF) == 1) {
// resp.addr.is_ip6 = true;
// memcpy(resp.addr.addr.ip, (char *)(rh + 1) + n - 16], 16);
// MG_DEBUG(("AAAA response from %.*s = %M", name_len, name,
// mg_print_ip, &resp.addr));
} else {
return;
}
resp.name = mg_str_n(name, name_len);
resp.rr = &rr;
mg_call(c, MG_EV_MDNS_RESP, &resp);
}
}
static void handle_mdns_record(struct mg_connection *c) {
struct mg_dns_header *h = (struct mg_dns_header *) c->recv.buf;
if (c->recv.len <= 12) return;
if ((h->flags & mg_htons(0xF800)) == 0) {
// flags -> !resp, opcode=0 => query; ignore other opcodes
handle_mdns_query(c);
} else if ((h->flags & mg_htons(0xF800)) == mg_htons(0x8000)) {
// flags -> resp, opcode=0 => response; ignore other opcodes
handle_mdns_response(c);
}
}
static void mdns_cb(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_READ) {
struct mg_dns_header *qh = (struct mg_dns_header *) c->recv.buf;
if (c->recv.len > 12 && (qh->flags & mg_htons(0xF800)) == 0) {
// flags -> !resp, opcode=0 => query; ignore other opcodes and responses
struct mg_dns_rr rr; // Parse first question, offset 12 is header size
size_t n = mg_dns_parse_rr(c->recv.buf, c->recv.len, 12, true, &rr);
MG_VERBOSE(("mDNS request parsed, result=%d", (int) n));
if (n > 0) {
// RFC-6762 Appendix C, RFC2181 11: m(n + 1-63), max 255 + 0x0
// buf and h declared here to ease future expansion to DNS-SD
uint8_t buf[sizeof(struct mg_dns_header) + 256 + sizeof(mdns_answer) + 4];
struct mg_dns_header *h = (struct mg_dns_header *) buf;
char local_name[63 + 7]; // name label + '.' + local label + '\0'
uint8_t name_len = (uint8_t) strlen((char *)c->fn_data);
struct mg_dns_message dm;
bool unicast = (rr.aclass & MG_BIT(15)) != 0; // QU
// uint16_t q = mg_ntohs(qh->num_questions);
rr.aclass &= (uint16_t) ~MG_BIT(15); // remove "QU" (unicast response)
qh->num_questions = mg_htons(1); // parser sanity
mg_dns_parse(c->recv.buf, c->recv.len, &dm);
if (name_len > (sizeof(local_name) - 7)) // leave room for .local\0
name_len = sizeof(local_name) - 7;
memcpy(local_name, c->fn_data, name_len);
strcpy(local_name + name_len, ".local"); // ensure proper name.local\0
if (strcmp(local_name, dm.name) == 0) {
uint8_t *p = &buf[sizeof(*h)];
memset(h, 0, sizeof(*h)); // clear header
h->txnid = unicast ? qh->txnid : 0; // RFC-6762 18.1
// RFC-6762 6: 0 questions, 1 Answer, 0 Auth, 0 Additional RRs
h->num_answers = mg_htons(1); // only one answer
h->flags = mg_htons(0x8400); // Authoritative response
*p++ = name_len; // label 1
memcpy(p, c->fn_data, name_len), p += name_len;
*p++ = 5; // label 2
memcpy(p, "local", 5), p += 5;
*p++ = 0; // no more labels
memcpy(p, mdns_answer, sizeof(mdns_answer)), p += sizeof(mdns_answer);
#if MG_ENABLE_TCPIP
memcpy(p, &c->mgr->ifp->ip, 4), p += 4;
#else
memcpy(p, c->data, 4), p += 4;
#endif
if (!unicast) memcpy(&c->rem, &c->loc, sizeof(c->rem));
mg_send(c, buf, (size_t)(p - buf)); // And send it!
MG_DEBUG(("mDNS %c response sent", unicast ? 'U' : 'M'));
}
}
}
handle_mdns_record(c);
mg_iobuf_del(&c->recv, 0, c->recv.len);
}
(void) ev_data;
}
void mg_multicast_add(struct mg_connection *c, char *ip);
struct mg_connection *mg_mdns_listen(struct mg_mgr *mgr, char *name) {
struct mg_connection *mg_mdns_listen(struct mg_mgr *mgr, mg_event_handler_t fn,
void *fn_data) {
struct mg_connection *c =
mg_listen(mgr, "udp://224.0.0.251:5353", mdns_cb, name);
if (c != NULL) mg_multicast_add(c, (char *)"224.0.0.251");
mg_listen(mgr, "udp://224.0.0.251:5353", fn, fn_data);
if (c == NULL) return NULL;
c->pfn = mdns_cb, c->pfn_data = fn_data;
mg_multicast_add(c, (char *) "224.0.0.251");
return c;
}
bool mg_mdns_query(struct mg_connection *c, const char *name,
unsigned int rtype) {
struct mg_str name_;
name_.buf = (char *) name, name_.len = strlen(name);
mg_multicast_restore(c, (uint8_t *) &c->loc);
(void) rtype;
return mg_dns_send(c, &name_, 0, false);
}
+37 -2
View File
@@ -3,6 +3,12 @@
#include "net.h"
#include "str.h"
#define MG_DNS_RTYPE_A 1
#define MG_DNS_RTYPE_PTR 12
#define MG_DNS_RTYPE_TXT 16
#define MG_DNS_RTYPE_AAAA 28
#define MG_DNS_RTYPE_SRV 33
// Mongoose sends DNS queries that contain only one question:
// either A (IPv4) or AAAA (IPv6) address lookup.
// Therefore, we expect zero or one answer.
@@ -31,10 +37,39 @@ struct mg_dns_rr {
uint16_t alen; // Address length
};
// DNS-SD response record
struct mg_dnssd_record {
struct mg_str srvcproto; // service.proto, service name
struct mg_str txt; // TXT record contents
uint16_t port; // SRV record port
};
// mDNS request and response data structs passed to event handlers
struct mg_mdns_req {
struct mg_dns_rr *rr;
struct mg_dnssd_record *r;
struct mg_str reqname; // requested name in RR
struct mg_str respname; // actual name to use in response
struct mg_addr *addr; // actual address to use in response
bool is_listing;
bool is_resp;
bool is_unicast;
};
struct mg_mdns_resp {
struct mg_dns_rr *rr;
// TODO(scaprile )struct mg_str srvcproto; struct mg_str txt; uint16_t port; ?
struct mg_str name;
struct mg_addr addr;
// TODO(scaprile); bool has_A; bool has_PTR; bool has_SRV; bool has_TXT; ?
};
void mg_resolve(struct mg_connection *, const char *url);
void mg_resolve_cancel(struct mg_connection *);
bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *);
size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs,
bool is_question, struct mg_dns_rr *);
struct mg_connection *mg_mdns_listen(struct mg_mgr *mgr, char *name);
struct mg_connection *mg_mdns_listen(struct mg_mgr *mgr, mg_event_handler_t fn,
void *fn_data);
bool mg_mdns_query(struct mg_connection *, const char *, unsigned int);
+372 -157
View File
@@ -1,32 +1,54 @@
#include "cyw.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 uint32_t s_ip, s_mask;
static bool s_link, s_auth, s_join;
static void wifi_cb(struct mg_tcpip_if *ifp, int ev, void *ev_data) {
struct mg_wifi_data *wifi = &((struct mg_tcpip_driver_cyw_data *) ifp->driver_data)->wifi;
if (wifi->apmode && ev == MG_TCPIP_EV_ST_CHG && *(uint8_t *) ev_data == MG_TCPIP_STATE_UP) {
MG_DEBUG(("Access Point started"));
s_ip = ifp->ip, ifp->ip = wifi->apip;
s_mask = ifp->mask, ifp->mask = wifi->apmask;
ifp->enable_dhcp_client = false;
ifp->enable_dhcp_server = true;
}
}
static bool cyw_init(uint8_t *mac);
static void cyw_poll(void);
static bool mg_tcpip_driver_cyw_init(struct mg_tcpip_if *ifp) {
struct mg_tcpip_driver_cyw_data *d =
(struct mg_tcpip_driver_cyw_data *) ifp->driver_data;
struct mg_wifi_data *wifi = &d->wifi;
if (MG_BIG_ENDIAN) {
MG_ERROR(("Big-endian host"));
return false;
}
s_ifp = ifp;
s_ip = ifp->ip;
s_mask = ifp->mask;
s_link = s_auth = s_join = false;
ifp->pfn = wifi_cb;
if (!cyw_init(ifp->mac)) return false;
if (d->apmode) {
MG_DEBUG(("Starting AP '%s' (%u)", d->apssid, d->apchannel));
return mg_wifi_ap_start(d->apssid, d->appass, d->apchannel);
} else if (d->ssid != NULL && d->pass != NULL) {
MG_DEBUG(("Connecting to '%s'", d->ssid));
return mg_wifi_connect(d->ssid, d->pass);
if (wifi->apmode) {
return mg_wifi_ap_start(wifi);
} else if (wifi->ssid != NULL && wifi->pass != NULL) {
return mg_wifi_connect(wifi);
}
return true;
}
@@ -36,7 +58,7 @@ size_t mg_tcpip_driver_cyw_output(const void *buf, size_t len,
struct mg_tcpip_if *ifp) {
struct mg_tcpip_driver_cyw_data *d =
(struct mg_tcpip_driver_cyw_data *) ifp->driver_data;
return mg_cyw_tx(d->apmode ? 1 : 0, (void *) buf, len) >= len ? len : 0;
return mg_cyw_tx(d->wifi.apmode ? 1 : 0, (void *) buf, len) >= len ? len : 0;
}
static bool mg_tcpip_driver_cyw_poll(struct mg_tcpip_if *ifp, bool s1) {
@@ -44,7 +66,7 @@ static bool mg_tcpip_driver_cyw_poll(struct mg_tcpip_if *ifp, bool s1) {
if (!s1) return false;
struct mg_tcpip_driver_cyw_data *d =
(struct mg_tcpip_driver_cyw_data *) ifp->driver_data;
return d->apmode ? s_link : s_link && s_auth && s_join;
return d->wifi.apmode ? s_link : s_link && s_auth && s_join;
}
struct mg_tcpip_driver mg_tcpip_driver_cyw = {mg_tcpip_driver_cyw_init,
@@ -68,10 +90,12 @@ struct mg_tcpip_driver mg_tcpip_driver_cyw = {mg_tcpip_driver_cyw_init,
// SPI | SDIO <-- padded to 32-bit | 64-bytes
//
// - SDPCM has 3 channels (control, data, and asynchronous data)
// - SPI (and SDIO) has 4 "functions", F0 to F3, to access different
// blocks in the chip, like the SPI/SDIO controller, chip backplane, and 2 DMA
// I/Os; these are usually handled by SDPCM but we need to explicitly access
// the I/O controller and chip backplane during initialization
// - SPI has 4 "functions", F0 to F3, to access different blocks in the chip,
// like the SPI/SDIO controller, chip backplane, and 2 DMA I/Os; these are
// usually handled by SDPCM but we need to explicitly access the I/O controller
// 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
// (hardware design) NVRAM data, via the chip backplane access through the bus
@@ -121,10 +145,15 @@ struct data_hdr {
struct bdc_hdr bdc;
};
// gSPI, DS 4.2.1 Fig.12, 2-bit field
#define CYW_SD_FUNC_BUS 0 // F0
#define CYW_SD_FUNC_CHIP 1 // F1
#define CYW_SD_FUNC_WLAN 2 // F2
// gSPI, CYW43439 DS 4.2.1 Fig.12, 2-bit field
#define CYW_SPID_FUNC_BUS 0 // F0
#define CYW_SPID_FUNC_CHIP 1 // F1
#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_ASYNC_HDR 1
@@ -139,7 +168,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_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);
// High-level comm stuff
@@ -152,7 +181,7 @@ static void cyw_poll(void) {
cyw_update_hash_table();
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) ||
sdpcm->len > 2048 - sizeof(*sdpcm))
return;
@@ -185,7 +214,7 @@ static void cyw_handle_bdc(struct bdc_hdr *bdc, size_t len) {
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
static size_t mg_cyw_tx(unsigned int ifc, void *data, size_t len) {
@@ -194,15 +223,15 @@ static size_t mg_cyw_tx(unsigned int ifc, void *data, size_t len) {
memset(txdata, 0, sizeof(*hdr));
memcpy((uint8_t *) txdata + sizeof(*hdr), data, len);
// TODO(): hdr->bdc.priority = map IP to TOS if supporting QoS/ToS
hdr->bdc.flags = 2 << 4; // BDC version 2
hdr->bdc.flags2 = ifc; // 0 -> STA, 1 -> AP
hdr->bdc.flags = 2 << 4; // BDC version 2
hdr->bdc.flags2 = (uint8_t) ifc; // 0 -> STA, 1 -> AP
// hdr->bdc.data_offset = 0; // actually zeroed above
hdr->sdpcm.len = txlen;
hdr->sdpcm._len = (uint16_t) ~txlen;
hdr->sdpcm.sw_hdr.sequence = ++s_tx_seqno;
hdr->sdpcm.sw_hdr.channel_and_flags = CYW_SDPCM_DATA_HDR,
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
@@ -250,6 +279,7 @@ struct scan_result;
static void cyw_handle_scan_result(uint32_t status, struct scan_result *data,
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) {
struct evnt_msg *msg = (struct evnt_msg *) &bdc[bdc->data_offset + 1];
MG_VERBOSE(("%u bytes event", len));
@@ -263,7 +293,7 @@ static void cyw_handle_bdc_evnt(struct bdc_hdr *bdc, size_t len) {
uint32_t status = mg_ntohl(msg->event.status);
uint32_t reason = mg_ntohl(msg->event.reason);
uint16_t flags = mg_ntohs(msg->event.flags);
MG_DEBUG(("BCM event %lu %lu %lu %p", event_type, status, reason, flags));
MG_VERBOSE(("BCM evt %lu %lu %lu %p", event_type, status, reason, flags));
if (event_type == 16 && status == 0) { // Link
s_link = flags & 1;
} else if (event_type == 46 && s_link) { // PSK sup with link up
@@ -313,7 +343,7 @@ static bool cyw_ioctl_iovar_set_(unsigned int ifc, char *var, void *data,
size_t len);
// clang-format off
// 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_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); }
@@ -324,11 +354,12 @@ static bool cyw_ioctl_iovar_set(char *var, void *data, size_t len) { return cyw_
// clang-format off
static bool cyw_wifi_connect(char *ssid, char *pass) {
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};
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;
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
// sup_wpa[1] = 0 if not using security
if (!(cyw_ioctl_set(134 /* SET_WSEC */, (uint8_t *)&val, sizeof(val))
@@ -340,8 +371,8 @@ static bool cyw_wifi_connect(char *ssid, char *pass) {
// skip if not using auth
memset(data, 0, sizeof(data));
len = strlen(pass);
((uint16_t *)data)[0] = (uint16_t) len;
((uint16_t *)data)[1] = 1; // indicates wireless security key, skip for WPA3 SAE
da[0] = (uint16_t) len;
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
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));
@@ -368,8 +399,9 @@ static bool cyw_wifi_disconnect(void) {
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
uint16_t *da = (uint16_t *) data;
unsigned int len;
uint32_t val;
uint32_t val;
// CHIP DEPENDENCY
// RPi set the AMPDU parameter for AP (window size = 2) *****************
// val = 2 ; cyw_ioctl_iovar_set_(0, "ampdu_ba_wsize", (uint8_t *)&val, sizeof(val));
@@ -394,14 +426,14 @@ 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
memset(data, 0, sizeof(data));
len = strlen(pass);
((uint16_t *)data)[0] = (uint16_t) len; // skip for WPA3 SAE
((uint16_t *)data)[1] = 1; // indicates wireless security key, skip for WPA3 SAE
da[0] = (uint16_t) len; // skip for WPA3 SAE (43430 does NOT support WPA3 in AP)
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
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:
memcpy((uint8_t *)data + sizeof(uint16_t), pass, len);
cyw_ioctl_iovar_set_(1, "sae_password", data, sizeof(data)); */
/* for WPA3 or mixed WPA2/WPA3:
/* for WPA3 or mixed WPA2/WPA3:
val = 5 ; cyw_ioctl_iovar_set_(1, "sae_max_pwe_loop", (uint8_t *)&val, sizeof(val)); // Some chipsets do not support this */
// resume if not using auth
@@ -539,15 +571,15 @@ 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)
return; // silently discard malformed data
if (!(sbss->flags & MG_BIT(2))) return; // RSSI_ONCHANNEL, ignore off-channel results
bss.SSID = mg_str_n(sbss->SSID, sbss->SSID_len);
bss.BSSID = sbss->BSSID;
bss.SSID = mg_str_n((char *)sbss->SSID, sbss->SSID_len);
bss.BSSID = (char *)sbss->BSSID;
bss.RSSI = (int8_t)sbss->RSSI;
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.band = band & CYW_BSS_BAND2G ? MG_WIFI_BAND_2G : MG_WIFI_BAND_5G;
bss.security = (sbss->capability & MG_BIT(4) /* CAP_PRIVACY */) ? MG_WIFI_SECURITY_WEP : MG_WIFI_SECURITY_OPEN;
{ // travel IEs (Information Elements) in search of security definitions
const uint8_t wot1[4] = {0x00, 0x50, 0xf2, 0x01}; // WPA_OUI_TYPE1
const uint8_t wot1[4] = {0x00, 0x50, 0xf2, 0x01}; // WPA_OUI_TYPE1
uint8_t *ie = (uint8_t *)sbss + sbss->ie_offset;
int bytes = (int) sbss->ie_length;
while (bytes > 0 && ie[1] + 2 < bytes) { // ie[0] -> type, ie[1] -> bytes from ie[2]
@@ -558,11 +590,11 @@ static void cyw_handle_scan_result(uint32_t status, struct scan_result *data, si
bytes -= ie[1] + 2;
}
}
MG_VERBOSE(("BSS: %.*s (%u) (%M) %d dBm %u", bss.SSID.len, bss.SSID.buf, bss.channel, mg_print_mac, bss.BSSID, (int) bss.RSSI, bss.security));
MG_VERBOSE(("BSS: %.*s (%u) (%M) %d dBm %u", bss.SSID.len, bss.SSID.buf, bss.channel, mg_print_mac, bss.BSSID, (int) bss.RSSI, bss.security));
mg_tcpip_call(s_ifp, MG_TCPIP_EV_WIFI_SCAN_RESULT, &bss);
} else {
MG_ERROR(("scan error"));
}
}
}
// clang-format on
@@ -575,7 +607,7 @@ static uint8_t *s_ioctl_resp;
static bool s_ioctl_err;
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));
if ((cdc->flags >> 16) != s_ioctl_reqid) return;
if (cdc->flags & 1) {
@@ -584,9 +616,8 @@ static void cyw_handle_cdc(struct cdc_hdr *cdc, size_t len) {
return;
}
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],
resp[3]));
s_ioctl_resp = resp;
MG_VERBOSE(("IOCTL result: %02x %02x %02x %02x ..", r[0], r[1], r[2], r[3]));
s_ioctl_resp = r;
}
// NOTE(): alt no loop handler dispatching IOCTL response to current handler:
// static void *s_ioctl_hnd; *s_ioctl_hnd(ioctl, len);
@@ -618,7 +649,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.channel_and_flags = CYW_SDPCM_CTRL_HDR;
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
@@ -652,20 +683,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
}
static void cyw_ioctl_send_iovar_set(unsigned int ifc, char *var, void *data,
size_t len) {
__attribute__((unused)) static void cyw_ioctl_send_iovar_set(unsigned int ifc,
char *var,
void *data,
size_t len) {
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
static bool cyw_ioctl_wait(void) {
unsigned int times = 6000;
unsigned int times = 100;
s_ioctl_resp = NULL;
s_ioctl_err = false;
while (s_ioctl_resp == NULL && !s_ioctl_err && times-- > 0)
cyw_poll(); // TODO(scaprile): review wait/sleep strategy (this loop is executed only when initializing/acting on the chip)
MG_DEBUG(("resp: %lp, err: %c, times: %d", s_ioctl_resp,
s_ioctl_err ? '1' : '0', (int) times));
do { // IOCTL response processing does not call any other IOCTL function
cyw_poll(); // otherwise we can't allow them to pile up here
// network frames will be pushed to the queue so that is safe
} 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;
}
@@ -723,15 +763,22 @@ struct clm_hdr {
#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 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
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;
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
// set Wi-Fi up
val = 0 /* disable */; cyw_ioctl_iovar_set("bus:txglom", (uint8_t *)&val, sizeof(val));
@@ -739,7 +786,7 @@ static bool cyw_init(uint8_t *mac) {
// CHIP DEPENDENCY
val = 8 ; cyw_ioctl_iovar_set("ampdu_ba_wsize", (uint8_t *)&val, sizeof(val));
val = 4 ; cyw_ioctl_iovar_set("ampdu_mpdu", (uint8_t *)&val, sizeof(val));
val = 0 /* 8K */; cyw_ioctl_iovar_set("ampdu_rx_factor", (uint8_t *)&val, sizeof(val));
val = 0 /* 8K */; cyw_ioctl_iovar_set("ampdu_rx_factor", (uint8_t *)&val, sizeof(val));
//
{
struct cyw_country c;
@@ -759,7 +806,7 @@ static bool cyw_init(uint8_t *mac) {
unsigned int times = 100;
while (times --)
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;
if (!cyw_ioctl_set(2 /* UP, interface up */, NULL, 0)) return false;
@@ -818,20 +865,18 @@ static bool cyw_load_clmll(void *data, size_t len) {
break;
sent += bytes;
offset += bytes;
hdr.flag &= ~MG_BIT(1); // DL_BEGIN
hdr.flag &= (uint16_t)~MG_BIT(1); // DL_BEGIN
}
return sent >= len;
}
// 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) {
// TODO(): read database, rebuild hash table
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);
}
@@ -848,8 +893,16 @@ static void cyw_update_hash_table(void) {
#define CYW_CHIP_BCKPLN_ADDRMSK 0x7fff
#define CYW_CHIP_BCKPLN_ACCSS4B MG_BIT(15)
#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_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
#define CYW_CHIP_ARMCORE_BASE (CYW_CHIP_CHIPCOMMON + 0x3000)
@@ -874,9 +927,9 @@ static void cyw_update_hash_table(void) {
#define CYW_CHIP_AI_IOCTRL 0x408
#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);
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);
// clang-format off
@@ -884,9 +937,9 @@ static void cyw_spi_read(unsigned int f, uint32_t addr, void *data,
static void cyw_set_backplane_window(uint32_t addr) {
uint32_t val;
addr &= ~CYW_CHIP_BCKPLN_ADDRMSK;
val = (addr >> 24) & 0xff; cyw_spi_write(CYW_SD_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 >> 8) & 0xff; cyw_spi_write(CYW_SD_FUNC_CHIP, CYW_CHIP_ADDRLOW, &val, 1);
val = (addr >> 24) & 0xff; cyw_bus_write(CYW_BUS_FUNC_CHIP, CYW_CHIP_ADDRHIGH, &val, 1);
val = (addr >> 16) & 0xff; cyw_bus_write(CYW_BUS_FUNC_CHIP, CYW_CHIP_ADDRMID, &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) {
@@ -894,21 +947,21 @@ static bool cyw_core_reset(uint32_t core_base, bool check) {
// 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
// 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
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
cyw_spi_read(CYW_SD_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
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_bus_write(CYW_BUS_FUNC_CHIP, (core_base + CYW_CHIP_AI_IOCTRL) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 1); // reset
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_bus_write(CYW_BUS_FUNC_CHIP, (core_base + CYW_CHIP_AI_RESETCTRL) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 1); // release reset
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);
cyw_spi_read(CYW_SD_FUNC_CHIP, (core_base + CYW_CHIP_AI_IOCTRL) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 1); // ensure backplane operations end
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_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);
if (check) {
// 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;
// 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
}
return true;
@@ -916,29 +969,28 @@ static bool cyw_core_reset(uint32_t core_base, bool check) {
static void cyw_socram_init(void) {
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
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 = 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 = 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_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
static void cyw_load_data(uint32_t dest, void *data, size_t len) {
size_t sent = 0, offset = 0;
uint32_t last_addr = ~0;
uint32_t last_addr = (uint32_t) ~0;
while (sent < len) {
size_t bytes = len - sent, avail;
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
last_addr = 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;
// BUS DEPENDENCY: max bus to backplane transfer size
if (bytes > CYW_CHIP_BCKPLN_SPIMAX) bytes = CYW_CHIP_BCKPLN_SPIMAX;
cyw_spi_write(CYW_SD_FUNC_CHIP, addr | CYW_CHIP_BCKPLN_ACCSS4B, (uint8_t *)data + offset, bytes);
if (bytes > CYW_CHIP_BCKPLN_BUSMAX) bytes = CYW_CHIP_BCKPLN_BUSMAX; // bus to backplane transfer limit
cyw_bus_write(CYW_BUS_FUNC_CHIP, addr, (uint8_t *)data + offset, (uint16_t) bytes);
sent += bytes;
offset += bytes;
}
@@ -950,13 +1002,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_socram_init();
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
{
{
const uint32_t start = CYW_CHIP_RAM_SIZE - 4 - nvramlen;
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
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
if (!cyw_core_reset(CYW_CHIP_ARMCORE, true)) return false;
@@ -964,6 +1016,8 @@ static bool cyw_load_fwll(void *fwdata, size_t fwlen, void *nvramdata, size_t nv
}
// clang-format on
#if !MG_ENABLE_DRIVER_CYW_SDIO
// CYW43 SPI bus specifics
#define CYW_BUS_SPI_BUSCTRL 0x00 // 4 regs, 0 to 3
@@ -975,29 +1029,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)
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
static size_t cyw_spi_poll(uint8_t *response) {
size_t len;
uint32_t res;
// SPI poll
cyw_spi_read(CYW_SD_FUNC_BUS, CYW_BUS_SPI_STATUS, &res, sizeof(res));
if (res == ~0 || !(res & MG_BIT(8) /* packet available */ )) return 0;
cyw_spi_read(CYW_SPID_FUNC_BUS, CYW_BUS_SPI_STATUS, &res, sizeof(res));
if (res == (uint32_t) ~0 || !(res & MG_BIT(8) /* packet available */ )) return 0;
len = CYW_BUS_STS_LEN(res);
if (len == 0) { // just ack IRQ
uint16_t val = 1;
cyw_spi_write(CYW_SD_FUNC_CHIP, CYW_CHIP_SPIFRCTRL, &val, 1);
cyw_spi_read(CYW_SD_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_CHIP, CYW_CHIP_SPIFRCTRL, &val, 1);
cyw_spi_read(CYW_SPID_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;
}
cyw_spi_read(CYW_SD_FUNC_WLAN, 0, response, len);
cyw_spi_read(CYW_SPID_FUNC_WLAN, 0, response, (uint16_t)len);
return len;
}
// BUS DEPENDENCY: name is generic but function is bus dependent
static size_t cyw_bus_tx(uint32_t *data, uint16_t len) {
while (len & 3) data[len++] = 0; // SPI 32-bit padding (SDIO->64-byte)
return cyw_spi_write(CYW_SD_FUNC_WLAN, 0, data, len) ? len: 0;
static size_t cyw_spi_tx(uint32_t *data, uint16_t len) {
while (len & 3) data[len++] = 0; // SPI 32-bit padding
return cyw_spi_write(CYW_SPID_FUNC_WLAN, 0, data, len) ? len: 0;
}
// this can be integrated in lowest level SPI read/write _driver_ functions
@@ -1007,20 +1065,19 @@ uint32_t sw16_2(uint32_t data) {
}
// 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() {
struct mg_tcpip_driver_cyw_data *d =
(struct mg_tcpip_driver_cyw_data *) s_ifp->driver_data;
struct mg_tcpip_driver_cyw_data *d = (struct mg_tcpip_driver_cyw_data *) s_ifp->driver_data;
uint32_t val = 0;
// DS 4.2.3 Boot-Up Sequence; WHD: other chips might require more effort
unsigned int times = 51;
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;
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.
// Configure SPI and switch to 32-bit big-endian mode:
// - High-speed mode: d->hs true
@@ -1028,33 +1085,34 @@ static bool cyw_spi_init() {
// - SPI RESPONSE DELAY 4 bytes time [not in DS] TODO(scaprile): logic ana
// - Status not sent after command, IRQ with status
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);
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;
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
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
// 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
// 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
times = 10;
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
mg_delayms(1);
}
if (times == ~0) return false;
if (times == (unsigned int) ~0) return false;
// 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_spi_read(CYW_SD_FUNC_CHIP, (CYW_CHIP_CHIPCOMMON + 0x00) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 2);
MG_INFO(("WLAN chip is CYW%u", *((uint16_t *)&val)));
cyw_spi_read(CYW_SPID_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;
@@ -1062,77 +1120,74 @@ static bool cyw_spi_init() {
// Wait for High Throughput (HT) clock ready
times = 50;
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
mg_delayms(1);
}
if (times == ~0) return false;
if (times == (unsigned int) ~0) return false;
// Wait for backplane ready
times = 1000;
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
mg_delayms(1);
}
if (times == ~0) return false;
if (times == (unsigned int) ~0) return false;
// CHIP DEPENDENCY
// Enable save / restore
// Configure WakeupCtrl, set HT_AVAIL in CLOCK_CSR
cyw_spi_read(CYW_SD_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);
cyw_spi_read(CYW_SPID_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
// 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
// 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)
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))) {
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)
cyw_spi_read(CYW_SD_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));
cyw_spi_read(CYW_SPID_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
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(): ?
val = 0x00; cyw_spi_write(CYW_SD_FUNC_CHIP, CYW_CHIP_PULLUP, &val, 1);
cyw_spi_read(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_SPID_FUNC_CHIP, CYW_CHIP_PULLUP, &val, 1);
// Clear possible data unavailable error
cyw_spi_read(CYW_SD_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));
// Load CLM blob
if (!cyw_load_clm(d->fw)) return false;
cyw_spi_read(CYW_SPID_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));
return true;
}
// clang-format on
// gSPI, DS 4.2.1 Fig.12
#define CYW_SD_LEN(x) ((x) &0x7FF) // bits 0-10
#define CYW_SD_ADDR(x) (((x) &0x1FFFF) << 11) // bits 11-27,
#define CYW_SD_FUNC(x) (((x) &3) << 28) // bits 28-29
#define CYW_SD_INC MG_BIT(30)
#define CYW_SD_WR MG_BIT(31)
// gSPI, CYW43439 DS 4.2.1 Fig.12
#define CYW_SPID_LEN(x) ((x) &0x7FF) // bits 0-10
#define CYW_SPID_ADDR(x) (((x) &0x1FFFF) << 11) // bits 11-27,
#define CYW_SPID_FUNC(x) (((x) &3) << 28) // bits 28-29
#define CYW_SPID_INC MG_BIT(30)
#define CYW_SPID_WR MG_BIT(31)
static bool cyw_spi_write(unsigned int f, uint32_t addr, void *data,
uint16_t len) {
struct mg_tcpip_driver_cyw_data *d =
(struct mg_tcpip_driver_cyw_data *) s_ifp->driver_data;
struct mg_tcpip_spi_ *s = (struct mg_tcpip_spi_ *) d->spi;
uint32_t hdr = CYW_SD_WR | CYW_SD_INC | CYW_SD_FUNC(f) | CYW_SD_ADDR(addr) |
CYW_SD_LEN(len); // gSPI header
struct mg_tcpip_spi_ *s = (struct mg_tcpip_spi_ *) d->bus;
uint32_t hdr = CYW_SPID_WR | CYW_SPID_INC | CYW_SPID_FUNC(f) |
CYW_SPID_ADDR(addr) | CYW_SPID_LEN(len); // gSPI header
// 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;
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
s->begin(NULL);
@@ -1148,26 +1203,26 @@ static bool cyw_spi_write(unsigned int f, uint32_t addr, void *data,
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,
uint16_t len) {
struct mg_tcpip_driver_cyw_data *d =
(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 =
f == CYW_SD_FUNC_CHIP
f == CYW_SPID_FUNC_CHIP
? 4
: 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) |
CYW_SD_LEN(len + padding); // gSPI header
if (f == CYW_SD_FUNC_WLAN && (len & 3))
uint32_t hdr = CYW_SPID_INC | CYW_SPID_FUNC(f) | CYW_SPID_ADDR(addr) |
CYW_SPID_LEN(len + padding); // gSPI header
if (f == CYW_SPID_FUNC_WLAN && (len & 3))
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
s->begin(NULL);
s->txn(NULL, (uint8_t *) &hdr, NULL, sizeof(hdr));
if (f == CYW_SD_FUNC_CHIP) {
if (f == CYW_SPID_FUNC_CHIP) {
uint32_t pad;
s->txn(NULL, NULL, (uint8_t *) &pad, 4); // read padding back and discard
}
@@ -1175,22 +1230,182 @@ static void cyw_spi_read(unsigned int f, uint32_t addr, void *data,
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
bool mg_wifi_scan(void) {
return cyw_wifi_scan();
}
bool mg_wifi_connect(char *ssid, char *pass) {
return cyw_wifi_connect(ssid, pass);
bool mg_wifi_connect(struct mg_wifi_data *wifi) {
s_ifp->ip = s_ip;
s_ifp->mask = s_mask;
if (s_ifp->ip == 0) s_ifp->enable_dhcp_client = true;
s_ifp->enable_dhcp_server = false;
MG_DEBUG(("Connecting to '%s'", wifi->ssid));
return cyw_wifi_connect(wifi->ssid, wifi->pass);
}
bool mg_wifi_disconnect(void) {
return cyw_wifi_disconnect();
}
bool mg_wifi_ap_start(char *ssid, char *pass, unsigned int channel) {
return cyw_wifi_ap_start(ssid, pass, channel);
bool mg_wifi_ap_start(struct mg_wifi_data *wifi) {
MG_DEBUG(("Starting AP '%s' (%u)", wifi->apssid, wifi->apchannel));
return cyw_wifi_ap_start(wifi->apssid, wifi->appass, wifi->apchannel);
}
bool mg_wifi_ap_stop(void) {
+19 -26
View File
@@ -1,6 +1,8 @@
#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_ {
void *spi; // Opaque SPI bus descriptor
@@ -20,35 +22,26 @@ struct mg_tcpip_driver_cyw_firmware {
};
struct mg_tcpip_driver_cyw_data {
struct mg_tcpip_spi_ *spi;
struct mg_wifi_data wifi;
void *bus;
struct mg_tcpip_driver_cyw_firmware *fw;
char *ssid;
char *pass;
char *apssid;
char *appass;
uint8_t security; // TBD
uint8_t apsecurity; // TBD
uint8_t apchannel;
bool apmode; // start in AP mode; 'false' starts connection to 'ssid' if not NULL
bool hs; // use chip "high-speed" mode; otherwise SPI CPOL0 CPHA0 (DS 4.2.3 Table 6)
bool hs; // use chip "high-speed" mode; otherwise SPI CPOL0 CPHA0 (DS 4.2.3 Table 6)
};
#if 0
#define MG_TCPIP_DRIVER_INIT(mgr) \
do { \
static struct mg_tcpip_driver_cyw_data driver_data_; \
static struct mg_tcpip_if mif_; \
MG_SET_WIFI_CONFIG(&driver_data_); \
mif_.ip = MG_TCPIP_IP; \
mif_.mask = MG_TCPIP_MASK; \
mif_.gw = MG_TCPIP_GW; \
mif_.driver = &mg_tcpip_driver_pico_w; \
mif_.driver_data = &driver_data_; \
mif_.recv_queue.size = 8192; \
mif_.mac[0] = 2; /* MAC read from OTP at driver init */ \
mg_tcpip_init(mgr, &mif_); \
#define MG_TCPIP_DRIVER_INIT(mgr) \
do { \
static struct mg_tcpip_driver_cyw_data driver_data_; \
static struct mg_tcpip_if mif_; \
MG_SET_WIFI_CONFIG(&driver_data_); \
mif_.ip = MG_TCPIP_IP; \
mif_.mask = MG_TCPIP_MASK; \
mif_.gw = MG_TCPIP_GW; \
mif_.driver = &mg_tcpip_driver_cyw; \
mif_.driver_data = &driver_data_; \
mif_.recv_queue.size = 8192; \
mif_.mac[0] = 2; /* MAC read from OTP at driver init */ \
mg_tcpip_init(mgr, &mif_); \
MG_INFO(("Driver: cyw, MAC: %M", mg_print_mac, mif_.mac)); \
} while (0)
#endif
#endif
+19 -11
View File
@@ -1,6 +1,9 @@
#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) || \
(defined(MG_ENABLE_DRIVER_MCXE) && MG_ENABLE_DRIVER_MCXE)
struct imxrt_enet {
volatile uint32_t RESERVED0, EIR, EIMR, RESERVED1, RDAR, TDAR, RESERVED2[3],
ECR, RESERVED3[6], MMFR, MSCR, RESERVED4[7], MIBC, RESERVED5[7], RCR,
@@ -26,12 +29,15 @@ struct imxrt_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 ETH_DESC_CNT 5 // Descriptors count
#else
#elif defined(MG_ENABLE_DRIVER_IMXRT10) && MG_ENABLE_DRIVER_IMXRT10
#define ENET ((struct imxrt_enet *) (uintptr_t) 0x402D8000U)
#define ETH_DESC_CNT 4 // Descriptors count
#else // MG_ENABLE_DRIVER_MCXE
#define ENET ((struct imxrt_enet *) (uintptr_t) 0x40079000U)
#define ETH_DESC_CNT 4 // Descriptor count
#endif
#define ETH_PKT_SIZE 1536 // Max frame size, 64-bit aligned
@@ -42,15 +48,12 @@ struct enet_desc {
uint32_t *buffer; // Data ptr
};
// TODO(): handle these in a portable compiler-independent CMSIS-friendly way
#define MG_64BYTE_ALIGNED __attribute__((aligned((64U))))
// Descriptors: in non-cached area (TODO(scaprile)), (37.5.1.22.2 37.5.1.23.2)
// Buffers: 64-byte aligned (37.3.14)
static volatile struct enet_desc s_rxdesc[ETH_DESC_CNT] MG_64BYTE_ALIGNED;
static volatile struct enet_desc s_txdesc[ETH_DESC_CNT] MG_64BYTE_ALIGNED;
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_64BYTE_ALIGNED;
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_64BYTE_ALIGNED;
static volatile struct enet_desc s_rxdesc[ETH_DESC_CNT] MG_ETH_RAM MG_64BYTE_ALIGNED;
static volatile struct enet_desc s_txdesc[ETH_DESC_CNT] MG_ETH_RAM MG_64BYTE_ALIGNED;
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM MG_64BYTE_ALIGNED;
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM MG_64BYTE_ALIGNED;
static struct mg_tcpip_if *s_ifp; // MIP interface
static uint16_t enet_read_phy(uint8_t addr, uint8_t reg) {
@@ -187,9 +190,14 @@ static bool mg_tcpip_driver_imxrt_poll(struct mg_tcpip_if *ifp, bool s1) {
return up;
}
void ENET_IRQHandler(void);
static uint32_t s_rxno;
#if !defined(MG_ENABLE_DRIVER_MCXE)
void ENET_IRQHandler(void);
void ENET_IRQHandler(void) {
#else
void ENET_Receive_IRQHandler(void);
void ENET_Receive_IRQHandler(void) {
#endif
ENET->EIR = MG_BIT(25); // Ack IRQ
// Frame received, loop
for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever
+4 -1
View File
@@ -1,6 +1,9 @@
#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) || \
(defined(MG_ENABLE_DRIVER_MCXE) && MG_ENABLE_DRIVER_MCXE)
struct mg_tcpip_driver_imxrt_data {
// MDC clock divider. MDC clock is derived from IPS Bus clock (ipg_clk),
+91
View File
@@ -0,0 +1,91 @@
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_NXP_WIFI) && \
MG_ENABLE_DRIVER_NXP_WIFI
#include "drivers/nxp_wifi.h"
bool __attribute__((weak)) netif_init(struct mg_tcpip_if *ifp) {
(void) ifp;
MG_ERROR(("Please link wifi/port/net contents"));
return false;
}
size_t __attribute__((weak))
netif_tx(const void *bfr, size_t len, struct mg_tcpip_if *ifp) {
(void) bfr;
(void) len;
netif_init(ifp);
return 0;
}
bool __attribute__((weak)) netif_connect(struct mg_wifi_data *wifi) {
(void) wifi;
return netif_init(NULL);
}
bool __attribute__((weak))
netif_poll(struct mg_tcpip_if *ifp, bool s1, mg_tcpip_event_handler_t evcb) {
(void) ifp;
(void) s1;
(void) evcb;
return false;
}
static struct mg_tcpip_if *s_ifp;
static uint32_t s_ip, s_mask;
static void wifi_cb(struct mg_tcpip_if *ifp, int ev, void *ev_data) {
struct mg_wifi_data *wifi =
&((struct mg_tcpip_driver_nxp_wifi_data *) ifp->driver_data)->wifi;
if (wifi->apmode && ev == MG_TCPIP_EV_ST_CHG &&
*(uint8_t *) ev_data == MG_TCPIP_STATE_UP) {
MG_DEBUG(("Access Point started"));
s_ip = ifp->ip, ifp->ip = wifi->apip;
s_mask = ifp->mask, ifp->mask = wifi->apmask;
ifp->enable_dhcp_client = false;
ifp->enable_dhcp_server = true;
}
}
static bool nxp_wifi_init(struct mg_tcpip_if *ifp) {
struct mg_wifi_data *wifi =
&((struct mg_tcpip_driver_nxp_wifi_data *) ifp->driver_data)->wifi;
s_ifp = ifp;
s_ip = ifp->ip;
s_mask = ifp->mask;
ifp->pfn = wifi_cb;
if (!netif_init(ifp)) return false;
if (wifi->apmode) {
return mg_wifi_ap_start(wifi);
} else if (wifi->ssid != NULL && wifi->pass != NULL) {
return mg_wifi_connect(wifi);
}
return true;
}
bool nxp_wifi_poll(struct mg_tcpip_if *ifp, bool s1) {
return netif_poll(ifp, s1, mg_tcpip_call);
}
struct mg_tcpip_driver mg_tcpip_driver_nxp_wifi = {nxp_wifi_init, netif_tx,
NULL, nxp_wifi_poll};
bool mg_wifi_connect(struct mg_wifi_data *wifi) {
s_ifp->ip = s_ip;
s_ifp->mask = s_mask;
if (s_ifp->ip == 0) s_ifp->enable_dhcp_client = true;
s_ifp->enable_dhcp_server = false;
return netif_connect(wifi);
}
bool __attribute__((weak)) mg_wifi_scan(void) {
return netif_init(NULL);
}
bool __attribute__((weak)) mg_wifi_disconnect(void) {
return netif_init(NULL);
}
bool __attribute__((weak)) mg_wifi_ap_start(struct mg_wifi_data *wifi) {
(void) wifi;
return netif_init(NULL);
}
bool __attribute__((weak)) mg_wifi_ap_stop(void) {
return netif_init(NULL);
}
#endif
+28
View File
@@ -0,0 +1,28 @@
#pragma once
#if MG_ENABLE_TCPIP && \
defined(MG_ENABLE_DRIVER_NXP_WIFI) && MG_ENABLE_DRIVER_NXP_WIFI
struct mg_tcpip_driver_nxp_wifi_data {
struct mg_wifi_data wifi;
};
#define MG_TCPIP_DRIVER_INIT(mgr) \
do { \
static struct mg_tcpip_driver_nxp_wifi_data driver_data_; \
static struct mg_tcpip_if mif_; \
MG_SET_WIFI_CONFIG(&driver_data_); \
mif_.ip = MG_TCPIP_IP; \
mif_.mask = MG_TCPIP_MASK; \
mif_.gw = MG_TCPIP_GW; \
mif_.driver = &mg_tcpip_driver_nxp_wifi; \
mif_.driver_data = &driver_data_; \
mif_.recv_queue.size = 8192; \
mif_.mac[0] = 2; /* MAC read from OTP at driver init */ \
mg_tcpip_init(mgr, &mif_); \
MG_INFO(("Driver: nxp wifi, MAC: %M", mg_print_mac, mif_.mac)); \
} while (0)
#endif
+54 -20
View File
@@ -1,13 +1,17 @@
#include "phy.h"
enum { // ID1 ID2
MG_PHY_KSZ8x = 0x22, // 0022 1561 - KSZ8081RNB
enum { // ID1 ID2
MG_PHY_KSZ8x = 0x22, // 0022 156x - KSZ8081RNB, KSZ8091RNB
MG_PHY_DP83x = 0x2000,
MG_PHY_DP83867 = 0xa231, // 2000 a231 - TI DP83867I
MG_PHY_DP83825 = 0xa140, // 2000 a140 - TI DP83825I
MG_PHY_DP83848 = 0x5ca2, // 2000 5ca2 - TI DP83848I
MG_PHY_LAN87x = 0x7, // 0007 c0fx - LAN8720
MG_PHY_RTL8201 = 0x1C // 001c c816 - RTL8201
MG_PHY_RTL82x = 0x1c,
MG_PHY_RTL8201 = 0xc816, // 001c c816 - RTL8201F
MG_PHY_RTL8211 = 0xc916, // 001c c916 - RTL8211F
MG_PHY_ICS1894x = 0x15,
MG_PHY_ICS189432 = 0xf450 // 0015 f450 - ICS1894
};
enum {
@@ -22,8 +26,10 @@ enum {
MG_PHY_KSZ8x_REG_PC1R = 30,
MG_PHY_KSZ8x_REG_PC2R = 31,
MG_PHY_LAN87x_REG_SCSR = 31,
MG_PHY_RTL8201_REG_RMSR = 16, // in page 7
MG_PHY_RTL8201_REG_PAGESEL = 31
MG_PHY_RTL82x_REG_PAGESEL = 31,
MG_PHY_RTL8201_REG_RMSR = 16, // in page 7
MG_PHY_RTL8211_REG_PHYSR = 26, // in page a43
MG_PHY_ICS189432_REG_POLL = 17
};
static const char *mg_phy_id_to_str(uint16_t id1, uint16_t id2) {
@@ -43,12 +49,20 @@ static const char *mg_phy_id_to_str(uint16_t id1, uint16_t id2) {
return "KSZ8x";
case MG_PHY_LAN87x:
return "LAN87x";
case MG_PHY_RTL8201:
return "RTL8201";
case MG_PHY_RTL82x:
switch (id2) {
case MG_PHY_RTL8201:
return "RTL8201";
case MG_PHY_RTL8211:
return "RTL8211";
default:
return "RTL82x";
}
case MG_PHY_ICS1894x:
return "ICS1894x";
default:
return "unknown";
}
(void) id2;
}
void mg_phy_init(struct mg_phy *phy, uint8_t phy_addr, uint8_t config) {
@@ -77,20 +91,24 @@ 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));
} else if (id1 == MG_PHY_KSZ8x) {
// Disable isolation (override hw, it doesn't make sense at this point)
phy->write_reg( // #2848, some NXP boards set ISO, even though
phy_addr, MG_PHY_REG_BCR, // docs say they don't
phy->read_reg(phy_addr, MG_PHY_REG_BCR) & (uint16_t) ~MG_BIT(10));
phy->write_reg(phy_addr, MG_PHY_KSZ8x_REG_PC2R, // now do clock stuff
MG_BIT(15) | MG_BIT(8) | MG_BIT(7));
// - #2848, some NXP boards set ISO, even though docs say they don't
phy->write_reg(phy_addr, MG_PHY_REG_BCR,
(uint16_t) (phy->read_reg(phy_addr, MG_PHY_REG_BCR) &
(uint16_t) ~MG_BIT(10)));
// 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) {
// nothing to do
} else if (id1 == MG_PHY_RTL8201) {
} else if (id1 == MG_PHY_RTL82x && id2 == MG_PHY_RTL8201) {
// assume PHY has been hardware strapped properly
#if 0
phy->write_reg(phy_addr, MG_PHY_RTL8201_REG_PAGESEL, 7); // Select page 7
phy->write_reg(phy_addr, MG_PHY_RTL82x_REG_PAGESEL, 7); // Select page 7
phy->write_reg(phy_addr, MG_PHY_RTL8201_REG_RMSR, 0x1ffa);
phy->write_reg(phy_addr, MG_PHY_RTL8201_REG_PAGESEL, 0); // Select page 0
phy->write_reg(phy_addr, MG_PHY_RTL82x_REG_PAGESEL, 0); // Select page 0
#endif
} else if (id1 == MG_PHY_RTL82x && id2 == MG_PHY_RTL8211) {
// assume PHY has been hardware strapped properly
}
}
@@ -130,10 +148,26 @@ bool mg_phy_up(struct mg_phy *phy, uint8_t phy_addr, bool *full_duplex,
uint16_t scsr = phy->read_reg(phy_addr, MG_PHY_LAN87x_REG_SCSR);
*full_duplex = scsr & MG_BIT(4);
*speed = (scsr & MG_BIT(3)) ? MG_PHY_SPEED_100M : MG_PHY_SPEED_10M;
} else if (id1 == MG_PHY_RTL8201) {
uint16_t bcr = phy->read_reg(phy_addr, MG_PHY_REG_BCR);
*full_duplex = bcr & MG_BIT(8);
*speed = (bcr & MG_BIT(13)) ? MG_PHY_SPEED_100M : MG_PHY_SPEED_10M;
} else if (id1 == MG_PHY_RTL82x) {
uint16_t id2 = phy->read_reg(phy_addr, MG_PHY_REG_ID2);
if (id2 == MG_PHY_RTL8211) {
uint16_t physr;
phy->write_reg(phy_addr, MG_PHY_RTL82x_REG_PAGESEL, 0xa43);
physr = phy->read_reg(phy_addr, MG_PHY_RTL8211_REG_PHYSR);
phy->write_reg(phy_addr, MG_PHY_RTL82x_REG_PAGESEL, 0);
*full_duplex = physr & MG_BIT(3);
*speed = (physr & MG_BIT(5)) ? MG_PHY_SPEED_1000M
: (physr & MG_BIT(4)) ? MG_PHY_SPEED_100M
: MG_PHY_SPEED_10M;
} else {
uint16_t bcr = phy->read_reg(phy_addr, MG_PHY_REG_BCR);
*full_duplex = bcr & MG_BIT(8);
*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;
+45 -21
View File
@@ -6,23 +6,41 @@
#include "pico/stdlib.h"
static struct mg_tcpip_if *s_ifp;
static uint32_t s_ip, s_mask;
static bool s_aplink = false, s_scanning = false;
static bool s_stalink = false, s_connecting = false;
static void wifi_cb(struct mg_tcpip_if *ifp, int ev, void *ev_data) {
struct mg_wifi_data *wifi =
&((struct mg_tcpip_driver_pico_w_data *) ifp->driver_data)->wifi;
if (wifi->apmode && ev == MG_TCPIP_EV_ST_CHG &&
*(uint8_t *) ev_data == MG_TCPIP_STATE_UP) {
MG_DEBUG(("Access Point started"));
s_ip = ifp->ip, ifp->ip = wifi->apip;
s_mask = ifp->mask, ifp->mask = wifi->apmask;
ifp->enable_dhcp_client = false;
ifp->enable_dhcp_server = true;
}
}
static bool mg_tcpip_driver_pico_w_init(struct mg_tcpip_if *ifp) {
struct mg_tcpip_driver_pico_w_data *d =
(struct mg_tcpip_driver_pico_w_data *) ifp->driver_data;
struct mg_wifi_data *wifi = &d->wifi;
s_ifp = ifp;
s_ip = ifp->ip;
s_mask = ifp->mask;
ifp->pfn = wifi_cb;
if (cyw43_arch_init() != 0)
return false; // initialize async_context and WiFi chip
if (d->apmode && d->apssid != NULL) {
MG_DEBUG(("Starting AP '%s' (%u)", d->apssid, d->apchannel));
if (!mg_wifi_ap_start(d->apssid, d->appass, d->apchannel)) return false;
if (wifi->apmode && wifi->apssid != NULL) {
if (!mg_wifi_ap_start(wifi)) return false;
cyw43_wifi_get_mac(&cyw43_state, CYW43_ITF_STA, ifp->mac); // same MAC
} else {
cyw43_arch_enable_sta_mode();
cyw43_wifi_get_mac(&cyw43_state, CYW43_ITF_STA, ifp->mac);
if (d->ssid != NULL) {
MG_DEBUG(("Connecting to '%s'", d->ssid));
return mg_wifi_connect(d->ssid, d->pass);
if (wifi->ssid != NULL) {
return mg_wifi_connect(wifi);
} else {
cyw43_arch_disable_sta_mode();
}
@@ -35,35 +53,33 @@ static size_t mg_tcpip_driver_pico_w_tx(const void *buf, size_t len,
struct mg_tcpip_driver_pico_w_data *d =
(struct mg_tcpip_driver_pico_w_data *) ifp->driver_data;
return cyw43_send_ethernet(&cyw43_state,
d->apmode ? CYW43_ITF_AP : CYW43_ITF_STA, len, buf,
false) == 0
d->wifi.apmode ? CYW43_ITF_AP : CYW43_ITF_STA, len,
buf, false) == 0
? len
: 0;
}
static bool s_aplink = false, s_scanning = false;
static bool s_stalink = false, s_connecting = false;
static bool mg_tcpip_driver_pico_w_poll(struct mg_tcpip_if *ifp, bool s1) {
cyw43_arch_poll(); // not necessary, except when IRQs are disabled (OTA)
if (s_scanning && !cyw43_wifi_scan_active(&cyw43_state)) {
MG_VERBOSE(("scan complete"));
s_scanning = 0;
mg_tcpip_call(s_ifp, MG_TCPIP_EV_WIFI_SCAN_END, NULL);
mg_tcpip_call(ifp, MG_TCPIP_EV_WIFI_SCAN_END, NULL);
}
if (ifp->update_mac_hash_table) {
// first call to _poll() is after _init(), so this is safe
cyw43_wifi_update_multicast_filter(&cyw43_state, (uint8_t *)mcast_addr, true);
cyw43_wifi_update_multicast_filter(&cyw43_state, (uint8_t *) mcast_addr,
true);
ifp->update_mac_hash_table = false;
}
if (!s1) return false;
struct mg_tcpip_driver_pico_w_data *d =
(struct mg_tcpip_driver_pico_w_data *) ifp->driver_data;
if (d->apmode) return s_aplink;
if (d->wifi.apmode) return s_aplink;
int sdkstate = cyw43_wifi_link_status(&cyw43_state, CYW43_ITF_STA);
MG_VERBOSE(("conn: %c state: %d", s_connecting ? '1' : '0', sdkstate));
if (sdkstate < 0 && s_connecting) {
mg_tcpip_call(s_ifp, MG_TCPIP_EV_WIFI_CONNECT_ERR, &sdkstate);
mg_tcpip_call(ifp, MG_TCPIP_EV_WIFI_CONNECT_ERR, &sdkstate);
s_connecting = false;
}
return s_stalink;
@@ -94,7 +110,7 @@ void cyw43_cb_tcpip_set_link_up(cyw43_t *self, int itf) {
}
void cyw43_cb_tcpip_set_link_down(cyw43_t *self, int itf) {
if (itf == CYW43_ITF_AP) {
s_aplink = false;
s_aplink = false;
} else {
s_stalink = false;
// SDK calls this before we check status, don't clear s_connecting here
@@ -134,9 +150,15 @@ bool mg_wifi_scan(void) {
return res;
}
bool mg_wifi_connect(char *ssid, char *pass) {
bool mg_wifi_connect(struct mg_wifi_data *wifi) {
s_ifp->ip = s_ip;
s_ifp->mask = s_mask;
if (s_ifp->ip == 0) s_ifp->enable_dhcp_client = true;
s_ifp->enable_dhcp_server = false;
cyw43_arch_enable_sta_mode();
int res = cyw43_arch_wifi_connect_async(ssid, pass, CYW43_AUTH_WPA2_AES_PSK);
MG_DEBUG(("Connecting to '%s'", wifi->ssid));
int res = cyw43_arch_wifi_connect_async(wifi->ssid, wifi->pass,
CYW43_AUTH_WPA2_AES_PSK);
MG_VERBOSE(("res: %d", res));
if (res == 0) s_connecting = true;
return (res == 0);
@@ -148,9 +170,11 @@ bool mg_wifi_disconnect(void) {
return true;
}
bool mg_wifi_ap_start(char *ssid, char *pass, unsigned int channel) {
cyw43_wifi_ap_set_channel(&cyw43_state, channel);
cyw43_arch_enable_ap_mode(ssid, pass, CYW43_AUTH_WPA2_AES_PSK);
bool mg_wifi_ap_start(struct mg_wifi_data *wifi) {
MG_DEBUG(("Starting AP '%s' (%u)", wifi->apssid, wifi->apchannel));
cyw43_wifi_ap_set_channel(&cyw43_state, wifi->apchannel);
cyw43_arch_enable_ap_mode(wifi->apssid, wifi->appass,
CYW43_AUTH_WPA2_AES_PSK);
return true;
}
+1 -8
View File
@@ -8,14 +8,7 @@
#include "pico/unique_id.h" // keep this include
struct mg_tcpip_driver_pico_w_data {
char *ssid;
char *pass;
char *apssid;
char *appass;
uint8_t security; // TBD
uint8_t apsecurity; // TBD
uint8_t apchannel;
bool apmode; // start in AP mode; 'false' starts connection to 'ssid' if not NULL
struct mg_wifi_data wifi;
};
#define MG_TCPIP_DRIVER_INIT(mgr) \
+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,
mg_ppp_up};
mg_ppp_poll};
#endif
+18 -13
View File
@@ -1,6 +1,8 @@
#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 {
volatile uint32_t ECMR, RESERVED, RFLR, RESERVED1, ECSR, RESERVED2, ECSIPR,
RESERVED3, PIR, RESERVED4, PSR, RESERVED5[5], RDMLR, RESERVED6[3], IPGR,
@@ -18,27 +20,30 @@ struct ra_edmac {
};
#undef ETHERC
#define ETHERC ((struct ra_etherc *) (uintptr_t) 0x40114100U)
#undef EDMAC
#define EDMAC ((struct ra_edmac *) (uintptr_t) 0x40114000U)
#undef RASYSC
#define RASYSC ((uint32_t *) (uintptr_t) 0x4001E000U)
#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)
#endif
#define ETH_PKT_SIZE 1536 // Max frame size, multiple of 32
#define ETH_DESC_CNT 4 // Descriptors count
// TODO(): handle these in a portable compiler-independent CMSIS-friendly way
#define MG_16BYTE_ALIGNED __attribute__((aligned((16U))))
#define MG_32BYTE_ALIGNED __attribute__((aligned((32U))))
// Descriptors: 16-byte aligned
// Buffers: 32-byte aligned (27.3.1)
static volatile uint32_t s_rxdesc[ETH_DESC_CNT][4] MG_16BYTE_ALIGNED;
static volatile uint32_t s_txdesc[ETH_DESC_CNT][4] MG_16BYTE_ALIGNED;
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_32BYTE_ALIGNED;
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_32BYTE_ALIGNED;
static volatile uint32_t s_rxdesc[ETH_DESC_CNT][4] MG_ETH_RAM MG_16BYTE_ALIGNED;
static volatile uint32_t s_txdesc[ETH_DESC_CNT][4] MG_ETH_RAM MG_16BYTE_ALIGNED;
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM MG_32BYTE_ALIGNED;
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM MG_32BYTE_ALIGNED;
static struct mg_tcpip_if *s_ifp; // MIP interface
// fastest is 3 cycles (SUB + BNE) on a 3-stage pipeline or equivalent
@@ -155,7 +160,7 @@ static bool mg_tcpip_driver_ra_init(struct mg_tcpip_if *ifp) {
MG_DEBUG(("PHY addr: %d, smispin: %d", d->phy_addr, s_smispin));
struct mg_phy phy = {raeth_read_phy, raeth_write_phy};
mg_phy_init(&phy, d->phy_addr, 0); // MAC clocks PHY
mg_phy_init(&phy, d->phy_addr, MG_PHY_CLOCKS_MAC);
// Select RMII mode,
ETHERC->ECMR = MG_BIT(2) | MG_BIT(1); // 100M, Full-duplex, CRC
+3 -1
View File
@@ -1,6 +1,8 @@
#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 {
// MDC clock "divider". MDC clock is software generated,
+5 -5
View File
@@ -26,17 +26,17 @@ struct ENET_Type {
CHANNEL_TCSR[4], CHANNEL_TCCR[4];
};
#undef ENET
#define ENET ((struct ENET_Type *) 0x40138000)
#define ETH_PKT_SIZE 1536 // Max frame size
#define ETH_DESC_CNT 4 // Descriptors count
#define ETH_DS 2 // Descriptor size (words)
#define MG_8BYTE_ALIGNED __attribute__((aligned((8U))))
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_8BYTE_ALIGNED;
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_8BYTE_ALIGNED;
static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS] MG_8BYTE_ALIGNED;
static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS] MG_8BYTE_ALIGNED;
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM MG_8BYTE_ALIGNED;
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM MG_8BYTE_ALIGNED;
static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS] MG_ETH_RAM MG_8BYTE_ALIGNED;
static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS] MG_ETH_RAM MG_8BYTE_ALIGNED;
static uint8_t s_txno; // Current TX descriptor
static uint8_t s_rxno; // Current RX descriptor
+100 -82
View File
@@ -3,7 +3,35 @@
#if MG_ENABLE_TCPIP && defined(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_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 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) {
GMAC_REGS->GMAC_MAN = GMAC_MAN_CLTTO_Msk |
GMAC_MAN_OP(2) | // Setting the read operation
GMAC_MAN_WTN(2) | GMAC_MAN_PHYA(addr) | // PHY address
GMAC_MAN_REGA(reg); // Setting the register
while (!(GMAC_REGS->GMAC_NSR & GMAC_NSR_IDLE_Msk)) (void) 0;
return GMAC_REGS->GMAC_MAN & GMAC_MAN_DATA_Msk; // Getting the read value
GMAC_REGS->GMAC_MAN = MG_BIT(30) | // Clause 22
MG_BIT(29) | // Setting the read operation
MG_BIT(17) | ((addr & 0x1f) << 23) | // PHY address
((reg & 0x1f) << 18); // Setting the register
while (!(GMAC_REGS->GMAC_NSR & MG_BIT(2))) (void) 0;
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) {
GMAC_REGS->GMAC_MAN = GMAC_MAN_CLTTO_Msk | GMAC_MAN_OP(1) | // Setting the write operation
GMAC_MAN_WTN(2) | GMAC_MAN_PHYA(addr) | // PHY address
GMAC_MAN_REGA(reg) | GMAC_MAN_DATA(val); // Setting the register
while (!(GMAC_REGS->GMAC_NSR & GMAC_NSR_IDLE_Msk)); // Waiting until the write op is complete
GMAC_REGS->GMAC_MAN = MG_BIT(30) |
MG_BIT(28) | // Setting the write operation
MG_BIT(17) | ((addr & 0x1f) << 23) | // PHY address
((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) {
return d->mdc_cr;
} else {
// get MCLK from GCLK_GENERATOR 0
uint32_t div = 512;
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);
if (div == 0) div = 1;
}
switch (GCLK_REGS->GCLK_GENCTRL[0] & GCLK_GENCTRL_SRC_Msk) {
case GCLK_GENCTRL_SRC_XOSC0_Val:
mclk = 32000000UL; /* 32MHz */
switch (GCLK_REGS->GCLK_GENCTRL[0] & 0xF) {
case 0: // GCLK_GENCTRL_SRC_XOSC0_Val
mclk = 32000000UL; // 32MHz
break;
case GCLK_GENCTRL_SRC_XOSC1_Val:
mclk = 32000000UL; /* 32MHz */
case 1: // GCLK_GENCTRL_SRC_XOSC1_Val
mclk = 32000000UL; // 32MHz
break;
case GCLK_GENCTRL_SRC_OSCULP32K_Val:
mclk = 32000UL;
case 4: // GCLK_GENCTRL_SRC_OSCULP32K_Val
mclk = 32000UL; // 32Khz
break;
case GCLK_GENCTRL_SRC_XOSC32K_Val:
mclk = 32000UL;
case 5: // GCLK_GENCTRL_SRC_XOSC32K_Val
mclk = 32000UL; // 32Khz
break;
case GCLK_GENCTRL_SRC_DFLL_Val:
mclk = 48000000UL; /* 48MHz */
case 6: // GCLK_GENCTRL_SRC_DFLL_Val
mclk = 48000000UL; // 48MHz
break;
case GCLK_GENCTRL_SRC_DPLL0_Val:
mclk = 200000000UL; /* 200MHz */
case 7: // GCLK_GENCTRL_SRC_DPLL0_Val:
mclk = 200000000UL; // 200MHz
break;
case GCLK_GENCTRL_SRC_DPLL1_Val:
mclk = 200000000UL; /* 200MHz */
case 8: // GCLK_GENCTRL_SRC_DPLL1_Val
mclk = 200000000UL; // 200MHz
break;
default:
mclk = 200000000UL; /* 200MHz */
mclk = 200000000UL; // 200MHz
}
mclk /= div;
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
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];
}
}
@@ -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;
s_ifp = ifp;
MCLK_REGS->MCLK_APBCMASK |= MCLK_APBCMASK_GMAC_Msk;
MCLK_REGS->MCLK_AHBMASK |= MCLK_AHBMASK_GMAC_Msk;
GMAC_REGS->GMAC_NCFGR = GMAC_NCFGR_CLK(get_clock_rate(d)); // Set MDC divider
GMAC_REGS->GMAC_NCR = 0; // Disable RX & TX
GMAC_REGS->GMAC_NCR |= GMAC_NCR_MPE_Msk; // Enable MDC & MDIO
GMAC_REGS->GMAC_NCFGR = get_clock_rate(d) << 18; // Set MDC divider
GMAC_REGS->GMAC_NCR = 0; // Disable RX & TX
GMAC_REGS->GMAC_NCR |= MG_BIT(4); // 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
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
GMAC_REGS->GMAC_DCFGR = GMAC_DCFGR_DRBS(0x18) // DMA recv buf 1536
| GMAC_DCFGR_RXBMS(GMAC_DCFGR_RXBMS_FULL_Val) |
GMAC_DCFGR_TXPBMS(1); // See #2487
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][1] = 0; // Clear status
GMAC_REGS->GMAC_DCFGR = (0x18 << 16) | // DMA recv buf 1536
(3 << 8) | // RXBMS
MG_BIT(10); // See #2487
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][1] = 0; // Clear status
}
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_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]);
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_NCFGR |= GMAC_NCFGR_MAXFS_Msk | GMAC_NCFGR_MTIHEN_Msk |
GMAC_NCFGR_EFRHD_Msk | GMAC_NCFGR_CAF_Msk;
GMAC_REGS->GMAC_TSR = GMAC_TSR_HRESP_Msk | GMAC_TSR_UND_Msk |
GMAC_TSR_TXCOMP_Msk | GMAC_TSR_TFC_Msk |
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_UR &= ~MG_BIT(0); // Disable MII, use RMII
GMAC_REGS->GMAC_NCFGR |= MG_BIT(8) | MG_BIT(6) | // MAXFX, MTIHEN
MG_BIT(25) | MG_BIT(4); // EFRHD, CAF
GMAC_REGS->GMAC_TSR = 0x17f; // all transmit statuses
GMAC_REGS->GMAC_RSR = 0xf; // all recv statuses
GMAC_REGS->GMAC_IDR = ~0U; // Disable interrupts, then enable required
GMAC_REGS->GMAC_IER = GMAC_IER_HRESP_Msk | GMAC_IER_ROVR_Msk |
GMAC_IER_TCOMP_Msk | GMAC_IER_TFC_Msk |
GMAC_IER_RLEX_Msk | GMAC_IER_TUR_Msk |
GMAC_IER_RXUBR_Msk | GMAC_IER_RCOMP_Msk;
GMAC_REGS->GMAC_NCR |= GMAC_NCR_TXEN_Msk | GMAC_NCR_RXEN_Msk;
NVIC_EnableIRQ(GMAC_IRQn);
GMAC_REGS->GMAC_IER = MG_BIT(11) | MG_BIT(10) | // HRESP, ROVR
MG_BIT(7) | MG_BIT(6) | // TCOMP, TFC
MG_BIT(5) | MG_BIT(4) | // RLEX, TUR
MG_BIT(2) | MG_BIT(1); // RXUBR, RCOMP
GMAC_REGS->GMAC_NCR |= MG_BIT(3) | MG_BIT(2); // TXEN, RXEN
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;
if (++s_txno >= ETH_DESC_CNT) s_txno = 0;
}
__DSB(); // Ensure descriptors have been written
GMAC_REGS->GMAC_NCR |= GMAC_NCR_TSTART_Msk; // Enable transmission
MG_DSB(); // Ensure descriptors have been written
GMAC_REGS->GMAC_NCR |= MG_BIT(9); // Enable transmission
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
// HRT register must be set
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;
}
@@ -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);
ifp->update_mac_hash_table = false;
}
bool up = false;
if (s1) {
uint16_t bsr = eth_read_phy(MG_PHY_ADDR, MG_PHYREG_BSR);
bool up = bsr & MG_PHYREGBIT_BSR_LINK_STATUS ? 1 : 0;
uint8_t speed = MG_PHY_SPEED_10M;
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 (ifp->state == MG_TCPIP_STATE_DOWN && up) {
uint16_t bcr = eth_read_phy(MG_PHY_ADDR, MG_PHYREG_BCR);
bool fd = bcr & MG_PHYREGBIT_BCR_DUPLEX_MODE ? 1 : 0;
bool spd = bcr & MG_PHYREGBIT_BCR_SPEED ? 1 : 0;
GMAC_REGS->GMAC_NCFGR = (GMAC_REGS->GMAC_NCFGR &
~(GMAC_NCFGR_SPD_Msk | MG_PHYREGBIT_BCR_SPEED)) |
GMAC_NCFGR_SPD(spd) | GMAC_NCFGR_FD(fd);
GMAC_REGS->GMAC_NCFGR =
(GMAC_REGS->GMAC_NCFGR & ~(MG_BIT(0) | MG_BIT(1))) | (speed & 1) |
(full_duplex << 1);
}
}
return false;
return up;
}
void GMAC_Handler(void);
@@ -203,8 +223,8 @@ void GMAC_Handler(void) {
uint32_t isr = GMAC_REGS->GMAC_ISR;
uint32_t rsr = GMAC_REGS->GMAC_RSR;
uint32_t tsr = GMAC_REGS->GMAC_TSR;
if (isr & GMAC_ISR_RCOMP_Msk) {
if (rsr & GMAC_ISR_RCOMP_Msk) {
if (isr & MG_BIT(1)) {
if (rsr & MG_BIT(1)) {
for (uint8_t i = 0; i < ETH_DESC_CNT; i++) {
if ((s_rxdesc[s_rxno][0] & MG_BIT(0)) == 0) break;
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 |
GMAC_TSR_TFC_Msk | GMAC_TSR_TXGO_Msk | GMAC_TSR_RLE_Msk |
GMAC_TSR_COL_Msk | GMAC_TSR_UBR_Msk)) != 0) {
if (tsr != 0) {
// 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);
}
+27 -5
View File
@@ -1,13 +1,35 @@
#pragma once
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_SAME54) && MG_ENABLE_DRIVER_SAME54
struct mg_tcpip_driver_same54_data {
int mdc_cr;
};
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_SAME54) && \
MG_ENABLE_DRIVER_SAME54
#ifndef MG_DRIVER_MDC_CR
#define MG_DRIVER_MDC_CR 5
#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
+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
+525
View File
@@ -0,0 +1,525 @@
#include "st67w6.h"
#include "net.h"
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_ST67W6) && \
MG_ENABLE_DRIVER_ST67W6
static struct mg_tcpip_if *s_ifp;
static uint32_t s_ip, s_mask;
static bool s_link = false, s_connecting = false;
static void wifi_cb(struct mg_tcpip_if *ifp, int ev, void *ev_data) {
struct mg_wifi_data *wifi =
&((struct mg_tcpip_driver_st67w6_data *) ifp->driver_data)->wifi;
if (wifi->apmode && ev == MG_TCPIP_EV_ST_CHG &&
*(uint8_t *) ev_data == MG_TCPIP_STATE_UP) {
MG_DEBUG(("Access Point started"));
s_ip = ifp->ip, ifp->ip = wifi->apip;
s_mask = ifp->mask, ifp->mask = wifi->apmask;
ifp->enable_dhcp_client = false;
ifp->enable_dhcp_server = true;
}
}
static bool st67w6_init(uint8_t *mac);
static void st67w6_poll(bool is_at);
static bool mg_tcpip_driver_st67w6_init(struct mg_tcpip_if *ifp) {
struct mg_tcpip_driver_st67w6_data *d =
(struct mg_tcpip_driver_st67w6_data *) ifp->driver_data;
struct mg_wifi_data *wifi = &d->wifi;
if (MG_BIG_ENDIAN) {
MG_ERROR(("Big-endian host"));
return false;
}
if (d->is_ready == NULL) return false;
s_ifp = ifp;
s_ip = ifp->ip;
s_mask = ifp->mask;
s_link = false;
ifp->pfn = wifi_cb;
if (!st67w6_init(ifp->mac)) return false;
if (d->send_queue.size == 0) d->send_queue.size = 8192;
d->send_queue.buf = (char *) mg_calloc(1, d->send_queue.size);
if (d->send_queue.buf == NULL) {
MG_ERROR(("OOM"));
return false;
}
if (wifi->apmode) {
return mg_wifi_ap_start(wifi);
} else if (wifi->ssid != NULL && wifi->pass != NULL) {
return mg_wifi_connect(wifi);
}
return true;
}
// Decouple; module access depends on it being RDY. See st67w6_poll()
size_t mg_tcpip_driver_st67w6_output(const void *buf, size_t len,
struct mg_tcpip_if *ifp) {
struct mg_tcpip_driver_st67w6_data *d =
(struct mg_tcpip_driver_st67w6_data *) ifp->driver_data;
char *p;
if (mg_queue_book(&d->send_queue, &p, len) < len) return 0;
memcpy(p, buf, len);
mg_queue_add(&d->send_queue, len);
return len;
}
static bool mg_tcpip_driver_st67w6_poll(struct mg_tcpip_if *ifp, bool s1) {
struct mg_tcpip_driver_st67w6_data *d =
(struct mg_tcpip_driver_st67w6_data *) ifp->driver_data;
if (d->is_ready == NULL) return false;
st67w6_poll(false);
if (!s1) return false;
return s_link;
}
struct mg_tcpip_driver mg_tcpip_driver_st67w6 = {
mg_tcpip_driver_st67w6_init, mg_tcpip_driver_st67w6_output, NULL,
mg_tcpip_driver_st67w6_poll};
// AT | STA | AP | HCI | OT
// --------------------------
// framing <-- includes rx stall indication
// --------------------------
// SPI <-- padded to 32-bit
//
// Transactions take place when the module signals RDY, 'tx' and 'write'
// functions actually just write to memory
// - AT: handles configuration and events (unsolicited +foo:). Responses may
// come as:
// - 1 frame: just OK or ERROR
// - 2 frames: 1 text line each, a response and OK
// - 3 frames: 2 text lines: 1 frame with text and no CR/LF, 1 frame with
// binary and CR/LF, 1 text line with OK
// - STA and AP contain plain Ethernet frames to/from the STA and AP networks,
// respectively
// - HCI: BLE stuff
// - OT: ?
#pragma pack(push, 1)
// little endian
struct spi_hdr {
uint16_t magic;
uint16_t len;
uint8_t vflags; // version :2, rx_stall :1, flags :5
uint8_t type;
uint16_t reserved;
};
#define ST67W6_SPI_TYPE_AT 0
#define ST67W6_SPI_TYPE_STA 1
#define ST67W6_SPI_TYPE_AP 2
#define ST67W6_SPI_TYPE_HCI 3
#define ST67W6_SPI_TYPE_OT 4
#pragma pack(pop)
static uint32_t txdata[2048 / 4], rxdata[2048 / 4];
static uint8_t at_resp[300];
static bool s_at_ok, s_at_err;
static size_t s_at_resp_len;
static void st67w6_handle_wifi_evnt(char *, size_t len);
static void st67w6_handle_scan_result(char *, size_t len);
static size_t st67w6_spi_poll(uint8_t *write, uint8_t *read);
static void st67w6_write(unsigned int f, void *data, uint16_t len);
static void st67w6_update_hash_table(void);
// High-level comm stuff
static void st67w6_poll(bool is_at) {
struct mg_tcpip_driver_st67w6_data *d =
(struct mg_tcpip_driver_st67w6_data *) s_ifp->driver_data;
struct spi_hdr *h = (struct spi_hdr *) rxdata;
unsigned int type;
uint8_t *txsource = (uint8_t *) txdata;
if (s_ifp->update_mac_hash_table) {
// first call to _poll() is after _init(), so this is safe
st67w6_update_hash_table();
s_ifp->update_mac_hash_table = false;
}
if (!is_at) { // send outstanding WLAN frames in the queue
char *buf;
size_t len;
// NOTE(): have traffic-dependent queues or queue traffic type with data
if ((len = mg_queue_next(&d->send_queue, &buf)) > 0) {
st67w6_write(d->wifi.apmode ? ST67W6_SPI_TYPE_AP : ST67W6_SPI_TYPE_STA,
buf, (uint16_t) len);
mg_queue_del(&d->send_queue, len);
} else { // nothing to send
txsource = NULL;
}
}
if (st67w6_spi_poll(txsource, (uint8_t *) rxdata) == 0) return;
if (h->len == 0) return;
type = h->type;
if (type == ST67W6_SPI_TYPE_AT) {
char *p = (char *) (h + 1);
size_t len = h->len;
if (len > 7 && strncmp(p, "+CWLAP:", 7) == 0) { // scan result
st67w6_handle_scan_result(p + 7, len - 7);
} else if (len > 4 && strncmp(p, "+CW:", 4) == 0) {
st67w6_handle_wifi_evnt(p + 4, len - 4);
} else {
MG_VERBOSE(("AT partial: %.*s", (int) len, p));
if (s_at_resp_len + len >= sizeof(at_resp))
s_at_resp_len = 0; // truncate response, error will be caught later
memcpy(at_resp + s_at_resp_len, p, len);
s_at_resp_len += len;
if (mg_match(mg_str_n((char *) at_resp, s_at_resp_len),
mg_str_n("*ERROR*", 7), NULL)) {
s_at_err = true;
} else if (mg_match(mg_str_n((char *) at_resp, s_at_resp_len),
mg_str_n("*OK*", 4), NULL)) {
s_at_ok = true;
}
}
} else if (type == ST67W6_SPI_TYPE_STA || type == ST67W6_SPI_TYPE_AP) {
// WLAN frame reception
mg_tcpip_qwrite(h + 1, h->len, s_ifp);
} // else silently discard
}
// WLAN event handling
// - Do not call any AT functions here, otherwise revise st67w6_at_wait()
// - The module likes to send ERROR along with other events
static void st67w6_handle_wifi_evnt(char *p, size_t len) {
struct mg_str data[2];
MG_VERBOSE(("event: %.*s", (int) len, p));
if (len > 9 && strncmp(p, "CONNECTED", 9) == 0) {
s_link = true;
s_connecting = false;
} else if (len > 12 && strncmp(p, "DISCONNECTED", 12) == 0) {
s_link = false;
s_connecting = false; // should not be needed
} else if (s_connecting && len > 6 &&
mg_match(mg_str_n(p, len), mg_str_n("ERROR,*\r\n*", 10), data)) {
size_t reason = 0;
bool ok = mg_to_size_t(data[0], &reason);
s_connecting = false;
MG_ERROR(("CONNECT FAILED"));
mg_tcpip_call(s_ifp, MG_TCPIP_EV_WIFI_CONNECT_ERR, ok ? &reason : NULL);
} else if (len > 9 && strncmp(p, "SCAN_DONE", 9) == 0) {
MG_VERBOSE(("scan complete"));
mg_tcpip_call(s_ifp, MG_TCPIP_EV_WIFI_SCAN_END, NULL);
} // else silently discard: CONNECTING; STA_CONNECTED,"MAC";
// STA_DISCONNECTED,"MAC"; DIST_STA_IP,"MAC","IP"
}
static bool st67w6_at_cmd(char *cmd, size_t len);
// Wi-Fi network stuff
static bool st67w6_wifi_connect(char *ssid, char *pass) {
char cmd[90]; // ssid + pass + AT
size_t cmd_len;
if (!st67w6_at_cmd("AT+CWMODE=1,0\r\n", 15)) return false;
cmd_len = mg_snprintf(cmd, sizeof(cmd), "AT+CWJAP=\"%s\",\"%s\",,0\r\n", ssid,
pass); // takes >700ms
if (!st67w6_at_cmd(cmd, cmd_len)) return false;
st67w6_at_cmd("AT+CWRECONNCFG=0,0\r\n", 20); // disregard error, connecting
s_connecting = true;
return true;
}
static bool st67w6_wifi_disconnect(void) {
s_connecting = false;
if (!st67w6_at_cmd("AT+CWQAP=0\r\n", 12)) return false; // takes >800ms
return st67w6_at_cmd("AT+CWMODE=0,0\r\n", 15); // takes >550ms
}
static bool st67w6_wifi_ap_start(char *ssid, char *pass, unsigned int channel) {
char cmd[90]; // ssid + pass + AT
size_t cmd_len;
if (!st67w6_at_cmd("AT+CWMODE=2,0\r\n", 15)) return false; // takes >800ms
cmd_len = mg_snprintf(
cmd, sizeof(cmd), "AT+CWSAP=\"%s\",\"%s\",%u,3,2,0\r\n", ssid, pass,
channel); // 3: WPA2_PSK; 2: max stations // takes >350ms
s_link = true;
return st67w6_at_cmd(cmd, cmd_len);
}
static bool st67w6_wifi_ap_stop(void) {
s_link = false;
return st67w6_at_cmd("AT+CWMODE=0,0\r\n", 15); // takes >550ms
}
// WLAN scan handling
// +CWLAP:(security,"SSID",RSSI,"BSSID",channel,cipher,proto,wps)\r\n
// security: OPEN, WEP, WPA, WPA2, WPA-WPA2, WPA-EAP, WPA3-SAE, WPA2-WPA3-SAE
// cipher: NONE, WEP, AES/CCMP, TKIP, TKIP and AES/CCMP
// proto: 4-bit bitmap AX,N,G,B; all set from right to left
static bool st67w6_wifi_scan(void) {
return st67w6_at_cmd("AT+CWLAPOPT=1,1695,-100,255,50\r\n", 32) &&
st67w6_at_cmd("AT+CWLAP=0,,,0\r\n", 16);
}
static void st67w6_handle_scan_result(char *data, size_t len) {
struct mg_wifi_scan_bss_data bss;
struct mg_str fields[2];
char mac[6];
uint8_t val;
unsigned int i;
MG_VERBOSE(("scan result event: %.*s", (int) len, data));
++data, --len; // skip '('
if (!mg_span(mg_str_n(data, len), &fields[0], &fields[1], ',') ||
!mg_str_to_num(fields[0], 10, &val, 1))
return;
bss.security =
(val == 0) ? MG_WIFI_SECURITY_OPEN : (uint8_t) MG_WIFI_SECURITY_WEP;
if (val == 2 || val == 4) bss.security |= MG_WIFI_SECURITY_WPA;
if (val == 3 || val == 4 || val == 7) bss.security |= MG_WIFI_SECURITY_WPA2;
if (val == 6 || val == 7) bss.security |= MG_WIFI_SECURITY_WPA3;
if (val == 5) bss.security |= MG_WIFI_SECURITY_WPA_ENTERPRISE;
if (!mg_span(fields[1], &fields[0], &fields[1], ',')) return;
bss.SSID.buf = fields[0].buf + 1, bss.SSID.len = fields[0].len - 2;
if (!mg_span(fields[1], &fields[0], &fields[1], ',')) return;
while (fields[0].buf[0] == ' ') ++fields[0].buf, --fields[0].len;
if (fields[0].buf[0] != '-') return; // positive RSSI would be great
++fields[0].buf, --fields[0].len;
if (!mg_str_to_num(fields[0], 10, &val, 1)) return;
bss.RSSI = (int8_t) - (int8_t) val;
if (!mg_span(fields[1], &fields[0], &fields[1], ',')) return;
if (fields[0].len < 19) return;
++fields[0].buf, --fields[0].len; // skip '"'
for (i = 0; i < 6; i++) {
struct mg_str str;
str.buf = fields[0].buf + 3 * i;
str.len = 2;
if (!mg_str_to_num(str, 16, &mac[i], 1)) return;
}
bss.BSSID = mac;
if (!mg_span(fields[1], &fields[0], &fields[1], ',') ||
!mg_str_to_num(fields[0], 10, &bss.channel, 1))
return;
if (!mg_span(fields[1], &fields[0], &fields[1], ',') ||
!mg_str_to_num(fields[0], 10, &val, 1))
return;
// ignore cypher
if (!mg_span(fields[1], &fields[0], &fields[1], ',') ||
!mg_str_to_num(fields[0], 10, &val, 1))
return;
bss.has_n = (val & 4) != 0;
bss.has_ax = (val & 8) != 0;
bss.band = MG_WIFI_BAND_2G; // NOT INFORMED with default options, no docs
MG_VERBOSE(("BSS: %.*s (%u) (%M) %d dBm %u", bss.SSID.len, bss.SSID.buf,
bss.channel, mg_print_mac, bss.BSSID, (int) bss.RSSI,
bss.security));
mg_tcpip_call(s_ifp, MG_TCPIP_EV_WIFI_SCAN_RESULT, &bss);
}
// AT stuff
static inline bool delayms(unsigned int ms) {
mg_delayms(ms);
return true;
}
// send AT command, wait for a response or timeout, meanwhile delivering
// received frames and events
static bool st67w6_at_cmd(char *cmd, size_t len) {
bool is_at = true;
unsigned int times = 1000;
s_at_resp_len = 0;
st67w6_write(ST67W6_SPI_TYPE_AT, cmd, (uint16_t) len);
s_at_ok = false, s_at_err = false;
do { // AT response processing does not call any other AT function
st67w6_poll(is_at); // otherwise we can't allow them to pile up here
is_at = false; // avoid repeating, allow queued WLAN frames to be sent
// network frames will be pushed to the queue so that is safe
} while (!s_at_ok && !s_at_err && times-- > 0 && delayms(1));
MG_VERBOSE(("AT response:\n%.*s", s_at_resp_len, at_resp));
MG_VERBOSE(("ok: %c, err: %c, times: %d", s_at_ok ? '1' : '0',
s_at_err ? '1' : '0', (int) times));
return s_at_ok;
}
static bool st67w6_spi_init(void);
bool mg_to_size_t(struct mg_str str, size_t *val);
static bool st67w6_init(uint8_t *mac) {
// struct mg_tcpip_driver_st67w6_data *d = (struct
// mg_tcpip_driver_st67w6_data *) s_ifp->driver_data;
struct mg_str data[3];
size_t val;
bool is_b = false;
if (!st67w6_spi_init()) return false;
if (!st67w6_at_cmd("AT\r\n", 4)) return false;
if (!st67w6_at_cmd("AT+CWNETMODE?\r\n", 15) ||
!mg_match(mg_str_n((char *) at_resp, s_at_resp_len),
mg_str_n("*:*\r\n*", 6), data) ||
!mg_to_size_t(data[1], &val))
return false;
if (val != 0) {
MG_ERROR(("Wrong firmware, T02 is needed"));
return false;
}
// set clock, who cares ???
if (!st67w6_at_cmd("AT+GET_CLOCK\r\n", 14)) return false;
MG_DEBUG(("%.*s", s_at_resp_len, at_resp)); // TODO(scaprile): --> VERBOSE
// BT-ENABLED DEPENDENCY
// MODULE DEPENDENCY
if (!st67w6_at_cmd("AT+EFUSE-R=24,\"0x100\"\r\n", 23) ||
!mg_match(mg_str_n((char *) at_resp, s_at_resp_len), mg_str_n("*,*", 3),
data))
return false;
if (data[1].buf[0] == 'C' && data[1].buf[1] == '6') is_b = true;
MG_DEBUG(("WLAN module is %sB type", is_b ? "" : "not")); // --> VERBOSE
if (is_b) {
// Disable the antenna diversity pin
if (!st67w6_at_cmd("AT+IORST=0\r\n", 12)) return false;
// Apparently they intend to disable some antenna ...
if (!st67w6_at_cmd("AT+CWANTENABLE?\r\n", 17)) return false;
MG_DEBUG(("%.*s", s_at_resp_len, at_resp)); // --> VERBOSE
}
// Do not set wake-up pin (AT+SLWKIO)
// Disable power save mode
// NOTE(scaprile): (no response if in hibernate mode, though I guess we
// wouldn't have reached this point in that case either)
if (!st67w6_at_cmd("AT+PWR=0\r\n", 12)) return false;
// set Wi-Fi
// set country code
if (!st67w6_at_cmd("AT+CWCOUNTRY=0,\"00\"\r\n", 21)) return false;
#if 0
// set DTIM
if (!st67w6_at_cmd("AT+SLWKDTIM=1\r\n", 15)) return false;
#endif
// Read only default MAC, ignore set bit count (data[6] & 0x3F). Custom MACs
// reside at @0x64 and 0x70
if (st67w6_at_cmd("AT+EFUSE-R=7,\"0x014\"\r\n", 22) &&
mg_match(mg_str_n((char *) at_resp, s_at_resp_len), mg_str_n("*,*", 3),
data)) {
int i;
for (i = 0; i < 6; i++) mac[i] = data[1].buf[5 - i];
MG_DEBUG(("MAC: %M", mg_print_mac, mac));
} else {
MG_ERROR(("read MAC failed"));
}
return true;
}
static void st67w6_update_hash_table(void) {
// TODO(): read database, rebuild hash table
// uint32_t val = 0;
// val = 1;
// st67w6_at_iovar_set2_(0, "mcast_list", (uint8_t *) &val, sizeof(val),
// (uint8_t *) mcast_addr, sizeof(mcast_addr)); mg_delayms(50);
}
// SPI specifics
#define ST67W6_SPI_MAGIC 0x55AA
// #define ST67W6_SPI_VERSION(x), IS_STALL, FLAGS(x), ...
static const uint8_t idlehdr[sizeof(struct spi_hdr)] = {0xaa, 0x55, 0, 0,
0, 0, 0, 0};
static void st67w6_write(unsigned int f, void *data, uint16_t len) {
struct spi_hdr *h = (struct spi_hdr *) txdata;
h->magic = ST67W6_SPI_MAGIC;
h->type = (uint8_t) f;
h->vflags = 0;
h->len = len;
h->reserved = 0;
memmove(h + 1, data, len);
}
static size_t st67w6_spi_poll(uint8_t *write, uint8_t *read) {
struct mg_tcpip_driver_st67w6_data *d =
(struct mg_tcpip_driver_st67w6_data *) s_ifp->driver_data;
struct spi_hdr *th, *rh = (struct spi_hdr *) read;
struct mg_tcpip_spi_ *s = (struct mg_tcpip_spi_ *) d->spi;
size_t padded;
unsigned int times;
th = (write != NULL) ? (struct spi_hdr *) write : (struct spi_hdr *) idlehdr;
s->begin(s->spi);
times = 50;
while (times--) {
if (d->is_ready()) break;
if (times == 0) {
MG_ERROR(("RDY TIMEOUT"));
s->end(s->spi);
return 0;
}
mg_delayms(1);
}
padded = (th->len + 3) & ~3;
s->txn(s->spi, (uint8_t *) th, (uint8_t *) rh, sizeof(*th) + padded);
if (rh->magic == ST67W6_SPI_MAGIC && rh->len > padded) {
size_t remaining_padded = (rh->len - padded + 3) & ~3;
if (remaining_padded > (2048 - sizeof(*rh) - padded))
remaining_padded = 2048 - sizeof(*rh) - padded;
s->txn(s->spi, NULL, read + sizeof(*rh) + padded, remaining_padded);
}
times = 50;
while (times--) {
if (!d->is_ready()) break;
if (times == 0) {
MG_ERROR(("!RDY TIMEOUT"));
break;
}
mg_delayms(1);
}
s->end(s->spi);
return (size_t) rh->len;
}
static bool st67w6_spi_init(void) {
struct mg_tcpip_driver_st67w6_data *d =
(struct mg_tcpip_driver_st67w6_data *) s_ifp->driver_data;
size_t len;
unsigned int times = 1000;
while (times--) {
if (d->is_ready()) break;
if (times == 0) return false;
mg_delayms(1);
}
if (((len = st67w6_spi_poll(NULL, (uint8_t *) rxdata)) == 0) ||
!mg_match(mg_str_n(((char *) rxdata) + sizeof(struct spi_hdr), len),
mg_str_n("*ready*", 7), NULL))
return false;
return true;
}
// Mongoose Wi-Fi API functions
bool mg_wifi_scan(void) {
return st67w6_wifi_scan();
}
bool mg_wifi_connect(struct mg_wifi_data *wifi) {
s_ifp->ip = s_ip;
s_ifp->mask = s_mask;
if (s_ifp->ip == 0) s_ifp->enable_dhcp_client = true;
s_ifp->enable_dhcp_server = false;
MG_DEBUG(("Connecting to '%s'", wifi->ssid));
return st67w6_wifi_connect(wifi->ssid, wifi->pass);
}
bool mg_wifi_disconnect(void) {
return st67w6_wifi_disconnect();
}
bool mg_wifi_ap_start(struct mg_wifi_data *wifi) {
MG_DEBUG(("Starting AP '%s' (%u)", wifi->apssid, wifi->apchannel));
return st67w6_wifi_ap_start(wifi->apssid, wifi->appass, wifi->apchannel);
}
bool mg_wifi_ap_stop(void) {
return st67w6_wifi_ap_stop();
}
#endif
+37
View File
@@ -0,0 +1,37 @@
#pragma once
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_ST67W6) && \
MG_ENABLE_DRIVER_ST67W6
struct mg_tcpip_spi_ {
void *spi; // Opaque SPI bus descriptor
void (*begin)(void *); // SPI begin: slave select low
void (*end)(void *); // SPI end: slave select high
void (*txn)(void *, uint8_t *, uint8_t *,
size_t len); // SPI transaction: write-read len bytes
};
struct mg_tcpip_driver_st67w6_data {
struct mg_wifi_data wifi;
void *spi;
bool (*is_ready)(void); // return state of module RDY pin
struct mg_queue send_queue; // decouple tx calls from module polls
};
#define MG_TCPIP_DRIVER_INIT(mgr) \
do { \
static struct mg_tcpip_driver_st67w6_data driver_data_; \
static struct mg_tcpip_if mif_; \
MG_SET_WIFI_CONFIG(&driver_data_); \
mif_.ip = MG_TCPIP_IP; \
mif_.mask = MG_TCPIP_MASK; \
mif_.gw = MG_TCPIP_GW; \
mif_.driver = &mg_tcpip_driver_st67w6; \
mif_.driver_data = &driver_data_; \
mif_.recv_queue.size = 8192; \
mif_.mac[0] = 2; /* MAC read from OTP at driver init */ \
mg_tcpip_init(mgr, &mif_); \
MG_INFO(("Driver: st67w6, MAC: %M", mg_print_mac, mif_.mac)); \
} while (0)
#endif
+4 -4
View File
@@ -22,10 +22,10 @@ struct stm32f_eth {
#define ETH_DESC_CNT 4 // Descriptors count
#define ETH_DS 4 // Descriptor size (words)
static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]; // RX descriptors
static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // RX ethernet buffers
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // TX ethernet buffers
static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS] MG_ETH_RAM; // RX descriptors
static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS] MG_ETH_RAM; // TX descriptors
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM; // RX ethernet buffers
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM; // TX ethernet buffers
static uint8_t s_txno; // Current TX descriptor
static uint8_t s_rxno; // Current RX descriptor
+7
View File
@@ -28,6 +28,12 @@ struct mg_tcpip_driver_stm32f_data {
#define MG_DRIVER_MDC_CR 4
#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) \
do { \
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_data = &driver_data_; \
MG_SET_MAC_ADDRESS(mif_.mac); \
MG_ENABLE_ETH_IRQ(); \
mg_tcpip_init(mgr, &mif_); \
MG_INFO(("Driver: stm32f, MAC: %M", mg_print_mac, mif_.mac)); \
} while (0)
+123 -23
View File
@@ -1,9 +1,28 @@
#include "net_builtin.h"
#if MG_ENABLE_TCPIP && (MG_ENABLE_DRIVER_STM32H || MG_ENABLE_DRIVER_MCXN)
#if MG_ENABLE_TCPIP && (MG_ENABLE_DRIVER_STM32H || MG_ENABLE_DRIVER_MCXN || \
MG_ENABLE_DRIVER_STM32N)
// STM32H: vendor modded single-queue Synopsys v4.2
// STM32N: dual-queue GbE Synopsys v5.2 with no hash table option, 64-bit AXI
// MCXNx4x: dual-queue Synopsys v5.2 with no hash table option
// RT1170 ENET_QOS: quad-queue Synopsys v5.1
// RT1170: ENET_QOS: quad-queue Synopsys v5.1
#if MG_ENABLE_DRIVER_STM32H
#define SYNOPSYS_ENET_V5 0
#define SYNOPSYS_ENET_SINGLEQ 1
#define SYNOPSYS_ENET_NOHASHTABLE 0
#define SYNOPSYS_ENET_GbE 0
#elif MG_ENABLE_DRIVER_STM32N
#define SYNOPSYS_ENET_V5 1
#define SYNOPSYS_ENET_SINGLEQ 0
#define SYNOPSYS_ENET_NOHASHTABLE 1
#define SYNOPSYS_ENET_GbE 1
#elif MG_ENABLE_DRIVER_MCXN
#define SYNOPSYS_ENET_V5 1
#define SYNOPSYS_ENET_SINGLEQ 0
#define SYNOPSYS_ENET_NOHASHTABLE 1
#define SYNOPSYS_ENET_GbE 0
#endif
struct synopsys_enet_qos {
volatile uint32_t MACCR, MACECR, MACPFR, MACWTR, MACHT0R, MACHT1R,
RESERVED1[14], MACVTR, RESERVED2, MACVHTR, RESERVED3, MACVIR, MACIVIR,
@@ -36,9 +55,9 @@ struct synopsys_enet_qos {
};
#undef ETH
#if MG_ENABLE_DRIVER_STM32H
#define ETH \
((struct synopsys_enet_qos *) (uintptr_t) (0x40000000UL + 0x00020000UL + \
0x8000UL))
#define ETH ((struct synopsys_enet_qos *) (uintptr_t) 0x40028000UL)
#elif MG_ENABLE_DRIVER_STM32N
#define ETH ((struct synopsys_enet_qos *) (uintptr_t) 0x48036000UL)
#elif MG_ENABLE_DRIVER_MCXN
#define ETH ((struct synopsys_enet_qos *) (uintptr_t) 0x40100000UL)
#endif
@@ -47,11 +66,74 @@ struct synopsys_enet_qos {
#define ETH_DESC_CNT 4 // Descriptors count
#define ETH_DS 4 // Descriptor size (words)
static volatile uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]; // RX descriptors
static volatile uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // RX ethernet buffers
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // TX ethernet buffers
static struct mg_tcpip_if *s_ifp; // MIP interface
#if MG_ENABLE_DRIVER_STM32H || MG_ENABLE_DRIVER_STM32N
#define CACHE_LINESZ 32 // must be a whole number of (d)words (see DESC_SZW)
#ifndef SCB
struct m7_scb {
volatile uint32_t CPUID, RESERVED1[4], CCR, RESERVED2[145], DCIMVAC, DCISW,
DCCMVAU, DCCMVAC, DCCSW, DCCIMVAC, DCCISW, RESERVED3[10], CACR,
RESERVED4[3];
};
#define SCB ((struct m7_scb *) (uintptr_t) 0xE000ED00UL)
#endif
// ending ISB is not needed because we don't cache instructions in data space
static inline void MG_CACHE_INVAL(uint8_t *addr, int32_t len) {
#if MG_ENABLE_DRIVER_STM32H
if ((SCB->CPUID & 0xfff0) != 0xc270) return; // not a Cortex-M7 => not an H7
#endif
if ((SCB->CCR & MG_BIT(16)) == 0) return; // cache not enabled
MG_DSB();
while (len > 0) {
SCB->DCIMVAC = (uint32_t) addr;
addr += CACHE_LINESZ;
len -= CACHE_LINESZ;
}
MG_DSB();
}
static inline void MG_CACHE_FLUSH(uint8_t *addr, int32_t len) {
#if MG_ENABLE_DRIVER_STM32H
if ((SCB->CPUID & 0xfff0) != 0xc270) return; // not a Cortex-M7 => not an H7
#endif
if ((SCB->CCR & MG_BIT(16)) == 0) return; // cache not enabled
MG_DSB();
while (len > 0) {
SCB->DCCMVAC = (uint32_t) addr;
addr += CACHE_LINESZ;
len -= CACHE_LINESZ;
}
MG_DSB();
}
#define ETH_RAM_ALIGNED MG_32BYTE_ALIGNED // depends on CACHE_LINESZ and ETH
#define CACHE_ALIGN(x) \
((((size_t) (x)) + CACHE_LINESZ - 1) & ~(CACHE_LINESZ - 1))
#define DESC_SZ CACHE_ALIGN(4 * ETH_DS) // grow descriptors to fit a line
#define DESC_SZW (DESC_SZ / 4)
#define BUFF_SZ CACHE_ALIGN(ETH_PKT_SIZE) // grow buffers to fit n lines
#if MG_ENABLE_DRIVER_STM32H
#define DESC_SKIPW (DESC_SZW - ETH_DS) // tell DMA the descriptor size, words
#else
// MG_ENABLE_DRIVER_STM32N, DMA is AXI and specs skip in 64-bit double-words
#define DESC_SKIPW ((DESC_SZW - ETH_DS) / 2)
#endif
#else
#define MG_CACHE_FLUSH(a, b)
#define MG_CACHE_INVAL(a, b)
#define ETH_RAM_ALIGNED MG_8BYTE_ALIGNED // depends on ETH DMA alone
#define DESC_SZ 0
#define DESC_SZW ETH_DS
#define BUFF_SZ ETH_PKT_SIZE
#define DESC_SKIPW 0 // no need to skip, as we're not aligning to cache lines
#endif
// array[rows][cols] = coldata coldata ... for all rows, keeps alignment
static volatile uint32_t s_rxdesc[ETH_DESC_CNT][DESC_SZW] MG_ETH_RAM
ETH_RAM_ALIGNED;
static volatile uint32_t s_txdesc[ETH_DESC_CNT][DESC_SZW] MG_ETH_RAM
ETH_RAM_ALIGNED;
static uint8_t s_rxbuf[ETH_DESC_CNT][BUFF_SZ] MG_ETH_RAM ETH_RAM_ALIGNED;
static uint8_t s_txbuf[ETH_DESC_CNT][BUFF_SZ] MG_ETH_RAM ETH_RAM_ALIGNED;
static struct mg_tcpip_if *s_ifp; // MIP interface
static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) {
ETH->MACMDIOAR &= (0xF << 8);
@@ -77,15 +159,19 @@ static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) {
uint8_t phy_conf = d == NULL ? MG_PHY_CLOCKS_MAC : d->phy_conf;
// Init RX descriptors
memset((char *) s_rxdesc, 0, sizeof(s_rxdesc)); // manual init
for (int i = 0; i < ETH_DESC_CNT; i++) {
s_rxdesc[i][0] = (uint32_t) (uintptr_t) s_rxbuf[i]; // Point to data buffer
s_rxdesc[i][3] = MG_BIT(31) | MG_BIT(30) | MG_BIT(24); // OWN, IOC, BUF1V
}
MG_CACHE_FLUSH((uint8_t *) s_rxdesc, sizeof(s_rxdesc));
// Init TX descriptors
memset((char *) s_txdesc, 0, sizeof(s_txdesc)); // manual init
for (int i = 0; i < ETH_DESC_CNT; i++) {
s_txdesc[i][0] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer
}
MG_CACHE_FLUSH((uint8_t *) s_txdesc, sizeof(s_txdesc));
ETH->DMAMR |= MG_BIT(0); // Software reset
for (int i = 0; i < 4; i++)
@@ -102,7 +188,7 @@ static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) {
ETH->DMASBMR |= MG_BIT(12); // AAL NOTE(scaprile): is this actually needed
ETH->MACIER = 0; // Do not enable additional irq sources (reset value)
ETH->MACTFCR = MG_BIT(7); // Disable zero-quanta pause
#if !MG_ENABLE_DRIVER_MCXN
#if !SYNOPSYS_ENET_V5
ETH->MACPFR = MG_BIT(10); // Perfect filtering
#endif
struct mg_phy phy = {eth_read_phy, eth_write_phy};
@@ -118,15 +204,15 @@ static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) {
ETH->DMACTDRLR = ETH_DESC_CNT - 1; // ring length
ETH->DMACTDTPR =
(uint32_t) (uintptr_t) s_txdesc; // first available descriptor address
ETH->DMACCR = 0; // DSL = 0 (contiguous descriptor table) (reset value)
#if !MG_ENABLE_DRIVER_STM32H
ETH->DMACCR = DESC_SKIPW << 18; // DSL (contiguous/sparse descriptor table)
#if SYNOPSYS_ENET_V5
MG_SET_BITS(ETH->DMACTCR, 0x3F << 16, MG_BIT(16));
MG_SET_BITS(ETH->DMACRCR, 0x3F << 16, MG_BIT(16));
#endif
ETH->DMACIER = MG_BIT(6) | MG_BIT(15); // RIE, NIE
ETH->MACCR = MG_BIT(0) | MG_BIT(1) | MG_BIT(13) | MG_BIT(14) |
MG_BIT(15); // RE, TE, Duplex, Fast, Reserved
#if MG_ENABLE_DRIVER_STM32H
MG_BIT(15); // RE, TE, Duplex, Fast, (10/100)/Reserved
#if SYNOPSYS_ENET_SINGLEQ
ETH->MTLTQOMR |= MG_BIT(1); // TSF
ETH->MTLRQOMR |= MG_BIT(5); // RSF
#else
@@ -150,18 +236,23 @@ static size_t mg_tcpip_driver_stm32h_tx(const void *buf, size_t len,
struct mg_tcpip_if *ifp) {
if (len > sizeof(s_txbuf[s_txno])) {
MG_ERROR(("Frame too big, %ld", (long) len));
len = 0; // Frame is too big
} else if ((s_txdesc[s_txno][3] & MG_BIT(31))) {
return 0; // Frame is too big
}
MG_CACHE_INVAL((uint8_t *) &s_txdesc[s_txno], DESC_SZ);
if ((s_txdesc[s_txno][3] & MG_BIT(31))) {
ifp->nerr++;
MG_ERROR(("No free descriptors: %u %08X %08X %08X", s_txno,
s_txdesc[s_txno][3], ETH->DMACSR, ETH->DMACTCR));
MG_CACHE_INVAL((uint8_t *) s_txdesc, sizeof(s_txdesc));
for (int i = 0; i < ETH_DESC_CNT; i++) MG_ERROR(("%08X", s_txdesc[i][3]));
len = 0; // All descriptors are busy, fail
} else {
memcpy(s_txbuf[s_txno], buf, len); // Copy data
memcpy(s_txbuf[s_txno], buf, len); // Copy data
MG_CACHE_FLUSH((uint8_t *) &s_txbuf[s_txno], BUFF_SZ);
s_txdesc[s_txno][2] = (uint32_t) len; // Set data len
s_txdesc[s_txno][3] = MG_BIT(28) | MG_BIT(29); // FD, LD
s_txdesc[s_txno][3] |= MG_BIT(31); // Set OWN bit - let DMA take over
MG_CACHE_FLUSH((uint8_t *) &s_txdesc[s_txno], DESC_SZ);
if (++s_txno >= ETH_DESC_CNT) s_txno = 0;
}
ETH->DMACSR |= MG_BIT(2) | MG_BIT(1); // Clear any prior TBU, TPS
@@ -171,7 +262,7 @@ static size_t mg_tcpip_driver_stm32h_tx(const void *buf, size_t len,
}
static void mg_tcpip_driver_stm32h_update_hash_table(struct mg_tcpip_if *ifp) {
#if MG_ENABLE_DRIVER_MCXN
#if SYNOPSYS_ENET_NOHASHTABLE
ETH->MACPFR = MG_BIT(4); // Pass Multicast (pass all multicast frames)
#else
// TODO(): read database, rebuild hash table
@@ -182,7 +273,7 @@ static void mg_tcpip_driver_stm32h_update_hash_table(struct mg_tcpip_if *ifp) {
ETH->MACA1HR = (uint32_t) mcast_addr[5] << 8 | (uint32_t) mcast_addr[4];
ETH->MACA1HR |= MG_BIT(31); // AE
#endif
(void) ifp;
(void) ifp;
}
static bool mg_tcpip_driver_stm32h_poll(struct mg_tcpip_if *ifp, bool s1) {
@@ -203,8 +294,11 @@ static bool mg_tcpip_driver_stm32h_poll(struct mg_tcpip_if *ifp, bool s1) {
// if(link is slow or half) set flags otherwise
// reg = tmp
uint32_t maccr = ETH->MACCR | MG_BIT(14) | MG_BIT(13); // 100M, Full-duplex
if (speed == MG_PHY_SPEED_10M) maccr &= ~MG_BIT(14); // 10M
if (full_duplex == false) maccr &= ~MG_BIT(13); // Half-duplex
#if SYNOPSYS_ENET_GbE
if (speed == MG_PHY_SPEED_1000M) maccr &= ~MG_BIT(15); // 1000M
#endif
if (speed == MG_PHY_SPEED_10M) maccr &= ~MG_BIT(14); // 10M
if (full_duplex == false) maccr &= ~MG_BIT(13); // Half-duplex
ETH->MACCR = maccr; // IRQ handler does not fiddle with this register
MG_DEBUG(("Link is %uM %s-duplex", maccr & MG_BIT(14) ? 100 : 10,
maccr & MG_BIT(13) ? "full" : "half"));
@@ -216,13 +310,17 @@ static uint32_t s_rxno;
#if MG_ENABLE_DRIVER_MCXN
void ETHERNET_IRQHandler(void);
void ETHERNET_IRQHandler(void) {
#else
#elif MG_ENABLE_DRIVER_STM32H
void ETH_IRQHandler(void);
void ETH_IRQHandler(void) {
#else
void ETH1_IRQHandler(void);
void ETH1_IRQHandler(void) {
#endif
if (ETH->DMACSR & MG_BIT(6)) { // Frame received, loop
ETH->DMACSR = MG_BIT(15) | MG_BIT(6); // Clear flag
for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever
MG_CACHE_INVAL((uint8_t *) &s_rxdesc[s_rxno], DESC_SZ);
if (s_rxdesc[s_rxno][3] & MG_BIT(31)) break; // exit when done
if (((s_rxdesc[s_rxno][3] & (MG_BIT(28) | MG_BIT(29))) ==
(MG_BIT(28) | MG_BIT(29))) &&
@@ -230,10 +328,12 @@ void ETH_IRQHandler(void) {
uint32_t len = s_rxdesc[s_rxno][3] & (MG_BIT(15) - 1);
// MG_DEBUG(("%lx %lu %lx %08lx", s_rxno, len, s_rxdesc[s_rxno][3],
// ETH->DMACSR));
MG_CACHE_INVAL((uint8_t *) &s_rxbuf[s_rxno], BUFF_SZ);
mg_tcpip_qwrite(s_rxbuf[s_rxno], len > 4 ? len - 4 : len, s_ifp);
}
s_rxdesc[s_rxno][3] =
MG_BIT(31) | MG_BIT(30) | MG_BIT(24); // OWN, IOC, BUF1V
MG_CACHE_FLUSH((uint8_t *) &s_rxdesc[s_rxno], DESC_SZ);
if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0;
}
}
+24 -1
View File
@@ -7,7 +7,10 @@
#if !defined(MG_ENABLE_DRIVER_MCXN)
#define MG_ENABLE_DRIVER_MCXN 0
#endif
#if MG_ENABLE_DRIVER_STM32H || MG_ENABLE_DRIVER_MCXN
#if !defined(MG_ENABLE_DRIVER_STM32N)
#define MG_ENABLE_DRIVER_STM32N 0
#endif
#if MG_ENABLE_DRIVER_STM32H || MG_ENABLE_DRIVER_MCXN || MG_ENABLE_DRIVER_STM32N
struct mg_tcpip_driver_stm32h_data {
// MDC clock divider. MDC clock is derived from HCLK, must not exceed 2.5MHz
@@ -40,6 +43,24 @@ struct mg_tcpip_driver_stm32h_data {
#define MG_DRIVER_MDC_CR 4
#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
#if MG_ENABLE_IPV6
#define MG_IPV6_INIT(mif) \
do { \
memcpy(mif.ip6ll, (uint8_t[16]) MG_TCPIP_IPV6_LINKLOCAL, 16); \
memcpy(mif.ip6, (uint8_t[16]) MG_TCPIP_GLOBAL, 16); \
memcpy(mif.gw6, (uint8_t[16]) MG_TCPIP_GW6, 16); \
mif.prefix_len = MG_TCPIP_PREFIX_LEN; \
} while(0)
#else
#define MG_IPV6_INIT(mif)
#endif
#define MG_TCPIP_DRIVER_INIT(mgr) \
do { \
static struct mg_tcpip_driver_stm32h_data driver_data_; \
@@ -53,7 +74,9 @@ struct mg_tcpip_driver_stm32h_data {
mif_.driver = &mg_tcpip_driver_stm32h; \
mif_.driver_data = &driver_data_; \
MG_SET_MAC_ADDRESS(mif_.mac); \
MG_IPV6_INIT(mif_); \
mg_tcpip_init(mgr, &mif_); \
MG_ENABLE_ETH_IRQ(); \
MG_INFO(("Driver: stm32h, MAC: %M", mg_print_mac, mif_.mac)); \
} while (0)
+7 -6
View File
@@ -111,11 +111,11 @@ static int guess_mdc_cr(void) {
uint8_t crs[] = {2, 3, 0, 1}; // EMAC->MACMIIAR::CR values
uint8_t div[] = {16, 26, 42, 62}; // Respective HCLK dividers
uint32_t sysclk = get_sysclk(); // Guess system SYSCLK
int result = -1; // Invalid CR value
int i, result = -1; // Invalid CR value
if (sysclk < 25000000) {
MG_ERROR(("SYSCLK too low"));
} else {
for (int i = 0; i < 4; i++) {
for (i = 0; i < 4; i++) {
if (sysclk / div[i] <= 2375000UL /* 2.5MHz - 5% */) {
result = crs[i];
break;
@@ -130,10 +130,11 @@ static int guess_mdc_cr(void) {
static bool mg_tcpip_driver_tm4c_init(struct mg_tcpip_if *ifp) {
struct mg_tcpip_driver_tm4c_data *d =
(struct mg_tcpip_driver_tm4c_data *) ifp->driver_data;
int i;
s_ifp = ifp;
// Init RX descriptors
for (int i = 0; i < ETH_DESC_CNT; i++) {
for (i = 0; i < ETH_DESC_CNT; i++) {
s_rxdesc[i][0] = MG_BIT(31); // Own
s_rxdesc[i][1] = sizeof(s_rxbuf[i]) | MG_BIT(14); // 2nd address chained
s_rxdesc[i][2] = (uint32_t) (uintptr_t) s_rxbuf[i]; // Point to data buffer
@@ -143,7 +144,7 @@ static bool mg_tcpip_driver_tm4c_init(struct mg_tcpip_if *ifp) {
}
// Init TX descriptors
for (int i = 0; i < ETH_DESC_CNT; i++) {
for (i = 0; i < ETH_DESC_CNT; i++) {
s_txdesc[i][2] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer
s_txdesc[i][3] =
(uint32_t) (uintptr_t) s_txdesc[(i + 1) % ETH_DESC_CNT]; // Chain
@@ -204,7 +205,6 @@ static size_t mg_tcpip_driver_tm4c_tx(const void *buf, size_t len,
EMAC->EMACDMARIS = MG_BIT(2) | MG_BIT(5); // Clear any prior TU/UNF
EMAC->EMACTXPOLLD = 0; // and resume
return len;
(void) ifp;
}
static void mg_tcpip_driver_tm4c_update_hash_table(struct mg_tcpip_if *ifp) {
@@ -245,9 +245,10 @@ static bool mg_tcpip_driver_tm4c_poll(struct mg_tcpip_if *ifp, bool s1) {
void EMAC0_IRQHandler(void);
static uint32_t s_rxno;
void EMAC0_IRQHandler(void) {
int i;
if (EMAC->EMACDMARIS & MG_BIT(6)) { // Frame received, loop
EMAC->EMACDMARIS = MG_BIT(16) | MG_BIT(6); // Clear flag
for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever
for (i = 0; i < 10; i++) { // read as they arrive but not forever
if (s_rxdesc[s_rxno][0] & MG_BIT(31)) break; // exit when done
if (((s_rxdesc[s_rxno][0] & (MG_BIT(8) | MG_BIT(9))) ==
(MG_BIT(8) | MG_BIT(9))) &&
+4 -10
View File
@@ -35,18 +35,12 @@ struct ETH_GLOBAL_TypeDef {
#define ETH_DESC_CNT 4 // Descriptors count
#define ETH_DS 4 // Descriptor size (words)
#ifndef ETH_RAM_SECTION
// if no section is specified, then the data will be placed in the default
// bss section
#define ETH_RAM_SECTION
#endif
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] ETH_RAM_SECTION;
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] ETH_RAM_SECTION;
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM;
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM;
static uint32_t s_rxdesc[ETH_DESC_CNT]
[ETH_DS] ETH_RAM_SECTION; // RX descriptors
[ETH_DS] MG_ETH_RAM; // RX descriptors
static uint32_t s_txdesc[ETH_DESC_CNT]
[ETH_DS] ETH_RAM_SECTION; // TX descriptors
[ETH_DS] MG_ETH_RAM; // TX descriptors
static uint8_t s_txno; // Current TX descriptor
static uint8_t s_rxno; // Current RX descriptor
+6 -9
View File
@@ -59,15 +59,12 @@ struct ETH_Type {
#define ETH_DESC_CNT 4 // Descriptors count
#define ETH_DS 2 // Descriptor size (words)
// TODO(): handle these in a portable compiler-independent CMSIS-friendly way
#define MG_8BYTE_ALIGNED __attribute__((aligned((8U))))
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE];
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE];
static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS] MG_8BYTE_ALIGNED;
static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS] MG_8BYTE_ALIGNED;
static uint8_t s_txno MG_8BYTE_ALIGNED; // Current TX descriptor
static uint8_t s_rxno MG_8BYTE_ALIGNED; // Current RX descriptor
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM;
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM;
static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS] MG_ETH_RAM MG_8BYTE_ALIGNED;
static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS] MG_ETH_RAM MG_8BYTE_ALIGNED;
static uint8_t s_txno; // Current TX descriptor
static uint8_t s_rxno; // Current RX descriptor
static struct mg_tcpip_if *s_ifp; // MIP interface
enum { MG_PHY_ADDR = 0, MG_PHYREG_BCR = 0, MG_PHYREG_BSR = 1 };
+2
View File
@@ -27,5 +27,7 @@ enum {
MG_EV_MQTT_OPEN, // MQTT CONNACK received int *connack_status_code
MG_EV_SNTP_TIME, // SNTP time received uint64_t *epoch_millis
MG_EV_WAKEUP, // mg_wakeup() data received struct mg_str *data
MG_EV_MDNS_REQ, // mDNS request struct mg_mdns_req *
MG_EV_MDNS_RESP, // mDNS response struct mg_mdns_resp *
MG_EV_USER // Starting ID for user events
};
+6 -4
View File
@@ -22,7 +22,8 @@ static int xisinf(double x) {
union {
double f;
uint64_t u;
} ieee754 = {x};
} ieee754;
ieee754.f = x;
return ((unsigned) (ieee754.u >> 32) & 0x7fffffff) == 0x7ff00000 &&
((unsigned) ieee754.u == 0);
}
@@ -31,7 +32,8 @@ static int xisnan(double x) {
union {
double f;
uint64_t u;
} ieee754 = {x};
} ieee754;
ieee754.f = x;
return ((unsigned) (ieee754.u >> 32) & 0x7fffffff) +
((unsigned) ieee754.u != 0) >
0x7ff00000;
@@ -99,7 +101,7 @@ static size_t mg_dtoa(char *dst, size_t dstlen, double d, int width, bool tz) {
}
while (tz && n > 0 && buf[s + n - 1] == '0') n--; // Trim trailing zeroes
if (tz && n > 0 && buf[s + n - 1] == '.') n--; // Trim trailing dot
if (tz && n > 0 && buf[s + n - 1] == '.') n--; // Trim trailing dot
n += s;
if (n >= (int) sizeof(buf)) n = (int) sizeof(buf) - 1;
buf[n] = '\0';
@@ -129,7 +131,7 @@ static size_t mg_lld(char *buf, int64_t val, bool is_signed, bool is_hex) {
}
static size_t scpy(void (*out)(char, void *), void *ptr, char *buf,
size_t len) {
size_t len) {
size_t i = 0;
while (i < len && buf[i] != '\0') out(buf[i++], ptr);
return i;
+9 -7
View File
@@ -1,14 +1,15 @@
#include "fs.h"
#include "printf.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 *fd = (struct mg_fd *) calloc(1, sizeof(*fd));
struct mg_fd *fd = (struct mg_fd *) mg_calloc(1, sizeof(*fd));
if (fd != NULL) {
fd->fd = fs->op(path, flags);
fd->fs = fs;
if (fd->fd == NULL) {
free(fd);
mg_free(fd);
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) {
if (fd != NULL) {
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;
fs->st(path, &result.len, 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 &&
fs->rd(fp, (void *) result.buf, result.len) != result.len) {
free((void *) result.buf);
mg_free((void *) result.buf);
result.buf = NULL;
}
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);
va_end(ap);
result = mg_file_write(fs, path, data, strlen(data));
free(data);
mg_free(data);
return result;
}
@@ -85,7 +86,8 @@ static void mg_fs_ls_fn(const char *filename, void *param) {
}
bool mg_fs_ls(struct mg_fs *fs, const char *path, char *buf, size_t len) {
struct mg_str s = {buf, len};
struct mg_str s;
s.buf = buf, s.len = len;
fs->ls(path, mg_fs_ls_fn, &s);
return buf[0] != '\0';
}
+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 (f_open(&f, path, mode) == 0) {
FIL *fp;
if ((fp = calloc(1, sizeof(*fp))) != NULL) {
if ((fp = mg_calloc(1, sizeof(*fp))) != NULL) {
memcpy(fp, &f, sizeof(*fp));
return fp;
}
@@ -85,7 +85,7 @@ static void *ff_open(const char *path, int flags) {
static void ff_close(void *fp) {
if (fp != NULL) {
f_close((FIL *) fp);
free(fp);
mg_free(fp);
}
}
+3 -2
View File
@@ -1,6 +1,7 @@
#include "fs.h"
#include "printf.h"
#include "str.h"
#include "util.h"
struct packed_file {
const char *data;
@@ -72,7 +73,7 @@ static void *packed_open(const char *path, int flags) {
struct packed_file *fp = NULL;
if (data == NULL) 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->data = data;
}
@@ -80,7 +81,7 @@ static void *packed_open(const char *path, int flags) {
}
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) {
+3 -3
View File
@@ -99,7 +99,7 @@ DIR *opendir(const char *name) {
if (name == NULL) {
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);
} else {
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->result.d_name[0] = '\0';
} else {
free(d);
mg_free(d);
d = NULL;
}
}
@@ -121,7 +121,7 @@ int closedir(DIR *d) {
if (d != NULL) {
if (d->handle != INVALID_HANDLE_VALUE)
result = FindClose(d->handle) ? 0 : -1;
free(d);
mg_free(d);
} else {
result = -1;
SetLastError(ERROR_BAD_ARGUMENTS);
+45 -69
View File
@@ -1,7 +1,7 @@
#include "http.h"
#include "arch.h"
#include "base64.h"
#include "fmt.h"
#include "http.h"
#include "json.h"
#include "log.h"
#include "net.h"
@@ -216,7 +216,7 @@ static bool vcb(uint8_t c) {
static size_t clen(const char *s, const char *end) {
const unsigned char *u = (unsigned char *) s, c = *u;
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 & 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]))
@@ -237,6 +237,8 @@ static const char *skiptorn(const char *s, const char *end, struct mg_str *v) {
static bool mg_http_parse_headers(const char *s, const char *end,
struct mg_http_header *h, size_t max_hdrs) {
size_t i, n;
int cl_count = 0, te_count = 0, auth_count = 0;
int conn_count = 0, cookie_count = 0;
for (i = 0; i < max_hdrs; i++) {
struct mg_str k = {NULL, 0}, v = {NULL, 0};
if (s >= end) return false;
@@ -252,6 +254,13 @@ static bool mg_http_parse_headers(const char *s, const char *end,
while (v.len > 0 && (v.buf[v.len - 1] == ' ' || v.buf[v.len - 1] == '\t')) {
v.len--; // Trim spaces
}
// detect duplicated headers -> discard
if (((mg_strcasecmp(k, mg_str("Content-Length")) == 0) && (++cl_count > 1)) ||
((mg_strcasecmp(k, mg_str("Transfer-Encoding")) == 0) && (++te_count > 1)) ||
((mg_strcasecmp(k, mg_str("Authorization")) == 0) && (++auth_count > 1)) ||
((mg_strcasecmp(k, mg_str("Cookie")) == 0) && (++cookie_count > 1)) ||
((mg_strcasecmp(k, mg_str("Connection")) == 0) && (++conn_count > 1)))
return false;
// MG_INFO(("--HH [%.*s] [%.*s]", (int) k.len, k.buf, (int) v.len, v.buf));
h[i].name = k, h[i].value = v; // Success. Assign values
}
@@ -280,17 +289,19 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) {
hm->uri.buf = (char *) s;
while (s < end && (n = clen(s, end)) > 0) s += n, hm->uri.len += n;
while (s < end && s[0] == ' ') s++; // Skip spaces
is_response = hm->method.len > 5 &&
(mg_ncasecmp(hm->method.buf, "HTTP/", 5) == 0);
is_response =
hm->method.len > 5 && (mg_ncasecmp(hm->method.buf, "HTTP/", 5) == 0);
if ((s = skiptorn(s, end, &hm->proto)) == NULL) return false;
// If we're given a version, check that it is HTTP/x.x
version_prefix_valid = hm->proto.len > 5 &&
(mg_ncasecmp(hm->proto.buf, "HTTP/", 5) == 0);
version_prefix_valid =
hm->proto.len > 5 && (mg_ncasecmp(hm->proto.buf, "HTTP/", 5) == 0);
if (!is_response && !version_prefix_valid)
return -1; // no version detected in request
if (!is_response && hm->proto.len > 0 &&
(!version_prefix_valid || hm->proto.len != 8 ||
(hm->proto.buf[5] < '0' || hm->proto.buf[5] > '9') ||
(hm->proto.buf[6] != '.') ||
(hm->proto.buf[7] < '0' || hm->proto.buf[7] > '9'))) {
(!version_prefix_valid || hm->proto.len != 8 ||
(hm->proto.buf[5] < '0' || hm->proto.buf[5] > '9') ||
(hm->proto.buf[6] != '.') ||
(hm->proto.buf[7] < '0' || hm->proto.buf[7] > '9'))) {
return -1;
}
@@ -317,17 +328,9 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) {
// responses. If HTTP response does not have Content-Length set, then
// body is read until socket is closed, i.e. body.len is infinite (~0).
//
// For HTTP requests though, according to
// http://tools.ietf.org/html/rfc7231#section-8.1.3,
// only POST and PUT methods have defined body semantics.
// Therefore, if Content-Length is not specified and methods are
// not one of PUT or POST, set body length to 0.
//
// So, if it is HTTP request, and Content-Length is not set,
// and method is not (PUT or POST) then reset body length to zero.
if (hm->body.len == (size_t) ~0 && !is_response &&
mg_strcasecmp(hm->method, mg_str("PUT")) != 0 &&
mg_strcasecmp(hm->method, mg_str("POST")) != 0) {
// For HTTP requests though, if Content-Length is not specified
// set body length to 0.
if (hm->body.len == (size_t) ~0 && !is_response) {
hm->body.len = 0;
hm->message.len = (size_t) req_len;
}
@@ -346,14 +349,14 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) {
static void mg_http_vprintf_chunk(struct mg_connection *c, const char *fmt,
va_list *ap) {
size_t len = c->send.len;
mg_send(c, " \r\n", 10);
if (!mg_send(c, " \r\n", 10)) mg_error(c, "OOM");
mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap);
if (c->send.len >= len + 10) {
mg_snprintf((char *) c->send.buf + len, 9, "%08lx", c->send.len - len - 10);
c->send.buf[len + 8] = '\r';
if (c->send.len == len + 10) c->is_resp = 0; // Last chunk, reset marker
}
mg_send(c, "\r\n", 2);
if (!mg_send(c, "\r\n", 2)) mg_error(c, "OOM");
}
void mg_http_printf_chunk(struct mg_connection *c, const char *fmt, ...) {
@@ -365,8 +368,7 @@ void mg_http_printf_chunk(struct mg_connection *c, const char *fmt, ...) {
void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len) {
mg_printf(c, "%lx\r\n", (unsigned long) len);
mg_send(c, buf, len);
mg_send(c, "\r\n", 2);
if (!mg_send(c, buf, len) || !mg_send(c, "\r\n", 2)) mg_error(c, "OOM");
if (len == 0) c->is_resp = 0;
}
@@ -589,13 +591,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
struct mg_str *ae = mg_http_get_header(hm, "Accept-Encoding");
if (ae != NULL) {
char *ae_ = mg_mprintf("%.*s", ae->len, ae->buf);
if (ae_ != NULL && strstr(ae_, "gzip") != NULL) {
if (mg_match(*ae, mg_str("*gzip*"), NULL)) {
mg_snprintf(tmp, sizeof(tmp), "%s.gz", path);
fd = mg_fs_open(fs, tmp, MG_FS_READ);
if (fd != NULL) gzip = true, path = tmp;
}
free(ae_);
}
// No luck opening .gz? Open what we've told to open
if (fd == NULL) fd = mg_fs_open(fs, path, MG_FS_READ);
@@ -651,10 +651,10 @@ void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm,
status, mg_http_status_code_str(status), (int) mime.len, mime.buf,
etag, (uint64_t) cl, gzip ? "Content-Encoding: gzip\r\n" : "",
range, opts->extra_headers ? opts->extra_headers : "");
if (mg_strcasecmp(hm->method, mg_str("HEAD")) == 0) {
if (mg_strcasecmp(hm->method, mg_str("HEAD")) == 0 || c->is_closing) {
c->is_resp = 0;
mg_fs_close(fd);
} else {
} else { // start serving static content only if not closing, see #3354
// Track to-be-sent content length at the end of c->data, aligned
size_t *clp = (size_t *) &c->data[(sizeof(c->data) - sizeof(size_t)) /
sizeof(size_t) * sizeof(size_t)];
@@ -686,7 +686,7 @@ static void printdirentry(const char *name, void *userdata) {
sizeof(path)) {
MG_ERROR(("%s truncated", name));
} 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 {
const char *slash = flags & MG_FS_DIR ? "/" : "";
if (flags & MG_FS_DIR) {
@@ -977,7 +977,7 @@ long mg_http_upload(struct mg_connection *c, struct mg_http_message *hm,
mg_http_reply(c, 400, "", "%s: offset mismatch", path);
res = -5;
} 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;
} else {
res = offset + (long) fs->wr(fd->fd, hm->body.buf, hm->body.len);
@@ -1023,7 +1023,7 @@ static void http_cb(struct mg_connection *c, int ev, void *ev_data) {
const char *buf = (char *) c->recv.buf + ofs;
int n = mg_http_parse(buf, c->recv.len - ofs, &hm);
struct mg_str *te; // Transfer - encoding header
bool is_chunked = false;
bool is_chunked = false, is_http_1_0 = false;
size_t old_len = c->recv.len;
if (n < 0) {
// We don't use mg_error() here, to avoid closing pipelined requests
@@ -1042,11 +1042,15 @@ static void http_cb(struct mg_connection *c, int ev, void *ev_data) {
c->pfn = NULL;
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.body.len = hm.message.len - (size_t) (hm.body.buf - hm.message.buf);
}
if ((te = mg_http_get_header(&hm, "Transfer-Encoding")) != NULL) {
is_http_1_0 =
hm.proto.len > 8 && mg_ncasecmp(hm.proto.buf, "HTTP/1.0", 8) == 0;
// HTTP/1.0 does not use "Transfer-Encoding: chunked"
if (!is_http_1_0 &&
(te = mg_http_get_header(&hm, "Transfer-Encoding")) != NULL) {
if (mg_strcasecmp(*te, mg_str("chunked")) == 0) {
is_chunked = true;
} else {
@@ -1061,9 +1065,10 @@ static void http_cb(struct mg_connection *c, int ev, void *ev_data) {
if (!is_response && (mg_strcasecmp(hm.method, mg_str("POST")) == 0 ||
mg_strcasecmp(hm.method, mg_str("PUT")) == 0)) {
// POST and PUT should include an entity body. Therefore, they should
// contain a Content-length header. Other requests can also contain a
// contain a Content-length header (unless the body length is 0, in
// which case it can be omitted). Other requests can also contain a
// body, but their content has no defined semantics (RFC 7231)
require_content_len = true;
if (hm.body.len != 0) require_content_len = true;
ofs += (size_t) n; // this request has been processed
} else if (is_response) {
// HTTP spec 7.2 Entity body: All other responses must include a body
@@ -1073,7 +1078,8 @@ static void http_cb(struct mg_connection *c, int ev, void *ev_data) {
}
if (require_content_len) {
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 +1126,9 @@ static void http_cb(struct mg_connection *c, int ev, 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,
mg_event_handler_t fn, void *fn_data) {
struct mg_connection *c = mg_connect(mgr, url, fn, fn_data);
if (c != NULL) c->pfn = http_cb;
return c;
return mg_connect_svc(mgr, url, fn, fn_data, http_cb, NULL);
}
struct mg_connection *mg_http_listen(struct mg_mgr *mgr, const char *url,
-2
View File
@@ -40,7 +40,6 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *);
int mg_http_get_request_len(const unsigned char *buf, size_t buf_len);
void mg_http_printf_chunk(struct mg_connection *cnn, const char *fmt, ...);
void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len);
void mg_http_delete_chunk(struct mg_connection *c, struct mg_http_message *hm);
struct mg_connection *mg_http_listen(struct mg_mgr *, const char *url,
mg_event_handler_t fn, void *fn_data);
struct mg_connection *mg_http_connect(struct mg_mgr *, const char *url,
@@ -63,4 +62,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);
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);
void mg_hello(const char *url);
+10 -10
View File
@@ -1,5 +1,5 @@
#include "arch.h"
#include "iobuf.h"
#include "arch.h"
#include "log.h"
#include "util.h"
@@ -7,34 +7,34 @@ static size_t roundup(size_t size, size_t align) {
return align == 0 ? size : (size + align - 1) / align * align;
}
int mg_iobuf_resize(struct mg_iobuf *io, size_t new_size) {
int ok = 1;
bool mg_iobuf_resize(struct mg_iobuf *io, size_t new_size) {
bool ok = true;
new_size = roundup(new_size, io->align);
if (new_size == 0) {
mg_bzero(io->buf, io->size);
free(io->buf);
mg_free(io->buf);
io->buf = NULL;
io->len = io->size = 0;
} else if (new_size != io->size) {
// NOTE(lsm): do not use realloc here. Use calloc/free only, to ease the
// porting to some obscure platforms like FreeRTOS
void *p = calloc(1, new_size);
// NOTE(lsm): do not use realloc here. Use mg_calloc/mg_free only
void *p = mg_calloc(1, new_size);
if (p != NULL) {
size_t len = new_size < io->len ? new_size : io->len;
if (len > 0 && io->buf != NULL) memmove(p, io->buf, len);
mg_bzero(io->buf, io->size);
free(io->buf);
mg_free(io->buf);
io->buf = (unsigned char *) p;
io->size = new_size;
io->len = len;
} else {
ok = 0;
ok = false;
MG_ERROR(("%lld->%lld", (uint64_t) io->size, (uint64_t) new_size));
}
}
return ok;
}
int mg_iobuf_init(struct mg_iobuf *io, size_t size, size_t align) {
bool mg_iobuf_init(struct mg_iobuf *io, size_t size, size_t align) {
io->buf = NULL;
io->align = align;
io->size = io->len = 0;
+2 -2
View File
@@ -9,8 +9,8 @@ struct mg_iobuf {
size_t align; // Alignment during allocation
};
int mg_iobuf_init(struct mg_iobuf *, size_t, size_t);
int mg_iobuf_resize(struct mg_iobuf *, size_t);
bool mg_iobuf_init(struct mg_iobuf *, size_t, size_t);
bool mg_iobuf_resize(struct mg_iobuf *, size_t);
void mg_iobuf_free(struct mg_iobuf *);
size_t mg_iobuf_add(struct mg_iobuf *, size_t, const void *, size_t);
size_t mg_iobuf_del(struct mg_iobuf *, size_t ofs, size_t len);
+22 -8
View File
@@ -1,6 +1,7 @@
#include "json.h"
#include "base64.h"
#include "fmt.h"
#include "util.h"
static const char *escapeseq(int esc) {
return esc ? "\b\f\n\r\t\\\"" : "bfnrt\\\"";
@@ -59,15 +60,28 @@ static double mg_atod(const char *p, int len, int *numlen) {
// Exponential
if (i < len && (p[i] == 'e' || p[i] == 'E')) {
int j, exp = 0, minus = 0;
int exp = 0, minus = 0;
i++;
if (i < len && p[i] == '-') minus = 1, i++;
if (i < len && p[i] == '+') i++;
while (i < len && p[i] >= '0' && p[i] <= '9' && exp < 308)
exp = exp * 10 + (p[i++] - '0');
if (minus) exp = -exp;
for (j = 0; j < exp; j++) d *= 10.0;
for (j = 0; j < -exp; j++) d /= 10.0;
// use fast exponentiation
// https://en.wikipedia.org/wiki/Exponentiation_by_squaring
if (exp != 0) {
double x = 10, y = 1;
if (exp > 308) exp = 308;
if (minus) x = 0.1;
while (exp > 1) {
if (exp & 1) {
y *= x;
--exp;
}
x *= x;
exp >>= 1;
}
d *= x * y;
}
}
if (numlen != NULL) *numlen = i;
@@ -320,10 +334,10 @@ char *mg_json_get_str(struct mg_str json, const char *path) {
char *result = NULL;
int len = 0, off = mg_json_get(json, path, &len);
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)),
result, (size_t) len)) {
free(result);
mg_free(result);
result = NULL;
}
}
@@ -334,7 +348,7 @@ char *mg_json_get_b64(struct mg_str json, const char *path, int *slen) {
char *result = NULL;
int len = 0, off = mg_json_get(json, path, &len);
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) len);
if (slen != NULL) *slen = (int) k;
@@ -346,7 +360,7 @@ char *mg_json_get_hex(struct mg_str json, const char *path, int *slen) {
char *result = NULL;
int len = 0, off = mg_json_get(json, path, &len);
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;
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],
+121
View File
@@ -0,0 +1,121 @@
#include "l2.h"
#include "net.h"
#include "net_builtin.h"
#if MG_ENABLE_TCPIP
// L2 API
void mg_l2_init(enum mg_l2type type, uint8_t *addr, uint16_t *mtu,
uint16_t *framesize);
uint8_t *mg_l2_header(enum mg_l2type type, enum mg_l2proto proto, uint8_t *src,
uint8_t *dst, uint8_t *frame);
size_t mg_l2_footer(enum mg_l2type type, size_t len, uint8_t *frame);
bool mg_l2_rx(struct mg_tcpip_if *ifp, enum mg_l2proto *proto,
struct mg_str *pay, struct mg_str *raw);
// TODO(): ? bool mg_l2_rx(enum mg_l2type type, struct mg_l2opts *opts, uint8_t
// *addr, enum mg_l2proto *proto, struct mg_str *pay, struct mg_str *raw);
uint8_t *mg_l2_getaddr(enum mg_l2type type, uint8_t *frame);
uint8_t *mg_l2_mapip(enum mg_l2type type, enum mg_l2addrtype addrtype,
struct mg_addr *ip);
bool mg_l2_genip6(enum mg_l2type type, uint64_t *ip6, uint8_t prefix_len,
uint8_t *addr);
bool mg_l2_ip6get(enum mg_l2type type, uint8_t *addr, uint8_t *opts,
uint8_t len);
uint8_t mg_l2_ip6put(enum mg_l2type type, uint8_t *addr, uint8_t *opts);
// clang-format off
extern void mg_l2_eth_init(struct mg_l2addr *, uint16_t *, uint16_t *);
extern uint8_t *mg_l2_eth_header(enum mg_l2proto, struct mg_l2addr *, struct mg_l2addr *, uint8_t *);
extern size_t mg_l2_eth_footer(size_t, uint8_t *);
extern bool mg_l2_eth_rx(struct mg_tcpip_if *, enum mg_l2proto *, struct mg_str *, struct mg_str *);
extern struct mg_l2addr *mg_l2_eth_getaddr(uint8_t *);
extern struct mg_l2addr *mg_l2_eth_mapip(enum mg_l2addrtype, struct mg_addr *);
extern bool mg_l2_eth_genip6(uint64_t *, uint8_t, struct mg_l2addr *);
extern bool mg_l2_eth_ip6get(struct mg_l2addr *, uint8_t *, uint8_t);
extern uint8_t mg_l2_eth_ip6put(struct mg_l2addr *, uint8_t *);
extern void mg_l2_ppp_init(struct mg_l2addr *, uint16_t *, uint16_t *);
extern uint8_t *mg_l2_ppp_header(enum mg_l2proto, struct mg_l2addr *, struct mg_l2addr *, uint8_t *);
extern size_t mg_l2_ppp_footer(size_t, uint8_t *);
extern bool mg_l2_ppp_rx(struct mg_tcpip_if *, enum mg_l2proto *, struct mg_str *, struct mg_str *);
extern struct mg_l2addr *mg_l2_ppp_getaddr(uint8_t *);
extern struct mg_l2addr *mg_l2_ppp_mapip(enum mg_l2addrtype, struct mg_addr *);
#if MG_ENABLE_IPV6
extern bool mg_l2_ppp_genip6(uint64_t *, uint8_t, struct mg_l2addr *);
extern bool mg_l2_ppp_ip6get(struct mg_l2addr *, uint8_t *, uint8_t);
extern uint8_t mg_l2_ppp_ip6put(struct mg_l2addr *, uint8_t *);
#endif
typedef void (*l2_init_fn)(struct mg_l2addr *, uint16_t *, uint16_t *);
typedef uint8_t *((*l2_header_fn)(enum mg_l2proto, struct mg_l2addr *, struct mg_l2addr *, uint8_t *));
typedef size_t (*l2_footer_fn)(size_t, uint8_t *);
typedef bool (*l2_rx_fn)(struct mg_tcpip_if *, enum mg_l2proto *, struct mg_str *, struct mg_str *);
typedef struct mg_l2addr (*(*l2_getaddr_fn)(uint8_t *));
typedef struct mg_l2addr (*(*l2_mapip_fn)(enum mg_l2addrtype, struct mg_addr *));
#if MG_ENABLE_IPV6
typedef bool (*l2_genip6_fn)(uint64_t *, uint8_t, struct mg_l2addr *);
typedef bool (*l2_ip6get_fn)(struct mg_l2addr *, uint8_t *, uint8_t);
typedef uint8_t (*l2_ip6put_fn)(struct mg_l2addr *, uint8_t *);
#endif
// clang-format on
static const l2_init_fn l2_init[] = {mg_l2_eth_init, mg_l2_ppp_init};
static const l2_header_fn l2_header[] = {mg_l2_eth_header, mg_l2_ppp_header};
static const l2_footer_fn l2_footer[] = {mg_l2_eth_footer, mg_l2_ppp_footer};
static const l2_rx_fn l2_rx[] = {mg_l2_eth_rx, mg_l2_ppp_rx};
static const l2_getaddr_fn l2_getaddr[] = {mg_l2_eth_getaddr,
mg_l2_ppp_getaddr};
static const l2_mapip_fn l2_mapip[] = {mg_l2_eth_mapip, mg_l2_ppp_mapip};
#if MG_ENABLE_IPV6
static const l2_genip6_fn l2_genip6[] = {mg_l2_eth_genip6, mg_l2_ppp_genip6};
static const l2_ip6get_fn l2_ip6get[] = {mg_l2_eth_ip6get, mg_l2_ppp_ip6get};
static const l2_ip6put_fn l2_ip6put[] = {mg_l2_eth_ip6put, mg_l2_ppp_ip6put};
#endif
void mg_l2_init(enum mg_l2type type, uint8_t *addr, uint16_t *mtu,
uint16_t *framesize) {
l2_init[type]((struct mg_l2addr *) addr, mtu, framesize);
}
uint8_t *mg_l2_header(enum mg_l2type type, enum mg_l2proto proto, uint8_t *src,
uint8_t *dst, uint8_t *frame) {
return l2_header[type](proto, (struct mg_l2addr *) src,
(struct mg_l2addr *) dst, frame);
}
size_t mg_l2_footer(enum mg_l2type type, size_t len, uint8_t *frame) {
return l2_footer[type](len, frame);
}
bool mg_l2_rx(struct mg_tcpip_if *ifp, enum mg_l2proto *proto,
struct mg_str *pay, struct mg_str *raw) {
return l2_rx[ifp->l2type](ifp, proto, pay, raw);
}
uint8_t *mg_l2_getaddr(enum mg_l2type type, uint8_t *frame) {
return (uint8_t *) l2_getaddr[type](frame);
}
struct mg_l2addr s_mapip;
uint8_t *mg_l2_mapip(enum mg_l2type type, enum mg_l2addrtype addrtype,
struct mg_addr *ip) {
return (uint8_t *) l2_mapip[type](addrtype, ip);
}
#if MG_ENABLE_IPV6
bool mg_l2_genip6(enum mg_l2type type, uint64_t *ip6, uint8_t prefix_len,
uint8_t *addr) {
return l2_genip6[type](ip6, prefix_len, (struct mg_l2addr *) addr);
}
bool mg_l2_ip6get(enum mg_l2type type, uint8_t *addr, uint8_t *opts,
uint8_t len) {
return l2_ip6get[type]((struct mg_l2addr *) addr, opts, len);
}
uint8_t mg_l2_ip6put(enum mg_l2type type, uint8_t *addr, uint8_t *opts) {
return l2_ip6put[type]((struct mg_l2addr *) addr, opts);
}
#endif
#endif
+55
View File
@@ -0,0 +1,55 @@
#pragma once
#include "arch.h"
#include "config.h"
#if MG_ENABLE_TCPIP
// no config defaults to 0 => Ethernet
enum mg_l2type { MG_TCPIP_L2_ETH = 0, MG_TCPIP_L2_PPP }; // MG_TCPIP_L2_PPPoE
#if defined(__DCC__)
#pragma pack(1)
#else
#pragma pack(push, 1)
#endif
struct mg_l2addr {
union {
uint8_t mac[6];
} addr;
};
#if defined(__DCC__)
#pragma pack(0)
#else
#pragma pack(pop)
#endif
#if 0
TODO(): ?
struct eth_opts {
bool enable_crc32_check; // Do a CRC check on RX frames and strip it
bool enable_mac_check; // Do a MAC check on RX frames
};
struct mg_l2opts {
union {
struct eth_opts eth;
};
};
#endif
enum mg_l2proto {
MG_TCPIP_L2PROTO_IPV4 = 0,
MG_TCPIP_L2PROTO_IPV6,
MG_TCPIP_L2PROTO_ARP,
MG_TCPIP_L2PROTO_PPPoE_DISC,
MG_TCPIP_L2PROTO_PPPoE_SESS
};
enum mg_l2addrtype {
MG_TCPIP_L2ADDR_BCAST,
MG_TCPIP_L2ADDR_MCAST,
MG_TCPIP_L2ADDR_MCAST6
};
#endif
+171
View File
@@ -0,0 +1,171 @@
#include "l2.h"
#include "log.h"
#include "net.h"
#include "net_builtin.h"
#include "printf.h"
#include "util.h"
#if MG_ENABLE_TCPIP
#if defined(__DCC__)
#pragma pack(1)
#else
#pragma pack(push, 1)
#endif
struct eth {
uint8_t dst[6]; // Destination MAC address
uint8_t src[6]; // Source MAC address
uint16_t type; // Ethernet type
};
#if defined(__DCC__)
#pragma pack(0)
#else
#pragma pack(pop)
#endif
static const uint16_t eth_types[] = {
// order is vital, see l2.h
0x800, // IPv4
0x86dd, // IPv6
0x806, // ARP
0x8863, // PPPoE Discovery Stage
0x8864 // PPPoE Session Stage
};
void mg_l2_eth_init(struct mg_l2addr *l2addr, uint16_t *mtu,
uint16_t *framesize) {
// If MAC is not set, make a random one
if (l2addr->addr.mac[0] == 0 && l2addr->addr.mac[1] == 0 &&
l2addr->addr.mac[2] == 0 && l2addr->addr.mac[3] == 0 &&
l2addr->addr.mac[4] == 0 && l2addr->addr.mac[5] == 0) {
l2addr->addr.mac[0] = 0x02; // Locally administered, unicast
mg_random(&l2addr->addr.mac[1], sizeof(l2addr->addr.mac) - 1);
MG_INFO(
("MAC not set. Generated random: %M", mg_print_mac, l2addr->addr.mac));
}
*mtu = 1500;
*framesize = 1540;
}
uint8_t *mg_l2_eth_header(enum mg_l2proto proto, struct mg_l2addr *src,
struct mg_l2addr *dst, uint8_t *frame) {
struct eth *eth = (struct eth *) frame;
eth->type = mg_htons(eth_types[(unsigned int) proto]);
memcpy(eth->src, src->addr.mac, sizeof(eth->dst));
memcpy(eth->dst, dst->addr.mac, sizeof(eth->dst));
return (uint8_t *) (eth + 1);
}
size_t mg_l2_eth_footer(size_t len, uint8_t *frame) {
struct eth *eth = (struct eth *) frame;
// nothing to do; there is no len field in Ethernet, CRC is hw-calculated
return len + sizeof(*eth);
}
struct mg_l2addr *mg_l2_eth_mapip(enum mg_l2addrtype addrtype,
struct mg_addr *addr);
bool mg_l2_eth_rx(struct mg_tcpip_if *ifp, enum mg_l2proto *proto,
struct mg_str *pay, struct mg_str *raw) {
struct eth *eth = (struct eth *) raw->buf;
uint16_t type, len;
unsigned int i;
if (raw->len < sizeof(*eth)) return false; // Truncated - runt?
len = (uint16_t) raw->len;
if (ifp->enable_mac_check &&
memcmp(eth->dst, ifp->mac, sizeof(eth->dst)) != 0 &&
memcmp(eth->dst, mg_l2_eth_mapip(MG_TCPIP_L2ADDR_BCAST, NULL),
sizeof(eth->dst)) != 0)
return false; // TODO(): add multicast addresses
if (ifp->enable_crc32_check && len > sizeof(*eth) + 4) {
uint32_t crc;
len -= 4; // TODO(scaprile): check on bigendian
crc = mg_crc32(0, (const char *) raw->buf, len);
if (memcmp((void *) ((size_t) raw->buf + len), &crc, sizeof(crc)))
return false;
}
pay->buf = (char *) (eth + 1);
pay->len = len - sizeof(*eth);
type = mg_htons(eth->type);
for (i = 0; i < sizeof(eth_types) / sizeof(uint16_t); i++) {
if (type == eth_types[i]) break;
}
if (i == sizeof(eth_types)) {
MG_DEBUG(("Unknown eth type %x", type));
if (mg_log_level >= MG_LL_VERBOSE)
mg_hexdump(raw->buf, raw->len >= 32 ? 32 : raw->len);
return false;
}
*proto = (enum mg_l2proto) i;
return true;
}
struct mg_l2addr *mg_l2_eth_getaddr(uint8_t *frame) {
struct eth *eth = (struct eth *) frame;
return (struct mg_l2addr *) &eth->src;
}
extern struct mg_l2addr s_mapip;
struct mg_l2addr *mg_l2_eth_mapip(enum mg_l2addrtype addrtype,
struct mg_addr *addr) {
switch (addrtype) {
case MG_TCPIP_L2ADDR_BCAST:
memset(s_mapip.addr.mac, 0xff, sizeof(s_mapip.addr.mac));
break;
case MG_TCPIP_L2ADDR_MCAST: {
uint8_t *ip = (uint8_t *) &addr->addr.ip4;
// IP multicast group MAC, RFC-1112 6.4
s_mapip.addr.mac[0] = 0x01, s_mapip.addr.mac[1] = 0x00,
s_mapip.addr.mac[2] = 0x5E;
s_mapip.addr.mac[3] = ip[1] & 0x7F; // 23 LSb
s_mapip.addr.mac[4] = ip[2];
s_mapip.addr.mac[5] = ip[3];
break;
}
case MG_TCPIP_L2ADDR_MCAST6: {
// IPv6 multicast address mapping, RFC-2464 7
uint8_t *ip = (uint8_t *) &addr->addr.ip6;
s_mapip.addr.mac[0] = 0x33, s_mapip.addr.mac[1] = 0x33;
s_mapip.addr.mac[2] = ip[12], s_mapip.addr.mac[3] = ip[13],
s_mapip.addr.mac[4] = ip[14], s_mapip.addr.mac[5] = ip[15];
break;
}
}
return &s_mapip;
}
#if MG_ENABLE_IPV6
static void meui64(uint8_t *addr, uint8_t *mac) {
*addr++ = *mac++ ^ (uint8_t) 0x02, *addr++ = *mac++, *addr++ = *mac++;
*addr++ = 0xff, *addr++ = 0xfe;
*addr++ = *mac++, *addr++ = *mac++, *addr = *mac;
}
bool mg_l2_eth_genip6(uint64_t *ip6, uint8_t prefix_len,
struct mg_l2addr *l2addr) {
if (prefix_len > 64) {
MG_ERROR(("Prefix length > 64, UNSUPPORTED"));
return false;
}
ip6[0] = 0;
meui64(((uint8_t *) &ip6[1]), l2addr->addr.mac); // RFC-4291 2.5.4, 2.5.1
return true;
}
bool mg_l2_eth_ip6get(struct mg_l2addr *l2addr, uint8_t *opts, uint8_t len) {
if (len != 1) return false;
memcpy(l2addr->addr.mac, opts, 6);
return true;
}
uint8_t mg_l2_eth_ip6put(struct mg_l2addr *l2addr, uint8_t *opts) {
memcpy(opts, l2addr->addr.mac, 6);
return 1;
}
#endif
#endif
+115
View File
@@ -0,0 +1,115 @@
#include "l2.h"
#include "log.h"
#include "net.h"
#include "net_builtin.h"
#include "printf.h"
#include "util.h"
#if MG_ENABLE_TCPIP
#if defined(__DCC__)
#pragma pack(1)
#else
#pragma pack(push, 1)
#endif
struct ppp { // RFC-1662
uint8_t addr, ctrl;
uint16_t proto;
};
struct lcp { // RFC-1661
uint8_t code, id, len[2];
};
struct ipcp { // RFC-1332
uint8_t code;
};
struct ipv6cp { // RFC-5072
uint8_t code;
};
#if defined(__DCC__)
#pragma pack(0)
#else
#pragma pack(pop)
#endif
void mg_l2_ppp_init(struct mg_l2addr *addr, uint16_t *mtu,
uint16_t *framesize) {
(void) addr;
*mtu = 1500; // 1492 for PPPoE
*framesize = 1540; // *** TODO(scaprile): actual value, check for PPPoE too
}
uint8_t *mg_l2_ppp_header(enum mg_l2proto proto, struct mg_l2addr *src,
struct mg_l2addr *dst, uint8_t *frame) {
(void) src;
(void) dst;
(void) proto;
return frame;
}
size_t mg_l2_ppp_footer(size_t len, uint8_t *frame) {
(void) frame;
return len;
}
bool mg_l2_ppp_rx(struct mg_tcpip_if *ifp, enum mg_l2proto *proto,
struct mg_str *pay, struct mg_str *raw) {
#if 0
if (ppp->addr == MG_PPP_ADDR && ppp->ctrl == MG_PPP_CTRL) {
code = ntohs(ppp->proto);
payload = (uint8_t *) (ppp + 1);
} else { // Address-and-Control-Field-Compressed PPP header
uint16_t *cppp = (uint16_t *) ppp;
code = ntohs(*cppp);
payload = (uint8_t *) (cppp + 1);
}
#endif
*pay = *raw;
*proto = MG_TCPIP_L2PROTO_IPV4;
(void) ifp;
return true;
}
struct mg_l2addr *mg_l2_ppp_getaddr(uint8_t *frame) {
(void) frame;
return &s_mapip; // bogus
}
extern struct mg_l2addr s_mapip;
struct mg_l2addr *mg_l2_ppp_mapip(enum mg_l2addrtype addrtype,
struct mg_addr *addr) {
(void) addrtype;
(void) addr;
return &s_mapip; // bogus
}
#if MG_ENABLE_IPV6
bool mg_l2_ppp_genip6(uint64_t *ip6, uint8_t prefix_len,
struct mg_l2addr *addr) {
(void) ip6;
(void) prefix_len;
(void) addr;
return false;
}
bool mg_l2_ppp_ip6get(struct mg_l2addr *addr, uint8_t *opts, uint8_t len) {
(void) addr;
(void) opts;
(void) len;
return false;
}
uint8_t mg_l2_ppp_ip6put(struct mg_l2addr *addr, uint8_t *opts) {
(void) addr;
(void) opts;
return 0;
}
#endif
#endif
+1 -1
View File
@@ -3,7 +3,7 @@
#include "str.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 void *s_log_func_param = NULL;
+12 -6
View File
@@ -16,12 +16,18 @@ void mg_log_set_fn(mg_pfn_t fn, void *param);
#define mg_log_set(level_) mg_log_level = (level_)
#if MG_ENABLE_LOG
#define MG_LOG(level, args) \
do { \
if ((level) <= mg_log_level) { \
mg_log_prefix((level), __FILE__, __LINE__, __func__); \
mg_log args; \
} \
#if !defined(_MSC_VER) && \
(!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L)
#define MG___FUNC__ ""
#else
#define MG___FUNC__ __func__ // introduced in C99
#endif
#define MG_LOG(level, args) \
do { \
if ((level) <= mg_log_level) { \
mg_log_prefix((level), __FILE__, __LINE__, MG___FUNC__); \
mg_log args; \
} \
} while (0)
#else
#define MG_LOG(level, args) \
+148 -89
View File
@@ -1,8 +1,8 @@
#include "mqtt.h"
#include "arch.h"
#include "base64.h"
#include "event.h"
#include "log.h"
#include "mqtt.h"
#include "url.h"
#include "util.h"
@@ -46,8 +46,8 @@ static const struct mg_mqtt_pmap s_prop_map[] = {
{MQTT_PROP_SUBSCRIPTION_IDENTIFIER_AVAILABLE, MQTT_PROP_TYPE_BYTE},
{MQTT_PROP_SHARED_SUBSCRIPTION_AVAILABLE, MQTT_PROP_TYPE_BYTE}};
void mg_mqtt_send_header(struct mg_connection *c, uint8_t cmd, uint8_t flags,
uint32_t len) {
static bool mqtt_send_header(struct mg_connection *c, uint8_t cmd,
uint8_t flags, uint32_t len) {
uint8_t buf[1 + sizeof(len)], *vlen = &buf[1];
buf[0] = (uint8_t) ((cmd << 4) | flags);
do {
@@ -56,15 +56,20 @@ void mg_mqtt_send_header(struct mg_connection *c, uint8_t cmd, uint8_t flags,
if (len > 0) *vlen |= 0x80;
vlen++;
} while (len > 0 && vlen < &buf[sizeof(buf)]);
mg_send(c, buf, (size_t) (vlen - buf));
return mg_send(c, buf, (size_t) (vlen - buf));
}
static void mg_send_u16(struct mg_connection *c, uint16_t value) {
mg_send(c, &value, sizeof(value));
void mg_mqtt_send_header(struct mg_connection *c, uint8_t cmd, uint8_t flags,
uint32_t len) {
if (!mqtt_send_header(c, cmd, flags, len)) mg_error(c, "OOM");
}
static void mg_send_u32(struct mg_connection *c, uint32_t value) {
mg_send(c, &value, sizeof(value));
static bool mg_send_u16(struct mg_connection *c, uint16_t value) {
return mg_send(c, &value, sizeof(value));
}
static bool mg_send_u32(struct mg_connection *c, uint32_t value) {
return mg_send(c, &value, sizeof(value));
}
static uint8_t varint_size(size_t length) {
@@ -132,17 +137,10 @@ static size_t get_properties_length(struct mg_mqtt_prop *props, size_t count) {
case MQTT_PROP_TYPE_VARIABLE_INT:
size += varint_size((uint32_t) props[i].iv);
break;
case MQTT_PROP_TYPE_INT:
size += (uint32_t) sizeof(uint32_t);
break;
case MQTT_PROP_TYPE_SHORT:
size += (uint32_t) sizeof(uint16_t);
break;
case MQTT_PROP_TYPE_BYTE:
size += (uint32_t) sizeof(uint8_t);
break;
default:
return size; // cannot parse further down
case MQTT_PROP_TYPE_INT: size += (uint32_t) sizeof(uint32_t); break;
case MQTT_PROP_TYPE_SHORT: size += (uint32_t) sizeof(uint16_t); break;
case MQTT_PROP_TYPE_BYTE: size += (uint32_t) sizeof(uint8_t); break;
default: return size; // cannot parse further down
}
}
@@ -157,46 +155,50 @@ static size_t get_props_size(struct mg_mqtt_prop *props, size_t count) {
return size;
}
static void mg_send_mqtt_properties(struct mg_connection *c,
static bool mg_send_mqtt_properties(struct mg_connection *c,
struct mg_mqtt_prop *props, size_t nprops) {
size_t total_size = get_properties_length(props, nprops);
uint8_t buf_v[4] = {0, 0, 0, 0};
uint8_t buf[4] = {0, 0, 0, 0};
size_t i, len = encode_varint(buf, total_size);
mg_send(c, buf, (size_t) len);
if (!mg_send(c, buf, (size_t) len)) return false;
for (i = 0; i < nprops; i++) {
mg_send(c, &props[i].id, sizeof(props[i].id));
if (!mg_send(c, &props[i].id, sizeof(props[i].id))) return false;
switch (mqtt_prop_type_by_id(props[i].id)) {
case MQTT_PROP_TYPE_STRING_PAIR:
mg_send_u16(c, mg_htons((uint16_t) props[i].key.len));
mg_send(c, props[i].key.buf, props[i].key.len);
mg_send_u16(c, mg_htons((uint16_t) props[i].val.len));
mg_send(c, props[i].val.buf, props[i].val.len);
if (!mg_send_u16(c, mg_htons((uint16_t) props[i].key.len)) ||
!mg_send(c, props[i].key.buf, props[i].key.len) ||
!mg_send_u16(c, mg_htons((uint16_t) props[i].val.len)) ||
!mg_send(c, props[i].val.buf, props[i].val.len))
return false;
break;
case MQTT_PROP_TYPE_BYTE:
mg_send(c, &props[i].iv, sizeof(uint8_t));
if (!mg_send(c, &props[i].iv, sizeof(uint8_t))) return false;
break;
case MQTT_PROP_TYPE_SHORT:
mg_send_u16(c, mg_htons((uint16_t) props[i].iv));
if (!mg_send_u16(c, mg_htons((uint16_t) props[i].iv))) return false;
break;
case MQTT_PROP_TYPE_INT:
mg_send_u32(c, mg_htonl((uint32_t) props[i].iv));
if (!mg_send_u32(c, mg_htonl((uint32_t) props[i].iv))) return false;
break;
case MQTT_PROP_TYPE_STRING:
mg_send_u16(c, mg_htons((uint16_t) props[i].val.len));
mg_send(c, props[i].val.buf, props[i].val.len);
if (!mg_send_u16(c, mg_htons((uint16_t) props[i].val.len)) ||
!mg_send(c, props[i].val.buf, props[i].val.len))
return false;
break;
case MQTT_PROP_TYPE_BINARY_DATA:
mg_send_u16(c, mg_htons((uint16_t) props[i].val.len));
mg_send(c, props[i].val.buf, props[i].val.len);
if (!mg_send_u16(c, mg_htons((uint16_t) props[i].val.len)) ||
!mg_send(c, props[i].val.buf, props[i].val.len))
return false;
break;
case MQTT_PROP_TYPE_VARIABLE_INT:
len = encode_varint(buf_v, props[i].iv);
mg_send(c, buf_v, (size_t) len);
if (!mg_send(c, buf_v, (size_t) len)) return false;
break;
}
}
return true;
}
size_t mg_mqtt_next_prop(struct mg_mqtt_message *msg, struct mg_mqtt_prop *prop,
@@ -204,50 +206,64 @@ size_t mg_mqtt_next_prop(struct mg_mqtt_message *msg, struct mg_mqtt_prop *prop,
uint8_t *i = (uint8_t *) msg->dgram.buf + msg->props_start + ofs;
uint8_t *end = (uint8_t *) msg->dgram.buf + msg->dgram.len;
size_t new_pos = ofs, len;
prop->id = i[0];
if (ofs >= msg->dgram.len || ofs >= msg->props_start + msg->props_size)
if (ofs >= msg->dgram.len || ofs >= msg->props_start + msg->props_size || (i + 1) >= end)
return 0;
memset(prop, 0, sizeof(struct mg_mqtt_prop));
prop->id = i[0];
i++, new_pos++;
switch (mqtt_prop_type_by_id(prop->id)) {
case MQTT_PROP_TYPE_STRING_PAIR:
if (i + 2 >= end) return 0;
prop->key.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
prop->key.buf = (char *) i + 2;
i += 2 + prop->key.len;
if (i + 2 >= end) return 0;
prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
prop->val.buf = (char *) i + 2;
if (i + 2 + prop->val.len >= end) return 0;
new_pos += 2 * sizeof(uint16_t) + prop->val.len + prop->key.len;
break;
case MQTT_PROP_TYPE_BYTE:
if (i + 1 >= end) return 0;
prop->iv = (uint8_t) i[0];
new_pos++;
break;
case MQTT_PROP_TYPE_SHORT:
if (i + 2 >= end) return 0;
prop->iv = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
new_pos += sizeof(uint16_t);
break;
case MQTT_PROP_TYPE_INT:
if (i + 4 >= end) return 0;
prop->iv = ((uint32_t) i[0] << 24) | ((uint32_t) i[1] << 16) |
((uint32_t) i[2] << 8) | i[3];
new_pos += sizeof(uint32_t);
break;
case MQTT_PROP_TYPE_STRING:
if (i + 2 >= end) return 0;
prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
prop->val.buf = (char *) i + 2;
if (i + 2 + prop->val.len >= end) return 0;
new_pos += 2 + prop->val.len;
break;
case MQTT_PROP_TYPE_BINARY_DATA:
if (i + 2 >= end) return 0;
prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
prop->val.buf = (char *) i + 2;
if (i + 2 + prop->val.len >= end) return 0;
new_pos += 2 + prop->val.len;
break;
case MQTT_PROP_TYPE_VARIABLE_INT:
len = decode_varint(i, (size_t) (end - i), (size_t *) &prop->iv);
new_pos = (!len) ? 0 : new_pos + len;
if (i + len >= end) return 0;
new_pos = (len == 0) ? 0 : new_pos + len;
break;
default:
new_pos = 0;
break;
}
return new_pos;
@@ -257,7 +273,8 @@ void mg_mqtt_login(struct mg_connection *c, const struct mg_mqtt_opts *opts) {
char client_id[21];
struct mg_str cid = opts->client_id;
size_t total_len = 7 + 1 + 2 + 2;
uint8_t hdr[8] = {0, 4, 'M', 'Q', 'T', 'T', opts->version, 0};
uint8_t hdr[8] = {0, 4, 'M', 'Q', 'T', 'T', 0, 0};
hdr[6] = opts->version;
if (cid.len == 0) {
mg_random_str(client_id, sizeof(client_id) - 1);
@@ -289,33 +306,41 @@ void mg_mqtt_login(struct mg_connection *c, const struct mg_mqtt_opts *opts) {
total_len += get_props_size(opts->will_props, opts->num_will_props);
}
mg_mqtt_send_header(c, MQTT_CMD_CONNECT, 0, (uint32_t) total_len);
mg_send(c, hdr, sizeof(hdr));
// keepalive == 0 means "do not disconnect us!"
mg_send_u16(c, mg_htons((uint16_t) opts->keepalive));
if (!mqtt_send_header(c, MQTT_CMD_CONNECT, 0, (uint32_t) total_len) ||
!mg_send(c, hdr, sizeof(hdr)) ||
!mg_send_u16(c, mg_htons((uint16_t) opts->keepalive)))
goto fail;
if (c->is_mqtt5) mg_send_mqtt_properties(c, opts->props, opts->num_props);
if (c->is_mqtt5 && !mg_send_mqtt_properties(c, opts->props, opts->num_props))
goto fail;
mg_send_u16(c, mg_htons((uint16_t) cid.len));
mg_send(c, cid.buf, cid.len);
if (!mg_send_u16(c, mg_htons((uint16_t) cid.len)) ||
!mg_send(c, cid.buf, cid.len))
goto fail;
if (hdr[7] & MQTT_HAS_WILL) {
if (c->is_mqtt5)
mg_send_mqtt_properties(c, opts->will_props, opts->num_will_props);
if (c->is_mqtt5 &&
!mg_send_mqtt_properties(c, opts->will_props, opts->num_will_props))
goto fail;
mg_send_u16(c, mg_htons((uint16_t) opts->topic.len));
mg_send(c, opts->topic.buf, opts->topic.len);
mg_send_u16(c, mg_htons((uint16_t) opts->message.len));
mg_send(c, opts->message.buf, opts->message.len);
}
if (opts->user.len > 0) {
mg_send_u16(c, mg_htons((uint16_t) opts->user.len));
mg_send(c, opts->user.buf, opts->user.len);
}
if (opts->pass.len > 0) {
mg_send_u16(c, mg_htons((uint16_t) opts->pass.len));
mg_send(c, opts->pass.buf, opts->pass.len);
if (!mg_send_u16(c, mg_htons((uint16_t) opts->topic.len)) ||
!mg_send(c, opts->topic.buf, opts->topic.len) ||
!mg_send_u16(c, mg_htons((uint16_t) opts->message.len)) ||
!mg_send(c, opts->message.buf, opts->message.len))
goto fail;
}
if (opts->user.len > 0 &&
(!mg_send_u16(c, mg_htons((uint16_t) opts->user.len)) ||
!mg_send(c, opts->user.buf, opts->user.len)))
goto fail;
if (opts->pass.len > 0 &&
(!mg_send_u16(c, mg_htons((uint16_t) opts->pass.len)) ||
!mg_send(c, opts->pass.buf, opts->pass.len)))
goto fail;
return;
fail:
mg_error(c, "OOM");
}
uint16_t mg_mqtt_pub(struct mg_connection *c, const struct mg_mqtt_opts *opts) {
@@ -330,36 +355,60 @@ uint16_t mg_mqtt_pub(struct mg_connection *c, const struct mg_mqtt_opts *opts) {
if (c->is_mqtt5) len += get_props_size(opts->props, opts->num_props);
if (opts->qos > 0 && id != 0) flags |= 1 << 3;
mg_mqtt_send_header(c, MQTT_CMD_PUBLISH, flags, (uint32_t) len);
mg_send_u16(c, mg_htons((uint16_t) opts->topic.len));
mg_send(c, opts->topic.buf, opts->topic.len);
if (!mqtt_send_header(c, MQTT_CMD_PUBLISH, flags, (uint32_t) len) ||
!mg_send_u16(c, mg_htons((uint16_t) opts->topic.len)) ||
!mg_send(c, opts->topic.buf, opts->topic.len))
goto fail;
if (opts->qos > 0) { // need to send 'id' field
if (id == 0) { // generate new one if not resending
if (++c->mgr->mqtt_id == 0) ++c->mgr->mqtt_id;
id = c->mgr->mqtt_id;
}
mg_send_u16(c, mg_htons(id));
if (!mg_send_u16(c, mg_htons(id))) goto fail;
}
if (c->is_mqtt5) mg_send_mqtt_properties(c, opts->props, opts->num_props);
if (c->is_mqtt5 && !mg_send_mqtt_properties(c, opts->props, opts->num_props))
goto fail;
if (opts->message.len > 0) mg_send(c, opts->message.buf, opts->message.len);
if (opts->message.len > 0 &&
!mg_send(c, opts->message.buf, opts->message.len))
goto fail;
return id;
fail:
mg_error(c, "OOM");
return id;
}
void mg_mqtt_sub(struct mg_connection *c, const struct mg_mqtt_opts *opts) {
static void mg_mqtt_sub_unsub(struct mg_connection *c,
const struct mg_mqtt_opts *opts, uint8_t cmd) {
uint8_t qos_ = opts->qos & 3;
bool is_sub = cmd == MQTT_CMD_SUBSCRIBE;
size_t plen = c->is_mqtt5 ? get_props_size(opts->props, opts->num_props) : 0;
size_t len = 2 + opts->topic.len + 2 + 1 + plen;
size_t len = 2 + opts->topic.len + 2 + (is_sub ? 1 : 0) + plen;
mg_mqtt_send_header(c, MQTT_CMD_SUBSCRIBE, 2, (uint32_t) len);
if (!mqtt_send_header(c, cmd, 2, (uint32_t) len)) goto fail;
if (++c->mgr->mqtt_id == 0) ++c->mgr->mqtt_id;
mg_send_u16(c, mg_htons(c->mgr->mqtt_id));
if (c->is_mqtt5) mg_send_mqtt_properties(c, opts->props, opts->num_props);
if (!mg_send_u16(c, mg_htons(c->mgr->mqtt_id))) goto fail;
mg_send_u16(c, mg_htons((uint16_t) opts->topic.len));
mg_send(c, opts->topic.buf, opts->topic.len);
mg_send(c, &qos_, sizeof(qos_));
if (c->is_mqtt5 && !mg_send_mqtt_properties(c, opts->props, opts->num_props))
goto fail;
if (!mg_send_u16(c, mg_htons((uint16_t) opts->topic.len)) ||
!mg_send(c, opts->topic.buf, opts->topic.len))
goto fail;
if (is_sub && !mg_send(c, &qos_, sizeof(qos_))) goto fail;
return;
fail:
mg_error(c, "OOM");
}
void mg_mqtt_sub(struct mg_connection *c, const struct mg_mqtt_opts *opts) {
mg_mqtt_sub_unsub(c, opts, MQTT_CMD_SUBSCRIBE);
}
void mg_mqtt_unsub(struct mg_connection *c, const struct mg_mqtt_opts *opts) {
mg_mqtt_sub_unsub(c, opts, MQTT_CMD_UNSUBSCRIBE);
}
int mg_mqtt_parse(const uint8_t *buf, size_t len, uint8_t version,
@@ -427,8 +476,7 @@ int mg_mqtt_parse(const uint8_t *buf, size_t len, uint8_t version,
m->data.len = (size_t) (end - p);
break;
}
default:
break;
default: break;
}
return MQTT_OK;
}
@@ -466,15 +514,16 @@ static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data) {
uint32_t remaining_len = sizeof(id);
if (c->is_mqtt5) remaining_len += 2; // 3.4.2
mg_mqtt_send_header(
c,
(uint8_t) (mm.qos == 2 ? MQTT_CMD_PUBREC : MQTT_CMD_PUBACK),
0, remaining_len);
mg_send(c, &id, sizeof(id));
if (!mqtt_send_header(c,
(uint8_t) (mm.qos == 2 ? MQTT_CMD_PUBREC
: MQTT_CMD_PUBACK),
0, remaining_len) ||
!mg_send(c, &id, sizeof(id)))
goto fail;
if (c->is_mqtt5) {
uint16_t zero = 0;
mg_send(c, &zero, sizeof(zero));
if (!mg_send(c, &zero, sizeof(zero))) goto fail;
}
}
mg_call(c, MG_EV_MQTT_MSG, &mm); // let the app handle qos stuff
@@ -483,15 +532,18 @@ static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data) {
case MQTT_CMD_PUBREC: { // MQTT5: 3.5.2-1 TODO(): variable header rc
uint16_t id = mg_ntohs(mm.id);
uint32_t remaining_len = sizeof(id); // MQTT5 3.6.2-1
mg_mqtt_send_header(c, MQTT_CMD_PUBREL, 2, remaining_len);
mg_send(c, &id, sizeof(id)); // MQTT5 3.6.1-1, flags = 2
if (!mqtt_send_header(c, MQTT_CMD_PUBREL, 2,
remaining_len) // MQTT5 3.6.1-1, flags = 2
|| !mg_send(c, &id, sizeof(id)))
goto fail;
break;
}
case MQTT_CMD_PUBREL: { // MQTT5: 3.6.2-1 TODO(): variable header rc
uint16_t id = mg_ntohs(mm.id);
uint32_t remaining_len = sizeof(id); // MQTT5 3.7.2-1
mg_mqtt_send_header(c, MQTT_CMD_PUBCOMP, 0, remaining_len);
mg_send(c, &id, sizeof(id));
if (!mqtt_send_header(c, MQTT_CMD_PUBCOMP, 0, remaining_len) ||
!mg_send(c, &id, sizeof(id)))
goto fail;
break;
}
}
@@ -503,6 +555,9 @@ static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data) {
}
}
(void) ev_data;
return;
fail:
mg_error(c, "OOM");
}
void mg_mqtt_ping(struct mg_connection *nc) {
@@ -517,24 +572,28 @@ void mg_mqtt_disconnect(struct mg_connection *c,
const struct mg_mqtt_opts *opts) {
size_t len = 0;
if (c->is_mqtt5) len = 1 + get_props_size(opts->props, opts->num_props);
mg_mqtt_send_header(c, MQTT_CMD_DISCONNECT, 0, (uint32_t) len);
if (!mqtt_send_header(c, MQTT_CMD_DISCONNECT, 0, (uint32_t) len)) goto fail;
if (c->is_mqtt5) {
uint8_t zero = 0;
mg_send(c, &zero, sizeof(zero)); // reason code
mg_send_mqtt_properties(c, opts->props, opts->num_props);
if (!mg_send(c, &zero, sizeof(zero)) // reason code
|| !mg_send_mqtt_properties(c, opts->props, opts->num_props))
goto fail;
}
return;
fail:
mg_error(c, "OOM");
}
struct mg_connection *mg_mqtt_connect(struct mg_mgr *mgr, const char *url,
const struct mg_mqtt_opts *opts,
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) {
struct mg_mqtt_opts empty;
memset(&empty, 0, sizeof(empty));
mg_mqtt_login(c, opts == NULL ? &empty : opts);
c->pfn = mqtt_cb;
}
return c;
}
+1
View File
@@ -104,6 +104,7 @@ struct mg_connection *mg_mqtt_listen(struct mg_mgr *mgr, const char *url,
void mg_mqtt_login(struct mg_connection *c, const struct mg_mqtt_opts *opts);
uint16_t mg_mqtt_pub(struct mg_connection *c, const struct mg_mqtt_opts *opts);
void mg_mqtt_sub(struct mg_connection *, const struct mg_mqtt_opts *opts);
void mg_mqtt_unsub(struct mg_connection *c, const struct mg_mqtt_opts *opts);
int mg_mqtt_parse(const uint8_t *, size_t, uint8_t, struct mg_mqtt_message *);
void mg_mqtt_send_header(struct mg_connection *, uint8_t cmd, uint8_t flags,
uint32_t len);
+72 -31
View File
@@ -1,7 +1,7 @@
#include "net.h"
#include "dns.h"
#include "fmt.h"
#include "log.h"
#include "net.h"
#include "printf.h"
#include "profile.h"
#include "timer.h"
@@ -9,8 +9,14 @@
size_t mg_vprintf(struct mg_connection *c, const char *fmt, va_list *ap) {
size_t old = c->send.len;
mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap);
return c->send.len - old;
size_t expected = mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap);
size_t actual = c->send.len - old;
if (actual != expected) {
mg_error(c, "OOM");
c->send.len = old;
actual = 0;
}
return actual;
}
size_t mg_printf(struct mg_connection *c, const char *fmt, ...) {
@@ -25,14 +31,14 @@ size_t mg_printf(struct mg_connection *c, const char *fmt, ...) {
static bool mg_atonl(struct mg_str str, struct mg_addr *addr) {
uint32_t localhost = mg_htonl(0x7f000001);
if (mg_strcasecmp(str, mg_str("localhost")) != 0) return false;
memcpy(addr->ip, &localhost, sizeof(uint32_t));
memcpy(addr->addr.ip, &localhost, sizeof(uint32_t));
addr->is_ip6 = false;
return true;
}
static bool mg_atone(struct mg_str str, struct mg_addr *addr) {
if (str.len > 0) return false;
memset(addr->ip, 0, sizeof(addr->ip));
memset(addr->addr.ip, 0, sizeof(addr->addr.ip));
addr->is_ip6 = false;
return true;
}
@@ -53,7 +59,7 @@ static bool mg_aton4(struct mg_str str, struct mg_addr *addr) {
}
}
if (num_dots != 3 || str.buf[i - 1] == '.') return false;
memcpy(&addr->ip, data, sizeof(data));
memcpy(&addr->addr.ip, data, sizeof(data));
addr->is_ip6 = false;
return true;
}
@@ -68,10 +74,10 @@ static bool mg_v4mapped(struct mg_str str, struct mg_addr *addr) {
}
// struct mg_str s = mg_str_n(&str.buf[7], str.len - 7);
if (!mg_aton4(mg_str_n(&str.buf[7], str.len - 7), addr)) return false;
memcpy(&ipv4, addr->ip, sizeof(ipv4));
memset(addr->ip, 0, sizeof(addr->ip));
addr->ip[10] = addr->ip[11] = 255;
memcpy(&addr->ip[12], &ipv4, 4);
memcpy(&ipv4, addr->addr.ip, sizeof(ipv4));
memset(addr->addr.ip, 0, sizeof(addr->addr.ip));
addr->addr.ip[10] = addr->addr.ip[11] = 255;
memcpy(&addr->addr.ip[12], &ipv4, 4);
addr->is_ip6 = true;
return true;
}
@@ -80,7 +86,7 @@ static bool mg_aton6(struct mg_str str, struct mg_addr *addr) {
size_t i, j = 0, n = 0, dc = 42;
addr->scope_id = 0;
if (str.len > 2 && str.buf[0] == '[') str.buf++, str.len -= 2;
if (mg_v4mapped(str, addr)) return true;
if (mg_v4mapped(str, addr)) return true; // sets addr->is_ip6
for (i = 0; i < str.len; i++) {
if ((str.buf[i] >= '0' && str.buf[i] <= '9') ||
(str.buf[i] >= 'a' && str.buf[i] <= 'f') ||
@@ -89,8 +95,8 @@ static bool mg_aton6(struct mg_str str, struct mg_addr *addr) {
if (i > j + 3) return false;
// MG_DEBUG(("%lu %lu [%.*s]", i, j, (int) (i - j + 1), &str.buf[j]));
mg_str_to_num(mg_str_n(&str.buf[j], i - j + 1), 16, &val, sizeof(val));
addr->ip[n] = (uint8_t) ((val >> 8) & 255);
addr->ip[n + 1] = (uint8_t) (val & 255);
addr->addr.ip[n] = (uint8_t) ((val >> 8) & 255);
addr->addr.ip[n + 1] = (uint8_t) (val & 255);
} else if (str.buf[i] == ':') {
j = i + 1;
if (i > 0 && str.buf[i - 1] == ':') {
@@ -100,18 +106,23 @@ static bool mg_aton6(struct mg_str str, struct mg_addr *addr) {
n += 2;
}
if (n > 14) return false;
addr->ip[n] = addr->ip[n + 1] = 0; // For trailing ::
} else if (str.buf[i] == '%') { // Scope ID, last in string
return mg_str_to_num(mg_str_n(&str.buf[i + 1], str.len - i - 1), 10,
&addr->scope_id, sizeof(uint8_t));
addr->addr.ip[n] = addr->addr.ip[n + 1] = 0; // For trailing ::
} else if (str.buf[i] == '%') { // Scope ID, last in string
if (mg_str_to_num(mg_str_n(&str.buf[i + 1], str.len - i - 1), 10,
&addr->scope_id, sizeof(uint8_t))) {
addr->is_ip6 = true;
return true;
} else {
return false;
}
} else {
return false;
}
}
if (n < 14 && dc == 42) return false;
if (n < 14) {
memmove(&addr->ip[dc + (14 - n)], &addr->ip[dc], n - dc + 2);
memset(&addr->ip[dc], 0, 14 - n);
memmove(&addr->addr.ip[dc + (14 - n)], &addr->addr.ip[dc], n - dc + 2);
memset(&addr->addr.ip[dc], 0, 14 - n);
}
addr->is_ip6 = true;
@@ -126,7 +137,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 *c =
(struct mg_connection *) calloc(1, sizeof(*c) + mgr->extraconnsize);
(struct mg_connection *) mg_calloc(1, sizeof(*c) + mgr->extraconnsize);
if (c != NULL) {
c->mgr = mgr;
c->send.align = c->recv.align = c->rtls.align = MG_IO_SIZE;
@@ -153,14 +164,19 @@ void mg_close_conn(struct mg_connection *c) {
mg_iobuf_free(&c->send);
mg_iobuf_free(&c->rtls);
mg_bzero((unsigned char *) c, sizeof(*c));
free(c);
mg_free(c);
}
struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *url,
mg_event_handler_t fn, void *fn_data) {
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) {
struct mg_connection *c = NULL;
if (url == NULL || url[0] == '\0') {
MG_ERROR(("null url"));
#if MG_ENABLE_TCPIP
} else if (mgr->ifp != NULL && mgr->ifp->state != MG_TCPIP_STATE_READY) {
MG_ERROR(("Network is down"));
#endif
} else if ((c = mg_alloc_conn(mgr)) == NULL) {
MG_ERROR(("OOM"));
} else {
@@ -170,22 +186,30 @@ struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *url,
c->fn = fn;
c->is_client = true;
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_DEBUG(("%lu %ld %s", c->id, c->fd, url));
mg_resolve(c, url);
}
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,
mg_event_handler_t fn, void *fn_data) {
struct mg_connection *c = NULL;
if ((c = mg_alloc_conn(mgr)) == NULL) {
MG_ERROR(("OOM %s", 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);
free(c);
mg_free(c);
c = NULL;
} else {
c->is_listening = 1;
@@ -193,8 +217,8 @@ struct mg_connection *mg_listen(struct mg_mgr *mgr, const char *url,
LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c);
c->fn = fn;
c->fn_data = fn_data;
c->is_tls = (mg_url_is_ssl(url) != 0);
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));
}
return c;
@@ -216,9 +240,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,
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) {
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);
}
return t;
@@ -235,7 +259,7 @@ long mg_io_recv(struct mg_connection *c, void *buf, size_t len) {
void mg_mgr_free(struct mg_mgr *mgr) {
struct mg_connection *c;
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
for (c = mgr->conns; c != NULL; c = c->next) c->is_closing = 1;
mg_mgr_poll(mgr, 0);
@@ -266,7 +290,7 @@ void mg_mgr_init(struct mg_mgr *mgr) {
// clang-format on
#elif MG_ENABLE_FREERTOS_TCP
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
// won't kill the whole process.
signal(SIGPIPE, SIG_IGN);
@@ -278,4 +302,21 @@ void mg_mgr_init(struct mg_mgr *mgr) {
mgr->dns4.url = "udp://8.8.8.8:53";
mgr->dns6.url = "udp://[2001:4860:4860::8888]:53";
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"));
}
#if MG_ENABLE_TCPIP
void mg_tcpip_mapip(struct mg_connection *, struct mg_addr *);
#endif
void mg_multicast_restore(struct mg_connection *c, uint8_t *from) {
memcpy(&c->rem, from, sizeof(c->rem));
#if MG_ENABLE_TCPIP
mg_tcpip_mapip(c, &c->rem);
#endif
}
+9 -1
View File
@@ -14,7 +14,11 @@ struct mg_dns {
};
struct mg_addr {
uint8_t ip[16]; // Holds IPv4 or IPv6 address, in network byte order
union { // Holds IPv4 or IPv6 address, in network byte order
uint8_t ip[16];
uint32_t ip4;
uint64_t ip6[2];
} addr;
uint16_t port; // TCP or UDP port in network byte order
uint8_t scope_id; // IPv6 scope ID
bool is_ip6; // True when address is IPv6 address
@@ -105,3 +109,7 @@ bool mg_wakeup(struct mg_mgr *, unsigned long id, const void *buf, size_t len);
bool mg_wakeup_init(struct mg_mgr *);
struct mg_timer *mg_timer_add(struct mg_mgr *mgr, uint64_t milliseconds,
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);
void mg_multicast_restore(struct mg_connection *c, uint8_t *from);
+1402 -444
View File
File diff suppressed because it is too large. Load diff
+85 -25
View File
@@ -1,6 +1,7 @@
#pragma once
#include "arch.h"
#include "l2.h"
#include "net.h"
#include "queue.h"
#include "str.h"
@@ -20,44 +21,58 @@ typedef void (*mg_tcpip_event_handler_t)(struct mg_tcpip_if *ifp, int ev,
void *ev_data);
enum {
MG_TCPIP_EV_ST_CHG, // state change uint8_t * (&ifp->state)
MG_TCPIP_EV_DHCP_DNS, // DHCP DNS assignment uint32_t *ipaddr
MG_TCPIP_EV_DHCP_SNTP, // DHCP SNTP assignment uint32_t *ipaddr
MG_TCPIP_EV_ARP, // Got ARP packet struct mg_str *
MG_TCPIP_EV_TIMER_1S, // 1 second timer NULL
MG_TCPIP_EV_WIFI_SCAN_RESULT, // Wi-Fi scan results struct mg_wifi_scan_bss_data *
MG_TCPIP_EV_WIFI_SCAN_END, // Wi-Fi scan has finished NULL
MG_TCPIP_EV_WIFI_CONNECT_ERR, // Wi-Fi connect has failed driver and chip specific
MG_TCPIP_EV_DRIVER, // Driver event driver specific
MG_TCPIP_EV_USER // Starting ID for user events
MG_TCPIP_EV_ST_CHG, // state change uint8_t * (&ifp->state)
MG_TCPIP_EV_DHCP_DNS, // DHCP DNS assignment uint32_t *ipaddr
MG_TCPIP_EV_DHCP_SNTP, // DHCP SNTP assignment uint32_t *ipaddr
MG_TCPIP_EV_ARP, // Got ARP packet struct mg_str *
MG_TCPIP_EV_TIMER_1S, // 1 second timer NULL
MG_TCPIP_EV_WIFI_SCAN_RESULT, // Wi-Fi scan results struct
// mg_wifi_scan_bss_data *
MG_TCPIP_EV_WIFI_SCAN_END, // Wi-Fi scan has finished NULL
MG_TCPIP_EV_WIFI_CONNECT_ERR, // Wi-Fi connect has failed driver and
// chip specific
MG_TCPIP_EV_DRIVER, // Driver event driver specific
MG_TCPIP_EV_ST6_CHG, // state6 change uint8_t *
// (&ifp->state6)
MG_TCPIP_EV_USER // Starting ID for user events
};
// Network interface
struct mg_tcpip_if {
uint8_t mac[6]; // MAC address. Must be set to a valid MAC
uint32_t ip, mask, gw; // IP address, mask, default gateway
struct mg_str tx; // Output (TX) buffer
bool enable_dhcp_client; // Enable DCHP client
bool enable_dhcp_server; // Enable DCHP server
bool enable_get_gateway; // DCHP server sets client as gateway
bool enable_req_dns; // DCHP client requests DNS server
bool enable_req_sntp; // DCHP client requests SNTP server
uint8_t mac[sizeof(struct mg_l2addr)]; // hw address. Set to a valid addr
uint32_t ip, mask, gw; // IP address, mask, default gateway
struct mg_str tx; // Output (TX) buffer
bool enable_dhcp_client; // Enable DCHP client
bool enable_dhcp_server; // Enable DCHP server
bool enable_get_gateway; // DCHP server sets client as gateway
bool enable_req_dns; // DCHP client requests DNS server
bool enable_req_sntp; // DCHP client requests SNTP server
bool enable_crc32_check; // Do a CRC check on RX frames and strip it
bool enable_mac_check; // Do a MAC check on RX frames
bool update_mac_hash_table; // Signal drivers to update MAC controller
struct mg_tcpip_driver *driver; // Low level driver
void *driver_data; // Driver-specific data
mg_tcpip_event_handler_t pfn; // Driver-specific event handler function
mg_tcpip_event_handler_t fn; // User-specified event handler function
struct mg_mgr *mgr; // Mongoose event manager
struct mg_queue recv_queue; // Receive queue
char dhcp_name[12]; // Name reported to DHCP, "mip" if unset
uint16_t mtu; // Interface MTU
#define MG_TCPIP_MTU_DEFAULT 1500
char dhcp_name[MG_TCPIP_DHCPNAME_SIZE]; // Name for DHCP, "mip" if unset
uint16_t mtu; // Interface link payload
uint16_t framesize; // Interface frame max length
#if MG_ENABLE_IPV6
uint64_t ip6ll[2], ip6[2]; // IPv6 link-local and global addresses,
uint8_t prefix[8]; // prefix,
uint8_t prefix_len; // prefix length,
uint64_t gw6[2]; // default gateway.
bool enable_slaac; // Enable IPv6 address autoconfiguration
bool enable_dhcp6_client; // Enable DCHPv6 client TODO()
#endif
// Internal state, user can use it but should not change it
uint8_t gwmac[6]; // Router's MAC
uint64_t now; // Current time
uint8_t gwmac[sizeof(struct mg_l2addr)]; // Router's hw address
enum mg_l2type l2type; // Ethernet, PPP, etc.
char *dns4_url; // DNS server URL
uint64_t now; // Current time
uint64_t timer_1000ms; // 1000 ms timer: for DHCP and link state
uint64_t lease_expire; // Lease expiration time, in ms
uint16_t eport; // Next ephemeral port
@@ -65,12 +80,18 @@ struct mg_tcpip_if {
volatile uint32_t nrecv; // Number of received frames
volatile uint32_t nsent; // Number of transmitted frames
volatile uint32_t nerr; // Number of driver errors
uint8_t state; // Current state
uint8_t state; // Current link and IPv4 state
#define MG_TCPIP_STATE_DOWN 0 // Interface is down
#define MG_TCPIP_STATE_UP 1 // Interface is up
#define MG_TCPIP_STATE_REQ 2 // Interface is up, DHCP REQUESTING state
#define MG_TCPIP_STATE_IP 3 // Interface is up and has an IP assigned
#define MG_TCPIP_STATE_READY 4 // Interface has fully come up, ready to work
bool gw_ready; // We've got a hw address for the router
#if MG_ENABLE_IPV6
uint8_t gw6mac[sizeof(struct mg_l2addr)]; // IPV6 Router's hw address
uint8_t state6; // Current IPv6 state
bool gw6_ready; // We've got a hw address for the IPv6 router
#endif
};
void mg_tcpip_init(struct mg_mgr *, struct mg_tcpip_if *);
@@ -94,6 +115,8 @@ extern struct mg_tcpip_driver mg_tcpip_driver_ppp;
extern struct mg_tcpip_driver mg_tcpip_driver_pico_w;
extern struct mg_tcpip_driver mg_tcpip_driver_rw612;
extern struct mg_tcpip_driver mg_tcpip_driver_cyw;
extern struct mg_tcpip_driver mg_tcpip_driver_nxp_wifi;
extern struct mg_tcpip_driver mg_tcpip_driver_st67w6;
// Drivers that require SPI, can use this SPI abstraction
struct mg_tcpip_spi {
@@ -103,4 +126,41 @@ struct mg_tcpip_spi {
uint8_t (*txn)(void *, uint8_t); // SPI transaction: write 1 byte, read reply
};
// Alignment and memory section requirements
#ifndef MG_8BYTE_ALIGNED
#if defined(__GNUC__)
#define MG_8BYTE_ALIGNED __attribute__((aligned((8U))))
#else
#define MG_8BYTE_ALIGNED
#endif // compiler
#endif // 8BYTE_ALIGNED
#ifndef MG_16BYTE_ALIGNED
#if defined(__GNUC__)
#define MG_16BYTE_ALIGNED __attribute__((aligned((16U))))
#else
#define MG_16BYTE_ALIGNED
#endif // compiler
#endif // 16BYTE_ALIGNED
#ifndef MG_32BYTE_ALIGNED
#if defined(__GNUC__)
#define MG_32BYTE_ALIGNED __attribute__((aligned((32U))))
#else
#define MG_32BYTE_ALIGNED
#endif // compiler
#endif // 32BYTE_ALIGNED
#ifndef MG_64BYTE_ALIGNED
#if defined(__GNUC__)
#define MG_64BYTE_ALIGNED __attribute__((aligned((64U))))
#else
#define MG_64BYTE_ALIGNED
#endif // compiler
#endif // 64BYTE_ALIGNED
#ifndef MG_ETH_RAM
#define MG_ETH_RAM
#endif
#endif
+2 -2
View File
@@ -17,8 +17,8 @@
#define MG_OTA_RT1060 302 // IMXRT1060
#define MG_OTA_RT1064 303 // IMXRT1064
#define MG_OTA_RT1170 304 // IMXRT1170
#define MG_OTA_MCXN 310 // MCXN947
#define MG_OTA_FRDM 320 // FRDM-RW612
#define MG_OTA_MCXN 310 // MCXN947
#define MG_OTA_RW612 320 // FRDM-RW612
#define MG_OTA_FLASH 900 // OTA via an internal flash
#define MG_OTA_ESP32 910 // ESP32 OTA implementation
#define MG_OTA_PICOSDK 920 // RP2040/2350 using Pico-SDK hardware_flash
+1 -1
View File
@@ -150,7 +150,7 @@ fwxit:
// 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) {
char *tmp = malloc(ss);
char *tmp = mg_calloc(1, ss);
// no stdlib calls here
for (size_t ofs = 0; ofs < s; ofs += ss) {
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,
size_t s,
size_t ss) {
char *tmp = malloc(ss);
char *tmp = mg_calloc(1, ss);
if (tmp == NULL) return;
#if PICO_RP2040
uint32_t xip[256 / sizeof(uint32_t)];
+1 -1
View File
@@ -2,7 +2,7 @@
#include "log.h"
#include "ota.h"
#if MG_OTA == MG_OTA_FRDM
#if MG_OTA == MG_OTA_RW612
MG_IRAM static bool mg_frdm_write(void *, const void *, size_t);
static bool mg_frdm_swap(void);
+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) {
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);
}
+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) {
#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);
}
+4
View File
@@ -184,6 +184,10 @@ bool mg_ota_begin(size_t new_firmware_size) {
// Using only the 1st bank (mapped to CM7)
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);
}
+38 -25
View File
@@ -1,25 +1,20 @@
#include "printf.h"
#include "fmt.h"
#include "printf.h"
#include "util.h"
size_t mg_queue_vprintf(struct mg_queue *q, const char *fmt, va_list *ap) {
size_t len = mg_snprintf(NULL, 0, fmt, ap);
char *buf;
if (len == 0 || mg_queue_book(q, &buf, len + 1) < len + 1) {
len = 0; // Nah. Not enough space
} else {
len = mg_vsnprintf((char *) buf, len + 1, fmt, ap);
mg_queue_add(q, len);
}
return len;
}
size_t mg_queue_printf(struct mg_queue *q, const char *fmt, ...) {
va_list ap;
char *buf;
size_t len;
va_start(ap, fmt);
len = mg_queue_vprintf(q, fmt, &ap);
va_end(ap);
va_list ap1, ap2;
va_start(ap1, fmt);
len = mg_vsnprintf(NULL, 0, fmt, &ap1);
va_end(ap1);
if (len == 0 || mg_queue_book(q, &buf, len + 1) < len + 1)
return 0; // Nah. Not enough space
va_start(ap2, fmt);
len = mg_vsnprintf(buf, len + 1, fmt, &ap2);
mg_queue_add(q, len);
va_end(ap2);
return len;
}
@@ -34,7 +29,7 @@ static void mg_pfn_iobuf_private(char ch, void *param, bool expand) {
}
}
static void mg_putchar_iobuf_static(char ch, void *param) {
void mg_pfn_iobuf_noresize(char ch, void *param) {
mg_pfn_iobuf_private(ch, param, false);
}
@@ -43,8 +38,10 @@ void mg_pfn_iobuf(char ch, void *param) {
}
size_t mg_vsnprintf(char *buf, size_t len, const char *fmt, va_list *ap) {
struct mg_iobuf io = {(uint8_t *) buf, len, 0, 0};
size_t n = mg_vxprintf(mg_putchar_iobuf_static, &io, fmt, ap);
struct mg_iobuf io = {0, 0, 0, 0};
size_t n;
io.buf = (uint8_t *) buf, io.size = len;
n = mg_vxprintf(mg_pfn_iobuf_noresize, &io, fmt, ap);
if (n < len) buf[n] = '\0';
return n;
}
@@ -101,8 +98,8 @@ size_t mg_print_ip6(void (*out)(char, void *), void *arg, va_list *ap) {
size_t mg_print_ip(void (*out)(char, void *), void *arg, va_list *ap) {
struct mg_addr *addr = va_arg(*ap, struct mg_addr *);
if (addr->is_ip6) return print_ip6(out, arg, (uint16_t *) addr->ip);
return print_ip4(out, arg, (uint8_t *) &addr->ip);
if (addr->is_ip6) return print_ip6(out, arg, (uint16_t *) addr->addr.ip);
return print_ip4(out, arg, (uint8_t *) &addr->addr.ip);
}
size_t mg_print_ip_port(void (*out)(char, void *), void *arg, va_list *ap) {
@@ -110,12 +107,27 @@ size_t mg_print_ip_port(void (*out)(char, void *), void *arg, va_list *ap) {
return mg_xprintf(out, arg, "%M:%hu", mg_print_ip, a, mg_ntohs(a->port));
}
size_t mg_print_mac(void (*out)(char, void *), void *arg, va_list *ap) {
uint8_t *p = va_arg(*ap, uint8_t *);
static size_t print_mac(void (*out)(char, void *), void *arg, uint8_t *p) {
return mg_xprintf(out, arg, "%02x:%02x:%02x:%02x:%02x:%02x", p[0], p[1], p[2],
p[3], p[4], p[5]);
}
size_t mg_print_mac(void (*out)(char, void *), void *arg, va_list *ap) {
uint8_t *p = va_arg(*ap, uint8_t *);
return print_mac(out, arg, p);
}
#if MG_ENABLE_TCPIP
size_t mg_print_l2addr(void (*out)(char, void *), void *arg, va_list *ap) {
enum mg_l2type type = (enum mg_l2type) va_arg(*ap, int);
if (type == MG_TCPIP_L2_ETH) {
uint8_t *p = va_arg(*ap, uint8_t *);
return print_mac(out, arg, p);
}
return 0;
}
#endif
static char mg_esc(int c, bool esc) {
const char *p, *esc1 = "\b\f\n\r\t\\\"", *esc2 = "bfnrt\\\"";
for (p = esc ? esc1 : esc2; *p != '\0'; p++) {
@@ -150,7 +162,8 @@ static size_t bcpy(void (*out)(char, void *), void *arg, uint8_t *buf,
for (i = 0; i < len; i += 3) {
uint8_t c1 = buf[i], c2 = i + 1 < len ? buf[i + 1] : 0,
c3 = i + 2 < len ? buf[i + 2] : 0;
char tmp[4] = {t[c1 >> 2], t[(c1 & 3) << 4 | (c2 >> 4)], '=', '='};
char tmp[4] = {0, 0, '=', '='};
tmp[0] = t[c1 >> 2], tmp[1] = t[(c1 & 3) << 4 | (c2 >> 4)];
if (i + 1 < len) tmp[2] = t[(c2 & 15) << 2 | (c3 >> 6)];
if (i + 2 < len) tmp[3] = t[c3 & 63];
for (j = 0; j < sizeof(tmp) && tmp[j] != '\0'; j++) out(tmp[j], arg);
+4 -3
View File
@@ -9,7 +9,6 @@ size_t mg_vsnprintf(char *buf, size_t len, const char *fmt, va_list *ap);
size_t mg_snprintf(char *, size_t, const char *fmt, ...);
char *mg_vmprintf(const char *fmt, va_list *ap);
char *mg_mprintf(const char *fmt, ...);
size_t mg_queue_vprintf(struct mg_queue *, const char *fmt, va_list *);
size_t mg_queue_printf(struct mg_queue *, const char *fmt, ...);
// %M print helper functions
@@ -21,10 +20,12 @@ size_t mg_print_ip_port(void (*out)(char, void *), void *arg, va_list *ap);
size_t mg_print_ip4(void (*out)(char, void *), void *arg, va_list *ap);
size_t mg_print_ip6(void (*out)(char, void *), void *arg, va_list *ap);
size_t mg_print_mac(void (*out)(char, void *), void *arg, va_list *ap);
size_t mg_print_l2addr(void (*out)(char, void *), void *arg, va_list *ap);
// Various output functions
void mg_pfn_iobuf(char ch, void *param); // param: struct mg_iobuf *
void mg_pfn_stdout(char c, void *param); // param: ignored
void mg_pfn_iobuf(char ch, void *param); // param: struct mg_iobuf *
void mg_pfn_iobuf_noresize(char ch, void *param); // param: struct mg_iobuf *
void mg_pfn_stdout(char c, void *param); // param: ignored
// A helper macro for printing JSON: mg_snprintf(buf, len, "%m", MG_ESC("hi"))
#define MG_ESC(str) mg_print_esc, 0, (str)
+4 -3
View File
@@ -1,9 +1,10 @@
#include "rpc.h"
#include "printf.h"
#include "util.h"
void mg_rpc_add(struct mg_rpc **head, struct mg_str method,
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) {
rpc->method = mg_strdup(method);
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) {
if (r->fn == fn || fn == NULL) {
*head = r->next;
free((void *) r->method.buf);
free(r);
mg_free((void *) r->method.buf);
mg_free(r);
} else {
head = &(*head)->next;
}
+43 -1
View File
@@ -180,6 +180,35 @@ void mg_hmac_sha256(uint8_t dst[32], uint8_t *key, size_t keysz, uint8_t *data,
#define sig164(x) (rotr64(x, 19) ^ rotr64(x, 61) ^ ((x) >> 6))
static const uint64_t mg_sha256_k2[80] = {
#if defined(__DCC__)
0x428a2f98d728ae22ull, 0x7137449123ef65cdull, 0xb5c0fbcfec4d3b2full,
0xe9b5dba58189dbbcull, 0x3956c25bf348b538ull, 0x59f111f1b605d019ull,
0x923f82a4af194f9bull, 0xab1c5ed5da6d8118ull, 0xd807aa98a3030242ull,
0x12835b0145706fbeull, 0x243185be4ee4b28cull, 0x550c7dc3d5ffb4e2ull,
0x72be5d74f27b896full, 0x80deb1fe3b1696b1ull, 0x9bdc06a725c71235ull,
0xc19bf174cf692694ull, 0xe49b69c19ef14ad2ull, 0xefbe4786384f25e3ull,
0x0fc19dc68b8cd5b5ull, 0x240ca1cc77ac9c65ull, 0x2de92c6f592b0275ull,
0x4a7484aa6ea6e483ull, 0x5cb0a9dcbd41fbd4ull, 0x76f988da831153b5ull,
0x983e5152ee66dfabull, 0xa831c66d2db43210ull, 0xb00327c898fb213full,
0xbf597fc7beef0ee4ull, 0xc6e00bf33da88fc2ull, 0xd5a79147930aa725ull,
0x06ca6351e003826full, 0x142929670a0e6e70ull, 0x27b70a8546d22ffcull,
0x2e1b21385c26c926ull, 0x4d2c6dfc5ac42aedull, 0x53380d139d95b3dfull,
0x650a73548baf63deull, 0x766a0abb3c77b2a8ull, 0x81c2c92e47edaee6ull,
0x92722c851482353bull, 0xa2bfe8a14cf10364ull, 0xa81a664bbc423001ull,
0xc24b8b70d0f89791ull, 0xc76c51a30654be30ull, 0xd192e819d6ef5218ull,
0xd69906245565a910ull, 0xf40e35855771202aull, 0x106aa07032bbd1b8ull,
0x19a4c116b8d2d0c8ull, 0x1e376c085141ab53ull, 0x2748774cdf8eeb99ull,
0x34b0bcb5e19b48a8ull, 0x391c0cb3c5c95a63ull, 0x4ed8aa4ae3418acbull,
0x5b9cca4f7763e373ull, 0x682e6ff3d6b2b8a3ull, 0x748f82ee5defb2fcull,
0x78a5636f43172f60ull, 0x84c87814a1f0ab72ull, 0x8cc702081a6439ecull,
0x90befffa23631e28ull, 0xa4506cebde82bde9ull, 0xbef9a3f7b2c67915ull,
0xc67178f2e372532bull, 0xca273eceea26619cull, 0xd186b8c721c0c207ull,
0xeada7dd6cde0eb1eull, 0xf57d4f7fee6ed178ull, 0x06f067aa72176fbaull,
0x0a637dc5a2c898a6ull, 0x113f9804bef90daeull, 0x1b710b35131c471bull,
0x28db77f523047d84ull, 0x32caab7b40c72493ull, 0x3c9ebe0a15c9bebcull,
0x431d67c49c100d4cull, 0x4cc5d4becb3e42b6ull, 0x597f299cfc657e2aull,
0x5fcb6fab3ad6faecull, 0x6c44198c4a475817ull
#else
0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f,
0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019,
0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242,
@@ -206,7 +235,9 @@ static const uint64_t mg_sha256_k2[80] = {
0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc,
0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a,
0x5fcb6fab3ad6faec, 0x6c44198c4a475817};
0x5fcb6fab3ad6faec, 0x6c44198c4a475817
#endif
};
static void mg_sha384_transform(mg_sha384_ctx *ctx, const uint8_t data[]) {
uint64_t m[80];
@@ -257,6 +288,16 @@ void mg_sha384_init(mg_sha384_ctx *ctx) {
ctx->datalen = 0;
ctx->bitlen[0] = 0;
ctx->bitlen[1] = 0;
#if defined(__DCC__)
ctx->state[0] = 0xcbbb9d5dc1059ed8ull;
ctx->state[1] = 0x629a292a367cd507ull;
ctx->state[2] = 0x9159015a3070dd17ull;
ctx->state[3] = 0x152fecd8f70e5939ull;
ctx->state[4] = 0x67332667ffc00b31ull;
ctx->state[5] = 0x8eb44a8768581511ull;
ctx->state[6] = 0xdb0c2e0d64f98fa7ull;
ctx->state[7] = 0x47b5481dbefa4fa4ull;
#else
ctx->state[0] = 0xcbbb9d5dc1059ed8;
ctx->state[1] = 0x629a292a367cd507;
ctx->state[2] = 0x9159015a3070dd17;
@@ -265,6 +306,7 @@ void mg_sha384_init(mg_sha384_ctx *ctx) {
ctx->state[5] = 0x8eb44a8768581511;
ctx->state[6] = 0xdb0c2e0d64f98fa7;
ctx->state[7] = 0x47b5481dbefa4fa4;
#endif
}
void mg_sha384_update(mg_sha384_ctx *ctx, const uint8_t *data, size_t len) {
+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,
mg_event_handler_t fn, void *fnd) {
struct mg_connection *c = NULL;
mg_event_handler_t fn, void *fn_data) {
if (url == NULL) url = "udp://time.google.com:123";
if ((c = mg_connect(mgr, url, fn, fnd)) != NULL) {
c->pfn = sntp_cb;
sntp_cb(c, MG_EV_OPEN, (void *) url);
}
return c;
return mg_connect_svc(mgr, url, fn, fn_data, sntp_cb, NULL);
}
+72 -29
View File
@@ -57,13 +57,13 @@ static socklen_t tousa(struct mg_addr *a, union usa *usa) {
memset(usa, 0, sizeof(*usa));
usa->sin.sin_family = AF_INET;
usa->sin.sin_port = a->port;
memcpy(&usa->sin.sin_addr, a->ip, sizeof(uint32_t));
memcpy(&usa->sin.sin_addr, a->addr.ip, sizeof(uint32_t));
#if MG_ENABLE_IPV6
if (a->is_ip6) {
usa->sin.sin_family = AF_INET6;
usa->sin6.sin6_port = a->port;
usa->sin6.sin6_scope_id = a->scope_id;
memcpy(&usa->sin6.sin6_addr, a->ip, sizeof(a->ip));
memcpy(&usa->sin6.sin6_addr, a->addr.ip, sizeof(a->addr.ip));
len = sizeof(usa->sin6);
}
#endif
@@ -72,15 +72,17 @@ static socklen_t tousa(struct mg_addr *a, union usa *usa) {
static void tomgaddr(union usa *usa, struct mg_addr *a, bool is_ip6) {
a->is_ip6 = is_ip6;
a->port = usa->sin.sin_port;
memcpy(&a->ip, &usa->sin.sin_addr, sizeof(uint32_t));
#if MG_ENABLE_IPV6
if (is_ip6) {
memcpy(a->ip, &usa->sin6.sin6_addr, sizeof(a->ip));
memcpy(a->addr.ip, &usa->sin6.sin6_addr, sizeof(a->addr.ip));
a->port = usa->sin6.sin6_port;
a->scope_id = (uint8_t) usa->sin6.sin6_scope_id;
}
} else
#endif
{
a->port = usa->sin.sin_port;
memcpy(&a->addr.ip, &usa->sin.sin_addr, sizeof(uint32_t));
}
}
static void setlocaddr(MG_SOCKET_TYPE fd, struct mg_addr *addr) {
@@ -91,6 +93,29 @@ static void setlocaddr(MG_SOCKET_TYPE fd, struct mg_addr *addr) {
}
}
// Get the local 'addr' the stack will use to connect to 'to'
void mg_getlocaddr(struct mg_connection *c, struct mg_addr *to, struct mg_addr *addr);
void mg_getlocaddr(struct mg_connection *c, struct mg_addr *to, struct mg_addr *addr) {
union usa usa;
socklen_t slen;
MG_SOCKET_TYPE fd;
int rc, af = to->is_ip6 ? AF_INET6 : AF_INET;
fd = socket(af, SOCK_DGRAM, IPPROTO_UDP);
if (fd == MG_INVALID_SOCKET) {
mg_error(c, "socket(): %d", MG_SOCK_ERR(-1));
return;
}
// NOTE(): TI-RTOS NDK may require binding
slen = tousa(to, &usa);
if ((rc = connect(fd, &usa.sa, slen)) != 0) {
mg_error(c, "connect: %d", MG_SOCK_ERR(rc));
return;
}
setlocaddr(fd, addr);
closesocket(fd);
}
static void iolog(struct mg_connection *c, char *buf, long n, bool r) {
if (n == MG_IO_WAIT) {
// Do nothing
@@ -141,7 +166,9 @@ bool mg_send(struct mg_connection *c, const void *buf, size_t len) {
iolog(c, (char *) buf, n, false);
return n > 0;
} else {
return mg_iobuf_add(&c->send, c->send.len, buf, len);
return len == 0 || mg_iobuf_add(&c->send, c->send.len, buf, len) > 0;
// returning 0 means an OOM condition (iobuf couldn't resize), yet this is
// so far recoverable, let the caller decide
}
}
@@ -160,8 +187,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;
#elif MG_ENABLE_LWIP
lwip_fcntl(fd, F_SETFL, O_NONBLOCK);
#elif MG_ARCH == MG_ARCH_AZURERTOS
fcntl(fd, F_SETFL, O_NONBLOCK);
#elif MG_ARCH == MG_ARCH_THREADX
// 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
int val = 0;
setsockopt(fd, SOL_SOCKET, SO_BLOCKING, &val, sizeof(val));
@@ -179,19 +208,24 @@ static void mg_set_non_blocking_mode(MG_SOCKET_TYPE fd) {
void mg_multicast_add(struct mg_connection *c, char *ip);
void mg_multicast_add(struct mg_connection *c, char *ip) {
#if MG_ENABLE_RL
#error UNSUPPORTED
MG_ERROR(("unsupported"));
#elif MG_ENABLE_FREERTOS_TCP
// TODO(): prvAllowIPPacketIPv4()
#else
// lwIP, Unix, Windows, Zephyr(, AzureRTOS ?)
// lwIP, Unix, Windows, Zephyr 4+(, AzureRTOS ?)
#if MG_ENABLE_LWIP && !LWIP_IGMP
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
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(ip);
mreq.imr_interface.s_addr = mg_htonl(INADDR_ANY);
setsockopt(FD(c), IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq));
#endif
setsockopt(FD(c), IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq,
sizeof(mreq));
#endif // !Zephyr
#endif // !lwIP
#endif
}
@@ -309,9 +343,9 @@ static void read_conn(struct mg_connection *c) {
if (n == MG_IO_ERR || n == MG_IO_RESET) { // Windows, see #3031
if (c->rtls.len == 0 || m < 0) {
// Close only when we have fully drained both rtls and TLS buffers
c->is_closing = 1; // or there's nothing we can do about it.
if (m < 0) m = MG_IO_ERR; // but return last record data, see #3104
} else { // see #2885
c->is_closing = 1; // or there's nothing we can do about it.
if (m < 0) m = MG_IO_ERR; // but return last record data, see #3104
} else { // see #2885
// TLS buffer is capped to max record size, even though, there can
// be more than one record, give TLS a chance to process them.
}
@@ -332,6 +366,7 @@ static void write_conn(struct mg_connection *c) {
char *buf = (char *) c->send.buf;
size_t len = c->send.len;
long n = c->is_tls ? mg_tls_send(c, buf, len) : mg_io_send(c, buf, len);
// TODO(): mg_tls_send() may return 0 forever on steady OOM
MG_DEBUG(("%lu %ld snd %ld/%ld rcv %ld/%ld n=%ld err=%d", c->id, c->fd,
(long) c->send.len, (long) c->send.size, (long) c->recv.len,
(long) c->recv.size, n, MG_SOCK_ERR(n)));
@@ -361,13 +396,14 @@ static void connect_conn(struct mg_connection *c) {
mg_call(c, MG_EV_CONNECT, NULL);
MG_EPOLL_MOD(c, 0);
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 {
mg_error(c, "socket error");
}
}
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
(void) c;
#else
@@ -412,8 +448,9 @@ void mg_connect_resolved(struct mg_connection *c) {
rc = connect(FD(c), &usa.sa, slen); // Attempt to connect
if (rc == 0) { // Success
setlocaddr(FD(c), &c->loc);
mg_call(c, MG_EV_CONNECT, NULL); // Send MG_EV_CONNECT to the user
} else if (MG_SOCK_PENDING(rc)) { // Need to wait for TCP handshake
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
MG_DEBUG(("%lu %ld -> %M pend", c->id, c->fd, mg_print_ip_port, &c->rem));
c->is_connecting = 1;
} else {
@@ -438,8 +475,8 @@ static void accept_conn(struct mg_mgr *mgr, struct mg_connection *lsn) {
socklen_t sa_len = sizeof(usa);
MG_SOCKET_TYPE fd = raccept(FD(lsn), &usa, &sa_len);
if (fd == MG_INVALID_SOCKET) {
#if MG_ARCH == MG_ARCH_AZURERTOS || defined(__ECOS)
// AzureRTOS, in non-block socket mode can mark listening socket readable
#if MG_ARCH == MG_ARCH_THREADX || defined(__ECOS)
// NetxDuo, in non-block socket mode can mark listening socket readable
// even it is not. See comment for 'select' func implementation in
// nx_bsd.c That's not an error, just should try later
if (errno != EAGAIN)
@@ -463,15 +500,17 @@ static void accept_conn(struct mg_mgr *mgr, struct mg_connection *lsn) {
setsockopts(c);
c->is_accepted = 1;
c->is_hexdumping = lsn->is_hexdumping;
c->loc = lsn->loc;
setlocaddr(fd, &c->loc); // set local addr to where the client connected to
c->pfn = lsn->pfn;
c->pfn_data = lsn->pfn_data;
c->fn = lsn->fn;
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,
&c->rem, mg_print_ip_port, &c->loc));
mg_call(c, MG_EV_OPEN, 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 +616,7 @@ static void mg_iotest(struct mg_mgr *mgr, int ms) {
}
}
#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;
fd_set rset, wset, eset;
MG_SOCKET_TYPE maxfd = 0;
@@ -593,16 +632,16 @@ static void mg_iotest(struct mg_mgr *mgr, int ms) {
FD_SET(FD(c), &eset);
if (can_read(c)) FD_SET(FD(c), &rset);
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 (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 (maxfd == 0) Sleep(ms); // On Windows, select fails if no sockets
#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
FD_ZERO(&rset);
FD_ZERO(&wset);
@@ -611,7 +650,12 @@ static void mg_iotest(struct mg_mgr *mgr, int ms) {
for (c = mgr->conns; c != NULL; c = c->next) {
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");
#endif
} else {
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);
@@ -734,11 +778,10 @@ void mg_mgr_poll(struct mg_mgr *mgr, int ms) {
if (c->is_readable) accept_conn(mgr, c);
} else if (c->is_connecting) {
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 {
if (c->is_readable) read_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;
+27 -13
View File
@@ -1,6 +1,7 @@
#include "ssi.h"
#include "log.h"
#include "printf.h"
#include "ssi.h"
#include "util.h"
#ifndef MG_MAX_SSI_DEPTH
#define MG_MAX_SSI_DEPTH 5
@@ -30,31 +31,35 @@ static char *mg_ssi(const char *path, const char *root, int depth) {
mg_snprintf(tmp, sizeof(tmp), "%.*s%s", (int) (p - path), path, arg);
if (depth < MG_MAX_SSI_DEPTH &&
(data = mg_ssi(tmp, root, depth + 1)) != NULL) {
mg_iobuf_add(&b, b.len, data, strlen(data));
free(data);
size_t datalen = strlen(data);
size_t ret = mg_iobuf_add(&b, b.len, data, datalen);
mg_free(data);
if (datalen > 0 && ret == 0) goto fail;
} else {
MG_ERROR(("%s: file=%s error or too deep", path, arg));
}
} // TODO(): or OOM at recursive call
} else if (sscanf(buf, "<!--#include virtual=\"%[^\"]", arg) > 0) {
char tmp[MG_PATH_MAX + MG_SSI_BUFSIZ + 10], *data;
mg_snprintf(tmp, sizeof(tmp), "%s%s", root, arg);
if (depth < MG_MAX_SSI_DEPTH &&
(data = mg_ssi(tmp, root, depth + 1)) != NULL) {
mg_iobuf_add(&b, b.len, data, strlen(data));
free(data);
size_t datalen = strlen(data);
size_t ret = mg_iobuf_add(&b, b.len, data, datalen);
mg_free(data);
if (datalen > 0 && ret == 0) goto fail;
} else {
MG_ERROR(("%s: virtual=%s error or too deep", path, arg));
}
} // TODO(): or OOM at recursive call
} else {
// Unknown SSI tag
MG_ERROR(("Unknown SSI tag: %.*s", (int) len, buf));
mg_iobuf_add(&b, b.len, buf, len);
if (len > 0 && mg_iobuf_add(&b, b.len, buf, len) == 0) goto fail;
}
intag = 0;
len = 0;
} else if (ch == '<') {
intag = 1;
if (len > 0) mg_iobuf_add(&b, b.len, buf, len);
if (len > 0 && mg_iobuf_add(&b, b.len, buf, len) == 0) goto fail;
len = 0;
buf[len++] = (char) (ch & 0xff);
} else if (intag) {
@@ -68,26 +73,35 @@ static char *mg_ssi(const char *path, const char *root, int depth) {
} else {
buf[len++] = (char) (ch & 0xff);
if (len >= sizeof(buf)) {
mg_iobuf_add(&b, b.len, buf, len);
if (mg_iobuf_add(&b, b.len, buf, len) == 0) goto fail;
len = 0;
}
}
}
if (len > 0) mg_iobuf_add(&b, b.len, buf, len);
if (b.len > 0) mg_iobuf_add(&b, b.len, "", 1); // nul-terminate
if (len > 0 && mg_iobuf_add(&b, b.len, buf, len) == 0) goto fail;
if (b.len > 0 && mg_iobuf_add(&b, b.len, "", 1) == 0) // nul-terminate
goto fail;
fclose(fp);
}
(void) depth;
(void) root;
return (char *) b.buf;
fail:
fclose(fp);
return NULL;
}
void mg_http_serve_ssi(struct mg_connection *c, const char *root,
const char *fullpath) {
const char *headers = "Content-Type: text/html; charset=utf-8\r\n";
char *data = mg_ssi(fullpath, root, 0);
if (data == NULL) {
mg_error(c, "OOM");
return;
}
mg_http_reply(c, 200, headers, "%s", data == NULL ? "" : data);
free(data);
mg_free(data);
}
#else
void mg_http_serve_ssi(struct mg_connection *c, const char *root,
+10 -6
View File
@@ -1,12 +1,15 @@
#include "str.h"
#include "util.h"
struct mg_str mg_str_s(const char *s) {
struct mg_str str = {(char *) s, s == NULL ? 0 : strlen(s)};
struct mg_str str;
str.buf = (char *) s, str.len = (s == NULL) ? 0 : strlen(s);
return str;
}
struct mg_str mg_str_n(const char *s, size_t n) {
struct mg_str str = {(char *) s, n};
struct mg_str str;
str.buf = (char *) s, str.len = n;
return str;
}
@@ -26,7 +29,7 @@ int mg_casecmp(const char *s1, const char *s2) {
struct mg_str mg_strdup(const struct mg_str s) {
struct mg_str r = {NULL, 0};
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) {
memcpy(sc, s.buf, s.len);
sc[s.len] = '\0';
@@ -84,7 +87,9 @@ bool mg_match(struct mg_str s, struct mg_str p, struct mg_str *caps) {
} else if (i < p.len && (p.buf[i] == '*' || p.buf[i] == '#')) {
if (caps && !caps->buf) caps->len = 0, caps->buf = &s.buf[j]; // Init cap
ni = i++, nj = j + 1;
} else if (nj > 0 && nj <= s.len && (p.buf[ni] == '#' || s.buf[j] != '/')) {
} else if (nj > 0 && nj <= s.len &&
((ni < p.len && p.buf[ni] == '#') ||
(j < s.len && s.buf[j] != '/'))) {
i = ni, j = nj;
if (caps && caps->buf == NULL && caps->len == 0) {
caps--, caps->len = 0; // Restart previous cap
@@ -165,8 +170,7 @@ bool mg_str_to_num(struct mg_str str, int base, void *val, size_t val_len) {
i++, ndigits++;
}
break;
default:
return false;
default: return false;
}
if (ndigits == 0) return false;
if (i != str.len) return false;
+2 -1
View File
@@ -1,5 +1,6 @@
#include "arch.h"
#include "timer.h"
#include "util.h"
void mg_timer_init(struct mg_timer **head, struct mg_timer *t, uint64_t ms,
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 (!(t->flags & MG_TIMER_REPEAT) && (t->flags & MG_TIMER_AUTODELETE)) {
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_RUN_NOW 2 // Call immediately when timer is set
#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 *arg; // Function argument
struct mg_timer *next; // Linkage
+2
View File
@@ -28,11 +28,13 @@ void mg_tls_free(struct mg_connection *);
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);
size_t mg_tls_pending(struct mg_connection *);
void mg_tls_flush(struct mg_connection *);
void mg_tls_handshake(struct mg_connection *);
// Private
void mg_tls_ctx_init(struct mg_mgr *);
void mg_tls_ctx_free(struct mg_mgr *);
#define MG_IS_DER(buf) (((uint8_t *) (buf))[0] == 0x30) // DER begins with 0x30
// Low-level IO primives used by TLS layer
enum { MG_IO_ERR = -1, MG_IO_WAIT = -2, MG_IO_RESET = -3 };
+96 -84
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
/******************************************************************************/
@@ -27,11 +30,8 @@
#define MG_ENCRYPT 1 // specify whether we're encrypting
#define MG_DECRYPT 0 // or decrypting
#include "arch.h"
#include "tls.h"
#include "tls_aes128.h"
#if MG_TLS == MG_TLS_BUILTIN
/******************************************************************************
* AES_INIT_KEYGEN_TABLES : MUST be called once before any AES use
******************************************************************************/
@@ -40,45 +40,47 @@ static void aes_init_keygen_tables(void);
/******************************************************************************
* AES_SETKEY : called to expand the key for encryption or decryption
******************************************************************************/
static int aes_setkey(aes_context *ctx, // pointer to context
int mode, // 1 or 0 for Encrypt/Decrypt
const unsigned char *key, // AES input key
unsigned int keysize); // size in bytes (must be 16, 24, 32 for
// 128, 192 or 256-bit keys respectively)
// returns 0 for success
static int aes_setkey(
aes_context *ctx, // pointer to context
int mode, // 1 or 0 for Encrypt/Decrypt
const unsigned char *key, // AES input key
unsigned int keysize); // size in bytes (must be 16, 24, 32 for
// 128, 192 or 256-bit keys respectively)
// returns 0 for success
/******************************************************************************
* AES_CIPHER : called to encrypt or decrypt ONE 128-bit block of data
******************************************************************************/
static int aes_cipher(aes_context *ctx, // pointer to context
const unsigned char input[16], // 128-bit block to en/decipher
unsigned char output[16]); // 128-bit output result block
// returns 0 for success
static int aes_cipher(
aes_context *ctx, // pointer to context
const unsigned char input[16], // 128-bit block to en/decipher
unsigned char output[16]); // 128-bit output result block
// returns 0 for success
/******************************************************************************
* GCM_CONTEXT : GCM context / holds keytables, instance data, and AES ctx
******************************************************************************/
typedef struct {
int mode; // cipher direction: encrypt/decrypt
uint64_t len; // cipher data length processed so far
uint64_t add_len; // total add data length
uint64_t HL[16]; // precalculated lo-half HTable
uint64_t HH[16]; // precalculated hi-half HTable
int mode; // cipher direction: encrypt/decrypt
uint64_t len; // cipher data length processed so far
uint64_t add_len; // total add data length
uint64_t HL[16]; // precalculated lo-half HTable
uint64_t HH[16]; // precalculated hi-half HTable
unsigned char base_ectr[16]; // first counter-mode cipher output for tag
unsigned char y[16]; // the current cipher-input IV|Counter value
unsigned char buf[16]; // buf working value
aes_context aes_ctx; // cipher context used
aes_context aes_ctx; // cipher context used
} gcm_context;
/******************************************************************************
* GCM_SETKEY : sets the GCM (and AES) keying material for use
******************************************************************************/
static int gcm_setkey(
gcm_context *ctx, // caller-provided context ptr
gcm_context *ctx, // caller-provided context ptr
const unsigned char *key, // pointer to cipher key
const unsigned int keysize // size in bytes (must be 16, 24, 32 for
// 128, 192 or 256-bit keys respectively)
); // returns 0 for success
// 128, 192 or 256-bit keys respectively)
); // returns 0 for success
/******************************************************************************
*
@@ -98,17 +100,17 @@ static int gcm_setkey(
*
******************************************************************************/
static int gcm_crypt_and_tag(
gcm_context *ctx, // gcm context with key already setup
int mode, // cipher direction: MG_ENCRYPT (1) or MG_DECRYPT (0)
gcm_context *ctx, // gcm context with key already setup
int mode, // cipher direction: MG_ENCRYPT (1) or MG_DECRYPT (0)
const unsigned char *iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12
size_t iv_len, // byte length if the IV. should always be 12
const unsigned char *add, // pointer to the non-ciphered additional data
size_t add_len, // byte length of the additional AEAD data
size_t add_len, // byte length of the additional AEAD data
const unsigned char *input, // pointer to the cipher data source
unsigned char *output, // pointer to the cipher data destination
size_t length, // byte length of the cipher data
size_t length, // byte length of the cipher data
unsigned char *tag, // pointer to the tag to be generated
size_t tag_len); // byte length of the tag to be generated
size_t tag_len); // byte length of the tag to be generated
/******************************************************************************
*
@@ -119,12 +121,12 @@ static int gcm_crypt_and_tag(
*
******************************************************************************/
static int gcm_start(
gcm_context *ctx, // pointer to user-provided GCM context
int mode, // MG_ENCRYPT (1) or MG_DECRYPT (0)
gcm_context *ctx, // pointer to user-provided GCM context
int mode, // MG_ENCRYPT (1) or MG_DECRYPT (0)
const unsigned char *iv, // pointer to initialization vector
size_t iv_len, // IV length in bytes (should == 12)
size_t iv_len, // IV length in bytes (should == 12)
const unsigned char *add, // pointer to additional AEAD data (NULL if none)
size_t add_len); // length of additional AEAD data (bytes)
size_t add_len); // length of additional AEAD data (bytes)
/******************************************************************************
*
@@ -140,7 +142,7 @@ static int gcm_start(
static int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
size_t length, // length, in bytes, of data to process
const unsigned char *input, // pointer to source data
unsigned char *output); // pointer to destination data
unsigned char *output); // pointer to destination data
/******************************************************************************
*
@@ -151,9 +153,9 @@ static int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
*
******************************************************************************/
static int gcm_finish(
gcm_context *ctx, // pointer to user-provided GCM context
unsigned char *tag, // ptr to tag buffer - NULL if tag_len = 0
size_t tag_len); // length, in bytes, of the tag-receiving buf
gcm_context *ctx, // pointer to user-provided GCM context
unsigned char *tag, // ptr to tag buffer - NULL if tag_len = 0
size_t tag_len); // length, in bytes, of the tag-receiving buf
/******************************************************************************
*
@@ -204,15 +206,15 @@ static int aes_tables_inited = 0; // run-once flag for performing key
* decryption is typically disabled by setting AES_DECRYPTION to 0 in aes.h.
*/
// We always need our forward tables
static unsigned char FSb[256]; // Forward substitution box (FSb)
static uint32_t FT0[256]; // Forward key schedule assembly tables
static unsigned char FSb[256]; // Forward substitution box (FSb)
static uint32_t FT0[256]; // Forward key schedule assembly tables
static uint32_t FT1[256];
static uint32_t FT2[256];
static uint32_t FT3[256];
#if AES_DECRYPTION // We ONLY need reverse for decryption
static unsigned char RSb[256]; // Reverse substitution box (RSb)
static uint32_t RT0[256]; // Reverse key schedule assembly tables
#if AES_DECRYPTION // We ONLY need reverse for decryption
static unsigned char RSb[256]; // Reverse substitution box (RSb)
static uint32_t RT0[256]; // Reverse key schedule assembly tables
static uint32_t RT1[256];
static uint32_t RT2[256];
static uint32_t RT3[256];
@@ -230,8 +232,8 @@ static uint32_t RCON[10]; // AES round constants
((uint32_t) (b)[(i) + 2] << 16) | ((uint32_t) (b)[(i) + 3] << 24); \
}
#define PUT_UINT32_LE(n, b, i) \
{ \
#define PUT_UINT32_LE(n, b, i) \
{ \
(b)[(i)] = (unsigned char) ((n)); \
(b)[(i) + 1] = (unsigned char) ((n) >> 8); \
(b)[(i) + 2] = (unsigned char) ((n) >> 16); \
@@ -376,7 +378,7 @@ void aes_init_keygen_tables(void) {
******************************************************************************/
static int aes_set_encryption_key(aes_context *ctx, const unsigned char *key,
unsigned int keysize) {
unsigned int i; // general purpose iteration local
unsigned int i; // general purpose iteration local
uint32_t *RK = ctx->rk; // initialize our RoundKey buffer pointer
for (i = 0; i < (keysize >> 2); i++) {
@@ -711,8 +713,8 @@ static const uint64_t last4[16] = {
((uint32_t) (b)[(i) + 2] << 8) | ((uint32_t) (b)[(i) + 3]); \
}
#define PUT_UINT32_BE(n, b, i) \
{ \
#define PUT_UINT32_BE(n, b, i) \
{ \
(b)[(i)] = (unsigned char) ((n) >> 24); \
(b)[(i) + 1] = (unsigned char) ((n) >> 16); \
(b)[(i) + 2] = (unsigned char) ((n) >> 8); \
@@ -745,9 +747,10 @@ int mg_gcm_initialize(void) {
* 'x' and 'output' are seen as elements of GCM's GF(2^128) Galois field.
*
******************************************************************************/
static void gcm_mult(gcm_context *ctx, // pointer to established context
const unsigned char x[16], // pointer to 128-bit input vector
unsigned char output[16]) // pointer to 128-bit output vector
static void gcm_mult(
gcm_context *ctx, // pointer to established context
const unsigned char x[16], // pointer to 128-bit input vector
unsigned char output[16]) // pointer to 128-bit output vector
{
int i;
unsigned char lo, hi, rem;
@@ -792,10 +795,10 @@ static void gcm_mult(gcm_context *ctx, // pointer to established context
*
******************************************************************************/
static int gcm_setkey(
gcm_context *ctx, // pointer to caller-provided gcm context
gcm_context *ctx, // pointer to caller-provided gcm context
const unsigned char *key, // pointer to the AES encryption key
const unsigned int keysize) // size in bytes (must be 16, 24, 32 for
// 128, 192 or 256-bit keys respectively)
// 128, 192 or 256-bit keys respectively)
{
int ret, i, j;
uint64_t hi, lo;
@@ -864,18 +867,19 @@ static int gcm_setkey(
* mode, and preprocesses the initialization vector and additional AEAD data.
*
******************************************************************************/
int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
int mode, // GCM_ENCRYPT or GCM_DECRYPT
const unsigned char *iv, // pointer to initialization vector
size_t iv_len, // IV length in bytes (should == 12)
const unsigned char *add, // ptr to additional AEAD data (NULL if none)
size_t add_len) // length of additional AEAD data (bytes)
int gcm_start(
gcm_context *ctx, // pointer to user-provided GCM context
int mode, // GCM_ENCRYPT or GCM_DECRYPT
const unsigned char *iv, // pointer to initialization vector
size_t iv_len, // IV length in bytes (should == 12)
const unsigned char *add, // ptr to additional AEAD data (NULL if none)
size_t add_len) // length of additional AEAD data (bytes)
{
int ret; // our error return if the AES encrypt fails
int ret; // our error return if the AES encrypt fails
unsigned char work_buf[16]; // XOR source built from provided IV if len != 16
const unsigned char *p; // general purpose array pointer
size_t use_len; // byte count to process, up to 16 bytes
size_t i; // local loop iterator
size_t use_len; // byte count to process, up to 16 bytes
size_t i; // local loop iterator
// since the context might be reused under the same key
// we zero the working buffers for this next new process
@@ -932,15 +936,15 @@ int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
* have a partial block length of < 128 bits.)
*
******************************************************************************/
int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
size_t length, // length, in bytes, of data to process
int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
size_t length, // length, in bytes, of data to process
const unsigned char *input, // pointer to source data
unsigned char *output) // pointer to destination data
{
int ret; // our error return if the AES encrypt fails
int ret; // our error return if the AES encrypt fails
unsigned char ectr[16]; // counter-mode cipher output for XORing
size_t use_len; // byte count to process, up to 16 bytes
size_t i; // local loop iterator
size_t use_len; // byte count to process, up to 16 bytes
size_t i; // local loop iterator
ctx->len += length; // bump the GCM context's running length count
@@ -996,9 +1000,9 @@ int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
* It performs the final GHASH to produce the resulting authentication TAG.
*
******************************************************************************/
int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
unsigned char *tag, // pointer to buffer which receives the tag
size_t tag_len) // length, in bytes, of the tag-receiving buf
int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
unsigned char *tag, // pointer to buffer which receives the tag
size_t tag_len) // length, in bytes, of the tag-receiving buf
{
unsigned char work_buf[16];
uint64_t orig_len = ctx->len * 8;
@@ -1040,22 +1044,22 @@ int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
*
******************************************************************************/
int gcm_crypt_and_tag(
gcm_context *ctx, // gcm context with key already setup
int mode, // cipher direction: GCM_ENCRYPT or GCM_DECRYPT
gcm_context *ctx, // gcm context with key already setup
int mode, // cipher direction: GCM_ENCRYPT or GCM_DECRYPT
const unsigned char *iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12
size_t iv_len, // byte length if the IV. should always be 12
const unsigned char *add, // pointer to the non-ciphered additional data
size_t add_len, // byte length of the additional AEAD data
size_t add_len, // byte length of the additional AEAD data
const unsigned char *input, // pointer to the cipher data source
unsigned char *output, // pointer to the cipher data destination
size_t length, // byte length of the cipher data
size_t length, // byte length of the cipher data
unsigned char *tag, // pointer to the tag to be generated
size_t tag_len) // byte length of the tag to be generated
{ /*
assuming that the caller has already invoked gcm_setkey to
prepare the gcm context with the keying material, we simply
invoke each of the three GCM sub-functions in turn...
*/
size_t tag_len) // byte length of the tag to be generated
{ /*
assuming that the caller has already invoked gcm_setkey to
prepare the gcm context with the keying material, we simply
invoke each of the three GCM sub-functions in turn...
*/
gcm_start(ctx, mode, iv, iv_len, add, add_len);
gcm_update(ctx, length, input, output);
gcm_finish(ctx, tag, tag_len);
@@ -1105,20 +1109,28 @@ int mg_aes_gcm_encrypt(unsigned char *output, //
int mg_aes_gcm_decrypt(unsigned char *output, const unsigned char *input,
size_t input_length, const unsigned char *key,
const size_t key_len, const unsigned char *iv,
const size_t iv_len) {
const size_t iv_len, unsigned char *aead,
size_t aead_len, const unsigned char *tag,
const size_t tag_len) {
int ret = 0; // our return value
gcm_context ctx; // includes the AES context structure
unsigned char computed_tag[16];
size_t i;
int diff = 0;
size_t tag_len = 0;
unsigned char *tag_buf = NULL;
if (tag_len > sizeof(computed_tag)) return -1;
gcm_setkey(&ctx, key, (unsigned int) key_len);
ret = gcm_crypt_and_tag(&ctx, MG_DECRYPT, iv, iv_len, NULL, 0, input, output,
input_length, tag_buf, tag_len);
ret = gcm_crypt_and_tag(&ctx, MG_DECRYPT, iv, iv_len, aead, aead_len, input,
output, input_length, computed_tag, tag_len);
gcm_zero_ctx(&ctx);
// compare tags
for (i = 0; i < tag_len; i++) diff |= computed_tag[i] ^ tag[i];
if (diff != 0) ret = -1;
return (ret);
}
#endif
+3 -1
View File
@@ -59,7 +59,9 @@ int mg_aes_gcm_encrypt(unsigned char *output, const unsigned char *input,
int mg_aes_gcm_decrypt(unsigned char *output, const unsigned char *input,
size_t input_length, const unsigned char *key,
const size_t key_len, const unsigned char *iv,
const size_t iv_len);
const size_t iv_len, unsigned char *aead,
size_t aead_len, const unsigned char *tag,
const size_t tag_len);
#endif /* TLS_AES128_H */
+1217 -387
View File
File diff suppressed because it is too large. Load diff
+31 -17
View File
@@ -20,8 +20,8 @@
#if defined(_MSC_VER) || defined(__cplusplus)
// add restrict support
#if (defined(_MSC_VER) && _MSC_VER >= 1900) || defined(__clang__) || \
defined(__GNUC__)
#if ((defined(_MSC_VER) && _MSC_VER >= 1900) && !defined(__cplusplus)) || \
defined(__clang__) || defined(__GNUC__)
#define restrict __restrict
#else
#define restrict
@@ -79,9 +79,11 @@ static PORTABLE_8439_DECL void poly1305_finish(poly1305_context *ctx,
#elif defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || \
defined(__THUMBEL__) || defined(__AARCH64EL__) || defined(_MIPSEL) || \
defined(__MIPSEL) || defined(__MIPSEL__) || defined(__XTENSA_EL__) || \
defined(__AVR__) || defined(LITTLE_ENDIAN)
defined(__AVR__)
#define __HAVE_LITTLE_ENDIAN 1
#endif
// DO NOT test for LITTLE_ENDIAN, as it is defined as 1234 when including
// sys/types.h in GCC
#ifndef TEST_SLOW_PATH
#if defined(__HAVE_LITTLE_ENDIAN)
@@ -177,7 +179,7 @@ static void core_block(const uint32_t *restrict start,
TIMES16(__FIN)
}
#define U8(x) ((uint8_t) ((x) &0xFF))
#define U8(x) ((uint8_t) ((x) & 0xFF))
#ifdef FAST_PATH
#define xor32_le(dst, src, pad) \
@@ -502,7 +504,7 @@ static unsigned short U8TO16(const unsigned char *p) {
/* store a 16 bit unsigned integer as two 8 bit unsigned integers in little
* endian */
static void U16TO8(unsigned char *p, unsigned short v) {
p[0] = (v) &0xff;
p[0] = (v) & 0xff;
p[1] = (v >> 8) & 0xff;
}
@@ -513,7 +515,7 @@ static void poly1305_init(poly1305_context *ctx, const unsigned char key[32]) {
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
t0 = U8TO16(&key[0]);
st->r[0] = (t0) &0x1fff;
st->r[0] = (t0) & 0x1fff;
t1 = U8TO16(&key[2]);
st->r[1] = ((t0 >> 13) | (t1 << 3)) & 0x1fff;
t2 = U8TO16(&key[4]);
@@ -553,7 +555,7 @@ static void poly1305_blocks(poly1305_state_internal_t *st,
/* h += m[i] */
t0 = U8TO16(&m[0]);
st->h[0] += (t0) &0x1fff;
st->h[0] += (t0) & 0x1fff;
t1 = U8TO16(&m[2]);
st->h[1] += ((t0 >> 13) | (t1 << 3)) & 0x1fff;
t2 = U8TO16(&m[4]);
@@ -715,7 +717,7 @@ static unsigned long U8TO32(const unsigned char *p) {
/* store a 32 bit unsigned integer as four 8 bit unsigned integers in little
* endian */
static void U32TO8(unsigned char *p, unsigned long v) {
p[0] = (unsigned char) ((v) &0xff);
p[0] = (unsigned char) ((v) & 0xff);
p[1] = (unsigned char) ((v >> 8) & 0xff);
p[2] = (unsigned char) ((v >> 16) & 0xff);
p[3] = (unsigned char) ((v >> 24) & 0xff);
@@ -979,8 +981,8 @@ typedef unsigned uint128_t __attribute__((mode(TI)));
#define MUL128(out, x, y) out = ((uint128_t) x * y)
#define ADD(out, in) out += in
#define ADDLO(out, in) out += in
#define SHR(in, shift) (uint64_t)(in >> (shift))
#define LO(in) (uint64_t)(in)
#define SHR(in, shift) (uint64_t) (in >> (shift))
#define LO(in) (uint64_t) (in)
#define POLY1305_NOINLINE __attribute__((noinline))
#endif
@@ -1009,7 +1011,7 @@ static uint64_t U8TO64(const unsigned char *p) {
/* store a 64 bit unsigned integer as eight 8 bit unsigned integers in little
* endian */
static void U64TO8(unsigned char *p, uint64_t v) {
p[0] = (unsigned char) ((v) &0xff);
p[0] = (unsigned char) ((v) & 0xff);
p[1] = (unsigned char) ((v >> 8) & 0xff);
p[2] = (unsigned char) ((v >> 16) & 0xff);
p[3] = (unsigned char) ((v >> 24) & 0xff);
@@ -1027,7 +1029,7 @@ static void poly1305_init(poly1305_context *ctx, const unsigned char key[32]) {
t0 = U8TO64(&key[0]);
t1 = U8TO64(&key[8]);
st->r[0] = (t0) &0xffc0fffffff;
st->r[0] = (t0) & 0xffc0fffffff;
st->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff;
st->r[2] = ((t1 >> 24)) & 0x00ffffffc0f;
@@ -1071,7 +1073,7 @@ static void poly1305_blocks(poly1305_state_internal_t *st,
t0 = U8TO64(&m[0]);
t1 = U8TO64(&m[8]);
h0 += ((t0) &0xfffffffffff);
h0 += ((t0) & 0xfffffffffff);
h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff);
h2 += (((t1 >> 24)) & 0x3ffffffffff) | hibit;
@@ -1178,7 +1180,7 @@ static POLY1305_NOINLINE void poly1305_finish(poly1305_context *ctx,
t0 = st->pad[0];
t1 = st->pad[1];
h0 += ((t0) &0xfffffffffff);
h0 += ((t0) & 0xfffffffffff);
c = (h0 >> 44);
h0 &= 0xfffffffffff;
h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + c;
@@ -1255,7 +1257,7 @@ static PORTABLE_8439_DECL void pad_if_needed(poly1305_context *ctx,
}
}
#define __u8(v) ((uint8_t) ((v) &0xFF))
#define __u8(v) ((uint8_t) ((v) & 0xFF))
// TODO: make this depending on the unaligned/native read size possible
static PORTABLE_8439_DECL void write_64bit_int(poly1305_context *ctx,
@@ -1328,14 +1330,26 @@ PORTABLE_8439_DECL size_t mg_chacha20_poly1305_encrypt(
PORTABLE_8439_DECL size_t mg_chacha20_poly1305_decrypt(
uint8_t *restrict plain_text, const uint8_t key[RFC_8439_KEY_SIZE],
const uint8_t nonce[RFC_8439_NONCE_SIZE],
const uint8_t *restrict cipher_text, size_t cipher_text_size) {
const uint8_t nonce[RFC_8439_NONCE_SIZE], const uint8_t *restrict ad,
size_t ad_size, const uint8_t *restrict cipher_text,
size_t cipher_text_size) {
// first we calculate the mac and see if it lines up, only then do we decrypt
size_t actual_size = cipher_text_size - RFC_8439_TAG_SIZE;
uint8_t computed_mac[RFC_8439_TAG_SIZE];
int diff = 0;
size_t i;
if (MG_OVERLAPPING(plain_text, actual_size, cipher_text, cipher_text_size)) {
return (size_t) -1;
}
poly1305_calculate_mac(computed_mac, cipher_text, actual_size, key, nonce, ad,
ad_size);
// compare tags
for (i = 0; i < RFC_8439_TAG_SIZE; i++)
diff |= computed_mac[i] ^ cipher_text[actual_size + i];
if (diff != 0) return (size_t) -1;
chacha20_xor_stream(plain_text, cipher_text, actual_size, key, nonce, 1);
return actual_size;
}
+4
View File
@@ -6,7 +6,9 @@
#include "arch.h"
#include "config.h"
#include "tls.h"
#if MG_TLS == MG_TLS_BUILTIN
#ifndef __PORTABLE_8439_H
#define __PORTABLE_8439_H
#if defined(__cplusplus)
@@ -103,8 +105,10 @@ PORTABLE_8439_DECL size_t mg_chacha20_poly1305_encrypt(
PORTABLE_8439_DECL size_t mg_chacha20_poly1305_decrypt(
uint8_t *restrict plain_text, const uint8_t key[RFC_8439_KEY_SIZE],
const uint8_t nonce[RFC_8439_NONCE_SIZE],
const uint8_t *restrict ad, size_t ad_size,
const uint8_t *restrict cipher_text, size_t cipher_text_size);
#if defined(__cplusplus)
}
#endif
#endif
#endif
+3
View File
@@ -21,6 +21,9 @@ size_t mg_tls_pending(struct mg_connection *c) {
(void) c;
return 0;
}
void mg_tls_flush(struct mg_connection *c) {
(void) c;
}
void mg_tls_ctx_init(struct mg_mgr *mgr) {
(void) mgr;
}
+66 -23
View File
@@ -1,24 +1,38 @@
#include "log.h"
#include "printf.h"
#include "profile.h"
#include "tls.h"
#include "util.h"
#if MG_TLS == MG_TLS_MBED
#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000
#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000 && \
MBEDTLS_VERSION_NUMBER < 0x04000000
#define MG_MBEDTLS_RNG_GET , mg_mbed_rng, NULL
#else
#define MG_MBEDTLS_RNG_GET
#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;
}
#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x04000000
#else
static int mg_mbed_rng(void *ctx, unsigned char *buf, size_t len) {
mg_random(buf, len);
(void) ctx;
return 0;
}
#endif
static bool mg_load_cert(struct mg_str str, mbedtls_x509_crt *p) {
int rc;
if (str.buf == NULL || str.buf[0] == '\0' || str.buf[0] == '*') return true;
if (str.buf[0] == '-') str.len++; // PEM, include trailing NUL
if (!MG_IS_DER(str.buf)) str.len++; // PEM, include trailing NUL
if ((rc = mbedtls_x509_crt_parse(p, (uint8_t *) str.buf, str.len)) != 0) {
MG_ERROR(("cert err %#x", -rc));
return false;
@@ -29,7 +43,7 @@ static bool mg_load_cert(struct mg_str str, mbedtls_x509_crt *p) {
static bool mg_load_key(struct mg_str str, mbedtls_pk_context *p) {
int rc;
if (str.buf == NULL || str.buf[0] == '\0' || str.buf[0] == '*') return true;
if (str.buf[0] == '-') str.len++; // PEM, include trailing NUL
if (!MG_IS_DER(str.buf)) str.len++; // PEM, include trailing NUL
if ((rc = mbedtls_pk_parse_key(p, (uint8_t *) str.buf, str.len, NULL,
0 MG_MBEDTLS_RNG_GET)) != 0) {
MG_ERROR(("key err %#x", -rc));
@@ -49,7 +63,10 @@ void mg_tls_free(struct mg_connection *c) {
#ifdef MBEDTLS_SSL_SESSION_TICKETS
mbedtls_ssl_ticket_free(&tls->ticket);
#endif
free(tls);
// PSA has global data. Do not call mbedtls_psa_crypto_free() here,
// it will free all global resources. Call it when actually freeing all
// application resources (main() exits)
mg_free(tls);
c->tls = NULL;
}
}
@@ -84,7 +101,7 @@ void mg_tls_handshake(struct mg_connection *c) {
MG_VERBOSE(("%lu pending, %d%d %d (-%#x)", c->id, c->is_connecting,
c->is_tls_hs, rc, -rc));
} else {
mg_error(c, "TLS handshake: -%#x", -rc); // Error
mg_error(c, "TLS handshake: -%#x", -mg_tls_err(c, rc)); // Error
}
}
@@ -95,7 +112,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) {
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;
c->tls = tls;
if (c->tls == NULL) {
@@ -108,6 +125,7 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000 && \
defined(MBEDTLS_PSA_CRYPTO_C)
psa_crypto_init(); // https://github.com/Mbed-TLS/mbedtls/issues/9072#issuecomment-2084845711
// this initializes global resources and then just returns when called again
#endif
mbedtls_ssl_init(&tls->ssl);
mbedtls_ssl_config_init(&tls->conf);
@@ -122,10 +140,14 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
&tls->conf,
c->is_client ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER,
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;
}
#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x04000000
MG_INFO(("PSA is in control of random number generation"));
#else
mbedtls_ssl_conf_rng(&tls->conf, mg_mbed_rng, c);
#endif
if (opts->ca.len == 0 || mg_strcmp(opts->ca, mg_str("*")) == 0) {
// NOTE: MBEDTLS_SSL_VERIFY_NONE is not supported for TLS1.3 on client side
@@ -134,11 +156,16 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
} else {
if (mg_load_cert(opts->ca, &tls->ca) == false) goto fail;
mbedtls_ssl_conf_ca_chain(&tls->conf, &tls->ca, NULL);
if (c->is_client && opts->name.buf != NULL && opts->name.buf[0] != '\0') {
char *host = mg_mprintf("%.*s", opts->name.len, opts->name.buf);
mbedtls_ssl_set_hostname(&tls->ssl, host);
MG_DEBUG(("%lu hostname verification: %s", c->id, host));
free(host);
if (c->is_client) {
if (opts->name.buf != NULL && opts->name.buf[0] != '\0') {
char *host = mg_mprintf("%.*s", opts->name.len, opts->name.buf);
mbedtls_ssl_set_hostname(&tls->ssl, host);
MG_DEBUG(("%lu hostname verification: %s", c->id, host));
mg_free(host);
} else {
MG_DEBUG(("%lu skipping hostname verification", c->id));
mbedtls_ssl_set_hostname(&tls->ssl, NULL);
}
}
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
}
@@ -146,7 +173,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 (tls->cert.version &&
(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;
}
@@ -157,7 +184,7 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
#endif
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;
}
c->is_tls = 1;
@@ -177,7 +204,7 @@ size_t mg_tls_pending(struct mg_connection *c) {
long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
struct mg_tls *tls = (struct mg_tls *) c->tls;
long n = mbedtls_ssl_read(&tls->ssl, (unsigned char *) buf, len);
if (!c->is_tls_hs && buf == NULL && n == 0) return 0; // TODO(): MIP
if (!c->is_tls_hs && buf == NULL && n == 0) return 0; // TODO(): MIP
if (n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE)
return MG_IO_WAIT;
#if defined(MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET)
@@ -201,25 +228,41 @@ long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
(n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE);
if (was_throttled) return MG_IO_WAIT; // flushed throttled data instead
if (c->is_tls_throttled) {
tls->throttled_buf = (unsigned char *)buf; // MbedTLS code actually ignores
tls->throttled_len = len; // these, but let's play API rules
return (long) len; // already encripted that when throttled
}
tls->throttled_buf =
(unsigned char *) buf; // MbedTLS code actually ignores
tls->throttled_len = len; // these, but let's play API rules
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;
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) {
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) {
MG_ERROR(("TLS context init OOM"));
} else {
#ifdef MBEDTLS_SSL_SESSION_TICKETS
int rc;
mbedtls_ssl_ticket_init(&ctx->tickets);
#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x04000000
if ((rc = mbedtls_ssl_ticket_setup(&ctx->tickets, PSA_ALG_GCM,
PSA_KEY_TYPE_AES, 128, 86400))
#else
if ((rc = mbedtls_ssl_ticket_setup(&ctx->tickets, mg_mbed_rng, NULL,
MBEDTLS_CIPHER_AES_128_GCM, 86400)) !=
0) {
MBEDTLS_CIPHER_AES_128_GCM, 86400))
#endif
!= 0) {
MG_ERROR((" mbedtls_ssl_ticket_setup %#x", -rc));
}
#endif
@@ -233,7 +276,7 @@ void mg_tls_ctx_free(struct mg_mgr *mgr) {
#ifdef MBEDTLS_SSL_SESSION_TICKETS
mbedtls_ssl_ticket_free(&ctx->tickets);
#endif
free(ctx);
mg_free(ctx);
mgr->tls_ctx = NULL;
}
}
+1
View File
@@ -7,6 +7,7 @@
#if MG_TLS == MG_TLS_MBED
#include <mbedtls/debug.h>
#include <mbedtls/error.h>
#include <mbedtls/net_sockets.h>
#include <mbedtls/ssl.h>
#include <mbedtls/ssl_ticket.h>
+30 -7
View File
@@ -1,5 +1,6 @@
#include "printf.h"
#include "tls.h"
#include "util.h"
#if MG_TLS == MG_TLS_OPENSSL || MG_TLS == MG_TLS_WOLFSSL
@@ -27,6 +28,7 @@ static int mg_tls_err(struct mg_connection *c, struct mg_tls *tls, int res) {
return err;
}
#if MG_TLS != MG_TLS_WOLFSSL
static STACK_OF(X509_INFO) * load_ca_certs(struct mg_str ca) {
BIO *bio = BIO_new_mem_buf(ca.buf, (int) ca.len);
STACK_OF(X509_INFO) *certs =
@@ -38,6 +40,7 @@ static STACK_OF(X509_INFO) * load_ca_certs(struct mg_str ca) {
static bool add_ca_certs(SSL_CTX *ctx, STACK_OF(X509_INFO) * certs) {
int i;
X509_STORE *cert_store = SSL_CTX_get_cert_store(ctx);
if (cert_store == NULL) return false;
for (i = 0; i < sk_X509_INFO_num(certs); i++) {
X509_INFO *cert_info = sk_X509_INFO_value(certs, i);
if (cert_info->x509 && !X509_STORE_add_cert(cert_store, cert_info->x509))
@@ -45,6 +48,7 @@ static bool add_ca_certs(SSL_CTX *ctx, STACK_OF(X509_INFO) * certs) {
}
return true;
}
#endif
static EVP_PKEY *load_key(struct mg_str s) {
BIO *bio = BIO_new_mem_buf(s.buf, (int) (long) s.len);
@@ -56,9 +60,9 @@ static EVP_PKEY *load_key(struct mg_str s) {
static X509 *load_cert(struct mg_str s) {
BIO *bio = BIO_new_mem_buf(s.buf, (int) (long) s.len);
X509 *cert = bio == NULL ? NULL
: s.buf[0] == '-'
? PEM_read_bio_X509(bio, NULL, NULL, NULL) // PEM
: d2i_X509_bio(bio, NULL); // DER
: MG_IS_DER(s.buf)
? d2i_X509_bio(bio, NULL) // DER
: PEM_read_bio_X509(bio, NULL, NULL, NULL); // PEM
if (bio) BIO_free(bio);
return cert;
}
@@ -104,6 +108,7 @@ static void ssl_keylog_cb(const SSL *ssl, const char *line) {
fprintf(f, "%s\n", line);
fflush(f);
fclose(f);
(void) ssl;
}
#endif
@@ -113,12 +118,12 @@ void mg_tls_free(struct mg_connection *c) {
SSL_free(tls->ssl);
SSL_CTX_free(tls->ctx);
BIO_meth_free(tls->bm);
free(tls);
mg_free(tls);
c->tls = NULL;
}
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";
static unsigned char s_initialised = 0;
BIO *bio = NULL;
@@ -168,9 +173,21 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
SSL_set_verify(tls->ssl, SSL_VERIFY_NONE, NULL);
}
#endif
if (opts->ca.buf != NULL && opts->ca.buf[0] != '\0') {
SSL_set_verify(tls->ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
NULL);
#if MG_TLS == MG_TLS_WOLFSSL
extern int wolfSSL_CTX_load_verify_buffer(SSL_CTX *, const unsigned char *,
long, int);
rc = wolfSSL_CTX_load_verify_buffer(tls->ctx,
(const unsigned char *) opts->ca.buf,
(long) opts->ca.len, SSL_FILETYPE_PEM);
if (rc != 1) {
mg_error(c, "CA err");
goto fail;
}
#else
STACK_OF(X509_INFO) *certs = load_ca_certs(opts->ca);
rc = add_ca_certs(tls->ctx, certs);
sk_X509_INFO_pop_free(certs, X509_INFO_free);
@@ -178,7 +195,9 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
mg_error(c, "CA err");
goto fail;
}
#endif
}
if (opts->cert.buf != NULL && opts->cert.buf[0] != '\0') {
X509 *cert = load_cert(opts->cert);
rc = cert == NULL ? 0 : SSL_use_certificate(tls->ssl, cert);
@@ -211,7 +230,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);
#endif
SSL_set_tlsext_host_name(tls->ssl, s);
free(s);
mg_free(s);
}
#endif
#if MG_TLS == MG_TLS_WOLFSSL
@@ -256,7 +275,7 @@ size_t mg_tls_pending(struct mg_connection *c) {
long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
struct mg_tls *tls = (struct mg_tls *) c->tls;
int n = SSL_read(tls->ssl, buf, (int) len);
if (!c->is_tls_hs && buf == NULL && n == 0) return 0; // TODO(): MIP
if (!c->is_tls_hs && buf == NULL && n == 0) return 0; // TODO(): MIP
if (n < 0 && mg_tls_err(c, tls, n) == 0) return MG_IO_WAIT;
if (n <= 0) return MG_IO_ERR;
return n;
@@ -270,6 +289,10 @@ long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
return n;
}
void mg_tls_flush(struct mg_connection *c) {
(void) c;
}
void mg_tls_ctx_init(struct mg_mgr *mgr) {
(void) mgr;
}
Loaded 100 of 1446 files, more files were not shown because too many files have changed in this diff. Show more