Compare commits

..
291 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
552 changed files with 335668 additions and 4009 deletions

No files matched your search

+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: make -C test ${{ matrix.target }} ARGS="-max_total_time=7200" - 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: # as we're not getting access to test units causing a problem, convert from the log:
# base64 -d > dataofdeath # base64 -d > dataofdeath
+74 -155
View File
@@ -1,4 +1,4 @@
name: Full build and test name: Full build
on: on:
schedule: schedule:
- cron: '0 22 * * *' # run at 10 PM UTC - cron: '0 22 * * *' # run at 10 PM UTC
@@ -29,15 +29,28 @@ jobs:
select: "-DMG_ENABLE_POLL=0 -DMG_ENABLE_EPOLL=0" select: "-DMG_ENABLE_POLL=0 -DMG_ENABLE_EPOLL=0"
- ssl: WOLFSSL - ssl: WOLFSSL
select: "-DMG_ENABLE_POLL=1 -DMG_ENABLE_EPOLL=0" 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 }} name: linux ${{ matrix.target }} CC=${{ matrix.cc }} SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }}
env: env:
CC: ${{ matrix.cc }} CC: ${{ matrix.cc }}
SSL: ${{ matrix.ssl }} SSL: ${{ matrix.ssl }}
TFLAGS: ${{ matrix.select }} -DMQTT_LOCALHOST TFLAGS: ${{ matrix.select }} -DMQTT_LOCALHOST -DNO_ABORT
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev && test/setup_mqtt_server.sh && 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: mip:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
@@ -54,11 +67,20 @@ jobs:
env: env:
CC: ${{ matrix.cc }} CC: ${{ matrix.cc }}
SSL: ${{ matrix.ssl }} SSL: ${{ matrix.ssl }}
TFLAGS: -DMQTT_LOCALHOST TFLAGS: -DMQTT_LOCALHOST -DNO_ABORT
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: if [ "${{ matrix.target }}" == "mip_tap_test" ]; then ./test/setup_ga_network.sh ; fi && sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev && make -C test ${{ matrix.target }} IPV6=0 - 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: mip89:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
@@ -70,7 +92,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: make -C test ${{ matrix.target }} - run: make -C test ${{ matrix.target }} IPV6=1
s390: s390:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
@@ -128,32 +150,37 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
# Mongoose does not work with WolfSSL version in MacOS ssl: ["", BUILTIN, MBEDTLS, OPENSSL, WOLFSSL]
ssl: ["", BUILTIN, MBEDTLS, OPENSSL] # , WOLFSSL]
select: [-DMG_ENABLE_POLL=0, -DMG_ENABLE_POLL=1] select: [-DMG_ENABLE_POLL=0, -DMG_ENABLE_POLL=1]
include:
- ssl: MBEDTLS
env:
# MbedTLS version in MacOS refuses to validate a certificate without a hostname, causing MQTT tests to fail when using MQTT_LOCALHOST
tflags: -DNO_MQTT_TESTS
exclude: exclude:
- ssl: MBEDTLS - ssl: MBEDTLS
select: -DMG_ENABLE_POLL=0 select: -DMG_ENABLE_POLL=0
- ssl: MBEDTLS # see issue#2694
select: -DMG_ENABLE_POLL=1
- ssl: OPENSSL - ssl: OPENSSL
select: -DMG_ENABLE_POLL=0 select: -DMG_ENABLE_POLL=0
#- ssl: WOLFSSL - ssl: WOLFSSL
# select: -DMG_ENABLE_POLL=0 select: -DMG_ENABLE_POLL=0
name: macos SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }} name: macos SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }}
env: env:
SSL: ${{ matrix.ssl }} SSL: ${{ matrix.ssl }}
TFLAGS: ${{ matrix.select }} -DMQTT_LOCALHOST ${{ matrix.env.tflags }} -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 HOMEBREW_NO_AUTO_UPDATE: 1
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: brew install mbedtls wolfssl mosquitto # jq openssl already pre-installed - 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: /opt/homebrew/opt/mosquitto/sbin/mosquitto -c /Users/runner/work/mongoose/mongoose/test/mosquitto.conf.macos &
- run: make -C test test ASAN_OPTIONS= MBEDTLS=$(echo $(brew --cellar)/mbedtls*/*) OPENSSL=$(echo $(brew --cellar)/openssl*/*) WOLFSSL=$(echo $(brew --cellar)/wolfssl*/*) - run: make -C test test ASAN_OPTIONS= MBEDTLS=$(echo $(brew --cellar)/mbedtls*/*) OPENSSL=$(echo $(brew --cellar)/openssl*/*) WOLFSSL=$(echo $(brew --cellar)/wolfssl*/*) > 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: windows:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
@@ -169,11 +196,20 @@ jobs:
name: windows ${{ matrix.target }} SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }} name: windows ${{ matrix.target }} SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }}
env: env:
SSL: ${{ matrix.ssl }} SSL: ${{ matrix.ssl }}
TFLAGS: ${{ matrix.select }} -DMQTT_LOCALHOST TFLAGS: ${{ matrix.select }} -DMQTT_LOCALHOST -DNO_ABORT
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: ./test/setup_mqtt_server.sh && 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: arm:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
@@ -204,9 +240,18 @@ jobs:
name: tutorials ${{ matrix.ssl }} name: tutorials ${{ matrix.ssl }}
steps: steps:
- uses: actions/checkout@v4 - 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: 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 - run: make -C test clean_tutorials
tutorials_win: tutorials_win:
runs-on: windows-latest runs-on: windows-latest
strategy: strategy:
@@ -284,6 +329,7 @@ jobs:
- path: pico-sdk/pico-2-w-picosdk-baremetal-builtin - path: pico-sdk/pico-2-w-picosdk-baremetal-builtin
- path: pico-sdk/w5500-evb-pico-picosdk-baremetal-builtin - path: pico-sdk/w5500-evb-pico-picosdk-baremetal-builtin
- path: pico-sdk/w5500-evb-pico2-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-baremetal-builtin
- path: stm32/nucleo-f429zi-make-freertos-builtin - path: stm32/nucleo-f429zi-make-freertos-builtin
- path: stm32/nucleo-f746zg-make-baremetal-builtin - path: stm32/nucleo-f746zg-make-baremetal-builtin
@@ -454,137 +500,10 @@ jobs:
- run: sudo pip install yq - run: sudo pip install yq
- run: cd test/cube && make - run: cd test/cube && make
test_f7: # xpresso_examples:
runs-on: ubuntu-latest # runs-on: ubuntu-latest
steps: # steps:
- uses: actions/checkout@v4 # - uses: actions/checkout@v4
with: { fetch-depth: 2 } # with: { fetch-depth: 2 }
- name: baremetal # - run: sudo pip install yq
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi # - run: cd test/xpresso && make
- 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}}
+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"
+17
View File
@@ -170,6 +170,7 @@ jobs:
- path: pico-sdk/pico-2-w-picosdk-baremetal-builtin - path: pico-sdk/pico-2-w-picosdk-baremetal-builtin
- path: pico-sdk/w5500-evb-pico-picosdk-baremetal-builtin - path: pico-sdk/w5500-evb-pico-picosdk-baremetal-builtin
- path: pico-sdk/w5500-evb-pico2-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-baremetal-builtin
- path: stm32/nucleo-f429zi-make-freertos-builtin - path: stm32/nucleo-f429zi-make-freertos-builtin
- path: stm32/nucleo-f746zg-make-baremetal-builtin - path: stm32/nucleo-f746zg-make-baremetal-builtin
@@ -347,6 +348,22 @@ jobs:
- if: ${{ env.GO == 1 }} - if: ${{ env.GO == 1 }}
run: cd test/cube && make run: cd test/cube && make
# 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_f7: # test_f7:
# runs-on: ubuntu-latest # runs-on: ubuntu-latest
# env: # env:
+8 -7
View File
@@ -10,17 +10,18 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
revno: ["--mr v3.7-branch", "--mr v4.2.0"] # LTS, latest stable revno: ["--mr v3.7-branch", "--mr v4.2.0", "--mr v4.3.0"] # LTS, latest stable
name: Zephyr ${{ matrix.revno }} name: Zephyr ${{ matrix.revno }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 2 } with: { fetch-depth: 2 }
- run: test/setup_ga_docker_filesystem.sh - run: test/setup_ga_docker_filesystem.sh
- run: make -C tutorials/zephyr init REPO=zephyrprojectrtos/ci REVNO="${{ matrix.revno }}" - 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 minify REVNO="${{ matrix.revno }}"
- run: make -C tutorials/zephyr update - run: make -C tutorials/zephyr update
- run: make -C tutorials/zephyr/device-dashboard build - run: make -C tutorials/zephyr/device-dashboard build REPO=zephyrprojectrtos/ci:v0.28.8
- run: make -C tutorials/zephyr/http-client build - run: make -C tutorials/zephyr/http-client build REPO=zephyrprojectrtos/ci:v0.28.8
- run: make -C tutorials/zephyr/http-server build - run: make -C tutorials/zephyr/http-server build REPO=zephyrprojectrtos/ci:v0.28.8
- run: make -C tutorials/zephyr/mqtt-aws-client build - run: make -C tutorials/zephyr/mqtt-aws-client build REPO=zephyrprojectrtos/ci:v0.28.8
- run: make -C tutorials/zephyr/websocket-server build - 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) 2004-2013 Sergey Lyubka
Copyright (c) 2013-2025 Cesanta Software Limited Copyright (c) 2013-2026 Cesanta Software Limited
All rights reserved All rights reserved
This software is dual-licensed: you can redistribute it and/or modify This software is dual-licensed: you can redistribute it and/or modify
+13 -1
View File
@@ -5,7 +5,7 @@
[![Code Coverage](https://codecov.io/gh/cesanta/mongoose/branch/master/graph/badge.svg)](https://codecov.io/gh/cesanta/mongoose) [![Code Coverage](https://codecov.io/gh/cesanta/mongoose/branch/master/graph/badge.svg)](https://codecov.io/gh/cesanta/mongoose)
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/mongoose.svg)](https://issues.oss-fuzz.com/issues?sort=-opened&can=1&q=proj:mongoose) [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/mongoose.svg)](https://issues.oss-fuzz.com/issues?sort=-opened&can=1&q=proj:mongoose)
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 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 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 by vast number of open source and commercial products - it even runs on the
@@ -198,6 +198,10 @@ We take security seriously:
have specific security requirements and run independent security audits, have specific security requirements and run independent security audits,
of which we get notified and in case of any issue, act similar to (3). 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 ## Articles
@@ -209,6 +213,14 @@ Technical guides and deep dives into embedded web servers, WebUI integration and
- [STM32 WebSocket Guide](https://mongoose.ws/articles/stm32-websocket-guide/) - [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 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/) - [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 ## Contributions
+5052 -1526
View File
File diff suppressed because it is too large. Load diff
+419 -102
View File
@@ -20,7 +20,7 @@
#ifndef MONGOOSE_H #ifndef MONGOOSE_H
#define MONGOOSE_H #define MONGOOSE_H
#define MG_VERSION "7.19" #define MG_VERSION "7.21"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -159,11 +159,14 @@ extern "C" {
#define MG_ENABLE_TCPIP 1 // Enable built-in TCP/IP stack #define MG_ENABLE_TCPIP 1 // Enable built-in TCP/IP stack
#endif #endif
#if MG_ENABLE_TCPIP && !defined(MG_ENABLE_DRIVER_STM32F) && !defined(MG_ENABLE_DRIVER_STM32H) #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) #if defined(STM32F1) || defined(STM32F2) || defined(STM32F4) || defined(STM32F7)
#define MG_ENABLE_DRIVER_STM32F 1 #define MG_ENABLE_DRIVER_STM32F 1
#elif defined(STM32H5) || defined(STM32H7) #elif defined(STM32H5) || defined(STM32H7)
#define MG_ENABLE_DRIVER_STM32H 1 #define MG_ENABLE_DRIVER_STM32H 1
#elif defined(STM32N6)
#define MG_ENABLE_DRIVER_STM32N 1
#else #else
#error Select a driver in mongoose_config.h #error Select a driver in mongoose_config.h
#endif #endif
@@ -173,7 +176,8 @@ extern "C" {
#define MG_TLS MG_TLS_BUILTIN #define MG_TLS MG_TLS_BUILTIN
#endif #endif
#if !defined(MG_OTA) && defined(STM32F1) || defined(STM32F2) || defined(STM32F4) || defined(STM32F7) #if !defined(MG_OTA) && defined(STM32F1) || defined(STM32F2) || \
defined(STM32F4) || defined(STM32F7)
#define MG_OTA MG_OTA_STM32F #define MG_OTA MG_OTA_STM32F
#elif !defined(MG_OTA) && defined(STM32H5) #elif !defined(MG_OTA) && defined(STM32H5)
#define MG_OTA MG_OTA_STM32H5 #define MG_OTA MG_OTA_STM32H5
@@ -285,6 +289,7 @@ extern "C" {
#define mode_t size_t #define mode_t size_t
#include <alloca.h> #include <alloca.h>
#include <time.h> #include <time.h>
#define strdup(s) ((char *) mg_strdup(mg_str(s)).buf)
#elif defined(__CCRH__) #elif defined(__CCRH__)
#else #else
#include <sys/stat.h> #include <sys/stat.h>
@@ -650,7 +655,10 @@ typedef enum { false = 0, true = 1 } bool;
#endif #endif
#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 defined(_MSC_VER)
#if MG_ENABLE_WINSOCK #if MG_ENABLE_WINSOCK
#pragma comment(lib, "ws2_32.lib") #pragma comment(lib, "ws2_32.lib")
@@ -721,13 +729,15 @@ typedef int socklen_t;
#if MG_ARCH == MG_ARCH_ZEPHYR #if MG_ARCH == MG_ARCH_ZEPHYR
#include <zephyr/kernel.h> #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 <zephyr/version.h>
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <zephyr/net/socket.h>
#include <zephyr/posix/fcntl.h>
#include <zephyr/posix/sys/select.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
@@ -1056,10 +1066,34 @@ struct timeval {
#define MG_TCPIP_GW MG_IPV4(0, 0, 0, 0) // Default is 0.0.0.0 (DHCP) #define MG_TCPIP_GW MG_IPV4(0, 0, 0, 0) // Default is 0.0.0.0 (DHCP)
#endif #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 #ifndef MG_SET_MAC_ADDRESS
#define MG_SET_MAC_ADDRESS(mac) #define MG_SET_MAC_ADDRESS(mac)
#endif #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 #ifndef MG_SET_WIFI_CONFIG
#define MG_SET_WIFI_CONFIG(data) #define MG_SET_WIFI_CONFIG(data)
#endif #endif
@@ -1206,7 +1240,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, ...); size_t mg_snprintf(char *, size_t, const char *fmt, ...);
char *mg_vmprintf(const char *fmt, va_list *ap); char *mg_vmprintf(const char *fmt, va_list *ap);
char *mg_mprintf(const char *fmt, ...); 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, ...); size_t mg_queue_printf(struct mg_queue *, const char *fmt, ...);
// %M print helper functions // %M print helper functions
@@ -1218,10 +1251,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_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_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_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 // Various output functions
void mg_pfn_iobuf(char ch, void *param); // param: struct mg_iobuf * 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_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")) // A helper macro for printing JSON: mg_snprintf(buf, len, "%m", MG_ESC("hi"))
#define MG_ESC(str) mg_print_esc, 0, (str) #define MG_ESC(str) mg_print_esc, 0, (str)
@@ -1243,12 +1278,18 @@ void mg_log_set_fn(mg_pfn_t fn, void *param);
#define mg_log_set(level_) mg_log_level = (level_) #define mg_log_set(level_) mg_log_level = (level_)
#if MG_ENABLE_LOG #if MG_ENABLE_LOG
#define MG_LOG(level, args) \ #if !defined(_MSC_VER) && \
do { \ (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L)
if ((level) <= mg_log_level) { \ #define MG___FUNC__ ""
mg_log_prefix((level), __FILE__, __LINE__, __func__); \ #else
mg_log args; \ #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) } while (0)
#else #else
#define MG_LOG(level, args) \ #define MG_LOG(level, args) \
@@ -1364,6 +1405,16 @@ void mg_delayms(unsigned int ms);
#define MG_IPV4(a, b, c, d) mg_htonl(MG_U32(a, b, c, d)) #define MG_IPV4(a, b, c, d) mg_htonl(MG_U32(a, b, c, d))
#define MG_IPV6(a, b, c, d, e, f, g ,h) \
{ (uint8_t)((a)>>8),(uint8_t)(a), \
(uint8_t)((b)>>8),(uint8_t)(b), \
(uint8_t)((c)>>8),(uint8_t)(c), \
(uint8_t)((d)>>8),(uint8_t)(d), \
(uint8_t)((e)>>8),(uint8_t)(e), \
(uint8_t)((f)>>8),(uint8_t)(f), \
(uint8_t)((g)>>8),(uint8_t)(g), \
(uint8_t)((h)>>8),(uint8_t)(h) }
// For printing IPv4 addresses: printf("%d.%d.%d.%d\n", MG_IPADDR_PARTS(&ip)) // For printing IPv4 addresses: printf("%d.%d.%d.%d\n", MG_IPADDR_PARTS(&ip))
#define MG_U8P(ADDR) ((uint8_t *) (ADDR)) #define MG_U8P(ADDR) ((uint8_t *) (ADDR))
#define MG_IPADDR_PARTS(ADDR) \ #define MG_IPADDR_PARTS(ADDR) \
@@ -1378,6 +1429,14 @@ void mg_delayms(unsigned int ms);
((uint32_t) (((uint32_t) MG_U8P(p)[0] << 24U) | \ ((uint32_t) (((uint32_t) MG_U8P(p)[0] << 24U) | \
((uint32_t) MG_U8P(p)[1] << 16U) | \ ((uint32_t) MG_U8P(p)[1] << 16U) | \
((uint32_t) MG_U8P(p)[2] << 8U) | MG_U8P(p)[3])) ((uint32_t) MG_U8P(p)[2] << 8U) | MG_U8P(p)[3]))
#define MG_LOAD_BE64(p) \
((uint64_t) (((uint64_t) MG_U8P(p)[0] << 56U) | \
((uint64_t) MG_U8P(p)[1] << 48U) | \
((uint64_t) MG_U8P(p)[2] << 40U) | \
((uint64_t) MG_U8P(p)[3] << 32U) | \
((uint64_t) MG_U8P(p)[4] << 24U) | \
((uint64_t) MG_U8P(p)[5] << 16U) | \
((uint64_t) MG_U8P(p)[6] << 8U) | MG_U8P(p)[7]))
#define MG_STORE_BE16(p, n) \ #define MG_STORE_BE16(p, n) \
do { \ do { \
MG_U8P(p)[0] = ((n) >> 8U) & 255; \ MG_U8P(p)[0] = ((n) >> 8U) & 255; \
@@ -1396,11 +1455,24 @@ void mg_delayms(unsigned int ms);
MG_U8P(p)[2] = ((n) >> 8U) & 255; \ MG_U8P(p)[2] = ((n) >> 8U) & 255; \
MG_U8P(p)[3] = (n) &255; \ MG_U8P(p)[3] = (n) &255; \
} while (0) } while (0)
#define MG_STORE_BE64(p, n) \
do { \
MG_U8P(p)[0] = ((n) >> 56U) & 255; \
MG_U8P(p)[1] = ((n) >> 48U) & 255; \
MG_U8P(p)[2] = ((n) >> 40U) & 255; \
MG_U8P(p)[3] = ((n) >> 32U) & 255; \
MG_U8P(p)[4] = ((n) >> 24U) & 255; \
MG_U8P(p)[5] = ((n) >> 16U) & 255; \
MG_U8P(p)[6] = ((n) >> 8U) & 255; \
MG_U8P(p)[7] = (n) &255; \
} while (0)
uint16_t mg_ntohs(uint16_t net); uint16_t mg_ntohs(uint16_t net);
uint32_t mg_ntohl(uint32_t net); uint32_t mg_ntohl(uint32_t net);
uint64_t mg_ntohll(uint64_t net);
#define mg_htons(x) mg_ntohs(x) #define mg_htons(x) mg_ntohs(x)
#define mg_htonl(x) mg_ntohl(x) #define mg_htonl(x) mg_ntohl(x)
#define mg_htonll(x) mg_ntohll(x)
#define MG_REG(x) ((volatile uint32_t *) (x))[0] #define MG_REG(x) ((volatile uint32_t *) (x))[0]
#define MG_BIT(x) (((uint32_t) 1U) << (x)) #define MG_BIT(x) (((uint32_t) 1U) << (x))
@@ -1484,8 +1556,8 @@ struct mg_iobuf {
size_t align; // Alignment during allocation size_t align; // Alignment during allocation
}; };
int mg_iobuf_init(struct mg_iobuf *, size_t, size_t); bool mg_iobuf_init(struct mg_iobuf *, size_t, size_t);
int mg_iobuf_resize(struct mg_iobuf *, size_t); bool mg_iobuf_resize(struct mg_iobuf *, size_t);
void mg_iobuf_free(struct mg_iobuf *); 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_add(struct mg_iobuf *, size_t, const void *, size_t);
size_t mg_iobuf_del(struct mg_iobuf *, size_t ofs, size_t len); size_t mg_iobuf_del(struct mg_iobuf *, size_t ofs, size_t len);
@@ -1586,6 +1658,8 @@ enum {
MG_EV_MQTT_OPEN, // MQTT CONNACK received int *connack_status_code MG_EV_MQTT_OPEN, // MQTT CONNACK received int *connack_status_code
MG_EV_SNTP_TIME, // SNTP time received uint64_t *epoch_millis MG_EV_SNTP_TIME, // SNTP time received uint64_t *epoch_millis
MG_EV_WAKEUP, // mg_wakeup() data received struct mg_str *data 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 MG_EV_USER // Starting ID for user events
}; };
@@ -1604,7 +1678,11 @@ struct mg_dns {
}; };
struct mg_addr { 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 uint16_t port; // TCP or UDP port in network byte order
uint8_t scope_id; // IPv6 scope ID uint8_t scope_id; // IPv6 scope ID
bool is_ip6; // True when address is IPv6 address bool is_ip6; // True when address is IPv6 address
@@ -1698,6 +1776,7 @@ struct mg_timer *mg_timer_add(struct mg_mgr *mgr, uint64_t milliseconds,
struct mg_connection *mg_connect_svc(struct mg_mgr *mgr, const char *url, struct mg_connection *mg_connect_svc(struct mg_mgr *mgr, const char *url,
mg_event_handler_t fn, void *fn_data, mg_event_handler_t fn, void *fn_data,
mg_event_handler_t pfn, void *pfn_data); mg_event_handler_t pfn, void *pfn_data);
void mg_multicast_restore(struct mg_connection *c, uint8_t *from);
@@ -1740,7 +1819,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); 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_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_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, struct mg_connection *mg_http_listen(struct mg_mgr *, const char *url,
mg_event_handler_t fn, void *fn_data); mg_event_handler_t fn, void *fn_data);
struct mg_connection *mg_http_connect(struct mg_mgr *, const char *url, struct mg_connection *mg_http_connect(struct mg_mgr *, const char *url,
@@ -1803,6 +1881,7 @@ void mg_tls_handshake(struct mg_connection *);
// Private // Private
void mg_tls_ctx_init(struct mg_mgr *); void mg_tls_ctx_init(struct mg_mgr *);
void mg_tls_ctx_free(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 // Low-level IO primives used by TLS layer
enum { MG_IO_ERR = -1, MG_IO_WAIT = -2, MG_IO_RESET = -3 }; enum { MG_IO_ERR = -1, MG_IO_WAIT = -2, MG_IO_RESET = -3 };
@@ -1882,7 +1961,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, int mg_aes_gcm_decrypt(unsigned char *output, const unsigned char *input,
size_t input_length, const unsigned char *key, size_t input_length, const unsigned char *key,
const size_t key_len, const unsigned char *iv, 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 */ #endif /* TLS_AES128_H */
@@ -2648,6 +2729,7 @@ PORTABLE_8439_DECL size_t mg_chacha20_poly1305_encrypt(
PORTABLE_8439_DECL size_t mg_chacha20_poly1305_decrypt( PORTABLE_8439_DECL size_t mg_chacha20_poly1305_decrypt(
uint8_t *restrict plain_text, const uint8_t key[RFC_8439_KEY_SIZE], uint8_t *restrict plain_text, const uint8_t key[RFC_8439_KEY_SIZE],
const uint8_t nonce[RFC_8439_NONCE_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); const uint8_t *restrict cipher_text, size_t cipher_text_size);
#if defined(__cplusplus) #if defined(__cplusplus)
} }
@@ -2659,7 +2741,13 @@ PORTABLE_8439_DECL size_t mg_chacha20_poly1305_decrypt(
int mg_rsa_mod_pow(const uint8_t *mod, size_t modsz, const uint8_t *exp, size_t expsz, const uint8_t *msg, size_t msgsz, uint8_t *out, size_t outsz); int mg_rsa_mod_pow(const uint8_t *mod, size_t modsz, const uint8_t *exp, size_t expsz, const uint8_t *msg, size_t msgsz, uint8_t *out, size_t outsz);
int mg_rsa_crt_sign(const uint8_t *em, size_t em_len,
const uint8_t *dP, size_t dP_len,
const uint8_t *dQ, size_t dQ_len,
const uint8_t *p, size_t p_len,
const uint8_t *q, size_t q_len,
const uint8_t *qInv, size_t qInv_len,
uint8_t *signature, size_t sig_len);
#endif // TLS_RSA_H #endif // TLS_RSA_H
@@ -2851,6 +2939,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); 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); 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_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 *); 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, void mg_mqtt_send_header(struct mg_connection *, uint8_t cmd, uint8_t flags,
uint32_t len); uint32_t len);
@@ -2864,6 +2953,12 @@ size_t mg_mqtt_next_prop(struct mg_mqtt_message *, struct mg_mqtt_prop *,
#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: // Mongoose sends DNS queries that contain only one question:
// either A (IPv4) or AAAA (IPv6) address lookup. // either A (IPv4) or AAAA (IPv6) address lookup.
// Therefore, we expect zero or one answer. // Therefore, we expect zero or one answer.
@@ -2892,13 +2987,42 @@ struct mg_dns_rr {
uint16_t alen; // Address length 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(struct mg_connection *, const char *url);
void mg_resolve_cancel(struct mg_connection *); void mg_resolve_cancel(struct mg_connection *);
bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *); 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, size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs,
bool is_question, struct mg_dns_rr *); 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);
@@ -2975,8 +3099,8 @@ void mg_rpc_list(struct mg_rpc_req *r);
#define MG_OTA_RT1060 302 // IMXRT1060 #define MG_OTA_RT1060 302 // IMXRT1060
#define MG_OTA_RT1064 303 // IMXRT1064 #define MG_OTA_RT1064 303 // IMXRT1064
#define MG_OTA_RT1170 304 // IMXRT1170 #define MG_OTA_RT1170 304 // IMXRT1170
#define MG_OTA_MCXN 310 // MCXN947 #define MG_OTA_MCXN 310 // MCXN947
#define MG_OTA_FRDM 320 // FRDM-RW612 #define MG_OTA_RW612 320 // FRDM-RW612
#define MG_OTA_FLASH 900 // OTA via an internal flash #define MG_OTA_FLASH 900 // OTA via an internal flash
#define MG_OTA_ESP32 910 // ESP32 OTA implementation #define MG_OTA_ESP32 910 // ESP32 OTA implementation
#define MG_OTA_PICOSDK 920 // RP2040/2350 using Pico-SDK hardware_flash #define MG_OTA_PICOSDK 920 // RP2040/2350 using Pico-SDK hardware_flash
@@ -3023,34 +3147,104 @@ bool mg_ota_flash_end(struct mg_flash *flash);
struct mg_wifi_scan_bss_data { struct mg_wifi_data {
struct mg_str SSID; char *ssid, *pass; // STA mode, SSID to connect to
char *BSSID; char *apssid, *appass; // AP mode, our SSID
int16_t RSSI; uint32_t apip, apmask; // AP mode, our IP address and mask
uint8_t security; uint8_t security; // STA mode, TBD
#define MG_WIFI_SECURITY_OPEN 0 uint8_t apsecurity; // AP mode, TBD
#define MG_WIFI_SECURITY_WEP MG_BIT(0) uint8_t apchannel; // AP mode, channel to use
#define MG_WIFI_SECURITY_WPA MG_BIT(1) bool apmode; // start in AP mode; 'false' -> connect to 'ssid' != NULL
#define MG_WIFI_SECURITY_WPA2 MG_BIT(2)
#define MG_WIFI_SECURITY_WPA3 MG_BIT(3)
uint8_t channel;
unsigned band :2;
#define MG_WIFI_BAND_2G 0
#define MG_WIFI_BAND_5G 1
unsigned has_n :1;
}; };
struct mg_wifi_scan_bss_data {
struct mg_str SSID;
char *BSSID;
int16_t RSSI;
uint8_t security;
#define MG_WIFI_SECURITY_OPEN 0
#define MG_WIFI_SECURITY_WEP MG_BIT(0)
#define MG_WIFI_SECURITY_WPA MG_BIT(1)
#define MG_WIFI_SECURITY_WPA2 MG_BIT(2)
#define MG_WIFI_SECURITY_WPA3 MG_BIT(3)
#define MG_WIFI_SECURITY_WPA_ENTERPRISE MG_BIT(4)
#define MG_WIFI_SECURITY_WPA2_ENTERPRISE MG_BIT(5)
#define MG_WIFI_SECURITY_WPA3_ENTERPRISE MG_BIT(6)
uint8_t channel;
unsigned band : 2;
#define MG_WIFI_BAND_2G 0
#define MG_WIFI_BAND_5G 1
unsigned has_n : 1;
unsigned has_ac : 1;
unsigned has_ax : 1;
};
bool mg_wifi_scan(void); bool mg_wifi_scan(void);
bool mg_wifi_connect(char *ssid, char *pass); bool mg_wifi_connect(struct mg_wifi_data *);
bool mg_wifi_disconnect(void); bool mg_wifi_disconnect(void);
bool mg_wifi_ap_start(char *ssid, char *pass, unsigned int channel); bool mg_wifi_ap_start(struct mg_wifi_data *);
bool mg_wifi_ap_stop(void); bool mg_wifi_ap_stop(void);
#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
#if MG_ENABLE_TCPIP #if MG_ENABLE_TCPIP
@@ -3068,45 +3262,58 @@ typedef void (*mg_tcpip_event_handler_t)(struct mg_tcpip_if *ifp, int ev,
void *ev_data); void *ev_data);
enum { enum {
MG_TCPIP_EV_ST_CHG, // state change uint8_t * (&ifp->state) 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_DNS, // DHCP DNS assignment uint32_t *ipaddr
MG_TCPIP_EV_DHCP_SNTP, // DHCP SNTP 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_ARP, // Got ARP packet struct mg_str *
MG_TCPIP_EV_TIMER_1S, // 1 second timer NULL 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_RESULT, // Wi-Fi scan results struct
MG_TCPIP_EV_WIFI_SCAN_END, // Wi-Fi scan has finished NULL // mg_wifi_scan_bss_data *
MG_TCPIP_EV_WIFI_CONNECT_ERR, // Wi-Fi connect has failed driver and chip specific MG_TCPIP_EV_WIFI_SCAN_END, // Wi-Fi scan has finished NULL
MG_TCPIP_EV_DRIVER, // Driver event driver specific MG_TCPIP_EV_WIFI_CONNECT_ERR, // Wi-Fi connect has failed driver and
MG_TCPIP_EV_USER // Starting ID for user events // 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 // Network interface
struct mg_tcpip_if { struct mg_tcpip_if {
uint8_t mac[6]; // MAC address. Must be set to a valid MAC uint8_t mac[sizeof(struct mg_l2addr)]; // hw address. Set to a valid addr
uint32_t ip, mask, gw; // IP address, mask, default gateway uint32_t ip, mask, gw; // IP address, mask, default gateway
struct mg_str tx; // Output (TX) buffer struct mg_str tx; // Output (TX) buffer
bool enable_dhcp_client; // Enable DCHP client bool enable_dhcp_client; // Enable DCHP client
bool enable_dhcp_server; // Enable DCHP server bool enable_dhcp_server; // Enable DCHP server
bool enable_get_gateway; // DCHP server sets client as gateway bool enable_get_gateway; // DCHP server sets client as gateway
bool enable_req_dns; // DCHP client requests DNS server bool enable_req_dns; // DCHP client requests DNS server
bool enable_req_sntp; // DCHP client requests SNTP 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_crc32_check; // Do a CRC check on RX frames and strip it
bool enable_mac_check; // Do a MAC check on RX frames bool enable_mac_check; // Do a MAC check on RX frames
bool update_mac_hash_table; // Signal drivers to update MAC controller bool update_mac_hash_table; // Signal drivers to update MAC controller
struct mg_tcpip_driver *driver; // Low level driver struct mg_tcpip_driver *driver; // Low level driver
void *driver_data; // Driver-specific data 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 mg_tcpip_event_handler_t fn; // User-specified event handler function
struct mg_mgr *mgr; // Mongoose event manager struct mg_mgr *mgr; // Mongoose event manager
struct mg_queue recv_queue; // Receive queue struct mg_queue recv_queue; // Receive queue
char dhcp_name[12]; // Name reported to DHCP, "mip" if unset char dhcp_name[MG_TCPIP_DHCPNAME_SIZE]; // Name for DHCP, "mip" if unset
uint16_t mtu; // Interface MTU uint16_t mtu; // Interface link payload
#define MG_TCPIP_MTU_DEFAULT 1500 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 // Internal state, user can use it but should not change it
uint8_t gwmac[6]; // Router's MAC uint8_t gwmac[sizeof(struct mg_l2addr)]; // Router's hw address
char *dns4_url; // DNS server URL enum mg_l2type l2type; // Ethernet, PPP, etc.
uint64_t now; // Current time 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 timer_1000ms; // 1000 ms timer: for DHCP and link state
uint64_t lease_expire; // Lease expiration time, in ms uint64_t lease_expire; // Lease expiration time, in ms
uint16_t eport; // Next ephemeral port uint16_t eport; // Next ephemeral port
@@ -3114,12 +3321,18 @@ struct mg_tcpip_if {
volatile uint32_t nrecv; // Number of received frames volatile uint32_t nrecv; // Number of received frames
volatile uint32_t nsent; // Number of transmitted frames volatile uint32_t nsent; // Number of transmitted frames
volatile uint32_t nerr; // Number of driver errors 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_DOWN 0 // Interface is down
#define MG_TCPIP_STATE_UP 1 // Interface is up #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_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_IP 3 // Interface is up and has an IP assigned
#define MG_TCPIP_STATE_READY 4 // Interface has fully come up, ready to work #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 *); void mg_tcpip_init(struct mg_mgr *, struct mg_tcpip_if *);
@@ -3143,6 +3356,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_pico_w;
extern struct mg_tcpip_driver mg_tcpip_driver_rw612; 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_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 // Drivers that require SPI, can use this SPI abstraction
struct mg_tcpip_spi { struct mg_tcpip_spi {
@@ -3152,6 +3367,42 @@ struct mg_tcpip_spi {
uint8_t (*txn)(void *, uint8_t); // SPI transaction: write 1 byte, read reply uint8_t (*txn)(void *, uint8_t); // SPI transaction: write 1 byte, read reply
}; };
// 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 #endif
@@ -3186,43 +3437,35 @@ struct mg_tcpip_driver_cyw_firmware {
}; };
struct mg_tcpip_driver_cyw_data { struct mg_tcpip_driver_cyw_data {
struct mg_wifi_data wifi;
void *bus; void *bus;
struct mg_tcpip_driver_cyw_firmware *fw; struct mg_tcpip_driver_cyw_firmware *fw;
char *ssid; bool hs; // use chip "high-speed" mode; otherwise SPI CPOL0 CPHA0 (DS 4.2.3 Table 6)
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)
}; };
#if 0 #define MG_TCPIP_DRIVER_INIT(mgr) \
#define MG_TCPIP_DRIVER_INIT(mgr) \ do { \
do { \ static struct mg_tcpip_driver_cyw_data driver_data_; \
static struct mg_tcpip_driver_cyw_data driver_data_; \ static struct mg_tcpip_if mif_; \
static struct mg_tcpip_if mif_; \ MG_SET_WIFI_CONFIG(&driver_data_); \
MG_SET_WIFI_CONFIG(&driver_data_); \ mif_.ip = MG_TCPIP_IP; \
mif_.ip = MG_TCPIP_IP; \ mif_.mask = MG_TCPIP_MASK; \
mif_.mask = MG_TCPIP_MASK; \ mif_.gw = MG_TCPIP_GW; \
mif_.gw = MG_TCPIP_GW; \ mif_.driver = &mg_tcpip_driver_cyw; \
mif_.driver = &mg_tcpip_driver_pico_w; \ mif_.driver_data = &driver_data_; \
mif_.driver_data = &driver_data_; \ mif_.recv_queue.size = 8192; \
mif_.recv_queue.size = 8192; \ mif_.mac[0] = 2; /* MAC read from OTP at driver init */ \
mif_.mac[0] = 2; /* MAC read from OTP at driver init */ \ mg_tcpip_init(mgr, &mif_); \
mg_tcpip_init(mgr, &mif_); \
MG_INFO(("Driver: cyw, MAC: %M", mg_print_mac, mif_.mac)); \ MG_INFO(("Driver: cyw, MAC: %M", mg_print_mac, mif_.mac)); \
} while (0) } while (0)
#endif
#endif #endif
#if MG_ENABLE_TCPIP && \ #if MG_ENABLE_TCPIP && \
(defined(MG_ENABLE_DRIVER_IMXRT10) && MG_ENABLE_DRIVER_IMXRT10) || \ (defined(MG_ENABLE_DRIVER_IMXRT10) && MG_ENABLE_DRIVER_IMXRT10) || \
(defined(MG_ENABLE_DRIVER_IMXRT11) && MG_ENABLE_DRIVER_IMXRT11) (defined(MG_ENABLE_DRIVER_IMXRT11) && MG_ENABLE_DRIVER_IMXRT11) || \
(defined(MG_ENABLE_DRIVER_MCXE) && MG_ENABLE_DRIVER_MCXE)
struct mg_tcpip_driver_imxrt_data { struct mg_tcpip_driver_imxrt_data {
// MDC clock divider. MDC clock is derived from IPS Bus clock (ipg_clk), // MDC clock divider. MDC clock is derived from IPS Bus clock (ipg_clk),
@@ -3268,6 +3511,34 @@ struct mg_tcpip_driver_imxrt_data {
#endif #endif
#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
struct mg_phy { struct mg_phy {
@@ -3298,14 +3569,7 @@ bool mg_phy_up(struct mg_phy *, uint8_t addr, bool *full_duplex,
#include "pico/unique_id.h" // keep this include #include "pico/unique_id.h" // keep this include
struct mg_tcpip_driver_pico_w_data { struct mg_tcpip_driver_pico_w_data {
char *ssid; struct mg_wifi_data wifi;
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
}; };
#define MG_TCPIP_DRIVER_INIT(mgr) \ #define MG_TCPIP_DRIVER_INIT(mgr) \
@@ -3501,6 +3765,43 @@ bool mg_sdio_transfer(struct mg_tcpip_sdio *sdio, bool write, unsigned int f,
#endif #endif
#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
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_STM32F) && \ #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_STM32F) && \
MG_ENABLE_DRIVER_STM32F MG_ENABLE_DRIVER_STM32F
@@ -3562,7 +3863,10 @@ struct mg_tcpip_driver_stm32f_data {
#if !defined(MG_ENABLE_DRIVER_MCXN) #if !defined(MG_ENABLE_DRIVER_MCXN)
#define MG_ENABLE_DRIVER_MCXN 0 #define MG_ENABLE_DRIVER_MCXN 0
#endif #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 { struct mg_tcpip_driver_stm32h_data {
// MDC clock divider. MDC clock is derived from HCLK, must not exceed 2.5MHz // MDC clock divider. MDC clock is derived from HCLK, must not exceed 2.5MHz
@@ -3601,6 +3905,18 @@ struct mg_tcpip_driver_stm32h_data {
#define MG_ENABLE_ETH_IRQ() #define MG_ENABLE_ETH_IRQ()
#endif #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) \ #define MG_TCPIP_DRIVER_INIT(mgr) \
do { \ do { \
static struct mg_tcpip_driver_stm32h_data driver_data_; \ static struct mg_tcpip_driver_stm32h_data driver_data_; \
@@ -3614,6 +3930,7 @@ struct mg_tcpip_driver_stm32h_data {
mif_.driver = &mg_tcpip_driver_stm32h; \ mif_.driver = &mg_tcpip_driver_stm32h; \
mif_.driver_data = &driver_data_; \ mif_.driver_data = &driver_data_; \
MG_SET_MAC_ADDRESS(mif_.mac); \ MG_SET_MAC_ADDRESS(mif_.mac); \
MG_IPV6_INIT(mif_); \
mg_tcpip_init(mgr, &mif_); \ mg_tcpip_init(mgr, &mif_); \
MG_ENABLE_ETH_IRQ(); \ MG_ENABLE_ETH_IRQ(); \
MG_INFO(("Driver: stm32h, MAC: %M", mg_print_mac, mif_.mac)); \ MG_INFO(("Driver: stm32h, MAC: %M", mg_print_mac, mif_.mac)); \
+6 -2
View File
@@ -35,11 +35,14 @@
#define MG_ENABLE_TCPIP 1 // Enable built-in TCP/IP stack #define MG_ENABLE_TCPIP 1 // Enable built-in TCP/IP stack
#endif #endif
#if MG_ENABLE_TCPIP && !defined(MG_ENABLE_DRIVER_STM32F) && !defined(MG_ENABLE_DRIVER_STM32H) #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) #if defined(STM32F1) || defined(STM32F2) || defined(STM32F4) || defined(STM32F7)
#define MG_ENABLE_DRIVER_STM32F 1 #define MG_ENABLE_DRIVER_STM32F 1
#elif defined(STM32H5) || defined(STM32H7) #elif defined(STM32H5) || defined(STM32H7)
#define MG_ENABLE_DRIVER_STM32H 1 #define MG_ENABLE_DRIVER_STM32H 1
#elif defined(STM32N6)
#define MG_ENABLE_DRIVER_STM32N 1
#else #else
#error Select a driver in mongoose_config.h #error Select a driver in mongoose_config.h
#endif #endif
@@ -49,7 +52,8 @@
#define MG_TLS MG_TLS_BUILTIN #define MG_TLS MG_TLS_BUILTIN
#endif #endif
#if !defined(MG_OTA) && defined(STM32F1) || defined(STM32F2) || defined(STM32F4) || defined(STM32F7) #if !defined(MG_OTA) && defined(STM32F1) || defined(STM32F2) || \
defined(STM32F4) || defined(STM32F7)
#define MG_OTA MG_OTA_STM32F #define MG_OTA MG_OTA_STM32F
#elif !defined(MG_OTA) && defined(STM32H5) #elif !defined(MG_OTA) && defined(STM32H5)
#define MG_OTA MG_OTA_STM32H5 #define MG_OTA MG_OTA_STM32H5
+1
View File
@@ -17,6 +17,7 @@
#define mode_t size_t #define mode_t size_t
#include <alloca.h> #include <alloca.h>
#include <time.h> #include <time.h>
#define strdup(s) ((char *) mg_strdup(mg_str(s)).buf)
#elif defined(__CCRH__) #elif defined(__CCRH__)
#else #else
#include <sys/stat.h> #include <sys/stat.h>
+4 -1
View File
@@ -110,7 +110,10 @@ typedef enum { false = 0, true = 1 } bool;
#endif #endif
#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 defined(_MSC_VER)
#if MG_ENABLE_WINSOCK #if MG_ENABLE_WINSOCK
#pragma comment(lib, "ws2_32.lib") #pragma comment(lib, "ws2_32.lib")
+5 -3
View File
@@ -3,13 +3,15 @@
#if MG_ARCH == MG_ARCH_ZEPHYR #if MG_ARCH == MG_ARCH_ZEPHYR
#include <zephyr/kernel.h> #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 <zephyr/version.h>
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <zephyr/net/socket.h>
#include <zephyr/posix/fcntl.h>
#include <zephyr/posix/sys/select.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
+24
View File
@@ -175,10 +175,34 @@
#define MG_TCPIP_GW MG_IPV4(0, 0, 0, 0) // Default is 0.0.0.0 (DHCP) #define MG_TCPIP_GW MG_IPV4(0, 0, 0, 0) // Default is 0.0.0.0 (DHCP)
#endif #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 #ifndef MG_SET_MAC_ADDRESS
#define MG_SET_MAC_ADDRESS(mac) #define MG_SET_MAC_ADDRESS(mac)
#endif #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 #ifndef MG_SET_WIFI_CONFIG
#define MG_SET_WIFI_CONFIG(data) #define MG_SET_WIFI_CONFIG(data)
#endif #endif
+332 -57
View File
@@ -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 if (j < tolen) to[j] = '\0'; // Zero-terminate this chunk
// MG_INFO(("--> [%s]", to)); // 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; 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)); mg_dns_parse_name(buf, len, ofs, dm->name, sizeof(dm->name));
ofs += n; 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; 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; dm->resolved = true;
break; // Return success 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; 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; dm->resolved = true;
break; // Return success break; // Return success
} }
@@ -255,8 +256,12 @@ static void mg_sendnsreq(struct mg_connection *c, struct mg_str *name, int ms,
mg_error(c, "resolve OOM"); mg_error(c, "resolve OOM");
} else { } else {
struct dns_data *reqs = (struct dns_data *) c->mgr->active_dns_requests; struct dns_data *reqs = (struct dns_data *) c->mgr->active_dns_requests;
d->txnid = reqs ? (uint16_t) (reqs->txnid + 1) : 1; uint16_t id;
d->next = (struct dns_data *) c->mgr->active_dns_requests; 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; c->mgr->active_dns_requests = d;
d->expire = mg_millis() + (uint64_t) ms; d->expire = mg_millis() + (uint64_t) ms;
d->c = c; d->c = c;
@@ -282,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[] = { static const uint8_t mdns_answer[] = {
0, 1, // 2 bytes - record type, A 0, 1, // 2 bytes - record type, A
0, 1, // 2 bytes - address class, INET 0, 1, // 2 bytes - address class, INET
@@ -289,65 +295,334 @@ static const uint8_t mdns_answer[] = {
0, 4 // 2 bytes - address length 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) { static void mdns_cb(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_READ) { if (ev == MG_EV_READ) {
struct mg_dns_header *qh = (struct mg_dns_header *) c->recv.buf; handle_mdns_record(c);
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'));
}
}
}
mg_iobuf_del(&c->recv, 0, c->recv.len); mg_iobuf_del(&c->recv, 0, c->recv.len);
} }
(void) ev_data; (void) ev_data;
} }
void mg_multicast_add(struct mg_connection *c, char *ip); 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 = struct mg_connection *c =
mg_listen(mgr, "udp://224.0.0.251:5353", mdns_cb, name); mg_listen(mgr, "udp://224.0.0.251:5353", fn, fn_data);
if (c != NULL) mg_multicast_add(c, (char *)"224.0.0.251"); 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; 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);
}
+36 -1
View File
@@ -3,6 +3,12 @@
#include "net.h" #include "net.h"
#include "str.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: // Mongoose sends DNS queries that contain only one question:
// either A (IPv4) or AAAA (IPv6) address lookup. // either A (IPv4) or AAAA (IPv6) address lookup.
// Therefore, we expect zero or one answer. // Therefore, we expect zero or one answer.
@@ -31,10 +37,39 @@ struct mg_dns_rr {
uint16_t alen; // Address length 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(struct mg_connection *, const char *url);
void mg_resolve_cancel(struct mg_connection *); void mg_resolve_cancel(struct mg_connection *);
bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *); 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, size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs,
bool is_question, struct mg_dns_rr *); 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);
+36 -16
View File
@@ -13,28 +13,42 @@
#endif #endif
static struct mg_tcpip_if *s_ifp; static struct mg_tcpip_if *s_ifp;
static uint32_t s_ip, s_mask;
static bool s_link, s_auth, s_join; 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 bool cyw_init(uint8_t *mac);
static void cyw_poll(void); static void cyw_poll(void);
static bool mg_tcpip_driver_cyw_init(struct mg_tcpip_if *ifp) { 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 *d =
(struct mg_tcpip_driver_cyw_data *) ifp->driver_data; (struct mg_tcpip_driver_cyw_data *) ifp->driver_data;
struct mg_wifi_data *wifi = &d->wifi;
if (MG_BIG_ENDIAN) { if (MG_BIG_ENDIAN) {
MG_ERROR(("Big-endian host")); MG_ERROR(("Big-endian host"));
return false; return false;
} }
s_ifp = ifp; s_ifp = ifp;
s_ip = ifp->ip;
s_mask = ifp->mask;
s_link = s_auth = s_join = false; s_link = s_auth = s_join = false;
ifp->pfn = wifi_cb;
if (!cyw_init(ifp->mac)) return false; if (!cyw_init(ifp->mac)) return false;
if (d->apmode) { if (wifi->apmode) {
MG_DEBUG(("Starting AP '%s' (%u)", d->apssid, d->apchannel)); return mg_wifi_ap_start(wifi);
return mg_wifi_ap_start(d->apssid, d->appass, d->apchannel); } else if (wifi->ssid != NULL && wifi->pass != NULL) {
} else if (d->ssid != NULL && d->pass != NULL) { return mg_wifi_connect(wifi);
MG_DEBUG(("Connecting to '%s'", d->ssid));
return mg_wifi_connect(d->ssid, d->pass);
} }
return true; return true;
} }
@@ -44,7 +58,7 @@ size_t mg_tcpip_driver_cyw_output(const void *buf, size_t len,
struct mg_tcpip_if *ifp) { struct mg_tcpip_if *ifp) {
struct mg_tcpip_driver_cyw_data *d = struct mg_tcpip_driver_cyw_data *d =
(struct mg_tcpip_driver_cyw_data *) ifp->driver_data; (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) { static bool mg_tcpip_driver_cyw_poll(struct mg_tcpip_if *ifp, bool s1) {
@@ -52,7 +66,7 @@ static bool mg_tcpip_driver_cyw_poll(struct mg_tcpip_if *ifp, bool s1) {
if (!s1) return false; if (!s1) return false;
struct mg_tcpip_driver_cyw_data *d = struct mg_tcpip_driver_cyw_data *d =
(struct mg_tcpip_driver_cyw_data *) ifp->driver_data; (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, struct mg_tcpip_driver mg_tcpip_driver_cyw = {mg_tcpip_driver_cyw_init,
@@ -279,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 status = mg_ntohl(msg->event.status);
uint32_t reason = mg_ntohl(msg->event.reason); uint32_t reason = mg_ntohl(msg->event.reason);
uint16_t flags = mg_ntohs(msg->event.flags); 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 if (event_type == 16 && status == 0) { // Link
s_link = flags & 1; s_link = flags & 1;
} else if (event_type == 46 && s_link) { // PSK sup with link up } else if (event_type == 46 && s_link) { // PSK sup with link up
@@ -602,7 +616,7 @@ static void cyw_handle_cdc(struct cdc_hdr *cdc, size_t len) {
return; return;
} }
if (mg_log_level >= MG_LL_VERBOSE) mg_hexdump((void *) cdc, len); if (mg_log_level >= MG_LL_VERBOSE) mg_hexdump((void *) cdc, len);
MG_DEBUG(("IOCTL result: %02x %02x %02x %02x ...", r[0], r[1], r[2], r[3])); MG_VERBOSE(("IOCTL result: %02x %02x %02x %02x ..", r[0], r[1], r[2], r[3]));
s_ioctl_resp = r; s_ioctl_resp = r;
} }
// NOTE(): alt no loop handler dispatching IOCTL response to current handler: // NOTE(): alt no loop handler dispatching IOCTL response to current handler:
@@ -1035,7 +1049,7 @@ static size_t cyw_spi_poll(uint8_t *response) {
cyw_spi_write(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; return 0;
} }
cyw_spi_read(CYW_SPID_FUNC_WLAN, 0, response, len); cyw_spi_read(CYW_SPID_FUNC_WLAN, 0, response, (uint16_t)len);
return len; return len;
} }
@@ -1098,7 +1112,7 @@ static bool cyw_spi_init() {
cyw_set_backplane_window(CYW_CHIP_CHIPCOMMON); // set backplane window to start of CHIPCOMMON area cyw_set_backplane_window(CYW_CHIP_CHIPCOMMON); // set backplane window to start of CHIPCOMMON area
cyw_spi_read(CYW_SPID_FUNC_CHIP, (CYW_CHIP_CHIPCOMMON + 0x00) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 2); cyw_spi_read(CYW_SPID_FUNC_CHIP, (CYW_CHIP_CHIPCOMMON + 0x00) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 2);
if (val == 43430) val = 4343; if (val == 43430) val = 4343;
MG_INFO(("WLAN chip is CYW%u%c", val), val == 4343 ? 'W' : ' ')); MG_INFO(("WLAN chip is CYW%u%c", val, val == 4343 ? 'W' : ' '));
// Load firmware (code and NVRAM) // Load firmware (code and NVRAM)
if (!cyw_load_firmware(d->fw)) return false; if (!cyw_load_firmware(d->fw)) return false;
@@ -1376,16 +1390,22 @@ bool mg_wifi_scan(void) {
return cyw_wifi_scan(); return cyw_wifi_scan();
} }
bool mg_wifi_connect(char *ssid, char *pass) { bool mg_wifi_connect(struct mg_wifi_data *wifi) {
return cyw_wifi_connect(ssid, pass); 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) { bool mg_wifi_disconnect(void) {
return cyw_wifi_disconnect(); return cyw_wifi_disconnect();
} }
bool mg_wifi_ap_start(char *ssid, char *pass, unsigned int channel) { bool mg_wifi_ap_start(struct mg_wifi_data *wifi) {
return cyw_wifi_ap_start(ssid, pass, channel); 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) { bool mg_wifi_ap_stop(void) {
+15 -24
View File
@@ -22,35 +22,26 @@ struct mg_tcpip_driver_cyw_firmware {
}; };
struct mg_tcpip_driver_cyw_data { struct mg_tcpip_driver_cyw_data {
struct mg_wifi_data wifi;
void *bus; void *bus;
struct mg_tcpip_driver_cyw_firmware *fw; struct mg_tcpip_driver_cyw_firmware *fw;
char *ssid; bool hs; // use chip "high-speed" mode; otherwise SPI CPOL0 CPHA0 (DS 4.2.3 Table 6)
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)
}; };
#if 0 #define MG_TCPIP_DRIVER_INIT(mgr) \
#define MG_TCPIP_DRIVER_INIT(mgr) \ do { \
do { \ static struct mg_tcpip_driver_cyw_data driver_data_; \
static struct mg_tcpip_driver_cyw_data driver_data_; \ static struct mg_tcpip_if mif_; \
static struct mg_tcpip_if mif_; \ MG_SET_WIFI_CONFIG(&driver_data_); \
MG_SET_WIFI_CONFIG(&driver_data_); \ mif_.ip = MG_TCPIP_IP; \
mif_.ip = MG_TCPIP_IP; \ mif_.mask = MG_TCPIP_MASK; \
mif_.mask = MG_TCPIP_MASK; \ mif_.gw = MG_TCPIP_GW; \
mif_.gw = MG_TCPIP_GW; \ mif_.driver = &mg_tcpip_driver_cyw; \
mif_.driver = &mg_tcpip_driver_pico_w; \ mif_.driver_data = &driver_data_; \
mif_.driver_data = &driver_data_; \ mif_.recv_queue.size = 8192; \
mif_.recv_queue.size = 8192; \ mif_.mac[0] = 2; /* MAC read from OTP at driver init */ \
mif_.mac[0] = 2; /* MAC read from OTP at driver init */ \ mg_tcpip_init(mgr, &mif_); \
mg_tcpip_init(mgr, &mif_); \
MG_INFO(("Driver: cyw, MAC: %M", mg_print_mac, mif_.mac)); \ MG_INFO(("Driver: cyw, MAC: %M", mg_print_mac, mif_.mac)); \
} while (0) } while (0)
#endif
#endif #endif
+16 -10
View File
@@ -2,7 +2,8 @@
#if MG_ENABLE_TCPIP && \ #if MG_ENABLE_TCPIP && \
(defined(MG_ENABLE_DRIVER_IMXRT10) && MG_ENABLE_DRIVER_IMXRT10) || \ (defined(MG_ENABLE_DRIVER_IMXRT10) && MG_ENABLE_DRIVER_IMXRT10) || \
(defined(MG_ENABLE_DRIVER_IMXRT11) && MG_ENABLE_DRIVER_IMXRT11) (defined(MG_ENABLE_DRIVER_IMXRT11) && MG_ENABLE_DRIVER_IMXRT11) || \
(defined(MG_ENABLE_DRIVER_MCXE) && MG_ENABLE_DRIVER_MCXE)
struct imxrt_enet { struct imxrt_enet {
volatile uint32_t RESERVED0, EIR, EIMR, RESERVED1, RDAR, TDAR, RESERVED2[3], volatile uint32_t RESERVED0, EIR, EIMR, RESERVED1, RDAR, TDAR, RESERVED2[3],
ECR, RESERVED3[6], MMFR, MSCR, RESERVED4[7], MIBC, RESERVED5[7], RCR, ECR, RESERVED3[6], MMFR, MSCR, RESERVED4[7], MIBC, RESERVED5[7], RCR,
@@ -31,9 +32,12 @@ struct imxrt_enet {
#if defined(MG_ENABLE_DRIVER_IMXRT11) && MG_ENABLE_DRIVER_IMXRT11 #if defined(MG_ENABLE_DRIVER_IMXRT11) && MG_ENABLE_DRIVER_IMXRT11
#define ENET ((struct imxrt_enet *) (uintptr_t) 0x40424000U) #define ENET ((struct imxrt_enet *) (uintptr_t) 0x40424000U)
#define ETH_DESC_CNT 5 // Descriptors count #define ETH_DESC_CNT 5 // Descriptors count
#else #elif defined(MG_ENABLE_DRIVER_IMXRT10) && MG_ENABLE_DRIVER_IMXRT10
#define ENET ((struct imxrt_enet *) (uintptr_t) 0x402D8000U) #define ENET ((struct imxrt_enet *) (uintptr_t) 0x402D8000U)
#define ETH_DESC_CNT 4 // Descriptors count #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 #endif
#define ETH_PKT_SIZE 1536 // Max frame size, 64-bit aligned #define ETH_PKT_SIZE 1536 // Max frame size, 64-bit aligned
@@ -44,15 +48,12 @@ struct enet_desc {
uint32_t *buffer; // Data ptr 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) // Descriptors: in non-cached area (TODO(scaprile)), (37.5.1.22.2 37.5.1.23.2)
// Buffers: 64-byte aligned (37.3.14) // 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_rxdesc[ETH_DESC_CNT] MG_ETH_RAM MG_64BYTE_ALIGNED;
static volatile struct enet_desc s_txdesc[ETH_DESC_CNT] 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_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_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 struct mg_tcpip_if *s_ifp; // MIP interface
static uint16_t enet_read_phy(uint8_t addr, uint8_t reg) { static uint16_t enet_read_phy(uint8_t addr, uint8_t reg) {
@@ -189,9 +190,14 @@ static bool mg_tcpip_driver_imxrt_poll(struct mg_tcpip_if *ifp, bool s1) {
return up; return up;
} }
void ENET_IRQHandler(void);
static uint32_t s_rxno; static uint32_t s_rxno;
#if !defined(MG_ENABLE_DRIVER_MCXE)
void ENET_IRQHandler(void);
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 ENET->EIR = MG_BIT(25); // Ack IRQ
// Frame received, loop // Frame received, loop
for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever
+2 -1
View File
@@ -2,7 +2,8 @@
#if MG_ENABLE_TCPIP && \ #if MG_ENABLE_TCPIP && \
(defined(MG_ENABLE_DRIVER_IMXRT10) && MG_ENABLE_DRIVER_IMXRT10) || \ (defined(MG_ENABLE_DRIVER_IMXRT10) && MG_ENABLE_DRIVER_IMXRT10) || \
(defined(MG_ENABLE_DRIVER_IMXRT11) && MG_ENABLE_DRIVER_IMXRT11) (defined(MG_ENABLE_DRIVER_IMXRT11) && MG_ENABLE_DRIVER_IMXRT11) || \
(defined(MG_ENABLE_DRIVER_MCXE) && MG_ENABLE_DRIVER_MCXE)
struct mg_tcpip_driver_imxrt_data { struct mg_tcpip_driver_imxrt_data {
// MDC clock divider. MDC clock is derived from IPS Bus clock (ipg_clk), // MDC clock divider. MDC clock is derived from IPS Bus clock (ipg_clk),
+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
+37 -14
View File
@@ -1,13 +1,15 @@
#include "phy.h" #include "phy.h"
enum { // ID1 ID2 enum { // ID1 ID2
MG_PHY_KSZ8x = 0x22, // 0022 1561 - KSZ8081RNB MG_PHY_KSZ8x = 0x22, // 0022 156x - KSZ8081RNB, KSZ8091RNB
MG_PHY_DP83x = 0x2000, MG_PHY_DP83x = 0x2000,
MG_PHY_DP83867 = 0xa231, // 2000 a231 - TI DP83867I MG_PHY_DP83867 = 0xa231, // 2000 a231 - TI DP83867I
MG_PHY_DP83825 = 0xa140, // 2000 a140 - TI DP83825I MG_PHY_DP83825 = 0xa140, // 2000 a140 - TI DP83825I
MG_PHY_DP83848 = 0x5ca2, // 2000 5ca2 - TI DP83848I MG_PHY_DP83848 = 0x5ca2, // 2000 5ca2 - TI DP83848I
MG_PHY_LAN87x = 0x7, // 0007 c0fx - LAN8720 MG_PHY_LAN87x = 0x7, // 0007 c0fx - LAN8720
MG_PHY_RTL8201 = 0x1C, // 001c c816 - RTL8201, MG_PHY_RTL82x = 0x1c,
MG_PHY_RTL8201 = 0xc816, // 001c c816 - RTL8201F
MG_PHY_RTL8211 = 0xc916, // 001c c916 - RTL8211F
MG_PHY_ICS1894x = 0x15, MG_PHY_ICS1894x = 0x15,
MG_PHY_ICS189432 = 0xf450 // 0015 f450 - ICS1894 MG_PHY_ICS189432 = 0xf450 // 0015 f450 - ICS1894
}; };
@@ -24,8 +26,9 @@ enum {
MG_PHY_KSZ8x_REG_PC1R = 30, MG_PHY_KSZ8x_REG_PC1R = 30,
MG_PHY_KSZ8x_REG_PC2R = 31, MG_PHY_KSZ8x_REG_PC2R = 31,
MG_PHY_LAN87x_REG_SCSR = 31, MG_PHY_LAN87x_REG_SCSR = 31,
MG_PHY_RTL8201_REG_RMSR = 16, // in page 7 MG_PHY_RTL82x_REG_PAGESEL = 31,
MG_PHY_RTL8201_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 MG_PHY_ICS189432_REG_POLL = 17
}; };
@@ -46,14 +49,20 @@ static const char *mg_phy_id_to_str(uint16_t id1, uint16_t id2) {
return "KSZ8x"; return "KSZ8x";
case MG_PHY_LAN87x: case MG_PHY_LAN87x:
return "LAN87x"; return "LAN87x";
case MG_PHY_RTL8201: case MG_PHY_RTL82x:
return "RTL8201"; switch (id2) {
case MG_PHY_RTL8201:
return "RTL8201";
case MG_PHY_RTL8211:
return "RTL8211";
default:
return "RTL82x";
}
case MG_PHY_ICS1894x: case MG_PHY_ICS1894x:
return "ICS1894x"; return "ICS1894x";
default: default:
return "unknown"; return "unknown";
} }
(void) id2;
} }
void mg_phy_init(struct mg_phy *phy, uint8_t phy_addr, uint8_t config) { void mg_phy_init(struct mg_phy *phy, uint8_t phy_addr, uint8_t config) {
@@ -91,13 +100,15 @@ void mg_phy_init(struct mg_phy *phy, uint8_t phy_addr, uint8_t config) {
(uint16_t) (MG_BIT(15) | MG_BIT(8) | MG_BIT(7))); (uint16_t) (MG_BIT(15) | MG_BIT(8) | MG_BIT(7)));
} else if (id1 == MG_PHY_LAN87x) { } else if (id1 == MG_PHY_LAN87x) {
// nothing to do // nothing to do
} else if (id1 == MG_PHY_RTL8201) { } else if (id1 == MG_PHY_RTL82x && id2 == MG_PHY_RTL8201) {
// assume PHY has been hardware strapped properly // assume PHY has been hardware strapped properly
#if 0 #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_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 #endif
} else if (id1 == MG_PHY_RTL82x && id2 == MG_PHY_RTL8211) {
// assume PHY has been hardware strapped properly
} }
} }
@@ -137,10 +148,22 @@ 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); uint16_t scsr = phy->read_reg(phy_addr, MG_PHY_LAN87x_REG_SCSR);
*full_duplex = scsr & MG_BIT(4); *full_duplex = scsr & MG_BIT(4);
*speed = (scsr & MG_BIT(3)) ? MG_PHY_SPEED_100M : MG_PHY_SPEED_10M; *speed = (scsr & MG_BIT(3)) ? MG_PHY_SPEED_100M : MG_PHY_SPEED_10M;
} else if (id1 == MG_PHY_RTL8201) { } else if (id1 == MG_PHY_RTL82x) {
uint16_t bcr = phy->read_reg(phy_addr, MG_PHY_REG_BCR); uint16_t id2 = phy->read_reg(phy_addr, MG_PHY_REG_ID2);
*full_duplex = bcr & MG_BIT(8); if (id2 == MG_PHY_RTL8211) {
*speed = (bcr & MG_BIT(13)) ? MG_PHY_SPEED_100M : MG_PHY_SPEED_10M; 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) { } else if (id1 == MG_PHY_ICS1894x) {
uint16_t poll_reg = phy->read_reg(phy_addr, MG_PHY_ICS189432_REG_POLL); uint16_t poll_reg = phy->read_reg(phy_addr, MG_PHY_ICS189432_REG_POLL);
*full_duplex = poll_reg & MG_BIT(14); *full_duplex = poll_reg & MG_BIT(14);
+45 -21
View File
@@ -6,23 +6,41 @@
#include "pico/stdlib.h" #include "pico/stdlib.h"
static struct mg_tcpip_if *s_ifp; 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) { 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 *d =
(struct mg_tcpip_driver_pico_w_data *) ifp->driver_data; (struct mg_tcpip_driver_pico_w_data *) ifp->driver_data;
struct mg_wifi_data *wifi = &d->wifi;
s_ifp = ifp; s_ifp = ifp;
s_ip = ifp->ip;
s_mask = ifp->mask;
ifp->pfn = wifi_cb;
if (cyw43_arch_init() != 0) if (cyw43_arch_init() != 0)
return false; // initialize async_context and WiFi chip return false; // initialize async_context and WiFi chip
if (d->apmode && d->apssid != NULL) { if (wifi->apmode && wifi->apssid != NULL) {
MG_DEBUG(("Starting AP '%s' (%u)", d->apssid, d->apchannel)); if (!mg_wifi_ap_start(wifi)) return false;
if (!mg_wifi_ap_start(d->apssid, d->appass, d->apchannel)) return false;
cyw43_wifi_get_mac(&cyw43_state, CYW43_ITF_STA, ifp->mac); // same MAC cyw43_wifi_get_mac(&cyw43_state, CYW43_ITF_STA, ifp->mac); // same MAC
} else { } else {
cyw43_arch_enable_sta_mode(); cyw43_arch_enable_sta_mode();
cyw43_wifi_get_mac(&cyw43_state, CYW43_ITF_STA, ifp->mac); cyw43_wifi_get_mac(&cyw43_state, CYW43_ITF_STA, ifp->mac);
if (d->ssid != NULL) { if (wifi->ssid != NULL) {
MG_DEBUG(("Connecting to '%s'", d->ssid)); return mg_wifi_connect(wifi);
return mg_wifi_connect(d->ssid, d->pass);
} else { } else {
cyw43_arch_disable_sta_mode(); 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 *d =
(struct mg_tcpip_driver_pico_w_data *) ifp->driver_data; (struct mg_tcpip_driver_pico_w_data *) ifp->driver_data;
return cyw43_send_ethernet(&cyw43_state, return cyw43_send_ethernet(&cyw43_state,
d->apmode ? CYW43_ITF_AP : CYW43_ITF_STA, len, buf, d->wifi.apmode ? CYW43_ITF_AP : CYW43_ITF_STA, len,
false) == 0 buf, false) == 0
? len ? len
: 0; : 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) { 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) cyw43_arch_poll(); // not necessary, except when IRQs are disabled (OTA)
if (s_scanning && !cyw43_wifi_scan_active(&cyw43_state)) { if (s_scanning && !cyw43_wifi_scan_active(&cyw43_state)) {
MG_VERBOSE(("scan complete")); MG_VERBOSE(("scan complete"));
s_scanning = 0; 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) { if (ifp->update_mac_hash_table) {
// first call to _poll() is after _init(), so this is safe // 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; ifp->update_mac_hash_table = false;
} }
if (!s1) return false; if (!s1) return false;
struct mg_tcpip_driver_pico_w_data *d = struct mg_tcpip_driver_pico_w_data *d =
(struct mg_tcpip_driver_pico_w_data *) ifp->driver_data; (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); int sdkstate = cyw43_wifi_link_status(&cyw43_state, CYW43_ITF_STA);
MG_VERBOSE(("conn: %c state: %d", s_connecting ? '1' : '0', sdkstate)); MG_VERBOSE(("conn: %c state: %d", s_connecting ? '1' : '0', sdkstate));
if (sdkstate < 0 && s_connecting) { 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; s_connecting = false;
} }
return s_stalink; 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) { void cyw43_cb_tcpip_set_link_down(cyw43_t *self, int itf) {
if (itf == CYW43_ITF_AP) { if (itf == CYW43_ITF_AP) {
s_aplink = false; s_aplink = false;
} else { } else {
s_stalink = false; s_stalink = false;
// SDK calls this before we check status, don't clear s_connecting here // SDK calls this before we check status, don't clear s_connecting here
@@ -134,9 +150,15 @@ bool mg_wifi_scan(void) {
return res; 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(); 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)); MG_VERBOSE(("res: %d", res));
if (res == 0) s_connecting = true; if (res == 0) s_connecting = true;
return (res == 0); return (res == 0);
@@ -148,9 +170,11 @@ bool mg_wifi_disconnect(void) {
return true; return true;
} }
bool mg_wifi_ap_start(char *ssid, char *pass, unsigned int channel) { bool mg_wifi_ap_start(struct mg_wifi_data *wifi) {
cyw43_wifi_ap_set_channel(&cyw43_state, channel); MG_DEBUG(("Starting AP '%s' (%u)", wifi->apssid, wifi->apchannel));
cyw43_arch_enable_ap_mode(ssid, pass, CYW43_AUTH_WPA2_AES_PSK); 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; return true;
} }
+1 -8
View File
@@ -8,14 +8,7 @@
#include "pico/unique_id.h" // keep this include #include "pico/unique_id.h" // keep this include
struct mg_tcpip_driver_pico_w_data { struct mg_tcpip_driver_pico_w_data {
char *ssid; struct mg_wifi_data wifi;
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
}; };
#define MG_TCPIP_DRIVER_INIT(mgr) \ #define MG_TCPIP_DRIVER_INIT(mgr) \
+5 -9
View File
@@ -38,16 +38,12 @@ struct ra_edmac {
#define ETH_PKT_SIZE 1536 // Max frame size, multiple of 32 #define ETH_PKT_SIZE 1536 // Max frame size, multiple of 32
#define ETH_DESC_CNT 4 // Descriptors count #define ETH_DESC_CNT 4 // Descriptors count
// 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 // Descriptors: 16-byte aligned
// Buffers: 32-byte aligned (27.3.1) // 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_rxdesc[ETH_DESC_CNT][4] MG_ETH_RAM MG_16BYTE_ALIGNED;
static volatile uint32_t s_txdesc[ETH_DESC_CNT][4] 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_32BYTE_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_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 static struct mg_tcpip_if *s_ifp; // MIP interface
// fastest is 3 cycles (SUB + BNE) on a 3-stage pipeline or equivalent // fastest is 3 cycles (SUB + BNE) on a 3-stage pipeline or equivalent
@@ -164,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)); MG_DEBUG(("PHY addr: %d, smispin: %d", d->phy_addr, s_smispin));
struct mg_phy phy = {raeth_read_phy, raeth_write_phy}; 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, // Select RMII mode,
ETHERC->ECMR = MG_BIT(2) | MG_BIT(1); // 100M, Full-duplex, CRC ETHERC->ECMR = MG_BIT(2) | MG_BIT(1); // 100M, Full-duplex, CRC
+5 -5
View File
@@ -26,17 +26,17 @@ struct ENET_Type {
CHANNEL_TCSR[4], CHANNEL_TCCR[4]; CHANNEL_TCSR[4], CHANNEL_TCCR[4];
}; };
#undef ENET
#define ENET ((struct ENET_Type *) 0x40138000) #define ENET ((struct ENET_Type *) 0x40138000)
#define ETH_PKT_SIZE 1536 // Max frame size #define ETH_PKT_SIZE 1536 // Max frame size
#define ETH_DESC_CNT 4 // Descriptors count #define ETH_DESC_CNT 4 // Descriptors count
#define ETH_DS 2 // Descriptor size (words) #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_ETH_RAM MG_8BYTE_ALIGNED;
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_ETH_RAM 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_ETH_RAM 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_ETH_RAM MG_8BYTE_ALIGNED;
static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS] MG_8BYTE_ALIGNED;
static uint8_t s_txno; // Current TX descriptor static uint8_t s_txno; // Current TX descriptor
static uint8_t s_rxno; // Current RX descriptor static uint8_t s_rxno; // Current RX descriptor
+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_DESC_CNT 4 // Descriptors count
#define ETH_DS 4 // Descriptor size (words) #define ETH_DS 4 // Descriptor size (words)
static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]; // RX descriptors 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]; // TX 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]; // RX ethernet buffers 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]; // TX 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_txno; // Current TX descriptor
static uint8_t s_rxno; // Current RX descriptor static uint8_t s_rxno; // Current RX descriptor
+123 -23
View File
@@ -1,9 +1,28 @@
#include "net_builtin.h" #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 // 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 // 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 { struct synopsys_enet_qos {
volatile uint32_t MACCR, MACECR, MACPFR, MACWTR, MACHT0R, MACHT1R, volatile uint32_t MACCR, MACECR, MACPFR, MACWTR, MACHT0R, MACHT1R,
RESERVED1[14], MACVTR, RESERVED2, MACVHTR, RESERVED3, MACVIR, MACIVIR, RESERVED1[14], MACVTR, RESERVED2, MACVHTR, RESERVED3, MACVIR, MACIVIR,
@@ -36,9 +55,9 @@ struct synopsys_enet_qos {
}; };
#undef ETH #undef ETH
#if MG_ENABLE_DRIVER_STM32H #if MG_ENABLE_DRIVER_STM32H
#define ETH \ #define ETH ((struct synopsys_enet_qos *) (uintptr_t) 0x40028000UL)
((struct synopsys_enet_qos *) (uintptr_t) (0x40000000UL + 0x00020000UL + \ #elif MG_ENABLE_DRIVER_STM32N
0x8000UL)) #define ETH ((struct synopsys_enet_qos *) (uintptr_t) 0x48036000UL)
#elif MG_ENABLE_DRIVER_MCXN #elif MG_ENABLE_DRIVER_MCXN
#define ETH ((struct synopsys_enet_qos *) (uintptr_t) 0x40100000UL) #define ETH ((struct synopsys_enet_qos *) (uintptr_t) 0x40100000UL)
#endif #endif
@@ -47,11 +66,74 @@ struct synopsys_enet_qos {
#define ETH_DESC_CNT 4 // Descriptors count #define ETH_DESC_CNT 4 // Descriptors count
#define ETH_DS 4 // Descriptor size (words) #define ETH_DS 4 // Descriptor size (words)
static volatile uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]; // RX descriptors #if MG_ENABLE_DRIVER_STM32H || MG_ENABLE_DRIVER_STM32N
static volatile uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors #define CACHE_LINESZ 32 // must be a whole number of (d)words (see DESC_SZW)
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // RX ethernet buffers #ifndef SCB
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // TX ethernet buffers struct m7_scb {
static struct mg_tcpip_if *s_ifp; // MIP interface 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) { static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) {
ETH->MACMDIOAR &= (0xF << 8); 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; uint8_t phy_conf = d == NULL ? MG_PHY_CLOCKS_MAC : d->phy_conf;
// Init RX descriptors // Init RX descriptors
memset((char *) s_rxdesc, 0, sizeof(s_rxdesc)); // manual init
for (int i = 0; i < ETH_DESC_CNT; i++) { 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][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 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 // Init TX descriptors
memset((char *) s_txdesc, 0, sizeof(s_txdesc)); // manual init
for (int i = 0; i < ETH_DESC_CNT; i++) { for (int i = 0; i < ETH_DESC_CNT; i++) {
s_txdesc[i][0] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer 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 ETH->DMAMR |= MG_BIT(0); // Software reset
for (int i = 0; i < 4; i++) 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->DMASBMR |= MG_BIT(12); // AAL NOTE(scaprile): is this actually needed
ETH->MACIER = 0; // Do not enable additional irq sources (reset value) ETH->MACIER = 0; // Do not enable additional irq sources (reset value)
ETH->MACTFCR = MG_BIT(7); // Disable zero-quanta pause 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 ETH->MACPFR = MG_BIT(10); // Perfect filtering
#endif #endif
struct mg_phy phy = {eth_read_phy, eth_write_phy}; 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->DMACTDRLR = ETH_DESC_CNT - 1; // ring length
ETH->DMACTDTPR = ETH->DMACTDTPR =
(uint32_t) (uintptr_t) s_txdesc; // first available descriptor address (uint32_t) (uintptr_t) s_txdesc; // first available descriptor address
ETH->DMACCR = 0; // DSL = 0 (contiguous descriptor table) (reset value) ETH->DMACCR = DESC_SKIPW << 18; // DSL (contiguous/sparse descriptor table)
#if !MG_ENABLE_DRIVER_STM32H #if SYNOPSYS_ENET_V5
MG_SET_BITS(ETH->DMACTCR, 0x3F << 16, MG_BIT(16)); MG_SET_BITS(ETH->DMACTCR, 0x3F << 16, MG_BIT(16));
MG_SET_BITS(ETH->DMACRCR, 0x3F << 16, MG_BIT(16)); MG_SET_BITS(ETH->DMACRCR, 0x3F << 16, MG_BIT(16));
#endif #endif
ETH->DMACIER = MG_BIT(6) | MG_BIT(15); // RIE, NIE ETH->DMACIER = MG_BIT(6) | MG_BIT(15); // RIE, NIE
ETH->MACCR = MG_BIT(0) | MG_BIT(1) | MG_BIT(13) | MG_BIT(14) | ETH->MACCR = MG_BIT(0) | MG_BIT(1) | MG_BIT(13) | MG_BIT(14) |
MG_BIT(15); // RE, TE, Duplex, Fast, Reserved MG_BIT(15); // RE, TE, Duplex, Fast, (10/100)/Reserved
#if MG_ENABLE_DRIVER_STM32H #if SYNOPSYS_ENET_SINGLEQ
ETH->MTLTQOMR |= MG_BIT(1); // TSF ETH->MTLTQOMR |= MG_BIT(1); // TSF
ETH->MTLRQOMR |= MG_BIT(5); // RSF ETH->MTLRQOMR |= MG_BIT(5); // RSF
#else #else
@@ -150,18 +236,23 @@ static size_t mg_tcpip_driver_stm32h_tx(const void *buf, size_t len,
struct mg_tcpip_if *ifp) { struct mg_tcpip_if *ifp) {
if (len > sizeof(s_txbuf[s_txno])) { if (len > sizeof(s_txbuf[s_txno])) {
MG_ERROR(("Frame too big, %ld", (long) len)); MG_ERROR(("Frame too big, %ld", (long) len));
len = 0; // Frame is too big return 0; // Frame is too big
} else if ((s_txdesc[s_txno][3] & MG_BIT(31))) { }
MG_CACHE_INVAL((uint8_t *) &s_txdesc[s_txno], DESC_SZ);
if ((s_txdesc[s_txno][3] & MG_BIT(31))) {
ifp->nerr++; ifp->nerr++;
MG_ERROR(("No free descriptors: %u %08X %08X %08X", s_txno, MG_ERROR(("No free descriptors: %u %08X %08X %08X", s_txno,
s_txdesc[s_txno][3], ETH->DMACSR, ETH->DMACTCR)); 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])); for (int i = 0; i < ETH_DESC_CNT; i++) MG_ERROR(("%08X", s_txdesc[i][3]));
len = 0; // All descriptors are busy, fail len = 0; // All descriptors are busy, fail
} else { } 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][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(28) | MG_BIT(29); // FD, LD
s_txdesc[s_txno][3] |= MG_BIT(31); // Set OWN bit - let DMA take over 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; if (++s_txno >= ETH_DESC_CNT) s_txno = 0;
} }
ETH->DMACSR |= MG_BIT(2) | MG_BIT(1); // Clear any prior TBU, TPS 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) { 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) ETH->MACPFR = MG_BIT(4); // Pass Multicast (pass all multicast frames)
#else #else
// TODO(): read database, rebuild hash table // 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 = (uint32_t) mcast_addr[5] << 8 | (uint32_t) mcast_addr[4];
ETH->MACA1HR |= MG_BIT(31); // AE ETH->MACA1HR |= MG_BIT(31); // AE
#endif #endif
(void) ifp; (void) ifp;
} }
static bool mg_tcpip_driver_stm32h_poll(struct mg_tcpip_if *ifp, bool s1) { 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 // if(link is slow or half) set flags otherwise
// reg = tmp // reg = tmp
uint32_t maccr = ETH->MACCR | MG_BIT(14) | MG_BIT(13); // 100M, Full-duplex 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 SYNOPSYS_ENET_GbE
if (full_duplex == false) maccr &= ~MG_BIT(13); // Half-duplex 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 ETH->MACCR = maccr; // IRQ handler does not fiddle with this register
MG_DEBUG(("Link is %uM %s-duplex", maccr & MG_BIT(14) ? 100 : 10, MG_DEBUG(("Link is %uM %s-duplex", maccr & MG_BIT(14) ? 100 : 10,
maccr & MG_BIT(13) ? "full" : "half")); maccr & MG_BIT(13) ? "full" : "half"));
@@ -216,13 +310,17 @@ static uint32_t s_rxno;
#if MG_ENABLE_DRIVER_MCXN #if MG_ENABLE_DRIVER_MCXN
void ETHERNET_IRQHandler(void); void ETHERNET_IRQHandler(void);
void ETHERNET_IRQHandler(void) { void ETHERNET_IRQHandler(void) {
#else #elif MG_ENABLE_DRIVER_STM32H
void ETH_IRQHandler(void); void ETH_IRQHandler(void);
void ETH_IRQHandler(void) { void ETH_IRQHandler(void) {
#else
void ETH1_IRQHandler(void);
void ETH1_IRQHandler(void) {
#endif #endif
if (ETH->DMACSR & MG_BIT(6)) { // Frame received, loop if (ETH->DMACSR & MG_BIT(6)) { // Frame received, loop
ETH->DMACSR = MG_BIT(15) | MG_BIT(6); // Clear flag 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 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(31)) break; // exit when done
if (((s_rxdesc[s_rxno][3] & (MG_BIT(28) | MG_BIT(29))) == if (((s_rxdesc[s_rxno][3] & (MG_BIT(28) | MG_BIT(29))) ==
(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); 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], // MG_DEBUG(("%lx %lu %lx %08lx", s_rxno, len, s_rxdesc[s_rxno][3],
// ETH->DMACSR)); // 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); mg_tcpip_qwrite(s_rxbuf[s_rxno], len > 4 ? len - 4 : len, s_ifp);
} }
s_rxdesc[s_rxno][3] = s_rxdesc[s_rxno][3] =
MG_BIT(31) | MG_BIT(30) | MG_BIT(24); // OWN, IOC, BUF1V 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; if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0;
} }
} }
+17 -1
View File
@@ -7,7 +7,10 @@
#if !defined(MG_ENABLE_DRIVER_MCXN) #if !defined(MG_ENABLE_DRIVER_MCXN)
#define MG_ENABLE_DRIVER_MCXN 0 #define MG_ENABLE_DRIVER_MCXN 0
#endif #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 { struct mg_tcpip_driver_stm32h_data {
// MDC clock divider. MDC clock is derived from HCLK, must not exceed 2.5MHz // MDC clock divider. MDC clock is derived from HCLK, must not exceed 2.5MHz
@@ -46,6 +49,18 @@ struct mg_tcpip_driver_stm32h_data {
#define MG_ENABLE_ETH_IRQ() #define MG_ENABLE_ETH_IRQ()
#endif #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) \ #define MG_TCPIP_DRIVER_INIT(mgr) \
do { \ do { \
static struct mg_tcpip_driver_stm32h_data driver_data_; \ static struct mg_tcpip_driver_stm32h_data driver_data_; \
@@ -59,6 +74,7 @@ struct mg_tcpip_driver_stm32h_data {
mif_.driver = &mg_tcpip_driver_stm32h; \ mif_.driver = &mg_tcpip_driver_stm32h; \
mif_.driver_data = &driver_data_; \ mif_.driver_data = &driver_data_; \
MG_SET_MAC_ADDRESS(mif_.mac); \ MG_SET_MAC_ADDRESS(mif_.mac); \
MG_IPV6_INIT(mif_); \
mg_tcpip_init(mgr, &mif_); \ mg_tcpip_init(mgr, &mif_); \
MG_ENABLE_ETH_IRQ(); \ MG_ENABLE_ETH_IRQ(); \
MG_INFO(("Driver: stm32h, MAC: %M", mg_print_mac, mif_.mac)); \ MG_INFO(("Driver: stm32h, MAC: %M", mg_print_mac, mif_.mac)); \
+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 crs[] = {2, 3, 0, 1}; // EMAC->MACMIIAR::CR values
uint8_t div[] = {16, 26, 42, 62}; // Respective HCLK dividers uint8_t div[] = {16, 26, 42, 62}; // Respective HCLK dividers
uint32_t sysclk = get_sysclk(); // Guess system SYSCLK uint32_t sysclk = get_sysclk(); // Guess system SYSCLK
int result = -1; // Invalid CR value int i, result = -1; // Invalid CR value
if (sysclk < 25000000) { if (sysclk < 25000000) {
MG_ERROR(("SYSCLK too low")); MG_ERROR(("SYSCLK too low"));
} else { } else {
for (int i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
if (sysclk / div[i] <= 2375000UL /* 2.5MHz - 5% */) { if (sysclk / div[i] <= 2375000UL /* 2.5MHz - 5% */) {
result = crs[i]; result = crs[i];
break; break;
@@ -130,10 +130,11 @@ static int guess_mdc_cr(void) {
static bool mg_tcpip_driver_tm4c_init(struct mg_tcpip_if *ifp) { 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 *d =
(struct mg_tcpip_driver_tm4c_data *) ifp->driver_data; (struct mg_tcpip_driver_tm4c_data *) ifp->driver_data;
int i;
s_ifp = ifp; s_ifp = ifp;
// Init RX descriptors // 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][0] = MG_BIT(31); // Own
s_rxdesc[i][1] = sizeof(s_rxbuf[i]) | MG_BIT(14); // 2nd address chained 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 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 // 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][2] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer
s_txdesc[i][3] = s_txdesc[i][3] =
(uint32_t) (uintptr_t) s_txdesc[(i + 1) % ETH_DESC_CNT]; // Chain (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->EMACDMARIS = MG_BIT(2) | MG_BIT(5); // Clear any prior TU/UNF
EMAC->EMACTXPOLLD = 0; // and resume EMAC->EMACTXPOLLD = 0; // and resume
return len; return len;
(void) ifp;
} }
static void mg_tcpip_driver_tm4c_update_hash_table(struct mg_tcpip_if *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); void EMAC0_IRQHandler(void);
static uint32_t s_rxno; static uint32_t s_rxno;
void EMAC0_IRQHandler(void) { void EMAC0_IRQHandler(void) {
int i;
if (EMAC->EMACDMARIS & MG_BIT(6)) { // Frame received, loop if (EMAC->EMACDMARIS & MG_BIT(6)) { // Frame received, loop
EMAC->EMACDMARIS = MG_BIT(16) | MG_BIT(6); // Clear flag 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(31)) break; // exit when done
if (((s_rxdesc[s_rxno][0] & (MG_BIT(8) | MG_BIT(9))) == if (((s_rxdesc[s_rxno][0] & (MG_BIT(8) | MG_BIT(9))) ==
(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_DESC_CNT 4 // Descriptors count
#define ETH_DS 4 // Descriptor size (words) #define ETH_DS 4 // Descriptor size (words)
#ifndef ETH_RAM_SECTION static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM;
// if no section is specified, then the data will be placed in the default static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM;
// 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 uint32_t s_rxdesc[ETH_DESC_CNT] 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] 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_txno; // Current TX descriptor
static uint8_t s_rxno; // Current RX 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_DESC_CNT 4 // Descriptors count
#define ETH_DS 2 // Descriptor size (words) #define ETH_DS 2 // Descriptor size (words)
// TODO(): handle these in a portable compiler-independent CMSIS-friendly way static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM;
#define MG_8BYTE_ALIGNED __attribute__((aligned((8U)))) 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 uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS] MG_ETH_RAM MG_8BYTE_ALIGNED;
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; static uint8_t s_txno; // Current TX descriptor
static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS] MG_8BYTE_ALIGNED; static uint8_t s_rxno; // Current RX descriptor
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 struct mg_tcpip_if *s_ifp; // MIP interface static struct mg_tcpip_if *s_ifp; // MIP interface
enum { MG_PHY_ADDR = 0, MG_PHYREG_BCR = 0, MG_PHYREG_BSR = 1 }; 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_MQTT_OPEN, // MQTT CONNACK received int *connack_status_code
MG_EV_SNTP_TIME, // SNTP time received uint64_t *epoch_millis MG_EV_SNTP_TIME, // SNTP time received uint64_t *epoch_millis
MG_EV_WAKEUP, // mg_wakeup() data received struct mg_str *data 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 MG_EV_USER // Starting ID for user events
}; };
+6 -4
View File
@@ -22,7 +22,8 @@ static int xisinf(double x) {
union { union {
double f; double f;
uint64_t u; uint64_t u;
} ieee754 = {x}; } ieee754;
ieee754.f = x;
return ((unsigned) (ieee754.u >> 32) & 0x7fffffff) == 0x7ff00000 && return ((unsigned) (ieee754.u >> 32) & 0x7fffffff) == 0x7ff00000 &&
((unsigned) ieee754.u == 0); ((unsigned) ieee754.u == 0);
} }
@@ -31,7 +32,8 @@ static int xisnan(double x) {
union { union {
double f; double f;
uint64_t u; uint64_t u;
} ieee754 = {x}; } ieee754;
ieee754.f = x;
return ((unsigned) (ieee754.u >> 32) & 0x7fffffff) + return ((unsigned) (ieee754.u >> 32) & 0x7fffffff) +
((unsigned) ieee754.u != 0) > ((unsigned) ieee754.u != 0) >
0x7ff00000; 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 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; n += s;
if (n >= (int) sizeof(buf)) n = (int) sizeof(buf) - 1; if (n >= (int) sizeof(buf)) n = (int) sizeof(buf) - 1;
buf[n] = '\0'; 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, static size_t scpy(void (*out)(char, void *), void *ptr, char *buf,
size_t len) { size_t len) {
size_t i = 0; size_t i = 0;
while (i < len && buf[i] != '\0') out(buf[i++], ptr); while (i < len && buf[i] != '\0') out(buf[i++], ptr);
return i; return i;
+2 -1
View File
@@ -86,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) { 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); fs->ls(path, mg_fs_ls_fn, &s);
return buf[0] != '\0'; return buf[0] != '\0';
} }
+29 -22
View File
@@ -1,7 +1,7 @@
#include "http.h"
#include "arch.h" #include "arch.h"
#include "base64.h" #include "base64.h"
#include "fmt.h" #include "fmt.h"
#include "http.h"
#include "json.h" #include "json.h"
#include "log.h" #include "log.h"
#include "net.h" #include "net.h"
@@ -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, static bool mg_http_parse_headers(const char *s, const char *end,
struct mg_http_header *h, size_t max_hdrs) { struct mg_http_header *h, size_t max_hdrs) {
size_t i, n; 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++) { for (i = 0; i < max_hdrs; i++) {
struct mg_str k = {NULL, 0}, v = {NULL, 0}; struct mg_str k = {NULL, 0}, v = {NULL, 0};
if (s >= end) return false; 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')) { while (v.len > 0 && (v.buf[v.len - 1] == ' ' || v.buf[v.len - 1] == '\t')) {
v.len--; // Trim spaces 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)); // 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 h[i].name = k, h[i].value = v; // Success. Assign values
} }
@@ -286,6 +295,8 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) {
// If we're given a version, check that it is HTTP/x.x // If we're given a version, check that it is HTTP/x.x
version_prefix_valid = version_prefix_valid =
hm->proto.len > 5 && (mg_ncasecmp(hm->proto.buf, "HTTP/", 5) == 0); 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 && if (!is_response && hm->proto.len > 0 &&
(!version_prefix_valid || hm->proto.len != 8 || (!version_prefix_valid || hm->proto.len != 8 ||
(hm->proto.buf[5] < '0' || hm->proto.buf[5] > '9') || (hm->proto.buf[5] < '0' || hm->proto.buf[5] > '9') ||
@@ -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 // 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). // body is read until socket is closed, i.e. body.len is infinite (~0).
// //
// For HTTP requests though, according to // For HTTP requests though, if Content-Length is not specified
// http://tools.ietf.org/html/rfc7231#section-8.1.3, // set body length to 0.
// only POST and PUT methods have defined body semantics. if (hm->body.len == (size_t) ~0 && !is_response) {
// 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) {
hm->body.len = 0; hm->body.len = 0;
hm->message.len = (size_t) req_len; 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, static void mg_http_vprintf_chunk(struct mg_connection *c, const char *fmt,
va_list *ap) { va_list *ap) {
size_t len = c->send.len; 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); mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap);
if (c->send.len >= len + 10) { if (c->send.len >= len + 10) {
mg_snprintf((char *) c->send.buf + len, 9, "%08lx", 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'; c->send.buf[len + 8] = '\r';
if (c->send.len == len + 10) c->is_resp = 0; // Last chunk, reset marker 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, ...) { 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) { 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_printf(c, "%lx\r\n", (unsigned long) len);
mg_send(c, buf, len); if (!mg_send(c, buf, len) || !mg_send(c, "\r\n", 2)) mg_error(c, "OOM");
mg_send(c, "\r\n", 2);
if (len == 0) c->is_resp = 0; if (len == 0) c->is_resp = 0;
} }
@@ -649,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, status, mg_http_status_code_str(status), (int) mime.len, mime.buf,
etag, (uint64_t) cl, gzip ? "Content-Encoding: gzip\r\n" : "", etag, (uint64_t) cl, gzip ? "Content-Encoding: gzip\r\n" : "",
range, opts->extra_headers ? opts->extra_headers : ""); 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; c->is_resp = 0;
mg_fs_close(fd); 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 // 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)) / size_t *clp = (size_t *) &c->data[(sizeof(c->data) - sizeof(size_t)) /
sizeof(size_t) * sizeof(size_t)]; sizeof(size_t) * sizeof(size_t)];
@@ -1021,7 +1023,7 @@ static void http_cb(struct mg_connection *c, int ev, void *ev_data) {
const char *buf = (char *) c->recv.buf + ofs; const char *buf = (char *) c->recv.buf + ofs;
int n = mg_http_parse(buf, c->recv.len - ofs, &hm); int n = mg_http_parse(buf, c->recv.len - ofs, &hm);
struct mg_str *te; // Transfer - encoding header 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; size_t old_len = c->recv.len;
if (n < 0) { if (n < 0) {
// We don't use mg_error() here, to avoid closing pipelined requests // We don't use mg_error() here, to avoid closing pipelined requests
@@ -1044,7 +1046,11 @@ static void http_cb(struct mg_connection *c, int ev, void *ev_data) {
hm.message.len = c->recv.len - ofs; // and closes now, deliver MSG hm.message.len = c->recv.len - ofs; // and closes now, deliver MSG
hm.body.len = hm.message.len - (size_t) (hm.body.buf - hm.message.buf); hm.body.len = hm.message.len - (size_t) (hm.body.buf - hm.message.buf);
} }
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) { if (mg_strcasecmp(*te, mg_str("chunked")) == 0) {
is_chunked = true; is_chunked = true;
} else { } else {
@@ -1059,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 || if (!is_response && (mg_strcasecmp(hm.method, mg_str("POST")) == 0 ||
mg_strcasecmp(hm.method, mg_str("PUT")) == 0)) { mg_strcasecmp(hm.method, mg_str("PUT")) == 0)) {
// POST and PUT should include an entity body. Therefore, they should // 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) // 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 ofs += (size_t) n; // this request has been processed
} else if (is_response) { } else if (is_response) {
// HTTP spec 7.2 Entity body: All other responses must include a body // HTTP spec 7.2 Entity body: All other responses must include a body
-1
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); 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_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_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, struct mg_connection *mg_http_listen(struct mg_mgr *, const char *url,
mg_event_handler_t fn, void *fn_data); mg_event_handler_t fn, void *fn_data);
struct mg_connection *mg_http_connect(struct mg_mgr *, const char *url, struct mg_connection *mg_http_connect(struct mg_mgr *, const char *url,
+6 -5
View File
@@ -1,5 +1,5 @@
#include "arch.h"
#include "iobuf.h" #include "iobuf.h"
#include "arch.h"
#include "log.h" #include "log.h"
#include "util.h" #include "util.h"
@@ -7,8 +7,8 @@ static size_t roundup(size_t size, size_t align) {
return align == 0 ? size : (size + align - 1) / align * align; return align == 0 ? size : (size + align - 1) / align * align;
} }
int mg_iobuf_resize(struct mg_iobuf *io, size_t new_size) { bool mg_iobuf_resize(struct mg_iobuf *io, size_t new_size) {
int ok = 1; bool ok = true;
new_size = roundup(new_size, io->align); new_size = roundup(new_size, io->align);
if (new_size == 0) { if (new_size == 0) {
mg_bzero(io->buf, io->size); mg_bzero(io->buf, io->size);
@@ -25,15 +25,16 @@ int mg_iobuf_resize(struct mg_iobuf *io, size_t new_size) {
mg_free(io->buf); mg_free(io->buf);
io->buf = (unsigned char *) p; io->buf = (unsigned char *) p;
io->size = new_size; io->size = new_size;
io->len = len;
} else { } else {
ok = 0; ok = false;
MG_ERROR(("%lld->%lld", (uint64_t) io->size, (uint64_t) new_size)); MG_ERROR(("%lld->%lld", (uint64_t) io->size, (uint64_t) new_size));
} }
} }
return ok; 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->buf = NULL;
io->align = align; io->align = align;
io->size = io->len = 0; io->size = io->len = 0;
+2 -2
View File
@@ -9,8 +9,8 @@ struct mg_iobuf {
size_t align; // Alignment during allocation size_t align; // Alignment during allocation
}; };
int mg_iobuf_init(struct mg_iobuf *, size_t, size_t); bool mg_iobuf_init(struct mg_iobuf *, size_t, size_t);
int mg_iobuf_resize(struct mg_iobuf *, size_t); bool mg_iobuf_resize(struct mg_iobuf *, size_t);
void mg_iobuf_free(struct mg_iobuf *); 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_add(struct mg_iobuf *, size_t, const void *, size_t);
size_t mg_iobuf_del(struct mg_iobuf *, size_t ofs, size_t len); size_t mg_iobuf_del(struct mg_iobuf *, size_t ofs, size_t len);
+17 -4
View File
@@ -60,15 +60,28 @@ static double mg_atod(const char *p, int len, int *numlen) {
// Exponential // Exponential
if (i < len && (p[i] == 'e' || p[i] == 'E')) { if (i < len && (p[i] == 'e' || p[i] == 'E')) {
int j, exp = 0, minus = 0; int exp = 0, minus = 0;
i++; i++;
if (i < len && p[i] == '-') minus = 1, i++; if (i < len && p[i] == '-') minus = 1, i++;
if (i < len && p[i] == '+') i++; if (i < len && p[i] == '+') i++;
while (i < len && p[i] >= '0' && p[i] <= '9' && exp < 308) while (i < len && p[i] >= '0' && p[i] <= '9' && exp < 308)
exp = exp * 10 + (p[i++] - '0'); exp = exp * 10 + (p[i++] - '0');
if (minus) exp = -exp; // use fast exponentiation
for (j = 0; j < exp; j++) d *= 10.0; // https://en.wikipedia.org/wiki/Exponentiation_by_squaring
for (j = 0; j < -exp; j++) d /= 10.0; 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; if (numlen != NULL) *numlen = i;
+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
+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_) #define mg_log_set(level_) mg_log_level = (level_)
#if MG_ENABLE_LOG #if MG_ENABLE_LOG
#define MG_LOG(level, args) \ #if !defined(_MSC_VER) && \
do { \ (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L)
if ((level) <= mg_log_level) { \ #define MG___FUNC__ ""
mg_log_prefix((level), __FILE__, __LINE__, __func__); \ #else
mg_log args; \ #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) } while (0)
#else #else
#define MG_LOG(level, args) \ #define MG_LOG(level, args) \
+148 -88
View File
@@ -1,8 +1,8 @@
#include "mqtt.h"
#include "arch.h" #include "arch.h"
#include "base64.h" #include "base64.h"
#include "event.h" #include "event.h"
#include "log.h" #include "log.h"
#include "mqtt.h"
#include "url.h" #include "url.h"
#include "util.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_SUBSCRIPTION_IDENTIFIER_AVAILABLE, MQTT_PROP_TYPE_BYTE},
{MQTT_PROP_SHARED_SUBSCRIPTION_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, static bool mqtt_send_header(struct mg_connection *c, uint8_t cmd,
uint32_t len) { uint8_t flags, uint32_t len) {
uint8_t buf[1 + sizeof(len)], *vlen = &buf[1]; uint8_t buf[1 + sizeof(len)], *vlen = &buf[1];
buf[0] = (uint8_t) ((cmd << 4) | flags); buf[0] = (uint8_t) ((cmd << 4) | flags);
do { 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; if (len > 0) *vlen |= 0x80;
vlen++; vlen++;
} while (len > 0 && vlen < &buf[sizeof(buf)]); } 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) { void mg_mqtt_send_header(struct mg_connection *c, uint8_t cmd, uint8_t flags,
mg_send(c, &value, sizeof(value)); 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) { static bool mg_send_u16(struct mg_connection *c, uint16_t value) {
mg_send(c, &value, sizeof(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) { 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: case MQTT_PROP_TYPE_VARIABLE_INT:
size += varint_size((uint32_t) props[i].iv); size += varint_size((uint32_t) props[i].iv);
break; break;
case MQTT_PROP_TYPE_INT: case MQTT_PROP_TYPE_INT: size += (uint32_t) sizeof(uint32_t); break;
size += (uint32_t) sizeof(uint32_t); case MQTT_PROP_TYPE_SHORT: size += (uint32_t) sizeof(uint16_t); break;
break; case MQTT_PROP_TYPE_BYTE: size += (uint32_t) sizeof(uint8_t); break;
case MQTT_PROP_TYPE_SHORT: default: return size; // cannot parse further down
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; 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) { struct mg_mqtt_prop *props, size_t nprops) {
size_t total_size = get_properties_length(props, nprops); size_t total_size = get_properties_length(props, nprops);
uint8_t buf_v[4] = {0, 0, 0, 0}; uint8_t buf_v[4] = {0, 0, 0, 0};
uint8_t buf[4] = {0, 0, 0, 0}; uint8_t buf[4] = {0, 0, 0, 0};
size_t i, len = encode_varint(buf, total_size); 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++) { 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)) { switch (mqtt_prop_type_by_id(props[i].id)) {
case MQTT_PROP_TYPE_STRING_PAIR: case MQTT_PROP_TYPE_STRING_PAIR:
mg_send_u16(c, mg_htons((uint16_t) props[i].key.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(c, props[i].key.buf, props[i].key.len) ||
mg_send_u16(c, mg_htons((uint16_t) props[i].val.len)); !mg_send_u16(c, mg_htons((uint16_t) props[i].val.len)) ||
mg_send(c, props[i].val.buf, props[i].val.len); !mg_send(c, props[i].val.buf, props[i].val.len))
return false;
break; break;
case MQTT_PROP_TYPE_BYTE: 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; break;
case MQTT_PROP_TYPE_SHORT: 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; break;
case MQTT_PROP_TYPE_INT: 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; break;
case MQTT_PROP_TYPE_STRING: case MQTT_PROP_TYPE_STRING:
mg_send_u16(c, mg_htons((uint16_t) 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); !mg_send(c, props[i].val.buf, props[i].val.len))
return false;
break; break;
case MQTT_PROP_TYPE_BINARY_DATA: case MQTT_PROP_TYPE_BINARY_DATA:
mg_send_u16(c, mg_htons((uint16_t) 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); !mg_send(c, props[i].val.buf, props[i].val.len))
return false;
break; break;
case MQTT_PROP_TYPE_VARIABLE_INT: case MQTT_PROP_TYPE_VARIABLE_INT:
len = encode_varint(buf_v, props[i].iv); 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; break;
} }
} }
return true;
} }
size_t mg_mqtt_next_prop(struct mg_mqtt_message *msg, struct mg_mqtt_prop *prop, 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 *i = (uint8_t *) msg->dgram.buf + msg->props_start + ofs;
uint8_t *end = (uint8_t *) msg->dgram.buf + msg->dgram.len; uint8_t *end = (uint8_t *) msg->dgram.buf + msg->dgram.len;
size_t new_pos = ofs, 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; return 0;
memset(prop, 0, sizeof(struct mg_mqtt_prop));
prop->id = i[0];
i++, new_pos++; i++, new_pos++;
switch (mqtt_prop_type_by_id(prop->id)) { switch (mqtt_prop_type_by_id(prop->id)) {
case MQTT_PROP_TYPE_STRING_PAIR: 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.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
prop->key.buf = (char *) i + 2; prop->key.buf = (char *) i + 2;
i += 2 + prop->key.len; 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.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
prop->val.buf = (char *) i + 2; 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; new_pos += 2 * sizeof(uint16_t) + prop->val.len + prop->key.len;
break; break;
case MQTT_PROP_TYPE_BYTE: case MQTT_PROP_TYPE_BYTE:
if (i + 1 >= end) return 0;
prop->iv = (uint8_t) i[0]; prop->iv = (uint8_t) i[0];
new_pos++; new_pos++;
break; break;
case MQTT_PROP_TYPE_SHORT: case MQTT_PROP_TYPE_SHORT:
if (i + 2 >= end) return 0;
prop->iv = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); prop->iv = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
new_pos += sizeof(uint16_t); new_pos += sizeof(uint16_t);
break; break;
case MQTT_PROP_TYPE_INT: case MQTT_PROP_TYPE_INT:
if (i + 4 >= end) return 0;
prop->iv = ((uint32_t) i[0] << 24) | ((uint32_t) i[1] << 16) | prop->iv = ((uint32_t) i[0] << 24) | ((uint32_t) i[1] << 16) |
((uint32_t) i[2] << 8) | i[3]; ((uint32_t) i[2] << 8) | i[3];
new_pos += sizeof(uint32_t); new_pos += sizeof(uint32_t);
break; break;
case MQTT_PROP_TYPE_STRING: 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.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
prop->val.buf = (char *) i + 2; prop->val.buf = (char *) i + 2;
if (i + 2 + prop->val.len >= end) return 0;
new_pos += 2 + prop->val.len; new_pos += 2 + prop->val.len;
break; break;
case MQTT_PROP_TYPE_BINARY_DATA: 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.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
prop->val.buf = (char *) i + 2; prop->val.buf = (char *) i + 2;
if (i + 2 + prop->val.len >= end) return 0;
new_pos += 2 + prop->val.len; new_pos += 2 + prop->val.len;
break; break;
case MQTT_PROP_TYPE_VARIABLE_INT: case MQTT_PROP_TYPE_VARIABLE_INT:
len = decode_varint(i, (size_t) (end - i), (size_t *) &prop->iv); 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; break;
default: default:
new_pos = 0; new_pos = 0;
break;
} }
return new_pos; 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]; char client_id[21];
struct mg_str cid = opts->client_id; struct mg_str cid = opts->client_id;
size_t total_len = 7 + 1 + 2 + 2; 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) { if (cid.len == 0) {
mg_random_str(client_id, sizeof(client_id) - 1); 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); 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!" // 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)); if (!mg_send_u16(c, mg_htons((uint16_t) cid.len)) ||
mg_send(c, cid.buf, cid.len); !mg_send(c, cid.buf, cid.len))
goto fail;
if (hdr[7] & MQTT_HAS_WILL) { if (hdr[7] & MQTT_HAS_WILL) {
if (c->is_mqtt5) if (c->is_mqtt5 &&
mg_send_mqtt_properties(c, opts->will_props, opts->num_will_props); !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)); if (!mg_send_u16(c, mg_htons((uint16_t) opts->topic.len)) ||
mg_send(c, opts->topic.buf, 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_u16(c, mg_htons((uint16_t) opts->message.len)) ||
mg_send(c, opts->message.buf, 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);
}
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 (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) { 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 (c->is_mqtt5) len += get_props_size(opts->props, opts->num_props);
if (opts->qos > 0 && id != 0) flags |= 1 << 3; if (opts->qos > 0 && id != 0) flags |= 1 << 3;
mg_mqtt_send_header(c, MQTT_CMD_PUBLISH, flags, (uint32_t) 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_u16(c, mg_htons((uint16_t) opts->topic.len)) ||
mg_send(c, opts->topic.buf, opts->topic.len); !mg_send(c, opts->topic.buf, opts->topic.len))
goto fail;
if (opts->qos > 0) { // need to send 'id' field if (opts->qos > 0) { // need to send 'id' field
if (id == 0) { // generate new one if not resending if (id == 0) { // generate new one if not resending
if (++c->mgr->mqtt_id == 0) ++c->mgr->mqtt_id; if (++c->mgr->mqtt_id == 0) ++c->mgr->mqtt_id;
id = 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; 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; 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 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; if (++c->mgr->mqtt_id == 0) ++c->mgr->mqtt_id;
mg_send_u16(c, mg_htons(c->mgr->mqtt_id)); if (!mg_send_u16(c, mg_htons(c->mgr->mqtt_id))) goto fail;
if (c->is_mqtt5) mg_send_mqtt_properties(c, opts->props, opts->num_props);
mg_send_u16(c, mg_htons((uint16_t) opts->topic.len)); if (c->is_mqtt5 && !mg_send_mqtt_properties(c, opts->props, opts->num_props))
mg_send(c, opts->topic.buf, opts->topic.len); goto fail;
mg_send(c, &qos_, sizeof(qos_));
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, 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); m->data.len = (size_t) (end - p);
break; break;
} }
default: default: break;
break;
} }
return MQTT_OK; 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); uint32_t remaining_len = sizeof(id);
if (c->is_mqtt5) remaining_len += 2; // 3.4.2 if (c->is_mqtt5) remaining_len += 2; // 3.4.2
mg_mqtt_send_header( if (!mqtt_send_header(c,
c, (uint8_t) (mm.qos == 2 ? MQTT_CMD_PUBREC
(uint8_t) (mm.qos == 2 ? MQTT_CMD_PUBREC : MQTT_CMD_PUBACK), : MQTT_CMD_PUBACK),
0, remaining_len); 0, remaining_len) ||
mg_send(c, &id, sizeof(id)); !mg_send(c, &id, sizeof(id)))
goto fail;
if (c->is_mqtt5) { if (c->is_mqtt5) {
uint16_t zero = 0; 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 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 case MQTT_CMD_PUBREC: { // MQTT5: 3.5.2-1 TODO(): variable header rc
uint16_t id = mg_ntohs(mm.id); uint16_t id = mg_ntohs(mm.id);
uint32_t remaining_len = sizeof(id); // MQTT5 3.6.2-1 uint32_t remaining_len = sizeof(id); // MQTT5 3.6.2-1
mg_mqtt_send_header(c, MQTT_CMD_PUBREL, 2, remaining_len); if (!mqtt_send_header(c, MQTT_CMD_PUBREL, 2,
mg_send(c, &id, sizeof(id)); // MQTT5 3.6.1-1, flags = 2 remaining_len) // MQTT5 3.6.1-1, flags = 2
|| !mg_send(c, &id, sizeof(id)))
goto fail;
break; break;
} }
case MQTT_CMD_PUBREL: { // MQTT5: 3.6.2-1 TODO(): variable header rc case MQTT_CMD_PUBREL: { // MQTT5: 3.6.2-1 TODO(): variable header rc
uint16_t id = mg_ntohs(mm.id); uint16_t id = mg_ntohs(mm.id);
uint32_t remaining_len = sizeof(id); // MQTT5 3.7.2-1 uint32_t remaining_len = sizeof(id); // MQTT5 3.7.2-1
mg_mqtt_send_header(c, MQTT_CMD_PUBCOMP, 0, remaining_len); if (!mqtt_send_header(c, MQTT_CMD_PUBCOMP, 0, remaining_len) ||
mg_send(c, &id, sizeof(id)); !mg_send(c, &id, sizeof(id)))
goto fail;
break; break;
} }
} }
@@ -503,6 +555,9 @@ static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data) {
} }
} }
(void) ev_data; (void) ev_data;
return;
fail:
mg_error(c, "OOM");
} }
void mg_mqtt_ping(struct mg_connection *nc) { void mg_mqtt_ping(struct mg_connection *nc) {
@@ -517,19 +572,24 @@ void mg_mqtt_disconnect(struct mg_connection *c,
const struct mg_mqtt_opts *opts) { const struct mg_mqtt_opts *opts) {
size_t len = 0; size_t len = 0;
if (c->is_mqtt5) len = 1 + get_props_size(opts->props, opts->num_props); 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) { if (c->is_mqtt5) {
uint8_t zero = 0; uint8_t zero = 0;
mg_send(c, &zero, sizeof(zero)); // reason code if (!mg_send(c, &zero, sizeof(zero)) // reason code
mg_send_mqtt_properties(c, opts->props, opts->num_props); || !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, struct mg_connection *mg_mqtt_connect(struct mg_mgr *mgr, const char *url,
const struct mg_mqtt_opts *opts, const struct mg_mqtt_opts *opts,
mg_event_handler_t fn, void *fn_data) { mg_event_handler_t fn, void *fn_data) {
struct mg_connection *c = mg_connect_svc(mgr, url, fn, fn_data, mqtt_cb, NULL); struct mg_connection *c =
mg_connect_svc(mgr, url, fn, fn_data, mqtt_cb, NULL);
if (c != NULL) { if (c != NULL) {
struct mg_mqtt_opts empty; struct mg_mqtt_opts empty;
memset(&empty, 0, sizeof(empty)); memset(&empty, 0, sizeof(empty));
+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); 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); 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_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 *); 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, void mg_mqtt_send_header(struct mg_connection *, uint8_t cmd, uint8_t flags,
uint32_t len); uint32_t len);
+43 -18
View File
@@ -9,8 +9,14 @@
size_t mg_vprintf(struct mg_connection *c, const char *fmt, va_list *ap) { size_t mg_vprintf(struct mg_connection *c, const char *fmt, va_list *ap) {
size_t old = c->send.len; size_t old = c->send.len;
mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap); size_t expected = mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap);
return c->send.len - old; 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, ...) { 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) { static bool mg_atonl(struct mg_str str, struct mg_addr *addr) {
uint32_t localhost = mg_htonl(0x7f000001); uint32_t localhost = mg_htonl(0x7f000001);
if (mg_strcasecmp(str, mg_str("localhost")) != 0) return false; 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; addr->is_ip6 = false;
return true; return true;
} }
static bool mg_atone(struct mg_str str, struct mg_addr *addr) { static bool mg_atone(struct mg_str str, struct mg_addr *addr) {
if (str.len > 0) return false; 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; addr->is_ip6 = false;
return true; 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; 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; addr->is_ip6 = false;
return true; 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); // 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; if (!mg_aton4(mg_str_n(&str.buf[7], str.len - 7), addr)) return false;
memcpy(&ipv4, addr->ip, sizeof(ipv4)); memcpy(&ipv4, addr->addr.ip, sizeof(ipv4));
memset(addr->ip, 0, sizeof(addr->ip)); memset(addr->addr.ip, 0, sizeof(addr->addr.ip));
addr->ip[10] = addr->ip[11] = 255; addr->addr.ip[10] = addr->addr.ip[11] = 255;
memcpy(&addr->ip[12], &ipv4, 4); memcpy(&addr->addr.ip[12], &ipv4, 4);
addr->is_ip6 = true; addr->is_ip6 = true;
return 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; size_t i, j = 0, n = 0, dc = 42;
addr->scope_id = 0; addr->scope_id = 0;
if (str.len > 2 && str.buf[0] == '[') str.buf++, str.len -= 2; 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++) { for (i = 0; i < str.len; i++) {
if ((str.buf[i] >= '0' && str.buf[i] <= '9') || if ((str.buf[i] >= '0' && str.buf[i] <= '9') ||
(str.buf[i] >= 'a' && str.buf[i] <= 'f') || (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; if (i > j + 3) return false;
// MG_DEBUG(("%lu %lu [%.*s]", i, j, (int) (i - j + 1), &str.buf[j])); // 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)); 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->addr.ip[n] = (uint8_t) ((val >> 8) & 255);
addr->ip[n + 1] = (uint8_t) (val & 255); addr->addr.ip[n + 1] = (uint8_t) (val & 255);
} else if (str.buf[i] == ':') { } else if (str.buf[i] == ':') {
j = i + 1; j = i + 1;
if (i > 0 && str.buf[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; n += 2;
} }
if (n > 14) return false; if (n > 14) return false;
addr->ip[n] = addr->ip[n + 1] = 0; // For trailing :: addr->addr.ip[n] = addr->addr.ip[n + 1] = 0; // For trailing ::
} else if (str.buf[i] == '%') { // Scope ID, last in string } 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, if (mg_str_to_num(mg_str_n(&str.buf[i + 1], str.len - i - 1), 10,
&addr->scope_id, sizeof(uint8_t)); &addr->scope_id, sizeof(uint8_t))) {
addr->is_ip6 = true;
return true;
} else {
return false;
}
} else { } else {
return false; return false;
} }
} }
if (n < 14 && dc == 42) return false; if (n < 14 && dc == 42) return false;
if (n < 14) { if (n < 14) {
memmove(&addr->ip[dc + (14 - n)], &addr->ip[dc], n - dc + 2); memmove(&addr->addr.ip[dc + (14 - n)], &addr->addr.ip[dc], n - dc + 2);
memset(&addr->ip[dc], 0, 14 - n); memset(&addr->addr.ip[dc], 0, 14 - n);
} }
addr->is_ip6 = true; addr->is_ip6 = true;
@@ -162,6 +173,10 @@ struct mg_connection *mg_connect_svc(struct mg_mgr *mgr, const char *url,
struct mg_connection *c = NULL; struct mg_connection *c = NULL;
if (url == NULL || url[0] == '\0') { if (url == NULL || url[0] == '\0') {
MG_ERROR(("null url")); MG_ERROR(("null url"));
#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) { } else if ((c = mg_alloc_conn(mgr)) == NULL) {
MG_ERROR(("OOM")); MG_ERROR(("OOM"));
} else { } else {
@@ -295,3 +310,13 @@ void mg_mgr_init(struct mg_mgr *mgr) {
: MG_TLS == MG_TLS_WOLFSSL ? "WolfSSL" : MG_TLS == MG_TLS_WOLFSSL ? "WolfSSL"
: "custom")); : "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
}
+6 -1
View File
@@ -14,7 +14,11 @@ struct mg_dns {
}; };
struct mg_addr { 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 uint16_t port; // TCP or UDP port in network byte order
uint8_t scope_id; // IPv6 scope ID uint8_t scope_id; // IPv6 scope ID
bool is_ip6; // True when address is IPv6 address bool is_ip6; // True when address is IPv6 address
@@ -108,3 +112,4 @@ struct mg_timer *mg_timer_add(struct mg_mgr *mgr, uint64_t milliseconds,
struct mg_connection *mg_connect_svc(struct mg_mgr *mgr, const char *url, struct mg_connection *mg_connect_svc(struct mg_mgr *mgr, const char *url,
mg_event_handler_t fn, void *fn_data, mg_event_handler_t fn, void *fn_data,
mg_event_handler_t pfn, void *pfn_data); mg_event_handler_t pfn, void *pfn_data);
void mg_multicast_restore(struct mg_connection *c, uint8_t *from);
+1350 -441
View File
File diff suppressed because it is too large. Load diff
+84 -26
View File
@@ -1,6 +1,7 @@
#pragma once #pragma once
#include "arch.h" #include "arch.h"
#include "l2.h"
#include "net.h" #include "net.h"
#include "queue.h" #include "queue.h"
#include "str.h" #include "str.h"
@@ -20,45 +21,58 @@ typedef void (*mg_tcpip_event_handler_t)(struct mg_tcpip_if *ifp, int ev,
void *ev_data); void *ev_data);
enum { enum {
MG_TCPIP_EV_ST_CHG, // state change uint8_t * (&ifp->state) 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_DNS, // DHCP DNS assignment uint32_t *ipaddr
MG_TCPIP_EV_DHCP_SNTP, // DHCP SNTP 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_ARP, // Got ARP packet struct mg_str *
MG_TCPIP_EV_TIMER_1S, // 1 second timer NULL 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_RESULT, // Wi-Fi scan results struct
MG_TCPIP_EV_WIFI_SCAN_END, // Wi-Fi scan has finished NULL // mg_wifi_scan_bss_data *
MG_TCPIP_EV_WIFI_CONNECT_ERR, // Wi-Fi connect has failed driver and chip specific MG_TCPIP_EV_WIFI_SCAN_END, // Wi-Fi scan has finished NULL
MG_TCPIP_EV_DRIVER, // Driver event driver specific MG_TCPIP_EV_WIFI_CONNECT_ERR, // Wi-Fi connect has failed driver and
MG_TCPIP_EV_USER // Starting ID for user events // 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 // Network interface
struct mg_tcpip_if { struct mg_tcpip_if {
uint8_t mac[6]; // MAC address. Must be set to a valid MAC uint8_t mac[sizeof(struct mg_l2addr)]; // hw address. Set to a valid addr
uint32_t ip, mask, gw; // IP address, mask, default gateway uint32_t ip, mask, gw; // IP address, mask, default gateway
struct mg_str tx; // Output (TX) buffer struct mg_str tx; // Output (TX) buffer
bool enable_dhcp_client; // Enable DCHP client bool enable_dhcp_client; // Enable DCHP client
bool enable_dhcp_server; // Enable DCHP server bool enable_dhcp_server; // Enable DCHP server
bool enable_get_gateway; // DCHP server sets client as gateway bool enable_get_gateway; // DCHP server sets client as gateway
bool enable_req_dns; // DCHP client requests DNS server bool enable_req_dns; // DCHP client requests DNS server
bool enable_req_sntp; // DCHP client requests SNTP 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_crc32_check; // Do a CRC check on RX frames and strip it
bool enable_mac_check; // Do a MAC check on RX frames bool enable_mac_check; // Do a MAC check on RX frames
bool update_mac_hash_table; // Signal drivers to update MAC controller bool update_mac_hash_table; // Signal drivers to update MAC controller
struct mg_tcpip_driver *driver; // Low level driver struct mg_tcpip_driver *driver; // Low level driver
void *driver_data; // Driver-specific data 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 mg_tcpip_event_handler_t fn; // User-specified event handler function
struct mg_mgr *mgr; // Mongoose event manager struct mg_mgr *mgr; // Mongoose event manager
struct mg_queue recv_queue; // Receive queue struct mg_queue recv_queue; // Receive queue
char dhcp_name[12]; // Name reported to DHCP, "mip" if unset char dhcp_name[MG_TCPIP_DHCPNAME_SIZE]; // Name for DHCP, "mip" if unset
uint16_t mtu; // Interface MTU uint16_t mtu; // Interface link payload
#define MG_TCPIP_MTU_DEFAULT 1500 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 // Internal state, user can use it but should not change it
uint8_t gwmac[6]; // Router's MAC uint8_t gwmac[sizeof(struct mg_l2addr)]; // Router's hw address
char *dns4_url; // DNS server URL enum mg_l2type l2type; // Ethernet, PPP, etc.
uint64_t now; // Current time 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 timer_1000ms; // 1000 ms timer: for DHCP and link state
uint64_t lease_expire; // Lease expiration time, in ms uint64_t lease_expire; // Lease expiration time, in ms
uint16_t eport; // Next ephemeral port uint16_t eport; // Next ephemeral port
@@ -66,12 +80,18 @@ struct mg_tcpip_if {
volatile uint32_t nrecv; // Number of received frames volatile uint32_t nrecv; // Number of received frames
volatile uint32_t nsent; // Number of transmitted frames volatile uint32_t nsent; // Number of transmitted frames
volatile uint32_t nerr; // Number of driver errors 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_DOWN 0 // Interface is down
#define MG_TCPIP_STATE_UP 1 // Interface is up #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_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_IP 3 // Interface is up and has an IP assigned
#define MG_TCPIP_STATE_READY 4 // Interface has fully come up, ready to work #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 *); void mg_tcpip_init(struct mg_mgr *, struct mg_tcpip_if *);
@@ -95,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_pico_w;
extern struct mg_tcpip_driver mg_tcpip_driver_rw612; 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_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 // Drivers that require SPI, can use this SPI abstraction
struct mg_tcpip_spi { struct mg_tcpip_spi {
@@ -104,5 +126,41 @@ struct mg_tcpip_spi {
uint8_t (*txn)(void *, uint8_t); // SPI transaction: write 1 byte, read reply uint8_t (*txn)(void *, uint8_t); // SPI transaction: write 1 byte, read reply
}; };
// 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 #endif
+2 -2
View File
@@ -17,8 +17,8 @@
#define MG_OTA_RT1060 302 // IMXRT1060 #define MG_OTA_RT1060 302 // IMXRT1060
#define MG_OTA_RT1064 303 // IMXRT1064 #define MG_OTA_RT1064 303 // IMXRT1064
#define MG_OTA_RT1170 304 // IMXRT1170 #define MG_OTA_RT1170 304 // IMXRT1170
#define MG_OTA_MCXN 310 // MCXN947 #define MG_OTA_MCXN 310 // MCXN947
#define MG_OTA_FRDM 320 // FRDM-RW612 #define MG_OTA_RW612 320 // FRDM-RW612
#define MG_OTA_FLASH 900 // OTA via an internal flash #define MG_OTA_FLASH 900 // OTA via an internal flash
#define MG_OTA_ESP32 910 // ESP32 OTA implementation #define MG_OTA_ESP32 910 // ESP32 OTA implementation
#define MG_OTA_PICOSDK 920 // RP2040/2350 using Pico-SDK hardware_flash #define MG_OTA_PICOSDK 920 // RP2040/2350 using Pico-SDK hardware_flash
+1 -1
View File
@@ -2,7 +2,7 @@
#include "log.h" #include "log.h"
#include "ota.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); MG_IRAM static bool mg_frdm_write(void *, const void *, size_t);
static bool mg_frdm_swap(void); static bool mg_frdm_swap(void);
+38 -25
View File
@@ -1,25 +1,20 @@
#include "printf.h"
#include "fmt.h" #include "fmt.h"
#include "printf.h"
#include "util.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, ...) { size_t mg_queue_printf(struct mg_queue *q, const char *fmt, ...) {
va_list ap; char *buf;
size_t len; size_t len;
va_start(ap, fmt); va_list ap1, ap2;
len = mg_queue_vprintf(q, fmt, &ap); va_start(ap1, fmt);
va_end(ap); 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; 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); 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) { 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}; struct mg_iobuf io = {0, 0, 0, 0};
size_t n = mg_vxprintf(mg_putchar_iobuf_static, &io, fmt, ap); 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'; if (n < len) buf[n] = '\0';
return n; 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) { size_t mg_print_ip(void (*out)(char, void *), void *arg, va_list *ap) {
struct mg_addr *addr = va_arg(*ap, struct mg_addr *); struct mg_addr *addr = va_arg(*ap, struct mg_addr *);
if (addr->is_ip6) return print_ip6(out, arg, (uint16_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->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) { 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)); 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) { static size_t print_mac(void (*out)(char, void *), void *arg, uint8_t *p) {
uint8_t *p = va_arg(*ap, uint8_t *);
return mg_xprintf(out, arg, "%02x:%02x:%02x:%02x:%02x:%02x", p[0], p[1], p[2], return mg_xprintf(out, arg, "%02x:%02x:%02x:%02x:%02x:%02x", p[0], p[1], p[2],
p[3], p[4], p[5]); 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) { static char mg_esc(int c, bool esc) {
const char *p, *esc1 = "\b\f\n\r\t\\\"", *esc2 = "bfnrt\\\""; const char *p, *esc1 = "\b\f\n\r\t\\\"", *esc2 = "bfnrt\\\"";
for (p = esc ? esc1 : esc2; *p != '\0'; p++) { 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) { for (i = 0; i < len; i += 3) {
uint8_t c1 = buf[i], c2 = i + 1 < len ? buf[i + 1] : 0, uint8_t c1 = buf[i], c2 = i + 1 < len ? buf[i + 1] : 0,
c3 = i + 2 < len ? buf[i + 2] : 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 + 1 < len) tmp[2] = t[(c2 & 15) << 2 | (c3 >> 6)];
if (i + 2 < len) tmp[3] = t[c3 & 63]; if (i + 2 < len) tmp[3] = t[c3 & 63];
for (j = 0; j < sizeof(tmp) && tmp[j] != '\0'; j++) out(tmp[j], arg); 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, ...); size_t mg_snprintf(char *, size_t, const char *fmt, ...);
char *mg_vmprintf(const char *fmt, va_list *ap); char *mg_vmprintf(const char *fmt, va_list *ap);
char *mg_mprintf(const char *fmt, ...); 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, ...); size_t mg_queue_printf(struct mg_queue *, const char *fmt, ...);
// %M print helper functions // %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_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_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_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 // Various output functions
void mg_pfn_iobuf(char ch, void *param); // param: struct mg_iobuf * 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_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")) // A helper macro for printing JSON: mg_snprintf(buf, len, "%m", MG_ESC("hi"))
#define MG_ESC(str) mg_print_esc, 0, (str) #define MG_ESC(str) mg_print_esc, 0, (str)
+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)) #define sig164(x) (rotr64(x, 19) ^ rotr64(x, 61) ^ ((x) >> 6))
static const uint64_t mg_sha256_k2[80] = { 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, 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f,
0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019, 0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019,
0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242,
@@ -206,7 +235,9 @@ static const uint64_t mg_sha256_k2[80] = {
0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc,
0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a,
0x5fcb6fab3ad6faec, 0x6c44198c4a475817}; 0x5fcb6fab3ad6faec, 0x6c44198c4a475817
#endif
};
static void mg_sha384_transform(mg_sha384_ctx *ctx, const uint8_t data[]) { static void mg_sha384_transform(mg_sha384_ctx *ctx, const uint8_t data[]) {
uint64_t m[80]; uint64_t m[80];
@@ -257,6 +288,16 @@ void mg_sha384_init(mg_sha384_ctx *ctx) {
ctx->datalen = 0; ctx->datalen = 0;
ctx->bitlen[0] = 0; ctx->bitlen[0] = 0;
ctx->bitlen[1] = 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[0] = 0xcbbb9d5dc1059ed8;
ctx->state[1] = 0x629a292a367cd507; ctx->state[1] = 0x629a292a367cd507;
ctx->state[2] = 0x9159015a3070dd17; ctx->state[2] = 0x9159015a3070dd17;
@@ -265,6 +306,7 @@ void mg_sha384_init(mg_sha384_ctx *ctx) {
ctx->state[5] = 0x8eb44a8768581511; ctx->state[5] = 0x8eb44a8768581511;
ctx->state[6] = 0xdb0c2e0d64f98fa7; ctx->state[6] = 0xdb0c2e0d64f98fa7;
ctx->state[7] = 0x47b5481dbefa4fa4; ctx->state[7] = 0x47b5481dbefa4fa4;
#endif
} }
void mg_sha384_update(mg_sha384_ctx *ctx, const uint8_t *data, size_t len) { void mg_sha384_update(mg_sha384_ctx *ctx, const uint8_t *data, size_t len) {
+50 -21
View File
@@ -57,13 +57,13 @@ static socklen_t tousa(struct mg_addr *a, union usa *usa) {
memset(usa, 0, sizeof(*usa)); memset(usa, 0, sizeof(*usa));
usa->sin.sin_family = AF_INET; usa->sin.sin_family = AF_INET;
usa->sin.sin_port = a->port; 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 MG_ENABLE_IPV6
if (a->is_ip6) { if (a->is_ip6) {
usa->sin.sin_family = AF_INET6; usa->sin.sin_family = AF_INET6;
usa->sin6.sin6_port = a->port; usa->sin6.sin6_port = a->port;
usa->sin6.sin6_scope_id = a->scope_id; 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); len = sizeof(usa->sin6);
} }
#endif #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) { static void tomgaddr(union usa *usa, struct mg_addr *a, bool is_ip6) {
a->is_ip6 = 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 MG_ENABLE_IPV6
if (is_ip6) { 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->port = usa->sin6.sin6_port;
a->scope_id = (uint8_t) usa->sin6.sin6_scope_id; a->scope_id = (uint8_t) usa->sin6.sin6_scope_id;
} } else
#endif #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) { 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) { static void iolog(struct mg_connection *c, char *buf, long n, bool r) {
if (n == MG_IO_WAIT) { if (n == MG_IO_WAIT) {
// Do nothing // 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); iolog(c, (char *) buf, n, false);
return n > 0; return n > 0;
} else { } 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
} }
} }
@@ -163,7 +190,7 @@ static void mg_set_non_blocking_mode(MG_SOCKET_TYPE fd) {
#elif MG_ARCH == MG_ARCH_THREADX #elif MG_ARCH == MG_ARCH_THREADX
// NetxDuo fails to send large blocks of data to the non-blocking sockets // NetxDuo fails to send large blocks of data to the non-blocking sockets
(void) fd; (void) fd;
//fcntl(fd, F_SETFL, O_NONBLOCK); // fcntl(fd, F_SETFL, O_NONBLOCK);
#elif MG_ARCH == MG_ARCH_TIRTOS #elif MG_ARCH == MG_ARCH_TIRTOS
int val = 0; int val = 0;
setsockopt(fd, SOL_SOCKET, SO_BLOCKING, &val, sizeof(val)); setsockopt(fd, SOL_SOCKET, SO_BLOCKING, &val, sizeof(val));
@@ -181,7 +208,7 @@ 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);
void mg_multicast_add(struct mg_connection *c, char *ip) { void mg_multicast_add(struct mg_connection *c, char *ip) {
#if MG_ENABLE_RL #if MG_ENABLE_RL
#error UNSUPPORTED MG_ERROR(("unsupported"));
#elif MG_ENABLE_FREERTOS_TCP #elif MG_ENABLE_FREERTOS_TCP
// TODO(): prvAllowIPPacketIPv4() // TODO(): prvAllowIPPacketIPv4()
#else #else
@@ -195,9 +222,10 @@ void mg_multicast_add(struct mg_connection *c, char *ip) {
struct ip_mreq mreq; struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(ip); mreq.imr_multiaddr.s_addr = inet_addr(ip);
mreq.imr_interface.s_addr = mg_htonl(INADDR_ANY); mreq.imr_interface.s_addr = mg_htonl(INADDR_ANY);
setsockopt(FD(c), IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq)); setsockopt(FD(c), IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq,
#endif // !Zephyr sizeof(mreq));
#endif // !lwIP #endif // !Zephyr
#endif // !lwIP
#endif #endif
} }
@@ -315,9 +343,9 @@ static void read_conn(struct mg_connection *c) {
if (n == MG_IO_ERR || n == MG_IO_RESET) { // Windows, see #3031 if (n == MG_IO_ERR || n == MG_IO_RESET) { // Windows, see #3031
if (c->rtls.len == 0 || m < 0) { if (c->rtls.len == 0 || m < 0) {
// Close only when we have fully drained both rtls and TLS buffers // 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. 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 if (m < 0) m = MG_IO_ERR; // but return last record data, see #3104
} else { // see #2885 } else { // see #2885
// TLS buffer is capped to max record size, even though, there can // TLS buffer is capped to max record size, even though, there can
// be more than one record, give TLS a chance to process them. // be more than one record, give TLS a chance to process them.
} }
@@ -338,6 +366,7 @@ static void write_conn(struct mg_connection *c) {
char *buf = (char *) c->send.buf; char *buf = (char *) c->send.buf;
size_t len = c->send.len; size_t len = c->send.len;
long n = c->is_tls ? mg_tls_send(c, buf, len) : mg_io_send(c, buf, 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, 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->send.len, (long) c->send.size, (long) c->recv.len,
(long) c->recv.size, n, MG_SOCK_ERR(n))); (long) c->recv.size, n, MG_SOCK_ERR(n)));
@@ -367,7 +396,7 @@ static void connect_conn(struct mg_connection *c) {
mg_call(c, MG_EV_CONNECT, NULL); mg_call(c, MG_EV_CONNECT, NULL);
MG_EPOLL_MOD(c, 0); MG_EPOLL_MOD(c, 0);
if (c->is_tls_hs) mg_tls_handshake(c); if (c->is_tls_hs) mg_tls_handshake(c);
if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init() if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init()
} else { } else {
mg_error(c, "socket error"); mg_error(c, "socket error");
} }
@@ -419,9 +448,9 @@ void mg_connect_resolved(struct mg_connection *c) {
rc = connect(FD(c), &usa.sa, slen); // Attempt to connect rc = connect(FD(c), &usa.sa, slen); // Attempt to connect
if (rc == 0) { // Success if (rc == 0) { // Success
setlocaddr(FD(c), &c->loc); setlocaddr(FD(c), &c->loc);
mg_call(c, MG_EV_CONNECT, NULL); // Send MG_EV_CONNECT to the user mg_call(c, MG_EV_CONNECT, NULL); // Send MG_EV_CONNECT to the user
if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init() if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init()
} else if (MG_SOCK_PENDING(rc)) { // Need to wait for TCP handshake } else if (MG_SOCK_PENDING(rc)) { // Need to wait for TCP handshake
MG_DEBUG(("%lu %ld -> %M pend", c->id, c->fd, mg_print_ip_port, &c->rem)); MG_DEBUG(("%lu %ld -> %M pend", c->id, c->fd, mg_print_ip_port, &c->rem));
c->is_connecting = 1; c->is_connecting = 1;
} else { } else {
@@ -471,7 +500,7 @@ static void accept_conn(struct mg_mgr *mgr, struct mg_connection *lsn) {
setsockopts(c); setsockopts(c);
c->is_accepted = 1; c->is_accepted = 1;
c->is_hexdumping = lsn->is_hexdumping; 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 = lsn->pfn;
c->pfn_data = lsn->pfn_data; c->pfn_data = lsn->pfn_data;
c->fn = lsn->fn; c->fn = lsn->fn;
@@ -481,7 +510,7 @@ static void accept_conn(struct mg_mgr *mgr, struct mg_connection *lsn) {
&c->rem, mg_print_ip_port, &c->loc)); &c->rem, mg_print_ip_port, &c->loc));
mg_call(c, MG_EV_OPEN, NULL); mg_call(c, MG_EV_OPEN, NULL);
mg_call(c, MG_EV_ACCEPT, NULL); mg_call(c, MG_EV_ACCEPT, NULL);
if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init() if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init()
} }
} }
+23 -10
View File
@@ -1,6 +1,6 @@
#include "ssi.h"
#include "log.h" #include "log.h"
#include "printf.h" #include "printf.h"
#include "ssi.h"
#include "util.h" #include "util.h"
#ifndef MG_MAX_SSI_DEPTH #ifndef MG_MAX_SSI_DEPTH
@@ -31,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); mg_snprintf(tmp, sizeof(tmp), "%.*s%s", (int) (p - path), path, arg);
if (depth < MG_MAX_SSI_DEPTH && if (depth < MG_MAX_SSI_DEPTH &&
(data = mg_ssi(tmp, root, depth + 1)) != NULL) { (data = mg_ssi(tmp, root, depth + 1)) != NULL) {
mg_iobuf_add(&b, b.len, data, strlen(data)); size_t datalen = strlen(data);
size_t ret = mg_iobuf_add(&b, b.len, data, datalen);
mg_free(data); mg_free(data);
if (datalen > 0 && ret == 0) goto fail;
} else { } else {
MG_ERROR(("%s: file=%s error or too deep", path, arg)); 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) { } else if (sscanf(buf, "<!--#include virtual=\"%[^\"]", arg) > 0) {
char tmp[MG_PATH_MAX + MG_SSI_BUFSIZ + 10], *data; char tmp[MG_PATH_MAX + MG_SSI_BUFSIZ + 10], *data;
mg_snprintf(tmp, sizeof(tmp), "%s%s", root, arg); mg_snprintf(tmp, sizeof(tmp), "%s%s", root, arg);
if (depth < MG_MAX_SSI_DEPTH && if (depth < MG_MAX_SSI_DEPTH &&
(data = mg_ssi(tmp, root, depth + 1)) != NULL) { (data = mg_ssi(tmp, root, depth + 1)) != NULL) {
mg_iobuf_add(&b, b.len, data, strlen(data)); size_t datalen = strlen(data);
size_t ret = mg_iobuf_add(&b, b.len, data, datalen);
mg_free(data); mg_free(data);
if (datalen > 0 && ret == 0) goto fail;
} else { } else {
MG_ERROR(("%s: virtual=%s error or too deep", path, arg)); MG_ERROR(("%s: virtual=%s error or too deep", path, arg));
} } // TODO(): or OOM at recursive call
} else { } else {
// Unknown SSI tag // Unknown SSI tag
MG_ERROR(("Unknown SSI tag: %.*s", (int) len, buf)); 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; intag = 0;
len = 0; len = 0;
} else if (ch == '<') { } else if (ch == '<') {
intag = 1; 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; len = 0;
buf[len++] = (char) (ch & 0xff); buf[len++] = (char) (ch & 0xff);
} else if (intag) { } else if (intag) {
@@ -69,24 +73,33 @@ static char *mg_ssi(const char *path, const char *root, int depth) {
} else { } else {
buf[len++] = (char) (ch & 0xff); buf[len++] = (char) (ch & 0xff);
if (len >= sizeof(buf)) { 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; len = 0;
} }
} }
} }
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;
if (b.len > 0) mg_iobuf_add(&b, b.len, "", 1); // nul-terminate if (b.len > 0 && mg_iobuf_add(&b, b.len, "", 1) == 0) // nul-terminate
goto fail;
fclose(fp); fclose(fp);
} }
(void) depth; (void) depth;
(void) root; (void) root;
return (char *) b.buf; return (char *) b.buf;
fail:
fclose(fp);
return NULL;
} }
void mg_http_serve_ssi(struct mg_connection *c, const char *root, void mg_http_serve_ssi(struct mg_connection *c, const char *root,
const char *fullpath) { const char *fullpath) {
const char *headers = "Content-Type: text/html; charset=utf-8\r\n"; const char *headers = "Content-Type: text/html; charset=utf-8\r\n";
char *data = mg_ssi(fullpath, root, 0); char *data = mg_ssi(fullpath, root, 0);
if (data == NULL) {
mg_error(c, "OOM");
return;
}
mg_http_reply(c, 200, headers, "%s", data == NULL ? "" : data); mg_http_reply(c, 200, headers, "%s", data == NULL ? "" : data);
mg_free(data); mg_free(data);
} }
+8 -5
View File
@@ -2,12 +2,14 @@
#include "util.h" #include "util.h"
struct mg_str mg_str_s(const char *s) { struct mg_str mg_str_s(const char *s) {
struct mg_str str = {(char *) s, s == NULL ? 0 : strlen(s)}; struct mg_str str;
str.buf = (char *) s, str.len = (s == NULL) ? 0 : strlen(s);
return str; return str;
} }
struct mg_str mg_str_n(const char *s, size_t n) { 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; return str;
} }
@@ -85,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] == '#')) { } 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 if (caps && !caps->buf) caps->len = 0, caps->buf = &s.buf[j]; // Init cap
ni = i++, nj = j + 1; 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; i = ni, j = nj;
if (caps && caps->buf == NULL && caps->len == 0) { if (caps && caps->buf == NULL && caps->len == 0) {
caps--, caps->len = 0; // Restart previous cap caps--, caps->len = 0; // Restart previous cap
@@ -166,8 +170,7 @@ bool mg_str_to_num(struct mg_str str, int base, void *val, size_t val_len) {
i++, ndigits++; i++, ndigits++;
} }
break; break;
default: default: return false;
return false;
} }
if (ndigits == 0) return false; if (ndigits == 0) return false;
if (i != str.len) return false; if (i != str.len) return false;
+1
View File
@@ -34,6 +34,7 @@ void mg_tls_handshake(struct mg_connection *);
// Private // Private
void mg_tls_ctx_init(struct mg_mgr *); void mg_tls_ctx_init(struct mg_mgr *);
void mg_tls_ctx_free(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 // Low-level IO primives used by TLS layer
enum { MG_IO_ERR = -1, MG_IO_WAIT = -2, MG_IO_RESET = -3 }; enum { MG_IO_ERR = -1, MG_IO_WAIT = -2, MG_IO_RESET = -3 };
+93 -81
View File
@@ -40,45 +40,47 @@ static void aes_init_keygen_tables(void);
/****************************************************************************** /******************************************************************************
* AES_SETKEY : called to expand the key for encryption or decryption * AES_SETKEY : called to expand the key for encryption or decryption
******************************************************************************/ ******************************************************************************/
static int aes_setkey(aes_context *ctx, // pointer to context static int aes_setkey(
int mode, // 1 or 0 for Encrypt/Decrypt aes_context *ctx, // pointer to context
const unsigned char *key, // AES input key int mode, // 1 or 0 for Encrypt/Decrypt
unsigned int keysize); // size in bytes (must be 16, 24, 32 for const unsigned char *key, // AES input key
// 128, 192 or 256-bit keys respectively) unsigned int keysize); // size in bytes (must be 16, 24, 32 for
// returns 0 for success // 128, 192 or 256-bit keys respectively)
// returns 0 for success
/****************************************************************************** /******************************************************************************
* AES_CIPHER : called to encrypt or decrypt ONE 128-bit block of data * AES_CIPHER : called to encrypt or decrypt ONE 128-bit block of data
******************************************************************************/ ******************************************************************************/
static int aes_cipher(aes_context *ctx, // pointer to context static int aes_cipher(
const unsigned char input[16], // 128-bit block to en/decipher aes_context *ctx, // pointer to context
unsigned char output[16]); // 128-bit output result block const unsigned char input[16], // 128-bit block to en/decipher
// returns 0 for success unsigned char output[16]); // 128-bit output result block
// returns 0 for success
/****************************************************************************** /******************************************************************************
* GCM_CONTEXT : GCM context / holds keytables, instance data, and AES ctx * GCM_CONTEXT : GCM context / holds keytables, instance data, and AES ctx
******************************************************************************/ ******************************************************************************/
typedef struct { typedef struct {
int mode; // cipher direction: encrypt/decrypt int mode; // cipher direction: encrypt/decrypt
uint64_t len; // cipher data length processed so far uint64_t len; // cipher data length processed so far
uint64_t add_len; // total add data length uint64_t add_len; // total add data length
uint64_t HL[16]; // precalculated lo-half HTable uint64_t HL[16]; // precalculated lo-half HTable
uint64_t HH[16]; // precalculated hi-half HTable uint64_t HH[16]; // precalculated hi-half HTable
unsigned char base_ectr[16]; // first counter-mode cipher output for tag 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 y[16]; // the current cipher-input IV|Counter value
unsigned char buf[16]; // buf working 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_context;
/****************************************************************************** /******************************************************************************
* GCM_SETKEY : sets the GCM (and AES) keying material for use * GCM_SETKEY : sets the GCM (and AES) keying material for use
******************************************************************************/ ******************************************************************************/
static int gcm_setkey( 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 char *key, // pointer to cipher key
const unsigned int keysize // size in bytes (must be 16, 24, 32 for 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)
); // returns 0 for success ); // returns 0 for success
/****************************************************************************** /******************************************************************************
* *
@@ -98,17 +100,17 @@ static int gcm_setkey(
* *
******************************************************************************/ ******************************************************************************/
static int gcm_crypt_and_tag( static int gcm_crypt_and_tag(
gcm_context *ctx, // gcm context with key already setup gcm_context *ctx, // gcm context with key already setup
int mode, // cipher direction: MG_ENCRYPT (1) or MG_DECRYPT (0) int mode, // cipher direction: MG_ENCRYPT (1) or MG_DECRYPT (0)
const unsigned char *iv, // pointer to the 12-byte initialization vector 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 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 const unsigned char *input, // pointer to the cipher data source
unsigned char *output, // pointer to the cipher data destination 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 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( static int gcm_start(
gcm_context *ctx, // pointer to user-provided GCM context gcm_context *ctx, // pointer to user-provided GCM context
int mode, // MG_ENCRYPT (1) or MG_DECRYPT (0) int mode, // MG_ENCRYPT (1) or MG_DECRYPT (0)
const unsigned char *iv, // pointer to initialization vector 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) 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 static int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
size_t length, // length, in bytes, of data to process size_t length, // length, in bytes, of data to process
const unsigned char *input, // pointer to source data 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( static int gcm_finish(
gcm_context *ctx, // pointer to user-provided GCM context gcm_context *ctx, // pointer to user-provided GCM context
unsigned char *tag, // ptr to tag buffer - NULL if tag_len = 0 unsigned char *tag, // ptr to tag buffer - NULL if tag_len = 0
size_t tag_len); // length, in bytes, of the tag-receiving buf 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. * decryption is typically disabled by setting AES_DECRYPTION to 0 in aes.h.
*/ */
// We always need our forward tables // We always need our forward tables
static unsigned char FSb[256]; // Forward substitution box (FSb) static unsigned char FSb[256]; // Forward substitution box (FSb)
static uint32_t FT0[256]; // Forward key schedule assembly tables static uint32_t FT0[256]; // Forward key schedule assembly tables
static uint32_t FT1[256]; static uint32_t FT1[256];
static uint32_t FT2[256]; static uint32_t FT2[256];
static uint32_t FT3[256]; static uint32_t FT3[256];
#if AES_DECRYPTION // We ONLY need reverse for decryption #if AES_DECRYPTION // We ONLY need reverse for decryption
static unsigned char RSb[256]; // Reverse substitution box (RSb) static unsigned char RSb[256]; // Reverse substitution box (RSb)
static uint32_t RT0[256]; // Reverse key schedule assembly tables static uint32_t RT0[256]; // Reverse key schedule assembly tables
static uint32_t RT1[256]; static uint32_t RT1[256];
static uint32_t RT2[256]; static uint32_t RT2[256];
static uint32_t RT3[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); \ ((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)] = (unsigned char) ((n)); \
(b)[(i) + 1] = (unsigned char) ((n) >> 8); \ (b)[(i) + 1] = (unsigned char) ((n) >> 8); \
(b)[(i) + 2] = (unsigned char) ((n) >> 16); \ (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, static int aes_set_encryption_key(aes_context *ctx, const unsigned char *key,
unsigned int keysize) { 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 uint32_t *RK = ctx->rk; // initialize our RoundKey buffer pointer
for (i = 0; i < (keysize >> 2); i++) { 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]); \ ((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)] = (unsigned char) ((n) >> 24); \
(b)[(i) + 1] = (unsigned char) ((n) >> 16); \ (b)[(i) + 1] = (unsigned char) ((n) >> 16); \
(b)[(i) + 2] = (unsigned char) ((n) >> 8); \ (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. * '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 static void gcm_mult(
const unsigned char x[16], // pointer to 128-bit input vector gcm_context *ctx, // pointer to established context
unsigned char output[16]) // pointer to 128-bit output vector const unsigned char x[16], // pointer to 128-bit input vector
unsigned char output[16]) // pointer to 128-bit output vector
{ {
int i; int i;
unsigned char lo, hi, rem; unsigned char lo, hi, rem;
@@ -792,10 +795,10 @@ static void gcm_mult(gcm_context *ctx, // pointer to established context
* *
******************************************************************************/ ******************************************************************************/
static int gcm_setkey( 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 char *key, // pointer to the AES encryption key
const unsigned int keysize) // size in bytes (must be 16, 24, 32 for 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; int ret, i, j;
uint64_t hi, lo; uint64_t hi, lo;
@@ -864,18 +867,19 @@ static int gcm_setkey(
* mode, and preprocesses the initialization vector and additional AEAD data. * mode, and preprocesses the initialization vector and additional AEAD data.
* *
******************************************************************************/ ******************************************************************************/
int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context int gcm_start(
int mode, // GCM_ENCRYPT or GCM_DECRYPT gcm_context *ctx, // pointer to user-provided GCM context
const unsigned char *iv, // pointer to initialization vector int mode, // GCM_ENCRYPT or GCM_DECRYPT
size_t iv_len, // IV length in bytes (should == 12) const unsigned char *iv, // pointer to initialization vector
const unsigned char *add, // ptr to additional AEAD data (NULL if none) size_t iv_len, // IV length in bytes (should == 12)
size_t add_len) // length of additional AEAD data (bytes) 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 unsigned char work_buf[16]; // XOR source built from provided IV if len != 16
const unsigned char *p; // general purpose array pointer const unsigned char *p; // general purpose array pointer
size_t use_len; // byte count to process, up to 16 bytes size_t use_len; // byte count to process, up to 16 bytes
size_t i; // local loop iterator size_t i; // local loop iterator
// since the context might be reused under the same key // since the context might be reused under the same key
// we zero the working buffers for this next new process // 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.) * have a partial block length of < 128 bits.)
* *
******************************************************************************/ ******************************************************************************/
int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
size_t length, // length, in bytes, of data to process size_t length, // length, in bytes, of data to process
const unsigned char *input, // pointer to source data const unsigned char *input, // pointer to source data
unsigned char *output) // pointer to destination 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 unsigned char ectr[16]; // counter-mode cipher output for XORing
size_t use_len; // byte count to process, up to 16 bytes size_t use_len; // byte count to process, up to 16 bytes
size_t i; // local loop iterator size_t i; // local loop iterator
ctx->len += length; // bump the GCM context's running length count 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. * It performs the final GHASH to produce the resulting authentication TAG.
* *
******************************************************************************/ ******************************************************************************/
int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
unsigned char *tag, // pointer to buffer which receives the tag unsigned char *tag, // pointer to buffer which receives the tag
size_t tag_len) // length, in bytes, of the tag-receiving buf size_t tag_len) // length, in bytes, of the tag-receiving buf
{ {
unsigned char work_buf[16]; unsigned char work_buf[16];
uint64_t orig_len = ctx->len * 8; 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( int gcm_crypt_and_tag(
gcm_context *ctx, // gcm context with key already setup gcm_context *ctx, // gcm context with key already setup
int mode, // cipher direction: GCM_ENCRYPT or GCM_DECRYPT int mode, // cipher direction: GCM_ENCRYPT or GCM_DECRYPT
const unsigned char *iv, // pointer to the 12-byte initialization vector 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 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 const unsigned char *input, // pointer to the cipher data source
unsigned char *output, // pointer to the cipher data destination 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 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
{ /* { /*
assuming that the caller has already invoked gcm_setkey to assuming that the caller has already invoked gcm_setkey to
prepare the gcm context with the keying material, we simply prepare the gcm context with the keying material, we simply
invoke each of the three GCM sub-functions in turn... invoke each of the three GCM sub-functions in turn...
*/ */
gcm_start(ctx, mode, iv, iv_len, add, add_len); gcm_start(ctx, mode, iv, iv_len, add, add_len);
gcm_update(ctx, length, input, output); gcm_update(ctx, length, input, output);
gcm_finish(ctx, tag, tag_len); 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, int mg_aes_gcm_decrypt(unsigned char *output, const unsigned char *input,
size_t input_length, const unsigned char *key, size_t input_length, const unsigned char *key,
const size_t key_len, const unsigned char *iv, 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 int ret = 0; // our return value
gcm_context ctx; // includes the AES context structure gcm_context ctx; // includes the AES context structure
unsigned char computed_tag[16];
size_t i;
int diff = 0;
size_t tag_len = 0; if (tag_len > sizeof(computed_tag)) return -1;
unsigned char *tag_buf = NULL;
gcm_setkey(&ctx, key, (unsigned int) key_len); gcm_setkey(&ctx, key, (unsigned int) key_len);
ret = gcm_crypt_and_tag(&ctx, MG_DECRYPT, iv, iv_len, NULL, 0, input, output, ret = gcm_crypt_and_tag(&ctx, MG_DECRYPT, iv, iv_len, aead, aead_len, input,
input_length, tag_buf, tag_len); output, input_length, computed_tag, tag_len);
gcm_zero_ctx(&ctx); 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); return (ret);
} }
#endif #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, int mg_aes_gcm_decrypt(unsigned char *output, const unsigned char *input,
size_t input_length, const unsigned char *key, size_t input_length, const unsigned char *key,
const size_t key_len, const unsigned char *iv, 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 */ #endif /* TLS_AES128_H */
+1001 -198
View File
File diff suppressed because it is too large. Load diff
+29 -15
View File
@@ -79,9 +79,11 @@ static PORTABLE_8439_DECL void poly1305_finish(poly1305_context *ctx,
#elif defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || \ #elif defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || \
defined(__THUMBEL__) || defined(__AARCH64EL__) || defined(_MIPSEL) || \ defined(__THUMBEL__) || defined(__AARCH64EL__) || defined(_MIPSEL) || \
defined(__MIPSEL) || defined(__MIPSEL__) || defined(__XTENSA_EL__) || \ defined(__MIPSEL) || defined(__MIPSEL__) || defined(__XTENSA_EL__) || \
defined(__AVR__) || defined(LITTLE_ENDIAN) defined(__AVR__)
#define __HAVE_LITTLE_ENDIAN 1 #define __HAVE_LITTLE_ENDIAN 1
#endif #endif
// DO NOT test for LITTLE_ENDIAN, as it is defined as 1234 when including
// sys/types.h in GCC
#ifndef TEST_SLOW_PATH #ifndef TEST_SLOW_PATH
#if defined(__HAVE_LITTLE_ENDIAN) #if defined(__HAVE_LITTLE_ENDIAN)
@@ -177,7 +179,7 @@ static void core_block(const uint32_t *restrict start,
TIMES16(__FIN) TIMES16(__FIN)
} }
#define U8(x) ((uint8_t) ((x) &0xFF)) #define U8(x) ((uint8_t) ((x) & 0xFF))
#ifdef FAST_PATH #ifdef FAST_PATH
#define xor32_le(dst, src, pad) \ #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 /* store a 16 bit unsigned integer as two 8 bit unsigned integers in little
* endian */ * endian */
static void U16TO8(unsigned char *p, unsigned short v) { static void U16TO8(unsigned char *p, unsigned short v) {
p[0] = (v) &0xff; p[0] = (v) & 0xff;
p[1] = (v >> 8) & 0xff; p[1] = (v >> 8) & 0xff;
} }
@@ -513,7 +515,7 @@ static void poly1305_init(poly1305_context *ctx, const unsigned char key[32]) {
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
t0 = U8TO16(&key[0]); t0 = U8TO16(&key[0]);
st->r[0] = (t0) &0x1fff; st->r[0] = (t0) & 0x1fff;
t1 = U8TO16(&key[2]); t1 = U8TO16(&key[2]);
st->r[1] = ((t0 >> 13) | (t1 << 3)) & 0x1fff; st->r[1] = ((t0 >> 13) | (t1 << 3)) & 0x1fff;
t2 = U8TO16(&key[4]); t2 = U8TO16(&key[4]);
@@ -553,7 +555,7 @@ static void poly1305_blocks(poly1305_state_internal_t *st,
/* h += m[i] */ /* h += m[i] */
t0 = U8TO16(&m[0]); t0 = U8TO16(&m[0]);
st->h[0] += (t0) &0x1fff; st->h[0] += (t0) & 0x1fff;
t1 = U8TO16(&m[2]); t1 = U8TO16(&m[2]);
st->h[1] += ((t0 >> 13) | (t1 << 3)) & 0x1fff; st->h[1] += ((t0 >> 13) | (t1 << 3)) & 0x1fff;
t2 = U8TO16(&m[4]); 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 /* store a 32 bit unsigned integer as four 8 bit unsigned integers in little
* endian */ * endian */
static void U32TO8(unsigned char *p, unsigned long v) { 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[1] = (unsigned char) ((v >> 8) & 0xff);
p[2] = (unsigned char) ((v >> 16) & 0xff); p[2] = (unsigned char) ((v >> 16) & 0xff);
p[3] = (unsigned char) ((v >> 24) & 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 MUL128(out, x, y) out = ((uint128_t) x * y)
#define ADD(out, in) out += in #define ADD(out, in) out += in
#define ADDLO(out, in) out += in #define ADDLO(out, in) out += in
#define SHR(in, shift) (uint64_t)(in >> (shift)) #define SHR(in, shift) (uint64_t) (in >> (shift))
#define LO(in) (uint64_t)(in) #define LO(in) (uint64_t) (in)
#define POLY1305_NOINLINE __attribute__((noinline)) #define POLY1305_NOINLINE __attribute__((noinline))
#endif #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 /* store a 64 bit unsigned integer as eight 8 bit unsigned integers in little
* endian */ * endian */
static void U64TO8(unsigned char *p, uint64_t v) { 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[1] = (unsigned char) ((v >> 8) & 0xff);
p[2] = (unsigned char) ((v >> 16) & 0xff); p[2] = (unsigned char) ((v >> 16) & 0xff);
p[3] = (unsigned char) ((v >> 24) & 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]); t0 = U8TO64(&key[0]);
t1 = U8TO64(&key[8]); t1 = U8TO64(&key[8]);
st->r[0] = (t0) &0xffc0fffffff; st->r[0] = (t0) & 0xffc0fffffff;
st->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff; st->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff;
st->r[2] = ((t1 >> 24)) & 0x00ffffffc0f; st->r[2] = ((t1 >> 24)) & 0x00ffffffc0f;
@@ -1071,7 +1073,7 @@ static void poly1305_blocks(poly1305_state_internal_t *st,
t0 = U8TO64(&m[0]); t0 = U8TO64(&m[0]);
t1 = U8TO64(&m[8]); t1 = U8TO64(&m[8]);
h0 += ((t0) &0xfffffffffff); h0 += ((t0) & 0xfffffffffff);
h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff); h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff);
h2 += (((t1 >> 24)) & 0x3ffffffffff) | hibit; h2 += (((t1 >> 24)) & 0x3ffffffffff) | hibit;
@@ -1178,7 +1180,7 @@ static POLY1305_NOINLINE void poly1305_finish(poly1305_context *ctx,
t0 = st->pad[0]; t0 = st->pad[0];
t1 = st->pad[1]; t1 = st->pad[1];
h0 += ((t0) &0xfffffffffff); h0 += ((t0) & 0xfffffffffff);
c = (h0 >> 44); c = (h0 >> 44);
h0 &= 0xfffffffffff; h0 &= 0xfffffffffff;
h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + c; 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 // TODO: make this depending on the unaligned/native read size possible
static PORTABLE_8439_DECL void write_64bit_int(poly1305_context *ctx, 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( PORTABLE_8439_DECL size_t mg_chacha20_poly1305_decrypt(
uint8_t *restrict plain_text, const uint8_t key[RFC_8439_KEY_SIZE], uint8_t *restrict plain_text, const uint8_t key[RFC_8439_KEY_SIZE],
const uint8_t nonce[RFC_8439_NONCE_SIZE], const uint8_t nonce[RFC_8439_NONCE_SIZE], const uint8_t *restrict ad,
const uint8_t *restrict cipher_text, size_t cipher_text_size) { 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 // 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; 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)) { if (MG_OVERLAPPING(plain_text, actual_size, cipher_text, cipher_text_size)) {
return (size_t) -1; 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); chacha20_xor_stream(plain_text, cipher_text, actual_size, key, nonce, 1);
return actual_size; return actual_size;
} }
+1
View File
@@ -105,6 +105,7 @@ PORTABLE_8439_DECL size_t mg_chacha20_poly1305_encrypt(
PORTABLE_8439_DECL size_t mg_chacha20_poly1305_decrypt( PORTABLE_8439_DECL size_t mg_chacha20_poly1305_decrypt(
uint8_t *restrict plain_text, const uint8_t key[RFC_8439_KEY_SIZE], uint8_t *restrict plain_text, const uint8_t key[RFC_8439_KEY_SIZE],
const uint8_t nonce[RFC_8439_NONCE_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); const uint8_t *restrict cipher_text, size_t cipher_text_size);
#if defined(__cplusplus) #if defined(__cplusplus)
} }
+42 -17
View File
@@ -6,7 +6,8 @@
#if MG_TLS == MG_TLS_MBED #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 #define MG_MBEDTLS_RNG_GET , mg_mbed_rng, NULL
#else #else
#define MG_MBEDTLS_RNG_GET #define MG_MBEDTLS_RNG_GET
@@ -19,16 +20,19 @@ static int mg_tls_err(struct mg_connection *c, int rc) {
return rc; 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) { static int mg_mbed_rng(void *ctx, unsigned char *buf, size_t len) {
mg_random(buf, len); mg_random(buf, len);
(void) ctx; (void) ctx;
return 0; return 0;
} }
#endif
static bool mg_load_cert(struct mg_str str, mbedtls_x509_crt *p) { static bool mg_load_cert(struct mg_str str, mbedtls_x509_crt *p) {
int rc; int rc;
if (str.buf == NULL || str.buf[0] == '\0' || str.buf[0] == '*') return true; 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) { if ((rc = mbedtls_x509_crt_parse(p, (uint8_t *) str.buf, str.len)) != 0) {
MG_ERROR(("cert err %#x", -rc)); MG_ERROR(("cert err %#x", -rc));
return false; return false;
@@ -39,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) { static bool mg_load_key(struct mg_str str, mbedtls_pk_context *p) {
int rc; int rc;
if (str.buf == NULL || str.buf[0] == '\0' || str.buf[0] == '*') return true; 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, if ((rc = mbedtls_pk_parse_key(p, (uint8_t *) str.buf, str.len, NULL,
0 MG_MBEDTLS_RNG_GET)) != 0) { 0 MG_MBEDTLS_RNG_GET)) != 0) {
MG_ERROR(("key err %#x", -rc)); MG_ERROR(("key err %#x", -rc));
@@ -59,6 +63,9 @@ void mg_tls_free(struct mg_connection *c) {
#ifdef MBEDTLS_SSL_SESSION_TICKETS #ifdef MBEDTLS_SSL_SESSION_TICKETS
mbedtls_ssl_ticket_free(&tls->ticket); mbedtls_ssl_ticket_free(&tls->ticket);
#endif #endif
// 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); mg_free(tls);
c->tls = NULL; c->tls = NULL;
} }
@@ -118,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 && \ #if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000 && \
defined(MBEDTLS_PSA_CRYPTO_C) defined(MBEDTLS_PSA_CRYPTO_C)
psa_crypto_init(); // https://github.com/Mbed-TLS/mbedtls/issues/9072#issuecomment-2084845711 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 #endif
mbedtls_ssl_init(&tls->ssl); mbedtls_ssl_init(&tls->ssl);
mbedtls_ssl_config_init(&tls->conf); mbedtls_ssl_config_init(&tls->conf);
@@ -135,7 +143,11 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
mg_error(c, "tls defaults %#x", -mg_tls_err(c, rc)); mg_error(c, "tls defaults %#x", -mg_tls_err(c, rc));
goto fail; 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); mbedtls_ssl_conf_rng(&tls->conf, mg_mbed_rng, c);
#endif
if (opts->ca.len == 0 || mg_strcmp(opts->ca, mg_str("*")) == 0) { 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 // NOTE: MBEDTLS_SSL_VERIFY_NONE is not supported for TLS1.3 on client side
@@ -144,11 +156,16 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
} else { } else {
if (mg_load_cert(opts->ca, &tls->ca) == false) goto fail; if (mg_load_cert(opts->ca, &tls->ca) == false) goto fail;
mbedtls_ssl_conf_ca_chain(&tls->conf, &tls->ca, NULL); mbedtls_ssl_conf_ca_chain(&tls->conf, &tls->ca, NULL);
if (c->is_client && opts->name.buf != NULL && opts->name.buf[0] != '\0') { if (c->is_client) {
char *host = mg_mprintf("%.*s", opts->name.len, opts->name.buf); if (opts->name.buf != NULL && opts->name.buf[0] != '\0') {
mbedtls_ssl_set_hostname(&tls->ssl, host); char *host = mg_mprintf("%.*s", opts->name.len, opts->name.buf);
MG_DEBUG(("%lu hostname verification: %s", c->id, host)); mbedtls_ssl_set_hostname(&tls->ssl, host);
mg_free(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); mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
} }
@@ -187,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) { long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
struct mg_tls *tls = (struct mg_tls *) c->tls; struct mg_tls *tls = (struct mg_tls *) c->tls;
long n = mbedtls_ssl_read(&tls->ssl, (unsigned char *) buf, len); 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) if (n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE)
return MG_IO_WAIT; return MG_IO_WAIT;
#if defined(MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET) #if defined(MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET)
@@ -211,10 +228,11 @@ 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); (n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE);
if (was_throttled) return MG_IO_WAIT; // flushed throttled data instead if (was_throttled) return MG_IO_WAIT; // flushed throttled data instead
if (c->is_tls_throttled) { if (c->is_tls_throttled) {
tls->throttled_buf = (unsigned char *)buf; // MbedTLS code actually ignores tls->throttled_buf =
tls->throttled_len = len; // these, but let's play API rules (unsigned char *) buf; // MbedTLS code actually ignores
return (long) len; // already encripted that when throttled tls->throttled_len = len; // these, but let's play API rules
} // if last chunk fails to be sent, it needs to be flushed return (long) len; // already encripted that when throttled
} // if last chunk fails to be sent, it needs to be flushed
if (n <= 0) return MG_IO_ERR; if (n <= 0) return MG_IO_ERR;
return n; return n;
} }
@@ -222,8 +240,10 @@ long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
void mg_tls_flush(struct mg_connection *c) { void mg_tls_flush(struct mg_connection *c) {
struct mg_tls *tls = (struct mg_tls *) c->tls; struct mg_tls *tls = (struct mg_tls *) c->tls;
if (c->is_tls_throttled) { if (c->is_tls_throttled) {
long n = mbedtls_ssl_write(&tls->ssl, tls->throttled_buf, tls->throttled_len); long n =
c->is_tls_throttled = (n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE); 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);
} }
} }
@@ -235,9 +255,14 @@ void mg_tls_ctx_init(struct mg_mgr *mgr) {
#ifdef MBEDTLS_SSL_SESSION_TICKETS #ifdef MBEDTLS_SSL_SESSION_TICKETS
int rc; int rc;
mbedtls_ssl_ticket_init(&ctx->tickets); 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, if ((rc = mbedtls_ssl_ticket_setup(&ctx->tickets, mg_mbed_rng, NULL,
MBEDTLS_CIPHER_AES_128_GCM, 86400)) != MBEDTLS_CIPHER_AES_128_GCM, 86400))
0) { #endif
!= 0) {
MG_ERROR((" mbedtls_ssl_ticket_setup %#x", -rc)); MG_ERROR((" mbedtls_ssl_ticket_setup %#x", -rc));
} }
#endif #endif
+21 -4
View File
@@ -28,6 +28,7 @@ static int mg_tls_err(struct mg_connection *c, struct mg_tls *tls, int res) {
return err; return err;
} }
#if MG_TLS != MG_TLS_WOLFSSL
static STACK_OF(X509_INFO) * load_ca_certs(struct mg_str ca) { static STACK_OF(X509_INFO) * load_ca_certs(struct mg_str ca) {
BIO *bio = BIO_new_mem_buf(ca.buf, (int) ca.len); BIO *bio = BIO_new_mem_buf(ca.buf, (int) ca.len);
STACK_OF(X509_INFO) *certs = STACK_OF(X509_INFO) *certs =
@@ -39,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) { static bool add_ca_certs(SSL_CTX *ctx, STACK_OF(X509_INFO) * certs) {
int i; int i;
X509_STORE *cert_store = SSL_CTX_get_cert_store(ctx); 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++) { for (i = 0; i < sk_X509_INFO_num(certs); i++) {
X509_INFO *cert_info = sk_X509_INFO_value(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)) if (cert_info->x509 && !X509_STORE_add_cert(cert_store, cert_info->x509))
@@ -46,6 +48,7 @@ static bool add_ca_certs(SSL_CTX *ctx, STACK_OF(X509_INFO) * certs) {
} }
return true; return true;
} }
#endif
static EVP_PKEY *load_key(struct mg_str s) { static EVP_PKEY *load_key(struct mg_str s) {
BIO *bio = BIO_new_mem_buf(s.buf, (int) (long) s.len); BIO *bio = BIO_new_mem_buf(s.buf, (int) (long) s.len);
@@ -57,9 +60,9 @@ static EVP_PKEY *load_key(struct mg_str s) {
static X509 *load_cert(struct mg_str s) { static X509 *load_cert(struct mg_str s) {
BIO *bio = BIO_new_mem_buf(s.buf, (int) (long) s.len); BIO *bio = BIO_new_mem_buf(s.buf, (int) (long) s.len);
X509 *cert = bio == NULL ? NULL X509 *cert = bio == NULL ? NULL
: s.buf[0] == '-' : MG_IS_DER(s.buf)
? PEM_read_bio_X509(bio, NULL, NULL, NULL) // PEM ? d2i_X509_bio(bio, NULL) // DER
: d2i_X509_bio(bio, NULL); // DER : PEM_read_bio_X509(bio, NULL, NULL, NULL); // PEM
if (bio) BIO_free(bio); if (bio) BIO_free(bio);
return cert; return cert;
} }
@@ -170,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); SSL_set_verify(tls->ssl, SSL_VERIFY_NONE, NULL);
} }
#endif #endif
if (opts->ca.buf != NULL && opts->ca.buf[0] != '\0') { 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, SSL_set_verify(tls->ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
NULL); 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); STACK_OF(X509_INFO) *certs = load_ca_certs(opts->ca);
rc = add_ca_certs(tls->ctx, certs); rc = add_ca_certs(tls->ctx, certs);
sk_X509_INFO_pop_free(certs, X509_INFO_free); sk_X509_INFO_pop_free(certs, X509_INFO_free);
@@ -180,7 +195,9 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
mg_error(c, "CA err"); mg_error(c, "CA err");
goto fail; goto fail;
} }
#endif
} }
if (opts->cert.buf != NULL && opts->cert.buf[0] != '\0') { if (opts->cert.buf != NULL && opts->cert.buf[0] != '\0') {
X509 *cert = load_cert(opts->cert); X509 *cert = load_cert(opts->cert);
rc = cert == NULL ? 0 : SSL_use_certificate(tls->ssl, cert); rc = cert == NULL ? 0 : SSL_use_certificate(tls->ssl, cert);
@@ -258,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) { long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
struct mg_tls *tls = (struct mg_tls *) c->tls; struct mg_tls *tls = (struct mg_tls *) c->tls;
int n = SSL_read(tls->ssl, buf, (int) len); 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 && mg_tls_err(c, tls, n) == 0) return MG_IO_WAIT;
if (n <= 0) return MG_IO_ERR; if (n <= 0) return MG_IO_ERR;
return n; return n;
+45 -2
View File
@@ -1520,7 +1520,6 @@ NS_INTERNAL bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp) {
#endif #endif
} }
#if 0
/** /**
* @brief Use the Chinese Remainder Theorem to quickly perform RSA decrypts. * @brief Use the Chinese Remainder Theorem to quickly perform RSA decrypts.
* *
@@ -1533,6 +1532,7 @@ NS_INTERNAL bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp) {
* @param qInv [in] CRT's qInv bigint * @param qInv [in] CRT's qInv bigint
* @return The result of the CRT operation * @return The result of the CRT operation
*/ */
#if 1
NS_INTERNAL bigint *bi_crt(BI_CTX *ctx, bigint *bi, bigint *dP, bigint *dQ, NS_INTERNAL bigint *bi_crt(BI_CTX *ctx, bigint *bi, bigint *dP, bigint *dQ,
bigint *p, bigint *q, bigint *qInv) { bigint *p, bigint *q, bigint *qInv) {
bigint *m1, *m2, *h; bigint *m1, *m2, *h;
@@ -1559,7 +1559,6 @@ NS_INTERNAL bigint *bi_crt(BI_CTX *ctx, bigint *bi, bigint *dP, bigint *dQ,
} }
#endif #endif
// Proper lib usage: // Proper lib usage:
// - BI_CTX *c = bi_initialize() // - BI_CTX *c = bi_initialize()
// - allocate bigints (e.g.: calling bi_import(), int_to_bi(), ...) // - allocate bigints (e.g.: calling bi_import(), int_to_bi(), ...)
@@ -1588,4 +1587,48 @@ int mg_rsa_mod_pow(const uint8_t *mod, size_t modsz, const uint8_t *exp, size_t
return 0; return 0;
} }
int mg_rsa_crt_sign(const uint8_t *em, size_t em_len,
const uint8_t *dP, size_t dP_len,
const uint8_t *dQ, size_t dQ_len,
const uint8_t *p, size_t p_len,
const uint8_t *q, size_t q_len,
const uint8_t *qInv, size_t qInv_len,
uint8_t *signature, size_t sig_len) {
BI_CTX *ctx;
bigint *em_bi, *dP_bi, *dQ_bi, *p_bi, *q_bi, *qInv_bi, *result_bi;
int ret = -1;
ctx = bi_initialize();
if (ctx == NULL) {
return -1;
}
em_bi = bi_import(ctx, em, (int) em_len);
dP_bi = bi_import(ctx, dP, (int) dP_len);
dQ_bi = bi_import(ctx, dQ, (int) dQ_len);
p_bi = bi_import(ctx, p, (int) p_len);
q_bi = bi_import(ctx, q, (int) q_len);
qInv_bi = bi_import(ctx, qInv, (int) qInv_len);
if (em_bi == NULL || dP_bi == NULL || dQ_bi == NULL ||
p_bi == NULL || q_bi == NULL || qInv_bi == NULL) {
goto cleanup;
}
bi_set_mod(ctx, bi_clone(ctx, p_bi), BIGINT_P_OFFSET);
bi_set_mod(ctx, bi_clone(ctx, q_bi), BIGINT_Q_OFFSET);
result_bi = bi_crt(ctx, em_bi, dP_bi, dQ_bi, p_bi, q_bi, qInv_bi);
if (result_bi == NULL) {
goto cleanup;
}
bi_export(ctx, result_bi, signature, (int) sig_len);
ret = 0; // Success!
cleanup:
bi_free_mod(ctx, BIGINT_P_OFFSET); // cloned p_bi stored in mod context
bi_free_mod(ctx, BIGINT_Q_OFFSET); // cloned q_bi stored in mod context
bi_terminate(ctx);
return ret;
}
#endif /* MG_TLS == MG_TLS_BUILTIN */ #endif /* MG_TLS == MG_TLS_BUILTIN */
+7 -1
View File
@@ -3,5 +3,11 @@
#include "arch.h" #include "arch.h"
int mg_rsa_mod_pow(const uint8_t *mod, size_t modsz, const uint8_t *exp, size_t expsz, const uint8_t *msg, size_t msgsz, uint8_t *out, size_t outsz); int mg_rsa_mod_pow(const uint8_t *mod, size_t modsz, const uint8_t *exp, size_t expsz, const uint8_t *msg, size_t msgsz, uint8_t *out, size_t outsz);
int mg_rsa_crt_sign(const uint8_t *em, size_t em_len,
const uint8_t *dP, size_t dP_len,
const uint8_t *dQ, size_t dQ_len,
const uint8_t *p, size_t p_len,
const uint8_t *q, size_t q_len,
const uint8_t *qInv, size_t qInv_len,
uint8_t *signature, size_t sig_len);
#endif // TLS_RSA_H #endif // TLS_RSA_H
+15 -3
View File
@@ -27,6 +27,15 @@ bool mg_random(void *buf, size_t len) {
#elif MG_ARCH == MG_ARCH_PICOSDK #elif MG_ARCH == MG_ARCH_PICOSDK
while (len--) *p++ = (unsigned char) (get_rand_32() & 255); while (len--) *p++ = (unsigned char) (get_rand_32() & 255);
success = true; success = true;
#elif MG_ARCH == MG_ARCH_ZEPHYR
#if MG_TLS == MG_TLS_BUILTIN || \
(MG_TLS == MG_TLS_MBED && (!defined(MBEDTLS_VERSION_NUMBER) || \
MBEDTLS_VERSION_NUMBER < 0x04000000))
return (sys_csrand_get(buf, len) == 0); // do not fallback on reseed error
#else
sys_rand_get(buf, len);
success = true;
#endif
#elif MG_ARCH == MG_ARCH_WIN32 #elif MG_ARCH == MG_ARCH_WIN32
#if defined(_MSC_VER) && _MSC_VER < 1700 #if defined(_MSC_VER) && _MSC_VER < 1700
static bool initialised = false; static bool initialised = false;
@@ -120,7 +129,7 @@ int mg_check_ip_acl(struct mg_str acl, struct mg_addr *remote_ip) {
if (remote_ip->is_ip6) { if (remote_ip->is_ip6) {
return -1; // TODO(): handle IPv6 ACL and addresses return -1; // TODO(): handle IPv6 ACL and addresses
} else { // IPv4 } else { // IPv4
memcpy((void *) &remote_ip4, remote_ip->ip, sizeof(remote_ip4)); memcpy((void *) &remote_ip4, remote_ip->addr.ip, sizeof(remote_ip4));
while (mg_span(acl, &entry, &acl, ',')) { while (mg_span(acl, &entry, &acl, ',')) {
uint32_t net, mask; uint32_t net, mask;
if (entry.buf[0] != '+' && entry.buf[0] != '-') return -1; if (entry.buf[0] != '+' && entry.buf[0] != '-') return -1;
@@ -134,7 +143,7 @@ int mg_check_ip_acl(struct mg_str acl, struct mg_addr *remote_ip) {
bool mg_path_is_sane(const struct mg_str path) { bool mg_path_is_sane(const struct mg_str path) {
const char *s = path.buf; const char *s = path.buf;
size_t n = path.len; size_t n = path.len;
if (path.buf[0] == '~') return false; // Starts with ~ if (path.buf[0] == '~') return false; // Starts with ~
if (path.buf[0] == '.' && path.buf[1] == '.') return false; // Starts with .. if (path.buf[0] == '.' && path.buf[1] == '.') return false; // Starts with ..
for (; s[0] != '\0' && n > 0; s++, n--) { for (; s[0] != '\0' && n > 0; s++, n--) {
if ((s[0] == '/' || s[0] == '\\') && n >= 2) { // Subdir? if ((s[0] == '/' || s[0] == '\\') && n >= 2) { // Subdir?
@@ -204,12 +213,15 @@ uint32_t mg_ntohl(uint32_t net) {
return MG_LOAD_BE32(&net); return MG_LOAD_BE32(&net);
} }
uint64_t mg_ntohll(uint64_t net) {
return MG_LOAD_BE64(&net);
}
void mg_delayms(unsigned int ms) { void mg_delayms(unsigned int ms) {
uint64_t to = mg_millis() + ms + 1; uint64_t to = mg_millis() + ms + 1;
while (mg_millis() < to) (void) 0; while (mg_millis() < to) (void) 0;
} }
#if MG_ENABLE_CUSTOM_CALLOC #if MG_ENABLE_CUSTOM_CALLOC
#else #else
void *mg_calloc(size_t count, size_t size) { void *mg_calloc(size_t count, size_t size) {
+31
View File
@@ -27,6 +27,16 @@ void mg_delayms(unsigned int ms);
#define MG_IPV4(a, b, c, d) mg_htonl(MG_U32(a, b, c, d)) #define MG_IPV4(a, b, c, d) mg_htonl(MG_U32(a, b, c, d))
#define MG_IPV6(a, b, c, d, e, f, g ,h) \
{ (uint8_t)((a)>>8),(uint8_t)(a), \
(uint8_t)((b)>>8),(uint8_t)(b), \
(uint8_t)((c)>>8),(uint8_t)(c), \
(uint8_t)((d)>>8),(uint8_t)(d), \
(uint8_t)((e)>>8),(uint8_t)(e), \
(uint8_t)((f)>>8),(uint8_t)(f), \
(uint8_t)((g)>>8),(uint8_t)(g), \
(uint8_t)((h)>>8),(uint8_t)(h) }
// For printing IPv4 addresses: printf("%d.%d.%d.%d\n", MG_IPADDR_PARTS(&ip)) // For printing IPv4 addresses: printf("%d.%d.%d.%d\n", MG_IPADDR_PARTS(&ip))
#define MG_U8P(ADDR) ((uint8_t *) (ADDR)) #define MG_U8P(ADDR) ((uint8_t *) (ADDR))
#define MG_IPADDR_PARTS(ADDR) \ #define MG_IPADDR_PARTS(ADDR) \
@@ -41,6 +51,14 @@ void mg_delayms(unsigned int ms);
((uint32_t) (((uint32_t) MG_U8P(p)[0] << 24U) | \ ((uint32_t) (((uint32_t) MG_U8P(p)[0] << 24U) | \
((uint32_t) MG_U8P(p)[1] << 16U) | \ ((uint32_t) MG_U8P(p)[1] << 16U) | \
((uint32_t) MG_U8P(p)[2] << 8U) | MG_U8P(p)[3])) ((uint32_t) MG_U8P(p)[2] << 8U) | MG_U8P(p)[3]))
#define MG_LOAD_BE64(p) \
((uint64_t) (((uint64_t) MG_U8P(p)[0] << 56U) | \
((uint64_t) MG_U8P(p)[1] << 48U) | \
((uint64_t) MG_U8P(p)[2] << 40U) | \
((uint64_t) MG_U8P(p)[3] << 32U) | \
((uint64_t) MG_U8P(p)[4] << 24U) | \
((uint64_t) MG_U8P(p)[5] << 16U) | \
((uint64_t) MG_U8P(p)[6] << 8U) | MG_U8P(p)[7]))
#define MG_STORE_BE16(p, n) \ #define MG_STORE_BE16(p, n) \
do { \ do { \
MG_U8P(p)[0] = ((n) >> 8U) & 255; \ MG_U8P(p)[0] = ((n) >> 8U) & 255; \
@@ -59,11 +77,24 @@ void mg_delayms(unsigned int ms);
MG_U8P(p)[2] = ((n) >> 8U) & 255; \ MG_U8P(p)[2] = ((n) >> 8U) & 255; \
MG_U8P(p)[3] = (n) &255; \ MG_U8P(p)[3] = (n) &255; \
} while (0) } while (0)
#define MG_STORE_BE64(p, n) \
do { \
MG_U8P(p)[0] = ((n) >> 56U) & 255; \
MG_U8P(p)[1] = ((n) >> 48U) & 255; \
MG_U8P(p)[2] = ((n) >> 40U) & 255; \
MG_U8P(p)[3] = ((n) >> 32U) & 255; \
MG_U8P(p)[4] = ((n) >> 24U) & 255; \
MG_U8P(p)[5] = ((n) >> 16U) & 255; \
MG_U8P(p)[6] = ((n) >> 8U) & 255; \
MG_U8P(p)[7] = (n) &255; \
} while (0)
uint16_t mg_ntohs(uint16_t net); uint16_t mg_ntohs(uint16_t net);
uint32_t mg_ntohl(uint32_t net); uint32_t mg_ntohl(uint32_t net);
uint64_t mg_ntohll(uint64_t net);
#define mg_htons(x) mg_ntohs(x) #define mg_htons(x) mg_ntohs(x)
#define mg_htonl(x) mg_ntohl(x) #define mg_htonl(x) mg_ntohl(x)
#define mg_htonll(x) mg_ntohll(x)
#define MG_REG(x) ((volatile uint32_t *) (x))[0] #define MG_REG(x) ((volatile uint32_t *) (x))[0]
#define MG_BIT(x) (((uint32_t) 1U) << (x)) #define MG_BIT(x) (((uint32_t) 1U) << (x))
+1 -1
View File
@@ -1 +1 @@
#define MG_VERSION "7.19" #define MG_VERSION "7.21"
+31 -17
View File
@@ -4,26 +4,40 @@
#include "log.h" #include "log.h"
#include "str.h" #include "str.h"
struct mg_wifi_scan_bss_data { struct mg_wifi_data {
struct mg_str SSID; char *ssid, *pass; // STA mode, SSID to connect to
char *BSSID; char *apssid, *appass; // AP mode, our SSID
int16_t RSSI; uint32_t apip, apmask; // AP mode, our IP address and mask
uint8_t security; uint8_t security; // STA mode, TBD
#define MG_WIFI_SECURITY_OPEN 0 uint8_t apsecurity; // AP mode, TBD
#define MG_WIFI_SECURITY_WEP MG_BIT(0) uint8_t apchannel; // AP mode, channel to use
#define MG_WIFI_SECURITY_WPA MG_BIT(1) bool apmode; // start in AP mode; 'false' -> connect to 'ssid' != NULL
#define MG_WIFI_SECURITY_WPA2 MG_BIT(2)
#define MG_WIFI_SECURITY_WPA3 MG_BIT(3)
uint8_t channel;
unsigned band :2;
#define MG_WIFI_BAND_2G 0
#define MG_WIFI_BAND_5G 1
unsigned has_n :1;
}; };
struct mg_wifi_scan_bss_data {
struct mg_str SSID;
char *BSSID;
int16_t RSSI;
uint8_t security;
#define MG_WIFI_SECURITY_OPEN 0
#define MG_WIFI_SECURITY_WEP MG_BIT(0)
#define MG_WIFI_SECURITY_WPA MG_BIT(1)
#define MG_WIFI_SECURITY_WPA2 MG_BIT(2)
#define MG_WIFI_SECURITY_WPA3 MG_BIT(3)
#define MG_WIFI_SECURITY_WPA_ENTERPRISE MG_BIT(4)
#define MG_WIFI_SECURITY_WPA2_ENTERPRISE MG_BIT(5)
#define MG_WIFI_SECURITY_WPA3_ENTERPRISE MG_BIT(6)
uint8_t channel;
unsigned band : 2;
#define MG_WIFI_BAND_2G 0
#define MG_WIFI_BAND_5G 1
unsigned has_n : 1;
unsigned has_ac : 1;
unsigned has_ax : 1;
};
bool mg_wifi_scan(void); bool mg_wifi_scan(void);
bool mg_wifi_connect(char *ssid, char *pass); bool mg_wifi_connect(struct mg_wifi_data *);
bool mg_wifi_disconnect(void); bool mg_wifi_disconnect(void);
bool mg_wifi_ap_start(char *ssid, char *pass, unsigned int channel); bool mg_wifi_ap_start(struct mg_wifi_data *);
bool mg_wifi_ap_stop(void); bool mg_wifi_ap_stop(void);
+7 -8
View File
@@ -2,7 +2,9 @@
#if (!defined(MG_ENABLE_DRIVER_PICO_W) || !MG_ENABLE_DRIVER_PICO_W) && \ #if (!defined(MG_ENABLE_DRIVER_PICO_W) || !MG_ENABLE_DRIVER_PICO_W) && \
(!defined(MG_ENABLE_DRIVER_CYW) || !MG_ENABLE_DRIVER_CYW) && \ (!defined(MG_ENABLE_DRIVER_CYW) || !MG_ENABLE_DRIVER_CYW) && \
(!defined(MG_ENABLE_DRIVER_CYW_SDIO) || !MG_ENABLE_DRIVER_CYW_SDIO) (!defined(MG_ENABLE_DRIVER_CYW_SDIO) || !MG_ENABLE_DRIVER_CYW_SDIO) && \
(!defined(MG_ENABLE_DRIVER_NXP_WIFI) || !MG_ENABLE_DRIVER_NXP_WIFI) && \
(!defined(MG_ENABLE_DRIVER_ST67W6) || !MG_ENABLE_DRIVER_ST67W6)
bool mg_wifi_scan(void) { bool mg_wifi_scan(void) {
@@ -10,9 +12,8 @@ bool mg_wifi_scan(void) {
return false; return false;
} }
bool mg_wifi_connect(char *ssid, char *pass) { bool mg_wifi_connect(struct mg_wifi_data *wifi) {
(void) ssid; (void) wifi;
(void) pass;
return mg_wifi_scan(); return mg_wifi_scan();
} }
@@ -20,10 +21,8 @@ bool mg_wifi_disconnect(void) {
return mg_wifi_scan(); return mg_wifi_scan();
} }
bool mg_wifi_ap_start(char *ssid, char *pass, unsigned int channel) { bool mg_wifi_ap_start(struct mg_wifi_data *wifi) {
(void) ssid; (void) wifi;
(void) pass;
(void) channel;
return mg_wifi_scan(); return mg_wifi_scan();
} }
+10 -6
View File
@@ -55,7 +55,7 @@ static void ws_handshake(struct mg_connection *c, const struct mg_str *wskey,
mg_printf(c, "Sec-WebSocket-Protocol: %.*s\r\n", (int) wsproto->len, mg_printf(c, "Sec-WebSocket-Protocol: %.*s\r\n", (int) wsproto->len,
wsproto->buf); wsproto->buf);
} }
mg_send(c, "\r\n", 2); if (!mg_send(c, "\r\n", 2)) mg_error(c, "OOM");
} }
static uint32_t be32(const uint8_t *p) { static uint32_t be32(const uint8_t *p) {
@@ -173,9 +173,13 @@ static void mg_ws_cb(struct mg_connection *c, int ev, void *ev_data) {
while (ws_process(c->recv.buf + ofs, c->recv.len - ofs, &msg) > 0) { while (ws_process(c->recv.buf + ofs, c->recv.len - ofs, &msg) > 0) {
char *s = (char *) c->recv.buf + ofs + msg.header_len; char *s = (char *) c->recv.buf + ofs + msg.header_len;
struct mg_ws_message m = {{s, msg.data_len}, msg.flags}; struct mg_ws_message m;
size_t len = msg.header_len + msg.data_len; size_t len;
uint8_t final = msg.flags & 128, op = msg.flags & 15; uint8_t final, op;
m.data.buf = s, m.data.len = msg.data_len, m.flags = msg.flags;
len = msg.header_len + msg.data_len;
final = msg.flags & 128;
op = msg.flags & 15;
// MG_VERBOSE ("fin %d op %d len %d [%.*s]", final, op, // MG_VERBOSE ("fin %d op %d len %d [%.*s]", final, op,
// (int) m.data.len, (int) m.data.len, m.data.buf)); // (int) m.data.len, (int) m.data.len, m.data.buf));
switch (op) { switch (op) {
@@ -292,6 +296,6 @@ size_t mg_ws_wrap(struct mg_connection *c, size_t len, int op) {
memmove(p, p - header_len, len); // Shift data memmove(p, p - header_len, len); // Shift data
memcpy(p - header_len, header, header_len); // Prepend header memcpy(p - header_len, header, header_len); // Prepend header
mg_ws_mask(c, len); // Mask data mg_ws_mask(c, len); // Mask data
} } // returning 0 means an OOM condition (iobuf couldn't resize), yet this is
return c->send.len; return c->send.len; // so far recoverable, let the caller decide
} }
+26 -4
View File
@@ -91,9 +91,18 @@ mip_tap_test: mip_tap_test.c mongoose.c mongoose.h packed_fs.c Makefile tls_mult
$(CC) mip_tap_test.c packed_fs.c $(CFLAGS) $(LDFLAGS) -o $@ $(CC) mip_tap_test.c packed_fs.c $(CFLAGS) $(LDFLAGS) -o $@
ASAN_OPTIONS=$(ASAN_OPTIONS) $(RUN) ./$@ ASAN_OPTIONS=$(ASAN_OPTIONS) $(RUN) ./$@
# bridge UDP port <--> TAP interface
port_tap_bridge: port_tap_bridge.c
cc port_tap_bridge.c -o $@
# requires port_tap_bridge to be running
mip_port_test: mip_port_test.c mongoose.c mongoose.h packed_fs.c Makefile tls_multirec/server
$(CC) mip_port_test.c packed_fs.c $(CFLAGS) $(LDFLAGS) -o $@
ASAN_OPTIONS=$(ASAN_OPTIONS) $(RUN) ./$@
mip_vc98: mip_test.c mongoose.c mongoose.h packed_fs.c Makefile mip_vc98: mip_test.c mongoose.c mongoose.h packed_fs.c Makefile
$(DOCKER) mdashnet/vc98 wine cl mip_test.c packed_fs.c $(VCFLAGS) $(DEFS) $(TFLAGS) /Fe$@.exe $(DOCKER) mdashnet/vc98 wine cl mip_test.c packed_fs.c $(VCFLAGS) $(DEFS) $(TFLAGS) /Fe$@.exe
$(DOCKER) mdashnet/vc98 wine $@.exe $(DOCKER) -e WINEPREFIX=/tmp/wineprefix mdashnet/vc98 wine $@.exe
packed_fs.c: Makefile data/ssi.h fuzz.c data/a.txt data/ca.pem certs/ca.crt certs/server.crt certs/server.key packed_fs.c: Makefile data/ssi.h fuzz.c data/a.txt data/ca.pem certs/ca.crt certs/server.crt certs/server.key
$(CC) $(CFLAGS) pack.c -o pack $(CC) $(CFLAGS) pack.c -o pack
@@ -179,11 +188,23 @@ armhf: test
s390: ASAN= s390: ASAN=
s390: IPV6=0 s390: IPV6=0
s390: CFLAGS += -Wno-stringop-overflow s390: CFLAGS += -Wno-stringop-overflow
s390: DEFS += -DMG_ENABLE_CHACHA20=0
s390: CC = $(DOCKER) mdashnet/s390 cc s390: CC = $(DOCKER) mdashnet/s390 cc
s390: RUN = $(DOCKER) --init mdashnet/s390 s390: RUN = $(DOCKER) --init mdashnet/s390
s390: test s390: test
mip_s390: ASAN=
mip_s390: CC = $(DOCKER) mdashnet/s390 cc
mip_s390: RUN = $(DOCKER) --init mdashnet/s390
mip_s390: mip_test
mip_port_s390: ASAN=
mip_port_s390: IPV6=0
# This test requires curl, not present in this image
mip_port_s390: CFLAGS += -DNO_HTTPSERVER_TEST
mip_port_s390: CC = $(DOCKER) mdashnet/s390 cc
mip_port_s390: RUN = $(DOCKER) --init mdashnet/s390
mip_port_s390: mip_port_test
arm: DEFS += -DMG_ENABLE_POSIX_FS=0 -DMG_ENABLE_TCPIP=1 -DMG_ENABLE_TCPIP_DRIVER_INIT=0 -DMG_ARCH=MG_ARCH_ARMGCC -DNO_SLEEP_ABORT arm: DEFS += -DMG_ENABLE_POSIX_FS=0 -DMG_ENABLE_TCPIP=1 -DMG_ENABLE_TCPIP_DRIVER_INIT=0 -DMG_ARCH=MG_ARCH_ARMGCC -DNO_SLEEP_ABORT
arm: mongoose.h $(SRCS) arm: mongoose.h $(SRCS)
$(DOCKER) mdashnet/armgcc arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb $(SRCS) $(OPTS) $(WARN) $(INCS) $(DEFS) $(TFLAGS) -o unit_test -nostartfiles --specs nosys.specs -e 0 $(DOCKER) mdashnet/armgcc arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb $(SRCS) $(OPTS) $(WARN) $(INCS) $(DEFS) $(TFLAGS) -o unit_test -nostartfiles --specs nosys.specs -e 0
@@ -194,7 +215,7 @@ riscv: mongoose.h $(SRCS)
vc98: Makefile mongoose.h $(SRCS) vc98: Makefile mongoose.h $(SRCS)
$(DOCKER) mdashnet/vc98 wine cl $(SRCS) $(VCFLAGS) $(DEFS) $(TFLAGS) /Fe$@.exe $(DOCKER) mdashnet/vc98 wine cl $(SRCS) $(VCFLAGS) $(DEFS) $(TFLAGS) /Fe$@.exe
$(DOCKER) mdashnet/vc98 wine $@.exe $(DOCKER) -e WINEPREFIX=/tmp/wineprefix mdashnet/vc98 wine $@.exe
vc17: Makefile mongoose.h $(SRCS) vc17: Makefile mongoose.h $(SRCS)
$(DOCKER) mdashnet/vc17 wine64 cl $(SRCS) $(VCFLAGS) $(DEFS) $(TFLAGS) /Fe$@.exe $(DOCKER) mdashnet/vc17 wine64 cl $(SRCS) $(VCFLAGS) $(DEFS) $(TFLAGS) /Fe$@.exe
@@ -230,11 +251,12 @@ mongoose.c: Makefile $(wildcard ../src/*.c) $(wildcard ../src/drivers/*.c)
cd .. && (export LC_ALL=C ; cat src/license.h; echo; echo '#include "mongoose.h"' ; (for F in src/*.c src/drivers/*.c ; do echo; echo '#ifdef MG_ENABLE_LINES'; echo "#line 1 \"$$F\""; echo '#endif'; cat $$F | sed -e 's,#include ".*,,'; done))> $@ cd .. && (export LC_ALL=C ; cat src/license.h; echo; echo '#include "mongoose.h"' ; (for F in src/*.c src/drivers/*.c ; do echo; echo '#ifdef MG_ENABLE_LINES'; echo "#line 1 \"$$F\""; echo '#endif'; cat $$F | sed -e 's,#include ".*,,'; done))> $@
mongoose.h: $(HDRS) Makefile mongoose.h: $(HDRS) Makefile
cd .. && (cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/arch.h src/arch_*.h src/net_ft.h src/net_lwip.h src/net_rl.h src/config.h src/profile.h src/str.h src/queue.h src/fmt.h src/printf.h src/log.h src/timer.h src/fs.h src/util.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/sha256.h src/event.h src/net.h src/http.h src/ssi.h src/tls.h src/tls_x25519.h src/tls_aes128.h src/tls_uecc.h src/tls_chacha20.h src/tls_rsa.h src/tls_mbed.h src/tls_openssl.h src/ws.h src/sntp.h src/mqtt.h src/dns.h src/json.h src/rpc.h src/ota.h src/flash.h src/wifi.h src/net_builtin.h src/drivers/*.h | sed -e '/keep/! s,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@ cd .. && (cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/arch.h src/arch_*.h src/net_ft.h src/net_lwip.h src/net_rl.h src/config.h src/profile.h src/str.h src/queue.h src/fmt.h src/printf.h src/log.h src/timer.h src/fs.h src/util.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/sha256.h src/event.h src/net.h src/http.h src/ssi.h src/tls.h src/tls_x25519.h src/tls_aes128.h src/tls_uecc.h src/tls_chacha20.h src/tls_rsa.h src/tls_mbed.h src/tls_openssl.h src/ws.h src/sntp.h src/mqtt.h src/dns.h src/json.h src/rpc.h src/ota.h src/flash.h src/wifi.h src/l2.h src/net_builtin.h src/drivers/*.h | sed -e '/keep/! s,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@
clean: clean_tutorials clean_tutorials_embedded clean: clean_tutorials clean_tutorials_embedded
rm -rf $(PROG) *.exe *.o *.dSYM *_test ut fuzzer *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb slow-unit* _CL_* infer-out data.txt crash-* packed_fs.c pack rm -rf $(PROG) *.exe *.o *.dSYM *_test ut fuzzer *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb slow-unit* _CL_* infer-out data.txt crash-* packed_fs.c pack
$(MAKE) -C tls_multirec $@
#find tutorials -maxdepth 3 -name zephyr -prune -o -name Makefile -print | xargs dirname | xargs -n1 make clean -C #find tutorials -maxdepth 3 -name zephyr -prune -o -name Makefile -print | xargs dirname | xargs -n1 make clean -C
-3
View File
@@ -1,6 +1,3 @@
- Make sure your PEM file starts with a dash -
Issuer: C=US, O=Internet Security Research Group, CN=ISRG Root X1 Issuer: C=US, O=Internet Security Research Group, CN=ISRG Root X1
Not Before: Mar 13 00:00:00 2024 GMT Not Before: Mar 13 00:00:00 2024 GMT
Not After : Mar 12 23:59:59 2027 GMT Not After : Mar 12 23:59:59 2027 GMT
-33
View File
@@ -1,33 +0,0 @@
- Make sure your PEM file starts with a dash -
Issuer: C=US, O=Internet Security Research Group, CN=ISRG Root X1
Not Before: Mar 13 00:00:00 2024 GMT
Not After : Mar 12 23:59:59 2027 GMT
-----BEGIN CERTIFICATE-----
MIIEVzCCAj+gAwIBAgIRAIOPbGPOsTmMYgZigxXJ/d4wDQYJKoZIhvcNAQELBQAw
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjQwMzEzMDAwMDAw
WhcNMjcwMzEyMjM1OTU5WjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg
RW5jcnlwdDELMAkGA1UEAxMCRTUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNCzqK
a2GOtu/cX1jnxkJFVKtj9mZhSAouWXW0gQI3ULc/FnncmOyhKJdyIBwsz9V8UiBO
VHhbhBRrwJCuhezAUUE8Wod/Bk3U/mDR+mwt4X2VEIiiCFQPmRpM5uoKrNijgfgw
gfUwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD
ATASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBSfK1/PPCFPnQS37SssxMZw
i9LXDTAfBgNVHSMEGDAWgBR5tFnme7bl5AFzgAiIyBpY9umbbjAyBggrBgEFBQcB
AQQmMCQwIgYIKwYBBQUHMAKGFmh0dHA6Ly94MS5pLmxlbmNyLm9yZy8wEwYDVR0g
BAwwCjAIBgZngQwBAgEwJwYDVR0fBCAwHjAcoBqgGIYWaHR0cDovL3gxLmMubGVu
Y3Iub3JnLzANBgkqhkiG9w0BAQsFAAOCAgEAH3KdNEVCQdqk0LKyuNImTKdRJY1C
2uw2SJajuhqkyGPY8C+zzsufZ+mgnhnq1A2KVQOSykOEnUbx1cy637rBAihx97r+
bcwbZM6sTDIaEriR/PLk6LKs9Be0uoVxgOKDcpG9svD33J+G9Lcfv1K9luDmSTgG
6XNFIN5vfI5gs/lMPyojEMdIzK9blcl2/1vKxO8WGCcjvsQ1nJ/Pwt8LQZBfOFyV
XP8ubAp/au3dc4EKWG9MO5zcx1qT9+NXRGdVWxGvmBFRAajciMfXME1ZuGmk3/GO
koAM7ZkjZmleyokP1LGzmfJcUd9s7eeu1/9/eg5XlXd/55GtYjAM+C4DG5i7eaNq
cm2F+yxYIPt6cbbtYVNJCGfHWqHEQ4FYStUyFnv8sjyqU8ypgZaNJ9aVcWSICLOI
E1/Qv/7oKsnZCWJ926wU6RqG1OYPGOi1zuABhLw61cuPVDT28nQS/e6z95cJXq0e
K1BcaJ6fJZsmbjRgD5p3mvEf5vdQM7MCEvU0tHbsx2I5mHHJoABHb8KVBgWp/lcX
GWiWaeOyB7RP+OfDtvi2OsapxXiV7vNVs7fMlrRjY1joKaqmmycnBvAq14AEbtyL
sVfOS66B8apkeFX2NY4XPEYV4ZSCe8VHPrdrERk2wILG3T/EGmSIkCYVUMSnjmJd
VQD9F6Na/+zmXCc=
-----END CERTIFICATE-----
+32
View File
@@ -0,0 +1,32 @@
1 s:C=US, O=Let's Encrypt, CN=E8
i:C=US, O=Internet Security Research Group, CN=ISRG Root X1
a:PKEY: id-ecPublicKey, 384 (bit); sigalg: RSA-SHA256
v:NotBefore: Mar 13 00:00:00 2024 GMT; NotAfter: Mar 12 23:59:59 2027 GMT
-----BEGIN CERTIFICATE-----
MIIEVjCCAj6gAwIBAgIQY5WTY8JOcIJxWRi/w9ftVjANBgkqhkiG9w0BAQsFADBP
MQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFy
Y2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMTAeFw0yNDAzMTMwMDAwMDBa
Fw0yNzAzMTIyMzU5NTlaMDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBF
bmNyeXB0MQswCQYDVQQDEwJFODB2MBAGByqGSM49AgEGBSuBBAAiA2IABNFl8l7c
S7QMApzSsvru6WyrOq44ofTUOTIzxULUzDMMNMchIJBwXOhiLxxxs0LXeb5GDcHb
R6EToMffgSZjO9SNHfY9gjMy9vQr5/WWOrQTZxh7az6NSNnq3u2ubT6HTKOB+DCB
9TAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMB
MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFI8NE6L2Ln7RUGwzGDhdWY4j
cpHKMB8GA1UdIwQYMBaAFHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEB
BCYwJDAiBggrBgEFBQcwAoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzATBgNVHSAE
DDAKMAgGBmeBDAECATAnBgNVHR8EIDAeMBygGqAYhhZodHRwOi8veDEuYy5sZW5j
ci5vcmcvMA0GCSqGSIb3DQEBCwUAA4ICAQBnE0hGINKsCYWi0Xx1ygxD5qihEjZ0
RI3tTZz1wuATH3ZwYPIp97kWEayanD1j0cDhIYzy4CkDo2jB8D5t0a6zZWzlr98d
AQFNh8uKJkIHdLShy+nUyeZxc5bNeMp1Lu0gSzE4McqfmNMvIpeiwWSYO9w82Ob8
otvXcO2JUYi3svHIWRm3+707DUbL51XMcY2iZdlCq4Wa9nbuk3WTU4gr6LY8MzVA
aDQG2+4U3eJ6qUF10bBnR1uuVyDYs9RhrwucRVnfuDj29CMLTsplM5f5wSV5hUpm
Uwp/vV7M4w4aGunt74koX71n4EdagCsL/Yk5+mAQU0+tue0JOfAV/R6t1k+Xk9s2
HMQFeoxppfzAVC04FdG9M+AC2JWxmFSt6BCuh3CEey3fE52Qrj9YM75rtvIjsm/1
Hl+u//Wqxnu1ZQ4jpa+VpuZiGOlWrqSP9eogdOhCGisnyewWJwRQOqK16wiGyZeR
xs/Bekw65vwSIaVkBruPiTfMOo0Zh4gVa8/qJgMbJbyrwwG97z/PRgmLKCDl8z3d
tA0Z7qq7fta0Gl24uyuB05dqI5J1LvAzKuWdIjT1tP8qCoxSE/xpix8hX2dt3h+/
jujUgFPFZ0EVZ0xSyBNRF3MboGZnYXFUxpNjTWPKpagDHJQmqrAcDmWJnMsFY3jS
u1igv3OefnWjSQ==
-----END CERTIFICATE-----
-2
View File
@@ -1,5 +1,3 @@
- Make sure your PEM file starts with a dash -
Certificate: Certificate:
Data: Data:
Version: 3 (0x2) Version: 3 (0x2)
-2
View File
@@ -1,5 +1,3 @@
- Make sure your PEM file starts with a dash -
Certificate: Certificate:
Data: Data:
Version: 3 (0x2) Version: 3 (0x2)
-2
View File
@@ -1,5 +1,3 @@
- Make sure your PEM file starts with a dash -
Certificate: Certificate:
Data: Data:
Version: 3 (0x2) Version: 3 (0x2)
+51 -17
View File
@@ -62,6 +62,14 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
mg_crc32(0, mm.topic.buf, mm.topic.len); mg_crc32(0, mm.topic.buf, mm.topic.len);
mg_crc32(0, mm.data.buf, mm.data.len); mg_crc32(0, mm.data.buf, mm.data.len);
mg_crc32(0, mm.dgram.buf, mm.dgram.len); mg_crc32(0, mm.dgram.buf, mm.dgram.len);
{
struct mg_mqtt_prop prop;
size_t ofs = 0;
while ((ofs = mg_mqtt_next_prop(&mm, &prop, ofs)) > 0) {
mg_crc32(0, prop.key.buf, prop.key.len);
mg_crc32(0, prop.val.buf, prop.val.len);
}
}
} }
mg_mqtt_parse(NULL, 0, 5, &mm); mg_mqtt_parse(NULL, 0, 5, &mm);
@@ -86,9 +94,19 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
// Test built-in TCP/IP stack // Test built-in TCP/IP stack
if (size > 0) { if (size > 0) {
struct mg_tcpip_if mif = {.ip = 0x01020304, struct mg_tcpip_if mif = {.ip = 1,
.mask = 255, .mask = 255,
.gw = 0x01010101, .gw = 1,
.gw_ready = true,
.state = MG_TCPIP_STATE_READY,
#if MG_ENABLE_IPV6
.ip6[0] = 1;
.prefix[0] = 1;
.prefix_len = 64;
.gw6[0] = 1;
.gw6_ready = true;
.state6 = MG_TCPIP_STATE_READY; // so mg_send() works and RS stops
#endif
.driver = &mg_tcpip_driver_mock}; .driver = &mg_tcpip_driver_mock};
struct mg_mgr mgr; struct mg_mgr mgr;
mg_mgr_init(&mgr); mg_mgr_init(&mgr);
@@ -100,45 +118,61 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
memcpy(pkt, data, size); memcpy(pkt, data, size);
if (size > sizeof(*eth)) { if (size > sizeof(*eth)) {
static size_t i; static size_t i;
uint16_t eth_types[] = {0x800, 0x806, 0x86dd}; // IPv4, ARP, IPv6 // eth_types[] exists in l2_eth.c
memcpy(eth->dst, mif.mac, 6); // Set valid destination MAC memcpy(eth->dst, mif.mac, 6); // Set valid destination MAC
// send all handled eth types, then 2 random ones // send all handled eth types, then 2 random ones
if (i >= (sizeof(eth_types) / sizeof(eth_types[0]) + 2)) i = 0; if (i >= (sizeof(eth_types) / sizeof(eth_types[0]) + 2)) i = 0;
if (i < (sizeof(eth_types) / sizeof(eth_types[0]))) eth->type = (eth_types[i++]); if (i < (sizeof(eth_types) / sizeof(eth_types[0]))) eth->type = mg_htons(eth_types[i++]);
// build proper layer-3 datagrams, to be able to exercise layers above // build proper layer-3 datagrams, to be able to exercise layers above
if (eth->type == mg_htons(0x800) && size > (sizeof(*eth) + sizeof(struct ip))) { // IPv4 if (eth->type == mg_htons(0x800) && size > (sizeof(*eth) + sizeof(struct ip))) { // IPv4
static size_t j; static size_t j;
uint8_t ip_protos[] = {1, 6, 17}; // ICMP, TCP, UDP uint8_t ip_protos[] = {1, 6, 17}; // ICMP, TCP, UDP
struct ip *ip4 = (struct ip *) (eth + 1); struct ip *ip4 = (struct ip *) (eth + 1);
ip4->ver = (ip4->ver & ~0xf0) | (4 << 4); ip4->ver = (ip4->ver & ~0xf0) | (4 << 4);
// send all handled ip protos, then 2 random ones // send all handled IP protos, then 2 random ones
if (j >= (sizeof(ip_protos) / sizeof(ip_protos[0]) + 2)) j = 0; if (j >= (sizeof(ip_protos) / sizeof(ip_protos[0]) + 2)) j = 0;
if (j < (sizeof(ip_protos) / sizeof(ip_protos[0]))) ip4->proto = (ip_protos[j++]); if (j < (sizeof(ip_protos) / sizeof(ip_protos[0]))) ip4->proto = (ip_protos[j++]);
if (ip4->proto == 1) { // ICMP if (ip4->proto == 1) { // ICMP
} else if (ip4->proto == 6) { // TCP } else if (ip4->proto == 6) { // TCP
} else if (ip4->proto == 17 && size > (sizeof(*eth) + sizeof(struct ip) + sizeof(struct udp))) { // UDP } else if (ip4->proto == 17) { // UDP
static size_t k; if (size > (sizeof(*eth) + sizeof(struct ip) + sizeof(struct udp))) {
uint16_t udp_ports[] = {67, 68}; // DHCP server and client static size_t k;
struct udp *udp = (struct udp *) (ip4 + 1); uint16_t udp_ports[] = {67, 68}; // DHCP server and client
// send all handled udp ports, then 2 random ones struct udp *udp = (struct udp *) (ip4 + 1);
if (k >= (sizeof(udp_ports) / sizeof(udp_ports[0]) + 2)) k = 0; // send all handled UDP ports, then 2 random ones
if (k < (sizeof(udp_ports) / sizeof(udp_ports[0]))) udp->dport = mg_htons(udp_ports[k++]); if (k >= (sizeof(udp_ports) / sizeof(udp_ports[0]) + 2)) k = 0;
if (k < (sizeof(udp_ports) / sizeof(udp_ports[0]))) udp->dport = mg_htons(udp_ports[k++]);
}
} }
} else if (eth->type == mg_htons(0x806)) { // ARP } else if (eth->type == mg_htons(0x806)) { // ARP
} else if (eth->type == mg_htons(0x86dd) && size > (sizeof(*eth) + sizeof(struct ip6))) { // IPv6 } else if (eth->type == mg_htons(0x86dd) && size > (sizeof(*eth) + sizeof(struct ip6))) { // IPv6
static size_t j; static size_t j;
uint8_t ip6_protos[] = {6, 17}; // TCP, UDP uint8_t ip6_protos[] = {6, 17, 58}; // TCP, UDP, ICMPv6
struct ip6 *ip6 = (struct ip6 *) (eth + 1); struct ip6 *ip6 = (struct ip6 *) (eth + 1);
ip6->ver = (ip6->ver & ~0xf0) | (6 << 4); ip6->ver = (ip6->ver & ~0xf0) | (6 << 4);
// send all handled ip6 "next headers", then 2 random ones // send all handled IPv6 "next headers", then 2 random ones
if (j >= (sizeof(ip6_protos) / sizeof(ip6_protos[0]) + 2)) j = 0; if (j >= (sizeof(ip6_protos) / sizeof(ip6_protos[0]) + 2)) j = 0;
if (j < (sizeof(ip6_protos) / sizeof(ip6_protos[0]))) ip6->proto = (ip6_protos[j++]); if (j < (sizeof(ip6_protos) / sizeof(ip6_protos[0]))) ip6->next = (ip6_protos[j++]);
if (ip6->proto == 6) { // TCP if (ip6->next == 6) { // TCP
} else if (ip6->proto == 17) { // UDP } else if (ip6->next == 17) { // UDP
} else if (ip6->next == 58) { // ICMPv6
if (size >= (sizeof(*eth) + sizeof(struct ip6) + sizeof(struct icmp6))) {
static size_t k;
uint8_t icmp6_types[] = {128, 134, 135, 136}; // Echo Request, RA, NS, NA
struct icmp6 *icmp6 = (struct icmp6 *) (ip6 + 1);
// send all handled ICMPv6 types, then 2 random ones
if (k >= (sizeof(icmp6_types) / sizeof(icmp6_types[0]) + 2)) k = 0;
if (k < (sizeof(icmp6_types) / sizeof(icmp6_types[0]))) icmp6->type = icmp6_types[k++];
}
} }
} }
} }
#if defined(MAIN)
printf("Sending to net_builtin:\n");
mg_hexdump(pkt, size);
#endif
mg_tcpip_rx(&mif, pkt, size); mg_tcpip_rx(&mif, pkt, size);
// Test HTTP serving (via our built-in TCP/IP stack) // Test HTTP serving (via our built-in TCP/IP stack)
+28 -6
View File
@@ -18,10 +18,11 @@ int LLVMFuzzerTestOneInput(const uint8_t *, size_t);
// Preprocessor magic, just add/remove functions here and leave the rest alone // Preprocessor magic, just add/remove functions here and leave the rest alone
#define TABLE(_) \ #define TABLE(_) \
_(mg_tls_server_recv_hello) \ _(mg_tls_server_recv_hello) \
//_(mg_tls_client_recv_hello) \ _(mg_tls_server_recv_finish) \
//_(mg_tls_client_recv_ext ) \ _(mg_tls_client_recv_hello) \
//_(mg_tls_client_recv_cert) \ _(mg_tls_client_recv_finish) \
//_(mg_tls_client_recv_cert_verify) \ _(mg_tls_client_recv_ext) \
_(mg_tls_recv_cert_verify) \
// ... // ...
struct f { struct f {
@@ -52,7 +53,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
c = &c_[i]; c = &c_[i];
io = &c->rtls; io = &c->rtls;
if (i > 0) memcpy(c, &c_[0], sizeof(*c)); // copy from 1st one if (i > 0) memcpy(c, &c_[0], sizeof(*c)); // copy from 1st one
if (i > 0) c->is_client = 1; // from 1 on, client functions if (i > 1) c->is_client = 1; // from 2 on, client functions
memset(&tls_[i], 0, sizeof(struct tls_data)); memset(&tls_[i], 0, sizeof(struct tls_data));
if (io->size - io->len < size && !mg_iobuf_resize(io, io->len + size)) { if (io->size - io->len < size && !mg_iobuf_resize(io, io->len + size)) {
mg_error(c, "oom"); mg_error(c, "oom");
@@ -64,7 +65,28 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
#ifdef PRINT_FUNCNAME #ifdef PRINT_FUNCNAME
printf("CALLING %s\n", f_[i].name); printf("CALLING %s\n", f_[i].name);
#endif #endif
f_[i].f(&c[i]); f_[i].f(c);
mg_iobuf_free(io);
}
// mg_tls_recv_cert() has an extra bool parameter
c = &c_[0]; // reuse first one
c->tls = &tls_[0];
for (i = 0; i < 2; i++) {
struct mg_iobuf *io;
io = &c->rtls;
c->is_client = (i > 0);
memset(c->tls, 0, sizeof(struct tls_data));
if (io->size - io->len < size && !mg_iobuf_resize(io, io->len + size)) {
mg_error(c, "oom");
return 0; // drop it
}
memcpy(&io->buf[io->len], data, size);
io->len += size;
#ifdef PRINT_FUNCNAME
printf("CALLING mg_tls_recv_cert\n");
#endif
mg_tls_recv_cert(c, !c->is_client); // call server for client and client for server
mg_iobuf_free(io); mg_iobuf_free(io);
} }
+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/env -S gawk -f
# gawk used to avoid "towc" errors seen on MacOS. env used to circumvent brew installing it wherever they like
BEGIN {
FS="\t"
print "{"
}
/HEALTH_DASHBOARD/ { print $2 }
END {
print "}"
}
Executable
+5
View File
@@ -0,0 +1,5 @@
#!/bin/bash
cd /data/downloads/health
find . -mtime +28 -not -name 'index*.json' -delete
find . -name "*.json" -not -name 'index*.json' | jq -R . | jq -s . > index.json
+120
View File
@@ -0,0 +1,120 @@
#define MIPPORTTEST_USING_DHCP 1
#include <sys/socket.h>
#include <sys/ioctl.h>
#include "mip_x_test.c"
struct port_driver_data {
int sockfd;
struct sockaddr_in port_addr;
struct sockaddr_in tap_addr;
};
// MIP Socket driver
static size_t sock_rx(void *buf, size_t len, struct mg_tcpip_if *ifp) {
ssize_t received = recv(((struct port_driver_data *)ifp->driver_data)->sockfd, buf, len, 0);
usleep(1); // This is to avoid 100% CPU
if (received < 0) return 0;
return (size_t) received;
}
static size_t sock_tx(const void *buf, size_t len, struct mg_tcpip_if *ifp) {
ssize_t res = send(((struct port_driver_data *)ifp->driver_data)->sockfd, buf, len, 0);
if (res < 0) {
MG_ERROR(("sock_tx failed: %d", errno));
return 0;
}
return (size_t) res;
}
static bool sock_poll(struct mg_tcpip_if *ifp, bool s1) {
return s1 && ifp->driver_data ? true : false;
}
int main(void) {
bool result;
const char *debug_level = getenv("V");
// Setup interface
const uint16_t port = 0xAA55; // UDP port
const uint16_t tap_port = 0x55AA; // UDP port for TAP socket
const char *mac = "02:00:01:02:03:78"; // MAC address
struct port_driver_data pdd;
pdd.sockfd = socket(AF_INET, SOCK_DGRAM, 0);
pdd.port_addr.sin_family = AF_INET;
pdd.port_addr.sin_addr.s_addr = htonl(INADDR_ANY);
pdd.port_addr.sin_port = htons(port);
if (bind(pdd.sockfd, (struct sockaddr *) &pdd.port_addr, sizeof(pdd.port_addr)) < 0) return EXIT_FAILURE;
printf("Opened UDP socket: 127.0.0.1:%u (0x%04x)\n", port, port);
pdd.tap_addr.sin_family = AF_INET;
pdd.tap_addr.sin_addr.s_addr = htonl(0x7f000001U); // 127.0.0.1
pdd.tap_addr.sin_port = htons(0x55AA);
if (connect(pdd.sockfd, (struct sockaddr *) &pdd.tap_addr, sizeof(pdd.tap_addr)) < 0) return EXIT_FAILURE;
printf("Connected to TAP UDP socket: 127.0.0.1:%u (0x%04x)\n", tap_port, tap_port);
usleep(200000); // 200 ms
if (debug_level == NULL) debug_level = "3";
mg_log_set(atoi(debug_level));
struct mg_mgr mgr; // Event manager
mg_mgr_init(&mgr); // Initialise event manager
// MIP driver
struct mg_tcpip_driver driver;
memset(&driver, 0, sizeof(driver));
driver.tx = sock_tx;
driver.poll = sock_poll;
driver.rx = sock_rx;
struct mg_tcpip_if mif;
memset(&mif, 0, sizeof(mif));
mif.driver = &driver;
mif.driver_data = &pdd;
#if MIPPORTTEST_USING_DHCP == 1
#else
mif.ip = mg_htonl(MG_U32(192, 168, 32, 2)); // Triggering a network failure
mif.mask = mg_htonl(MG_U32(255, 255, 255, 0));
mif.gw = mg_htonl(MG_U32(192, 168, 32, 1));
#endif
sscanf(mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mif.mac[0], &mif.mac[1],
&mif.mac[2], &mif.mac[3], &mif.mac[4], &mif.mac[5]);
mg_tcpip_init(&mgr, &mif);
MG_INFO(("Init done, starting main loop"));
usleep(200000); // 200 ms
// Stack initialization, Network configuration (DHCP lease, ...)
#if MIPPORTTEST_USING_DHCP == 0
MG_INFO(("MIF configuration: Static IP"));
ASSERT(mif.ip != 0); // Check we have a satic IP assigned
mg_mgr_poll(&mgr, 100); // For initialisation
#else
MG_INFO(("MIF configuration: DHCP"));
ASSERT(!mif.ip); // Check we are set for DHCP
int pc = 500; // Timeout on DHCP lease 500 ~ approx 5s (typical delay <1s)
while (((pc--) > 0) && !mif.ip) {
mg_mgr_poll(&mgr, 100);
usleep(10000); // 10 ms
}
if (!mif.ip) MG_ERROR(("No ip assigned (DHCP lease may have failed).\n"));
ASSERT(mif.ip); // We have an IP (lease or static)
#endif
while (mif.state != MG_TCPIP_STATE_READY) {
mg_mgr_poll(&mgr, 100);
usleep(10000); // 10 ms
}
// RUN TESTS
result = mip_x_test(&mgr);
close(pdd.sockfd);
if (!result) return EXIT_FAILURE;
return EXIT_SUCCESS;
}
+5 -425
View File
@@ -1,10 +1,5 @@
#define MG_ENABLE_TCPIP 1
#define MG_ENABLE_TCPIP_DRIVER_INIT 0
#define MIPTAPTEST_USING_DHCP 1 #define MIPTAPTEST_USING_DHCP 1
#define FETCH_BUF_SIZE (16 * 1024)
#include <sys/socket.h> #include <sys/socket.h>
#ifndef __OpenBSD__ #ifndef __OpenBSD__
#include <linux/if.h> #include <linux/if.h>
@@ -16,105 +11,8 @@
#endif #endif
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include "mongoose.c" #include "mip_x_test.c"
#include "driver_mock.c"
#ifdef MQTT_LOCALHOST
#define MQTT_URL "mqtt://127.0.0.1:1883"
#else
#define MQTT_URL "mqtt://broker.hivemq.com:1883"
#endif
#if MG_TLS == MG_TLS_BUILTIN
#define MQTTS_URL "mqtts://mongoose.ws:8883" // test requires TLS 1.3
#define MQTTS_CA mg_str(s_ca_cert)
static const char *s_ca_cert =
"-----BEGIN CERTIFICATE-----\n"
"MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw\n"
"TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\n"
"cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4\n"
"WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu\n"
"ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY\n"
"MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc\n"
"h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+\n"
"0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U\n"
"A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW\n"
"T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH\n"
"B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC\n"
"B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv\n"
"KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn\n"
"OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn\n"
"jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw\n"
"qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI\n"
"rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\n"
"HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq\n"
"hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL\n"
"ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ\n"
"3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK\n"
"NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5\n"
"ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur\n"
"TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC\n"
"jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc\n"
"oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq\n"
"4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA\n"
"mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d\n"
"emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=\n"
"-----END CERTIFICATE-----\n";
#elif MG_TLS
#ifdef MQTT_LOCALHOST
// we'll generate MQTTS_URL
#define MQTTS_CA mg_str(s_ca_cert)
static const char *s_ca_cert =
"-----BEGIN CERTIFICATE-----\n"
"MIIBFTCBvAIJAMNTFtpfcq8NMAoGCCqGSM49BAMCMBMxETAPBgNVBAMMCE1vbmdv\n"
"b3NlMB4XDTI0MDUwNzE0MzczNloXDTM0MDUwNTE0MzczNlowEzERMA8GA1UEAwwI\n"
"TW9uZ29vc2UwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASuP+86T/rOWnGpEVhl\n"
"fxYZ+pjMbCmDZ+vdnP0rjoxudwRMRQCv5slRlDK7Lxue761sdvqxWr0Ma6TFGTNg\n"
"epsRMAoGCCqGSM49BAMCA0gAMEUCIQCwb2CxuAKm51s81S6BIoy1IcandXSohnqs\n"
"us64BAA7QgIgGGtUrpkgFSS0oPBlCUG6YPHFVw42vTfpTC0ySwAS0M4=\n"
"-----END CERTIFICATE-----\n";
#else
#define MQTTS_URL "mqtts://broker.hivemq.com:8883"
#define MQTTS_CA mg_unpacked("/data/ca.pem")
#endif // MQTT_LOCALHOST
#endif
static char *host_ip;
static int s_num_tests = 0;
#ifdef NO_SLEEP_ABORT
#define ABORT() abort()
#else
#define ABORT() \
sleep(2); /* 2s, GH print reason */ \
abort();
#endif
#define ASSERT(expr) \
do { \
s_num_tests++; \
if (!(expr)) { \
printf("FAILURE %s:%d: %s\n", __FILE__, __LINE__, #expr); \
fflush(stdout); \
ABORT(); \
} \
} while (0)
static struct mg_http_message gethm(const char *buf) {
struct mg_http_message hm;
memset(&hm, 0, sizeof(hm));
mg_http_parse(buf, strlen(buf), &hm);
return hm;
}
static int cmpbody(const char *buf, const char *str) {
struct mg_str s = mg_str(str);
struct mg_http_message hm = gethm(buf);
size_t len = strlen(buf);
if (hm.body.len > len) hm.body.len = len - (size_t) (hm.body.buf - buf);
return mg_strcmp(hm.body, s);
}
// MIP TUNTAP driver // MIP TUNTAP driver
static size_t tap_rx(void *buf, size_t len, struct mg_tcpip_if *ifp) { static size_t tap_rx(void *buf, size_t len, struct mg_tcpip_if *ifp) {
@@ -137,311 +35,9 @@ static bool tap_poll(struct mg_tcpip_if *ifp, bool s1) {
return s1 && ifp->driver_data ? true : false; return s1 && ifp->driver_data ? true : false;
} }
static void eh1(struct mg_connection *c, int ev, void *ev_data) {
struct mg_tls_opts *topts = (struct mg_tls_opts *) c->fn_data;
if (ev == MG_EV_ACCEPT && topts != NULL) mg_tls_init(c, topts);
if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
MG_DEBUG(("[%.*s %.*s] message len %d", (int) hm->method.len,
hm->method.buf, (int) hm->uri.len, hm->uri.buf,
(int) hm->message.len));
if (mg_match(hm->uri, mg_str("/foo/*"), NULL)) {
mg_http_reply(c, 200, "", "uri: %.*s", hm->uri.len - 5, hm->uri.buf + 5);
} else if (mg_match(hm->uri, mg_str("/ws"), NULL)) {
mg_ws_upgrade(c, hm, NULL);
} else if (mg_match(hm->uri, mg_str("/body"), NULL)) {
mg_http_reply(c, 200, "", "%.*s", (int) hm->body.len, hm->body.buf);
} else {
struct mg_http_serve_opts sopts;
memset(&sopts, 0, sizeof(sopts));
sopts.root_dir = "./data";
mg_http_serve_dir(c, hm, &sopts);
}
} else if (ev == MG_EV_WS_OPEN) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
ASSERT(mg_strcmp(hm->uri, mg_str("/ws")) == 0);
mg_ws_send(c, "opened", 6, WEBSOCKET_OP_BINARY);
} else if (ev == MG_EV_WS_MSG) {
struct mg_ws_message *wm = (struct mg_ws_message *) ev_data;
mg_ws_send(c, wm->data.buf, wm->data.len, WEBSOCKET_OP_BINARY);
}
}
struct fetch_data {
char *buf;
const char *url;
int code, closed;
};
static void fcb(struct mg_connection *c, int ev, void *ev_data) {
struct fetch_data *fd = (struct fetch_data *) c->fn_data;
if (ev == MG_EV_CONNECT) {
MG_DEBUG(("CONNECT"));
if (mg_url_is_ssl(fd->url)) {
struct mg_tls_opts opts;
memset(&opts, 0, sizeof(opts)); // read CA from packed_fs
if (host_ip != NULL && strstr(fd->url, host_ip) != NULL) {
MG_DEBUG(("Local connection, using self-signed certificates"));
opts.name = mg_str_s("localhost");
opts.ca = mg_unpacked("/certs/ca.crt");
} else {
opts.name = mg_url_host(fd->url);
opts.ca = mg_unpacked("/data/ca.pem");
#if MG_TLS == MG_TLS_BUILTIN
// our TLS does not search for the proper CA in a bundle
opts.ca = mg_file_read(&mg_fs_posix, "data/e5.crt");
#endif
}
mg_tls_init(c, &opts);
#if MG_TLS == MG_TLS_BUILTIN
mg_free((void *) opts.ca.buf);
#endif
}
} else if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
snprintf(fd->buf, FETCH_BUF_SIZE, "%.*s", (int) hm->message.len,
hm->message.buf);
fd->code = atoi(hm->uri.buf);
fd->closed = 1;
c->is_closing = 1;
MG_DEBUG(("CODE: %d, MSG: %.*s", fd->code, (int) hm->message.len,
hm->message.buf));
(void) c;
} else if (ev == MG_EV_CLOSE) {
MG_DEBUG(("CLOSE"));
fd->closed = 1;
} else if (ev == MG_EV_READ) {
long bytes = *(long *) ev_data;
MG_DEBUG(("READ %d: %.*s", (int) bytes, (int) bytes, c->recv.buf));
}
}
static int fetch(struct mg_mgr *mgr, char *buf, const char *url,
const char *fmt, ...) {
struct fetch_data fd = {buf, url, 0, 0};
int i;
struct mg_connection *c = NULL;
va_list ap;
mg_mgr_poll(mgr, 0); // update ifp->now to avoid ARP lookup using an old
// timestamp (from an ancient call in other test)
c = mg_http_connect(mgr, url, fcb, &fd);
ASSERT(c != NULL);
va_start(ap, fmt);
mg_vprintf(c, fmt, &ap);
va_end(ap);
buf[0] = '\0';
// - TLS: multiple (small) records: allow enough loops so mg_mgr_poll can
// process buffered records when no more frames are coming in
for (i = 0; i < 500 && buf[0] == '\0' && !fd.closed; i++) {
mg_mgr_poll(mgr, 0);
usleep(5000); // 5 ms. Slow down poll loop to ensure packet transit, but
// allow enough loops to get the ARP response, otherwise,
// given enough traffic, the timer expires before we get a
// chance to see the response
}
if (!fd.closed) c->is_closing = 1;
mg_mgr_poll(mgr, 0);
return fd.code;
}
static void test_http_client(struct mg_mgr *mgr) {
char buf[FETCH_BUF_SIZE];
int rc = 0;
const bool ipv6 = 0;
#if MG_TLS
if (ipv6) {
rc = fetch(mgr, buf, "https://ipv6.google.com",
"GET / HTTP/1.0\r\nHost: ipv6.google.com\r\n\r\n");
} else {
rc = fetch(mgr, buf, "https://cesanta.com",
"GET /robots.txt HTTP/1.0\r\nHost: cesanta.com\r\n\r\n");
}
ASSERT(rc == 200); // OK
#else
if (ipv6) {
rc = fetch(mgr, buf, "http://ipv6.google.com",
"GET / HTTP/1.0\r\nHost: ipv6.google.com\r\n\r\n");
} else {
rc = fetch(mgr, buf, "http://cesanta.com",
"GET /robots.txt HTTP/1.0\r\nHost: cesanta.com\r\n\r\n");
}
ASSERT(rc == 301); // OK: Permanently moved (HTTP->HTTPS redirect)
#endif
}
static struct mg_connection *s_conn;
static char s_topic[16];
struct mqtt_data {
char *url;
bool passed;
};
static void mqtt_fn(struct mg_connection *c, int ev, void *ev_data) {
struct mqtt_data *data = (struct mqtt_data *) c->fn_data;
if (ev == MG_EV_CONNECT) {
MG_DEBUG(("CONNECT"));
#if MG_TLS
struct mg_tls_opts opts;
memset(&opts, 0, sizeof(opts));
opts.ca = MQTTS_CA;
opts.name = mg_url_host(data->url);
mg_tls_init(c, &opts);
#endif
} else if (ev == MG_EV_MQTT_OPEN) {
MG_DEBUG(("MQTT CONNECT"));
struct mg_mqtt_opts sub_opts;
memset(&sub_opts, 0, sizeof(sub_opts));
sub_opts.topic = mg_str(mg_random_str(s_topic, sizeof(s_topic)));
sub_opts.qos = 1;
mg_mqtt_sub(c, &sub_opts);
struct mg_mqtt_opts pub_opts;
memset(&pub_opts, 0, sizeof(pub_opts));
pub_opts.topic = sub_opts.topic;
pub_opts.message = mg_str("hi");
pub_opts.qos = 1, pub_opts.retain = false;
mg_mqtt_pub(c, &pub_opts);
} else if (ev == MG_EV_MQTT_MSG) {
struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
MG_DEBUG(("TOPIC: %.*s, MSG: %.*s", (int) mm->topic.len, mm->topic.buf,
mm->data.len > 10 ? 10 : (int) mm->data.len, mm->data.buf));
ASSERT(mm->topic.len == strlen(s_topic) &&
strncmp(mm->topic.buf, s_topic, mm->topic.len) == 0);
if (mm->data.len == 2 && strncmp(mm->data.buf, "hi", 2) == 0) {
struct mg_mqtt_opts pub_opts;
memset(&pub_opts, 0, sizeof(pub_opts));
pub_opts.topic = mm->topic;
// send more than 1 record, content is not relevant
pub_opts.message = mg_str_n((char *)(size_t) mqtt_fn, 21098);
pub_opts.qos = 1, pub_opts.retain = false;
mg_mqtt_pub(c, &pub_opts);
} else if (mm->data.len == 8 && strncmp(mm->data.buf, "farewell", 8) == 0) {
// close on farewell
MG_INFO(("%lu CLOSING", c->id));
mg_mqtt_disconnect(c, NULL);
data->passed = true;
} else if (mm->data.len == 21098) {
struct mg_mqtt_opts pub_opts;
ASSERT(memcmp((const char *) (size_t) mqtt_fn, mm->data.buf, 21098) == 0);
// send farewell after receiving big data
memset(&pub_opts, 0, sizeof(pub_opts));
pub_opts.topic = mm->topic;
pub_opts.message = mg_str("farewell");
pub_opts.qos = 1, pub_opts.retain = false;
mg_mqtt_pub(c, &pub_opts);
}
} else if (ev == MG_EV_CLOSE) {
MG_DEBUG(("CLOSE"));
s_conn = NULL;
} else if (ev == MG_EV_ERROR) {
MG_ERROR(("%lu ERROR %s", c->id, (char *) ev_data));
}
}
static void test_mqtt_connsubpub(struct mg_mgr *mgr) {
struct mqtt_data data;
struct mg_mqtt_opts opts;
memset(&opts, 0, sizeof(opts));
opts.clean = true, opts.version = 4;
data.passed = false;
#if defined(MQTT_LOCALHOST) && MG_TLS != MG_TLS_BUILTIN
if (host_ip == NULL) {
printf("\nMQTT_LOCALHOST defined but no HOST_IP provided, skipping MQTTS tests\n");
return;
}
printf("HOST_IP: %s\n", host_ip);
#endif
#if MG_TLS
#if defined(MQTT_LOCALHOST) && MG_TLS != MG_TLS_BUILTIN
data.url = mg_mprintf("mqtts://%s:8883", host_ip);
#else
data.url = strdup(MQTTS_URL);
#endif
#else
#ifdef MQTT_LOCALHOST
data.url = mg_mprintf("mqtt://%s:1883", host_ip);
#else
data.url = strdup(MQTT_URL);
#endif
#endif
s_conn = mg_mqtt_connect(mgr, data.url, &opts, mqtt_fn, &data);
ASSERT(s_conn != NULL);
for (int i = 0; i < 1000 && s_conn != NULL && !s_conn->is_closing; i++) {
mg_mgr_poll(mgr, 0);
usleep(10000); // 10 ms. Slow down poll loop to ensure packets transit
}
ASSERT(data.passed);
mg_mgr_poll(mgr, 0);
free(data.url);
}
#include <pthread.h>
static void *poll_thread(void *p) {
struct mg_mgr *mgr = (struct mg_mgr *) p;
int i;
for (i = 0; i < 300; i++) {
mg_mgr_poll(mgr, 0);
usleep(10000); // 10 ms. Slow down poll loop to ensure packet transit
}
return NULL;
}
static void test_http_server(struct mg_mgr *mgr) {
struct mg_connection *c;
char *cmd;
pthread_t thread_id = (pthread_t) 0;
#if MG_TLS
struct mg_tls_opts opts;
memset(&opts, 0, sizeof(opts));
// opts.ca = mg_str(s_tls_ca);
opts.cert = mg_unpacked("/certs/server.crt");
opts.key = mg_unpacked("/certs/server.key");
c = mg_http_listen(mgr, "https://0.0.0.0:12347", eh1, &opts);
cmd = mg_mprintf("./mip_curl.sh --insecure https://%M:12347", mg_print_ip4,
&mgr->ifp->ip);
#else
c = mg_http_listen(mgr, "http://0.0.0.0:12347", eh1, NULL);
cmd =
mg_mprintf("./mip_curl.sh http://%M:12347", mg_print_ip4, &mgr->ifp->ip);
#endif
ASSERT(c != NULL);
pthread_create(&thread_id, NULL, poll_thread,
mgr); // simpler this way, no concurrency anyway
MG_DEBUG(("CURL"));
ASSERT(system(cmd) == 0); // wait for curl
MG_DEBUG(("MONGOOSE"));
pthread_join(thread_id, NULL); // wait for Mongoose
MG_DEBUG(("DONE"));
free(cmd);
}
static void test_tls(struct mg_mgr *mgr) {
#if MG_TLS
char *url;
char buf[FETCH_BUF_SIZE]; // make sure it can hold Makefile
struct mg_str data = mg_unpacked("/Makefile");
if (host_ip == NULL) {
printf("\nNo HOST_IP provided, skipping TLS tests\n");
return;
}
printf("HOST_IP: %s\n", host_ip);
// - POST a large file, make sure we drain TLS buffers and read all: done at
// server test, using curl as POSTing client
// - Fire patched server, test multiple TLS records per TCP segment handling
url = mg_mprintf("https://%s:8443", host_ip); // for historic reasons
ASSERT(system("tls_multirec/server -d tls_multirec &") == 0);
sleep(1);
ASSERT(fetch(mgr, buf, url, "GET /thefile HTTP/1.0\n\n") == 200);
ASSERT(cmpbody(buf, data.buf) == 0); // "thefile" links to Makefile
ASSERT(system("killall tls_multirec/server") == 0);
free(url);
#else
(void) cmpbody("", "");
(void) mgr;
#endif
}
int main(void) { int main(void) {
bool result;
const char *debug_level = getenv("V"); const char *debug_level = getenv("V");
// Setup interface // Setup interface
const char *iface = "tap0"; // Network iface const char *iface = "tap0"; // Network iface
@@ -476,9 +72,6 @@ int main(void) {
if (debug_level == NULL) debug_level = "3"; if (debug_level == NULL) debug_level = "3";
mg_log_set(atoi(debug_level)); mg_log_set(atoi(debug_level));
host_ip = getenv("HOST_IP");
// Events
struct mg_mgr mgr; // Event manager struct mg_mgr mgr; // Event manager
mg_mgr_init(&mgr); // Initialise event manager mg_mgr_init(&mgr); // Initialise event manager
@@ -532,21 +125,8 @@ int main(void) {
} }
// RUN TESTS // RUN TESTS
usleep(500000); // 500 ms result = mip_x_test(&mgr);
test_http_client(&mgr);
usleep(500000); // 500 ms
test_http_server(&mgr);
usleep(500000); // 500 ms
test_tls(&mgr);
usleep(500000); // 500 ms
test_mqtt_connsubpub(&mgr);
usleep(500000); // 500 ms
printf("SUCCESS. Total tests: %d\n", s_num_tests);
// Clear
mg_mgr_free(&mgr);
ASSERT(mgr.conns == NULL); // Deconstruction OK
close(fd); close(fd);
return 0; if (!result) return EXIT_FAILURE;
return EXIT_SUCCESS;
} }
+1074 -95
View File
File diff suppressed because it is too large. Load diff
+468
View File
@@ -0,0 +1,468 @@
#define MG_ENABLE_TCPIP 1
#define MG_ENABLE_TCPIP_DRIVER_INIT 0
#define FETCH_BUF_SIZE (16 * 1024)
#include "mongoose.c"
bool mip_x_test(struct mg_mgr *);
#ifdef MQTT_LOCALHOST
#define MQTT_URL "mqtt://127.0.0.1:1883"
#else
#define MQTT_URL "mqtt://broker.hivemq.com:1883"
#endif
#if MG_TLS == MG_TLS_BUILTIN
#define MQTTS_URL "mqtts://mongoose.ws:8883" // test requires TLS 1.3
#define MQTTS_CA mg_str(s_ca_cert)
static const char *s_ca_cert =
"-----BEGIN CERTIFICATE-----\n"
"MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw\n"
"TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\n"
"cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4\n"
"WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu\n"
"ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY\n"
"MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc\n"
"h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+\n"
"0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U\n"
"A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW\n"
"T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH\n"
"B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC\n"
"B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv\n"
"KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn\n"
"OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn\n"
"jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw\n"
"qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI\n"
"rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\n"
"HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq\n"
"hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL\n"
"ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ\n"
"3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK\n"
"NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5\n"
"ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur\n"
"TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC\n"
"jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc\n"
"oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq\n"
"4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA\n"
"mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d\n"
"emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=\n"
"-----END CERTIFICATE-----\n";
#elif MG_TLS
#ifdef MQTT_LOCALHOST
// we'll generate MQTTS_URL
#define MQTTS_CA mg_str(s_ca_cert)
static const char *s_ca_cert =
"-----BEGIN CERTIFICATE-----\n"
"MIIBFTCBvAIJAMNTFtpfcq8NMAoGCCqGSM49BAMCMBMxETAPBgNVBAMMCE1vbmdv\n"
"b3NlMB4XDTI0MDUwNzE0MzczNloXDTM0MDUwNTE0MzczNlowEzERMA8GA1UEAwwI\n"
"TW9uZ29vc2UwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASuP+86T/rOWnGpEVhl\n"
"fxYZ+pjMbCmDZ+vdnP0rjoxudwRMRQCv5slRlDK7Lxue761sdvqxWr0Ma6TFGTNg\n"
"epsRMAoGCCqGSM49BAMCA0gAMEUCIQCwb2CxuAKm51s81S6BIoy1IcandXSohnqs\n"
"us64BAA7QgIgGGtUrpkgFSS0oPBlCUG6YPHFVw42vTfpTC0ySwAS0M4=\n"
"-----END CERTIFICATE-----\n";
#else
#define MQTTS_URL "mqtts://broker.hivemq.com:8883"
#define MQTTS_CA mg_unpacked("/data/ca.pem")
#endif // MQTT_LOCALHOST
#endif
static char *host_ip;
static int s_num_tests = 0;
static bool s_error = false;
#ifdef NO_ABORT
static int s_abort = 0;
#define ABORT() ++s_abort, s_error = true
#else
#ifdef NO_SLEEP_ABORT
#define ABORT() abort()
#else
#define ABORT() \
sleep(2); /* 2s, GH print reason */ \
abort();
#endif
#endif
#define ASSERT(expr) \
do { \
s_num_tests++; \
if (!(expr)) { \
printf("FAILURE %s:%d: %s\n", __FILE__, __LINE__, #expr); \
fflush(stdout); \
ABORT(); \
} \
} while (0)
static struct mg_http_message gethm(const char *buf) {
struct mg_http_message hm;
memset(&hm, 0, sizeof(hm));
mg_http_parse(buf, strlen(buf), &hm);
return hm;
}
static int cmpbody(const char *buf, const char *str) {
struct mg_str s = mg_str(str);
struct mg_http_message hm = gethm(buf);
size_t len = strlen(buf);
if (hm.body.len > len) hm.body.len = len - (size_t) (hm.body.buf - buf);
return mg_strcmp(hm.body, s);
}
#ifndef NO_HTTPSERVER_TEST
static void eh1(struct mg_connection *c, int ev, void *ev_data) {
struct mg_tls_opts *topts = (struct mg_tls_opts *) c->fn_data;
if (ev == MG_EV_ACCEPT && topts != NULL) mg_tls_init(c, topts);
if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
MG_DEBUG(("[%.*s %.*s] message len %d", (int) hm->method.len,
hm->method.buf, (int) hm->uri.len, hm->uri.buf,
(int) hm->message.len));
if (mg_match(hm->uri, mg_str("/foo/*"), NULL)) {
mg_http_reply(c, 200, "", "uri: %.*s", hm->uri.len - 5, hm->uri.buf + 5);
} else if (mg_match(hm->uri, mg_str("/ws"), NULL)) {
mg_ws_upgrade(c, hm, NULL);
} else if (mg_match(hm->uri, mg_str("/body"), NULL)) {
mg_http_reply(c, 200, "", "%.*s", (int) hm->body.len, hm->body.buf);
} else {
struct mg_http_serve_opts sopts;
memset(&sopts, 0, sizeof(sopts));
sopts.root_dir = "./data";
mg_http_serve_dir(c, hm, &sopts);
}
} else if (ev == MG_EV_WS_OPEN) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
ASSERT(mg_strcmp(hm->uri, mg_str("/ws")) == 0);
mg_ws_send(c, "opened", 6, WEBSOCKET_OP_BINARY);
} else if (ev == MG_EV_WS_MSG) {
struct mg_ws_message *wm = (struct mg_ws_message *) ev_data;
mg_ws_send(c, wm->data.buf, wm->data.len, WEBSOCKET_OP_BINARY);
}
}
#endif
struct fetch_data {
char *buf;
const char *url;
int code, closed;
};
static void fcb(struct mg_connection *c, int ev, void *ev_data) {
struct fetch_data *fd = (struct fetch_data *) c->fn_data;
if (ev == MG_EV_CONNECT) {
MG_DEBUG(("CONNECT"));
if (mg_url_is_ssl(fd->url)) {
struct mg_tls_opts opts;
memset(&opts, 0, sizeof(opts)); // read CA from packed_fs
if (host_ip != NULL && strstr(fd->url, host_ip) != NULL) {
MG_DEBUG(("Local connection, using self-signed certificates"));
opts.name = mg_str_s("localhost");
opts.ca = mg_unpacked("/certs/ca.crt");
} else {
opts.name = mg_url_host(fd->url);
opts.ca = mg_unpacked("/data/ca.pem");
#if MG_TLS == MG_TLS_BUILTIN
// our TLS does not search for the proper CA in a bundle
opts.ca = mg_file_read(&mg_fs_posix, "data/e5.crt");
#endif
}
mg_tls_init(c, &opts);
#if MG_TLS == MG_TLS_BUILTIN
mg_free((void *) opts.ca.buf);
#endif
}
} else if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
snprintf(fd->buf, FETCH_BUF_SIZE, "%.*s", (int) hm->message.len,
hm->message.buf);
fd->code = atoi(hm->uri.buf);
fd->closed = 1;
c->is_closing = 1;
MG_DEBUG(("CODE: %d, MSG: %.*s", fd->code, (int) hm->message.len,
hm->message.buf));
(void) c;
} else if (ev == MG_EV_CLOSE) {
MG_DEBUG(("CLOSE"));
fd->closed = 1;
} else if (ev == MG_EV_READ) {
long bytes = *(long *) ev_data;
MG_DEBUG(("READ %d: %.*s", (int) bytes, (int) bytes, c->recv.buf));
}
}
static int fetch(struct mg_mgr *mgr, char *buf, const char *url,
const char *fmt, ...) {
struct fetch_data fd = {buf, url, 0, 0};
int i;
struct mg_connection *c = NULL;
va_list ap;
mg_mgr_poll(mgr, 0); // update ifp->now to avoid ARP lookup using an old
// timestamp (from an ancient call in other test)
c = mg_http_connect(mgr, url, fcb, &fd);
ASSERT(c != NULL);
va_start(ap, fmt);
mg_vprintf(c, fmt, &ap);
va_end(ap);
buf[0] = '\0';
// - TLS: multiple (small) records: allow enough loops so mg_mgr_poll can
// process buffered records when no more frames are coming in
for (i = 0; i < 500 && buf[0] == '\0' && !fd.closed; i++) {
mg_mgr_poll(mgr, 0);
usleep(5000); // 5 ms. Slow down poll loop to ensure packet transit, but
// allow enough loops to get the ARP response, otherwise,
// given enough traffic, the timer expires before we get a
// chance to see the response
}
if (!fd.closed) c->is_closing = 1;
mg_mgr_poll(mgr, 0);
return fd.code;
}
static void test_http_client(struct mg_mgr *mgr) {
char buf[FETCH_BUF_SIZE];
int rc = 0;
const bool ipv6 = MG_ENABLE_IPV6;
#if MG_TLS
if (ipv6) {
rc = fetch(mgr, buf, "https://ipv6.google.com",
"GET / HTTP/1.0\r\nHost: ipv6.google.com\r\n\r\n");
} else {
rc = fetch(mgr, buf, "https://cesanta.com",
"GET /robots.txt HTTP/1.0\r\nHost: cesanta.com\r\n\r\n");
}
ASSERT(rc == 200); // OK
#else
if (ipv6) {
rc = fetch(mgr, buf, "http://ipv6.google.com",
"GET / HTTP/1.0\r\nHost: ipv6.google.com\r\n\r\n");
ASSERT(rc == 200); // OK
} else {
rc = fetch(mgr, buf, "http://cesanta.com",
"GET /robots.txt HTTP/1.0\r\nHost: cesanta.com\r\n\r\n");
ASSERT(rc == 301); // OK: Permanently moved (HTTP->HTTPS redirect)
}
#endif
}
static struct mg_connection *s_conn;
static char s_topic[16];
struct mqtt_data {
char *url;
bool passed;
};
static void mqtt_fn(struct mg_connection *c, int ev, void *ev_data) {
struct mqtt_data *data = (struct mqtt_data *) c->fn_data;
if (ev == MG_EV_CONNECT) {
MG_DEBUG(("CONNECT"));
#if MG_TLS
struct mg_tls_opts opts;
memset(&opts, 0, sizeof(opts));
opts.ca = MQTTS_CA;
opts.name = mg_url_host(data->url);
mg_tls_init(c, &opts);
#endif
} else if (ev == MG_EV_MQTT_OPEN) {
MG_DEBUG(("MQTT CONNECT"));
struct mg_mqtt_opts sub_opts;
memset(&sub_opts, 0, sizeof(sub_opts));
sub_opts.topic = mg_str(mg_random_str(s_topic, sizeof(s_topic)));
sub_opts.qos = 1;
mg_mqtt_sub(c, &sub_opts);
struct mg_mqtt_opts pub_opts;
memset(&pub_opts, 0, sizeof(pub_opts));
pub_opts.topic = sub_opts.topic;
pub_opts.message = mg_str("hi");
pub_opts.qos = 1, pub_opts.retain = false;
mg_mqtt_pub(c, &pub_opts);
} else if (ev == MG_EV_MQTT_MSG) {
struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
MG_DEBUG(("TOPIC: %.*s, MSG: %.*s", (int) mm->topic.len, mm->topic.buf,
mm->data.len > 10 ? 10 : (int) mm->data.len, mm->data.buf));
ASSERT(mm->topic.len == strlen(s_topic) &&
strncmp(mm->topic.buf, s_topic, mm->topic.len) == 0);
if (mm->data.len == 2 && strncmp(mm->data.buf, "hi", 2) == 0) {
struct mg_mqtt_opts pub_opts;
memset(&pub_opts, 0, sizeof(pub_opts));
pub_opts.topic = mm->topic;
// send more than 1 record, content is not relevant
pub_opts.message = mg_str_n((char *)(size_t) mqtt_fn, 21098);
pub_opts.qos = 1, pub_opts.retain = false;
mg_mqtt_pub(c, &pub_opts);
} else if (mm->data.len == 8 && strncmp(mm->data.buf, "farewell", 8) == 0) {
// close on farewell
MG_INFO(("%lu CLOSING", c->id));
mg_mqtt_disconnect(c, NULL);
data->passed = true;
} else if (mm->data.len == 21098) {
struct mg_mqtt_opts pub_opts;
ASSERT(memcmp((const char *) (size_t) mqtt_fn, mm->data.buf, 21098) == 0);
// send farewell after receiving big data
memset(&pub_opts, 0, sizeof(pub_opts));
pub_opts.topic = mm->topic;
pub_opts.message = mg_str("farewell");
pub_opts.qos = 1, pub_opts.retain = false;
mg_mqtt_pub(c, &pub_opts);
}
} else if (ev == MG_EV_CLOSE) {
MG_DEBUG(("CLOSE"));
s_conn = NULL;
} else if (ev == MG_EV_ERROR) {
MG_ERROR(("%lu ERROR %s", c->id, (char *) ev_data));
}
}
static void test_mqtt_connsubpub(struct mg_mgr *mgr) {
struct mqtt_data data;
struct mg_mqtt_opts opts;
memset(&opts, 0, sizeof(opts));
opts.clean = true, opts.version = 4;
data.passed = false;
#if defined(MQTT_LOCALHOST) && MG_TLS != MG_TLS_BUILTIN
if (host_ip == NULL) {
printf("\nMQTT_LOCALHOST defined but no HOST_IP provided, skipping MQTTS tests\n");
return;
}
printf("HOST_IP: %s\n", host_ip);
#endif
#if MG_TLS
#if defined(MQTT_LOCALHOST) && MG_TLS != MG_TLS_BUILTIN
data.url = mg_mprintf("mqtts://%s:8883", host_ip);
#else
data.url = strdup(MQTTS_URL);
#endif
#else
#ifdef MQTT_LOCALHOST
data.url = mg_mprintf("mqtt://%s:1883", host_ip);
#else
data.url = strdup(MQTT_URL);
#endif
#endif
s_conn = mg_mqtt_connect(mgr, data.url, &opts, mqtt_fn, &data);
ASSERT(s_conn != NULL);
for (int i = 0; i < 1000 && s_conn != NULL && !s_conn->is_closing; i++) {
mg_mgr_poll(mgr, 0);
usleep(10000); // 10 ms. Slow down poll loop to ensure packets transit
}
ASSERT(data.passed);
mg_mgr_poll(mgr, 0);
free(data.url);
}
#ifndef NO_HTTPSERVER_TEST
#include <pthread.h>
static void *poll_thread(void *p) {
struct mg_mgr *mgr = (struct mg_mgr *) p;
int i;
for (i = 0; i < 300; i++) {
mg_mgr_poll(mgr, 0);
usleep(10000); // 10 ms. Slow down poll loop to ensure packet transit
}
return NULL;
}
#endif
static void test_http_server(struct mg_mgr *mgr) {
#ifdef NO_HTTPSERVER_TEST
(void) mgr;
#else
struct mg_connection *c;
char *cmd;
pthread_t thread_id = (pthread_t) 0;
#if MG_TLS
struct mg_tls_opts opts;
memset(&opts, 0, sizeof(opts));
// opts.ca = mg_str(s_tls_ca);
opts.cert = mg_unpacked("/certs/server.crt");
opts.key = mg_unpacked("/certs/server.key");
c = mg_http_listen(mgr, "https://0.0.0.0:12347", eh1, &opts);
cmd = mg_mprintf("./mip_curl.sh --insecure https://%M:12347", mg_print_ip4,
&mgr->ifp->ip);
#else
c = mg_http_listen(mgr, "http://0.0.0.0:12347", eh1, NULL);
cmd =
mg_mprintf("./mip_curl.sh http://%M:12347", mg_print_ip4, &mgr->ifp->ip);
#endif
ASSERT(c != NULL);
ASSERT (mg_send(c, "NADA", 0)); // check mg_send allows len=0
pthread_create(&thread_id, NULL, poll_thread,
mgr); // simpler this way, no concurrency anyway
MG_DEBUG(("CURL"));
ASSERT(system(cmd) == 0); // wait for curl
MG_DEBUG(("MONGOOSE"));
pthread_join(thread_id, NULL); // wait for Mongoose
MG_DEBUG(("DONE"));
free(cmd);
#endif
}
static void test_tls(struct mg_mgr *mgr) {
#if MG_TLS
char *url;
char buf[FETCH_BUF_SIZE]; // make sure it can hold Makefile
struct mg_str data = mg_unpacked("/Makefile");
if (host_ip == NULL) {
printf("\nNo HOST_IP provided, skipping TLS tests\n");
return;
}
printf("HOST_IP: %s\n", host_ip);
// - POST a large file, make sure we drain TLS buffers and read all: done at
// server test, using curl as POSTing client
// - Fire patched server, test multiple TLS records per TCP segment handling
url = mg_mprintf("https://%s:8443", host_ip); // for historic reasons
ASSERT(system("tls_multirec/server -d tls_multirec &") == 0);
sleep(1);
ASSERT(fetch(mgr, buf, url, "GET /thefile HTTP/1.0\n\n") == 200);
ASSERT(cmpbody(buf, data.buf) == 0); // "thefile" links to Makefile
ASSERT(system("killall tls_multirec/server") == 0);
free(url);
#else
(void) cmpbody("", "");
(void) mgr;
#endif
}
bool mip_x_test(struct mg_mgr *mgr) {
host_ip = getenv("HOST_IP");
#define DASHBOARD(x) printf("HEALTH_DASHBOARD\t\"%s\": %s,\n", x, s_error ? "false":"true");
usleep(500000); // 500 ms
s_error = false;
test_http_client(mgr);
DASHBOARD("http_client");
usleep(500000); // 500 ms
s_error = false;
test_http_server(mgr);
DASHBOARD("http_server");
usleep(500000); // 500 ms
s_error = false;
test_tls(mgr);
DASHBOARD("tls");
usleep(500000); // 500 ms
s_error = false;
test_mqtt_connsubpub(mgr);
DASHBOARD("mqtt");
// Clear
s_error = false;
mg_mgr_free(mgr);
ASSERT(mgr->conns == NULL); // Deconstruction OK
printf("HEALTH_DASHBOARD\t\"cleanup\": %s\n", s_error ? "false":"true");
// last entry with no comma
#ifdef NO_ABORT
if (s_abort != 0) return false;
#endif
printf("SUCCESS. Total tests: %d\n", s_num_tests);
return true;
}
+105
View File
@@ -0,0 +1,105 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#ifndef __OpenBSD__
#include <linux/if.h>
#include <linux/if_tun.h>
#else
#include <net/if.h>
#include <net/if_tun.h>
#include <net/if_types.h>
#endif
static int s_signo;
void signal_handler(int signo) {
s_signo = signo;
}
int main(void) {
// Setup interface
const char *iface = "tap0"; // Network iface
const uint16_t port = 0x55AA; // UDP port
#ifndef __OpenBSD__
const char *tuntap_device = "/dev/net/tun";
#else
const char *tuntap_device = "/dev/tap0";
#endif
int fd = open(tuntap_device, O_RDWR);
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, iface, IFNAMSIZ);
#ifndef __OpenBSD__
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
if (ioctl(fd, TUNSETIFF, (void *) &ifr) < 0) {
#else
ifr.ifr_flags = (short) (IFF_UP | IFF_BROADCAST | IFF_MULTICAST);
if (ioctl(fd, TUNSIFMODE, (void *) &ifr) < 0) {
#endif
printf("Failed to setup TAP interface: %s", ifr.ifr_name);
return EXIT_FAILURE;
}
printf("Opened TAP interface: %s\n", iface);
int sockfd;
struct sockaddr_in tap_addr, port_addr;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
tap_addr.sin_family = AF_INET;
tap_addr.sin_addr.s_addr = htonl(0x7f000001U); // 127.0.0.1
tap_addr.sin_port = htons(port);
if (bind(sockfd, (struct sockaddr *) &tap_addr, sizeof(tap_addr)) < 0) return EXIT_FAILURE;
printf("Opened UDP socket: 127.0.0.1:%u (0x%04x)\n", port, port);
memset(&port_addr, 0, sizeof(port_addr));
while (s_signo == 0) {
struct pollfd pfd[2];
int result;
do {
pfd[0].fd = fd;
pfd[0].events = POLLIN | POLLPRI; // will wait for input available (read ready), use POLLOUT for write
pfd[1].fd = sockfd;
pfd[1].events = POLLIN | POLLPRI; // will wait for input available (read ready), use POLLOUT for write
// only read ready shown here, for write ready use the 3rd arg, and the 4th for exceptions
result = poll(pfd, 2, 1000); // 2 pfd, TIMEOUT in milliseconds
switch(result) {
case -1: // error
break;
case 0: // timeout (if a timeout struct was passed to select)
break;
default: // the number of fd/sockets with data available (see pfd.revents for each one);
uint8_t buf[1540];
if (pfd[0].revents & (POLLIN | POLLPRI)) {
ssize_t nread = read(fd, buf, 1540);
// printf("Got at TAP: %d bytes\n", (int) nread);
if (port_addr.sin_family != 0) { // something has been written to this struct (we got a conterpart)
sendto(sockfd, buf, (size_t) nread, 0, (struct sockaddr *) &port_addr, sizeof(port_addr));
// printf("Sent to %s port %d\n", inet_ntoa(port_addr.sin_addr), ntohs(port_addr.sin_port));
}
}
if (pfd[1].revents & (POLLIN | POLLPRI)) {
socklen_t len = sizeof(port_addr);
ssize_t nread = recvfrom(sockfd, buf, 1540, 0, (struct sockaddr *) &port_addr, &len);
// printf("Got at UDP: %d bytes from %s port %d\n", nread, inet_ntoa(port_addr.sin_addr), ntohs(port_addr.sin_port));
write(fd, buf, (size_t) nread);
// printf("Sent to TAP\n");
}
break;
}
} while (result >= 0);
printf("looks like we got an error here... should I quit ? Waiting for CTRL-C\n");
}
close(sockfd);
close(fd);
}
+1 -1
View File
@@ -6,4 +6,4 @@ server: main.c patched_mongoose.c mongoose.h Makefile
$(CC) main.c patched_mongoose.c $(CFLAGS) $(CFLAGS_MONGOOSE) $(CFLAGS_EXTRA) -o $@ $(CC) main.c patched_mongoose.c $(CFLAGS) $(CFLAGS_MONGOOSE) $(CFLAGS_EXTRA) -o $@
clean: clean:
rm -f server rm -rf server *.exe *.o *.dSYM
+292 -70
View File
@@ -4,7 +4,12 @@
#include "math.h" #include "math.h"
static int s_num_tests = 0; static int s_num_tests = 0;
static bool s_error = false;
#ifdef NO_ABORT
static int s_abort = 0;
#define ABORT() ++s_abort, s_error = true
#else
#ifdef NO_SLEEP_ABORT #ifdef NO_SLEEP_ABORT
#define ABORT() abort() #define ABORT() abort()
#else #else
@@ -12,6 +17,7 @@ static int s_num_tests = 0;
sleep(2); /* 2s, GH print reason */ \ sleep(2); /* 2s, GH print reason */ \
abort(); abort();
#endif #endif
#endif
#define ASSERT(expr) \ #define ASSERT(expr) \
do { \ do { \
@@ -66,6 +72,13 @@ static void test_match(void) {
ASSERT(mg_match(mg_str_n("caabxa", 6), mg_str_n("#aa#bb#", 7), NULL) == 0); ASSERT(mg_match(mg_str_n("caabxa", 6), mg_str_n("#aa#bb#", 7), NULL) == 0);
ASSERT(mg_match(mg_str_n("a__b_c", 6), mg_str_n("a*b*c", 5), NULL) == 1); ASSERT(mg_match(mg_str_n("a__b_c", 6), mg_str_n("a*b*c", 5), NULL) == 1);
{
char *ae_value = (char *) malloc(1); // Exact size for ASAN
ae_value[0] = 'g';
mg_match(mg_str_n(ae_value, 1), mg_str("*gzip*"), NULL); // Check for OOB
free(ae_value);
}
{ {
struct mg_str caps[3]; struct mg_str caps[3];
ASSERT(mg_match(mg_str("//a.c"), mg_str("#.c"), NULL) == true); ASSERT(mg_match(mg_str("//a.c"), mg_str("#.c"), NULL) == true);
@@ -316,6 +329,8 @@ static void test_iobuf(void) {
mg_iobuf_add(&io, io.len, "a", 1); mg_iobuf_add(&io, io.len, "a", 1);
ASSERT(io.buf != NULL && io.size == 20 && io.len == 11); ASSERT(io.buf != NULL && io.size == 20 && io.len == 11);
ASSERT(memcmp(io.buf, "xhi!123456a", io.len) == 0); ASSERT(memcmp(io.buf, "xhi!123456a", io.len) == 0);
mg_iobuf_resize(&io, 1);
ASSERT(io.buf != NULL && io.size == 10 && io.len == 10);
mg_iobuf_free(&io); mg_iobuf_free(&io);
} }
@@ -431,7 +446,7 @@ static const char *s_ca_cert =
#else #else
#define MQTTS_URL "mqtts://broker.hivemq.com:8883" #define MQTTS_URL "mqtts://broker.hivemq.com:8883"
#define MQTTS_CA mg_unpacked("/data/ca.pem") #define MQTTS_CA mg_unpacked("/data/ca.pem")
#endif // MQTT_LOCALHOST #endif // MQTT_LOCALHOST
#endif #endif
struct mqtt_data { struct mqtt_data {
@@ -446,6 +461,7 @@ struct mqtt_data {
#define flags_received (1 << 2) #define flags_received (1 << 2)
#define flags_released (1 << 3) #define flags_released (1 << 3)
#define flags_completed (1 << 4) #define flags_completed (1 << 4)
#define flags_unsubscribed (1 << 5)
static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data) { static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data) {
struct mqtt_data *test_data = (struct mqtt_data *) c->fn_data; struct mqtt_data *test_data = (struct mqtt_data *) c->fn_data;
@@ -455,7 +471,7 @@ static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data) {
struct mg_tls_opts opts; struct mg_tls_opts opts;
memset(&opts, 0, sizeof(opts)); memset(&opts, 0, sizeof(opts));
opts.ca = MQTTS_CA; opts.ca = MQTTS_CA;
#if defined( MQTT_LOCALHOST) && MG_TLS != MG_TLS_BUILTIN #if defined(MQTT_LOCALHOST) && MG_TLS != MG_TLS_BUILTIN
MG_ERROR(("Hostname not tested")); MG_ERROR(("Hostname not tested"));
#else #else
opts.name = mg_url_host(MQTTS_URL); opts.name = mg_url_host(MQTTS_URL);
@@ -479,6 +495,8 @@ static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data) {
test_data->flags |= flags_released; test_data->flags |= flags_released;
} else if (mm->cmd == MQTT_CMD_PUBCOMP) { } else if (mm->cmd == MQTT_CMD_PUBCOMP) {
test_data->flags |= flags_completed; test_data->flags |= flags_completed;
} else if (mm->cmd == MQTT_CMD_UNSUBACK) {
test_data->flags = flags_unsubscribed;
} }
} else if (ev == MG_EV_MQTT_MSG) { } else if (ev == MG_EV_MQTT_MSG) {
struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data; struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
@@ -491,7 +509,7 @@ static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data) {
size_t pos = 0, i = 0, j = 0; size_t pos = 0, i = 0, j = 0;
struct mg_mqtt_prop prop; struct mg_mqtt_prop prop;
for (i = 0; i < 5 ; i++) { for (i = 0; i < 5; i++) {
ASSERT((pos = mg_mqtt_next_prop(mm, &prop, pos)) > 0); ASSERT((pos = mg_mqtt_next_prop(mm, &prop, pos)) > 0);
if (prop.id == MQTT_PROP_MESSAGE_EXPIRY_INTERVAL) { if (prop.id == MQTT_PROP_MESSAGE_EXPIRY_INTERVAL) {
ASSERT(prop.iv == 10); ASSERT(prop.iv == 10);
@@ -500,14 +518,20 @@ static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data) {
j += 2; j += 2;
continue; continue;
} else if (prop.id == MQTT_PROP_CONTENT_TYPE) { } else if (prop.id == MQTT_PROP_CONTENT_TYPE) {
ASSERT(strncmp(prop.val.buf, "test_content_val_2", prop.val.len) == 0 && prop.val.len == strlen("test_content_val_2")); ASSERT(strncmp(prop.val.buf, "test_content_val_2", prop.val.len) ==
0 &&
prop.val.len == strlen("test_content_val_2"));
j += 4; j += 4;
} else if (prop.id == MQTT_PROP_USER_PROPERTY) { } else if (prop.id == MQTT_PROP_USER_PROPERTY) {
if (strncmp(prop.key.buf, "test_key_1", prop.key.len) == 0 && prop.key.len == strlen("test_key_1")) { if (strncmp(prop.key.buf, "test_key_1", prop.key.len) == 0 &&
ASSERT(strncmp(prop.val.buf, "test_value_1", prop.val.len) == 0 && prop.val.len == strlen("test_value_1")); prop.key.len == strlen("test_key_1")) {
ASSERT(strncmp(prop.val.buf, "test_value_1", prop.val.len) == 0 &&
prop.val.len == strlen("test_value_1"));
j += 8; j += 8;
} else if (strncmp(prop.key.buf, "test_key_2", prop.key.len) == 0 && prop.key.len == strlen("test_key_2")) { } else if (strncmp(prop.key.buf, "test_key_2", prop.key.len) == 0 &&
ASSERT(strncmp(prop.val.buf, "test_value_2", prop.val.len) == 0 && prop.val.len == strlen("test_value_2")); prop.key.len == strlen("test_key_2")) {
ASSERT(strncmp(prop.val.buf, "test_value_2", prop.val.len) == 0 &&
prop.val.len == strlen("test_value_2"));
j += 16; j += 16;
} else { } else {
ASSERT(0); ASSERT(0);
@@ -751,6 +775,12 @@ static void test_mqtt_ver(uint8_t mqtt_version) {
memset(mbuf + 1, 0, sizeof(mbuf) - 1); memset(mbuf + 1, 0, sizeof(mbuf) - 1);
test_data.flags = 0; test_data.flags = 0;
opts.props = 0; opts.num_props = 0;
mg_mqtt_unsub(c, &opts);
for (i = 0; i < 500 && test_data.flags == 0; i++) mg_mgr_poll(&mgr, 10);
ASSERT(test_data.flags == flags_unsubscribed);
test_data.flags = 0;
// dirty disconnect // dirty disconnect
mg_mgr_free(&mgr); mg_mgr_free(&mgr);
ASSERT(mgr.conns == NULL); ASSERT(mgr.conns == NULL);
@@ -867,8 +897,10 @@ static int fetch(struct mg_mgr *mgr, char *buf, const char *url,
if (strstr(url, "localhost") != NULL) { if (strstr(url, "localhost") != NULL) {
// Local connection, use self-signed certificates // Local connection, use self-signed certificates
opts.ca = mg_unpacked("/certs/ca.crt"); opts.ca = mg_unpacked("/certs/ca.crt");
// opts.cert = mg_str(s_tls_cert); if (strstr(url, "23456") != NULL) { // hinted from caller
// opts.key = mg_str(s_tls_key); opts.cert = mg_unpacked("/certs/client.crt");
opts.key = mg_unpacked("/certs/client.key");
}
} }
mg_tls_init(c, &opts); mg_tls_init(c, &opts);
} }
@@ -1414,7 +1446,6 @@ static void test_tls(void) {
struct mg_str bd; struct mg_str bd;
ASSERT(data.buf != NULL && data.len > 0); ASSERT(data.buf != NULL && data.len > 0);
memset(&opts, 0, sizeof(opts)); memset(&opts, 0, sizeof(opts));
// opts.ca = mg_str(s_tls_ca);
opts.cert = mg_unpacked("/certs/server.crt"); opts.cert = mg_unpacked("/certs/server.crt");
opts.key = mg_unpacked("/certs/server.key"); opts.key = mg_unpacked("/certs/server.key");
mg_mgr_init(&mgr); mg_mgr_init(&mgr);
@@ -1442,7 +1473,7 @@ static void test_tls(void) {
"%s", "%s",
bd.len, bd.buf) == 200); bd.len, bd.buf) == 200);
ASSERT(cmpbody(buf, bd.buf) == 0); ASSERT(cmpbody(buf, bd.buf) == 0);
#if MG_TLS == MG_TLS_BUILTIN && defined(__linux__) #if MG_TLS == MG_TLS_BUILTIN && defined(__linux__) && MG_ENABLE_CHACHA20 // skip for non-CHACHA tests
// fire patched server, test multiple TLS records per TCP segment handling // fire patched server, test multiple TLS records per TCP segment handling
// skip other TLS stacks to avoid "bad client hello", we are 1.3 only // skip other TLS stacks to avoid "bad client hello", we are 1.3 only
if (access("tls_multirec/server", X_OK) == 0) { if (access("tls_multirec/server", X_OK) == 0) {
@@ -1455,7 +1486,8 @@ static void test_tls(void) {
ASSERT(cmpbody(buf, data.buf) == 0); // "thefile" links to Makefile ASSERT(cmpbody(buf, data.buf) == 0); // "thefile" links to Makefile
ASSERT(system("killall tls_multirec/server") == 0); ASSERT(system("killall tls_multirec/server") == 0);
} else { } else {
MG_ERROR(("SKIPPED TLS MULTIPLE RECORDS TEST, tls_multirec/server NOT PRESENT")); MG_ERROR(
("SKIPPED TLS MULTIPLE RECORDS TEST, tls_multirec/server NOT PRESENT"));
} }
#else #else
printf( printf(
@@ -1463,6 +1495,20 @@ static void test_tls(void) {
"is 1.3 only; re-enable when other stacks can be easily configured for " "is 1.3 only; re-enable when other stacks can be easily configured for "
"1.3\n"); "1.3\n");
#endif #endif
// Repeat the simplest test with two-way authentication
opts.ca = mg_unpacked("/certs/ca.crt"); // configure the server for two-way
// make it fail: the client will not use 2-way
ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\n\n") != 200);
// make it work
mg_mgr_free(&mgr);
ASSERT(mgr.conns == NULL);
mg_mgr_init(&mgr);
url = "https://localhost:23456"; // port # hints the client to use two-way
c = mg_http_listen(&mgr, url, eh1, &opts);
ASSERT(c != NULL);
ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\n\n") == 200);
ASSERT(cmpbody(buf, "hello\n") == 0);
mg_mgr_free(&mgr); mg_mgr_free(&mgr);
ASSERT(mgr.conns == NULL); ASSERT(mgr.conns == NULL);
#endif #endif
@@ -1473,7 +1519,8 @@ static void f3(struct mg_connection *c, int ev, void *ev_data) {
// MG_INFO(("%d", ev)); // MG_INFO(("%d", ev));
if (ev == MG_EV_CONNECT) { if (ev == MG_EV_CONNECT) {
// c->is_hexdumping = 1; // c->is_hexdumping = 1;
ASSERT((c->loc.ip[0] != 0)); // Make sure that c->loc address is populated ASSERT((c->loc.addr.ip[0] !=
0)); // Make sure that c->loc address is populated
mg_printf(c, "GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n", mg_printf(c, "GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n",
c->rem.is_ip6 ? "" : "/robots.txt", c->rem.is_ip6 ? "" : "/robots.txt",
c->rem.is_ip6 ? "ipv6.google.com" : "cesanta.com"); c->rem.is_ip6 ? "ipv6.google.com" : "cesanta.com");
@@ -1510,12 +1557,12 @@ static void test_http_client(void) {
ASSERT(ok == 301 || ok == 200); ASSERT(ok == 301 || ok == 200);
mg_mgr_poll(&mgr, 0); mg_mgr_poll(&mgr, 0);
ok = 0; ok = 0;
#if MG_TLS #if MG_TLS && MG_TLS != MG_TLS_BUILTIN
url = "https://cesanta.com"; url = "https://cesanta.com";
opts.name = mg_url_host(url); opts.name = mg_url_host(url);
#if MG_TLS == MG_TLS_BUILTIN #if MG_TLS == MG_TLS_BUILTIN
// our TLS does not search for the proper CA in a bundle // our TLS does not search for the proper CA in a bundle
opts.ca = mg_file_read(&mg_fs_posix, "data/e5.crt"); opts.ca = mg_file_read(&mg_fs_posix, "data/e8.crt");
#endif #endif
c = mg_http_connect(&mgr, url, f3, &ok); c = mg_http_connect(&mgr, url, f3, &ok);
ASSERT(c != NULL); ASSERT(c != NULL);
@@ -1525,7 +1572,7 @@ static void test_http_client(void) {
ASSERT(ok == 200); ASSERT(ok == 200);
mg_mgr_poll(&mgr, 1); mg_mgr_poll(&mgr, 1);
// Make host validationfail // Make host validation fail
c = mg_http_connect(&mgr, url, f3, &ok); c = mg_http_connect(&mgr, url, f3, &ok);
ASSERT(c != NULL); ASSERT(c != NULL);
opts.name = mg_str("dummy"); // Set some invalid hostname value opts.name = mg_str("dummy"); // Set some invalid hostname value
@@ -1535,6 +1582,16 @@ static void test_http_client(void) {
MG_INFO(("OK: %d", ok)); MG_INFO(("OK: %d", ok));
ASSERT(ok == 777); ASSERT(ok == 777);
mg_mgr_poll(&mgr, 1); mg_mgr_poll(&mgr, 1);
// Skip host validation
c = mg_http_connect(&mgr, url, f3, &ok);
ASSERT(c != NULL);
opts.name = mg_str("");
mg_tls_init(c, &opts);
ok = 0;
for (i = 0; i < 500 && ok <= 0; i++) mg_mgr_poll(&mgr, 10);
MG_INFO(("OK: %d", ok));
ASSERT(ok == 200);
mg_mgr_poll(&mgr, 1);
opts.name = mg_url_host(url); opts.name = mg_url_host(url);
#if MG_TLS == MG_TLS_BUILTIN #if MG_TLS == MG_TLS_BUILTIN
mg_free((void *) opts.ca.buf); mg_free((void *) opts.ca.buf);
@@ -1622,14 +1679,12 @@ static void test_http_no_content_length(void) {
// 12348 is in TIME_WAIT, use another port // 12348 is in TIME_WAIT, use another port
mg_mgr_init(&mgr); mg_mgr_init(&mgr);
mg_http_listen(&mgr, url2, f41, (void *) NULL); mg_http_listen(&mgr, url2, f41, (void *) NULL);
ASSERT(fetch(&mgr, buf, url2, "POST / HTTP/1.1\r\n\r\n") == 411); ASSERT(fetch(&mgr, buf, url2, "POST / HTTP/1.1\r\n\r\n") == 200);
ASSERT(fetch(&mgr, buf, url2, "HTTP/1.1 200\r\n\r\n") == 411); ASSERT(fetch(&mgr, buf, url2, "HTTP/1.1 200\r\n\r\n") == 411);
ASSERT(fetch(&mgr, buf, url2, "HTTP/1.1 100\r\n\r\n") != 411); ASSERT(fetch(&mgr, buf, url2, "HTTP/1.1 100\r\n\r\n") != 411);
ASSERT(fetch(&mgr, buf, url2, "HTTP/1.1 304\r\n\r\n") != 411); ASSERT(fetch(&mgr, buf, url2, "HTTP/1.1 304\r\n\r\n") != 411);
ASSERT(fetch(&mgr, buf, url2, "HTTP/1.1 305\r\n\r\n") == 411); ASSERT(fetch(&mgr, buf, url2, "HTTP/1.1 305\r\n\r\n") == 411);
ASSERT(fetch(&mgr, buf, url2, post_req) != 411); ASSERT(fetch(&mgr, buf, url2, post_req) != 411);
// Check it is processed only once (see #2811)
ASSERT(fpr(&mgr, buf, url2, "POST / HTTP/1.1\r\n\r\n") == 411);
mg_mgr_free(&mgr); mg_mgr_free(&mgr);
ASSERT(mgr.conns == NULL); ASSERT(mgr.conns == NULL);
} }
@@ -1748,15 +1803,15 @@ static void test_http_parse(void) {
} }
// #2292: fail on stray \r inside the headers // #2292: fail on stray \r inside the headers
ASSERT(mg_http_parse("a є\n\n", 6, &req) == 6); ASSERT(mg_http_parse("a є HTTP/1.0\n\n", 15, &req) == 15);
ASSERT(mg_http_parse("a b\n\n", 5, &req) == 5); ASSERT(mg_http_parse("a b HTTP/1.0\n\n", 14, &req) == 14);
ASSERT(mg_http_parse("a b\na:\n\n", 8, &req) > 0); ASSERT(mg_http_parse("a b HTTP/1.0\na:\n\n", 17, &req) > 0);
ASSERT(mg_http_parse("a b\na:\r\n\n", 9, &req) > 0); ASSERT(mg_http_parse("a b HTTP/1.0\na:\r\n\n", 18, &req) > 0);
ASSERT(mg_http_parse("a b\n\ra:\r\n\n", 10, &req) == -1); ASSERT(mg_http_parse("a b HTTP/1.0\n\ra:\r\n\n", 19, &req) == -1);
ASSERT(mg_http_parse("a b\na:\r1\n\n", 10, &req) == -1); ASSERT(mg_http_parse("a b HTTP/1.0\na:\r1\n\n", 19, &req) == -1);
ASSERT(mg_http_parse("a b\na: \r1\n\n", 11, &req) == -1); ASSERT(mg_http_parse("a b HTTP/1.0\na: \r1\n\n", 20, &req) == -1);
ASSERT(mg_http_parse("a b\na: \rb:\n\n", 12, &req) == -1); ASSERT(mg_http_parse("a b HTTP/1.0\na: \rb:\n\n", 21, &req) == -1);
ASSERT(mg_http_parse("a b\na: \nb:\n\n", 12, &req) > 0); ASSERT(mg_http_parse("a b HTTP/1.0\na: \nb:\n\n", 21, &req) > 0);
{ {
const char *s = "ґєт /слеш HTTP/1.0\nмісто: кіїв \n\n"; const char *s = "ґєт /слеш HTTP/1.0\nмісто: кіїв \n\n";
@@ -1794,7 +1849,7 @@ static void test_http_parse(void) {
{ {
const char *s = "POST /x HTTP/1.0\n\n"; const char *s = "POST /x HTTP/1.0\n\n";
ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s)); ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s));
ASSERT(req.body.len == (size_t) ~0); ASSERT(req.body.len == 0);
} }
{ {
@@ -1833,8 +1888,7 @@ static void test_http_parse(void) {
} }
{ {
static const char *s = const char *s = "a b HTTP/1.0\na:1\nb:2\nc:3\nd:4\ne:5\nf:6\ng:7\nh:8\n\n";
"a b HTTP/1.0\na:1\nb:2\nc:3\nd:4\ne:5\nf:6\ng:7\nh:8\n\n";
ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s)); ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s));
ASSERT((v = mg_http_get_header(&req, "e")) != NULL); ASSERT((v = mg_http_get_header(&req, "e")) != NULL);
ASSERT(vcmp(*v, "5")); ASSERT(vcmp(*v, "5"));
@@ -1843,6 +1897,24 @@ static void test_http_parse(void) {
ASSERT((v = mg_http_get_header(&req, "h")) == NULL); // MG_MAX_HTTP_HEADERS ASSERT((v = mg_http_get_header(&req, "h")) == NULL); // MG_MAX_HTTP_HEADERS
} }
{
// no HTTP version
const char *s = "a b\na:1\nb:2\nc:2\n\n";
ASSERT(mg_http_parse(s, strlen(s), &req) == -1);
// HTTP version
s = "a b HTTP/1.0\na:1\nb:2\nc:2\n\n";
ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s));
// Content-Length
s = "a b HTTP/1.0\nContent-Length:10\nb:2\nc:2\n\n";
ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s));
// duplicated Content-Length
s = "a b HTTP/1.0\nContent-Length:10\nb:2\nContent-Length:20\n\n";
ASSERT(mg_http_parse(s, strlen(s), &req) == -1);
}
{ {
struct mg_connection c; struct mg_connection c;
struct mg_str s, struct mg_str s,
@@ -1868,15 +1940,15 @@ static void test_http_parse(void) {
struct mg_http_message hm; struct mg_http_message hm;
const char *s = "a b HTTP/1.0\n\n"; const char *s = "a b HTTP/1.0\n\n";
ASSERT(mg_http_parse(s, strlen(s), &hm) == (int) strlen(s)); ASSERT(mg_http_parse(s, strlen(s), &hm) == (int) strlen(s));
s = "a b\nc:d\n\n"; s = "a b HTTP/1.0\nc:d\n\n";
ASSERT(mg_http_parse(s, strlen(s), &hm) == (int) strlen(s)); ASSERT(mg_http_parse(s, strlen(s), &hm) == (int) strlen(s));
s = "a\nb:b\nc:c\n\n"; s = "a\nb:b\nc:c\n\n";
ASSERT(mg_http_parse(s, strlen(s), &hm) < 0); ASSERT(mg_http_parse(s, strlen(s), &hm) < 0);
s = "a b\nc: \xc0\n\n"; // Invalid UTF in the header value: accept s = "a b HTTP/1.0\nc: \xc0\n\n"; // Invalid UTF in the header value: accept
ASSERT(mg_http_parse(s, strlen(s), &hm) == (int) strlen(s)); ASSERT(mg_http_parse(s, strlen(s), &hm) == (int) strlen(s));
ASSERT((v = mg_http_get_header(&hm, "c")) != NULL); ASSERT((v = mg_http_get_header(&hm, "c")) != NULL);
ASSERT(vcmp(*v, "\xc0")); ASSERT(vcmp(*v, "\xc0"));
s = "a b\n\xc0: 2\n\n"; // Invalid UTF in the header name: do NOT accept s = "a b HTTP/1.0\n\xc0: 2\n\n"; // Invalid UTF in the header name: do NOT accept
ASSERT(mg_http_parse(s, strlen(s), &hm) == -1); ASSERT(mg_http_parse(s, strlen(s), &hm) == -1);
} }
@@ -2232,6 +2304,16 @@ static void test_str(void) {
ASSERT(sn("%s ", "a")); ASSERT(sn("%s ", "a"));
ASSERT(sn("%s %s", "a", "b")); ASSERT(sn("%s %s", "a", "b"));
ASSERT(sn("%2s %s", "a", "b")); ASSERT(sn("%2s %s", "a", "b"));
{ // mg_queue_printf()
struct mg_queue q;
char buf[128];
uint32_t p = 0xffffffff;
size_t len;
mg_queue_init(&q, buf, sizeof(buf));
len = mg_queue_printf(&q, "A%p%p%pB", p, p, p);
ASSERT(len == 32);
ASSERT(memcmp(buf + 4, "A0xffffffff0xffffffff0xffffffffB", 32) == 0);
}
// Non-standard formatting // Non-standard formatting
{ {
@@ -2435,7 +2517,7 @@ static void test_str(void) {
char buf[100]; char buf[100];
struct mg_addr a; struct mg_addr a;
uint32_t addr = mg_htonl(0x2000001); uint32_t addr = mg_htonl(0x2000001);
memcpy(a.ip, &addr, sizeof(uint32_t)); memcpy(a.addr.ip, &addr, sizeof(uint32_t));
a.port = mg_htons(3); a.port = mg_htons(3);
a.is_ip6 = false; a.is_ip6 = false;
@@ -2445,8 +2527,8 @@ static void test_str(void) {
11); 11);
ASSERT(strcmp(buf, "2.0.0.1:3 7") == 0); ASSERT(strcmp(buf, "2.0.0.1:3 7") == 0);
memset(a.ip, 0, sizeof(a.ip)); memset(a.addr.ip, 0, sizeof(a.addr.ip));
a.ip[0] = 1, a.ip[1] = 100, a.ip[2] = 33; a.addr.ip[0] = 1, a.addr.ip[1] = 100, a.addr.ip[2] = 33;
a.is_ip6 = true; a.is_ip6 = true;
ASSERT(mg_snprintf(buf, sizeof(buf), "%M %d", mg_print_ip, &a, 7) == 24); ASSERT(mg_snprintf(buf, sizeof(buf), "%M %d", mg_print_ip, &a, 7) == 24);
ASSERT(strcmp(buf, "[164:2100:0:0:0:0:0:0] 7") == 0); ASSERT(strcmp(buf, "[164:2100:0:0:0:0:0:0] 7") == 0);
@@ -2574,6 +2656,8 @@ static void test_util(void) {
const char *e; const char *e;
char buf[100], *s; char buf[100], *s;
struct mg_addr a; struct mg_addr a;
uint64_t ipv3;
uint8_t d64[8] = {0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef};
uint32_t ipv4; uint32_t ipv4;
uint16_t port; uint16_t port;
struct mg_str data; struct mg_str data;
@@ -2591,7 +2675,7 @@ static void test_util(void) {
ASSERT(mg_aton(mg_str("0.0.0.-1"), &a) == false); ASSERT(mg_aton(mg_str("0.0.0.-1"), &a) == false);
ASSERT(mg_aton(mg_str("127.0.0.1"), &a) == true); ASSERT(mg_aton(mg_str("127.0.0.1"), &a) == true);
ASSERT(a.is_ip6 == false); ASSERT(a.is_ip6 == false);
memcpy(&ipv4, a.ip, sizeof(ipv4)); memcpy(&ipv4, &a.addr.ip4, sizeof(ipv4));
ASSERT(ipv4 == mg_htonl(0x7f000001)); ASSERT(ipv4 == mg_htonl(0x7f000001));
ASSERT(mg_ntohl(ipv4) == 0x7f000001); ASSERT(mg_ntohl(ipv4) == 0x7f000001);
MG_STORE_BE32(&ipv4, 0x5678abcd); MG_STORE_BE32(&ipv4, 0x5678abcd);
@@ -2608,48 +2692,62 @@ static void test_util(void) {
((uint8_t *) &ipv4)[2] == 0x45); ((uint8_t *) &ipv4)[2] == 0x45);
ASSERT(MG_LOAD_BE24(&ipv4) == 0xef2345); ASSERT(MG_LOAD_BE24(&ipv4) == 0xef2345);
memset(a.ip, 0xa5, sizeof(a.ip)); memcpy(&ipv3, d64, sizeof(ipv3));
#if defined(_MSC_VER) && _MSC_VER < 1700
// VC98 doesn't suppport LL suffix
#else
ASSERT(ipv3 == mg_htonll(0x1234567890abcdefLL));
ASSERT(mg_ntohll(ipv3) == 0x1234567890abcdefLL);
#endif
MG_STORE_BE64(&ipv3, 0x5678abcd12349ef0);
ASSERT(((uint8_t *) &ipv3)[0] == 0x56 && ((uint8_t *) &ipv3)[1] == 0x78 &&
((uint8_t *) &ipv3)[2] == 0xab && ((uint8_t *) &ipv3)[3] == 0xcd &&
((uint8_t *) &ipv3)[4] == 0x12 && ((uint8_t *) &ipv3)[5] == 0x34 &&
((uint8_t *) &ipv3)[6] == 0x9e && ((uint8_t *) &ipv3)[7] == 0xf0);
ASSERT(MG_LOAD_BE64(&ipv3) == 0x5678abcd12349ef0);
memset(a.addr.ip, 0xa5, sizeof(a.addr.ip)), a.is_ip6 = false;
ASSERT(mg_aton(mg_str("1:2:3:4:5:6:7:8"), &a) == true); ASSERT(mg_aton(mg_str("1:2:3:4:5:6:7:8"), &a) == true);
ASSERT(a.is_ip6 == true); ASSERT(a.is_ip6 == true);
e = "\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x00\x07\x00\x08"; e = "\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x00\x07\x00\x08";
ASSERT(memcmp(a.ip, e, sizeof(a.ip)) == 0); ASSERT(memcmp(&a.addr.ip6, e, sizeof(a.addr.ip6)) == 0);
memset(a.ip, 0xa5, sizeof(a.ip)); memset(a.addr.ip, 0xa5, sizeof(a.addr.ip)), a.is_ip6 = false;
ASSERT(mg_aton(mg_str("1:2::3"), &a) == true); ASSERT(mg_aton(mg_str("1:2::3"), &a) == true);
ASSERT(a.is_ip6 == true); ASSERT(a.is_ip6 == true);
e = "\x00\x01\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03"; e = "\x00\x01\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03";
ASSERT(memcmp(a.ip, e, sizeof(a.ip)) == 0); ASSERT(memcmp(&a.addr.ip6, e, sizeof(a.addr.ip6)) == 0);
memset(a.ip, 0xaa, sizeof(a.ip)); memset(a.addr.ip, 0xaa, sizeof(a.addr.ip)), a.is_ip6 = false;
ASSERT(mg_aton(mg_str("1::1"), &a) == true); ASSERT(mg_aton(mg_str("1::1"), &a) == true);
ASSERT(a.is_ip6 == true); ASSERT(a.is_ip6 == true);
e = "\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"; e = "\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01";
ASSERT(memcmp(a.ip, e, sizeof(a.ip)) == 0); ASSERT(memcmp(&a.addr.ip6, e, sizeof(a.addr.ip6)) == 0);
memset(a.ip, 0xaa, sizeof(a.ip)); memset(a.addr.ip, 0xaa, sizeof(a.addr.ip)), a.is_ip6 = false;
ASSERT(mg_aton(mg_str("::fFff:1.2.3.4"), &a) == true); ASSERT(mg_aton(mg_str("::fFff:1.2.3.4"), &a) == true);
ASSERT(a.is_ip6 == true); ASSERT(a.is_ip6 == true);
e = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x01\x02\x03\x04"; e = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x01\x02\x03\x04";
ASSERT(memcmp(a.ip, e, sizeof(a.ip)) == 0); ASSERT(memcmp(&a.addr.ip6, e, sizeof(a.addr.ip6)) == 0);
memset(a.ip, 0xaa, sizeof(a.ip)); memset(a.addr.ip, 0xaa, sizeof(a.addr.ip)), a.is_ip6 = false;
ASSERT(mg_aton(mg_str("::1"), &a) == true); ASSERT(mg_aton(mg_str("::1"), &a) == true);
ASSERT(a.is_ip6 == true); ASSERT(a.is_ip6 == true);
ASSERT(a.scope_id == 0); ASSERT(a.scope_id == 0);
e = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"; e = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01";
ASSERT(memcmp(a.ip, e, sizeof(a.ip)) == 0); ASSERT(memcmp(&a.addr.ip6, e, sizeof(a.addr.ip6)) == 0);
memset(a.ip, 0xaa, sizeof(a.ip)); memset(a.addr.ip, 0xaa, sizeof(a.addr.ip)), a.is_ip6 = false;
ASSERT(mg_aton(mg_str("1::"), &a) == true); ASSERT(mg_aton(mg_str("1::"), &a) == true);
ASSERT(a.is_ip6 == true); ASSERT(a.is_ip6 == true);
e = "\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; e = "\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
ASSERT(memcmp(a.ip, e, sizeof(a.ip)) == 0); ASSERT(memcmp(&a.addr.ip6, e, sizeof(a.addr.ip6)) == 0);
memset(a.ip, 0xaa, sizeof(a.ip)); memset(a.addr.ip, 0xaa, sizeof(a.addr.ip)), a.is_ip6 = false;
ASSERT(mg_aton(mg_str("2001:4860:4860::8888"), &a) == true); ASSERT(mg_aton(mg_str("2001:4860:4860::8888"), &a) == true);
ASSERT(a.is_ip6 == true); ASSERT(a.is_ip6 == true);
e = "\x20\x01\x48\x60\x48\x60\x00\x00\x00\x00\x00\x00\x00\x00\x88\x88"; e = "\x20\x01\x48\x60\x48\x60\x00\x00\x00\x00\x00\x00\x00\x00\x88\x88";
ASSERT(memcmp(a.ip, e, sizeof(a.ip)) == 0); ASSERT(memcmp(&a.addr.ip6, e, sizeof(a.addr.ip6)) == 0);
ASSERT(mg_url_decode("a=%", 3, buf, sizeof(buf), 0) < 0); ASSERT(mg_url_decode("a=%", 3, buf, sizeof(buf), 0) < 0);
ASSERT(mg_url_decode("&&&a=%", 6, buf, sizeof(buf), 0) < 0); ASSERT(mg_url_decode("&&&a=%", 6, buf, sizeof(buf), 0) < 0);
@@ -2658,22 +2756,22 @@ static void test_util(void) {
ASSERT(mg_url_decode("a=%123", 6, buf, sizeof(buf), 0) == 4 && ASSERT(mg_url_decode("a=%123", 6, buf, sizeof(buf), 0) == 4 &&
buf[2] == 0x12 && buf[3] == '3'); buf[2] == 0x12 && buf[3] == '3');
memset(a.ip, 0xaa, sizeof(a.ip)); memset(&a, 0, sizeof(a));
ASSERT(mg_aton(mg_str("::1%1"), &a) == true); ASSERT(mg_aton(mg_str("::1%1"), &a) == true);
ASSERT(a.is_ip6 == true); ASSERT(a.is_ip6 == true);
ASSERT(a.scope_id == 1); ASSERT(a.scope_id == 1);
memset(a.ip, 0xaa, sizeof(a.ip)); memset(&a, 0, sizeof(a));
ASSERT(mg_aton(mg_str("abcd::aabb:ccdd%17"), &a) == true); ASSERT(mg_aton(mg_str("abcd::aabb:ccdd%17"), &a) == true);
ASSERT(a.is_ip6 == true); ASSERT(a.is_ip6 == true);
ASSERT(a.scope_id == 17); ASSERT(a.scope_id == 17);
memset(a.ip, 0xaa, sizeof(a.ip)); memset(&a, 0xaa, sizeof(a)), a.is_ip6 = false;
ASSERT(mg_aton(mg_str("::1%17"), &a) == true); ASSERT(mg_aton(mg_str("::1%17"), &a) == true);
ASSERT(a.is_ip6 == true); ASSERT(a.is_ip6 == true);
ASSERT(a.scope_id == 17); ASSERT(a.scope_id == 17);
memset(a.ip, 0xaa, sizeof(a.ip)); memset(&a, 0xaa, sizeof(a)), a.is_ip6 = false;
ASSERT(mg_aton(mg_str("::1%255"), &a) == true); ASSERT(mg_aton(mg_str("::1%255"), &a) == true);
ASSERT(a.is_ip6 == true); ASSERT(a.is_ip6 == true);
ASSERT(a.scope_id == 255); ASSERT(a.scope_id == 255);
@@ -2918,6 +3016,14 @@ static void eZ(struct mg_connection *c, int ev, void *ev_data) {
(void) ev_data; (void) ev_data;
} }
static void eS(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_HTTP_MSG) {
ASSERT(mg_send(c, "NADA", 0));
mg_http_reply(c, 200, "", "abcd");
}
(void) ev_data;
}
// Do not delete chunks as they arrive // Do not delete chunks as they arrive
static void eh4(struct mg_connection *c, int ev, void *ev_data) { static void eh4(struct mg_connection *c, int ev, void *ev_data) {
uint32_t *crc = (uint32_t *) c->fn_data; uint32_t *crc = (uint32_t *) c->fn_data;
@@ -2953,6 +3059,9 @@ static void test_http_chunked_case(mg_event_handler_t s, mg_event_handler_t c,
} }
static void test_http_chunked(void) { static void test_http_chunked(void) {
// test mg_send allows calls with 0 length
test_http_chunked_case(eS, eh4, 1, "abcd");
// Non-chunked encoding // Non-chunked encoding
test_http_chunked_case(eY, eh4, 1, "abcd"); // Chunks not deleted test_http_chunked_case(eY, eh4, 1, "abcd"); // Chunks not deleted
test_http_chunked_case(eY, eh4, 2, "abcdabcd"); test_http_chunked_case(eY, eh4, 2, "abcdabcd");
@@ -3176,7 +3285,7 @@ static void test_udp(void) {
} }
static void test_check_ip_acl(void) { static void test_check_ip_acl(void) {
struct mg_addr ip = {{1, 2, 3, 4}, 0, 0, false}; // 1.2.3.4 struct mg_addr ip = {{{1, 2, 3, 4}}, 0, 0, false}; // 1.2.3.4
ASSERT(mg_check_ip_acl(mg_str(NULL), &ip) == 1); ASSERT(mg_check_ip_acl(mg_str(NULL), &ip) == 1);
ASSERT(mg_check_ip_acl(mg_str(""), &ip) == 1); ASSERT(mg_check_ip_acl(mg_str(""), &ip) == 1);
ASSERT(mg_check_ip_acl(mg_str("invalid"), &ip) == -1); ASSERT(mg_check_ip_acl(mg_str("invalid"), &ip) == -1);
@@ -3540,6 +3649,39 @@ static void test_json(void) {
val = mg_json_get_tok(json, "$.a"); val = mg_json_get_tok(json, "$.a");
ASSERT(mg_strcmp(val, expected) == 0); ASSERT(mg_strcmp(val, expected) == 0);
} }
// mg_json_get_num: parsing exponential
{
double d = 0.0, tolerance = 1e-12;
json = mg_str(
"{"
"\"i\":1e3,"
"\"n\":-2.5e2,"
"\"p\":3E+4,"
"\"m\":4.25E-1,"
"\"z\":0e0,"
"\"s\":-0.0e+0,"
"\"a\":[6.123456789e3,-1e-9],"
"\"bad\":\"1e3\""
"}");
ASSERT(mg_json_get_num(json, "$.i", &d) == true);
ASSERT(fabs(d - 1000.0) < tolerance);
ASSERT(mg_json_get_num(json, "$.n", &d) == true);
ASSERT(fabs(d - -250.0) < tolerance);
ASSERT(mg_json_get_num(json, "$.p", &d) == true);
ASSERT(fabs(d - 30000.0) < tolerance);
ASSERT(mg_json_get_num(json, "$.m", &d) == true);
ASSERT(fabs(d - 0.425) < tolerance);
ASSERT(mg_json_get_num(json, "$.z", &d) == true);
ASSERT(fabs(d - 0.0) < tolerance);
ASSERT(mg_json_get_num(json, "$.s", &d) == true);
ASSERT(fabs(d - 0.0) < tolerance);
ASSERT(mg_json_get_num(json, "$.a[0]", &d) == true);
ASSERT(fabs(d - 6123.456789) < tolerance);
ASSERT(mg_json_get_num(json, "$.a[1]", &d) == true);
ASSERT(fabs(d - -1e-9) < tolerance);
ASSERT(mg_json_get_num(json, "$.bad", &d) == false);
}
} }
static void resp_rpc(struct mg_rpc_req *r) { static void resp_rpc(struct mg_rpc_req *r) {
@@ -3953,54 +4095,134 @@ static void test_crypto(void) {
test_rsa(); test_rsa();
} }
#define DASHBOARD(x) \
printf("HEALTH_DASHBOARD\t\"%s\": %s,\n", x, s_error ? "false" : "true");
int main(void) { int main(void) {
const char *debug_level = getenv("V"); const char *debug_level = getenv("V");
if (debug_level == NULL) debug_level = "3"; if (debug_level == NULL) debug_level = "3";
mg_log_set(atoi(debug_level)); mg_log_set(atoi(debug_level));
s_error = false;
test_crypto(); test_crypto();
DASHBOARD("crypto");
s_error = false;
test_split(); test_split();
test_json(); test_util();
test_queue();
test_rpc();
test_str(); test_str();
test_match(); test_match();
test_crc32();
DASHBOARD("misc");
s_error = false;
test_json();
DASHBOARD("json");
s_error = false;
test_queue();
DASHBOARD("queue");
s_error = false;
test_rpc();
DASHBOARD("rpc");
s_error = false;
test_check_ip_acl();
DASHBOARD("ip_acl");
s_error = false;
test_udp();
DASHBOARD("udp");
s_error = false;
test_get_header_var(); test_get_header_var();
test_http_get_var();
test_http_parse(); test_http_parse();
test_rewrites(); test_rewrites();
test_check_ip_acl();
test_udp();
test_packed();
test_crc32();
test_multipart(); test_multipart();
test_invalid_listen_addr(); test_invalid_listen_addr();
test_http_chunked(); test_http_chunked();
test_http_upload(); DASHBOARD("http_support");
test_http_stream_buffer();
test_util(); s_error = false;
test_packed();
DASHBOARD("packed_fs");
s_error = false;
test_dns(); test_dns();
DASHBOARD("dns");
s_error = false;
test_timer(); test_timer();
DASHBOARD("timers");
s_error = false;
test_url(); test_url();
DASHBOARD("url");
s_error = false;
test_iobuf(); test_iobuf();
DASHBOARD("iobuf");
s_error = false;
test_base64(); test_base64();
test_http_get_var(); DASHBOARD("base64");
s_error = false;
test_tls(); test_tls();
DASHBOARD("tls");
s_error = false;
test_ws(); test_ws();
test_ws_fragmentation(); test_ws_fragmentation();
DASHBOARD("ws");
s_error = false;
test_http_upload();
test_http_stream_buffer();
test_http_server(); test_http_server();
test_http_404(); test_http_404();
test_http_no_content_length(); test_http_no_content_length();
test_http_pipeline(); test_http_pipeline();
test_http_range(); test_http_range();
DASHBOARD("http_server");
#ifndef LOCALHOST_ONLY #ifndef LOCALHOST_ONLY
s_error = false;
test_sntp(); test_sntp();
DASHBOARD("sntp");
#if MG_TLS != MG_TLS_BUILTIN
s_error = false;
test_mqtt(); // sorry, MQTT_LOCALHOST is also skipped test_mqtt(); // sorry, MQTT_LOCALHOST is also skipped
DASHBOARD("mqtt");
#else
(void) test_mqtt;
#endif
s_error = false;
test_http_client(); test_http_client();
DASHBOARD("http_client");
#else #else
(void) test_sntp, (void) test_mqtt, (void) test_http_client; (void) test_sntp, (void) test_mqtt, (void) test_http_client;
#endif #endif
s_error = false;
test_poll(); test_poll();
printf("SUCCESS. Total tests: %d\n", s_num_tests); printf("HEALTH_DASHBOARD\t\"poll\": %s\n", s_error ? "false" : "true");
// last entry with no comma
#ifdef NO_ABORT
if (s_abort != 0) return EXIT_FAILURE;
#endif
#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000 && \
defined(MBEDTLS_PSA_CRYPTO_C)
// Call mbedtls_psa_crypto_free() here to avoid triggering memory-leak
// detectors. We are actually freeing all our resources and leaving
mbedtls_psa_crypto_free();
#endif
printf("SUCCESS. Total tests: %d\n", s_num_tests);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
+33
View File
@@ -0,0 +1,33 @@
SOURCES = main.c mongoose.c # Source code files
CFLAGS = -W -Wall -Wextra -g -I. # Build options
# O(1) Heap
SOURCES += o1heap/o1heap/o1heap.c
CFLAGS += -Io1heap/o1heap
# Mongoose build options. See https://mongoose.ws/documentation/#build-options
CFLAGS_MONGOOSE += -DMG_ENABLE_CUSTOM_CALLOC
ifeq ($(OS),Windows_NT)
# Windows settings. Assume MinGW compiler. To use VC: make CC=cl CFLAGS=/MD
PROG ?= example.exe # Use .exe suffix for the binary
CC = gcc # Use MinGW gcc compiler
CFLAGS += -lws2_32 # Link against Winsock library
DELETE = cmd /C del /f /q /s # Command prompt command to delete files
else
# Mac, Linux
PROG ?= example
DELETE = rm -rf
endif
all: $(PROG)
$(RUN) ./$(PROG) $(ARGS)
$(PROG): $(SOURCES)
$(CC) $(SOURCES) $(CFLAGS) $(CFLAGS_MONGOOSE) $(CFLAGS_EXTRA) -o $@
o1heap/o1heap/o1heap.c: # O(1) Heap sources
git clone --depth 1 -b 2.1.0 https://github.com/pavel-kirienko/o1heap.git
clean:
$(DELETE) $(PROG) *.o *.obj *.exe *.dSYM
+77
View File
@@ -0,0 +1,77 @@
// Copyright (c) 2025 Cesanta Software Limited
// All rights reserved
#include "mongoose.h"
#include "o1heap.h"
#define POOL_SIZE (5 * MG_IO_SIZE)
O1HeapInstance *s_mem;
// memory allocation
void *mg_calloc(size_t count, size_t size) {
size_t bytes = count * size;
void *ptr = o1heapAllocate(s_mem, bytes);
if (ptr != NULL) memset(ptr, 0, bytes);
if (ptr != NULL) MG_DEBUG(("%lu bytes @%p", bytes, ptr));
if (ptr == NULL) MG_ERROR(("Failed to allocate %lu bytes", bytes));
return ptr;
}
void mg_free(void *ptr) {
o1heapFree(s_mem, ptr);
if (ptr != NULL) MG_DEBUG(("block @%p", ptr));
}
// HTTP request callback
static void fn(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("/hi"), NULL)) {
mg_http_reply(c, 200, "Host: foo.com\r\n", "hi\n");
} else if (mg_match(hm->uri, mg_str("/echo"), NULL)) {
mg_http_reply(c, 200, "", "%.*s", (int) hm->body.len, hm->body.buf);
} else if (mg_match(hm->uri, mg_str("/stats"), NULL)) {
struct mg_connection *t;
mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
mg_http_printf_chunk(c, "ID PROTO TYPE LOCAL REMOTE\n");
for (t = c->mgr->conns; t != NULL; t = t->next) {
mg_http_printf_chunk(c, "%-3lu %4s %s %M %M\n", t->id,
t->is_udp ? "UDP" : "TCP",
t->is_listening ? "LISTENING"
: t->is_accepted ? "ACCEPTED "
: "CONNECTED",
mg_print_ip, &t->loc, mg_print_ip, &t->rem);
}
mg_http_printf_chunk(c, ""); // Don't forget the last empty chunk
} else {
struct mg_http_serve_opts opts;
memset(&opts, 0, sizeof(opts));
opts.root_dir = ".";
mg_http_serve_dir(c, ev_data, &opts);
}
}
}
int main(void) {
struct mg_mgr mgr;
void *pool = malloc(POOL_SIZE + O1HEAP_ALIGNMENT);
void *aligned = (void *) (((uintptr_t) pool) & ~(O1HEAP_ALIGNMENT - 1));
O1HeapDiagnostics d;
s_mem = o1heapInit(aligned, POOL_SIZE);
d = o1heapGetDiagnostics(s_mem);
MG_INFO(
("Created aligned %lu-byte pool @%p, out of a %lu-byte allocated system "
"memory pool",
d.capacity, s_mem, POOL_SIZE));
mg_mgr_init(&mgr); // Initialise event manager
mg_log_set(MG_LL_DEBUG); // Set debug log level
mg_http_listen(&mgr, "http://localhost:8000", fn, NULL); // Create listener
for (;;) { // Event loop
mg_mgr_poll(&mgr, 1000);
}
mg_mgr_free(&mgr);
return 0;
}
+1
View File
@@ -0,0 +1 @@
../../../../mongoose.c
Loaded 100 of 552 files, more files were not shown because too many files have changed in this diff. Show more