forked from espressif/esp-idf
Compare commits
867 Commits
Author | SHA1 | Date | |
---|---|---|---|
2e74914051 | |||
f2490688dc | |||
605c1b16f0 | |||
0c0b503f04 | |||
b368fa45d1 | |||
517dd5c5d5 | |||
4b95b8a5c4 | |||
93c639872b | |||
5fa8c0c088 | |||
8787f15a2d | |||
25ebb55908 | |||
92b98b475d | |||
58b289a22c | |||
69845456dc | |||
dc13a3d161 | |||
48ae2309fd | |||
6a13a9d0c4 | |||
496f749f63 | |||
f06307c08d | |||
b5262e9980 | |||
af03dcb037 | |||
3e1b174c53 | |||
c56aa5f34d | |||
30d6c8401c | |||
edcb5942ba | |||
9b8cdf9e87 | |||
913b31c13f | |||
032f6d34d1 | |||
b04705cfe2 | |||
0423027d5d | |||
1fd8fdcf7d | |||
135b46a078 | |||
1537cff293 | |||
9f1854533e | |||
353f493f22 | |||
192aa18c31 | |||
983e0c7fb2 | |||
217c023a44 | |||
95c572c0d2 | |||
9d4af47fa7 | |||
36130916f0 | |||
ea06260ec9 | |||
953e9a78e2 | |||
716efae251 | |||
c169788dac | |||
4c09277b27 | |||
d33824ac4d | |||
2333795d52 | |||
8bda396582 | |||
19f96b0e4f | |||
617da9f403 | |||
0e6f4ba2cf | |||
5adb8bd0d7 | |||
878e3f8468 | |||
ed21dd43de | |||
47b96db12d | |||
82b868a4b2 | |||
89486da74e | |||
7793f58e71 | |||
f56cd8fb29 | |||
f93fdda2ff | |||
59af9606e6 | |||
b5b629c584 | |||
7dc2e5e545 | |||
4fd1479dc6 | |||
ebf1d15e54 | |||
27e3447eea | |||
47ec40c44f | |||
35f79460a5 | |||
e9dc39730f | |||
0cb48f2f2e | |||
afd3fc6d16 | |||
e634a00ef8 | |||
de49ec5a46 | |||
1772277e98 | |||
75940e9364 | |||
5ab8799f09 | |||
ecd2c51e64 | |||
de8c6aaa8d | |||
ab452839ed | |||
965423d532 | |||
de30298223 | |||
355e152082 | |||
0d3c3a9173 | |||
91c93611e1 | |||
4373a89237 | |||
6adaf783aa | |||
ae7197e882 | |||
3d7666562b | |||
427fe1bcde | |||
cba6f1ae66 | |||
be3b44c92d | |||
8f75f93c14 | |||
3222f0a811 | |||
1d4eb835d0 | |||
60ef790969 | |||
bd4d591b79 | |||
658aaa4f93 | |||
f817971f68 | |||
4333e618b5 | |||
f7169ed063 | |||
acf5333b1e | |||
fa55d3722c | |||
4b47e7e643 | |||
e701c98e27 | |||
42376de238 | |||
c9ebba355f | |||
6785534f63 | |||
1f7172dbf9 | |||
bc3f0c7cdd | |||
ee8a78025c | |||
9c8dfa4ba4 | |||
33f1ad2106 | |||
07465563c5 | |||
7c55633bfb | |||
3c13a480d7 | |||
d5d20920bb | |||
b7791c171d | |||
d25b354cfc | |||
0347b5d043 | |||
47c728adf0 | |||
65b9f87998 | |||
6a9a962083 | |||
758fc73efe | |||
2dc4961063 | |||
dd12e9f8cd | |||
49a99fee56 | |||
1214944e78 | |||
fe485a1ea0 | |||
a2a7ea7012 | |||
96122d6f28 | |||
1fc288556c | |||
8807d8a5d8 | |||
b8ca42400b | |||
ce279af00d | |||
b47e8123ca | |||
4d53269a6d | |||
4b24d3d464 | |||
2ac59cc885 | |||
6e05a56713 | |||
ff75da76e4 | |||
64dc45a2e6 | |||
cf44123da5 | |||
64057d302a | |||
69a48e431e | |||
8080c8d343 | |||
e280541892 | |||
ea9dc928ee | |||
5e600d5b31 | |||
e4ada333cc | |||
00b9df2937 | |||
91430c8674 | |||
4de35f8e1e | |||
df99c92193 | |||
eb78648fa6 | |||
c1d5eafd16 | |||
3a0b4628ce | |||
01f05da3ae | |||
82c6e0628a | |||
f1adfaaced | |||
c836cef1a5 | |||
689fad7372 | |||
df0ed79cd5 | |||
32e8a809f6 | |||
073b45a8aa | |||
ae35d70359 | |||
9c8b2b92ad | |||
a060ee8e9c | |||
de92d7e15f | |||
139afb094e | |||
5b5e46971a | |||
6a1938384a | |||
84a0c67a8c | |||
f022863c35 | |||
7339b019f1 | |||
b9b7750b78 | |||
17f30a4aec | |||
62cc976e0e | |||
95ddb84df1 | |||
c42ee1b790 | |||
4cf65c3533 | |||
9de41781d5 | |||
bde386ab94 | |||
c1fe7fe230 | |||
00d84a3bb2 | |||
3844f6bb84 | |||
8767aa7a4f | |||
4d3715c836 | |||
dc209757b1 | |||
c2c3193209 | |||
2365242391 | |||
18e7da0285 | |||
99115d7e52 | |||
b6c91daa68 | |||
12e882632b | |||
166281238f | |||
29b8f3b719 | |||
e7b70a2f44 | |||
39bf05467a | |||
02872ada4f | |||
3a588d7d19 | |||
0e2045006c | |||
424203e411 | |||
460fc7f546 | |||
5ab41b6c5d | |||
2a09b9d91f | |||
f12d7c5835 | |||
cd4c444af9 | |||
4d08c344bd | |||
951c6cb719 | |||
0e078d9481 | |||
5abe2b059e | |||
58583f187e | |||
8744cb880b | |||
3423cc2937 | |||
306b035a51 | |||
ffe43f2c45 | |||
ecc86b3f22 | |||
6ff1d8c828 | |||
0da3b397f2 | |||
70912cb4b2 | |||
d42499a5db | |||
46144f7093 | |||
9175c9b706 | |||
b2d728075d | |||
beba6f954c | |||
1d23b83d3b | |||
9b014138bf | |||
4657069afd | |||
b67e388281 | |||
5186a968be | |||
418fed12df | |||
5d4e084669 | |||
a79a8e4215 | |||
e080f43245 | |||
698964f4b9 | |||
c93298c31d | |||
2ee5178667 | |||
d09f6cac24 | |||
1f2af24118 | |||
b007024c62 | |||
63e489255f | |||
1d05bb7c01 | |||
4e120e36eb | |||
2c9d8ac64e | |||
a59eccdd9e | |||
7406312f11 | |||
15dcd2eca1 | |||
3b88d9231b | |||
2fb93e6a54 | |||
8534799d66 | |||
e6115da7e9 | |||
97f007c08c | |||
976594b853 | |||
efb4784d78 | |||
6d708d50d9 | |||
6ee42ba036 | |||
83e9c1d28d | |||
6a50197246 | |||
2d439ba001 | |||
54ae758b77 | |||
99af5e9a71 | |||
362c9234dc | |||
9f6e09d0d3 | |||
fafaeb195c | |||
c5fc90f579 | |||
fe9ecf2f7a | |||
a6b1fda209 | |||
7182219718 | |||
e55985335d | |||
b2dfa2ed85 | |||
46d04231e6 | |||
1c0fb793b4 | |||
dd73ba9601 | |||
49c6b790c6 | |||
6203a22e2c | |||
c250bbc3fb | |||
8c909d3319 | |||
2060f63130 | |||
5f184c6556 | |||
b6826d8878 | |||
51aaf310fd | |||
84e4127f0c | |||
694f7e349f | |||
e9fd883f50 | |||
36cb29280a | |||
f819a4fffa | |||
cf3445db01 | |||
ef6910467c | |||
4d20919ff3 | |||
777907f8ef | |||
1508b9ff03 | |||
92a5c34a61 | |||
5c3d5faeff | |||
9249f05fc9 | |||
cb8d4585b2 | |||
850d8170f5 | |||
f2676b8e59 | |||
21b3068b77 | |||
b5256118ff | |||
9d50e27aff | |||
f40f6b4bb1 | |||
a213b289be | |||
6300f7791a | |||
a6f4f7399a | |||
3e28c250d7 | |||
a75b53954b | |||
0c3173874e | |||
b3d17474d6 | |||
c0c0497de3 | |||
94f447f599 | |||
fdec7348e2 | |||
054770407e | |||
7e8afda8b2 | |||
d8966087b1 | |||
a45fa929c2 | |||
2baf0e626a | |||
c0e07f8975 | |||
6507d1d892 | |||
0b2f0a3213 | |||
4c8ae4fd56 | |||
e660e32a6e | |||
9fde997b5c | |||
f50a8cc7b5 | |||
21dfe81a68 | |||
28010d4ef7 | |||
09d7409f44 | |||
ce9f195abe | |||
05f780cdb2 | |||
528d162da5 | |||
6fe2da9f89 | |||
381464d1cf | |||
04e4bdcff5 | |||
2a6e69c9f3 | |||
9ac6b53760 | |||
9c7d2c7595 | |||
1903d8587a | |||
e86ca4edc2 | |||
c9646ff0be | |||
b6bea34706 | |||
88c2b69c68 | |||
94a54d574b | |||
84b157e2ea | |||
22a02656b7 | |||
cde3860d21 | |||
c7de165ccb | |||
b53d874dac | |||
186fcc328b | |||
e900224343 | |||
a560a506f2 | |||
57442c38bd | |||
7e4f7867f0 | |||
5395f451a2 | |||
b41108b60a | |||
f0679fe175 | |||
b7ab286edf | |||
0e904b3f7e | |||
9dafde59b1 | |||
1967e53f4a | |||
98c20ce417 | |||
1c875e5baa | |||
d376c161aa | |||
9e2ce84a9a | |||
b66b98a25f | |||
9596f0d966 | |||
a3856c5438 | |||
58a3e08895 | |||
24035f698d | |||
ac362cc662 | |||
a29fe72cc9 | |||
4de9ba152a | |||
03a6c4975c | |||
415418cf0e | |||
0cca9e860d | |||
a573cfe58a | |||
7d1fe0b553 | |||
f2f6acd6a6 | |||
e66fec955e | |||
a9a8fd03b6 | |||
8efb2bb1ed | |||
c270a9f0b9 | |||
23b6e47aef | |||
390bdf2f78 | |||
6be10fab09 | |||
aa33c43644 | |||
2b19bd0c2f | |||
de0063164d | |||
acb05c21d9 | |||
93aee41c29 | |||
798aab5097 | |||
4db80bcc78 | |||
e97ddd80b7 | |||
2647288d32 | |||
a75a988c98 | |||
f00db86668 | |||
c7a10f9293 | |||
7095159a4c | |||
2644f793bd | |||
848f931e06 | |||
d5e2a482c3 | |||
36d7af5200 | |||
410a0a5f5a | |||
7478d96228 | |||
644e653293 | |||
53956cf8ad | |||
effee74b2f | |||
08c5b89096 | |||
e6f96717ff | |||
db49804f65 | |||
ed76cc4dd4 | |||
d51ed40487 | |||
31b142cf93 | |||
d95e2c63ca | |||
cdec9f3659 | |||
02e742271d | |||
5ec69efafa | |||
42657a7464 | |||
f16ec53183 | |||
3299a19c2f | |||
a3ae9ae482 | |||
a6b169f91e | |||
deeb517b72 | |||
874b470379 | |||
38aa99d63d | |||
a37c20b417 | |||
fd5d6db71e | |||
1957025f4a | |||
6d2bdfc5f5 | |||
d651e4e073 | |||
5fc3c0ca91 | |||
2e64d234c4 | |||
229fab87a5 | |||
e45be4dd4a | |||
f6d96f33bb | |||
228f875ada | |||
997c07c2ee | |||
dca229df07 | |||
831d470a75 | |||
b7707c54ce | |||
375f969d43 | |||
c29dbda5fd | |||
788312a009 | |||
6c9005e11b | |||
d30ec8c94e | |||
658a0acdbe | |||
4c974574d7 | |||
6ee835f6ea | |||
69b740dc5e | |||
2ecc8fad50 | |||
467c7af33e | |||
6121046090 | |||
4c113a0c0c | |||
ad759ee5a7 | |||
24af403dac | |||
469bb082d7 | |||
80e381e511 | |||
847273d0fb | |||
6d32eec165 | |||
6dc067dda7 | |||
0ddf00c6e1 | |||
8c6705ded5 | |||
a480a00237 | |||
2f603a56a7 | |||
2bffeb7265 | |||
9c872b1851 | |||
b2c18de9b3 | |||
f684bd10f5 | |||
9da031e0c3 | |||
64de7ee38c | |||
52d9d466fb | |||
a4a7e7b3e9 | |||
fbc6f27e81 | |||
31c396c127 | |||
a87f5c6c02 | |||
20993109e8 | |||
6c38cc736a | |||
193b60afcf | |||
e4d84804c1 | |||
e4ebaca693 | |||
3f358236f0 | |||
ba1ce2ebd0 | |||
aad1f7abde | |||
29ad86ed5b | |||
dede31cd83 | |||
d592a9863b | |||
f89f5b7f75 | |||
07291fdd27 | |||
00801c8044 | |||
b8e31efcac | |||
819ac7f847 | |||
46ab19818a | |||
b9038d045e | |||
ae72870d43 | |||
4d1aaed682 | |||
6059ef26fb | |||
5fa34f6a30 | |||
56a3845986 | |||
2c153af57a | |||
18d7d9497a | |||
38db3d9507 | |||
42ae0166d7 | |||
eff7fd9052 | |||
275743ab1c | |||
8a39b5237d | |||
5e9aa539ea | |||
6f3b1a0554 | |||
d0e0f80bd0 | |||
ecb01b28c4 | |||
1b82e9604c | |||
26139daaf5 | |||
f9831301ce | |||
cfb84d3381 | |||
952e47d45d | |||
ed6a0c324c | |||
c6ca4e3e88 | |||
999f648a35 | |||
9bf4d44235 | |||
50e3f9f66c | |||
613201c24d | |||
1166bc5680 | |||
02170d815e | |||
6e06d323b1 | |||
d7a793f406 | |||
85e0728700 | |||
3fb1165e4e | |||
34140d2a00 | |||
face9518b2 | |||
5f1887b3ca | |||
d8c4ab482b | |||
94ed8f8606 | |||
cdcb85fd70 | |||
a67793e9fc | |||
182c2eda48 | |||
1d218485ec | |||
257047c073 | |||
83358061df | |||
47e4386953 | |||
60bf9d30b2 | |||
e8282fb5c5 | |||
5a5327e77e | |||
5580d578bd | |||
759e4340a9 | |||
949a3cd61a | |||
ac9bd8bcc4 | |||
e45ce5c058 | |||
44b81cb280 | |||
b24671e935 | |||
d41781099a | |||
6403a229eb | |||
98ad8cc2e3 | |||
afc2f9b5d3 | |||
f2e222a8f8 | |||
bdce35c3d7 | |||
7d7ad29d5a | |||
905293a6c9 | |||
6587ff6110 | |||
991d0b8c31 | |||
2290d0385e | |||
4f04f48a70 | |||
2a7df3bcd8 | |||
67b09d3db5 | |||
5717f8f2fb | |||
fe2f3bfe1e | |||
e2af75b5e4 | |||
a17b57b062 | |||
df0c1a1285 | |||
662b6bb48a | |||
3d0a386c10 | |||
9ed4e06dd2 | |||
ededfb47b9 | |||
6f47a4e0a6 | |||
2335e5026f | |||
2bd0e9371a | |||
fead8b8a06 | |||
e9cf9e2978 | |||
6463dd9630 | |||
c9f1b55287 | |||
e16ec9a574 | |||
a7994b1a42 | |||
c725aa3ec1 | |||
3687ae989b | |||
16cf160d57 | |||
58160d46c6 | |||
776906dc84 | |||
891a17ea62 | |||
bd03a0e66a | |||
eab4e6fedd | |||
03d504dbb2 | |||
8e8737c128 | |||
3a5d9d9431 | |||
693aaef039 | |||
7703fcbd8d | |||
9a7deae742 | |||
84dc42c4b0 | |||
d7e680828a | |||
da47503c14 | |||
e490fdafbe | |||
94e3141a32 | |||
fd34406960 | |||
4544b709e5 | |||
a95c1c302d | |||
1ef91c72e2 | |||
90696dad89 | |||
e310fb1393 | |||
71de11e89d | |||
bda9e1fda7 | |||
97df333a3b | |||
6dfff2fdbd | |||
2ed3e8b344 | |||
58a7d9f239 | |||
e4dd9053c2 | |||
ff5e0d0d38 | |||
03b0540bc6 | |||
17e30c9e89 | |||
00cfcde385 | |||
0839fd08dd | |||
626964beae | |||
220f3d2198 | |||
904933745b | |||
ea4a8d5e4f | |||
10cce6b74a | |||
e36e433519 | |||
76ff1724b3 | |||
9f1ae278e0 | |||
54908d3a42 | |||
19b90e8ba9 | |||
a5e27d73a5 | |||
1e6a6ffa0d | |||
dbf2a64adb | |||
11970e65a1 | |||
3b8c7bdf0b | |||
670b057b04 | |||
ae3b4819da | |||
b0684e8b3c | |||
322cba0bf0 | |||
f5c6595cb4 | |||
02de1a8071 | |||
e9e2b68587 | |||
73d40cb813 | |||
bf6ddf2557 | |||
d761226f36 | |||
5036ec363b | |||
c724236623 | |||
f7034e7767 | |||
7e75d7f748 | |||
e5437afa7f | |||
319eecc793 | |||
d17923151b | |||
0a0b3bb23f | |||
2a5cf2c3e0 | |||
ae15a0cab8 | |||
0c7f286a87 | |||
3e26049a05 | |||
dece3abd9c | |||
1af5bc2f7d | |||
278cfc2047 | |||
1790aa6bc6 | |||
b75a5fd03a | |||
cbf2858450 | |||
868c96c59f | |||
60d5dcb000 | |||
62787fc277 | |||
9e97133481 | |||
c9087c205b | |||
736b87db6d | |||
c2eaa3d844 | |||
2a715c811b | |||
17aa9c5ec4 | |||
c93211db62 | |||
be56456add | |||
413bbe4de4 | |||
4906779d50 | |||
7d5d57ec03 | |||
67a1858bb1 | |||
fb9de62f74 | |||
f48346f22f | |||
79ce133ed7 | |||
a59a5cb2cc | |||
2d26c24e3a | |||
2792c333bc | |||
7c5e920c37 | |||
d4ac30a978 | |||
2596c7e2cc | |||
e6b7c933d5 | |||
8fe99aff96 | |||
4866027391 | |||
a6ed4611a2 | |||
d457641f90 | |||
1509264f2e | |||
271b84f5b6 | |||
f1be501271 | |||
ea20966c29 | |||
f25c996b06 | |||
745bb2123f | |||
143bb1edf4 | |||
f1737a630d | |||
83087f15fa | |||
a9d1d44d4d | |||
72b27f1782 | |||
8e482c9423 | |||
1fb45977fa | |||
257728feab | |||
26d362040e | |||
f6a794cf51 | |||
974db3016b | |||
9c4c377f2d | |||
e6b8bc6ecb | |||
718f296587 | |||
6c74618bff | |||
974f345316 | |||
f2ca74b139 | |||
ac8ea9e9e5 | |||
48890daab1 | |||
f1aabb2894 | |||
cc8ef3660a | |||
67402f035f | |||
7dd5568cb7 | |||
f00d7ee9d0 | |||
dba5597edf | |||
5019a6571e | |||
4f8d784753 | |||
a697377871 | |||
6ceee165b5 | |||
4a20f68f5c | |||
8ec0ffe751 | |||
5d0ce8b52f | |||
2313683b58 | |||
c41822dc7c | |||
21909d7823 | |||
651a939643 | |||
3bf9d389ef | |||
6238c49479 | |||
fe1126cccb | |||
4725249385 | |||
6cfef8ce93 | |||
a643ea9432 | |||
f54dfe2912 | |||
c2ba180de3 | |||
d6f76f8a5f | |||
1d778c941c | |||
87b613fd2f | |||
f5f7d21c83 | |||
502a819757 | |||
802a01c0b7 | |||
a479ee30c9 | |||
46e85ed021 | |||
0862fe815b | |||
918875424e | |||
5490c0a243 | |||
a71d9cc466 | |||
c75a8b11bb | |||
9c884b3ba9 | |||
9a2d251912 | |||
3b9af23290 | |||
ff12b50e45 | |||
f6336516d1 | |||
4d80dd1238 | |||
8a2155f95e | |||
367190deaf | |||
dbb632fe34 | |||
1329747dc1 | |||
f9e1942252 | |||
82ffb33085 | |||
9fd12182de | |||
d42958439d | |||
37946ab300 | |||
2b7a3f6d85 | |||
60642e580c | |||
4235e80008 | |||
a8e0989648 | |||
28f50addda | |||
9393a402eb | |||
268787c5fb | |||
d92ac450a2 | |||
233f3f80e5 | |||
d01efe4b8c | |||
e48935d187 | |||
12bbd1f051 | |||
0305d13467 | |||
e6ace495b4 | |||
b449909b35 | |||
0253d825e9 | |||
32b0836485 | |||
7dca6b7428 | |||
b180c2a146 | |||
113bf479a4 | |||
774f010196 | |||
22a8fe5b6f | |||
d36c72fba0 | |||
1c8fd4041e | |||
d4263c2558 | |||
ea49545269 | |||
9ca05c17ae | |||
fd93c475b6 | |||
27c72a4105 | |||
5c8b1d6ab8 | |||
c5f8fbea02 | |||
cf7891cb93 | |||
1e77586120 | |||
1ea548ecb3 | |||
962ea61d53 | |||
d61ee580d5 | |||
947e445e02 | |||
1821fd766b | |||
d508182429 | |||
58c9a2eaba | |||
07b62da0d4 | |||
fb82bdb9da | |||
f3be9976b9 | |||
b639514793 | |||
f12b571f82 | |||
c0f06115d4 | |||
20b25a9667 | |||
1d9d444c07 | |||
060a829091 | |||
78314df2a5 | |||
8ceb462993 | |||
6accffecea | |||
de79e482c9 | |||
6638b81f8e | |||
d92b647199 | |||
965daf977a | |||
aa652adc12 | |||
5795075460 | |||
198d350fe5 | |||
24f3341a2d | |||
5a429f644f | |||
9aae8e0ce3 | |||
e5e47ebae6 | |||
436c3c289e | |||
2aa6aa8b88 | |||
3e9cd49d32 | |||
2c1845995b | |||
0c77299c34 | |||
9ac3e7c5d1 | |||
c42ce05941 | |||
ea2eb9d833 | |||
dec52a93d4 | |||
41bee7831f | |||
bd1b4dbda1 | |||
1de12526eb | |||
f0f2799946 | |||
5aabdd8abf | |||
8a2f91b48a | |||
ed6fb33726 | |||
66d10f0eec | |||
97f248d22c | |||
ffc4ff5a8c | |||
326d76ebdf | |||
c6ed522d60 | |||
8e187e7157 | |||
19f18aaa11 | |||
626a861115 | |||
a0fdf4b06c | |||
3d9523724d | |||
813b6c4ef6 | |||
1b849d59de | |||
87576aba28 | |||
57fb076590 | |||
360e7c4d51 | |||
9083ef97e5 | |||
a7a1e4dfba | |||
8ad92a92b9 | |||
321ee21c4c | |||
33820657c5 | |||
33892aadb9 | |||
ad669801ae |
17
.github/workflows/release_zips.yml
vendored
Normal file
17
.github/workflows/release_zips.yml
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
name: Create zip file with recursive source clone for release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*
|
||||
|
||||
jobs:
|
||||
release_zips:
|
||||
name: Create release zip file
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Create a recursive clone source zip
|
||||
uses: espressif/github-actions/release_zips@master
|
||||
env:
|
||||
RELEASE_PROJECT_NAME: ESP-IDF
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
8
.gitmodules
vendored
8
.gitmodules
vendored
@ -7,8 +7,8 @@
|
||||
path = components/esptool_py/esptool
|
||||
url = ../../espressif/esptool.git
|
||||
|
||||
[submodule "components/bt/controller/lib"]
|
||||
path = components/bt/controller/lib
|
||||
[submodule "components/bt/controller/lib_esp32"]
|
||||
path = components/bt/controller/lib_esp32
|
||||
url = ../../espressif/esp32-bt-lib.git
|
||||
|
||||
[submodule "components/bootloader/subproject/components/micro-ecc/micro-ecc"]
|
||||
@ -90,3 +90,7 @@
|
||||
[submodule "components/cmock/CMock"]
|
||||
path = components/cmock/CMock
|
||||
url = ../../ThrowTheSwitch/CMock.git
|
||||
|
||||
[submodule "components/bt/controller/lib_esp32c3_family"]
|
||||
path = components/bt/controller/lib_esp32c3_family
|
||||
url = ../../espressif/esp32c3-bt-lib.git
|
||||
|
2
Kconfig
2
Kconfig
@ -154,7 +154,7 @@ mainmenu "Espressif IoT Development Framework Configuration"
|
||||
mon reset halt
|
||||
# Run to a specific point in ROM code,
|
||||
# where most of initialization is complete.
|
||||
thb *0x40007901
|
||||
thb *0x40007d54
|
||||
c
|
||||
# Load the application into RAM
|
||||
load
|
||||
|
16
README.md
16
README.md
@ -2,20 +2,15 @@
|
||||
|
||||
* [中文版](./README_CN.md)
|
||||
|
||||
ESP-IDF is the official development framework for the **ESP32** and **ESP32-S** Series SoCs provided for Windows, Linux and macOS.
|
||||
ESP-IDF is the development framework for Espressif SoCs (released after 2016<sup>[1](#fn1)</sup>) provided for Windows, Linux and macOS.
|
||||
|
||||
# Developing With ESP-IDF
|
||||
|
||||
## Setting Up ESP-IDF
|
||||
|
||||
See setup guides for detailed instructions to set up the ESP-IDF:
|
||||
See https://idf.espressif.com/ for links to detailed instructions on how to set up the ESP-IDF depending on chip you use.
|
||||
|
||||
| Chip | Getting Started Guides for ESP-IDF |
|
||||
|:----:|:----|
|
||||
| <img src="docs/_static/chip-esp32.svg" height="85" alt="ESP32"> | <ul><li>[stable](https://docs.espressif.com/projects/esp-idf/en/stable/get-started/) version</li><li>[latest (master branch)](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/) version</li></ul> |
|
||||
| <img src="docs/_static/chip-esp32-s2.svg" height="100" alt="ESP32-S2"> | <ul><li>[latest (master branch)](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/get-started/) version</li></ul> |
|
||||
|
||||
**Note:** Each ESP-IDF release has its own documentation. Please see Section [Versions](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/versions.html) how to find documentation and how to checkout specific release of ESP-IDF.
|
||||
**Note:** Each SoC series and each ESP-IDF release has its own documentation. Please see Section [Versions](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/versions.html) on how to find documentation and how to checkout specific release of ESP-IDF.
|
||||
|
||||
### Non-GitHub forks
|
||||
|
||||
@ -70,7 +65,7 @@ You don't need to run `idf.py build` before running `idf.py flash`, `idf.py flas
|
||||
|
||||
## Viewing Serial Output
|
||||
|
||||
The `idf.py monitor` target uses the [idf_monitor tool](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/idf-monitor.html) to display serial output from ESP32 or ESP32-S Series SoCs. idf_monitor also has a range of features to decode crash output and interact with the device. [Check the documentation page for details](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/idf-monitor.html).
|
||||
The `idf.py monitor` target uses the [idf_monitor tool](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/idf-monitor.html) to display serial output from Espressif SoCs. idf_monitor also has a range of features to decode crash output and interact with the device. [Check the documentation page for details](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/idf-monitor.html).
|
||||
|
||||
Exit the monitor by typing Ctrl-].
|
||||
|
||||
@ -106,3 +101,6 @@ This can be combined with other targets, ie `idf.py -p PORT erase_flash flash` w
|
||||
* If you're interested in contributing to ESP-IDF, please check the [Contributions Guide](https://docs.espressif.com/projects/esp-idf/en/latest/contribute/index.html).
|
||||
|
||||
|
||||
________
|
||||
|
||||
<a name="fn1">1</a>: ESP8266 and ESP8285 are not supported in ESP-IDF. See [RTOS SDK](https://github.com/espressif/ESP8266_RTOS_SDK) instead.
|
61
README_CN.md
61
README_CN.md
@ -2,26 +2,22 @@
|
||||
|
||||
* [English Version](./README.md)
|
||||
|
||||
ESP-IDF 是由乐鑫官方推出的针对 **ESP32** 和 **ESP32-S2** 系列芯片的开发框架。
|
||||
ESP-IDF 是由乐鑫官方针对乐鑫各系列芯片产品(发布于 2016 年后<sup>[1](#fn1)</sup>)推出的开发框架,支持 Windows、Linux 和 macOS 操作系统。
|
||||
|
||||
# 使用 ESP-IDF 进行开发
|
||||
|
||||
## 搭建 ESP-IDF 开发环境
|
||||
|
||||
请参阅如下指南搭建 ESP-IDF 的开发环境:
|
||||
|
||||
| 芯片 | ESP-IDF 入门指南 |
|
||||
|:----:|:----|
|
||||
| <img src="docs/_static/chip-esp32.svg" height="85" alt="ESP32"> | <ul><li>[稳定](https://docs.espressif.com/projects/esp-idf/zh_CN/stable/get-started/) 版</li><li>[最新(master 分支)](https://docs.espressif.com/projects/esp-idf/zh_CN/latest/get-started/) 版本</li></ul> |
|
||||
| <img src="docs/_static/chip-esp32-s2.svg" height="100" alt="ESP32-S2"> | <ul><li>[最新(master 分支)](https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32s2/get-started/) 版本</li></ul> |
|
||||
|
||||
**注意:** 每个 ESP-IDF 版本都有其对应的文档。 请参阅 [版本](https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/versions.html) 部分,如何查找文档以及如何检出ESP-IDF的特定发行版。
|
||||
关于不同芯片如何搭建 ESP-IDF 的开发环境,请参考 https://idf.espressif.com/。
|
||||
|
||||
**注意:** 不同系列芯片和不同 ESP-IDF 版本都有其对应的文档。请参阅[版本](https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/versions.html)部分,获得关于如何查找文档以及如何检出 ESP-IDF 的特定发行版的详细信息。
|
||||
|
||||
### 非 GitHub 分叉的 ESP-IDF 项目
|
||||
|
||||
ESP-IDF 中的子模块采用相对路径([详见 .gitmodules 文件](.gitmodules)),所以它们会指向 GitHub。
|
||||
如果 ESP-IDF 被分叉到的仓库不在 GitHub 上,那么你需要在克隆结束后运行该[脚本](tools/set-submodules-to-github.sh)。它会为所有的子模块设置绝对路径,接着可以通过 `git submodule update --init --recursive` 完成子模块的更新。
|
||||
如果 ESP-IDF 被分叉到的仓库不在 GitHub 上,那么你需要在克隆结束后运行该脚本 [tools/set-submodules-to-github.sh](tools/set-submodules-to-github.sh)。
|
||||
|
||||
这个脚本会为所有的子模块设置绝对路径,接着可以通过 `git submodule update --init --recursive` 完成子模块的更新。
|
||||
如果 ESP-IDF 是从 GitHub 上克隆得到,则不需要此步骤。
|
||||
|
||||
## 寻找项目
|
||||
@ -38,24 +34,16 @@ ESP-IDF 中的子模块采用相对路径([详见 .gitmodules 文件](.gitmodu
|
||||
|
||||
## 设置构建环境
|
||||
|
||||
(请参考入门指南中列出的详细步骤。)
|
||||
* 在主机中安装入门指南中提到的构建所依赖的工具。
|
||||
* 将 ESP-IDF 中的 `tools/` 目录加入 PATH 环境变量中。
|
||||
* 运行 `python -m pip install -r requirements.txt` 安装 Python 依赖库。
|
||||
请参考入门指南中列出的详细步骤。
|
||||
|
||||
* 在主机中安装入门指南中提到的构建所依赖的工具。
|
||||
* 运行安装脚本来设置构建环境。可为 Windows shell 选择 `install.bat` 或 `install.ps1`,为 Unix shell 选择 `install.sh` 和 `install.fish`。
|
||||
* 在使用 ESP-IDF 之前,需要在 shell 中运行导出脚本。Windows 下可运行 `export.bat`,Unix 下可运行 `source export.sh`。
|
||||
|
||||
## 配置项目
|
||||
|
||||
`idf.py menuconfig`
|
||||
|
||||
* 打开项目的文本配置菜单。
|
||||
* 使用上下键浏览菜单。
|
||||
* 使用回车键进入子菜单,退出键返回上一级菜单或者退出配置。
|
||||
* 输入 `?` 查看帮助界面,按下回车键可以退出帮助界面。
|
||||
* 使用空格键或者 `Y` 和 `N` 按键来启用和禁用带复选框“`[*]`”的配置项。
|
||||
* 高亮某个配置项的同时按下 `?` 键可以显示该选项的帮助文档。
|
||||
* 输入 `/` 可以搜索指定的配置项。
|
||||
|
||||
一旦配置完成,请按下退出键多次以退出配置界面,当提示是否保存新的的配置时,选择 “Yes”。
|
||||
* `idf.py set-target <chip_name>` 可将项目的目标芯片设置为 `<chip_name>`。运行 `idf.py set-target`,不用带任何参数,可查看所有支持的目标芯片列表。
|
||||
* `idf.py menuconfig` 可打开一个基于文本的配置菜单,可以用来对项目进行配置。
|
||||
|
||||
## 编译项目
|
||||
|
||||
@ -65,23 +53,23 @@ ESP-IDF 中的子模块采用相对路径([详见 .gitmodules 文件](.gitmodu
|
||||
|
||||
## 烧写项目
|
||||
|
||||
当构建结束,终端会打印出一条命令行,告知如何使用 esptool.py 工具烧写项目到芯片中。但是你还可以运行下面这条命令来自动烧写:
|
||||
当构建结束,终端会打印出一条命令行,告知如何使用 esptool.py 工具烧写项目到芯片中。但你也可以运行下面这条命令来自动烧写:
|
||||
|
||||
`idf.py -p PORT flash`
|
||||
|
||||
将其中的 PORT 替换为系统中实际串口的名字(比如 Windows 下的 `COM3`,Linux 下的 `/dev/ttyUSB0`,或者 MacOS 下的 `/dev/cu.usbserial-X`。如果省略 `-p` 选项,`idf.py flash` 会尝试使用第一个可用的串口进行烧写。
|
||||
将其中的 PORT 替换为系统中实际串口的名字(比如 Windows 下的 `COM3`,Linux 下的 `/dev/ttyUSB0`,或者 macOS 下的 `/dev/cu.usbserial-X`。如果省略 `-p` 选项,`idf.py flash` 会尝试使用第一个可用的串口进行烧写。
|
||||
|
||||
这会烧写整个项目(包括应用程序,引导程序和分区表)到芯片中,此外还可以使用 `idf.py menuconfig` 来调整串口烧写相关的配置。
|
||||
|
||||
你也不必先运行 `idf.py build`,再运行 `idf.py flash`,`idf.py flash` 会根据需要自动重新构建项目。
|
||||
不必先运行 `idf.py build` 再运行 `idf.py flash`,`idf.py flash` 会根据需要自动重新构建项目。
|
||||
|
||||
## 观察串口输入
|
||||
|
||||
`idf.py monitor` 会调用 [idf_monitor 工具](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/idf-monitor.html)来显示 ESP32 和 ESP32-S2 的串口输出。`idf_monitor` 还包含一系列的功能来解析程序崩溃后的输出结果并与设备进行交互。更多详细内容,请参阅[文档](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/idf-monitor.html).
|
||||
`idf.py monitor` 会调用 [idf_monitor 工具](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/idf-monitor.html)来显示乐鑫芯片的串口输出。`idf_monitor` 还包含一系列的功能来解析程序崩溃后的输出结果并与设备进行交互。更多详细内容,请参阅[文档](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/idf-monitor.html).
|
||||
|
||||
输入 `Ctrl-]` 可退出监视器。
|
||||
|
||||
想要一次性执行构建,烧写和监视,可以运行如下命令:
|
||||
想要一次性执行构建、烧写和监视,可以运行如下命令:
|
||||
|
||||
`idf.py flash monitor`
|
||||
|
||||
@ -92,24 +80,27 @@ ESP-IDF 中的子模块采用相对路径([详见 .gitmodules 文件](.gitmodu
|
||||
* `idf.py app` - 仅构建应用程序。
|
||||
* `idf.py app-flash` - 仅烧写应用程序。
|
||||
|
||||
`idf.py app-flash` 会自动判断是否有源文件发生了改变而后重新构建应用程序。
|
||||
`idf.py app-flash` 会自动判断是否有源文件发生了改变然后重新构建应用程序。
|
||||
|
||||
(在正常的开发中,即使引导程序和分区表没有发生变化,每次都重新烧写它们并不会带来什么危害。)
|
||||
|
||||
## 擦除 Flash
|
||||
|
||||
`idf.py flash` 并不会擦除 Flash 上所有的内容,但是有时候我们需要设备恢复到完全擦除的状态,尤其是分区表发生了变化或者 OTA 应用升级。要擦除整块 Flash 请运行 `idf.py erase_flash`。
|
||||
`idf.py flash` 并不会擦除 flash 上所有的内容,但是有时候我们需要设备恢复到完全擦除的状态,尤其是分区表发生了变化或者 OTA 应用升级时。要擦除整块 flash 请运行 `idf.py erase_flash`。
|
||||
|
||||
这条命令还可以和其余命令整合在一起,`idf.py -p PORT erase_flash flash` 会擦除一切然后重新烧写新的应用程序,引导程序和分区表。
|
||||
这条命令还可以和其余命令整合在一起,`idf.py -p PORT erase_flash flash` 会擦除一切然后重新烧写新的应用程序、引导程序和分区表。
|
||||
|
||||
# 其它参考资源
|
||||
|
||||
* 最新版的文档:https://docs.espressif.com/projects/esp-idf/ ,该文档是由本仓库 [docs 目录](docs) 构建得到。
|
||||
* 最新版的文档:https://docs.espressif.com/projects/esp-idf/,该文档是由本仓库 [docs 目录](docs) 构建得到。
|
||||
|
||||
* 可以前往 [esp32.com 论坛](https://esp32.com/) 提问,挖掘社区资源。
|
||||
|
||||
* 如果你在使用中发现了错误或者需要新的功能,请先[查看 GitHub Issues](https://github.com/espressif/esp-idf/issues),确保该问题不会被重复提交。
|
||||
* 如果你在使用中发现了错误或者需要新的功能,请先[查看 GitHub Issues](https://github.com/espressif/esp-idf/issues),确保该问题没有重复提交。
|
||||
|
||||
* 如果你有兴趣为 ESP-IDF 作贡献,请先阅读[贡献指南](https://docs.espressif.com/projects/esp-idf/en/latest/contribute/index.html)。
|
||||
|
||||
|
||||
__________
|
||||
|
||||
<a name="fn1">1</a>: ESP-IDF 不支持 ESP8266 和 ESP8285。如有需要,请参考 [RTOS SDK](https://github.com/espressif/ESP8266_RTOS_SDK)。
|
@ -33,10 +33,14 @@ idf_component_register(SRCS "${srcs}"
|
||||
PRIV_REQUIRES soc
|
||||
LDFRAGMENTS linker.lf)
|
||||
|
||||
# disable --coverage for this component, as it is used as transport
|
||||
# for gcov
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-fno-profile-arcs" "-fno-test-coverage")
|
||||
|
||||
# Force app_trace to also appear later than gcov in link line
|
||||
idf_component_get_property(app_trace app_trace COMPONENT_LIB)
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE $<TARGET_FILE:${app_trace}> gcov $<TARGET_FILE:${app_trace}> c)
|
||||
if(CONFIG_APPTRACE_GCOV_ENABLE)
|
||||
# disable --coverage for this component, as it is used as transport
|
||||
# for gcov
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-fno-profile-arcs" "-fno-test-coverage")
|
||||
|
||||
# Force app_trace to also appear later than gcov in link line
|
||||
idf_component_get_property(app_trace app_trace COMPONENT_LIB)
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE
|
||||
"-Wl,--undefined=gcov_rtio_atexit" $<TARGET_FILE:${app_trace}> gcov $<TARGET_FILE:${app_trace}> c)
|
||||
endif()
|
||||
|
@ -8,11 +8,7 @@ COMPONENT_ADD_INCLUDEDIRS = include
|
||||
|
||||
COMPONENT_ADD_LDFLAGS = -lapp_trace
|
||||
|
||||
# do not produce gcov info for this module, it is used as transport for gcov
|
||||
CFLAGS := $(subst --coverage,,$(CFLAGS))
|
||||
|
||||
ifdef CONFIG_SYSVIEW_ENABLE
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS += \
|
||||
sys_view/Config \
|
||||
sys_view/SEGGER \
|
||||
@ -26,7 +22,12 @@ COMPONENT_SRCDIRS += \
|
||||
sys_view/esp32 \
|
||||
sys_view/ext
|
||||
else
|
||||
ifdef CONFIG_APPTRACE_GCOV_ENABLE
|
||||
# do not produce gcov info for this module, it is used as transport for gcov
|
||||
CFLAGS := $(subst --coverage,,$(CFLAGS))
|
||||
COMPONENT_ADD_LDFLAGS += -Wl,--undefined=gcov_rtio_atexit
|
||||
COMPONENT_SRCDIRS += gcov
|
||||
endif
|
||||
endif
|
||||
|
||||
COMPONENT_ADD_LDFRAGMENTS += linker.lf
|
||||
|
@ -9,7 +9,7 @@ entries:
|
||||
SEGGER_SYSVIEW_Config_FreeRTOS (noflash)
|
||||
SEGGER_SYSVIEW_FreeRTOS (noflash)
|
||||
|
||||
[mapping:driver]
|
||||
[mapping:app_trace_driver]
|
||||
archive: libdriver.a
|
||||
entries:
|
||||
if SYSVIEW_TS_SOURCE_TIMER_00 = y || SYSVIEW_TS_SOURCE_TIMER_01 = y
|
||||
|
@ -41,16 +41,6 @@
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_attr.h"
|
||||
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
#include "esp32/rom/crc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/crc.h"
|
||||
#include "esp32s2/rom/secure_boot.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#include "esp32c3/rom/crc.h"
|
||||
#include "esp32c3/rom/secure_boot.h"
|
||||
#endif
|
||||
|
||||
#define SUB_TYPE_ID(i) (i & 0x0F)
|
||||
|
||||
/* Partial_data is word aligned so no reallocation is necessary for encrypted flash write */
|
||||
|
@ -31,7 +31,6 @@ try:
|
||||
except ImportError:
|
||||
COMPONENTS_PATH = os.path.expandvars(os.path.join('$IDF_PATH', 'components'))
|
||||
PARTTOOL_DIR = os.path.join(COMPONENTS_PATH, 'partition_table')
|
||||
|
||||
sys.path.append(PARTTOOL_DIR)
|
||||
from parttool import PARTITION_TABLE_OFFSET, PartitionName, PartitionType, ParttoolTarget
|
||||
|
||||
@ -86,9 +85,8 @@ class OtatoolTarget():
|
||||
seq = bytearray(self.otadata[start:start + 4])
|
||||
crc = bytearray(self.otadata[start + 28:start + 32])
|
||||
|
||||
seq = struct.unpack('>I', seq)
|
||||
crc = struct.unpack('>I', crc)
|
||||
|
||||
seq = struct.unpack('I', seq)
|
||||
crc = struct.unpack('I', crc)
|
||||
info.append(otadata_info(seq[0], crc[0]))
|
||||
|
||||
return info
|
||||
@ -102,12 +100,11 @@ class OtatoolTarget():
|
||||
def switch_ota_partition(self, ota_id):
|
||||
self._check_otadata_partition()
|
||||
|
||||
sys.path.append(PARTTOOL_DIR)
|
||||
import gen_esp32part as gen
|
||||
|
||||
def is_otadata_info_valid(status):
|
||||
seq = status.seq % (1 << 32)
|
||||
crc = hex(binascii.crc32(struct.pack('I', seq), 0xFFFFFFFF) % (1 << 32))
|
||||
crc = binascii.crc32(struct.pack('I', seq), 0xFFFFFFFF) % (1 << 32)
|
||||
return seq < (int('0xFFFFFFFF', 16) % (1 << 32)) and status.crc == crc
|
||||
|
||||
partition_table = self.target.partition_table
|
||||
@ -219,7 +216,7 @@ def _read_otadata(target):
|
||||
otadata_info = target._get_otadata_info()
|
||||
|
||||
print(' {:8s} \t {:8s} | \t {:8s} \t {:8s}'.format('OTA_SEQ', 'CRC', 'OTA_SEQ', 'CRC'))
|
||||
print('Firmware: 0x{:8x} \t0x{:8x} | \t0x{:8x} \t 0x{:8x}'.format(otadata_info[0].seq, otadata_info[0].crc,
|
||||
print('Firmware: 0x{:08x} \t0x{:08x} | \t0x{:08x} \t 0x{:08x}'.format(otadata_info[0].seq, otadata_info[0].crc,
|
||||
otadata_info[1].seq, otadata_info[1].crc))
|
||||
|
||||
|
||||
@ -290,7 +287,7 @@ def main():
|
||||
subparsers.add_parser('switch_ota_partition', help='switch otadata partition', parents=[slot_or_name_parser, spi_flash_sec_size])
|
||||
|
||||
read_ota_partition_subparser = subparsers.add_parser('read_ota_partition', help='read contents of an ota partition', parents=[slot_or_name_parser])
|
||||
read_ota_partition_subparser.add_argument('--output', help='file to write the contents of the ota partition to')
|
||||
read_ota_partition_subparser.add_argument('--output', help='file to write the contents of the ota partition to', required=True)
|
||||
|
||||
write_ota_partition_subparser = subparsers.add_parser('write_ota_partition', help='write contents to an ota partition', parents=[slot_or_name_parser])
|
||||
write_ota_partition_subparser.add_argument('--input', help='file whose contents to write to the ota partition')
|
||||
|
@ -274,6 +274,10 @@ menu "Bootloader config"
|
||||
|
||||
config BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP
|
||||
bool "Skip image validation when exiting deep sleep"
|
||||
# note: dependencies for this config item are different to other "skip image validation"
|
||||
# options, allowing to turn on "allow insecure options" and have secure boot with
|
||||
# "skip validation when existing deep sleep". Keeping this to avoid a breaking change,
|
||||
# but - as noted in help - it invalidates the integrity of Secure Boot checks
|
||||
depends on (SECURE_BOOT && SECURE_BOOT_INSECURE) || !SECURE_BOOT
|
||||
default n
|
||||
help
|
||||
@ -286,6 +290,48 @@ menu "Bootloader config"
|
||||
partition as this would skip the validation upon first load of the new
|
||||
OTA partition.
|
||||
|
||||
It is possible to enable this option with Secure Boot if "allow insecure
|
||||
options" is enabled, however it's strongly recommended to NOT enable it as
|
||||
it may allow a Secure Boot bypass.
|
||||
|
||||
config BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON
|
||||
bool "Skip image validation from power on reset (READ HELP FIRST)"
|
||||
# only available if both Secure Boot and Check Signature on Boot are disabled
|
||||
depends on !SECURE_SIGNED_ON_BOOT
|
||||
default n
|
||||
help
|
||||
Some applications need to boot very quickly from power on. By default, the entire app binary
|
||||
is read from flash and verified which takes up a significant portion of the boot time.
|
||||
|
||||
Enabling this option will skip validation of the app when the SoC boots from power on.
|
||||
Note that in this case it's not possible for the bootloader to detect if an app image is
|
||||
corrupted in the flash, therefore it's not possible to safely fall back to a different app
|
||||
partition. Flash corruption of this kind is unlikely but can happen if there is a serious
|
||||
firmware bug or physical damage.
|
||||
|
||||
Following other reset types, the bootloader will still validate the app image. This increases
|
||||
the chances that flash corruption resulting in a crash can be detected following soft reset, and
|
||||
the bootloader will fall back to a valid app image. To increase the chances of successfully recovering
|
||||
from a flash corruption event, keep the option BOOTLOADER_WDT_ENABLE enabled and consider also enabling
|
||||
BOOTLOADER_WDT_DISABLE_IN_USER_CODE - then manually disable the RTC Watchdog once the app is running.
|
||||
In addition, enable both the Task and Interrupt watchdog timers with reset options set.
|
||||
|
||||
config BOOTLOADER_SKIP_VALIDATE_ALWAYS
|
||||
bool "Skip image validation always (READ HELP FIRST)"
|
||||
# only available if both Secure Boot and Check Signature on Boot are disabled
|
||||
depends on !SECURE_SIGNED_ON_BOOT
|
||||
default n
|
||||
select BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP
|
||||
select BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON
|
||||
help
|
||||
Selecting this option prevents the bootloader from ever validating the app image before
|
||||
booting it. Any flash corruption of the selected app partition will make the entire SoC
|
||||
unbootable.
|
||||
|
||||
Although flash corruption is a very rare case, it is not recommended to select this option.
|
||||
Consider selecting "Skip image validation from power on reset" instead. However, if boot time
|
||||
is the only important factor then it can be enabled.
|
||||
|
||||
config BOOTLOADER_RESERVE_RTC_SIZE
|
||||
hex
|
||||
default 0x10 if BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP || BOOTLOADER_CUSTOM_RESERVE_RTC
|
||||
@ -378,7 +424,7 @@ menu "Security features"
|
||||
1. ECDSA based secure boot scheme. (Only choice for Secure Boot V1)
|
||||
Supported in ESP32 and ESP32-ECO3.
|
||||
2. The RSA based secure boot scheme. (Only choice for Secure Boot V2)
|
||||
Supported in ESP32-ECO3. (ESP32 Chip Revision 3 onwards)
|
||||
Supported in ESP32-ECO3 (ESP32 Chip Revision 3 onwards), ESP32-S2, ESP32-C3, ESP32-S3.
|
||||
|
||||
config SECURE_SIGNED_APPS_ECDSA_SCHEME
|
||||
bool "ECDSA"
|
||||
@ -390,7 +436,7 @@ menu "Security features"
|
||||
|
||||
config SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
bool "RSA"
|
||||
depends on SECURE_BOOT_SUPPORTS_RSA && SECURE_BOOT_V2_ENABLED
|
||||
depends on SECURE_BOOT_SUPPORTS_RSA && (SECURE_SIGNED_APPS_NO_SECURE_BOOT || SECURE_BOOT_V2_ENABLED)
|
||||
help
|
||||
Appends the RSA-3072 based Signature block to the application.
|
||||
Refer to <Secure Boot Version 2 documentation link> before enabling.
|
||||
@ -399,7 +445,7 @@ menu "Security features"
|
||||
config SECURE_SIGNED_ON_BOOT_NO_SECURE_BOOT
|
||||
bool "Bootloader verifies app signatures"
|
||||
default n
|
||||
depends on SECURE_SIGNED_APPS_NO_SECURE_BOOT
|
||||
depends on SECURE_SIGNED_APPS_NO_SECURE_BOOT && SECURE_SIGNED_APPS_ECDSA_SCHEME
|
||||
help
|
||||
If this option is set, the bootloader will be compiled with code to verify that an app is signed before
|
||||
booting it.
|
||||
@ -425,7 +471,7 @@ menu "Security features"
|
||||
config SECURE_BOOT
|
||||
bool "Enable hardware Secure Boot in bootloader (READ DOCS FIRST)"
|
||||
default n
|
||||
depends on !IDF_TARGET_ESP32C3 # IDF-2647
|
||||
depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || ESP32C3_REV_MIN_3
|
||||
help
|
||||
Build a bootloader which enables Secure Boot on first boot.
|
||||
|
||||
@ -442,7 +488,7 @@ menu "Security features"
|
||||
help
|
||||
Select the Secure Boot Version. Depends on the Chip Revision.
|
||||
Secure Boot V2 is the new RSA based secure boot scheme.
|
||||
Supported in ESP32-ECO3. (ESP32 Chip Revision 3 onwards)
|
||||
Supported in ESP32-ECO3 (ESP32 Chip Revision 3 onwards), ESP32-S2, ESP32-C3 ECO3.
|
||||
Secure Boot V1 is the AES based secure boot scheme.
|
||||
Supported in ESP32 and ESP32-ECO3.
|
||||
|
||||
@ -456,8 +502,6 @@ menu "Security features"
|
||||
config SECURE_BOOT_V2_ENABLED
|
||||
bool "Enable Secure Boot version 2"
|
||||
depends on SECURE_BOOT_SUPPORTS_RSA
|
||||
select SECURE_ENABLE_SECURE_ROM_DL_MODE if !IDF_TARGET_ESP32 && !SECURE_INSECURE_ALLOW_DL_MODE && !SECURE_DISABLE_ROM_DL_MODE # NOERROR
|
||||
select SECURE_DISABLE_ROM_DL_MODE if ESP32_REV_MIN_3 && !SECURE_INSECURE_ALLOW_DL_MODE
|
||||
help
|
||||
Build a bootloader which enables Secure Boot version 2 on first boot.
|
||||
Refer to Secure Boot V2 section of the ESP-IDF Programmer's Guide for this version before enabling.
|
||||
@ -626,7 +670,7 @@ menu "Security features"
|
||||
|
||||
config SECURE_FLASH_ENCRYPTION_MODE_RELEASE
|
||||
bool "Release"
|
||||
select SECURE_ENABLE_SECURE_ROM_DL_MODE if SECURE_TARGET_HAS_SECURE_ROM_DL_MODE && !SECURE_DISABLE_ROM_DL_MODE # NOERROR
|
||||
select PARTITION_TABLE_MD5 if !ESP32_COMPATIBLE_PRE_V3_1_BOOTLOADERS
|
||||
|
||||
endchoice
|
||||
|
||||
@ -692,19 +736,6 @@ menu "Security features"
|
||||
key digest, causing an immediate denial of service and possibly allowing an additional fault
|
||||
injection attack to bypass the signature protection.
|
||||
|
||||
config SECURE_INSECURE_ALLOW_DL_MODE
|
||||
bool "Don't automatically restrict UART download mode"
|
||||
depends on SECURE_BOOT_INSECURE && SECURE_BOOT_V2_ENABLED
|
||||
default N
|
||||
help
|
||||
By default, enabling either flash encryption in release mode or secure boot will automatically
|
||||
disable UART download mode on ESP32 ECO3, or enable secure download mode on newer chips.
|
||||
This is recommended to reduce the attack surface of the chip.
|
||||
|
||||
To allow the full UART download mode to stay enabled, enable this option and ensure
|
||||
the options SECURE_DISABLE_ROM_DL_MODE and SECURE_ENABLE_SECURE_ROM_DL_MODE are disabled as applicable.
|
||||
This is not recommended.
|
||||
|
||||
config SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
|
||||
bool "Leave UART bootloader encryption enabled"
|
||||
depends on SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT
|
||||
@ -752,47 +783,58 @@ menu "Security features"
|
||||
|
||||
endmenu # Potentially Insecure
|
||||
|
||||
config SECURE_DISABLE_ROM_DL_MODE
|
||||
bool "Permanently disable ROM Download Mode"
|
||||
choice SECURE_UART_ROM_DL_MODE
|
||||
bool "UART ROM download mode"
|
||||
default SECURE_ENABLE_SECURE_ROM_DL_MODE if SECURE_TARGET_HAS_SECURE_ROM_DL_MODE && !SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT # NOERROR
|
||||
default SECURE_INSECURE_ALLOW_DL_MODE
|
||||
depends on SECURE_BOOT_V2_ENABLED || SECURE_FLASH_ENC_ENABLED
|
||||
depends on !IDF_TARGET_ESP32 || ESP32_REV_MIN_3
|
||||
default n
|
||||
help
|
||||
If set, during startup the app will burn an eFuse bit to permanently disable the UART ROM
|
||||
Download Mode. This prevents any future use of esptool.py, espefuse.py and similar tools.
|
||||
|
||||
Once disabled, if the SoC is booted with strapping pins set for ROM Download Mode
|
||||
then an error is printed instead.
|
||||
config SECURE_DISABLE_ROM_DL_MODE
|
||||
bool "UART ROM download mode (Permanently disabled (recommended))"
|
||||
help
|
||||
If set, during startup the app will burn an eFuse bit to permanently disable the UART ROM
|
||||
Download Mode. This prevents any future use of esptool.py, espefuse.py and similar tools.
|
||||
|
||||
It is recommended to enable this option in any production application where Flash
|
||||
Encryption and/or Secure Boot is enabled and access to Download Mode is not required.
|
||||
Once disabled, if the SoC is booted with strapping pins set for ROM Download Mode
|
||||
then an error is printed instead.
|
||||
|
||||
It is also possible to permanently disable Download Mode by calling
|
||||
esp_efuse_disable_rom_download_mode() at runtime.
|
||||
It is recommended to enable this option in any production application where Flash
|
||||
Encryption and/or Secure Boot is enabled and access to Download Mode is not required.
|
||||
|
||||
config SECURE_ENABLE_SECURE_ROM_DL_MODE
|
||||
bool "Permanently switch to ROM UART Secure Download mode"
|
||||
depends on SECURE_TARGET_HAS_SECURE_ROM_DL_MODE && !SECURE_DISABLE_ROM_DL_MODE
|
||||
select ESPTOOLPY_NO_STUB
|
||||
help
|
||||
If set, during startup the app will burn an eFuse bit to permanently switch the UART ROM
|
||||
Download Mode into a separate Secure Download mode. This option can only work if
|
||||
Download Mode is not already disabled by eFuse.
|
||||
It is also possible to permanently disable Download Mode by calling
|
||||
esp_efuse_disable_rom_download_mode() at runtime.
|
||||
|
||||
Secure Download mode limits the use of Download Mode functions to simple flash read,
|
||||
write and erase operations, plus a command to return a summary of currently enabled
|
||||
security features.
|
||||
config SECURE_ENABLE_SECURE_ROM_DL_MODE
|
||||
bool "UART ROM download mode (Permanently switch to Secure mode (recommended))"
|
||||
depends on SECURE_TARGET_HAS_SECURE_ROM_DL_MODE
|
||||
select ESPTOOLPY_NO_STUB
|
||||
help
|
||||
If set, during startup the app will burn an eFuse bit to permanently switch the UART ROM
|
||||
Download Mode into a separate Secure Download mode. This option can only work if
|
||||
Download Mode is not already disabled by eFuse.
|
||||
|
||||
Secure Download mode is not compatible with the esptool.py flasher stub feature,
|
||||
espefuse.py, read/writing memory or registers, encrypted download, or any other
|
||||
features that interact with unsupported Download Mode commands.
|
||||
Secure Download mode limits the use of Download Mode functions to simple flash read,
|
||||
write and erase operations, plus a command to return a summary of currently enabled
|
||||
security features.
|
||||
|
||||
Secure Download mode should be enabled in any application where Flash Encryption
|
||||
and/or Secure Boot is enabled. Disabling this option does not immediately cancel
|
||||
the benefits of the security features, but it increases the potential "attack
|
||||
surface" for an attacker to try and bypass them with a successful physical attack.
|
||||
Secure Download mode is not compatible with the esptool.py flasher stub feature,
|
||||
espefuse.py, read/writing memory or registers, encrypted download, or any other
|
||||
features that interact with unsupported Download Mode commands.
|
||||
|
||||
It is also possible to enable secure download mode at runtime by calling
|
||||
esp_efuse_enable_rom_secure_download_mode()
|
||||
Secure Download mode should be enabled in any application where Flash Encryption
|
||||
and/or Secure Boot is enabled. Disabling this option does not immediately cancel
|
||||
the benefits of the security features, but it increases the potential "attack
|
||||
surface" for an attacker to try and bypass them with a successful physical attack.
|
||||
|
||||
It is also possible to enable secure download mode at runtime by calling
|
||||
esp_efuse_enable_rom_secure_download_mode()
|
||||
|
||||
config SECURE_INSECURE_ALLOW_DL_MODE
|
||||
bool "UART ROM download mode (Enabled (not recommended))"
|
||||
help
|
||||
This is a potentially insecure option.
|
||||
Enabling this option will allow the full UART download mode to stay enabled.
|
||||
This option SHOULD NOT BE ENABLED for production use cases.
|
||||
endchoice
|
||||
endmenu # Security features
|
||||
|
@ -17,6 +17,8 @@ CONFIG_SECURE_BOOT_SIGNING_KEY ?=
|
||||
SECURE_BOOT_SIGNING_KEY=$(abspath $(call dequote,$(CONFIG_SECURE_BOOT_SIGNING_KEY)))
|
||||
export SECURE_BOOT_SIGNING_KEY # used by bootloader_support component
|
||||
|
||||
BOOTLOADER_SIGNED_BIN ?=
|
||||
|
||||
# Has a matching value in bootloader_support esp_flash_partitions.h
|
||||
BOOTLOADER_OFFSET := 0x1000
|
||||
|
||||
|
@ -28,10 +28,11 @@ set(COMPONENTS
|
||||
micro-ecc
|
||||
main
|
||||
efuse
|
||||
esp_system)
|
||||
esp_system
|
||||
newlib)
|
||||
set(BOOTLOADER_BUILD 1)
|
||||
include("${IDF_PATH}/tools/cmake/project.cmake")
|
||||
set(common_req log esp_rom esp_common esp_hw_support hal)
|
||||
set(common_req log esp_rom esp_common esp_hw_support hal newlib)
|
||||
if(LEGACY_INCLUDE_COMMON_HEADERS)
|
||||
list(APPEND common_req soc hal)
|
||||
endif()
|
||||
@ -53,6 +54,9 @@ string(REPLACE ";" " " esptoolpy_write_flash
|
||||
string(REPLACE ";" " " espsecurepy "${ESPSECUREPY}")
|
||||
string(REPLACE ";" " " espefusepy "${ESPEFUSEPY}")
|
||||
|
||||
# Suppress warning: "Manually-specified variables were not used by the project: SECURE_BOOT_SIGNING_KEY"
|
||||
set(ignore_signing_key "${SECURE_BOOT_SIGNING_KEY}")
|
||||
|
||||
if(CONFIG_SECURE_BOOTLOADER_REFLASHABLE)
|
||||
if(CONFIG_SECURE_BOOTLOADER_KEY_ENCODING_192BIT)
|
||||
set(key_digest_len 192)
|
||||
|
@ -8,15 +8,16 @@ endif
|
||||
|
||||
PROJECT_NAME := bootloader
|
||||
|
||||
COMPONENTS := esp_hw_support esptool_py bootloader_support log spi_flash micro-ecc soc main efuse esp_rom hal
|
||||
COMPONENTS := esp_hw_support esptool_py bootloader_support log spi_flash micro-ecc soc main efuse esp_rom hal xtensa
|
||||
|
||||
# Clear C and CXX from top level project
|
||||
CFLAGS =
|
||||
CXXFLAGS =
|
||||
|
||||
#We cannot include the idf_target, esp_common component directly but we need their includes.
|
||||
#We cannot include the some components like idf_target, esp_common directly but we need their includes.
|
||||
CFLAGS += -I $(IDF_PATH)/components/$(IDF_TARGET)/include
|
||||
CFLAGS += -I $(IDF_PATH)/components/esp_common/include
|
||||
CFLAGS += -I $(IDF_PATH)/components/newlib/platform_include
|
||||
CFLAGS += -I $(IDF_PATH)/components/xtensa/include -I $(IDF_PATH)/components/xtensa/$(IDF_TARGET)/include
|
||||
|
||||
# The bootloader pseudo-component is also included in this build, for its Kconfig.projbuild to be included.
|
||||
|
@ -52,7 +52,7 @@ SECTIONS
|
||||
*libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:flash_partitions.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot_signatures.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot_signatures_bootloader.*(.literal .text .literal.* .text.*)
|
||||
*libmicro-ecc.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libspi_flash.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libhal.a:wdt_hal_iram.*(.literal .text .literal.* .text.*)
|
||||
@ -167,6 +167,14 @@ SECTIONS
|
||||
*(.fini.literal)
|
||||
*(.fini)
|
||||
*(.gnu.version)
|
||||
|
||||
/** CPU will try to prefetch up to 16 bytes of
|
||||
* of instructions. This means that any configuration (e.g. MMU, PMS) must allow
|
||||
* safe access to up to 16 bytes after the last real instruction, add
|
||||
* dummy bytes to ensure this
|
||||
*/
|
||||
. += 16;
|
||||
|
||||
_text_end = ABSOLUTE(.);
|
||||
_etext = .;
|
||||
} > iram_seg
|
||||
|
@ -40,7 +40,7 @@ SECTIONS
|
||||
*libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:flash_partitions.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot_signatures.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot_signatures_bootloader.*(.literal .text .literal.* .text.*)
|
||||
*libmicro-ecc.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libspi_flash.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libhal.a:wdt_hal_iram.*(.literal .text .literal.* .text.*)
|
||||
@ -156,6 +156,14 @@ SECTIONS
|
||||
*(.fini.literal)
|
||||
*(.fini)
|
||||
*(.gnu.version)
|
||||
|
||||
/** CPU will try to prefetch up to 16 bytes of
|
||||
* of instructions. This means that any configuration (e.g. MMU, PMS) must allow
|
||||
* safe access to up to 16 bytes after the last real instruction, add
|
||||
* dummy bytes to ensure this
|
||||
*/
|
||||
. += 16;
|
||||
|
||||
_text_end = ABSOLUTE(.);
|
||||
_etext = .;
|
||||
} > iram_seg
|
||||
|
@ -39,7 +39,7 @@ SECTIONS
|
||||
*libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:flash_partitions.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot_signatures.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot_signatures_bootloader.*(.literal .text .literal.* .text.*)
|
||||
*libmicro-ecc.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libspi_flash.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libhal.a:wdt_hal_iram.*(.literal .text .literal.* .text.*)
|
||||
@ -155,6 +155,14 @@ SECTIONS
|
||||
*(.fini.literal)
|
||||
*(.fini)
|
||||
*(.gnu.version)
|
||||
|
||||
/** CPU will try to prefetch up to 16 bytes of
|
||||
* of instructions. This means that any configuration (e.g. MMU, PMS) must allow
|
||||
* safe access to up to 16 bytes after the last real instruction, add
|
||||
* dummy bytes to ensure this
|
||||
*/
|
||||
. += 16;
|
||||
|
||||
_text_end = ABSOLUTE(.);
|
||||
_etext = .;
|
||||
} > iram_seg
|
||||
|
@ -40,7 +40,7 @@ SECTIONS
|
||||
*libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:flash_partitions.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot_signatures.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot_signatures_bootloader.*(.literal .text .literal.* .text.*)
|
||||
*libmicro-ecc.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libspi_flash.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libhal.a:wdt_hal_iram.*(.literal .text .literal.* .text.*)
|
||||
@ -156,6 +156,14 @@ SECTIONS
|
||||
*(.fini.literal)
|
||||
*(.fini)
|
||||
*(.gnu.version)
|
||||
|
||||
/** CPU will try to prefetch up to 16 bytes of
|
||||
* of instructions. This means that any configuration (e.g. MMU, PMS) must allow
|
||||
* safe access to up to 16 bytes after the last real instruction, add
|
||||
* dummy bytes to ensure this
|
||||
*/
|
||||
. += 16;
|
||||
|
||||
_text_end = ABSOLUTE(.);
|
||||
_etext = .;
|
||||
} > iram_seg
|
||||
|
@ -9,6 +9,7 @@ set(srcs
|
||||
"src/bootloader_utility.c"
|
||||
"src/esp_image_format.c"
|
||||
"src/flash_encrypt.c"
|
||||
"src/secure_boot.c"
|
||||
"src/flash_partitions.c"
|
||||
"src/flash_qio_mode.c"
|
||||
"src/bootloader_flash_config_${IDF_TARGET}.c"
|
||||
@ -34,16 +35,28 @@ else()
|
||||
"src/idf/bootloader_sha.c")
|
||||
set(include_dirs "include")
|
||||
set(priv_include_dirs "include_bootloader")
|
||||
set(priv_requires spi_flash mbedtls efuse)
|
||||
set(priv_requires spi_flash mbedtls efuse app_update)
|
||||
endif()
|
||||
|
||||
if(CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME OR CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME)
|
||||
if(BOOTLOADER_BUILD)
|
||||
list(APPEND srcs
|
||||
"src/${IDF_TARGET}/secure_boot_signatures.c")
|
||||
else()
|
||||
list(APPEND srcs
|
||||
"src/idf/secure_boot_signatures.c")
|
||||
if(BOOTLOADER_BUILD)
|
||||
if(CONFIG_SECURE_SIGNED_ON_BOOT)
|
||||
if(CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME)
|
||||
list(APPEND srcs "src/secure_boot_v1/secure_boot_signatures_bootloader.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME)
|
||||
list(APPEND srcs "src/secure_boot_v2/secure_boot_signatures_bootloader.c")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
if(CONFIG_SECURE_SIGNED_ON_UPDATE)
|
||||
if(CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME)
|
||||
list(APPEND srcs "src/secure_boot_v1/secure_boot_signatures_app.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME)
|
||||
list(APPEND srcs "src/secure_boot_v2/secure_boot_signatures_app.c")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
@ -7,7 +7,9 @@ else
|
||||
COMPONENT_PRIV_INCLUDEDIRS := include_bootloader
|
||||
endif
|
||||
|
||||
COMPONENT_SRCDIRS := src
|
||||
COMPONENT_SRCDIRS := src \
|
||||
src/secure_boot_v2 \
|
||||
src/secure_boot_v1
|
||||
|
||||
ifndef IS_BOOTLOADER_BUILD
|
||||
COMPONENT_SRCDIRS += src/idf # idf sub-directory contains platform agnostic IDF versions
|
||||
@ -33,12 +35,27 @@ COMPONENT_OBJEXCLUDE += src/bootloader_flash_config_esp32s2.o \
|
||||
src/bootloader_random_esp32s3.o \
|
||||
src/bootloader_random_esp32c3.o
|
||||
|
||||
ifndef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
|
||||
ifndef CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
COMPONENT_OBJEXCLUDE += src/$(IDF_TARGET)/secure_boot_signatures.o \
|
||||
src/idf/secure_boot_signatures.o
|
||||
endif
|
||||
endif
|
||||
ifdef IS_BOOTLOADER_BUILD
|
||||
ifndef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
|
||||
COMPONENT_OBJEXCLUDE += src/secure_boot_v1/secure_boot_signatures_bootloader.o
|
||||
endif
|
||||
|
||||
ifndef CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
COMPONENT_OBJEXCLUDE += src/secure_boot_v2/secure_boot_signatures_bootloader.o
|
||||
endif
|
||||
COMPONENT_OBJEXCLUDE += src/secure_boot_v1/secure_boot_signatures_app.o \
|
||||
src/secure_boot_v2/secure_boot_signatures_app.o
|
||||
else
|
||||
ifndef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
|
||||
COMPONENT_OBJEXCLUDE += src/secure_boot_v1/secure_boot_signatures_app.o
|
||||
endif
|
||||
|
||||
ifndef CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
COMPONENT_OBJEXCLUDE += src/secure_boot_v2/secure_boot_signatures_app.o
|
||||
endif
|
||||
COMPONENT_OBJEXCLUDE += src/secure_boot_v1/secure_boot_signatures_bootloader.o \
|
||||
src/secure_boot_v2/secure_boot_signatures_bootloader.o
|
||||
endif # IS_BOOTLOADER_BUILD
|
||||
|
||||
ifndef CONFIG_SECURE_BOOT
|
||||
COMPONENT_OBJEXCLUDE += src/$(IDF_TARGET)/secure_boot.o
|
||||
|
@ -42,6 +42,9 @@ extern "C" {
|
||||
|
||||
#define PART_FLAG_ENCRYPTED (1<<0)
|
||||
|
||||
/* The md5sum value is found this many bytes after the ESP_PARTITION_MAGIC_MD5 offset */
|
||||
#define ESP_PARTITION_MD5_OFFSET 16
|
||||
|
||||
/* Pre-partition table fixed flash offsets */
|
||||
#define ESP_BOOTLOADER_DIGEST_OFFSET 0x0
|
||||
#define ESP_BOOTLOADER_OFFSET CONFIG_BOOTLOADER_OFFSET_IN_FLASH /* Offset of bootloader image. Has matching value in bootloader KConfig.projbuild file. */
|
||||
|
@ -106,6 +106,20 @@ _Static_assert(sizeof(rtc_retain_mem_t) <= ESP_BOOTLOADER_RESERVE_RTC, "Reserved
|
||||
*/
|
||||
esp_err_t esp_image_verify(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data);
|
||||
|
||||
/**
|
||||
* @brief Get metadata of app
|
||||
*
|
||||
* If encryption is enabled, data will be transparently decrypted.
|
||||
*
|
||||
* @param part Partition to load the app from.
|
||||
* @param[out] metadata Pointer to the image metadata structure which is be filled in by this function.
|
||||
* Fields will all be initialised by this function.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if filling of metadata was successful
|
||||
*/
|
||||
esp_err_t esp_image_get_metadata(const esp_partition_pos_t *part, esp_image_metadata_t *metadata);
|
||||
|
||||
/**
|
||||
* @brief Verify and load an app image (available only in space of bootloader).
|
||||
*
|
||||
|
@ -19,17 +19,22 @@
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_rom_efuse.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_rom_crc.h"
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#include "esp32/rom/efuse.h"
|
||||
#include "esp32/rom/secure_boot.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/efuse.h"
|
||||
#include "esp32s2/rom/secure_boot.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#include "esp32c3/rom/efuse.h"
|
||||
#include "esp32c3/rom/secure_boot.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
#include "esp32s3/rom/efuse.h"
|
||||
#include "esp32s3/rom/secure_boot.h"
|
||||
#endif
|
||||
|
||||
typedef struct ets_secure_boot_signature ets_secure_boot_signature_t;
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_V1_ENABLED
|
||||
#if !defined(CONFIG_SECURE_SIGNED_ON_BOOT) || !defined(CONFIG_SECURE_SIGNED_ON_UPDATE) || !defined(CONFIG_SECURE_SIGNED_APPS)
|
||||
#error "internal sdkconfig error, secure boot should always enable all signature options"
|
||||
@ -45,6 +50,8 @@ extern "C" {
|
||||
Can be compiled as part of app or bootloader code.
|
||||
*/
|
||||
|
||||
#define ESP_SECURE_BOOT_DIGEST_LEN 32
|
||||
|
||||
/** @brief Is secure boot currently enabled in hardware?
|
||||
*
|
||||
* This means that the ROM bootloader code will only boot
|
||||
@ -181,6 +188,16 @@ typedef struct {
|
||||
*/
|
||||
esp_err_t esp_secure_boot_verify_ecdsa_signature_block(const esp_secure_boot_sig_block_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest);
|
||||
|
||||
#if !CONFIG_IDF_TARGET_ESP32 || CONFIG_ESP32_REV_MIN_3
|
||||
/**
|
||||
* @brief Structure to hold public key digests calculated from the signature blocks of a single image.
|
||||
*
|
||||
* Each image can have one or more signature blocks (up to SECURE_BOOT_NUM_BLOCKS). Each signature block includes a public key.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t key_digests[SECURE_BOOT_NUM_BLOCKS][ESP_SECURE_BOOT_DIGEST_LEN]; /* SHA of the public key components in the signature block */
|
||||
unsigned num_digests; /* Number of valid digests, starting at index 0 */
|
||||
} esp_image_sig_public_key_digests_t;
|
||||
|
||||
/** @brief Verify the RSA secure boot signature block for Secure Boot V2.
|
||||
*
|
||||
@ -194,6 +211,7 @@ esp_err_t esp_secure_boot_verify_ecdsa_signature_block(const esp_secure_boot_sig
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest);
|
||||
#endif // !CONFIG_IDF_TARGET_ESP32 || CONFIG_ESP32_REV_MIN_3
|
||||
|
||||
/** @brief Legacy ECDSA verification function
|
||||
*
|
||||
@ -214,6 +232,45 @@ typedef struct {
|
||||
uint8_t digest[64];
|
||||
} esp_secure_boot_iv_digest_t;
|
||||
|
||||
/** @brief Check the secure boot V2 during startup
|
||||
*
|
||||
* @note This function is called automatically during app startup,
|
||||
* it doesn't need to be called from the app.
|
||||
*
|
||||
* Verifies the secure boot config during startup:
|
||||
*
|
||||
* - Correct any insecure secure boot settings
|
||||
*/
|
||||
void esp_secure_boot_init_checks(void);
|
||||
|
||||
#if !BOOTLOADER_BUILD && CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
|
||||
/** @brief Scan the current running app for signature blocks
|
||||
*
|
||||
* @note This function doesn't verify that the signatures are valid or the
|
||||
* corresponding public keys are trusted, it only reads the number of signature
|
||||
* blocks present and optionally calculates the digests of the public keys
|
||||
* provided in the signature blocks.
|
||||
*
|
||||
* @param digest_public_keys If true, the key_digests fields in the
|
||||
* public_key_digests structure will be filled with the digests of the public
|
||||
* key provided in each signature block. Note that if Secure Boot V2 is enabled,
|
||||
* each public key will only be trusted if the same digest is also present in
|
||||
* eFuse (but this is not checked by this function).
|
||||
*
|
||||
* @param public_key_digests[out] Structure is initialized with the num_digests
|
||||
* field set to the number of signatures found. If digest_public_keys is set,
|
||||
* the public key digests are also calculated and stored here.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK - At least one signature was found
|
||||
* - ESP_ERR_NOT_FOUND - No signatures were found, num_digests value will be zero
|
||||
* - ESP_FAIL - An error occured trying to read the signature blocks from flash
|
||||
*/
|
||||
esp_err_t esp_secure_boot_get_signature_blocks_for_running_app(bool digest_public_keys, esp_image_sig_public_key_digests_t *public_key_digests);
|
||||
|
||||
#endif // !BOOTLOADER_BUILD && CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -80,4 +80,7 @@ __attribute__((weak)) void bootloader_clock_configure(void)
|
||||
rtc_clk_32k_bootstrap(CONFIG_ESP_SYSTEM_RTC_EXT_XTAL_BOOTSTRAP_CYCLES);
|
||||
}
|
||||
#endif // CONFIG_ESP_SYSTEM_RTC_EXT_XTAL
|
||||
|
||||
REG_WRITE(RTC_CNTL_INT_ENA_REG, 0);
|
||||
REG_WRITE(RTC_CNTL_INT_CLR_REG, UINT32_MAX);
|
||||
}
|
||||
|
@ -163,9 +163,7 @@ esp_err_t bootloader_common_get_sha256_of_partition (uint32_t address, uint32_t
|
||||
.size = size,
|
||||
};
|
||||
esp_image_metadata_t data;
|
||||
// Function esp_image_verify() verifies and fills the structure data.
|
||||
// here important to get: image_digest, image_len, hash_appended.
|
||||
if (esp_image_verify(ESP_IMAGE_VERIFY_SILENT, &partition_pos, &data) != ESP_OK) {
|
||||
if (esp_image_get_metadata(&partition_pos, &data) != ESP_OK) {
|
||||
return ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
if (data.image.hash_appended) {
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "soc/gpio_periph.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "soc/soc_memory_layout.h"
|
||||
#include "hal/gpio_ll.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "bootloader_sha.h"
|
||||
@ -76,7 +77,9 @@ esp_err_t bootloader_common_check_chip_validity(const esp_image_header_t* img_hd
|
||||
}
|
||||
uint8_t revision = bootloader_common_get_chip_revision();
|
||||
if (revision < img_hdr->min_chip_rev) {
|
||||
ESP_LOGE(TAG, "can't run on lower chip revision, expected %d, found %d", revision, img_hdr->min_chip_rev);
|
||||
/* To fix this error, please update mininum supported chip revision from configuration,
|
||||
* located in TARGET (e.g. ESP32) specific options under "Component config" menu */
|
||||
ESP_LOGE(TAG, "This chip is revision %d but the application is configured for minimum revision %d. Can't run.", revision, img_hdr->min_chip_rev);
|
||||
err = ESP_FAIL;
|
||||
} else if (revision != img_hdr->min_chip_rev) {
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
@ -138,7 +141,18 @@ esp_err_t bootloader_common_get_partition_description(const esp_partition_pos_t
|
||||
|
||||
#if defined( CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP ) || defined( CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC )
|
||||
|
||||
rtc_retain_mem_t *const rtc_retain_mem = (rtc_retain_mem_t *)(SOC_RTC_DRAM_HIGH - sizeof(rtc_retain_mem_t));
|
||||
#define RTC_RETAIN_MEM_ADDR (SOC_RTC_DRAM_HIGH - sizeof(rtc_retain_mem_t))
|
||||
|
||||
rtc_retain_mem_t *const rtc_retain_mem = (rtc_retain_mem_t *)RTC_RETAIN_MEM_ADDR;
|
||||
|
||||
#if !IS_BOOTLOADER_BUILD
|
||||
/* The app needs to be told this memory is reserved, important if configured to use RTC memory as heap.
|
||||
|
||||
Note that keeping this macro here only works when other symbols in this file are referenced by the app, as
|
||||
this feature is otherwise 100% part of the bootloader. However this seems to happen in all apps.
|
||||
*/
|
||||
SOC_RESERVE_MEMORY_REGION(RTC_RETAIN_MEM_ADDR, RTC_RETAIN_MEM_ADDR + sizeof(rtc_retain_mem_t), rtc_retain_mem);
|
||||
#endif
|
||||
|
||||
static bool check_rtc_retain_mem(void)
|
||||
{
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "hal/clk_gate_ll.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/usb/cdc_acm.h"
|
||||
#include "esp32s2/rom/usb/usb_common.h"
|
||||
@ -69,8 +70,8 @@ void bootloader_console_init(void)
|
||||
uart_tx_gpio != UART_NUM_0_TXD_DIRECT_GPIO_NUM ||
|
||||
uart_rx_gpio != UART_NUM_0_RXD_DIRECT_GPIO_NUM) {
|
||||
// Change default UART pins back to GPIOs
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_U0RXD_U, PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_U0TXD_U, PIN_FUNC_GPIO);
|
||||
// Route GPIO signals to/from pins
|
||||
const uint32_t tx_idx = uart_periph_signal[uart_num].tx_sig;
|
||||
const uint32_t rx_idx = uart_periph_signal[uart_num].rx_sig;
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "soc/spi_reg.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "soc/soc_pins.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "flash_qio_mode.h"
|
||||
#include "bootloader_common.h"
|
||||
#include "bootloader_flash_config.h"
|
||||
@ -87,7 +88,7 @@ void IRAM_ATTR bootloader_flash_gpio_config(const esp_image_header_t* pfhdr)
|
||||
pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOV302) {
|
||||
// For ESP32D2WD or ESP32-PICO series,the SPI pins are already configured
|
||||
// flash clock signal should come from IO MUX.
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
|
||||
} else {
|
||||
const uint32_t spiconfig = esp_rom_efuse_get_flash_gpio_info();
|
||||
@ -102,14 +103,14 @@ void IRAM_ATTR bootloader_flash_gpio_config(const esp_image_header_t* pfhdr)
|
||||
esp_rom_gpio_connect_out_signal(SPI_IOMUX_PIN_NUM_HD, SPIHD_OUT_IDX, 0, 0);
|
||||
esp_rom_gpio_connect_in_signal(SPI_IOMUX_PIN_NUM_HD, SPIHD_IN_IDX, 0);
|
||||
//select pin function gpio
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA2_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA3_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_DATA0_U, PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_DATA1_U, PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_DATA2_U, PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_DATA3_U, PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_CMD_U, PIN_FUNC_GPIO);
|
||||
// flash clock signal should come from IO MUX.
|
||||
// set drive ability for clock
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
|
||||
|
||||
uint32_t flash_id = g_rom_flashchip.device_id;
|
||||
@ -178,9 +179,9 @@ int bootloader_flash_get_wp_pin(void)
|
||||
uint8_t chip_ver;
|
||||
uint32_t pkg_ver = bootloader_common_get_chip_ver_pkg();
|
||||
switch(pkg_ver) {
|
||||
case EFUSE_RD_CHIP_VER_PKG_ESP32U4WDH:
|
||||
case EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5:
|
||||
return ESP32_D2WD_WP_GPIO;
|
||||
case EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2:
|
||||
case EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4:
|
||||
/* Same package IDs are used for ESP32-PICO-V3 and ESP32-PICO-D4, silicon version differentiates */
|
||||
chip_ver = bootloader_common_get_chip_revision();
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "soc/spi_reg.h"
|
||||
#include "soc/spi_mem_reg.h"
|
||||
#include "soc/spi_caps.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "flash_qio_mode.h"
|
||||
#include "bootloader_flash_config.h"
|
||||
#include "bootloader_common.h"
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/spi_periph.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
|
||||
#include "esp32/rom/cache.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
@ -61,7 +62,7 @@ void bootloader_configure_spi_pins(int drv)
|
||||
pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOV302) {
|
||||
// For ESP32D2WD or ESP32-PICO series,the SPI pins are already configured
|
||||
// flash clock signal should come from IO MUX.
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
|
||||
} else {
|
||||
const uint32_t spiconfig = esp_rom_efuse_get_flash_gpio_info();
|
||||
@ -76,14 +77,14 @@ void bootloader_configure_spi_pins(int drv)
|
||||
esp_rom_gpio_connect_out_signal(FLASH_SPIHD_IO, SPIHD_OUT_IDX, 0, 0);
|
||||
esp_rom_gpio_connect_in_signal(FLASH_SPIHD_IO, SPIHD_IN_IDX, 0);
|
||||
//select pin function gpio
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA2_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA3_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_DATA0_U, PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_DATA1_U, PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_DATA2_U, PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_DATA3_U, PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_CMD_U, PIN_FUNC_GPIO);
|
||||
// flash clock signal should come from IO MUX.
|
||||
// set drive ability for clock
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
|
||||
|
||||
#if CONFIG_SPIRAM_TYPE_ESPPSRAM32 || CONFIG_SPIRAM_TYPE_ESPPSRAM64
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "esp32/rom/cache.h"
|
||||
#include "esp_rom_crc.h"
|
||||
|
||||
#include "soc/efuse_periph.h"
|
||||
#include "soc/rtc_periph.h"
|
||||
@ -223,16 +222,12 @@ esp_err_t esp_secure_boot_permanently_enable(void)
|
||||
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
static const char *TAG = "secure_boot_v2";
|
||||
|
||||
#define SIG_BLOCK_MAGIC_BYTE 0xe7
|
||||
#define CRC_SIGN_BLOCK_LEN 1196
|
||||
#define SIG_BLOCK_PADDING 4096
|
||||
|
||||
#define DIGEST_LEN 32
|
||||
|
||||
static esp_err_t validate_signature_block(const ets_secure_boot_signature_t *sig_block, uint8_t *digest)
|
||||
{
|
||||
uint32_t crc = esp_rom_crc32_le(0, (uint8_t *)sig_block, CRC_SIGN_BLOCK_LEN);
|
||||
if (sig_block->block[0].magic_byte == SIG_BLOCK_MAGIC_BYTE && sig_block->block[0].block_crc == crc && !memcmp(digest, sig_block->block[0].image_digest, DIGEST_LEN)) {
|
||||
if (sig_block->block[0].magic_byte == ETS_SECURE_BOOT_V2_SIGNATURE_MAGIC
|
||||
&& sig_block->block[0].block_crc == crc
|
||||
&& !memcmp(digest, sig_block->block[0].image_digest, ESP_SECURE_BOOT_DIGEST_LEN)) {
|
||||
ESP_LOGI(TAG, "valid signature block found");
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -243,7 +238,7 @@ static esp_err_t secure_boot_v2_digest_generate(uint32_t flash_offset, uint32_t
|
||||
{
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
|
||||
uint8_t image_digest[DIGEST_LEN] = {0};
|
||||
uint8_t image_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
size_t sig_block_addr = flash_offset + ALIGN_UP(flash_size, FLASH_SECTOR_SIZE);
|
||||
ret = bootloader_sha256_flash_contents(flash_offset, sig_block_addr - flash_offset, image_digest);
|
||||
if (ret != ESP_OK) {
|
||||
@ -266,7 +261,7 @@ static esp_err_t secure_boot_v2_digest_generate(uint32_t flash_offset, uint32_t
|
||||
}
|
||||
|
||||
/* Verifying Signature block */
|
||||
uint8_t verified_digest[DIGEST_LEN] = {0};
|
||||
uint8_t verified_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
|
||||
/* Generating the SHA of the public key components in the signature block */
|
||||
bootloader_sha256_handle_t sig_block_sha;
|
||||
@ -318,7 +313,7 @@ esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *imag
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t boot_pub_key_digest[DIGEST_LEN];
|
||||
uint8_t boot_pub_key_digest[ESP_SECURE_BOOT_DIGEST_LEN];
|
||||
uint32_t dis_reg = REG_READ(EFUSE_BLK0_RDATA0_REG);
|
||||
bool efuse_key_read_protected = dis_reg & EFUSE_RD_DIS_BLK2;
|
||||
bool efuse_key_write_protected = dis_reg & EFUSE_WR_DIS_BLK2;
|
||||
@ -350,7 +345,7 @@ esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *imag
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Burning public key hash to efuse.");
|
||||
ret = esp_efuse_write_block(EFUSE_BLK2, boot_pub_key_digest, 0, (DIGEST_LEN * 8));
|
||||
ret = esp_efuse_write_block(EFUSE_BLK2, boot_pub_key_digest, 0, (ESP_SECURE_BOOT_DIGEST_LEN * 8));
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Writing public key hash to efuse failed.");
|
||||
return ret;
|
||||
@ -366,7 +361,7 @@ esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *imag
|
||||
efuse_blk2_digest[5] = efuse_blk2_r5;
|
||||
efuse_blk2_digest[6] = efuse_blk2_r6;
|
||||
efuse_blk2_digest[7] = efuse_blk2_r7;
|
||||
memcpy(boot_pub_key_digest, efuse_blk2_digest, DIGEST_LEN);
|
||||
memcpy(boot_pub_key_digest, efuse_blk2_digest, ESP_SECURE_BOOT_DIGEST_LEN);
|
||||
ESP_LOGW(TAG, "Using pre-loaded secure boot v2 public key digest in EFUSE block 2");
|
||||
}
|
||||
|
||||
@ -380,7 +375,7 @@ esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *imag
|
||||
efuse_key_write_protected = true;
|
||||
}
|
||||
|
||||
uint8_t app_pub_key_digest[DIGEST_LEN];
|
||||
uint8_t app_pub_key_digest[ESP_SECURE_BOOT_DIGEST_LEN];
|
||||
ret = secure_boot_v2_digest_generate(image_data->start_addr, image_data->image_len - SIG_BLOCK_PADDING, app_pub_key_digest);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Application signature block is invalid.");
|
||||
@ -388,7 +383,7 @@ esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *imag
|
||||
}
|
||||
|
||||
/* Confirming if the public key in the bootloader's signature block matches with the one in the application's signature block */
|
||||
if (memcmp(boot_pub_key_digest, app_pub_key_digest, DIGEST_LEN) != 0) {
|
||||
if (memcmp(boot_pub_key_digest, app_pub_key_digest, ESP_SECURE_BOOT_DIGEST_LEN) != 0) {
|
||||
ESP_LOGE(TAG, "Application not signed with a valid private key.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
@ -1,184 +0,0 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_sha.h"
|
||||
#include "bootloader_utility.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_spi_flash.h"
|
||||
#include "esp_fault.h"
|
||||
#include "esp32/rom/sha.h"
|
||||
#include "uECC_verify_antifault.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <string.h>
|
||||
|
||||
static const char *TAG = "secure_boot";
|
||||
#define DIGEST_LEN 32
|
||||
|
||||
#ifdef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
|
||||
extern const uint8_t signature_verification_key_start[] asm("_binary_signature_verification_key_bin_start");
|
||||
extern const uint8_t signature_verification_key_end[] asm("_binary_signature_verification_key_bin_end");
|
||||
|
||||
#define SIGNATURE_VERIFICATION_KEYLEN 64
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
uint8_t digest[DIGEST_LEN];
|
||||
uint8_t verified_digest[DIGEST_LEN] = { 0 }; /* ignored in this function */
|
||||
const esp_secure_boot_sig_block_t *sigblock;
|
||||
|
||||
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
|
||||
|
||||
esp_err_t err = bootloader_sha256_flash_contents(src_addr, length, digest);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// Map the signature block
|
||||
sigblock = (const esp_secure_boot_sig_block_t *) bootloader_mmap(src_addr + length, sizeof(esp_secure_boot_sig_block_t));
|
||||
if(!sigblock) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr + length, sizeof(esp_secure_boot_sig_block_t));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
// Verify the signature
|
||||
err = esp_secure_boot_verify_ecdsa_signature_block(sigblock, digest, verified_digest);
|
||||
// Unmap
|
||||
bootloader_munmap(sigblock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature_block(const esp_secure_boot_sig_block_t *sig_block, const uint8_t *image_digest)
|
||||
{
|
||||
uint8_t verified_digest[DIGEST_LEN] = { 0 };
|
||||
return esp_secure_boot_verify_ecdsa_signature_block(sig_block, image_digest, verified_digest);
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_verify_ecdsa_signature_block(const esp_secure_boot_sig_block_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
ptrdiff_t keylen;
|
||||
|
||||
keylen = signature_verification_key_end - signature_verification_key_start;
|
||||
if (keylen != SIGNATURE_VERIFICATION_KEYLEN) {
|
||||
ESP_LOGE(TAG, "Embedded public verification key has wrong length %d", keylen);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (sig_block->version != 0) {
|
||||
ESP_LOGE(TAG, "image has invalid signature version field 0x%08x", sig_block->version);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Verifying secure boot signature");
|
||||
|
||||
bool is_valid;
|
||||
is_valid = uECC_verify_antifault(signature_verification_key_start,
|
||||
image_digest,
|
||||
DIGEST_LEN,
|
||||
sig_block->signature,
|
||||
uECC_secp256r1(),
|
||||
verified_digest);
|
||||
ESP_LOGD(TAG, "Verification result %d", is_valid);
|
||||
|
||||
return is_valid ? ESP_OK : ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
|
||||
#elif CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
uint8_t digest[DIGEST_LEN] = {0};
|
||||
uint8_t verified_digest[DIGEST_LEN] = {0}; // ignored in this function
|
||||
const uint8_t *data;
|
||||
|
||||
/* Padding to round off the input to the nearest 4k boundary */
|
||||
int padded_length = ALIGN_UP(length, FLASH_SECTOR_SIZE);
|
||||
ESP_LOGD(TAG, "verifying src_addr 0x%x length", src_addr, padded_length);
|
||||
|
||||
data = bootloader_mmap(src_addr, padded_length + sizeof(ets_secure_boot_signature_t));
|
||||
if (data == NULL) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr, padded_length);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Calculate digest of main image */
|
||||
esp_err_t err = bootloader_sha256_flash_contents(src_addr, padded_length, digest);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Digest calculation failed 0x%x, 0x%x", src_addr, padded_length);
|
||||
bootloader_munmap(data);
|
||||
return err;
|
||||
}
|
||||
|
||||
const ets_secure_boot_signature_t *sig_block = (const ets_secure_boot_signature_t *)(data + padded_length);
|
||||
err = esp_secure_boot_verify_rsa_signature_block(sig_block, digest, verified_digest);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Secure Boot V2 verification failed.");
|
||||
}
|
||||
|
||||
bootloader_munmap(data);
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
secure_boot_v2_status_t r;
|
||||
uint8_t efuse_trusted_digest[DIGEST_LEN] = {0}, sig_block_trusted_digest[DIGEST_LEN] = {0};
|
||||
|
||||
memcpy(efuse_trusted_digest, (uint8_t *)EFUSE_BLK2_RDATA0_REG, DIGEST_LEN); /* EFUSE_BLK2_RDATA0_REG - Stores the Secure Boot Public Key Digest */
|
||||
|
||||
if (!ets_use_secure_boot_v2()) {
|
||||
ESP_LOGI(TAG, "Secure Boot eFuse bit(ABS_DONE_1) not yet programmed.");
|
||||
|
||||
/* Generating the SHA of the public key components in the signature block */
|
||||
bootloader_sha256_handle_t sig_block_sha;
|
||||
sig_block_sha = bootloader_sha256_start();
|
||||
bootloader_sha256_data(sig_block_sha, &sig_block->block[0].key, sizeof(sig_block->block[0].key));
|
||||
bootloader_sha256_finish(sig_block_sha, (unsigned char *)sig_block_trusted_digest);
|
||||
|
||||
#if CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
if (memcmp(efuse_trusted_digest, sig_block_trusted_digest, DIGEST_LEN) != 0) {
|
||||
/* Most likely explanation for this is that BLK2 is empty, and we're going to burn it
|
||||
after we verify that the signature is valid. However, if BLK2 is not empty then we need to
|
||||
fail here.
|
||||
*/
|
||||
bool all_zeroes = true;
|
||||
for (int i = 0; i < DIGEST_LEN; i++) {
|
||||
all_zeroes = all_zeroes && (efuse_trusted_digest[i] == 0);
|
||||
}
|
||||
if (!all_zeroes) {
|
||||
ESP_LOGE(TAG, "Different public key digest burned to eFuse BLK2");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
|
||||
ESP_FAULT_ASSERT(!ets_use_secure_boot_v2());
|
||||
#endif
|
||||
|
||||
memcpy(efuse_trusted_digest, sig_block_trusted_digest, DIGEST_LEN);
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Verifying with RSA-PSS...");
|
||||
r = ets_secure_boot_verify_signature(sig_block, image_digest, efuse_trusted_digest, verified_digest);
|
||||
if (r != SBV2_SUCCESS) {
|
||||
ESP_LOGE(TAG, "Secure Boot V2 verification failed.");
|
||||
}
|
||||
|
||||
return (r == SBV2_SUCCESS) ? ESP_OK : ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
#endif
|
@ -264,24 +264,33 @@ static void bootloader_super_wdt_auto_feed(void)
|
||||
|
||||
static inline void bootloader_hardware_init(void)
|
||||
{
|
||||
// TODO ESP32-C3 IDF-2452
|
||||
REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_FORCE_XPD_IPH, 1);
|
||||
REGI2C_WRITE_MASK(I2C_BIAS, I2C_BIAS_DREG_1P1_PVT, 12);
|
||||
// This check is always included in the bootloader so it can
|
||||
// print the minimum revision error message later in the boot
|
||||
if (bootloader_common_get_chip_revision() < 3) {
|
||||
REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_FORCE_XPD_IPH, 1);
|
||||
REGI2C_WRITE_MASK(I2C_BIAS, I2C_BIAS_DREG_1P1_PVT, 12);
|
||||
}
|
||||
}
|
||||
|
||||
/* There happend clock glitch reset for some chip when testing wifi[BIT0] and brownout reset when chip startup[BIT1].
|
||||
* But super_watch_dog_reset function is ok, so open it[BIT2].
|
||||
* Whether this api will deleted or not depends on analog design & test result when ECO chip come back.
|
||||
*/
|
||||
static inline void bootloader_glitch_reset_disable(void)
|
||||
{
|
||||
// TODO ESP32-C3 IDF-2453
|
||||
REG_SET_FIELD(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_SEL, BIT2);
|
||||
/*
|
||||
For origin chip & ECO1: only support swt reset;
|
||||
For ECO2: fix brownout reset bug, support swt & brownout reset;
|
||||
For ECO3: fix clock glitch reset bug, support all reset, include: swt & brownout & clock glitch reset.
|
||||
*/
|
||||
uint8_t chip_version = bootloader_common_get_chip_revision();
|
||||
if (chip_version < 2) {
|
||||
REG_SET_FIELD(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_SEL, RTC_CNTL_FIB_SUPER_WDT_RST);
|
||||
} else if (chip_version == 2) {
|
||||
REG_SET_FIELD(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_SEL, RTC_CNTL_FIB_SUPER_WDT_RST | RTC_CNTL_FIB_BOR_RST);
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t bootloader_init(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
bootloader_hardware_init();
|
||||
bootloader_glitch_reset_disable();
|
||||
bootloader_super_wdt_auto_feed();
|
||||
|
@ -31,17 +31,11 @@
|
||||
static const char *TAG = "secure_boot_v2";
|
||||
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
#define SIG_BLOCK_MAGIC_BYTE 0xe7
|
||||
#define CRC_SIGN_BLOCK_LEN 1196
|
||||
#define SIG_BLOCK_PADDING 4096
|
||||
|
||||
#define DIGEST_LEN 32
|
||||
|
||||
/* A signature block is valid when it has correct magic byte, crc and image digest. */
|
||||
static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *block, int block_num, const uint8_t *image_digest)
|
||||
{
|
||||
uint32_t crc = esp_rom_crc32_le(0, (uint8_t *)block, CRC_SIGN_BLOCK_LEN);
|
||||
if (block->magic_byte != SIG_BLOCK_MAGIC_BYTE) {
|
||||
if (block->magic_byte != ETS_SECURE_BOOT_V2_SIGNATURE_MAGIC) {
|
||||
// All signature blocks have been parsed, no new signature block present.
|
||||
ESP_LOGD(TAG, "Signature block(%d) invalid/absent.", block_num);
|
||||
return ESP_FAIL;
|
||||
@ -50,7 +44,7 @@ static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *blo
|
||||
ESP_LOGE(TAG, "Magic byte correct but incorrect crc.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (memcmp(image_digest, block->image_digest, DIGEST_LEN)) {
|
||||
if (memcmp(image_digest, block->image_digest, ESP_SECURE_BOOT_DIGEST_LEN)) {
|
||||
ESP_LOGE(TAG, "Magic byte & CRC correct but incorrect image digest.");
|
||||
return ESP_FAIL;
|
||||
} else {
|
||||
@ -61,19 +55,6 @@ static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *blo
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Structure to hold public key digests calculated from the signature blocks of a single image.
|
||||
|
||||
Each image can have one or more signature blocks (up to SECURE_BOOT_NUM_BLOCKS). Each signature block
|
||||
includes a public key.
|
||||
|
||||
Different to the ROM ets_secure_boot_key_digests_t structure which holds pointers to eFuse data with digests,
|
||||
in this data structure the digest data is included.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t key_digests[SECURE_BOOT_NUM_BLOCKS][DIGEST_LEN];
|
||||
unsigned num_digests; /* Number of valid digests, starting at index 0 */
|
||||
} image_sig_public_key_digests_t;
|
||||
|
||||
/* Generates the public key digests of the valid public keys in an image's
|
||||
signature block, verifies each signature, and stores the key digests in the
|
||||
public_key_digests structure.
|
||||
@ -89,16 +70,16 @@ typedef struct {
|
||||
@return - ESP_OK if no signatures failed to verify, or if no valid signature blocks are found at all.
|
||||
- ESP_FAIL if there's a valid signature block that doesn't verify using the included public key (unexpected!)
|
||||
*/
|
||||
static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uint32_t flash_size, image_sig_public_key_digests_t *public_key_digests)
|
||||
static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uint32_t flash_size, esp_image_sig_public_key_digests_t *public_key_digests)
|
||||
{
|
||||
esp_err_t ret;
|
||||
uint8_t image_digest[DIGEST_LEN] = {0};
|
||||
uint8_t __attribute__((aligned(4))) key_digest[DIGEST_LEN] = {0};
|
||||
uint8_t image_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
uint8_t __attribute__((aligned(4))) key_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
size_t sig_block_addr = flash_offset + ALIGN_UP(flash_size, FLASH_SECTOR_SIZE);
|
||||
|
||||
ESP_LOGD(TAG, "calculating public key digests for sig blocks of image offset 0x%x (sig block offset 0x%x)", flash_offset, sig_block_addr);
|
||||
|
||||
bzero(public_key_digests, sizeof(image_sig_public_key_digests_t));
|
||||
bzero(public_key_digests, sizeof(esp_image_sig_public_key_digests_t));
|
||||
|
||||
ret = bootloader_sha256_flash_contents(flash_offset, sig_block_addr - flash_offset, image_digest);
|
||||
if (ret != ESP_OK) {
|
||||
@ -129,7 +110,7 @@ static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uin
|
||||
bootloader_sha256_finish(sig_block_sha, key_digest);
|
||||
|
||||
// Check we can verify the image using this signature and this key
|
||||
uint8_t temp_verified_digest[DIGEST_LEN];
|
||||
uint8_t temp_verified_digest[ESP_SECURE_BOOT_DIGEST_LEN];
|
||||
bool verified = ets_rsa_pss_verify(&block->key, block->signature, image_digest, temp_verified_digest);
|
||||
|
||||
if (!verified) {
|
||||
@ -142,7 +123,7 @@ static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uin
|
||||
}
|
||||
ESP_LOGD(TAG, "Signature block (%d) is verified", i);
|
||||
/* Copy the key digest to the buffer provided by the caller */
|
||||
memcpy((void *)public_key_digests->key_digests[i], key_digest, DIGEST_LEN);
|
||||
memcpy((void *)public_key_digests->key_digests[i], key_digest, ESP_SECURE_BOOT_DIGEST_LEN);
|
||||
public_key_digests->num_digests++;
|
||||
}
|
||||
|
||||
@ -173,8 +154,8 @@ static esp_err_t check_and_generate_secure_boot_keys(const esp_image_metadata_t
|
||||
ESP_LOGI(TAG, "Secure boot digests %s", has_secure_boot_digest ? "already present":"absent, generating..");
|
||||
|
||||
if (!has_secure_boot_digest) {
|
||||
image_sig_public_key_digests_t boot_key_digests = {0};
|
||||
image_sig_public_key_digests_t app_key_digests = {0};
|
||||
esp_image_sig_public_key_digests_t boot_key_digests = {0};
|
||||
esp_image_sig_public_key_digests_t app_key_digests = {0};
|
||||
|
||||
/* Generate the bootloader public key digests */
|
||||
ret = s_calculate_image_public_key_digests(bootloader_data.start_addr, bootloader_data.image_len - SIG_BLOCK_PADDING, &boot_key_digests);
|
||||
@ -234,7 +215,7 @@ static esp_err_t check_and_generate_secure_boot_keys(const esp_image_metadata_t
|
||||
}
|
||||
|
||||
for (int j = 0; j < app_key_digests.num_digests; j++) {
|
||||
if (!memcmp(boot_key_digests.key_digests[i], app_key_digests.key_digests[j], DIGEST_LEN)) {
|
||||
if (!memcmp(boot_key_digests.key_digests[i], app_key_digests.key_digests[j], ESP_SECURE_BOOT_DIGEST_LEN)) {
|
||||
ESP_LOGI(TAG, "Application key(%d) matches with bootloader key(%d).", j, i);
|
||||
match = true;
|
||||
}
|
||||
|
@ -1,94 +0,0 @@
|
||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "esp_fault.h"
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_sha.h"
|
||||
#include "bootloader_utility.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp32c3/rom/secure_boot.h"
|
||||
|
||||
static const char* TAG = "secure_boot";
|
||||
|
||||
#define DIGEST_LEN 32
|
||||
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
uint8_t digest[DIGEST_LEN];
|
||||
uint8_t verified_digest[DIGEST_LEN] = { 0 }; /* Note: this function doesn't do any anti-FI checks on this buffer */
|
||||
const uint8_t *data;
|
||||
|
||||
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
|
||||
|
||||
/* Padding to round off the input to the nearest 4k boundary */
|
||||
int padded_length = ALIGN_UP(length, FLASH_SECTOR_SIZE);
|
||||
ESP_LOGD(TAG, "verifying src_addr 0x%x length", src_addr, padded_length);
|
||||
|
||||
data = bootloader_mmap(src_addr, length + sizeof(struct ets_secure_boot_sig_block));
|
||||
if (data == NULL) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr, length+sizeof(ets_secure_boot_signature_t));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Calculate digest of main image */
|
||||
esp_err_t err = bootloader_sha256_flash_contents(src_addr, padded_length, digest);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Digest calculation failed 0x%x, 0x%x", src_addr, padded_length);
|
||||
bootloader_munmap(data);
|
||||
return err;
|
||||
}
|
||||
|
||||
const ets_secure_boot_signature_t *sig = (const ets_secure_boot_signature_t *)(data + length);
|
||||
int r = esp_secure_boot_verify_rsa_signature_block(sig, digest, verified_digest);
|
||||
bootloader_munmap(data);
|
||||
|
||||
return (r == ETS_OK) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
ets_secure_boot_key_digests_t trusted_keys;
|
||||
ets_secure_boot_key_digests_t trusted_key_copies[2];
|
||||
ETS_STATUS r;
|
||||
ets_secure_boot_status_t sb_result;
|
||||
|
||||
memset(&trusted_keys, 0, sizeof(ets_secure_boot_key_digests_t));
|
||||
memset(trusted_key_copies, 0, 2 * sizeof(ets_secure_boot_key_digests_t));
|
||||
|
||||
if (!esp_secure_boot_enabled()) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
r = ets_secure_boot_read_key_digests(&trusted_keys);
|
||||
if (r != ETS_OK) {
|
||||
ESP_LOGI(TAG, "Could not read secure boot digests!");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
// Create the copies for FI checks (assuming result is ETS_OK, if it's not then it'll fail the fault check anyhow)
|
||||
ets_secure_boot_read_key_digests(&trusted_key_copies[0]);
|
||||
ets_secure_boot_read_key_digests(&trusted_key_copies[1]);
|
||||
ESP_FAULT_ASSERT(memcmp(&trusted_keys, &trusted_key_copies[0], sizeof(ets_secure_boot_key_digests_t)) == 0);
|
||||
ESP_FAULT_ASSERT(memcmp(&trusted_keys, &trusted_key_copies[1], sizeof(ets_secure_boot_key_digests_t)) == 0);
|
||||
|
||||
ESP_LOGI(TAG, "Verifying with RSA-PSS boot...");
|
||||
sb_result = ets_secure_boot_verify_signature(sig_block, image_digest, &trusted_keys, verified_digest);
|
||||
return (sb_result == SB_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
@ -31,17 +31,11 @@
|
||||
static const char *TAG = "secure_boot_v2";
|
||||
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
#define SIG_BLOCK_MAGIC_BYTE 0xe7
|
||||
#define CRC_SIGN_BLOCK_LEN 1196
|
||||
#define SIG_BLOCK_PADDING 4096
|
||||
|
||||
#define DIGEST_LEN 32
|
||||
|
||||
/* A signature block is valid when it has correct magic byte, crc and image digest. */
|
||||
static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *block, int block_num, const uint8_t *image_digest)
|
||||
{
|
||||
uint32_t crc = esp_rom_crc32_le(0, (uint8_t *)block, CRC_SIGN_BLOCK_LEN);
|
||||
if (block->magic_byte != SIG_BLOCK_MAGIC_BYTE) {
|
||||
if (block->magic_byte != ETS_SECURE_BOOT_V2_SIGNATURE_MAGIC) {
|
||||
// All signature blocks have been parsed, no new signature block present.
|
||||
ESP_LOGD(TAG, "Signature block(%d) invalid/absent.", block_num);
|
||||
return ESP_FAIL;
|
||||
@ -50,7 +44,7 @@ static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *blo
|
||||
ESP_LOGE(TAG, "Magic byte correct but incorrect crc.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (memcmp(image_digest, block->image_digest, DIGEST_LEN)) {
|
||||
if (memcmp(image_digest, block->image_digest, ESP_SECURE_BOOT_DIGEST_LEN)) {
|
||||
ESP_LOGE(TAG, "Magic byte & CRC correct but incorrect image digest.");
|
||||
return ESP_FAIL;
|
||||
} else {
|
||||
@ -61,19 +55,6 @@ static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *blo
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Structure to hold public key digests calculated from the signature blocks of a single image.
|
||||
|
||||
Each image can have one or more signature blocks (up to SECURE_BOOT_NUM_BLOCKS). Each signature block
|
||||
includes a public key.
|
||||
|
||||
Different to the ROM ets_secure_boot_key_digests_t structure which holds pointers to eFuse data with digests,
|
||||
in this data structure the digest data is included.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t key_digests[SECURE_BOOT_NUM_BLOCKS][DIGEST_LEN];
|
||||
unsigned num_digests; /* Number of valid digests, starting at index 0 */
|
||||
} image_sig_public_key_digests_t;
|
||||
|
||||
/* Generates the public key digests of the valid public keys in an image's
|
||||
signature block, verifies each signature, and stores the key digests in the
|
||||
public_key_digests structure.
|
||||
@ -89,16 +70,16 @@ typedef struct {
|
||||
@return - ESP_OK if no signatures failed to verify, or if no valid signature blocks are found at all.
|
||||
- ESP_FAIL if there's a valid signature block that doesn't verify using the included public key (unexpected!)
|
||||
*/
|
||||
static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uint32_t flash_size, image_sig_public_key_digests_t *public_key_digests)
|
||||
static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uint32_t flash_size, esp_image_sig_public_key_digests_t *public_key_digests)
|
||||
{
|
||||
esp_err_t ret;
|
||||
uint8_t image_digest[DIGEST_LEN] = {0};
|
||||
uint8_t __attribute__((aligned(4))) key_digest[DIGEST_LEN] = {0};
|
||||
uint8_t image_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
uint8_t __attribute__((aligned(4))) key_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
size_t sig_block_addr = flash_offset + ALIGN_UP(flash_size, FLASH_SECTOR_SIZE);
|
||||
|
||||
ESP_LOGD(TAG, "calculating public key digests for sig blocks of image offset 0x%x (sig block offset 0x%x)", flash_offset, sig_block_addr);
|
||||
|
||||
bzero(public_key_digests, sizeof(image_sig_public_key_digests_t));
|
||||
bzero(public_key_digests, sizeof(esp_image_sig_public_key_digests_t));
|
||||
|
||||
ret = bootloader_sha256_flash_contents(flash_offset, sig_block_addr - flash_offset, image_digest);
|
||||
if (ret != ESP_OK) {
|
||||
@ -129,7 +110,7 @@ static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uin
|
||||
bootloader_sha256_finish(sig_block_sha, key_digest);
|
||||
|
||||
// Check we can verify the image using this signature and this key
|
||||
uint8_t temp_verified_digest[DIGEST_LEN];
|
||||
uint8_t temp_verified_digest[ESP_SECURE_BOOT_DIGEST_LEN];
|
||||
bool verified = ets_rsa_pss_verify(&block->key, block->signature, image_digest, temp_verified_digest);
|
||||
|
||||
if (!verified) {
|
||||
@ -142,7 +123,7 @@ static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uin
|
||||
}
|
||||
ESP_LOGD(TAG, "Signature block (%d) is verified", i);
|
||||
/* Copy the key digest to the buffer provided by the caller */
|
||||
memcpy((void *)public_key_digests->key_digests[i], key_digest, DIGEST_LEN);
|
||||
memcpy((void *)public_key_digests->key_digests[i], key_digest, ESP_SECURE_BOOT_DIGEST_LEN);
|
||||
public_key_digests->num_digests++;
|
||||
}
|
||||
|
||||
@ -173,8 +154,8 @@ static esp_err_t check_and_generate_secure_boot_keys(const esp_image_metadata_t
|
||||
ESP_LOGI(TAG, "Secure boot digests %s", has_secure_boot_digest ? "already present":"absent, generating..");
|
||||
|
||||
if (!has_secure_boot_digest) {
|
||||
image_sig_public_key_digests_t boot_key_digests = {0};
|
||||
image_sig_public_key_digests_t app_key_digests = {0};
|
||||
esp_image_sig_public_key_digests_t boot_key_digests = {0};
|
||||
esp_image_sig_public_key_digests_t app_key_digests = {0};
|
||||
|
||||
/* Generate the bootloader public key digests */
|
||||
ret = s_calculate_image_public_key_digests(bootloader_data.start_addr, bootloader_data.image_len - SIG_BLOCK_PADDING, &boot_key_digests);
|
||||
@ -234,7 +215,7 @@ static esp_err_t check_and_generate_secure_boot_keys(const esp_image_metadata_t
|
||||
}
|
||||
|
||||
for (int j = 0; j < app_key_digests.num_digests; j++) {
|
||||
if (!memcmp(boot_key_digests.key_digests[i], app_key_digests.key_digests[j], DIGEST_LEN)) {
|
||||
if (!memcmp(boot_key_digests.key_digests[i], app_key_digests.key_digests[j], ESP_SECURE_BOOT_DIGEST_LEN)) {
|
||||
ESP_LOGI(TAG, "Application key(%d) matches with bootloader key(%d).", j, i);
|
||||
match = true;
|
||||
}
|
||||
|
@ -1,93 +0,0 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "esp_fault.h"
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_sha.h"
|
||||
#include "bootloader_utility.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp32s2/rom/secure_boot.h"
|
||||
|
||||
static const char* TAG = "secure_boot";
|
||||
|
||||
#define DIGEST_LEN 32
|
||||
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
uint8_t digest[DIGEST_LEN];
|
||||
uint8_t verified_digest[DIGEST_LEN] = { 0 }; /* Note: this function doesn't do any anti-FI checks on this buffer */
|
||||
const uint8_t *data;
|
||||
|
||||
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
|
||||
|
||||
/* Padding to round off the input to the nearest 4k boundary */
|
||||
int padded_length = ALIGN_UP(length, FLASH_SECTOR_SIZE);
|
||||
ESP_LOGD(TAG, "verifying src_addr 0x%x length", src_addr, padded_length);
|
||||
|
||||
data = bootloader_mmap(src_addr, length + sizeof(struct ets_secure_boot_sig_block));
|
||||
if (data == NULL) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr, length+sizeof(ets_secure_boot_signature_t));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Calculate digest of main image */
|
||||
esp_err_t err = bootloader_sha256_flash_contents(src_addr, padded_length, digest);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Digest calculation failed 0x%x, 0x%x", src_addr, padded_length);
|
||||
bootloader_munmap(data);
|
||||
return err;
|
||||
}
|
||||
|
||||
const ets_secure_boot_signature_t *sig = (const ets_secure_boot_signature_t *)(data + length);
|
||||
int r = esp_secure_boot_verify_rsa_signature_block(sig, digest, verified_digest);
|
||||
bootloader_munmap(data);
|
||||
|
||||
return (r == ETS_OK) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
ets_secure_boot_key_digests_t trusted_keys;
|
||||
ets_secure_boot_key_digests_t trusted_key_copies[2];
|
||||
ETS_STATUS r;
|
||||
ets_secure_boot_status_t sb_result;
|
||||
|
||||
memset(&trusted_keys, 0, sizeof(ets_secure_boot_key_digests_t));
|
||||
memset(trusted_key_copies, 0, 2 * sizeof(ets_secure_boot_key_digests_t));
|
||||
|
||||
if (!esp_secure_boot_enabled()) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
r = ets_secure_boot_read_key_digests(&trusted_keys);
|
||||
if (r != ETS_OK) {
|
||||
ESP_LOGI(TAG, "Could not read secure boot digests!");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
// Create the copies for FI checks (assuming result is ETS_OK, if it's not then it'll fail the fault check anyhow)
|
||||
ets_secure_boot_read_key_digests(&trusted_key_copies[0]);
|
||||
ets_secure_boot_read_key_digests(&trusted_key_copies[1]);
|
||||
ESP_FAULT_ASSERT(memcmp(&trusted_keys, &trusted_key_copies[0], sizeof(ets_secure_boot_key_digests_t)) == 0);
|
||||
ESP_FAULT_ASSERT(memcmp(&trusted_keys, &trusted_key_copies[1], sizeof(ets_secure_boot_key_digests_t)) == 0);
|
||||
|
||||
ESP_LOGI(TAG, "Verifying with RSA-PSS boot...");
|
||||
sb_result = ets_secure_boot_verify_signature(sig_block, image_digest, &trusted_keys, verified_digest);
|
||||
return (sb_result == SB_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
@ -31,17 +31,11 @@
|
||||
static const char *TAG = "secure_boot_v2";
|
||||
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
#define SIG_BLOCK_MAGIC_BYTE 0xe7
|
||||
#define CRC_SIGN_BLOCK_LEN 1196
|
||||
#define SIG_BLOCK_PADDING 4096
|
||||
|
||||
#define DIGEST_LEN 32
|
||||
|
||||
/* A signature block is valid when it has correct magic byte, crc and image digest. */
|
||||
static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *block, int block_num, const uint8_t *image_digest)
|
||||
{
|
||||
uint32_t crc = esp_rom_crc32_le(0, (uint8_t *)block, CRC_SIGN_BLOCK_LEN);
|
||||
if (block->magic_byte != SIG_BLOCK_MAGIC_BYTE) {
|
||||
if (block->magic_byte != ETS_SECURE_BOOT_V2_SIGNATURE_MAGIC) {
|
||||
// All signature blocks have been parsed, no new signature block present.
|
||||
ESP_LOGD(TAG, "Signature block(%d) invalid/absent.", block_num);
|
||||
return ESP_FAIL;
|
||||
@ -50,7 +44,7 @@ static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *blo
|
||||
ESP_LOGE(TAG, "Magic byte correct but incorrect crc.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (memcmp(image_digest, block->image_digest, DIGEST_LEN)) {
|
||||
if (memcmp(image_digest, block->image_digest, ESP_SECURE_BOOT_DIGEST_LEN)) {
|
||||
ESP_LOGE(TAG, "Magic byte & CRC correct but incorrect image digest.");
|
||||
return ESP_FAIL;
|
||||
} else {
|
||||
@ -61,19 +55,6 @@ static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *blo
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Structure to hold public key digests calculated from the signature blocks of a single image.
|
||||
|
||||
Each image can have one or more signature blocks (up to SECURE_BOOT_NUM_BLOCKS). Each signature block
|
||||
includes a public key.
|
||||
|
||||
Different to the ROM ets_secure_boot_key_digests_t structure which holds pointers to eFuse data with digests,
|
||||
in this data structure the digest data is included.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t key_digests[SECURE_BOOT_NUM_BLOCKS][DIGEST_LEN];
|
||||
unsigned num_digests; /* Number of valid digests, starting at index 0 */
|
||||
} image_sig_public_key_digests_t;
|
||||
|
||||
/* Generates the public key digests of the valid public keys in an image's
|
||||
signature block, verifies each signature, and stores the key digests in the
|
||||
public_key_digests structure.
|
||||
@ -89,16 +70,16 @@ typedef struct {
|
||||
@return - ESP_OK if no signatures failed to verify, or if no valid signature blocks are found at all.
|
||||
- ESP_FAIL if there's a valid signature block that doesn't verify using the included public key (unexpected!)
|
||||
*/
|
||||
static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uint32_t flash_size, image_sig_public_key_digests_t *public_key_digests)
|
||||
static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uint32_t flash_size, esp_image_sig_public_key_digests_t *public_key_digests)
|
||||
{
|
||||
esp_err_t ret;
|
||||
uint8_t image_digest[DIGEST_LEN] = {0};
|
||||
uint8_t __attribute__((aligned(4))) key_digest[DIGEST_LEN] = {0};
|
||||
uint8_t image_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
uint8_t __attribute__((aligned(4))) key_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
size_t sig_block_addr = flash_offset + ALIGN_UP(flash_size, FLASH_SECTOR_SIZE);
|
||||
|
||||
ESP_LOGD(TAG, "calculating public key digests for sig blocks of image offset 0x%x (sig block offset 0x%x)", flash_offset, sig_block_addr);
|
||||
|
||||
bzero(public_key_digests, sizeof(image_sig_public_key_digests_t));
|
||||
bzero(public_key_digests, sizeof(esp_image_sig_public_key_digests_t));
|
||||
|
||||
ret = bootloader_sha256_flash_contents(flash_offset, sig_block_addr - flash_offset, image_digest);
|
||||
if (ret != ESP_OK) {
|
||||
@ -129,7 +110,7 @@ static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uin
|
||||
bootloader_sha256_finish(sig_block_sha, key_digest);
|
||||
|
||||
// Check we can verify the image using this signature and this key
|
||||
uint8_t temp_verified_digest[DIGEST_LEN];
|
||||
uint8_t temp_verified_digest[ESP_SECURE_BOOT_DIGEST_LEN];
|
||||
bool verified = ets_rsa_pss_verify(&block->key, block->signature, image_digest, temp_verified_digest);
|
||||
|
||||
if (!verified) {
|
||||
@ -142,7 +123,7 @@ static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uin
|
||||
}
|
||||
ESP_LOGD(TAG, "Signature block (%d) is verified", i);
|
||||
/* Copy the key digest to the buffer provided by the caller */
|
||||
memcpy((void *)public_key_digests->key_digests[i], key_digest, DIGEST_LEN);
|
||||
memcpy((void *)public_key_digests->key_digests[i], key_digest, ESP_SECURE_BOOT_DIGEST_LEN);
|
||||
public_key_digests->num_digests++;
|
||||
}
|
||||
|
||||
@ -173,8 +154,8 @@ static esp_err_t check_and_generate_secure_boot_keys(const esp_image_metadata_t
|
||||
ESP_LOGI(TAG, "Secure boot digests %s", has_secure_boot_digest ? "already present":"absent, generating..");
|
||||
|
||||
if (!has_secure_boot_digest) {
|
||||
image_sig_public_key_digests_t boot_key_digests = {0};
|
||||
image_sig_public_key_digests_t app_key_digests = {0};
|
||||
esp_image_sig_public_key_digests_t boot_key_digests = {0};
|
||||
esp_image_sig_public_key_digests_t app_key_digests = {0};
|
||||
|
||||
/* Generate the bootloader public key digests */
|
||||
ret = s_calculate_image_public_key_digests(bootloader_data.start_addr, bootloader_data.image_len - SIG_BLOCK_PADDING, &boot_key_digests);
|
||||
@ -234,7 +215,7 @@ static esp_err_t check_and_generate_secure_boot_keys(const esp_image_metadata_t
|
||||
}
|
||||
|
||||
for (int j = 0; j < app_key_digests.num_digests; j++) {
|
||||
if (!memcmp(boot_key_digests.key_digests[i], app_key_digests.key_digests[j], DIGEST_LEN)) {
|
||||
if (!memcmp(boot_key_digests.key_digests[i], app_key_digests.key_digests[j], ESP_SECURE_BOOT_DIGEST_LEN)) {
|
||||
ESP_LOGI(TAG, "Application key(%d) matches with bootloader key(%d).", j, i);
|
||||
match = true;
|
||||
}
|
||||
|
@ -1,93 +0,0 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_fault.h"
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_sha.h"
|
||||
#include "bootloader_utility.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp32s3/rom/secure_boot.h"
|
||||
|
||||
static const char* TAG = "secure_boot";
|
||||
|
||||
#define DIGEST_LEN 32
|
||||
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
uint8_t digest[DIGEST_LEN];
|
||||
uint8_t verified_digest[DIGEST_LEN] = { 0 }; /* Note: this function doesn't do any anti-FI checks on this buffer */
|
||||
const uint8_t *data;
|
||||
|
||||
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
|
||||
|
||||
/* Padding to round off the input to the nearest 4k boundary */
|
||||
int padded_length = ALIGN_UP(length, FLASH_SECTOR_SIZE);
|
||||
ESP_LOGD(TAG, "verifying src_addr 0x%x length", src_addr, padded_length);
|
||||
|
||||
data = bootloader_mmap(src_addr, length + sizeof(struct ets_secure_boot_sig_block));
|
||||
if (data == NULL) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr, length+sizeof(ets_secure_boot_signature_t));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Calculate digest of main image */
|
||||
esp_err_t err = bootloader_sha256_flash_contents(src_addr, padded_length, digest);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Digest calculation failed 0x%x, 0x%x", src_addr, padded_length);
|
||||
bootloader_munmap(data);
|
||||
return err;
|
||||
}
|
||||
|
||||
const ets_secure_boot_signature_t *sig = (const ets_secure_boot_signature_t *)(data + length);
|
||||
int r = esp_secure_boot_verify_rsa_signature_block(sig, digest, verified_digest);
|
||||
bootloader_munmap(data);
|
||||
|
||||
return (r == ETS_OK) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
ets_secure_boot_key_digests_t trusted_keys;
|
||||
ets_secure_boot_key_digests_t trusted_key_copies[2];
|
||||
ETS_STATUS r;
|
||||
ets_secure_boot_status_t sb_result;
|
||||
|
||||
memset(&trusted_keys, 0, sizeof(ets_secure_boot_key_digests_t));
|
||||
memset(trusted_key_copies, 0, 2 * sizeof(ets_secure_boot_key_digests_t));
|
||||
|
||||
if (!esp_secure_boot_enabled()) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
r = ets_secure_boot_read_key_digests(&trusted_keys);
|
||||
if (r != ETS_OK) {
|
||||
ESP_LOGI(TAG, "Could not read secure boot digests!");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
// Create the copies for FI checks (assuming result is ETS_OK, if it's not then it'll fail the fault check anyhow)
|
||||
ets_secure_boot_read_key_digests(&trusted_key_copies[0]);
|
||||
ets_secure_boot_read_key_digests(&trusted_key_copies[1]);
|
||||
ESP_FAULT_ASSERT(memcmp(&trusted_keys, &trusted_key_copies[0], sizeof(ets_secure_boot_key_digests_t)) == 0);
|
||||
ESP_FAULT_ASSERT(memcmp(&trusted_keys, &trusted_key_copies[1], sizeof(ets_secure_boot_key_digests_t)) == 0);
|
||||
|
||||
ESP_LOGI(TAG, "Verifying with RSA-PSS boot...");
|
||||
sb_result = ets_secure_boot_verify_signature(sig_block, image_digest, &trusted_keys, verified_digest);
|
||||
return (sb_result == SB_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
@ -47,10 +47,14 @@
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
#ifdef CONFIG_SECURE_SIGNED_ON_BOOT
|
||||
#define SECURE_BOOT_CHECK_SIGNATURE 1
|
||||
#else
|
||||
#define SECURE_BOOT_CHECK_SIGNATURE 0
|
||||
#endif
|
||||
#else /* !BOOTLOADER_BUILD */
|
||||
#ifdef CONFIG_SECURE_SIGNED_ON_UPDATE
|
||||
#define SECURE_BOOT_CHECK_SIGNATURE 1
|
||||
#else
|
||||
#define SECURE_BOOT_CHECK_SIGNATURE 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -77,6 +81,7 @@ static bool should_load(uint32_t load_addr);
|
||||
/* Return true if load_addr is an address the bootloader should map via flash cache */
|
||||
static bool should_map(uint32_t load_addr);
|
||||
|
||||
static esp_err_t process_segments(esp_image_metadata_t *data, bool silent, bool do_load, bootloader_sha256_handle_t sha_handle, uint32_t *checksum);
|
||||
/* Load or verify a segment */
|
||||
static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segment_header_t *header, bool silent, bool do_load, bootloader_sha256_handle_t sha_handle, uint32_t *checksum);
|
||||
|
||||
@ -98,7 +103,16 @@ static esp_err_t verify_segment_header(int index, const esp_image_segment_header
|
||||
} \
|
||||
while(0)
|
||||
|
||||
static esp_err_t verify_checksum(bootloader_sha256_handle_t sha_handle, uint32_t checksum_word, esp_image_metadata_t *data);
|
||||
#define CHECK_ERR(func) do { \
|
||||
if ((err = func) != ESP_OK) { \
|
||||
goto err; \
|
||||
} \
|
||||
} \
|
||||
while(0)
|
||||
|
||||
static esp_err_t process_image_header(esp_image_metadata_t *data, uint32_t part_offset, bootloader_sha256_handle_t *sha_handle, bool do_verify, bool silent);
|
||||
static esp_err_t process_appended_hash(esp_image_metadata_t *data, uint32_t part_len, bool do_verify, bool silent);
|
||||
static esp_err_t process_checksum(bootloader_sha256_handle_t sha_handle, uint32_t checksum_word, esp_image_metadata_t *data, bool silent, bool skip_check_checksum);
|
||||
|
||||
static esp_err_t __attribute__((unused)) verify_secure_boot_signature(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data, uint8_t *image_digest, uint8_t *verified_digest);
|
||||
static esp_err_t __attribute__((unused)) verify_simple_hash(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data);
|
||||
@ -116,13 +130,22 @@ static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_
|
||||
esp_err_t err = ESP_OK;
|
||||
// checksum the image a word at a time. This shaves 30-40ms per MB of image size
|
||||
uint32_t checksum_word = ESP_ROM_CHECKSUM_INITIAL;
|
||||
uint32_t *checksum = NULL;
|
||||
uint32_t *checksum = (do_verify) ? &checksum_word : NULL;
|
||||
bootloader_sha256_handle_t sha_handle = NULL;
|
||||
#if SECURE_BOOT_CHECK_SIGNATURE
|
||||
#if (SECURE_BOOT_CHECK_SIGNATURE == 1)
|
||||
/* used for anti-FI checks */
|
||||
uint8_t image_digest[HASH_LEN] = { [ 0 ... 31] = 0xEE };
|
||||
uint8_t verified_digest[HASH_LEN] = { [ 0 ... 31 ] = 0x01 };
|
||||
#endif
|
||||
#if CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
// For Secure Boot V2, we do verify signature on bootloader which includes the SHA calculation.
|
||||
bool verify_sha = do_verify;
|
||||
#else // Secure boot not enabled
|
||||
// For secure boot V1 on ESP32, we don't calculate SHA or verify signature on bootloaders.
|
||||
// (For non-secure boot, we don't verify any SHA-256 hash appended to the bootloader because
|
||||
// esptool.py may have rewritten the header - rely on esptool.py having verified the bootloader at flashing time, instead.)
|
||||
bool verify_sha = (part->offset != ESP_BOOTLOADER_OFFSET) && do_verify;
|
||||
#endif
|
||||
|
||||
if (data == NULL || part == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
@ -133,142 +156,41 @@ static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_
|
||||
FAIL_LOAD("partition size 0x%x invalid, larger than 16MB", part->size);
|
||||
}
|
||||
|
||||
bzero(data, sizeof(esp_image_metadata_t));
|
||||
data->start_addr = part->offset;
|
||||
|
||||
ESP_LOGD(TAG, "reading image header @ 0x%x", data->start_addr);
|
||||
err = bootloader_flash_read(data->start_addr, &data->image, sizeof(esp_image_header_t), true);
|
||||
if (err != ESP_OK) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (do_verify) {
|
||||
checksum = &checksum_word;
|
||||
|
||||
// Calculate SHA-256 of image if secure boot is on, or if image has a hash appended
|
||||
#ifdef SECURE_BOOT_CHECK_SIGNATURE
|
||||
if (1) {
|
||||
#else
|
||||
if (data->image.hash_appended) {
|
||||
#endif
|
||||
sha_handle = bootloader_sha256_start();
|
||||
if (sha_handle == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
bootloader_sha256_data(sha_handle, &data->image, sizeof(esp_image_header_t));
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "image header: 0x%02x 0x%02x 0x%02x 0x%02x %08x",
|
||||
data->image.magic,
|
||||
data->image.segment_count,
|
||||
data->image.spi_mode,
|
||||
data->image.spi_size,
|
||||
data->image.entry_addr);
|
||||
|
||||
err = verify_image_header(data->start_addr, &data->image, silent);
|
||||
if (err != ESP_OK) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (data->image.segment_count > ESP_IMAGE_MAX_SEGMENTS) {
|
||||
FAIL_LOAD("image at 0x%x segment count %d exceeds max %d",
|
||||
data->start_addr, data->image.segment_count, ESP_IMAGE_MAX_SEGMENTS);
|
||||
}
|
||||
} // if (do_verify)
|
||||
|
||||
uint32_t next_addr = data->start_addr + sizeof(esp_image_header_t);
|
||||
for (int i = 0; i < data->image.segment_count; i++) {
|
||||
esp_image_segment_header_t *header = &data->segments[i];
|
||||
ESP_LOGV(TAG, "loading segment header %d at offset 0x%x", i, next_addr);
|
||||
|
||||
err = process_segment(i, next_addr, header, silent, do_load, sha_handle, checksum);
|
||||
if (err != ESP_OK) {
|
||||
goto err;
|
||||
}
|
||||
next_addr += sizeof(esp_image_segment_header_t);
|
||||
data->segment_data[i] = next_addr;
|
||||
next_addr += header->data_len;
|
||||
}
|
||||
|
||||
if (do_verify) {
|
||||
// Segments all loaded, verify length
|
||||
uint32_t end_addr = next_addr;
|
||||
if (end_addr < data->start_addr) {
|
||||
FAIL_LOAD("image offset has wrapped");
|
||||
}
|
||||
|
||||
data->image_len = end_addr - data->start_addr;
|
||||
ESP_LOGV(TAG, "image start 0x%08x end of last section 0x%08x", data->start_addr, end_addr);
|
||||
if (NULL != checksum && !esp_cpu_in_ocd_debug_mode()) {
|
||||
err = verify_checksum(sha_handle, checksum_word, data);
|
||||
if (err != ESP_OK) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
/* For secure boot V1 on ESP32, we don't calculate SHA or verify signature on bootloaders.
|
||||
For Secure Boot V2, we do verify signature on bootloader which includes the SHA calculation.
|
||||
|
||||
(For non-secure boot, we don't verify any SHA-256 hash appended to the bootloader because
|
||||
esptool.py may have rewritten the header - rely on esptool.py having verified the bootloader at flashing time, instead.)
|
||||
*/
|
||||
bool verify_sha;
|
||||
#if CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
verify_sha = true;
|
||||
#else // Secure boot not enabled
|
||||
verify_sha = (data->start_addr != ESP_BOOTLOADER_OFFSET);
|
||||
#endif
|
||||
|
||||
if (verify_sha) {
|
||||
if (data->image_len > part->size) {
|
||||
FAIL_LOAD("Image length %d doesn't fit in partition length %d", data->image_len, part->size);
|
||||
}
|
||||
|
||||
#ifdef SECURE_BOOT_CHECK_SIGNATURE
|
||||
// secure boot images have a signature appended
|
||||
bootloader_sha256_handle_t *p_sha_handle = &sha_handle;
|
||||
CHECK_ERR(process_image_header(data, part->offset, (verify_sha) ? p_sha_handle : NULL, do_verify, silent));
|
||||
CHECK_ERR(process_segments(data, silent, do_load, sha_handle, checksum));
|
||||
bool skip_check_checksum = !do_verify || esp_cpu_in_ocd_debug_mode();
|
||||
CHECK_ERR(process_checksum(sha_handle, checksum_word, data, silent, skip_check_checksum));
|
||||
CHECK_ERR(process_appended_hash(data, part->size, do_verify, silent));
|
||||
if (verify_sha) {
|
||||
#if (SECURE_BOOT_CHECK_SIGNATURE == 1)
|
||||
// secure boot images have a signature appended
|
||||
#if defined(BOOTLOADER_BUILD) && !defined(CONFIG_SECURE_BOOT)
|
||||
// If secure boot is not enabled in hardware, then
|
||||
// skip the signature check in bootloader when the debugger is attached.
|
||||
// This is done to allow for breakpoints in Flash.
|
||||
if (!esp_cpu_in_ocd_debug_mode()) {
|
||||
// If secure boot is not enabled in hardware, then
|
||||
// skip the signature check in bootloader when the debugger is attached.
|
||||
// This is done to allow for breakpoints in Flash.
|
||||
bool do_verify_sig = !esp_cpu_in_ocd_debug_mode();
|
||||
#else // CONFIG_SECURE_BOOT
|
||||
if (true) {
|
||||
bool do_verify_sig = true;
|
||||
#endif // end checking for JTAG
|
||||
err = verify_secure_boot_signature(sha_handle, data, image_digest, verified_digest);
|
||||
sha_handle = NULL; // verify_secure_boot_signature finishes sha_handle
|
||||
}
|
||||
#else // SECURE_BOOT_CHECK_SIGNATURE
|
||||
// No secure boot, but SHA-256 can be appended for basic corruption detection
|
||||
if (sha_handle != NULL && !esp_cpu_in_ocd_debug_mode()) {
|
||||
err = verify_simple_hash(sha_handle, data);
|
||||
#ifdef CONFIG_IDF_ENV_FPGA
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "Ignoring invalid SHA-256 as running on FPGA");
|
||||
err = ESP_OK;
|
||||
}
|
||||
#endif
|
||||
sha_handle = NULL; // calling verify_simple_hash finishes sha_handle
|
||||
}
|
||||
#endif // SECURE_BOOT_CHECK_SIGNATURE
|
||||
} else { // verify_sha
|
||||
// bootloader may still have a sha256 digest handle open
|
||||
if (sha_handle != NULL) {
|
||||
bootloader_sha256_finish(sha_handle, NULL);
|
||||
}
|
||||
sha_handle = NULL;
|
||||
} //verify_sha
|
||||
|
||||
// Separately, if there's a hash appended to the image then copy it out to the data->image_digest field
|
||||
if (data->image.hash_appended) {
|
||||
const void *hash = bootloader_mmap(data->start_addr + data->image_len - HASH_LEN, HASH_LEN);
|
||||
if (hash == NULL) {
|
||||
err = ESP_FAIL;
|
||||
goto err;
|
||||
}
|
||||
memcpy(data->image_digest, hash, HASH_LEN);
|
||||
bootloader_munmap(hash);
|
||||
if (do_verify_sig) {
|
||||
err = verify_secure_boot_signature(sha_handle, data, image_digest, verified_digest);
|
||||
sha_handle = NULL; // verify_secure_boot_signature finishes sha_handle
|
||||
}
|
||||
} // do_verify
|
||||
#else // SECURE_BOOT_CHECK_SIGNATURE
|
||||
// No secure boot, but SHA-256 can be appended for basic corruption detection
|
||||
if (sha_handle != NULL && !esp_cpu_in_ocd_debug_mode()) {
|
||||
err = verify_simple_hash(sha_handle, data);
|
||||
sha_handle = NULL; // calling verify_simple_hash finishes sha_handle
|
||||
}
|
||||
#endif // SECURE_BOOT_CHECK_SIGNATURE
|
||||
} // verify_sha
|
||||
|
||||
// bootloader may still have a sha256 digest handle open
|
||||
if (sha_handle != NULL) {
|
||||
bootloader_sha256_finish(sha_handle, NULL);
|
||||
sha_handle = NULL;
|
||||
}
|
||||
|
||||
if (err != ESP_OK) {
|
||||
goto err;
|
||||
@ -276,7 +198,7 @@ static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_
|
||||
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
|
||||
#ifdef SECURE_BOOT_CHECK_SIGNATURE
|
||||
#if (SECURE_BOOT_CHECK_SIGNATURE == 1)
|
||||
/* If signature was checked in bootloader build, verified_digest should equal image_digest
|
||||
|
||||
This is to detect any fault injection that caused signature verification to not complete normally.
|
||||
@ -307,7 +229,7 @@ static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif // BOOTLOADER_BUILD
|
||||
|
||||
// Success!
|
||||
return ESP_OK;
|
||||
@ -327,11 +249,24 @@ err:
|
||||
|
||||
esp_err_t bootloader_load_image(const esp_partition_pos_t *part, esp_image_metadata_t *data)
|
||||
{
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
return image_load(ESP_IMAGE_LOAD, part, data);
|
||||
#else
|
||||
#if !defined(BOOTLOADER_BUILD)
|
||||
return ESP_FAIL;
|
||||
#endif
|
||||
#else
|
||||
esp_image_load_mode_t mode = ESP_IMAGE_LOAD;
|
||||
|
||||
#if !defined(CONFIG_SECURE_BOOT)
|
||||
/* Skip validation under particular configurations */
|
||||
#if CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS
|
||||
mode = ESP_IMAGE_LOAD_NO_VALIDATE;
|
||||
#elif CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON
|
||||
if (rtc_get_reset_reason(0) == POWERON_RESET) {
|
||||
mode = ESP_IMAGE_LOAD_NO_VALIDATE;
|
||||
}
|
||||
#endif // CONFIG_BOOTLOADER_SKIP_...
|
||||
#endif // CONFIG_SECURE_BOOT
|
||||
|
||||
return image_load(mode, part, data);
|
||||
#endif // BOOTLOADER_BUILD
|
||||
}
|
||||
|
||||
esp_err_t bootloader_load_image_no_verify(const esp_partition_pos_t *part, esp_image_metadata_t *data)
|
||||
@ -348,15 +283,39 @@ esp_err_t esp_image_verify(esp_image_load_mode_t mode, const esp_partition_pos_t
|
||||
return image_load(mode, part, data);
|
||||
}
|
||||
|
||||
esp_err_t esp_image_get_metadata(const esp_partition_pos_t *part, esp_image_metadata_t *metadata)
|
||||
{
|
||||
esp_err_t err;
|
||||
if (metadata == NULL || part == NULL || part->size > SIXTEEN_MB) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
bool silent = true;
|
||||
bool do_verify = false;
|
||||
bool do_load = false;
|
||||
CHECK_ERR(process_image_header(metadata, part->offset, NULL, do_verify, silent));
|
||||
CHECK_ERR(process_segments(metadata, silent, do_load, NULL, NULL));
|
||||
bool skip_check_checksum = true;
|
||||
CHECK_ERR(process_checksum(NULL, 0, metadata, silent, skip_check_checksum));
|
||||
CHECK_ERR(process_appended_hash(metadata, part->size, true, silent));
|
||||
return ESP_OK;
|
||||
err:
|
||||
return err;
|
||||
}
|
||||
|
||||
static esp_err_t verify_image_header(uint32_t src_addr, const esp_image_header_t *image, bool silent)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
ESP_LOGD(TAG, "image header: 0x%02x 0x%02x 0x%02x 0x%02x %08x",
|
||||
image->magic,
|
||||
image->segment_count,
|
||||
image->spi_mode,
|
||||
image->spi_size,
|
||||
image->entry_addr);
|
||||
|
||||
if (image->magic != ESP_IMAGE_HEADER_MAGIC) {
|
||||
if (!silent) {
|
||||
ESP_LOGE(TAG, "image at 0x%x has invalid magic byte", src_addr);
|
||||
}
|
||||
err = ESP_ERR_IMAGE_INVALID;
|
||||
FAIL_LOAD("image at 0x%x has invalid magic byte (nothing flashed here?)", src_addr);
|
||||
}
|
||||
if (!silent) {
|
||||
if (image->spi_mode > ESP_IMAGE_SPI_MODE_SLOW_READ) {
|
||||
@ -370,15 +329,19 @@ static esp_err_t verify_image_header(uint32_t src_addr, const esp_image_header_t
|
||||
}
|
||||
}
|
||||
|
||||
if (err == ESP_OK) {
|
||||
// Checking the chip revision header *will* print a bunch of other info
|
||||
// regardless of silent setting as this may be important, but don't bother checking it
|
||||
// if it looks like the app partition is erased or otherwise garbage
|
||||
if (bootloader_common_check_chip_validity(image, ESP_IMAGE_APPLICATION) != ESP_OK) {
|
||||
err = ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
}
|
||||
// Checking the chip revision header *will* print a bunch of other info
|
||||
// regardless of silent setting as this may be important, but don't bother checking it
|
||||
// if it looks like the app partition is erased or otherwise garbage
|
||||
CHECK_ERR(bootloader_common_check_chip_validity(image, ESP_IMAGE_APPLICATION));
|
||||
|
||||
if (image->segment_count > ESP_IMAGE_MAX_SEGMENTS) {
|
||||
FAIL_LOAD("image at 0x%x segment count %d exceeds max %d", src_addr, image->segment_count, ESP_IMAGE_MAX_SEGMENTS);
|
||||
}
|
||||
return err;
|
||||
err:
|
||||
if (err == ESP_OK) {
|
||||
err = ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -503,6 +466,63 @@ static bool verify_load_addresses(int segment_index, intptr_t load_addr, intptr_
|
||||
}
|
||||
#endif // BOOTLOADER_BUILD
|
||||
|
||||
static esp_err_t process_image_header(esp_image_metadata_t *data, uint32_t part_offset, bootloader_sha256_handle_t *sha_handle, bool do_verify, bool silent)
|
||||
{
|
||||
esp_err_t err;
|
||||
bzero(data, sizeof(esp_image_metadata_t));
|
||||
data->start_addr = part_offset;
|
||||
|
||||
ESP_LOGD(TAG, "reading image header @ 0x%x", data->start_addr);
|
||||
CHECK_ERR(bootloader_flash_read(data->start_addr, &data->image, sizeof(esp_image_header_t), true));
|
||||
|
||||
if (do_verify) {
|
||||
// Calculate SHA-256 of image if secure boot is on, or if image has a hash appended
|
||||
if (SECURE_BOOT_CHECK_SIGNATURE || data->image.hash_appended) {
|
||||
if (sha_handle != NULL) {
|
||||
*sha_handle = bootloader_sha256_start();
|
||||
if (*sha_handle == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
bootloader_sha256_data(*sha_handle, &data->image, sizeof(esp_image_header_t));
|
||||
}
|
||||
}
|
||||
CHECK_ERR(verify_image_header(data->start_addr, &data->image, silent));
|
||||
}
|
||||
data->image_len = sizeof(esp_image_header_t);
|
||||
return ESP_OK;
|
||||
err:
|
||||
return err;
|
||||
}
|
||||
|
||||
static esp_err_t process_segments(esp_image_metadata_t *data, bool silent, bool do_load, bootloader_sha256_handle_t sha_handle, uint32_t *checksum)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
uint32_t start_segments = data->start_addr + data->image_len;
|
||||
uint32_t next_addr = start_segments;
|
||||
for (int i = 0; i < data->image.segment_count; i++) {
|
||||
esp_image_segment_header_t *header = &data->segments[i];
|
||||
ESP_LOGV(TAG, "loading segment header %d at offset 0x%x", i, next_addr);
|
||||
CHECK_ERR(process_segment(i, next_addr, header, silent, do_load, sha_handle, checksum));
|
||||
next_addr += sizeof(esp_image_segment_header_t);
|
||||
data->segment_data[i] = next_addr;
|
||||
next_addr += header->data_len;
|
||||
}
|
||||
// Segments all loaded, verify length
|
||||
uint32_t end_addr = next_addr;
|
||||
if (end_addr < data->start_addr) {
|
||||
FAIL_LOAD("image offset has wrapped");
|
||||
}
|
||||
|
||||
data->image_len += end_addr - start_segments;
|
||||
ESP_LOGV(TAG, "image start 0x%08x end of last section 0x%08x", data->start_addr, end_addr);
|
||||
return err;
|
||||
err:
|
||||
if (err == ESP_OK) {
|
||||
err = ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segment_header_t *header, bool silent, bool do_load, bootloader_sha256_handle_t sha_handle, uint32_t *checksum)
|
||||
{
|
||||
esp_err_t err;
|
||||
@ -523,10 +543,7 @@ static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segme
|
||||
|
||||
ESP_LOGV(TAG, "segment data length 0x%x data starts 0x%x", data_len, data_addr);
|
||||
|
||||
err = verify_segment_header(index, header, data_addr, silent);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
CHECK_ERR(verify_segment_header(index, header, data_addr, silent));
|
||||
|
||||
if (data_len % 4 != 0) {
|
||||
FAIL_LOAD("unaligned segment length 0x%x", data_len);
|
||||
@ -557,17 +574,14 @@ static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segme
|
||||
|
||||
uint32_t data_len_remain = data_len;
|
||||
while (data_len_remain > 0) {
|
||||
#if SECURE_BOOT_CHECK_SIGNATURE && defined(BOOTLOADER_BUILD)
|
||||
#if (SECURE_BOOT_CHECK_SIGNATURE == 1) && defined(BOOTLOADER_BUILD)
|
||||
/* Double check the address verification done above */
|
||||
ESP_FAULT_ASSERT(!do_load || verify_load_addresses(0, load_addr, load_addr + data_len_remain, false, false));
|
||||
#endif
|
||||
uint32_t offset_page = ((data_addr & MMAP_ALIGNED_MASK) != 0) ? 1 : 0;
|
||||
/* Data we could map in case we are not aligned to PAGE boundary is one page size lesser. */
|
||||
data_len = MIN(data_len_remain, ((free_page_count - offset_page) * SPI_FLASH_MMU_PAGE_SIZE));
|
||||
err = process_segment_data(load_addr, data_addr, data_len, do_load, sha_handle, checksum);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
CHECK_ERR(process_segment_data(load_addr, data_addr, data_len, do_load, sha_handle, checksum));
|
||||
data_addr += data_len;
|
||||
data_len_remain -= data_len;
|
||||
}
|
||||
@ -742,41 +756,64 @@ esp_err_t esp_image_verify_bootloader_data(esp_image_metadata_t *data)
|
||||
data);
|
||||
}
|
||||
|
||||
|
||||
static esp_err_t verify_checksum(bootloader_sha256_handle_t sha_handle, uint32_t checksum_word, esp_image_metadata_t *data)
|
||||
static esp_err_t process_appended_hash(esp_image_metadata_t *data, uint32_t part_len, bool do_verify, bool silent)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
if (data->image.hash_appended) {
|
||||
// Account for the hash in the total image length
|
||||
if (do_verify) {
|
||||
CHECK_ERR(bootloader_flash_read(data->start_addr + data->image_len, &data->image_digest, HASH_LEN, true));
|
||||
}
|
||||
data->image_len += HASH_LEN;
|
||||
}
|
||||
|
||||
if (data->image_len > part_len) {
|
||||
FAIL_LOAD("Image length %d doesn't fit in partition length %d", data->image_len, part_len);
|
||||
}
|
||||
return err;
|
||||
err:
|
||||
if (err == ESP_OK) {
|
||||
err = ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static esp_err_t process_checksum(bootloader_sha256_handle_t sha_handle, uint32_t checksum_word, esp_image_metadata_t *data, bool silent, bool skip_check_checksum)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
uint32_t unpadded_length = data->image_len;
|
||||
uint32_t length = unpadded_length + 1; // Add a byte for the checksum
|
||||
length = (length + 15) & ~15; // Pad to next full 16 byte block
|
||||
length = length - unpadded_length;
|
||||
|
||||
// Verify checksum
|
||||
WORD_ALIGNED_ATTR uint8_t buf[16];
|
||||
esp_err_t err = bootloader_flash_read(data->start_addr + unpadded_length, buf, length - unpadded_length, true);
|
||||
uint8_t calc = buf[length - unpadded_length - 1];
|
||||
uint8_t checksum = (checksum_word >> 24)
|
||||
^ (checksum_word >> 16)
|
||||
^ (checksum_word >> 8)
|
||||
^ (checksum_word >> 0);
|
||||
if (err != ESP_OK || checksum != calc) {
|
||||
ESP_LOGE(TAG, "Checksum failed. Calculated 0x%x read 0x%x", checksum, calc);
|
||||
return ESP_ERR_IMAGE_INVALID;
|
||||
if (!skip_check_checksum || sha_handle != NULL) {
|
||||
CHECK_ERR(bootloader_flash_read(data->start_addr + unpadded_length, buf, length, true));
|
||||
}
|
||||
uint8_t read_checksum = buf[length - 1];
|
||||
uint8_t calc_checksum = (checksum_word >> 24) ^ (checksum_word >> 16) ^ (checksum_word >> 8) ^ (checksum_word >> 0);
|
||||
if (!skip_check_checksum && calc_checksum != read_checksum) {
|
||||
FAIL_LOAD("Checksum failed. Calculated 0x%x read 0x%x", calc_checksum, read_checksum);
|
||||
}
|
||||
if (sha_handle != NULL) {
|
||||
bootloader_sha256_data(sha_handle, buf, length - unpadded_length);
|
||||
bootloader_sha256_data(sha_handle, buf, length);
|
||||
}
|
||||
data->image_len += length;
|
||||
|
||||
return err;
|
||||
err:
|
||||
if (err == ESP_OK) {
|
||||
err = ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
|
||||
if (data->image.hash_appended) {
|
||||
// Account for the hash in the total image length
|
||||
length += HASH_LEN;
|
||||
}
|
||||
data->image_len = length;
|
||||
|
||||
return ESP_OK;
|
||||
return err;
|
||||
}
|
||||
|
||||
static esp_err_t verify_secure_boot_signature(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data, uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
#ifdef SECURE_BOOT_CHECK_SIGNATURE
|
||||
#if (SECURE_BOOT_CHECK_SIGNATURE == 1)
|
||||
uint32_t end = data->start_addr + data->image_len;
|
||||
|
||||
ESP_LOGI(TAG, "Verifying image signature...");
|
||||
@ -808,18 +845,18 @@ static esp_err_t verify_secure_boot_signature(bootloader_sha256_handle_t sha_han
|
||||
|
||||
// Use hash to verify signature block
|
||||
esp_err_t err = ESP_ERR_IMAGE_INVALID;
|
||||
#if defined(CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME) || defined(CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME)
|
||||
const void *sig_block;
|
||||
#ifdef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
|
||||
ESP_FAULT_ASSERT(memcmp(image_digest, verified_digest, HASH_LEN) != 0); /* sanity check that these values start differently */
|
||||
#ifdef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
|
||||
sig_block = bootloader_mmap(data->start_addr + data->image_len, sizeof(esp_secure_boot_sig_block_t));
|
||||
err = esp_secure_boot_verify_ecdsa_signature_block(sig_block, image_digest, verified_digest);
|
||||
#elif CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
ESP_FAULT_ASSERT(memcmp(image_digest, verified_digest, HASH_LEN) != 0); /* sanity check that these values start differently */
|
||||
#else
|
||||
sig_block = bootloader_mmap(end, sizeof(ets_secure_boot_signature_t));
|
||||
err = esp_secure_boot_verify_rsa_signature_block(sig_block, image_digest, verified_digest);
|
||||
#endif
|
||||
|
||||
bootloader_munmap(sig_block);
|
||||
#endif // CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME or CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Secure boot signature verification failed");
|
||||
|
||||
@ -857,15 +894,16 @@ static esp_err_t verify_simple_hash(bootloader_sha256_handle_t sha_handle, esp_i
|
||||
bootloader_debug_buffer(image_hash, HASH_LEN, "Calculated hash");
|
||||
|
||||
// Simple hash for verification only
|
||||
const void *hash = bootloader_mmap(data->start_addr + data->image_len - HASH_LEN, HASH_LEN);
|
||||
if (memcmp(hash, image_hash, HASH_LEN) != 0) {
|
||||
if (memcmp(data->image_digest, image_hash, HASH_LEN) != 0) {
|
||||
ESP_LOGE(TAG, "Image hash failed - image is corrupt");
|
||||
bootloader_debug_buffer(hash, HASH_LEN, "Expected hash");
|
||||
bootloader_munmap(hash);
|
||||
bootloader_debug_buffer(data->image_digest, HASH_LEN, "Expected hash");
|
||||
#ifdef CONFIG_IDF_ENV_FPGA
|
||||
ESP_LOGW(TAG, "Ignoring invalid SHA-256 as running on FPGA");
|
||||
return ESP_OK;
|
||||
#endif
|
||||
return ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
|
||||
bootloader_munmap(hash);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,7 @@ esp_err_t esp_partition_table_verify(const esp_partition_info_t *partition_table
|
||||
esp_rom_md5_update(&context, (unsigned char *) partition_table, num_parts * sizeof(esp_partition_info_t));
|
||||
esp_rom_md5_final(digest, &context);
|
||||
|
||||
unsigned char *md5sum = ((unsigned char *) part) + 16; // skip the 2B magic number and the 14B fillup bytes
|
||||
unsigned char *md5sum = ((unsigned char *) part) + ESP_PARTITION_MD5_OFFSET;
|
||||
|
||||
if (memcmp(md5sum, digest, sizeof(digest)) != 0) {
|
||||
if (log_errors) {
|
||||
|
@ -1,339 +0,0 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_sha.h"
|
||||
#include "bootloader_utility.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "mbedtls/sha256.h"
|
||||
#include "mbedtls/x509.h"
|
||||
#include "mbedtls/md.h"
|
||||
#include "mbedtls/platform.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include "esp_secure_boot.h"
|
||||
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32S2
|
||||
#include <esp32s2/rom/secure_boot.h>
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#include <esp32c3/rom/secure_boot.h>
|
||||
#endif
|
||||
|
||||
#define DIGEST_LEN 32
|
||||
|
||||
#ifdef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
|
||||
static const char *TAG = "secure_boot_v1";
|
||||
|
||||
extern const uint8_t signature_verification_key_start[] asm("_binary_signature_verification_key_bin_start");
|
||||
extern const uint8_t signature_verification_key_end[] asm("_binary_signature_verification_key_bin_end");
|
||||
|
||||
#define SIGNATURE_VERIFICATION_KEYLEN 64
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
uint8_t digest[DIGEST_LEN];
|
||||
uint8_t verified_digest[DIGEST_LEN];
|
||||
const esp_secure_boot_sig_block_t *sigblock;
|
||||
|
||||
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
|
||||
|
||||
esp_err_t err = bootloader_sha256_flash_contents(src_addr, length, digest);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Digest calculation failed 0x%x, 0x%x", src_addr, length);
|
||||
return err;
|
||||
}
|
||||
|
||||
// Map the signature block and verify the signature
|
||||
sigblock = (const esp_secure_boot_sig_block_t *)bootloader_mmap(src_addr + length, sizeof(esp_secure_boot_sig_block_t));
|
||||
if (sigblock == NULL) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr + length, sizeof(esp_secure_boot_sig_block_t));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
err = esp_secure_boot_verify_ecdsa_signature_block(sigblock, digest, verified_digest);
|
||||
bootloader_munmap(sigblock);
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_verify_ecdsa_signature_block(const esp_secure_boot_sig_block_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
#if !(defined(CONFIG_MBEDTLS_ECDSA_C) && defined(CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED))
|
||||
ESP_LOGE(TAG, "Signature verification requires ECDSA & SECP256R1 curve enabled");
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
#else
|
||||
ptrdiff_t keylen;
|
||||
|
||||
/* Note: in IDF app image verification we don't add any fault injection resistance, boot-time checks only */
|
||||
memset(verified_digest, 0, DIGEST_LEN);
|
||||
|
||||
keylen = signature_verification_key_end - signature_verification_key_start;
|
||||
if (keylen != SIGNATURE_VERIFICATION_KEYLEN) {
|
||||
ESP_LOGE(TAG, "Embedded public verification key has wrong length %d", keylen);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (sig_block->version != 0) {
|
||||
ESP_LOGE(TAG, "image has invalid signature version field 0x%08x", sig_block->version);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Verifying secure boot signature");
|
||||
|
||||
int ret;
|
||||
mbedtls_mpi r, s;
|
||||
|
||||
mbedtls_mpi_init(&r);
|
||||
mbedtls_mpi_init(&s);
|
||||
|
||||
/* Extract r and s components from RAW ECDSA signature of 64 bytes */
|
||||
#define ECDSA_INTEGER_LEN 32
|
||||
ret = mbedtls_mpi_read_binary(&r, &sig_block->signature[0], ECDSA_INTEGER_LEN);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed mbedtls_mpi_read_binary(1), err:%d", ret);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ret = mbedtls_mpi_read_binary(&s, &sig_block->signature[ECDSA_INTEGER_LEN], ECDSA_INTEGER_LEN);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed mbedtls_mpi_read_binary(2), err:%d", ret);
|
||||
mbedtls_mpi_free(&r);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Initialise ECDSA context */
|
||||
mbedtls_ecdsa_context ecdsa_context;
|
||||
mbedtls_ecdsa_init(&ecdsa_context);
|
||||
|
||||
mbedtls_ecp_group_load(&ecdsa_context.grp, MBEDTLS_ECP_DP_SECP256R1);
|
||||
size_t plen = mbedtls_mpi_size(&ecdsa_context.grp.P);
|
||||
if (keylen != 2 * plen) {
|
||||
ESP_LOGE(TAG, "Incorrect ECDSA key length %d", keylen);
|
||||
ret = ESP_FAIL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Extract X and Y components from ECDSA public key */
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ecdsa_context.Q.X, signature_verification_key_start, plen));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ecdsa_context.Q.Y, signature_verification_key_start + plen, plen));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&ecdsa_context.Q.Z, 1));
|
||||
|
||||
ret = mbedtls_ecdsa_verify(&ecdsa_context.grp, image_digest, DIGEST_LEN, &ecdsa_context.Q, &r, &s);
|
||||
ESP_LOGD(TAG, "Verification result %d", ret);
|
||||
|
||||
cleanup:
|
||||
mbedtls_mpi_free(&r);
|
||||
mbedtls_mpi_free(&s);
|
||||
mbedtls_ecdsa_free(&ecdsa_context);
|
||||
return ret == 0 ? ESP_OK : ESP_ERR_IMAGE_INVALID;
|
||||
#endif // CONFIG_MBEDTLS_ECDSA_C && CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED
|
||||
}
|
||||
|
||||
#elif CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
|
||||
static const char *TAG = "secure_boot_v2";
|
||||
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
#define RSA_KEY_SIZE 384 /* RSA 3072 Bits */
|
||||
|
||||
#if SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS > 1
|
||||
inline static bool digest_matches(const void *trusted, const void *computed)
|
||||
{
|
||||
if (trusted == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 'trusted' is probably a pointer to read-only efuse registers,
|
||||
// which only support word reads. memcmp() cannot be guaranteed
|
||||
// to do word reads, so we make a local copy here (we know that
|
||||
// memcpy() will do word operations if it can).
|
||||
uint8_t __attribute__((aligned(4))) trusted_local[ETS_DIGEST_LEN];
|
||||
uint8_t __attribute__((aligned(4))) computed_local[ETS_DIGEST_LEN];
|
||||
|
||||
memcpy(trusted_local, trusted, ETS_DIGEST_LEN);
|
||||
memcpy(computed_local, computed, ETS_DIGEST_LEN);
|
||||
return memcmp(trusted_local, computed_local, ETS_DIGEST_LEN) == 0;
|
||||
}
|
||||
#endif /* SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS > 1 */
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
uint8_t digest[DIGEST_LEN] = {0};
|
||||
uint8_t verified_digest[DIGEST_LEN] = {0};
|
||||
|
||||
/* Rounding off length to the upper 4k boundary */
|
||||
uint32_t padded_length = ALIGN_UP(length, FLASH_SECTOR_SIZE);
|
||||
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
|
||||
|
||||
esp_err_t err = bootloader_sha256_flash_contents(src_addr, padded_length, digest);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Digest calculation failed 0x%x, 0x%x", src_addr, padded_length);
|
||||
return err;
|
||||
}
|
||||
|
||||
const ets_secure_boot_signature_t *sig_block = bootloader_mmap(src_addr + padded_length, sizeof(ets_secure_boot_signature_t));
|
||||
if (sig_block == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to mmap data at offset 0x%x", src_addr + padded_length);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
err = esp_secure_boot_verify_rsa_signature_block(sig_block, digest, verified_digest);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Secure Boot V2 verification failed.");
|
||||
}
|
||||
bootloader_munmap(sig_block);
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
uint8_t i = 0;
|
||||
#if CONFIG_SECURE_BOOT_V2_ENABLED /* Verify key against efuse block */
|
||||
uint8_t sig_block_key_digest[SECURE_BOOT_NUM_BLOCKS][DIGEST_LEN] = {0};
|
||||
|
||||
/* Note: in IDF verification we don't add any fault injection resistance, as we don't expect this to be called
|
||||
during boot-time verification. */
|
||||
memset(verified_digest, 0, DIGEST_LEN);
|
||||
|
||||
/* Generating the SHA of the public key components in the signature block */
|
||||
for (i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
|
||||
bootloader_sha256_handle_t sig_block_sha;
|
||||
sig_block_sha = bootloader_sha256_start();
|
||||
bootloader_sha256_data(sig_block_sha, &sig_block->block[i].key, sizeof(sig_block->block[i].key));
|
||||
bootloader_sha256_finish(sig_block_sha, (unsigned char *)sig_block_key_digest[i]);
|
||||
}
|
||||
|
||||
#if SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS == 1
|
||||
uint8_t efuse_trusted_digest[DIGEST_LEN] = {0};
|
||||
memcpy(efuse_trusted_digest, (uint8_t *) EFUSE_BLK2_RDATA0_REG, sizeof(efuse_trusted_digest));
|
||||
|
||||
if (memcmp(efuse_trusted_digest, sig_block_key_digest[0], DIGEST_LEN) != 0) {
|
||||
const uint8_t zeroes[DIGEST_LEN] = {0};
|
||||
/* Can't continue if secure boot is enabled, OR if a different digest is already written in efuse BLK2
|
||||
|
||||
(If BLK2 is empty and Secure Boot is disabled then we assume that it will be enabled later.)
|
||||
*/
|
||||
if (esp_secure_boot_enabled() || memcmp(efuse_trusted_digest, zeroes, DIGEST_LEN) != 0) {
|
||||
ESP_LOGE(TAG, "Public key digest in eFuse BLK2 and the signature block don't match.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
#elif SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS > 1
|
||||
bool match = false;
|
||||
ets_secure_boot_key_digests_t efuse_trusted_digest;
|
||||
ETS_STATUS r;
|
||||
r = ets_secure_boot_read_key_digests(&efuse_trusted_digest);
|
||||
if (r != 0) {
|
||||
ESP_LOGI(TAG, "Could not read secure boot digests!");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
#endif /* SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS */
|
||||
#endif /* CONFIG_SECURE_BOOT_V2_ENABLED */
|
||||
|
||||
ESP_LOGI(TAG, "Verifying with RSA-PSS...");
|
||||
int ret = 0;
|
||||
mbedtls_rsa_context pk;
|
||||
mbedtls_entropy_context entropy;
|
||||
mbedtls_ctr_drbg_context ctr_drbg;
|
||||
unsigned char *sig_be = calloc(1, RSA_KEY_SIZE);
|
||||
unsigned char *buf = calloc(1, RSA_KEY_SIZE);
|
||||
if (sig_be == NULL || buf == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
mbedtls_entropy_init(&entropy);
|
||||
mbedtls_ctr_drbg_init(&ctr_drbg);
|
||||
ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned -0x%04x\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
for (i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
|
||||
#if SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS > 1
|
||||
for (uint8_t j = 0; j < SECURE_BOOT_NUM_BLOCKS; j++) {
|
||||
if (digest_matches(efuse_trusted_digest.key_digests[j], sig_block_key_digest[i])) {
|
||||
ESP_LOGI(TAG, "eFuse key matches(%d) matches the application key(%d).", j, i);
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match == false) {
|
||||
continue; // Skip the public keys whose digests don't match.
|
||||
}
|
||||
# endif // SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS > 1
|
||||
|
||||
const mbedtls_mpi N = { .s = 1,
|
||||
.n = sizeof(sig_block->block[i].key.n)/sizeof(mbedtls_mpi_uint),
|
||||
.p = (void *)sig_block->block[i].key.n,
|
||||
};
|
||||
const mbedtls_mpi e = { .s = 1,
|
||||
.n = sizeof(sig_block->block[i].key.e)/sizeof(mbedtls_mpi_uint), // 1
|
||||
.p = (void *)&sig_block->block[i].key.e,
|
||||
};
|
||||
mbedtls_rsa_init(&pk, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
|
||||
ret = mbedtls_rsa_import(&pk, &N, NULL, NULL, NULL, &e);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed mbedtls_rsa_import, err: %d", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = mbedtls_rsa_complete(&pk);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed mbedtls_rsa_complete, err: %d", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = mbedtls_rsa_check_pubkey(&pk);
|
||||
if (ret != 0) {
|
||||
ESP_LOGI(TAG, "Key is not an RSA key -%0x", -ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Signature needs to be byte swapped into BE representation */
|
||||
for (int j = 0; j < RSA_KEY_SIZE; j++) {
|
||||
sig_be[RSA_KEY_SIZE- j - 1] = sig_block->block[i].signature[j];
|
||||
}
|
||||
|
||||
ret = mbedtls_rsa_public( &pk, sig_be, buf);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_rsa_public failed, err: %d", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = mbedtls_rsa_rsassa_pss_verify( &pk, mbedtls_ctr_drbg_random, &ctr_drbg, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA256, DIGEST_LEN,
|
||||
image_digest, sig_be);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed mbedtls_rsa_rsassa_pss_verify, err: %d", ret);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Signature verified successfully!");
|
||||
}
|
||||
exit:
|
||||
mbedtls_rsa_free(&pk);
|
||||
if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(sig_be);
|
||||
free(buf);
|
||||
#if SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS == 1
|
||||
return (ret != 0) ? ESP_ERR_IMAGE_INVALID: ESP_OK;
|
||||
#elif SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS > 1
|
||||
return (ret != 0 || match == false) ? ESP_ERR_IMAGE_INVALID: ESP_OK;
|
||||
#endif /* CONFIG_IDF_TARGET_ESP32 */
|
||||
}
|
||||
#endif
|
57
components/bootloader_support/src/secure_boot.c
Normal file
57
components/bootloader_support/src/secure_boot.c
Normal file
@ -0,0 +1,57 @@
|
||||
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <strings.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_secure_boot.h"
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
static __attribute__((unused)) const char *TAG = "secure_boot";
|
||||
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME && CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
|
||||
static void rsa_check_signature_on_update_check(void)
|
||||
{
|
||||
// We rely on the keys used to sign this app to verify the next app on OTA, so make sure there is at
|
||||
// least one to avoid a stuck firmware
|
||||
esp_image_sig_public_key_digests_t digests = { 0 };
|
||||
|
||||
esp_err_t err = esp_secure_boot_get_signature_blocks_for_running_app(false, &digests);
|
||||
|
||||
if (err != ESP_OK || digests.num_digests == 0) {
|
||||
ESP_LOGE(TAG, "This app is not signed, but check signature on update is enabled in config. It won't be possible to verify any update.");
|
||||
abort();
|
||||
}
|
||||
#if CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT && SECURE_BOOT_NUM_BLOCKS > 1
|
||||
if (digests.num_digests > 1) {
|
||||
ESP_LOGW(TAG, "App has %d signatures. Only the first position of signature blocks is used to verify any update", digests.num_digests);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif // CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME && CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
|
||||
void esp_secure_boot_init_checks(void)
|
||||
{
|
||||
|
||||
|
||||
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME && CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
rsa_check_signature_on_update_check();
|
||||
#endif // CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME && CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
|
||||
}
|
||||
#endif // not BOOTLOADER_BUILD
|
@ -0,0 +1,136 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_sha.h"
|
||||
#include "bootloader_utility.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "mbedtls/sha256.h"
|
||||
#include "mbedtls/x509.h"
|
||||
#include "mbedtls/md.h"
|
||||
#include "mbedtls/platform.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#ifdef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
|
||||
static const char *TAG = "secure_boot_v1";
|
||||
|
||||
extern const uint8_t signature_verification_key_start[] asm("_binary_signature_verification_key_bin_start");
|
||||
extern const uint8_t signature_verification_key_end[] asm("_binary_signature_verification_key_bin_end");
|
||||
|
||||
#define SIGNATURE_VERIFICATION_KEYLEN 64
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
uint8_t digest[ESP_SECURE_BOOT_DIGEST_LEN];
|
||||
uint8_t verified_digest[ESP_SECURE_BOOT_DIGEST_LEN];
|
||||
const esp_secure_boot_sig_block_t *sigblock;
|
||||
|
||||
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
|
||||
|
||||
esp_err_t err = bootloader_sha256_flash_contents(src_addr, length, digest);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Digest calculation failed 0x%x, 0x%x", src_addr, length);
|
||||
return err;
|
||||
}
|
||||
|
||||
// Map the signature block and verify the signature
|
||||
sigblock = (const esp_secure_boot_sig_block_t *)bootloader_mmap(src_addr + length, sizeof(esp_secure_boot_sig_block_t));
|
||||
if (sigblock == NULL) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr + length, sizeof(esp_secure_boot_sig_block_t));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
err = esp_secure_boot_verify_ecdsa_signature_block(sigblock, digest, verified_digest);
|
||||
bootloader_munmap(sigblock);
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_verify_ecdsa_signature_block(const esp_secure_boot_sig_block_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
#if !(defined(CONFIG_MBEDTLS_ECDSA_C) && defined(CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED))
|
||||
ESP_LOGE(TAG, "Signature verification requires ECDSA & SECP256R1 curve enabled");
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
#else
|
||||
ptrdiff_t keylen;
|
||||
|
||||
/* Note: in IDF app image verification we don't add any fault injection resistance, boot-time checks only */
|
||||
memset(verified_digest, 0, ESP_SECURE_BOOT_DIGEST_LEN);
|
||||
|
||||
keylen = signature_verification_key_end - signature_verification_key_start;
|
||||
if (keylen != SIGNATURE_VERIFICATION_KEYLEN) {
|
||||
ESP_LOGE(TAG, "Embedded public verification key has wrong length %d", keylen);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (sig_block->version != 0) {
|
||||
ESP_LOGE(TAG, "image has invalid signature version field 0x%08x", sig_block->version);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Verifying secure boot signature");
|
||||
|
||||
int ret;
|
||||
mbedtls_mpi r, s;
|
||||
|
||||
mbedtls_mpi_init(&r);
|
||||
mbedtls_mpi_init(&s);
|
||||
|
||||
/* Extract r and s components from RAW ECDSA signature of 64 bytes */
|
||||
#define ECDSA_INTEGER_LEN 32
|
||||
ret = mbedtls_mpi_read_binary(&r, &sig_block->signature[0], ECDSA_INTEGER_LEN);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed mbedtls_mpi_read_binary(1), err:%d", ret);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ret = mbedtls_mpi_read_binary(&s, &sig_block->signature[ECDSA_INTEGER_LEN], ECDSA_INTEGER_LEN);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed mbedtls_mpi_read_binary(2), err:%d", ret);
|
||||
mbedtls_mpi_free(&r);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Initialise ECDSA context */
|
||||
mbedtls_ecdsa_context ecdsa_context;
|
||||
mbedtls_ecdsa_init(&ecdsa_context);
|
||||
|
||||
mbedtls_ecp_group_load(&ecdsa_context.grp, MBEDTLS_ECP_DP_SECP256R1);
|
||||
size_t plen = mbedtls_mpi_size(&ecdsa_context.grp.P);
|
||||
if (keylen != 2 * plen) {
|
||||
ESP_LOGE(TAG, "Incorrect ECDSA key length %d", keylen);
|
||||
ret = ESP_FAIL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Extract X and Y components from ECDSA public key */
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ecdsa_context.Q.X, signature_verification_key_start, plen));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ecdsa_context.Q.Y, signature_verification_key_start + plen, plen));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&ecdsa_context.Q.Z, 1));
|
||||
|
||||
ret = mbedtls_ecdsa_verify(&ecdsa_context.grp, image_digest, ESP_SECURE_BOOT_DIGEST_LEN, &ecdsa_context.Q, &r, &s);
|
||||
ESP_LOGD(TAG, "Verification result %d", ret);
|
||||
|
||||
cleanup:
|
||||
mbedtls_mpi_free(&r);
|
||||
mbedtls_mpi_free(&s);
|
||||
mbedtls_ecdsa_free(&ecdsa_context);
|
||||
return ret == 0 ? ESP_OK : ESP_ERR_IMAGE_INVALID;
|
||||
#endif // CONFIG_MBEDTLS_ECDSA_C && CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED
|
||||
}
|
||||
#endif // CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
|
@ -0,0 +1,100 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_sha.h"
|
||||
#include "bootloader_utility.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_spi_flash.h"
|
||||
#include "esp_fault.h"
|
||||
#include "esp32/rom/sha.h"
|
||||
#include "uECC_verify_antifault.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <string.h>
|
||||
|
||||
static const char *TAG = "secure_boot";
|
||||
|
||||
#ifdef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
|
||||
extern const uint8_t signature_verification_key_start[] asm("_binary_signature_verification_key_bin_start");
|
||||
extern const uint8_t signature_verification_key_end[] asm("_binary_signature_verification_key_bin_end");
|
||||
|
||||
#define SIGNATURE_VERIFICATION_KEYLEN 64
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
uint8_t digest[ESP_SECURE_BOOT_DIGEST_LEN];
|
||||
uint8_t verified_digest[ESP_SECURE_BOOT_DIGEST_LEN] = { 0 }; /* ignored in this function */
|
||||
const esp_secure_boot_sig_block_t *sigblock;
|
||||
|
||||
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
|
||||
|
||||
esp_err_t err = bootloader_sha256_flash_contents(src_addr, length, digest);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// Map the signature block
|
||||
sigblock = (const esp_secure_boot_sig_block_t *) bootloader_mmap(src_addr + length, sizeof(esp_secure_boot_sig_block_t));
|
||||
if(!sigblock) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr + length, sizeof(esp_secure_boot_sig_block_t));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
// Verify the signature
|
||||
err = esp_secure_boot_verify_ecdsa_signature_block(sigblock, digest, verified_digest);
|
||||
// Unmap
|
||||
bootloader_munmap(sigblock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature_block(const esp_secure_boot_sig_block_t *sig_block, const uint8_t *image_digest)
|
||||
{
|
||||
uint8_t verified_digest[ESP_SECURE_BOOT_DIGEST_LEN] = { 0 };
|
||||
return esp_secure_boot_verify_ecdsa_signature_block(sig_block, image_digest, verified_digest);
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_verify_ecdsa_signature_block(const esp_secure_boot_sig_block_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
ptrdiff_t keylen;
|
||||
|
||||
keylen = signature_verification_key_end - signature_verification_key_start;
|
||||
if (keylen != SIGNATURE_VERIFICATION_KEYLEN) {
|
||||
ESP_LOGE(TAG, "Embedded public verification key has wrong length %d", keylen);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (sig_block->version != 0) {
|
||||
ESP_LOGE(TAG, "image has invalid signature version field 0x%08x", sig_block->version);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Verifying secure boot signature");
|
||||
|
||||
bool is_valid;
|
||||
is_valid = uECC_verify_antifault(signature_verification_key_start,
|
||||
image_digest,
|
||||
ESP_SECURE_BOOT_DIGEST_LEN,
|
||||
sig_block->signature,
|
||||
uECC_secp256r1(),
|
||||
verified_digest);
|
||||
ESP_LOGD(TAG, "Verification result %d", is_valid);
|
||||
|
||||
return is_valid ? ESP_OK : ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
|
||||
#endif // CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
|
@ -0,0 +1,295 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_sha.h"
|
||||
#include "bootloader_utility.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "mbedtls/sha256.h"
|
||||
#include "mbedtls/x509.h"
|
||||
#include "mbedtls/md.h"
|
||||
#include "mbedtls/platform.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_ota_ops.h"
|
||||
|
||||
// Secure boot V2 for app
|
||||
|
||||
_Static_assert(SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS == SECURE_BOOT_NUM_BLOCKS,
|
||||
"Parts of this code rely on the max number of signatures appended to an image"
|
||||
"being the same as the max number of trusted keys.");
|
||||
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME || CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
|
||||
static const char *TAG = "secure_boot_v2";
|
||||
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
/* A signature block is valid when it has correct magic byte, crc. */
|
||||
static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *block)
|
||||
{
|
||||
if (block->magic_byte != ETS_SECURE_BOOT_V2_SIGNATURE_MAGIC
|
||||
|| block->block_crc != esp_rom_crc32_le(0, (uint8_t *)block, CRC_SIGN_BLOCK_LEN)) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_get_signature_blocks_for_running_app(bool digest_public_keys, esp_image_sig_public_key_digests_t *public_key_digests)
|
||||
{
|
||||
esp_image_metadata_t metadata;
|
||||
const esp_partition_t* running_app_part = esp_ota_get_running_partition();
|
||||
if (running_app_part == NULL) {
|
||||
ESP_LOGE(TAG, "Cannot get running partition");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
const esp_partition_pos_t part_pos = {
|
||||
.offset = running_app_part->address,
|
||||
.size = running_app_part->size,
|
||||
};
|
||||
esp_err_t err = esp_image_get_metadata(&part_pos, &metadata);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error reading metadata from running app (err=0x%x)", err);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
memset(public_key_digests, 0, sizeof(esp_image_sig_public_key_digests_t));
|
||||
|
||||
// Generating the SHA of the public key components in the signature block
|
||||
|
||||
// metadata.image_len doesn't include any padding to start of the signature sector, so pad it here
|
||||
size_t sig_block_addr = metadata.start_addr + ALIGN_UP(metadata.image_len, FLASH_SECTOR_SIZE);
|
||||
ESP_LOGD(TAG, "reading signatures for app address 0x%x sig block address 0x%x", part_pos.offset, sig_block_addr);
|
||||
for (unsigned i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
|
||||
ets_secure_boot_sig_block_t block;
|
||||
size_t addr = sig_block_addr + sizeof(ets_secure_boot_sig_block_t) * i;
|
||||
esp_err_t err = bootloader_flash_read(addr, &block, sizeof(ets_secure_boot_sig_block_t), true);
|
||||
if (err == ESP_OK) {
|
||||
if (validate_signature_block(&block) == ESP_OK) {
|
||||
if (digest_public_keys) {
|
||||
bootloader_sha256_handle_t sig_block_sha = bootloader_sha256_start();
|
||||
bootloader_sha256_data(sig_block_sha, &block.key, sizeof(block.key));
|
||||
bootloader_sha256_finish(sig_block_sha, public_key_digests->key_digests[i]);
|
||||
}
|
||||
public_key_digests->num_digests++;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Secure boot sign blocks cannot be read from a running app (err=0x%x)", err);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
if (public_key_digests->num_digests > 0) {
|
||||
return ESP_OK;
|
||||
}
|
||||
ESP_LOGE(TAG, "No signatures were found for the running app");
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
static esp_err_t get_secure_boot_key_digests(esp_image_sig_public_key_digests_t *public_key_digests)
|
||||
{
|
||||
#ifdef CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
// Gets key digests from running app
|
||||
ESP_LOGI(TAG, "Take trusted digest key(s) from running app");
|
||||
return esp_secure_boot_get_signature_blocks_for_running_app(true, public_key_digests);
|
||||
#elif CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
ESP_LOGI(TAG, "Take trusted digest key(s) from eFuse block(s)");
|
||||
#if SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS > 1
|
||||
// Read key digests from efuse
|
||||
ets_secure_boot_key_digests_t efuse_trusted;
|
||||
if (ets_secure_boot_read_key_digests(&efuse_trusted) == ETS_OK) {
|
||||
for (unsigned i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
|
||||
if (efuse_trusted.key_digests[i] != NULL) {
|
||||
memcpy(public_key_digests->key_digests[i], (uint8_t *)efuse_trusted.key_digests[i], ESP_SECURE_BOOT_DIGEST_LEN);
|
||||
public_key_digests->num_digests++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (public_key_digests->num_digests > 0) {
|
||||
return ESP_OK;
|
||||
}
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
#else
|
||||
memcpy(public_key_digests->key_digests[0], (uint8_t *)EFUSE_BLK2_RDATA0_REG, ESP_SECURE_BOOT_DIGEST_LEN);
|
||||
public_key_digests->num_digests = 1;
|
||||
return ESP_OK;
|
||||
#endif // SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS
|
||||
#endif // CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
uint8_t digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
uint8_t verified_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
|
||||
/* Rounding off length to the upper 4k boundary */
|
||||
uint32_t padded_length = ALIGN_UP(length, FLASH_SECTOR_SIZE);
|
||||
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
|
||||
|
||||
esp_err_t err = bootloader_sha256_flash_contents(src_addr, padded_length, digest);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Digest calculation failed 0x%x, 0x%x", src_addr, padded_length);
|
||||
return err;
|
||||
}
|
||||
|
||||
const ets_secure_boot_signature_t *sig_block = bootloader_mmap(src_addr + padded_length, sizeof(ets_secure_boot_signature_t));
|
||||
if (sig_block == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to mmap data at offset 0x%x", src_addr + padded_length);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
err = esp_secure_boot_verify_rsa_signature_block(sig_block, digest, verified_digest);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Secure Boot V2 verification failed.");
|
||||
}
|
||||
bootloader_munmap(sig_block);
|
||||
return err;
|
||||
}
|
||||
|
||||
// This verify function is called only from app, during ota update.
|
||||
// This function is compiled in case when CONFIG_SECURE_BOOT_V2_ENABLED==y or CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT==y.
|
||||
// if CONFIG_SECURE_BOOT_V2_ENABLED==y and key digests from eFuse are missing, then FAIL (eFuse blocks should be set).
|
||||
esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
bool any_trusted_key = false;
|
||||
|
||||
/* Note: in IDF verification we don't add any fault injection resistance, as we don't expect this to be called
|
||||
during boot-time verification. */
|
||||
memset(verified_digest, 0, ESP_SECURE_BOOT_DIGEST_LEN);
|
||||
|
||||
esp_image_sig_public_key_digests_t trusted = {0};
|
||||
|
||||
if (get_secure_boot_key_digests(&trusted) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Could not read secure boot digests!");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
|
||||
int ret = 0;
|
||||
mbedtls_rsa_context pk;
|
||||
mbedtls_entropy_context entropy;
|
||||
mbedtls_ctr_drbg_context ctr_drbg;
|
||||
const unsigned rsa_key_size = sizeof(sig_block->block[0].signature);
|
||||
unsigned char *sig_be = calloc(1, rsa_key_size);
|
||||
unsigned char *buf = calloc(1, rsa_key_size);
|
||||
if (sig_be == NULL || buf == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
mbedtls_entropy_init(&entropy);
|
||||
mbedtls_ctr_drbg_init(&ctr_drbg);
|
||||
ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned -0x%04x\n", ret);
|
||||
goto exit_outer;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
const unsigned secure_boot_num_blocks = 1;
|
||||
#else
|
||||
const unsigned secure_boot_num_blocks = SECURE_BOOT_NUM_BLOCKS;
|
||||
#endif
|
||||
|
||||
for (unsigned app_blk_idx = 0; app_blk_idx < secure_boot_num_blocks; app_blk_idx++) {
|
||||
uint8_t app_blk_digest[ESP_SECURE_BOOT_DIGEST_LEN] = { 0 };
|
||||
const ets_secure_boot_sig_block_t *app_blk = &sig_block->block[app_blk_idx];
|
||||
const ets_secure_boot_sig_block_t *trusted_block = NULL;
|
||||
|
||||
if (validate_signature_block(app_blk) != ESP_OK) {
|
||||
continue; // Skip invalid signature blocks
|
||||
}
|
||||
|
||||
/* Generate the SHA of the public key components in the signature block */
|
||||
bootloader_sha256_handle_t sig_block_sha = bootloader_sha256_start();
|
||||
bootloader_sha256_data(sig_block_sha, &app_blk->key, sizeof(app_blk->key));
|
||||
bootloader_sha256_finish(sig_block_sha, app_blk_digest);
|
||||
|
||||
/* Check if the key is one we trust */
|
||||
for (unsigned trusted_key_idx = 0; trusted_key_idx < secure_boot_num_blocks; trusted_key_idx++) {
|
||||
if (memcmp(app_blk_digest, trusted.key_digests[trusted_key_idx], ESP_SECURE_BOOT_DIGEST_LEN) == 0) {
|
||||
ESP_LOGI(TAG, "#%d app key digest == #%d trusted key digest", app_blk_idx, trusted_key_idx);
|
||||
trusted_block = app_blk;
|
||||
any_trusted_key = true;
|
||||
break;
|
||||
}
|
||||
ESP_LOGV(TAG, "not trusting app sig %d trust idx %d", app_blk_idx, trusted_key_idx);
|
||||
}
|
||||
|
||||
if (trusted_block == NULL) {
|
||||
continue; // Skip the signature blocks with no trusted digest
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Verifying with RSA-PSS...");
|
||||
|
||||
const mbedtls_mpi N = { .s = 1,
|
||||
.n = sizeof(trusted_block->key.n)/sizeof(mbedtls_mpi_uint),
|
||||
.p = (void *)trusted_block->key.n,
|
||||
};
|
||||
const mbedtls_mpi e = { .s = 1,
|
||||
.n = sizeof(trusted_block->key.e)/sizeof(mbedtls_mpi_uint), // 1
|
||||
.p = (void *)&trusted_block->key.e,
|
||||
};
|
||||
mbedtls_rsa_init(&pk, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
|
||||
ret = mbedtls_rsa_import(&pk, &N, NULL, NULL, NULL, &e);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed mbedtls_rsa_import, err: %d", ret);
|
||||
goto exit_inner;
|
||||
}
|
||||
|
||||
ret = mbedtls_rsa_complete(&pk);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed mbedtls_rsa_complete, err: %d", ret);
|
||||
goto exit_inner;
|
||||
}
|
||||
|
||||
ret = mbedtls_rsa_check_pubkey(&pk);
|
||||
if (ret != 0) {
|
||||
ESP_LOGI(TAG, "Key is not an RSA key -%0x", -ret);
|
||||
goto exit_inner;
|
||||
}
|
||||
|
||||
/* Signature needs to be byte swapped into BE representation */
|
||||
for (int j = 0; j < rsa_key_size; j++) {
|
||||
sig_be[rsa_key_size - j - 1] = trusted_block->signature[j];
|
||||
}
|
||||
|
||||
ret = mbedtls_rsa_public( &pk, sig_be, buf);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_rsa_public failed, err: %d", ret);
|
||||
goto exit_inner;
|
||||
}
|
||||
|
||||
ret = mbedtls_rsa_rsassa_pss_verify( &pk, mbedtls_ctr_drbg_random, &ctr_drbg, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA256, ESP_SECURE_BOOT_DIGEST_LEN,
|
||||
image_digest, sig_be);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed mbedtls_rsa_rsassa_pss_verify, err: %d", ret);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Signature verified successfully!");
|
||||
}
|
||||
exit_inner:
|
||||
mbedtls_rsa_free(&pk);
|
||||
if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
exit_outer:
|
||||
free(sig_be);
|
||||
free(buf);
|
||||
return (ret != 0 || any_trusted_key == false) ? ESP_ERR_IMAGE_INVALID: ESP_OK;
|
||||
}
|
||||
#endif // CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME || CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
@ -0,0 +1,172 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "esp_fault.h"
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_sha.h"
|
||||
#include "bootloader_utility.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_secure_boot.h"
|
||||
|
||||
// Secure boot V2 for bootloader.
|
||||
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME && CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
|
||||
static const char* TAG = "secure_boot_v2";
|
||||
|
||||
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
uint8_t digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
uint8_t verified_digest[ESP_SECURE_BOOT_DIGEST_LEN] = { 0 }; /* Note: this function doesn't do any anti-FI checks on this buffer */
|
||||
|
||||
/* Rounding off length to the upper 4k boundary */
|
||||
uint32_t padded_length = ALIGN_UP(length, FLASH_SECTOR_SIZE);
|
||||
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
|
||||
|
||||
/* Calculate digest of main image */
|
||||
esp_err_t err = bootloader_sha256_flash_contents(src_addr, padded_length, digest);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Digest calculation failed 0x%x, 0x%x", src_addr, padded_length);
|
||||
return err;
|
||||
}
|
||||
|
||||
const ets_secure_boot_signature_t *sig_block = bootloader_mmap(src_addr + padded_length, sizeof(ets_secure_boot_signature_t));
|
||||
if (sig_block == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to mmap data at offset 0x%x", src_addr + padded_length);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
err = esp_secure_boot_verify_rsa_signature_block(sig_block, digest, verified_digest);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Secure Boot V2 verification failed.");
|
||||
}
|
||||
bootloader_munmap(sig_block);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* A signature block is valid when it has correct magic byte, crc. */
|
||||
static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *block)
|
||||
{
|
||||
if (block->magic_byte != ETS_SECURE_BOOT_V2_SIGNATURE_MAGIC
|
||||
|| block->block_crc != esp_rom_crc32_le(0, (uint8_t *)block, CRC_SIGN_BLOCK_LEN)) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t get_secure_boot_key_digests(esp_image_sig_public_key_digests_t *public_key_digests)
|
||||
{
|
||||
#if SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS > 1
|
||||
// Read key digests from efuse
|
||||
ets_secure_boot_key_digests_t trusted_keys;
|
||||
ets_secure_boot_key_digests_t trusted_key_copies[2];
|
||||
ETS_STATUS ets_ret;
|
||||
|
||||
memset(&trusted_keys, 0, sizeof(ets_secure_boot_key_digests_t));
|
||||
memset(trusted_key_copies, 0, 2 * sizeof(ets_secure_boot_key_digests_t));
|
||||
|
||||
|
||||
ets_ret = ets_secure_boot_read_key_digests(&trusted_keys);
|
||||
|
||||
// Create the copies for FI checks (assuming result is ETS_OK, if it's not then it'll fail the fault check anyhow)
|
||||
ets_secure_boot_read_key_digests(&trusted_key_copies[0]);
|
||||
ets_secure_boot_read_key_digests(&trusted_key_copies[1]);
|
||||
ESP_FAULT_ASSERT(memcmp(&trusted_keys, &trusted_key_copies[0], sizeof(ets_secure_boot_key_digests_t)) == 0);
|
||||
ESP_FAULT_ASSERT(memcmp(&trusted_keys, &trusted_key_copies[1], sizeof(ets_secure_boot_key_digests_t)) == 0);
|
||||
|
||||
if (ets_ret == ETS_OK) {
|
||||
for (unsigned i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
|
||||
if (trusted_keys.key_digests[i] != NULL) {
|
||||
memcpy(public_key_digests->key_digests[i], (uint8_t *)trusted_keys.key_digests[i], ESP_SECURE_BOOT_DIGEST_LEN);
|
||||
public_key_digests->num_digests++;
|
||||
}
|
||||
}
|
||||
if (public_key_digests->num_digests > 0) {
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
#else
|
||||
bool all_zeroes = true;
|
||||
uint32_t *reg = (uint32_t*)&public_key_digests->key_digests[0];
|
||||
for (int i = 0; i < ESP_SECURE_BOOT_DIGEST_LEN / 4; i++) {
|
||||
*(reg + i) = REG_READ(EFUSE_BLK2_RDATA0_REG + i * 4);
|
||||
all_zeroes = all_zeroes && (*(reg + i) == 0);
|
||||
}
|
||||
if (all_zeroes) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
public_key_digests->num_digests = 1;
|
||||
return ESP_OK;
|
||||
#endif // SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS
|
||||
}
|
||||
|
||||
// if CONFIG_SECURE_BOOT_V2_ENABLED==y and key digests from eFuse are missing, then it is the first boot,
|
||||
// trusted.key_digests are filled from app sig_block.
|
||||
esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
esp_image_sig_public_key_digests_t trusted = {0};
|
||||
bool efuse_keys_are_not_set = false;
|
||||
if (get_secure_boot_key_digests(&trusted) != ESP_OK) {
|
||||
if (esp_secure_boot_enabled()) {
|
||||
ESP_LOGE(TAG, "Could not read eFuse secure boot digests!");
|
||||
return ESP_FAIL;
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Secure boot V2 is not enabled yet and eFuse digest keys are not set");
|
||||
efuse_keys_are_not_set = true;
|
||||
ESP_FAULT_ASSERT(!esp_secure_boot_enabled());
|
||||
}
|
||||
}
|
||||
|
||||
if (!esp_secure_boot_enabled()) {
|
||||
// It is the first boot. eFuse secure boot bit is not set yet. eFuse block(s) can be written or not.
|
||||
// Generating the SHA of the public key components in the signature block
|
||||
for (unsigned i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
|
||||
if (validate_signature_block(&sig_block->block[i]) == ESP_OK) {
|
||||
if (efuse_keys_are_not_set) {
|
||||
// if efuse key digests are not in eFuse yet due to it is the first boot
|
||||
// then use digests from app to skip error in ets_secure_boot_verify_signature().
|
||||
bootloader_sha256_handle_t sig_block_sha = bootloader_sha256_start();
|
||||
bootloader_sha256_data(sig_block_sha, &sig_block->block[i].key, sizeof(sig_block->block[i].key));
|
||||
bootloader_sha256_finish(sig_block_sha, trusted.key_digests[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
ESP_FAULT_ASSERT(!esp_secure_boot_enabled());
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Verifying with RSA-PSS...");
|
||||
#if SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS == 1
|
||||
int sb_result = ets_secure_boot_verify_signature(sig_block, image_digest, trusted.key_digests[0], verified_digest);
|
||||
#else
|
||||
ets_secure_boot_key_digests_t trusted_key_digests;
|
||||
for (unsigned i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
|
||||
trusted_key_digests.key_digests[i] = &trusted.key_digests[i];
|
||||
}
|
||||
int sb_result = ets_secure_boot_verify_signature(sig_block, image_digest, &trusted_key_digests, verified_digest);
|
||||
#endif
|
||||
if (sb_result != SB_SUCCESS) {
|
||||
ESP_LOGE(TAG, "Secure Boot V2 verification failed.");
|
||||
return ESP_ERR_IMAGE_INVALID;
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Signature verified successfully!");
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME && CONFIG_SECURE_BOOT_V2_ENABLED
|
@ -20,10 +20,17 @@ if(CONFIG_BT_ENABLED)
|
||||
list(APPEND priv_include_dirs
|
||||
common/btc/include
|
||||
common/include)
|
||||
list(APPEND include_dirs
|
||||
common/api/include/api
|
||||
common/btc/profile/esp/blufi/include
|
||||
common/btc/profile/esp/include)
|
||||
|
||||
list(APPEND srcs "common/btc/core/btc_alarm.c"
|
||||
"common/api/esp_blufi_api.c"
|
||||
"common/btc/core/btc_manage.c"
|
||||
"common/btc/core/btc_task.c"
|
||||
"common/btc/profile/esp/blufi/blufi_prf.c"
|
||||
"common/btc/profile/esp/blufi/blufi_protocol.c"
|
||||
"common/osi/alarm.c"
|
||||
"common/osi/allocator.c"
|
||||
"common/osi/buffer.c"
|
||||
@ -57,7 +64,6 @@ if(CONFIG_BT_ENABLED)
|
||||
host/bluedroid/external/sbc/decoder/include
|
||||
host/bluedroid/external/sbc/encoder/include
|
||||
host/bluedroid/external/sbc/plc/include
|
||||
host/bluedroid/btc/profile/esp/blufi/include
|
||||
host/bluedroid/btc/profile/esp/include
|
||||
host/bluedroid/btc/profile/std/a2dp/include
|
||||
host/bluedroid/btc/profile/std/hid/include
|
||||
@ -81,7 +87,6 @@ if(CONFIG_BT_ENABLED)
|
||||
|
||||
list(APPEND srcs "host/bluedroid/api/esp_a2dp_api.c"
|
||||
"host/bluedroid/api/esp_avrc_api.c"
|
||||
"host/bluedroid/api/esp_blufi_api.c"
|
||||
"host/bluedroid/api/esp_bt_device.c"
|
||||
"host/bluedroid/api/esp_bt_main.c"
|
||||
"host/bluedroid/api/esp_gap_ble_api.c"
|
||||
@ -167,8 +172,6 @@ if(CONFIG_BT_ENABLED)
|
||||
"host/bluedroid/btc/core/btc_sm.c"
|
||||
"host/bluedroid/btc/core/btc_storage.c"
|
||||
"host/bluedroid/btc/core/btc_util.c"
|
||||
"host/bluedroid/btc/profile/esp/blufi/blufi_prf.c"
|
||||
"host/bluedroid/btc/profile/esp/blufi/blufi_protocol.c"
|
||||
"host/bluedroid/btc/profile/std/a2dp/bta_av_co.c"
|
||||
"host/bluedroid/btc/profile/std/a2dp/btc_a2dp.c"
|
||||
"host/bluedroid/btc/profile/std/a2dp/btc_a2dp_control.c"
|
||||
@ -321,6 +324,7 @@ if(CONFIG_BT_ENABLED)
|
||||
"host/bluedroid/stack/smp/smp_main.c"
|
||||
"host/bluedroid/stack/smp/smp_utils.c")
|
||||
|
||||
list(APPEND srcs "common/btc/profile/esp/blufi/bluedroid_host/esp_blufi.c")
|
||||
if(CONFIG_BLE_MESH)
|
||||
list(APPEND srcs "esp_ble_mesh/mesh_core/bluedroid_host/mesh_bearer_adapt.c")
|
||||
endif()
|
||||
@ -540,6 +544,8 @@ if(CONFIG_BT_ENABLED)
|
||||
"host/nimble/esp-hci/src/esp_nimble_hci.c"
|
||||
"host/nimble/port/src/esp_nimble_mem.c")
|
||||
|
||||
list(APPEND srcs
|
||||
"common/btc/profile/esp/blufi/nimble_host/esp_blufi.c")
|
||||
if(CONFIG_BLE_MESH)
|
||||
list(APPEND srcs "esp_ble_mesh/mesh_core/nimble_host/mesh_bearer_adapt.c")
|
||||
endif()
|
||||
@ -589,13 +595,15 @@ idf_component_register(SRCS "${srcs}"
|
||||
if(CONFIG_BT_ENABLED)
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-implicit-fallthrough -Wno-unused-const-variable)
|
||||
if(CONFIG_IDF_TARGET_ESP32)
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-L${CMAKE_CURRENT_LIST_DIR}/controller/lib/esp32")
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-L${CMAKE_CURRENT_LIST_DIR}/controller/lib_esp32/esp32")
|
||||
target_link_libraries(${COMPONENT_LIB} PUBLIC btdm_app)
|
||||
elseif(CONFIG_IDF_TARGET_ESP32C3)
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-L${CMAKE_CURRENT_LIST_DIR}/controller/lib/esp32c3")
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE
|
||||
"-L${CMAKE_CURRENT_LIST_DIR}/controller/lib_esp32c3_family/esp32c3")
|
||||
target_link_libraries(${COMPONENT_LIB} PUBLIC btdm_app btbb)
|
||||
elseif(CONFIG_IDF_TARGET_ESP32S3)
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-L${CMAKE_CURRENT_LIST_DIR}/controller/lib/esp32s3")
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE
|
||||
"-L${CMAKE_CURRENT_LIST_DIR}/controller/lib_esp32c3_family/esp32s3")
|
||||
target_link_libraries(${COMPONENT_LIB} PUBLIC btdm_app btbb)
|
||||
endif()
|
||||
endif()
|
||||
|
@ -14,22 +14,14 @@
|
||||
|
||||
|
||||
#include "esp_blufi_api.h"
|
||||
#include "esp_bt_defs.h"
|
||||
#include "esp_bt_main.h"
|
||||
#include "btc/btc_task.h"
|
||||
#include "btc_blufi_prf.h"
|
||||
#include "btc/btc_manage.h"
|
||||
#include "btc/btc_main.h"
|
||||
#include "osi/future.h"
|
||||
#include "btc_gatts.h"
|
||||
#include "btc_gatt_util.h"
|
||||
#include "common/bt_target.h"
|
||||
#if (BLUFI_INCLUDED == TRUE)
|
||||
esp_err_t esp_blufi_register_callbacks(esp_blufi_callbacks_t *callbacks)
|
||||
{
|
||||
if (esp_bluedroid_get_status() == ESP_BLUEDROID_STATUS_UNINITIALIZED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED);
|
||||
|
||||
if (callbacks == NULL) {
|
||||
return ESP_FAIL;
|
||||
@ -44,9 +36,7 @@ esp_err_t esp_blufi_send_wifi_conn_report(wifi_mode_t opmode, esp_blufi_sta_conn
|
||||
btc_msg_t msg;
|
||||
btc_blufi_args_t arg;
|
||||
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED);
|
||||
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
@ -64,9 +54,7 @@ esp_err_t esp_blufi_send_wifi_list(uint16_t apCount, esp_blufi_ap_record_t *list
|
||||
btc_msg_t msg;
|
||||
btc_blufi_args_t arg;
|
||||
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED);
|
||||
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
@ -81,9 +69,7 @@ esp_err_t esp_blufi_profile_init(void)
|
||||
{
|
||||
btc_msg_t msg;
|
||||
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED);
|
||||
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
@ -96,9 +82,7 @@ esp_err_t esp_blufi_profile_deinit(void)
|
||||
{
|
||||
btc_msg_t msg;
|
||||
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED);
|
||||
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
@ -112,29 +96,12 @@ uint16_t esp_blufi_get_version(void)
|
||||
return btc_blufi_get_version();
|
||||
}
|
||||
|
||||
esp_err_t esp_blufi_close(esp_gatt_if_t gatts_if, uint16_t conn_id)
|
||||
{
|
||||
btc_msg_t msg;
|
||||
btc_ble_gatts_args_t arg;
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_GATTS;
|
||||
msg.act = BTC_GATTS_ACT_CLOSE;
|
||||
arg.close.conn_id = BTC_GATT_CREATE_CONN_ID(gatts_if, conn_id);
|
||||
return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_gatts_args_t), NULL)
|
||||
== BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
|
||||
}
|
||||
|
||||
esp_err_t esp_blufi_send_error_info(esp_blufi_error_state_t state)
|
||||
{
|
||||
btc_msg_t msg;
|
||||
btc_blufi_args_t arg;
|
||||
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED);
|
||||
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
@ -151,9 +118,7 @@ esp_err_t esp_blufi_send_custom_data(uint8_t *data, uint32_t data_len)
|
||||
if(data == NULL || data_len == 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED);
|
||||
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_BLUFI;
|
@ -15,8 +15,6 @@
|
||||
#ifndef __ESP_BLUFI_API_H__
|
||||
#define __ESP_BLUFI_API_H__
|
||||
|
||||
#include "esp_bt_defs.h"
|
||||
#include "esp_gatt_defs.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_wifi_types.h"
|
||||
|
||||
@ -115,6 +113,11 @@ typedef struct {
|
||||
int8_t rssi; /**< signal strength of AP */
|
||||
} esp_blufi_ap_record_t;
|
||||
|
||||
/// Bluetooth address length
|
||||
#define ESP_BD_ADDR_LEN 6
|
||||
/// Bluetooth device address
|
||||
typedef uint8_t esp_bd_addr_t[ESP_BD_ADDR_LEN];
|
||||
|
||||
/**
|
||||
* @brief BLUFI callback parameters union
|
||||
*/
|
||||
@ -301,6 +304,7 @@ typedef void (* esp_blufi_event_cb_t)(esp_blufi_cb_event_t event, esp_blufi_cb_p
|
||||
* @param len : length of data from phone
|
||||
* @param output_data : data want to send to phone
|
||||
* @param output_len : length of data want to send to phone
|
||||
* @param need_free : output reporting if memory needs to be freed or not *
|
||||
*/
|
||||
typedef void (*esp_blufi_negotiate_data_handler_t)(uint8_t *data, int len, uint8_t **output_data, int *output_len, bool *need_free);
|
||||
|
||||
@ -311,7 +315,7 @@ typedef void (*esp_blufi_negotiate_data_handler_t)(uint8_t *data, int len, uint8
|
||||
* @param crypt_len : length of plain text
|
||||
* @return Nonnegative number is encrypted length, if error, return negative number;
|
||||
*/
|
||||
typedef int (* esp_blufi_encrypt_func_t)(uint8_t iv8, uint8_t *crypt_data, int cyprt_len);
|
||||
typedef int (* esp_blufi_encrypt_func_t)(uint8_t iv8, uint8_t *crypt_data, int crypt_len);
|
||||
|
||||
/**
|
||||
* @brief BLUFI decrypt the data after negotiate a share key
|
||||
@ -403,19 +407,6 @@ esp_err_t esp_blufi_send_wifi_list(uint16_t apCount, esp_blufi_ap_record_t *list
|
||||
*/
|
||||
uint16_t esp_blufi_get_version(void);
|
||||
|
||||
/**
|
||||
* @brief Close a connection a remote device.
|
||||
*
|
||||
* @param[in] gatts_if: GATT server access interface
|
||||
* @param[in] conn_id: connection ID to be closed.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : success
|
||||
* - other : failed
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_blufi_close(esp_gatt_if_t gatts_if, uint16_t conn_id);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief This function is called to send blufi error information
|
@ -21,17 +21,17 @@
|
||||
#include "osi/allocator.h"
|
||||
#include "btc/btc_alarm.h"
|
||||
|
||||
#include "btc/btc_manage.h"
|
||||
#include "btc_blufi_prf.h"
|
||||
#include "blufi_int.h"
|
||||
#ifdef CONFIG_BT_BLUEDROID_ENABLED
|
||||
#include "common/bt_target.h"
|
||||
#include "btc/btc_main.h"
|
||||
#include "btc/btc_manage.h"
|
||||
#include "btc/btc_dev.h"
|
||||
#include "btc_gatts.h"
|
||||
#include "btc_gattc.h"
|
||||
#include "btc_gatt_common.h"
|
||||
#include "btc_gap_ble.h"
|
||||
#include "btc_blufi_prf.h"
|
||||
#include "blufi_int.h"
|
||||
#include "btc/btc_dm.h"
|
||||
#include "bta/bta_gatt_api.h"
|
||||
#if CLASSIC_BT_INCLUDED
|
||||
@ -94,11 +94,11 @@ static const btc_func_t profile_tab[BTC_PID_NUM] = {
|
||||
#endif ///BLE_INCLUDED == TRUE
|
||||
[BTC_PID_BLE_HID] = {NULL, NULL},
|
||||
[BTC_PID_SPPLIKE] = {NULL, NULL},
|
||||
[BTC_PID_DM_SEC] = {NULL, btc_dm_sec_cb_handler },
|
||||
#endif
|
||||
#if (BLUFI_INCLUDED == TRUE)
|
||||
[BTC_PID_BLUFI] = {btc_blufi_call_handler, btc_blufi_cb_handler },
|
||||
#endif ///BLUFI_INCLUDED == TRUE
|
||||
[BTC_PID_DM_SEC] = {NULL, btc_dm_sec_cb_handler },
|
||||
#endif
|
||||
[BTC_PID_ALARM] = {btc_alarm_handler, NULL },
|
||||
#ifdef CONFIG_BT_BLUEDROID_ENABLED
|
||||
#if CLASSIC_BT_INCLUDED
|
||||
|
@ -0,0 +1,418 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "osi/allocator.h"
|
||||
#include "btc/btc_task.h"
|
||||
#include "btc/btc_manage.h"
|
||||
#include "blufi_int.h"
|
||||
#include "btc_blufi_prf.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_blufi_api.h"
|
||||
|
||||
#include "common/bt_target.h"
|
||||
#include "common/bt_trace.h"
|
||||
#include "stack/bt_types.h"
|
||||
#include "stack/gatt_api.h"
|
||||
#include "bta/bta_api.h"
|
||||
#include "bta/bta_gatt_api.h"
|
||||
#include "bta_gatts_int.h"
|
||||
#include "btc_gatt_util.h"
|
||||
#include "btc_gatts.h"
|
||||
|
||||
#include "esp_bt_defs.h"
|
||||
#include "esp_gap_ble_api.h"
|
||||
#include "esp_gatt_common_api.h"
|
||||
#include "esp_bt_main.h"
|
||||
#include "esp_bt_device.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_blufi.h"
|
||||
|
||||
#if (BLUFI_INCLUDED == TRUE)
|
||||
|
||||
#if GATT_DYNAMIC_MEMORY == FALSE
|
||||
tBLUFI_ENV blufi_env;
|
||||
#else
|
||||
tBLUFI_ENV *blufi_env_ptr;
|
||||
#endif
|
||||
|
||||
static uint8_t server_if;
|
||||
static uint16_t conn_id;
|
||||
static uint8_t blufi_service_uuid128[32] = {
|
||||
/* LSB <--------------------------------------------------------------------------------> MSB */
|
||||
//first uuid, 16bit, [12],[13] is the value
|
||||
0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
|
||||
};
|
||||
|
||||
static esp_ble_adv_data_t blufi_adv_data = {
|
||||
.set_scan_rsp = false,
|
||||
.include_name = true,
|
||||
.include_txpower = true,
|
||||
.min_interval = 0x0006, //slave connection min interval, Time = min_interval * 1.25 msec
|
||||
.max_interval = 0x0010, //slave connection max interval, Time = max_interval * 1.25 msec
|
||||
.appearance = 0x00,
|
||||
.manufacturer_len = 0,
|
||||
.p_manufacturer_data = NULL,
|
||||
.service_data_len = 0,
|
||||
.p_service_data = NULL,
|
||||
.service_uuid_len = 16,
|
||||
.p_service_uuid = blufi_service_uuid128,
|
||||
.flag = 0x6,
|
||||
};
|
||||
|
||||
static esp_ble_adv_params_t blufi_adv_params = {
|
||||
.adv_int_min = 0x100,
|
||||
.adv_int_max = 0x100,
|
||||
.adv_type = ADV_TYPE_IND,
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
//.peer_addr =
|
||||
//.peer_addr_type =
|
||||
.channel_map = ADV_CHNL_ALL,
|
||||
.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
|
||||
};
|
||||
|
||||
void esp_blufi_gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
|
||||
{
|
||||
switch (event) {
|
||||
case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT:
|
||||
esp_ble_gap_start_advertising(&blufi_adv_params);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// static functions declare
|
||||
static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data);
|
||||
|
||||
void blufi_create_service(void)
|
||||
{
|
||||
if (!blufi_env.enabled) {
|
||||
BTC_TRACE_ERROR("blufi service added error.");
|
||||
return;
|
||||
}
|
||||
|
||||
blufi_env.srvc_inst = 0x00;
|
||||
BTA_GATTS_CreateService(blufi_env.gatt_if, &blufi_srvc_uuid, blufi_env.srvc_inst, BLUFI_HDL_NUM, true);
|
||||
}
|
||||
|
||||
uint8_t esp_blufi_init(void)
|
||||
{
|
||||
|
||||
/* register the BLUFI profile to the BTA_GATTS module*/
|
||||
BTA_GATTS_AppRegister(&blufi_app_uuid, blufi_profile_cb);
|
||||
return GATT_SUCCESS;
|
||||
}
|
||||
|
||||
static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
|
||||
{
|
||||
tBTA_GATTS_RSP rsp;
|
||||
BLUFI_TRACE_DEBUG("blufi profile cb event = %x\n", event);
|
||||
|
||||
switch (event) {
|
||||
case BTA_GATTS_REG_EVT:
|
||||
BLUFI_TRACE_DEBUG("REG: status %d, app_uuid %04x, gatt_if %d\n", p_data->reg_oper.status, p_data->reg_oper.uuid.uu.uuid16, p_data->reg_oper.server_if);
|
||||
|
||||
if (p_data->reg_oper.status != BTA_GATT_OK) {
|
||||
BLUFI_TRACE_ERROR("BLUFI profile register failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
blufi_env.gatt_if = p_data->reg_oper.server_if;
|
||||
blufi_env.enabled = true;
|
||||
|
||||
//create the blufi service to the service data base.
|
||||
if (p_data->reg_oper.uuid.uu.uuid16 == BLUFI_APP_UUID) {
|
||||
BLUFI_TRACE_DEBUG("%s %d\n", __func__, __LINE__);
|
||||
blufi_create_service();
|
||||
}
|
||||
break;
|
||||
case BTA_GATTS_DEREG_EVT: {
|
||||
esp_blufi_cb_param_t param;
|
||||
btc_msg_t msg;
|
||||
|
||||
BLUFI_TRACE_DEBUG("DEREG: status %d, gatt_if %d\n", p_data->reg_oper.status, p_data->reg_oper.server_if);
|
||||
|
||||
if (p_data->reg_oper.status != BTA_GATT_OK) {
|
||||
BLUFI_TRACE_ERROR("BLUFI profile unregister failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
blufi_env.enabled = false;
|
||||
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_DEINIT_FINISH;
|
||||
param.deinit_finish.state = ESP_BLUFI_DEINIT_OK;
|
||||
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), NULL);
|
||||
|
||||
break;
|
||||
}
|
||||
case BTA_GATTS_READ_EVT:
|
||||
memset(&rsp, 0, sizeof(tBTA_GATTS_API_RSP));
|
||||
rsp.attr_value.handle = p_data->req_data.p_data->read_req.handle;
|
||||
rsp.attr_value.len = 1;
|
||||
rsp.attr_value.value[0] = 0x00;
|
||||
BTA_GATTS_SendRsp(p_data->req_data.conn_id, p_data->req_data.trans_id,
|
||||
p_data->req_data.status, &rsp);
|
||||
break;
|
||||
case BTA_GATTS_WRITE_EVT: {
|
||||
if (p_data->req_data.p_data->write_req.is_prep) {
|
||||
tBTA_GATT_STATUS status = GATT_SUCCESS;
|
||||
|
||||
if (blufi_env.prepare_buf == NULL) {
|
||||
blufi_env.prepare_buf = osi_malloc(BLUFI_PREPAIR_BUF_MAX_SIZE);
|
||||
blufi_env.prepare_len = 0;
|
||||
if (blufi_env.prepare_buf == NULL) {
|
||||
BLUFI_TRACE_ERROR("Blufi prep no mem\n");
|
||||
status = GATT_NO_RESOURCES;
|
||||
}
|
||||
} else {
|
||||
if (p_data->req_data.p_data->write_req.offset > BLUFI_PREPAIR_BUF_MAX_SIZE) {
|
||||
status = GATT_INVALID_OFFSET;
|
||||
} else if ((p_data->req_data.p_data->write_req.offset + p_data->req_data.p_data->write_req.len) > BLUFI_PREPAIR_BUF_MAX_SIZE) {
|
||||
status = GATT_INVALID_ATTR_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&rsp, 0, sizeof(tGATTS_RSP));
|
||||
rsp.attr_value.handle = p_data->req_data.p_data->write_req.handle;
|
||||
rsp.attr_value.len = p_data->req_data.p_data->write_req.len;
|
||||
rsp.attr_value.offset = p_data->req_data.p_data->write_req.offset;
|
||||
memcpy(rsp.attr_value.value, p_data->req_data.p_data->write_req.value, p_data->req_data.p_data->write_req.len);
|
||||
|
||||
BLUFI_TRACE_DEBUG("prep write, len=%d, offset=%d\n", p_data->req_data.p_data->write_req.len, p_data->req_data.p_data->write_req.offset);
|
||||
|
||||
BTA_GATTS_SendRsp(p_data->req_data.conn_id, p_data->req_data.trans_id,
|
||||
status, &rsp);
|
||||
|
||||
if (status != GATT_SUCCESS) {
|
||||
if (blufi_env.prepare_buf) {
|
||||
osi_free(blufi_env.prepare_buf);
|
||||
blufi_env.prepare_buf = NULL;
|
||||
blufi_env.prepare_len = 0;
|
||||
}
|
||||
BLUFI_TRACE_ERROR("write data error , error code 0x%x\n", status);
|
||||
return;
|
||||
}
|
||||
memcpy(blufi_env.prepare_buf + p_data->req_data.p_data->write_req.offset,
|
||||
p_data->req_data.p_data->write_req.value,
|
||||
p_data->req_data.p_data->write_req.len);
|
||||
blufi_env.prepare_len += p_data->req_data.p_data->write_req.len;
|
||||
|
||||
return;
|
||||
} else {
|
||||
BLUFI_TRACE_DEBUG("norm write, len=%d, offset=%d\n", p_data->req_data.p_data->write_req.len, p_data->req_data.p_data->write_req.offset);
|
||||
BTA_GATTS_SendRsp(p_data->req_data.conn_id, p_data->req_data.trans_id,
|
||||
p_data->req_data.status, NULL);
|
||||
}
|
||||
|
||||
if (p_data->req_data.p_data->write_req.handle == blufi_env.handle_char_p2e) {
|
||||
btc_blufi_recv_handler(&p_data->req_data.p_data->write_req.value[0],
|
||||
p_data->req_data.p_data->write_req.len);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BTA_GATTS_EXEC_WRITE_EVT:
|
||||
BLUFI_TRACE_DEBUG("exec write exec %d\n", p_data->req_data.p_data->exec_write);
|
||||
|
||||
BTA_GATTS_SendRsp(p_data->req_data.conn_id, p_data->req_data.trans_id,
|
||||
GATT_SUCCESS, NULL);
|
||||
|
||||
if (blufi_env.prepare_buf && p_data->req_data.p_data->exec_write == GATT_PREP_WRITE_EXEC) {
|
||||
btc_blufi_recv_handler(blufi_env.prepare_buf, blufi_env.prepare_len);
|
||||
}
|
||||
|
||||
if (blufi_env.prepare_buf) {
|
||||
osi_free(blufi_env.prepare_buf);
|
||||
blufi_env.prepare_buf = NULL;
|
||||
blufi_env.prepare_len = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
case BTA_GATTS_MTU_EVT:
|
||||
BLUFI_TRACE_DEBUG("MTU size %d\n", p_data->req_data.p_data->mtu);
|
||||
blufi_env.frag_size = (p_data->req_data.p_data->mtu < BLUFI_MAX_DATA_LEN ? p_data->req_data.p_data->mtu : BLUFI_MAX_DATA_LEN) - BLUFI_MTU_RESERVED_SIZE;
|
||||
break;
|
||||
case BTA_GATTS_CONF_EVT:
|
||||
BLUFI_TRACE_DEBUG("CONFIRM EVT\n");
|
||||
/* Nothing */
|
||||
break;
|
||||
case BTA_GATTS_CREATE_EVT:
|
||||
blufi_env.handle_srvc = p_data->create.service_id;
|
||||
|
||||
//add the frist blufi characteristic --> write characteristic
|
||||
BTA_GATTS_AddCharacteristic(blufi_env.handle_srvc, &blufi_char_uuid_p2e,
|
||||
(GATT_PERM_WRITE),
|
||||
(GATT_CHAR_PROP_BIT_WRITE),
|
||||
NULL, NULL);
|
||||
break;
|
||||
case BTA_GATTS_ADD_CHAR_EVT:
|
||||
switch (p_data->add_result.char_uuid.uu.uuid16) {
|
||||
case BLUFI_CHAR_P2E_UUID: /* Phone to ESP32 */
|
||||
blufi_env.handle_char_p2e = p_data->add_result.attr_id;
|
||||
|
||||
BTA_GATTS_AddCharacteristic(blufi_env.handle_srvc, &blufi_char_uuid_e2p,
|
||||
(GATT_PERM_READ),
|
||||
(GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY),
|
||||
NULL, NULL);
|
||||
break;
|
||||
case BLUFI_CHAR_E2P_UUID: /* ESP32 to Phone */
|
||||
blufi_env.handle_char_e2p = p_data->add_result.attr_id;
|
||||
|
||||
BTA_GATTS_AddCharDescriptor (blufi_env.handle_srvc,
|
||||
(GATT_PERM_READ | GATT_PERM_WRITE),
|
||||
&blufi_descr_uuid_e2p,
|
||||
NULL, NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case BTA_GATTS_ADD_CHAR_DESCR_EVT: {
|
||||
/* call init finish */
|
||||
esp_blufi_cb_param_t param;
|
||||
btc_msg_t msg;
|
||||
|
||||
blufi_env.handle_descr_e2p = p_data->add_result.attr_id;
|
||||
//start the blufi service after created
|
||||
BTA_GATTS_StartService(blufi_env.handle_srvc, BTA_GATT_TRANSPORT_LE);
|
||||
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_INIT_FINISH;
|
||||
param.init_finish.state = ESP_BLUFI_INIT_OK;
|
||||
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), NULL);
|
||||
break;
|
||||
}
|
||||
case BTA_GATTS_CONNECT_EVT: {
|
||||
btc_msg_t msg;
|
||||
esp_blufi_cb_param_t param;
|
||||
|
||||
//set the connection flag to true
|
||||
BLUFI_TRACE_API("\ndevice is connected "BT_BD_ADDR_STR", server_if=%d,reason=0x%x,connect_id=%d\n",
|
||||
BT_BD_ADDR_HEX(p_data->conn.remote_bda), p_data->conn.server_if,
|
||||
p_data->conn.reason, p_data->conn.conn_id);
|
||||
|
||||
memcpy(blufi_env.remote_bda, p_data->conn.remote_bda, sizeof(esp_bd_addr_t));
|
||||
blufi_env.conn_id = p_data->conn.conn_id;
|
||||
blufi_env.is_connected = true;
|
||||
blufi_env.recv_seq = blufi_env.send_seq = 0;
|
||||
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_BLE_CONNECT;
|
||||
memcpy(param.connect.remote_bda, p_data->conn.remote_bda, sizeof(esp_bd_addr_t));
|
||||
param.connect.conn_id = BTC_GATT_GET_CONN_ID(p_data->conn.conn_id);
|
||||
conn_id = param.connect.conn_id;
|
||||
server_if = p_data->conn.server_if;
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), NULL);
|
||||
break;
|
||||
}
|
||||
case BTA_GATTS_DISCONNECT_EVT: {
|
||||
btc_msg_t msg;
|
||||
esp_blufi_cb_param_t param;
|
||||
|
||||
blufi_env.is_connected = false;
|
||||
//set the connection flag to true
|
||||
BLUFI_TRACE_API("\ndevice is disconnected "BT_BD_ADDR_STR", server_if=%d,reason=0x%x,connect_id=%d\n",
|
||||
BT_BD_ADDR_HEX(p_data->conn.remote_bda), p_data->conn.server_if,
|
||||
p_data->conn.reason, p_data->conn.conn_id);
|
||||
|
||||
memcpy(blufi_env.remote_bda, p_data->conn.remote_bda, sizeof(esp_bd_addr_t));
|
||||
blufi_env.conn_id = p_data->conn.conn_id;
|
||||
blufi_env.recv_seq = blufi_env.send_seq = 0;
|
||||
blufi_env.sec_mode = 0x0;
|
||||
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_BLE_DISCONNECT;
|
||||
memcpy(param.disconnect.remote_bda, p_data->conn.remote_bda, sizeof(esp_bd_addr_t));
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), NULL);
|
||||
break;
|
||||
}
|
||||
case BTA_GATTS_OPEN_EVT:
|
||||
break;
|
||||
case BTA_GATTS_CLOSE_EVT:
|
||||
break;
|
||||
case BTA_GATTS_CONGEST_EVT:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void esp_blufi_send_notify(void *arg)
|
||||
{
|
||||
struct pkt_info *pkts = (struct pkt_info *) arg;
|
||||
uint16_t conn_id = blufi_env.conn_id;
|
||||
uint16_t attr_id = blufi_env.handle_char_e2p;
|
||||
bool rsp = false;
|
||||
BTA_GATTS_HandleValueIndication(conn_id, attr_id, pkts->pkt_len,
|
||||
pkts->pkt, rsp);
|
||||
|
||||
}
|
||||
|
||||
void esp_blufi_deinit(void)
|
||||
{
|
||||
BTA_GATTS_StopService(blufi_env.handle_srvc);
|
||||
BTA_GATTS_DeleteService(blufi_env.handle_srvc);
|
||||
/* register the BLUFI profile to the BTA_GATTS module*/
|
||||
BTA_GATTS_AppDeregister(blufi_env.gatt_if);
|
||||
}
|
||||
|
||||
void esp_blufi_adv_start(void)
|
||||
{
|
||||
esp_ble_gap_set_device_name(BLUFI_DEVICE_NAME);
|
||||
esp_ble_gap_config_adv_data(&blufi_adv_data);
|
||||
}
|
||||
|
||||
void esp_blufi_adv_stop(void)
|
||||
{
|
||||
esp_ble_gap_stop_advertising();
|
||||
}
|
||||
|
||||
void esp_blufi_send_encap(void *arg)
|
||||
{
|
||||
struct blufi_hdr *hdr = (struct blufi_hdr *)arg;
|
||||
retry:
|
||||
if (blufi_env.is_connected == false) {
|
||||
BTC_TRACE_WARNING("%s ble connection is broken\n", __func__);
|
||||
osi_free(hdr);
|
||||
hdr = NULL;
|
||||
return;
|
||||
}
|
||||
if (esp_ble_get_cur_sendable_packets_num(BTC_GATT_GET_CONN_ID(blufi_env.conn_id)) > 0) {
|
||||
btc_blufi_send_notify((uint8_t *)hdr,
|
||||
((hdr->fc & BLUFI_FC_CHECK) ?
|
||||
hdr->data_len + sizeof(struct blufi_hdr) + 2 :
|
||||
hdr->data_len + sizeof(struct blufi_hdr)));
|
||||
} else {
|
||||
BTC_TRACE_WARNING("%s wait to send blufi custom data\n", __func__);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t esp_blufi_close(esp_gatt_if_t gatts_if, uint16_t conn_id)
|
||||
{
|
||||
ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED);
|
||||
btc_msg_t msg;
|
||||
btc_ble_gatts_args_t arg;
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_GATTS;
|
||||
msg.act = BTC_GATTS_ACT_CLOSE;
|
||||
arg.close.conn_id = BTC_GATT_CREATE_CONN_ID(gatts_if, conn_id);
|
||||
return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_gatts_args_t), NULL)
|
||||
== BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
|
||||
}
|
||||
|
||||
void esp_blufi_disconnect()
|
||||
{
|
||||
int rc;
|
||||
rc = esp_blufi_close(server_if, conn_id);
|
||||
assert (rc == 0);
|
||||
}
|
||||
|
||||
#endif
|
@ -19,61 +19,30 @@
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
#include "common/bt_target.h"
|
||||
#include "common/bt_trace.h"
|
||||
#include "osi/allocator.h"
|
||||
#include "stack/bt_types.h"
|
||||
#include "stack/gatt_api.h"
|
||||
#include "bta/bta_api.h"
|
||||
#include "bta/bta_gatt_api.h"
|
||||
#include "bta_gatts_int.h"
|
||||
|
||||
#include "btc_blufi_prf.h"
|
||||
#include "btc/btc_task.h"
|
||||
#include "btc/btc_manage.h"
|
||||
#include "btc_gatt_util.h"
|
||||
|
||||
#include "blufi_int.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "esp_blufi_api.h"
|
||||
#include "esp_gatt_common_api.h"
|
||||
#include "esp_blufi.h"
|
||||
|
||||
#if (BLUFI_INCLUDED == TRUE)
|
||||
|
||||
#define BT_BD_ADDR_STR "%02x:%02x:%02x:%02x:%02x:%02x"
|
||||
#define BT_BD_ADDR_HEX(addr) addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]
|
||||
|
||||
//define the blufi serivce uuid
|
||||
#define BLUFI_SERVICE_UUID 0xFFFF
|
||||
//define the blufi Char uuid (PHONE to ESP32)
|
||||
#define BLUFI_CHAR_P2E_UUID 0xFF01
|
||||
//define the blufi Char uuid (ESP32 to PHONE)
|
||||
#define BLUFI_CHAR_E2P_UUID 0xFF02
|
||||
//define the blufi Descriptor uuid (ESP32 to PHONE)
|
||||
#define BLUFI_DESCR_E2P_UUID GATT_UUID_CHAR_CLIENT_CONFIG
|
||||
//define the blufi APP ID
|
||||
#define BLUFI_APP_UUID 0xFFFF
|
||||
|
||||
#define BLUFI_HDL_NUM 6
|
||||
|
||||
#if GATT_DYNAMIC_MEMORY == FALSE
|
||||
tBLUFI_ENV blufi_env;
|
||||
#else
|
||||
tBLUFI_ENV *blufi_env_ptr;
|
||||
#endif
|
||||
|
||||
static const tBT_UUID blufi_srvc_uuid = {LEN_UUID_16, {BLUFI_SERVICE_UUID}};
|
||||
static const tBT_UUID blufi_char_uuid_p2e = {LEN_UUID_16, {BLUFI_CHAR_P2E_UUID}};
|
||||
static const tBT_UUID blufi_char_uuid_e2p = {LEN_UUID_16, {BLUFI_CHAR_E2P_UUID}};
|
||||
static const tBT_UUID blufi_descr_uuid_e2p = {LEN_UUID_16, {BLUFI_DESCR_E2P_UUID}};
|
||||
static const tBT_UUID blufi_app_uuid = {LEN_UUID_16, {BLUFI_APP_UUID}};
|
||||
|
||||
// static functions declare
|
||||
static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data);
|
||||
static void btc_blufi_recv_handler(uint8_t *data, int len);
|
||||
static void btc_blufi_send_ack(uint8_t seq);
|
||||
|
||||
static inline void btc_blufi_cb_to_app(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *param)
|
||||
inline void btc_blufi_cb_to_app(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *param)
|
||||
{
|
||||
esp_blufi_event_cb_t btc_blufi_cb = (esp_blufi_event_cb_t)btc_profile_cb_get(BTC_PID_BLUFI);
|
||||
if (btc_blufi_cb) {
|
||||
@ -81,299 +50,44 @@ static inline void btc_blufi_cb_to_app(esp_blufi_cb_event_t event, esp_blufi_cb_
|
||||
}
|
||||
}
|
||||
|
||||
static void blufi_create_service(void)
|
||||
{
|
||||
if (!blufi_env.enabled) {
|
||||
BTC_TRACE_ERROR("blufi service added error.");
|
||||
return;
|
||||
}
|
||||
|
||||
blufi_env.srvc_inst = 0x00;
|
||||
BTA_GATTS_CreateService(blufi_env.gatt_if, &blufi_srvc_uuid, blufi_env.srvc_inst, BLUFI_HDL_NUM, true);
|
||||
}
|
||||
|
||||
static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
|
||||
{
|
||||
tBTA_GATTS_RSP rsp;
|
||||
|
||||
BLUFI_TRACE_DEBUG("blufi profile cb event = %x\n", event);
|
||||
|
||||
switch (event) {
|
||||
case BTA_GATTS_REG_EVT:
|
||||
BLUFI_TRACE_DEBUG("REG: status %d, app_uuid %04x, gatt_if %d\n", p_data->reg_oper.status, p_data->reg_oper.uuid.uu.uuid16, p_data->reg_oper.server_if);
|
||||
|
||||
if (p_data->reg_oper.status != BTA_GATT_OK) {
|
||||
BLUFI_TRACE_ERROR("BLUFI profile register failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
blufi_env.gatt_if = p_data->reg_oper.server_if;
|
||||
blufi_env.enabled = true;
|
||||
|
||||
//create the blufi service to the service data base.
|
||||
if (p_data->reg_oper.uuid.uu.uuid16 == BLUFI_APP_UUID) {
|
||||
BLUFI_TRACE_DEBUG("%s %d\n", __func__, __LINE__);
|
||||
blufi_create_service();
|
||||
}
|
||||
break;
|
||||
case BTA_GATTS_DEREG_EVT: {
|
||||
esp_blufi_cb_param_t param;
|
||||
btc_msg_t msg;
|
||||
|
||||
BLUFI_TRACE_DEBUG("DEREG: status %d, gatt_if %d\n", p_data->reg_oper.status, p_data->reg_oper.server_if);
|
||||
|
||||
if (p_data->reg_oper.status != BTA_GATT_OK) {
|
||||
BLUFI_TRACE_ERROR("BLUFI profile unregister failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
blufi_env.enabled = false;
|
||||
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_DEINIT_FINISH;
|
||||
param.deinit_finish.state = ESP_BLUFI_DEINIT_OK;
|
||||
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), NULL);
|
||||
|
||||
break;
|
||||
}
|
||||
case BTA_GATTS_READ_EVT:
|
||||
memset(&rsp, 0, sizeof(tBTA_GATTS_API_RSP));
|
||||
rsp.attr_value.handle = p_data->req_data.p_data->read_req.handle;
|
||||
rsp.attr_value.len = 1;
|
||||
rsp.attr_value.value[0] = 0x00;
|
||||
BTA_GATTS_SendRsp(p_data->req_data.conn_id, p_data->req_data.trans_id,
|
||||
p_data->req_data.status, &rsp);
|
||||
break;
|
||||
case BTA_GATTS_WRITE_EVT: {
|
||||
if(p_data->req_data.p_data->write_req.is_prep) {
|
||||
tBTA_GATT_STATUS status = GATT_SUCCESS;
|
||||
|
||||
if (blufi_env.prepare_buf == NULL) {
|
||||
blufi_env.prepare_buf = osi_malloc(BLUFI_PREPAIR_BUF_MAX_SIZE);
|
||||
blufi_env.prepare_len = 0;
|
||||
if (blufi_env.prepare_buf == NULL) {
|
||||
BLUFI_TRACE_ERROR("Blufi prep no mem\n");
|
||||
status = GATT_NO_RESOURCES;
|
||||
}
|
||||
} else {
|
||||
if(p_data->req_data.p_data->write_req.offset > BLUFI_PREPAIR_BUF_MAX_SIZE) {
|
||||
status = GATT_INVALID_OFFSET;
|
||||
} else if ((p_data->req_data.p_data->write_req.offset + p_data->req_data.p_data->write_req.len) > BLUFI_PREPAIR_BUF_MAX_SIZE) {
|
||||
status = GATT_INVALID_ATTR_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&rsp, 0, sizeof(tGATTS_RSP));
|
||||
rsp.attr_value.handle = p_data->req_data.p_data->write_req.handle;
|
||||
rsp.attr_value.len = p_data->req_data.p_data->write_req.len;
|
||||
rsp.attr_value.offset = p_data->req_data.p_data->write_req.offset;
|
||||
memcpy(rsp.attr_value.value, p_data->req_data.p_data->write_req.value, p_data->req_data.p_data->write_req.len);
|
||||
|
||||
BLUFI_TRACE_DEBUG("prep write, len=%d, offset=%d\n", p_data->req_data.p_data->write_req.len, p_data->req_data.p_data->write_req.offset);
|
||||
|
||||
BTA_GATTS_SendRsp(p_data->req_data.conn_id, p_data->req_data.trans_id,
|
||||
status, &rsp);
|
||||
|
||||
if(status != GATT_SUCCESS) {
|
||||
if (blufi_env.prepare_buf) {
|
||||
osi_free(blufi_env.prepare_buf);
|
||||
blufi_env.prepare_buf = NULL;
|
||||
blufi_env.prepare_len = 0;
|
||||
}
|
||||
BLUFI_TRACE_ERROR("write data error , error code 0x%x\n", status);
|
||||
return;
|
||||
}
|
||||
memcpy(blufi_env.prepare_buf + p_data->req_data.p_data->write_req.offset,
|
||||
p_data->req_data.p_data->write_req.value,
|
||||
p_data->req_data.p_data->write_req.len);
|
||||
blufi_env.prepare_len += p_data->req_data.p_data->write_req.len;
|
||||
|
||||
return;
|
||||
} else {
|
||||
BLUFI_TRACE_DEBUG("norm write, len=%d, offset=%d\n", p_data->req_data.p_data->write_req.len, p_data->req_data.p_data->write_req.offset);
|
||||
BTA_GATTS_SendRsp(p_data->req_data.conn_id, p_data->req_data.trans_id,
|
||||
p_data->req_data.status, NULL);
|
||||
}
|
||||
|
||||
if (p_data->req_data.p_data->write_req.handle == blufi_env.handle_char_p2e) {
|
||||
btc_blufi_recv_handler(&p_data->req_data.p_data->write_req.value[0],
|
||||
p_data->req_data.p_data->write_req.len);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BTA_GATTS_EXEC_WRITE_EVT:
|
||||
BLUFI_TRACE_DEBUG("exec write exec %d\n", p_data->req_data.p_data->exec_write);
|
||||
|
||||
BTA_GATTS_SendRsp(p_data->req_data.conn_id, p_data->req_data.trans_id,
|
||||
GATT_SUCCESS, NULL);
|
||||
|
||||
if (blufi_env.prepare_buf && p_data->req_data.p_data->exec_write == GATT_PREP_WRITE_EXEC) {
|
||||
btc_blufi_recv_handler(blufi_env.prepare_buf, blufi_env.prepare_len);
|
||||
}
|
||||
|
||||
if (blufi_env.prepare_buf) {
|
||||
osi_free(blufi_env.prepare_buf);
|
||||
blufi_env.prepare_buf = NULL;
|
||||
blufi_env.prepare_len = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
case BTA_GATTS_MTU_EVT:
|
||||
BLUFI_TRACE_DEBUG("MTU size %d\n", p_data->req_data.p_data->mtu);
|
||||
blufi_env.frag_size = (p_data->req_data.p_data->mtu < BLUFI_MAX_DATA_LEN ? p_data->req_data.p_data->mtu : BLUFI_MAX_DATA_LEN) - BLUFI_MTU_RESERVED_SIZE;
|
||||
break;
|
||||
case BTA_GATTS_CONF_EVT:
|
||||
BLUFI_TRACE_DEBUG("CONFIRM EVT\n");
|
||||
/* Nothing */
|
||||
break;
|
||||
case BTA_GATTS_CREATE_EVT:
|
||||
blufi_env.handle_srvc = p_data->create.service_id;
|
||||
|
||||
//add the frist blufi characteristic --> write characteristic
|
||||
BTA_GATTS_AddCharacteristic(blufi_env.handle_srvc, &blufi_char_uuid_p2e,
|
||||
(GATT_PERM_WRITE),
|
||||
(GATT_CHAR_PROP_BIT_WRITE),
|
||||
NULL, NULL);
|
||||
break;
|
||||
case BTA_GATTS_ADD_CHAR_EVT:
|
||||
switch (p_data->add_result.char_uuid.uu.uuid16) {
|
||||
case BLUFI_CHAR_P2E_UUID: /* Phone to ESP32 */
|
||||
blufi_env.handle_char_p2e = p_data->add_result.attr_id;
|
||||
|
||||
BTA_GATTS_AddCharacteristic(blufi_env.handle_srvc, &blufi_char_uuid_e2p,
|
||||
(GATT_PERM_READ),
|
||||
(GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY),
|
||||
NULL, NULL);
|
||||
break;
|
||||
case BLUFI_CHAR_E2P_UUID: /* ESP32 to Phone */
|
||||
blufi_env.handle_char_e2p = p_data->add_result.attr_id;
|
||||
|
||||
BTA_GATTS_AddCharDescriptor (blufi_env.handle_srvc,
|
||||
(GATT_PERM_READ | GATT_PERM_WRITE),
|
||||
&blufi_descr_uuid_e2p,
|
||||
NULL, NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case BTA_GATTS_ADD_CHAR_DESCR_EVT: {
|
||||
/* call init finish */
|
||||
esp_blufi_cb_param_t param;
|
||||
btc_msg_t msg;
|
||||
|
||||
blufi_env.handle_descr_e2p = p_data->add_result.attr_id;
|
||||
//start the blufi service after created
|
||||
BTA_GATTS_StartService(blufi_env.handle_srvc, BTA_GATT_TRANSPORT_LE);
|
||||
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_INIT_FINISH;
|
||||
param.init_finish.state = ESP_BLUFI_INIT_OK;
|
||||
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), NULL);
|
||||
break;
|
||||
}
|
||||
case BTA_GATTS_CONNECT_EVT: {
|
||||
btc_msg_t msg;
|
||||
esp_blufi_cb_param_t param;
|
||||
|
||||
//set the connection flag to true
|
||||
BLUFI_TRACE_API("\ndevice is connected "BT_BD_ADDR_STR", server_if=%d,reason=0x%x,connect_id=%d\n",
|
||||
BT_BD_ADDR_HEX(p_data->conn.remote_bda), p_data->conn.server_if,
|
||||
p_data->conn.reason, p_data->conn.conn_id);
|
||||
|
||||
memcpy(blufi_env.remote_bda, p_data->conn.remote_bda, sizeof(esp_bd_addr_t));
|
||||
blufi_env.conn_id = p_data->conn.conn_id;
|
||||
blufi_env.is_connected = true;
|
||||
blufi_env.recv_seq = blufi_env.send_seq = 0;
|
||||
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_BLE_CONNECT;
|
||||
memcpy(param.connect.remote_bda, p_data->conn.remote_bda, sizeof(esp_bd_addr_t));
|
||||
param.connect.conn_id=BTC_GATT_GET_CONN_ID(p_data->conn.conn_id);
|
||||
param.connect.server_if=p_data->conn.server_if;
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), NULL);
|
||||
break;
|
||||
}
|
||||
case BTA_GATTS_DISCONNECT_EVT: {
|
||||
btc_msg_t msg;
|
||||
esp_blufi_cb_param_t param;
|
||||
|
||||
blufi_env.is_connected = false;
|
||||
//set the connection flag to true
|
||||
BLUFI_TRACE_API("\ndevice is disconnected "BT_BD_ADDR_STR", server_if=%d,reason=0x%x,connect_id=%d\n",
|
||||
BT_BD_ADDR_HEX(p_data->conn.remote_bda), p_data->conn.server_if,
|
||||
p_data->conn.reason, p_data->conn.conn_id);
|
||||
|
||||
memcpy(blufi_env.remote_bda, p_data->conn.remote_bda, sizeof(esp_bd_addr_t));
|
||||
blufi_env.conn_id = p_data->conn.conn_id;
|
||||
blufi_env.recv_seq = blufi_env.send_seq = 0;
|
||||
blufi_env.sec_mode = 0x0;
|
||||
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_BLE_DISCONNECT;
|
||||
memcpy(param.disconnect.remote_bda, p_data->conn.remote_bda, sizeof(esp_bd_addr_t));
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), NULL);
|
||||
break;
|
||||
}
|
||||
case BTA_GATTS_OPEN_EVT:
|
||||
break;
|
||||
case BTA_GATTS_CLOSE_EVT:
|
||||
break;
|
||||
case BTA_GATTS_CONGEST_EVT:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static tGATT_STATUS btc_blufi_profile_init(void)
|
||||
static uint8_t btc_blufi_profile_init(void)
|
||||
{
|
||||
esp_blufi_callbacks_t *store_p = blufi_env.cbs;
|
||||
|
||||
uint8_t rc;
|
||||
if (blufi_env.enabled) {
|
||||
BLUFI_TRACE_ERROR("BLUFI already initialized");
|
||||
return GATT_ERROR;
|
||||
return ESP_BLUFI_ERROR;
|
||||
}
|
||||
|
||||
memset(&blufi_env, 0x0, sizeof(blufi_env));
|
||||
blufi_env.cbs = store_p; /* if set callback prior, restore the point */
|
||||
blufi_env.frag_size = BLUFI_FRAG_DATA_DEFAULT_LEN;
|
||||
rc = esp_blufi_init();
|
||||
if(rc != 0 ){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* register the BLUFI profile to the BTA_GATTS module*/
|
||||
BTA_GATTS_AppRegister(&blufi_app_uuid, blufi_profile_cb);
|
||||
|
||||
return GATT_SUCCESS;
|
||||
return ESP_BLUFI_SUCCESS;
|
||||
}
|
||||
|
||||
static tGATT_STATUS btc_blufi_profile_deinit(void)
|
||||
static uint8_t btc_blufi_profile_deinit(void)
|
||||
{
|
||||
if (!blufi_env.enabled) {
|
||||
BTC_TRACE_ERROR("BLUFI already de-initialized");
|
||||
return GATT_ERROR;
|
||||
return ESP_BLUFI_ERROR;
|
||||
}
|
||||
|
||||
BTA_GATTS_StopService(blufi_env.handle_srvc);
|
||||
BTA_GATTS_DeleteService(blufi_env.handle_srvc);
|
||||
/* register the BLUFI profile to the BTA_GATTS module*/
|
||||
BTA_GATTS_AppDeregister(blufi_env.gatt_if);
|
||||
|
||||
return GATT_SUCCESS;
|
||||
esp_blufi_deinit();
|
||||
return ESP_BLUFI_SUCCESS;
|
||||
}
|
||||
|
||||
static void btc_blufi_send_notify(uint8_t *pkt, int pkt_len)
|
||||
void btc_blufi_send_notify(uint8_t *pkt, int pkt_len)
|
||||
{
|
||||
UINT16 conn_id = blufi_env.conn_id;
|
||||
UINT16 attr_id = blufi_env.handle_char_e2p;
|
||||
bool rsp = false;
|
||||
|
||||
BTA_GATTS_HandleValueIndication(conn_id, attr_id, pkt_len,
|
||||
pkt, rsp);
|
||||
struct pkt_info pkts;
|
||||
pkts.pkt = pkt;
|
||||
pkts.pkt_len = pkt_len;
|
||||
esp_blufi_send_notify(&pkts);
|
||||
}
|
||||
|
||||
void btc_blufi_report_error(esp_blufi_error_state_t state)
|
||||
@ -387,7 +101,7 @@ void btc_blufi_report_error(esp_blufi_error_state_t state)
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), NULL);
|
||||
}
|
||||
|
||||
static void btc_blufi_recv_handler(uint8_t *data, int len)
|
||||
void btc_blufi_recv_handler(uint8_t *data, int len)
|
||||
{
|
||||
struct blufi_hdr *hdr = (struct blufi_hdr *)data;
|
||||
uint16_t checksum, checksum_pkt;
|
||||
@ -536,24 +250,7 @@ void btc_blufi_send_encap(uint8_t type, uint8_t *data, int total_data_len)
|
||||
remain_len -= hdr->data_len;
|
||||
}
|
||||
|
||||
retry:
|
||||
if (blufi_env.is_connected == false) {
|
||||
BTC_TRACE_WARNING("%s ble connection is broken\n", __func__);
|
||||
osi_free(hdr);
|
||||
hdr = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (esp_ble_get_cur_sendable_packets_num(BTC_GATT_GET_CONN_ID(blufi_env.conn_id)) > 0) {
|
||||
btc_blufi_send_notify((uint8_t *)hdr,
|
||||
((hdr->fc & BLUFI_FC_CHECK) ?
|
||||
hdr->data_len + sizeof(struct blufi_hdr) + 2 :
|
||||
hdr->data_len + sizeof(struct blufi_hdr)));
|
||||
} else {
|
||||
BTC_TRACE_WARNING("%s wait to send blufi custom data\n", __func__);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
goto retry;
|
||||
}
|
||||
esp_blufi_send_encap(hdr);
|
||||
|
||||
osi_free(hdr);
|
||||
hdr = NULL;
|
@ -18,15 +18,6 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
#include "common/bt_target.h"
|
||||
#include "common/bt_trace.h"
|
||||
#include "stack/bt_types.h"
|
||||
#include "stack/gatt_api.h"
|
||||
#include "bta/bta_api.h"
|
||||
#include "bta/bta_gatt_api.h"
|
||||
#include "bta_gatts_int.h"
|
||||
|
||||
#include "btc_blufi_prf.h"
|
||||
#include "btc/btc_task.h"
|
||||
#include "btc/btc_manage.h"
|
@ -15,11 +15,15 @@
|
||||
#ifndef __BLUFI_INT_H__
|
||||
#define __BLUFI_INT_H__
|
||||
|
||||
#include "btc/btc_task.h"
|
||||
#include "esp_blufi_api.h"
|
||||
#if (BLUFI_INCLUDED == TRUE)
|
||||
|
||||
#define BTC_BLUFI_GREAT_VER 0x01 //Version + Subversion
|
||||
#define BTC_BLUFI_SUB_VER 0x02 //Version + Subversion
|
||||
#define BTC_BLUFI_VERSION ((BTC_BLUFI_GREAT_VER<<8)|BTC_BLUFI_SUB_VER) //Version + Subversion
|
||||
|
||||
typedef UINT8 tGATT_IF;
|
||||
/* service engine control block */
|
||||
typedef struct {
|
||||
/* Protocol reference */
|
||||
@ -176,6 +180,9 @@ extern tBLUFI_ENV *blufi_env_ptr;
|
||||
#define BLUFI_FC_IS_REQ_ACK(fc) ((fc) & BLUFI_FC_REQ_ACK_MASK)
|
||||
#define BLUFI_FC_IS_FRAG(fc) ((fc) & BLUFI_FC_FRAG_MASK)
|
||||
|
||||
/* default GATT MTU size over LE link
|
||||
*/
|
||||
#define GATT_DEF_BLE_MTU_SIZE 23
|
||||
/* BLUFI HEADER + TOTAL(REMAIN) LENGTH + CRC + L2CAP RESERVED */
|
||||
#define BLUFI_MTU_RESERVED_SIZE (sizeof(struct blufi_hdr) + 2 + 2 + 3)
|
||||
#define BLUFI_FRAG_DATA_DEFAULT_LEN (GATT_DEF_BLE_MTU_SIZE - BLUFI_MTU_RESERVED_SIZE)
|
@ -0,0 +1,77 @@
|
||||
#ifndef __ESP_BLUFI_H__
|
||||
#define __ESP_BLUFI_H__
|
||||
|
||||
#include "esp_blufi_api.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef CONFIG_BT_NIMBLE_ENABLED
|
||||
#include "nimble/ble.h"
|
||||
#include "modlog/modlog.h"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_BLUEDROID_ENABLED
|
||||
#include "esp_gap_ble_api.h"
|
||||
#endif
|
||||
|
||||
#define BLUFI_APP_UUID 0xFFFF
|
||||
#define BLUFI_DEVICE_NAME "BLUFI_DEVICE"
|
||||
|
||||
#ifdef CONFIG_BT_NIMBLE_ENABLED
|
||||
struct ble_hs_cfg;
|
||||
struct ble_gatt_register_ctxt;
|
||||
struct gatt_value {
|
||||
struct os_mbuf *buf;
|
||||
uint16_t val_handle;
|
||||
uint8_t type;
|
||||
void *ptr;
|
||||
};
|
||||
#define SERVER_MAX_VALUES 3
|
||||
#define MAX_VAL_SIZE 512
|
||||
extern struct gatt_value gatt_values[SERVER_MAX_VALUES];
|
||||
/* GATT server callback */
|
||||
void esp_blufi_gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg);
|
||||
|
||||
/* Initialise gatt server */
|
||||
int esp_blufi_gatt_svr_init(void);
|
||||
void esp_blufi_btc_init(void);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_BLUEDROID_ENABLED
|
||||
/**
|
||||
* @brief Close a connection a remote device.
|
||||
*
|
||||
* @param[in] gatts_if: GATT server access interface
|
||||
* @param[in] conn_id: connection ID to be closed.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : success
|
||||
* - other : failed
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_blufi_close(uint8_t gatts_if, uint16_t conn_id);
|
||||
void esp_blufi_gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param);
|
||||
#endif
|
||||
|
||||
/* Initialise blufi profile */
|
||||
uint8_t esp_blufi_init(void);
|
||||
|
||||
/* start advertising */
|
||||
void bleprph_advertise(void);
|
||||
|
||||
/* send notifications */
|
||||
void esp_blufi_send_notify(void *arg);
|
||||
|
||||
/* Deinitialise blufi */
|
||||
void esp_blufi_deinit(void);
|
||||
/* disconnect */
|
||||
void esp_blufi_disconnect(void);
|
||||
|
||||
/* Stop advertisement */
|
||||
void esp_blufi_adv_stop(void);
|
||||
|
||||
/* Start advertisement */
|
||||
void esp_blufi_adv_start(void);
|
||||
|
||||
void esp_blufi_send_encap(void *arg);
|
||||
|
||||
#endif/* _ESP_BLUFI_ */
|
@ -0,0 +1,457 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "btc_blufi_prf.h"
|
||||
#include "blufi_int.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_blufi_api.h"
|
||||
#include "esp_err.h"
|
||||
#include "btc/btc_task.h"
|
||||
#include "esp_blufi.h"
|
||||
#include "osi/allocator.h"
|
||||
#include "console/console.h"
|
||||
|
||||
/*nimBLE Host*/
|
||||
#include "esp_nimble_hci.h"
|
||||
#include "nimble/nimble_port.h"
|
||||
#include "nimble/nimble_port_freertos.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/util/util.h"
|
||||
#include "host/ble_uuid.h"
|
||||
#include "host/ble_gatt.h"
|
||||
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#include "services/gatt/ble_svc_gatt.h"
|
||||
|
||||
#if (BLUFI_INCLUDED == TRUE)
|
||||
|
||||
static uint8_t own_addr_type;
|
||||
static uint16_t conn_handle;
|
||||
|
||||
struct gatt_value gatt_values[SERVER_MAX_VALUES];
|
||||
const static char *TAG = "BLUFI_EXAMPLE";
|
||||
|
||||
enum {
|
||||
GATT_VALUE_TYPE_CHR,
|
||||
GATT_VALUE_TYPE_DSC,
|
||||
};
|
||||
|
||||
static int gatt_svr_access_cb(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt,
|
||||
void *arg);
|
||||
|
||||
static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
|
||||
{
|
||||
/*** Service: Blufi */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = BLE_UUID16_DECLARE(BLUFI_SERVICE_UUID),
|
||||
.characteristics = (struct ble_gatt_chr_def[])
|
||||
{ {
|
||||
/*** Characteristic: P2E */
|
||||
.uuid = BLE_UUID16_DECLARE(BLUFI_CHAR_P2E_UUID),
|
||||
.access_cb = gatt_svr_access_cb,
|
||||
.flags = BLE_GATT_CHR_F_WRITE,
|
||||
.arg = &gatt_values[0],
|
||||
.val_handle = &gatt_values[0].val_handle,
|
||||
}, {
|
||||
/*** Characteristic: E2P */
|
||||
.uuid = BLE_UUID16_DECLARE(BLUFI_CHAR_E2P_UUID),
|
||||
.access_cb = gatt_svr_access_cb,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
|
||||
.arg = &gatt_values[1],
|
||||
.val_handle = &gatt_values[1].val_handle,
|
||||
}, {
|
||||
0, /* No more characteristics in this service. */
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
0, /* No more services. */
|
||||
},
|
||||
};
|
||||
|
||||
void esp_blufi_gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
|
||||
{
|
||||
char buf[BLE_UUID_STR_LEN];
|
||||
switch (ctxt->op) {
|
||||
case BLE_GATT_REGISTER_OP_SVC:
|
||||
ESP_LOGI(TAG, "registered service %s with handle=%d\n",
|
||||
ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf),
|
||||
ctxt->svc.handle);
|
||||
break;
|
||||
|
||||
case BLE_GATT_REGISTER_OP_CHR:
|
||||
ESP_LOGI(TAG, "registering characteristic %s with "
|
||||
"def_handle=%d val_handle=%d\n",
|
||||
ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf),
|
||||
ctxt->chr.def_handle,
|
||||
ctxt->chr.val_handle);
|
||||
break;
|
||||
|
||||
case BLE_GATT_REGISTER_OP_DSC:
|
||||
ESP_LOGI(TAG, "registering descriptor %s with handle=%d\n",
|
||||
ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf),
|
||||
ctxt->dsc.handle);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t write_value(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt,
|
||||
void *arg)
|
||||
{
|
||||
struct gatt_value *value = (struct gatt_value *)arg;
|
||||
uint16_t len;
|
||||
int rc;
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||
if (ctxt->chr->flags & BLE_GATT_CHR_F_WRITE_AUTHOR) {
|
||||
return BLE_ATT_ERR_INSUFFICIENT_AUTHOR;
|
||||
}
|
||||
} else {
|
||||
if (ctxt->dsc->att_flags & BLE_ATT_F_WRITE_AUTHOR) {
|
||||
return BLE_ATT_ERR_INSUFFICIENT_AUTHOR;
|
||||
}
|
||||
}
|
||||
|
||||
btc_blufi_recv_handler(&ctxt->om->om_data[0], ctxt->om->om_len);
|
||||
rc = ble_hs_mbuf_to_flat(ctxt->om, value->buf->om_data,
|
||||
value->buf->om_len, &len);
|
||||
if (rc != 0) {
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
/* Maximum attribute value size is 512 bytes */
|
||||
assert(value->buf->om_len < MAX_VAL_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t read_value(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt,
|
||||
void *arg)
|
||||
{
|
||||
const struct gatt_value *value = (const struct gatt_value *) arg;
|
||||
char str[BLE_UUID_STR_LEN];
|
||||
int rc;
|
||||
|
||||
memset(str, '\0', sizeof(str));
|
||||
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
|
||||
if (ctxt->chr->flags & BLE_GATT_CHR_F_READ_AUTHOR) {
|
||||
return BLE_ATT_ERR_INSUFFICIENT_AUTHOR;
|
||||
}
|
||||
|
||||
ble_uuid_to_str(ctxt->chr->uuid, str);
|
||||
} else {
|
||||
if (ctxt->dsc->att_flags & BLE_ATT_F_READ_AUTHOR) {
|
||||
return BLE_ATT_ERR_INSUFFICIENT_AUTHOR;
|
||||
}
|
||||
|
||||
ble_uuid_to_str(ctxt->dsc->uuid, str);
|
||||
}
|
||||
|
||||
rc = os_mbuf_append(ctxt->om, value->buf->om_data, value->buf->om_len);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
static int gatt_svr_access_cb(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt,
|
||||
void *arg)
|
||||
{
|
||||
switch (ctxt->op) {
|
||||
case BLE_GATT_ACCESS_OP_READ_CHR:
|
||||
return read_value(conn_handle, attr_handle,
|
||||
ctxt, arg);
|
||||
case BLE_GATT_ACCESS_OP_WRITE_CHR:
|
||||
return write_value(conn_handle, attr_handle,
|
||||
ctxt, arg);
|
||||
default:
|
||||
assert(0);
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
|
||||
/* Unknown characteristic; the nimble stack should not have called this
|
||||
* function.
|
||||
*/
|
||||
assert(0);
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
|
||||
static void init_gatt_values(void)
|
||||
{
|
||||
int i = 0;
|
||||
const struct ble_gatt_svc_def *svc;
|
||||
const struct ble_gatt_chr_def *chr;
|
||||
const struct ble_gatt_dsc_def *dsc;
|
||||
|
||||
for (svc = gatt_svr_svcs; svc && svc->uuid; svc++) {
|
||||
for (chr = svc->characteristics; chr && chr->uuid; chr++) {
|
||||
assert(i < SERVER_MAX_VALUES);
|
||||
gatt_values[i].type = GATT_VALUE_TYPE_CHR;
|
||||
gatt_values[i].ptr = (void *)chr;
|
||||
gatt_values[i].buf = os_msys_get(0, 0);
|
||||
os_mbuf_extend(gatt_values[i].buf, 1);
|
||||
++i;
|
||||
|
||||
for (dsc = chr->descriptors; dsc && dsc->uuid; dsc++) {
|
||||
assert(i < SERVER_MAX_VALUES);
|
||||
gatt_values[i].type = GATT_VALUE_TYPE_DSC;
|
||||
gatt_values[i].ptr = (void *)dsc;
|
||||
gatt_values[i].buf = os_msys_get(0, 0);
|
||||
os_mbuf_extend(gatt_values[i].buf, 1);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int esp_blufi_gatt_svr_init(void)
|
||||
{
|
||||
int rc;
|
||||
ble_svc_gap_init();
|
||||
ble_svc_gatt_init();
|
||||
|
||||
rc = ble_gatts_count_cfg(gatt_svr_svcs);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = ble_gatts_add_svcs(gatt_svr_svcs);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
init_gatt_values();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
esp_blufi_gap_event(struct ble_gap_event *event, void *arg)
|
||||
{
|
||||
struct ble_gap_conn_desc desc;
|
||||
int rc;
|
||||
|
||||
switch (event->type) {
|
||||
case BLE_GAP_EVENT_CONNECT:
|
||||
/* A new connection was established or a connection attempt failed. */
|
||||
ESP_LOGI(TAG, "connection %s; status=%d\n",
|
||||
event->connect.status == 0 ? "established" : "failed",
|
||||
event->connect.status);
|
||||
if (event->connect.status == 0) {
|
||||
|
||||
blufi_env.is_connected = true;
|
||||
blufi_env.recv_seq = blufi_env.send_seq = 0;
|
||||
btc_msg_t msg;
|
||||
esp_blufi_cb_param_t param;
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_BLE_CONNECT;
|
||||
|
||||
rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
|
||||
assert(rc == 0);
|
||||
memcpy(param.connect.remote_bda, desc.peer_id_addr.val, sizeof(esp_bd_addr_t));
|
||||
|
||||
param.connect.conn_id = event->connect.conn_handle;
|
||||
/* save connection handle */
|
||||
conn_handle = event->connect.conn_handle;
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), NULL);
|
||||
}
|
||||
if (event->connect.status != 0) {
|
||||
/* Connection failed; resume advertising. */
|
||||
esp_blufi_adv_start();
|
||||
}
|
||||
return 0;
|
||||
case BLE_GAP_EVENT_DISCONNECT:
|
||||
ESP_LOGI(TAG, "disconnect; reason=%d\n", event->disconnect.reason);
|
||||
memcpy(blufi_env.remote_bda, event->disconnect.conn.peer_id_addr.val, sizeof(esp_bd_addr_t));
|
||||
blufi_env.is_connected = false;
|
||||
blufi_env.recv_seq = blufi_env.send_seq = 0;
|
||||
blufi_env.sec_mode = 0x0;
|
||||
btc_msg_t msg;
|
||||
esp_blufi_cb_param_t param;
|
||||
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_BLE_DISCONNECT;
|
||||
memcpy(param.disconnect.remote_bda, event->disconnect.conn.peer_id_addr.val, sizeof(esp_bd_addr_t));
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), NULL);
|
||||
|
||||
return 0;
|
||||
case BLE_GAP_EVENT_CONN_UPDATE:
|
||||
/* The central has updated the connection parameters. */
|
||||
ESP_LOGI(TAG, "connection updated; status=%d\n",
|
||||
event->conn_update.status);
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_ADV_COMPLETE:
|
||||
ESP_LOGI(TAG, "advertise complete; reason=%d",
|
||||
event->adv_complete.reason);
|
||||
esp_blufi_adv_start();
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_SUBSCRIBE:
|
||||
ESP_LOGI(TAG, "subscribe event; conn_handle=%d attr_handle=%d "
|
||||
"reason=%d prevn=%d curn=%d previ=%d curi=%d\n",
|
||||
event->subscribe.conn_handle,
|
||||
event->subscribe.attr_handle,
|
||||
event->subscribe.reason,
|
||||
event->subscribe.prev_notify,
|
||||
event->subscribe.cur_notify,
|
||||
event->subscribe.prev_indicate,
|
||||
event->subscribe.cur_indicate);
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_MTU:
|
||||
ESP_LOGI(TAG, "mtu update event; conn_handle=%d cid=%d mtu=%d\n",
|
||||
event->mtu.conn_handle,
|
||||
event->mtu.channel_id,
|
||||
event->mtu.value);
|
||||
blufi_env.frag_size = (event->mtu.value < BLUFI_MAX_DATA_LEN ? event->mtu.value : BLUFI_MAX_DATA_LEN) - BLUFI_MTU_RESERVED_SIZE;
|
||||
return 0;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void esp_blufi_adv_start(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = ble_hs_util_ensure_addr(0);
|
||||
assert(rc == 0);
|
||||
|
||||
/* Figure out address to use while advertising (no privacy for now) */
|
||||
rc = ble_hs_id_infer_auto(0, &own_addr_type);
|
||||
if (rc != 0) {
|
||||
ESP_LOGI(TAG, "error determining address type; rc=%d ", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Printing ADDR */
|
||||
uint8_t addr_val[6] = {0};
|
||||
rc = ble_hs_id_copy_addr(own_addr_type, addr_val, NULL);
|
||||
|
||||
/* Begin advertising. */
|
||||
struct ble_gap_adv_params adv_params;
|
||||
struct ble_hs_adv_fields fields;
|
||||
const char *name;
|
||||
|
||||
/**
|
||||
* Set the advertisement data included in our advertisements:
|
||||
* o Flags (indicates advertisement type and other general info).
|
||||
* o Advertising tx power.
|
||||
* o Device name.
|
||||
* o 16-bit service UUIDs (alert notifications).
|
||||
*/
|
||||
|
||||
memset(&fields, 0, sizeof fields);
|
||||
|
||||
/* Advertise two flags:
|
||||
* o Discoverability in forthcoming advertisement (general)
|
||||
* o BLE-only (BR/EDR unsupported).
|
||||
*/
|
||||
fields.flags = BLE_HS_ADV_F_DISC_GEN |
|
||||
BLE_HS_ADV_F_BREDR_UNSUP;
|
||||
|
||||
/* Indicate that the TX power level field should be included; have the
|
||||
* stack fill this value automatically. This is done by assigning the
|
||||
* special value BLE_HS_ADV_TX_PWR_LVL_AUTO.
|
||||
*/
|
||||
fields.tx_pwr_lvl_is_present = 1;
|
||||
fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
|
||||
|
||||
name = ble_svc_gap_device_name();
|
||||
fields.name = (uint8_t *)name;
|
||||
fields.name_len = strlen(name);
|
||||
fields.name_is_complete = 1;
|
||||
|
||||
fields.uuids16 = (ble_uuid16_t[]) {
|
||||
BLE_UUID16_INIT(BLUFI_APP_UUID)
|
||||
};
|
||||
fields.num_uuids16 = 1;
|
||||
fields.uuids16_is_complete = 1;
|
||||
rc = ble_gap_adv_set_fields(&fields);
|
||||
if (rc != 0) {
|
||||
ESP_LOGE(TAG, "error setting advertisement data; rc=%d\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Begin advertising. */
|
||||
memset(&adv_params, 0, sizeof adv_params);
|
||||
adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
|
||||
adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
|
||||
rc = ble_gap_adv_start(own_addr_type, NULL, BLE_HS_FOREVER,
|
||||
&adv_params, esp_blufi_gap_event, NULL);
|
||||
if (rc != 0) {
|
||||
ESP_LOGE(TAG, "error enabling advertisement; rc=%d\n", rc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t esp_blufi_init(void)
|
||||
{
|
||||
blufi_env.enabled = true;
|
||||
esp_blufi_cb_param_t param;
|
||||
param.init_finish.state = ESP_BLUFI_INIT_OK;
|
||||
btc_blufi_cb_to_app(ESP_BLUFI_EVENT_INIT_FINISH, ¶m);
|
||||
return ESP_BLUFI_ERROR;
|
||||
}
|
||||
|
||||
void esp_blufi_deinit(void)
|
||||
{
|
||||
blufi_env.enabled = false;
|
||||
btc_msg_t msg;
|
||||
esp_blufi_cb_param_t param;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_DEINIT_FINISH;
|
||||
param.deinit_finish.state = ESP_BLUFI_DEINIT_OK;
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), NULL);
|
||||
}
|
||||
|
||||
void esp_blufi_send_notify(void *arg)
|
||||
{
|
||||
struct pkt_info *pkts = (struct pkt_info *) arg;
|
||||
struct os_mbuf *om;
|
||||
om = ble_hs_mbuf_from_flat(pkts->pkt, pkts->pkt_len);
|
||||
int rc = 0;
|
||||
rc = ble_gattc_notify_custom(conn_handle, gatt_values[1].val_handle, om);
|
||||
assert(rc == 0);
|
||||
}
|
||||
|
||||
void esp_blufi_disconnect(void)
|
||||
{
|
||||
ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM);
|
||||
}
|
||||
|
||||
void esp_blufi_adv_stop(void) {}
|
||||
|
||||
void esp_blufi_send_encap(void *arg)
|
||||
{
|
||||
struct blufi_hdr *hdr = (struct blufi_hdr *)arg;
|
||||
if (blufi_env.is_connected == false) {
|
||||
BTC_TRACE_WARNING("%s ble connection is broken\n", __func__);
|
||||
osi_free(hdr);
|
||||
hdr = NULL;
|
||||
return;
|
||||
}
|
||||
btc_blufi_send_notify((uint8_t *)hdr,
|
||||
((hdr->fc & BLUFI_FC_CHECK) ?
|
||||
hdr->data_len + sizeof(struct blufi_hdr) + 2 :
|
||||
hdr->data_len + sizeof(struct blufi_hdr)));
|
||||
}
|
||||
|
||||
void esp_blufi_btc_init(void)
|
||||
{
|
||||
int rc;
|
||||
rc = btc_init();
|
||||
assert(rc == 0);
|
||||
}
|
||||
|
||||
#endif
|
@ -15,9 +15,47 @@
|
||||
#ifndef __BTC_BLUFI_PRF_H__
|
||||
#define __BTC_BLUFI_PRF_H__
|
||||
|
||||
#include "common/bt_target.h"
|
||||
#include "blufi_int.h"
|
||||
#include "btc/btc_task.h"
|
||||
#include "esp_blufi_api.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef CONFIG_BT_BLUEDROID_ENABLED
|
||||
#include "stack/gatt_api.h"
|
||||
#define ESP_BLUFI_ERROR GATT_ERROR
|
||||
#define ESP_BLUFI_SUCCESS GATT_SUCCESS
|
||||
#else
|
||||
#define ESP_BLUFI_ERROR 0x85
|
||||
#define ESP_BLUFI_SUCCESS 0x00
|
||||
#endif
|
||||
|
||||
#define BT_BD_ADDR_STR "%02x:%02x:%02x:%02x:%02x:%02x"
|
||||
#define BT_BD_ADDR_HEX(addr) addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]
|
||||
|
||||
#define GATT_UUID_CHAR_CLIENT_CONFIG 0x2902 /* Client Characteristic Configuration */
|
||||
//define the blufi serivce uuid
|
||||
#define BLUFI_SERVICE_UUID 0xFFFF
|
||||
//define the blufi Char uuid (PHONE to ESP32)
|
||||
#define BLUFI_CHAR_P2E_UUID 0xFF01
|
||||
//define the blufi Char uuid (ESP32 to PHONE)
|
||||
#define BLUFI_CHAR_E2P_UUID 0xFF02
|
||||
//define the blufi Descriptor uuid (ESP32 to PHONE)
|
||||
#define BLUFI_DESCR_E2P_UUID GATT_UUID_CHAR_CLIENT_CONFIG
|
||||
//define the blufi APP ID
|
||||
#define BLUFI_APP_UUID 0xFFFF
|
||||
|
||||
#define BLUFI_HDL_NUM 6
|
||||
|
||||
struct pkt_info{
|
||||
uint8_t *pkt;
|
||||
int pkt_len;
|
||||
};
|
||||
|
||||
static const tBT_UUID blufi_srvc_uuid = {LEN_UUID_16, {BLUFI_SERVICE_UUID}};
|
||||
static const tBT_UUID blufi_char_uuid_p2e = {LEN_UUID_16, {BLUFI_CHAR_P2E_UUID}};
|
||||
static const tBT_UUID blufi_char_uuid_e2p = {LEN_UUID_16, {BLUFI_CHAR_E2P_UUID}};
|
||||
static const tBT_UUID blufi_descr_uuid_e2p = {LEN_UUID_16, {BLUFI_DESCR_E2P_UUID}};
|
||||
static const tBT_UUID blufi_app_uuid = {LEN_UUID_16, {BLUFI_APP_UUID}};
|
||||
|
||||
typedef enum {
|
||||
BTC_BLUFI_ACT_INIT = 0,
|
||||
@ -58,10 +96,13 @@ typedef union {
|
||||
} custom_data;
|
||||
} btc_blufi_args_t;
|
||||
|
||||
void btc_blufi_cb_to_app(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *param);
|
||||
void btc_blufi_cb_handler(btc_msg_t *msg);
|
||||
void btc_blufi_call_handler(btc_msg_t *msg);
|
||||
void btc_blufi_set_callbacks(esp_blufi_callbacks_t *callbacks);
|
||||
|
||||
void btc_blufi_recv_handler(uint8_t *data, int len);
|
||||
void btc_blufi_send_notify(uint8_t *pkt, int pkt_len);
|
||||
void btc_blufi_call_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);
|
||||
void btc_blufi_call_deep_free(btc_msg_t *msg);
|
||||
|
@ -27,12 +27,31 @@
|
||||
#define TRUE true
|
||||
#endif
|
||||
|
||||
|
||||
#if (UC_BT_BLUFI_ENABLE)
|
||||
#define BLUFI_INCLUDED TRUE
|
||||
#else
|
||||
#define BLUFI_INCLUDED FALSE
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_BLUEDROID_ENABLED
|
||||
#include "esp_bt_defs.h"
|
||||
#include "esp_bt_main.h"
|
||||
#include "esp_gatt_defs.h"
|
||||
#define ESP_BLE_HOST_STATUS_ENABLED ESP_BLUEDROID_STATUS_ENABLED
|
||||
#define ESP_BLE_HOST_STATUS_CHECK(status) ESP_BLUEDROID_STATUS_CHECK(status)
|
||||
#else
|
||||
#define ESP_BLE_HOST_STATUS_ENABLED 0
|
||||
#define ESP_BLE_HOST_STATUS_CHECK(status) do {} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef BT_QUEUE_CONGEST_SIZE
|
||||
#define BT_QUEUE_CONGEST_SIZE 40
|
||||
#endif
|
||||
|
||||
#define BTC_INITIAL_TRACE_LEVEL UC_BT_LOG_BTC_TRACE_LEVEL
|
||||
#define OSI_INITIAL_TRACE_LEVEL UC_BT_LOG_OSI_TRACE_LEVEL
|
||||
#define BLUFI_INITIAL_TRACE_LEVEL UC_BT_LOG_BLUFI_TRACE_LEVEL
|
||||
|
||||
#if UC_BT_BLE_DYNAMIC_ENV_MEMORY
|
||||
#define BT_BLE_DYNAMIC_ENV_MEMORY TRUE
|
||||
@ -109,6 +128,14 @@
|
||||
#define OSI_TRACE_DEBUG(fmt, args...) {if (OSI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_DEBUG && BT_LOG_LEVEL_CHECK(OSI,DEBUG)) BT_PRINT_D("BT_OSI", fmt, ## args);}
|
||||
#define OSI_TRACE_VERBOSE(fmt, args...) {if (OSI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_VERBOSE && BT_LOG_LEVEL_CHECK(OSI,VERBOSE)) BT_PRINT_V("BT_OSI", fmt, ## args);}
|
||||
|
||||
/* define traces for BLUFI */
|
||||
#define BLUFI_TRACE_ERROR(fmt, args...) {if (BLUFI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_ERROR && BT_LOG_LEVEL_CHECK(BLUFI, ERROR)) BT_PRINT_E("BT_BLUFI", fmt, ## args);}
|
||||
#define BLUFI_TRACE_WARNING(fmt, args...) {if (BLUFI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_WARNING && BT_LOG_LEVEL_CHECK(BLUFI, WARNING)) BT_PRINT_W("BT_BLUFI", fmt, ## args);}
|
||||
#define BLUFI_TRACE_API(fmt, args...) {if (BLUFI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_API && BT_LOG_LEVEL_CHECK(BLUFI,API)) BT_PRINT_I("BT_BLUFI", fmt, ## args);}
|
||||
#define BLUFI_TRACE_EVENT(fmt, args...) {if (BLUFI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_EVENT && BT_LOG_LEVEL_CHECK(BLUFI,EVENT)) BT_PRINT_D("BT_BLUFI", fmt, ## args);}
|
||||
#define BLUFI_TRACE_DEBUG(fmt, args...) {if (BLUFI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_DEBUG && BT_LOG_LEVEL_CHECK(BLUFI,DEBUG)) BT_PRINT_D("BT_BLUFI", fmt, ## args);}
|
||||
#define BLUFI_TRACE_VERBOSE(fmt, args...) {if (BLUFI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_VERBOSE && BT_LOG_LEVEL_CHECK(BLUFI,VERBOSE)) BT_PRINT_V("BT_BLUFI", fmt, ## args);}
|
||||
|
||||
#else
|
||||
|
||||
/* define traces for BTC */
|
||||
@ -127,6 +154,14 @@
|
||||
#define OSI_TRACE_DEBUG(fmt, args...)
|
||||
#define OSI_TRACE_VERBOSE(fmt, args...)
|
||||
|
||||
/* define traces for BLUFI */
|
||||
#define BLUFI_TRACE_ERROR(fmt, args...)
|
||||
#define BLUFI_TRACE_WARNING(fmt, args...)
|
||||
#define BLUFI_TRACE_API(fmt, args...)
|
||||
#define BLUFI_TRACE_EVENT(fmt, args...)
|
||||
#define BLUFI_TRACE_DEBUG(fmt, args...)
|
||||
#define BLUFI_TRACE_VERBOSE(fmt, args...)
|
||||
|
||||
#endif
|
||||
|
||||
/** Bluetooth Error Status */
|
||||
@ -155,4 +190,31 @@ typedef enum {
|
||||
BT_STATUS_EIR_TOO_LARGE,
|
||||
} bt_status_t;
|
||||
|
||||
typedef uint8_t UINT8;
|
||||
typedef uint16_t UINT16;
|
||||
typedef uint32_t UINT32;
|
||||
typedef uint64_t UINT64;
|
||||
typedef bool BOOLEAN;
|
||||
/* Maximum UUID size - 16 bytes, and structure to hold any type of UUID. */
|
||||
#define MAX_UUID_SIZE 16
|
||||
|
||||
typedef struct {
|
||||
#define LEN_UUID_16 2
|
||||
#define LEN_UUID_32 4
|
||||
#define LEN_UUID_128 16
|
||||
|
||||
UINT16 len;
|
||||
|
||||
union {
|
||||
UINT16 uuid16;
|
||||
UINT32 uuid32;
|
||||
UINT8 uuid128[MAX_UUID_SIZE];
|
||||
} uu;
|
||||
|
||||
} tBT_UUID;
|
||||
|
||||
/* Common Bluetooth field definitions */
|
||||
#define BD_ADDR_LEN 6 /* Device address length */
|
||||
typedef UINT8 BD_ADDR[BD_ADDR_LEN]; /* Device address */
|
||||
|
||||
#endif /* _BT_COMMON_H_ */
|
||||
|
@ -80,4 +80,17 @@
|
||||
#define UC_BT_LOG_OSI_TRACE_LEVEL UC_TRACE_LEVEL_WARNING
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_LOG_BLUFI_TRACE_LEVEL
|
||||
#define UC_BT_LOG_BLUFI_TRACE_LEVEL CONFIG_BT_LOG_BLUFI_TRACE_LEVEL
|
||||
#else
|
||||
#define UC_BT_LOG_BLUFI_TRACE_LEVEL UC_TRACE_LEVEL_WARNING
|
||||
#endif
|
||||
|
||||
//BLUFI
|
||||
#if defined(CONFIG_BT_BLE_BLUFI_ENABLE) || defined(CONFIG_BT_NIMBLE_BLUFI_ENABLE)
|
||||
#define UC_BT_BLUFI_ENABLE TRUE
|
||||
#else
|
||||
#define UC_BT_BLUFI_ENABLE FALSE
|
||||
#endif
|
||||
|
||||
#endif /* __BT_USER_CONFIG_H__ */
|
||||
|
@ -9,13 +9,13 @@ COMPONENT_ADD_INCLUDEDIRS := include
|
||||
|
||||
LIBS := btdm_app
|
||||
|
||||
COMPONENT_ADD_LDFLAGS := -lbt -L $(COMPONENT_PATH)/controller/lib/esp32 \
|
||||
COMPONENT_ADD_LDFLAGS := -lbt -L $(COMPONENT_PATH)/controller/lib_esp32/esp32 \
|
||||
$(addprefix -l,$(LIBS))
|
||||
|
||||
# re-link program if BT binary libs change
|
||||
COMPONENT_ADD_LINKER_DEPS := $(patsubst %,$(COMPONENT_PATH)/controller/lib/esp32/lib%.a,$(LIBS))
|
||||
COMPONENT_ADD_LINKER_DEPS := $(patsubst %,$(COMPONENT_PATH)/controller/lib_esp32/esp32/lib%.a,$(LIBS))
|
||||
|
||||
COMPONENT_SUBMODULES += controller/lib
|
||||
COMPONENT_SUBMODULES += controller/lib_esp32
|
||||
|
||||
|
||||
# TODO: annotate fallthroughs in Bluedroid code with comments
|
||||
@ -24,6 +24,18 @@ CFLAGS += -Wno-implicit-fallthrough
|
||||
COMPONENT_ADD_INCLUDEDIRS += include/esp32/include
|
||||
COMPONENT_SRCDIRS += controller/esp32
|
||||
|
||||
COMPONENT_PRIV_INCLUDEDIRS += common/btc/include \
|
||||
common/include
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS += common/api/include/api \
|
||||
common/btc/profile/esp/blufi/include \
|
||||
common/btc/profile/esp/include \
|
||||
common/osi/include
|
||||
COMPONENT_SRCDIRS += common/api \
|
||||
common/btc/core \
|
||||
common/osi \
|
||||
common/btc/profile/esp/blufi
|
||||
|
||||
ifdef CONFIG_BT_BLUEDROID_ENABLED
|
||||
|
||||
COMPONENT_PRIV_INCLUDEDIRS += host/bluedroid/bta/include \
|
||||
@ -44,7 +56,6 @@ COMPONENT_PRIV_INCLUDEDIRS += host/bluedroid/bta/include \
|
||||
host/bluedroid/external/sbc/decoder/include \
|
||||
host/bluedroid/external/sbc/encoder/include \
|
||||
host/bluedroid/external/sbc/plc/include \
|
||||
host/bluedroid/btc/profile/esp/blufi/include \
|
||||
host/bluedroid/btc/profile/esp/include \
|
||||
host/bluedroid/btc/profile/std/gatt/include \
|
||||
host/bluedroid/btc/profile/std/gap/include \
|
||||
@ -71,7 +82,6 @@ COMPONENT_PRIV_INCLUDEDIRS += host/bluedroid/bta/include \
|
||||
host/bluedroid/common/include \
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS += host/bluedroid/api/include/api \
|
||||
common/osi/include
|
||||
|
||||
COMPONENT_SRCDIRS += host/bluedroid/bta/dm \
|
||||
host/bluedroid/bta/gatt \
|
||||
@ -93,7 +103,6 @@ COMPONENT_SRCDIRS += host/bluedroid/bta/dm \
|
||||
host/bluedroid/external/sbc/encoder/srce \
|
||||
host/bluedroid/external/sbc/plc \
|
||||
host/bluedroid/btc/core \
|
||||
host/bluedroid/btc/profile/esp/blufi \
|
||||
host/bluedroid/btc/profile/std/gap \
|
||||
host/bluedroid/btc/profile/std/gatt \
|
||||
host/bluedroid/btc/profile/std/a2dp \
|
||||
@ -128,11 +137,7 @@ host/bluedroid/btc/core/btc_config.o: CFLAGS += -Wno-unused-const-variable
|
||||
host/bluedroid/stack/btm/btm_sec.o: CFLAGS += -Wno-unused-const-variable
|
||||
host/bluedroid/stack/smp/smp_keys.o: CFLAGS += -Wno-unused-const-variable
|
||||
|
||||
COMPONENT_PRIV_INCLUDEDIRS += common/btc/include \
|
||||
common/include
|
||||
|
||||
COMPONENT_SRCDIRS += common/osi \
|
||||
common/btc/core \
|
||||
COMPONENT_SRCDIRS += common/btc/profile/esp/blufi/bluedroid_host
|
||||
|
||||
ifdef CONFIG_BLE_MESH
|
||||
|
||||
@ -218,14 +223,9 @@ endif
|
||||
COMPONENT_OBJEXCLUDE += host/nimble/nimble/nimble/host/store/config/src/ble_store_config_conf.o
|
||||
|
||||
ifdef CONFIG_BLE_MESH
|
||||
COMPONENT_PRIV_INCLUDEDIRS += common/btc/include \
|
||||
common/include
|
||||
|
||||
COMPONENT_SRCDIRS += common/osi \
|
||||
common/btc/core \
|
||||
esp_ble_mesh/mesh_core/nimble_host
|
||||
COMPONENT_SRCDIRS += esp_ble_mesh/mesh_core/nimble_host
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS += common/osi/include
|
||||
endif
|
||||
|
||||
ifdef CONFIG_BT_NIMBLE_MESH
|
||||
@ -234,6 +234,7 @@ COMPONENT_ADD_INCLUDEDIRS += host/nimble/nimble/nimble/host/mesh/include
|
||||
COMPONENT_SRCDIRS += host/nimble/nimble/nimble/host/mesh/src
|
||||
|
||||
endif
|
||||
COMPONENT_SRCDIRS += common/btc/profile/esp/blufi/nimble_host
|
||||
endif
|
||||
|
||||
endif
|
||||
|
@ -415,18 +415,3 @@ config BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD
|
||||
of ADV packets lost in the controller reaches this threshold. It is better to set a larger value.
|
||||
If you set `BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD` to a small value or printf every adv lost event, it
|
||||
may cause adv packets lost more.
|
||||
|
||||
menuconfig BTDM_COEX_BT_OPTIONS
|
||||
bool "Coexistence Bluetooth Side Options"
|
||||
depends on ESP32_WIFI_SW_COEXIST_ENABLE
|
||||
default n
|
||||
help
|
||||
Options of Bluetooth Side of WiFi and bluetooth coexistence.
|
||||
|
||||
config BTDM_COEX_BLE_ADV_HIGH_PRIORITY
|
||||
bool "Improve BLE ADV priority for WiFi & BLE coexistence"
|
||||
depends on BTDM_COEX_BT_OPTIONS
|
||||
default n
|
||||
help
|
||||
Improve BLE ADV coexistence priority to make it better performance.
|
||||
For example, BLE mesh need to enable this option to improve BLE adv performance.
|
||||
|
@ -176,6 +176,14 @@ struct osi_funcs_t {
|
||||
int (* _coex_register_bt_cb)(coex_func_cb_t cb);
|
||||
uint32_t (* _coex_bb_reset_lock)(void);
|
||||
void (* _coex_bb_reset_unlock)(uint32_t restore);
|
||||
int (* _coex_schm_register_btdm_callback)(void *callback);
|
||||
void (* _coex_schm_status_bit_clear)(uint32_t type, uint32_t status);
|
||||
void (* _coex_schm_status_bit_set)(uint32_t type, uint32_t status);
|
||||
uint32_t (* _coex_schm_interval_get)(void);
|
||||
uint8_t (* _coex_schm_curr_period_get)(void);
|
||||
void *(* _coex_schm_curr_phase_get)(void);
|
||||
int (* _coex_wifi_channel_get)(uint8_t *primary, uint8_t *secondary);
|
||||
int (* _coex_register_wifi_channel_change_callback)(void *cb);
|
||||
uint32_t _magic;
|
||||
};
|
||||
|
||||
@ -224,7 +232,14 @@ extern int coex_bt_release(uint32_t event);
|
||||
extern int coex_register_bt_cb(coex_func_cb_t cb);
|
||||
extern uint32_t coex_bb_reset_lock(void);
|
||||
extern void coex_bb_reset_unlock(uint32_t restore);
|
||||
extern void coex_ble_adv_priority_high_set(bool high);
|
||||
extern int coex_schm_register_btdm_callback(void *callback);
|
||||
extern void coex_schm_status_bit_clear(uint32_t type, uint32_t status);
|
||||
extern void coex_schm_status_bit_set(uint32_t type, uint32_t status);
|
||||
extern uint32_t coex_schm_interval_get(void);
|
||||
extern uint8_t coex_schm_curr_period_get(void);
|
||||
extern void * coex_schm_curr_phase_get(void);
|
||||
extern int coex_wifi_channel_get(uint8_t *primary, uint8_t *secondary);
|
||||
extern int coex_register_wifi_channel_change_callback(void *cb);
|
||||
|
||||
extern char _bss_start_btdm;
|
||||
extern char _bss_end_btdm;
|
||||
@ -294,7 +309,14 @@ static int coex_bt_release_wrapper(uint32_t event);
|
||||
static int coex_register_bt_cb_wrapper(coex_func_cb_t cb);
|
||||
static uint32_t coex_bb_reset_lock_wrapper(void);
|
||||
static void coex_bb_reset_unlock_wrapper(uint32_t restore);
|
||||
|
||||
static int coex_schm_register_btdm_callback_wrapper(void *callback);
|
||||
static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status);
|
||||
static void coex_schm_status_bit_set_wrapper(uint32_t type, uint32_t status);
|
||||
static uint32_t coex_schm_interval_get_wrapper(void);
|
||||
static uint8_t coex_schm_curr_period_get_wrapper(void);
|
||||
static void * coex_schm_curr_phase_get_wrapper(void);
|
||||
static int coex_wifi_channel_get_wrapper(uint8_t *primary, uint8_t *secondary);
|
||||
static int coex_register_wifi_channel_change_callback_wrapper(void *cb);
|
||||
/* Local variable definition
|
||||
***************************************************************************
|
||||
*/
|
||||
@ -348,6 +370,14 @@ static const struct osi_funcs_t osi_funcs_ro = {
|
||||
._coex_register_bt_cb = coex_register_bt_cb_wrapper,
|
||||
._coex_bb_reset_lock = coex_bb_reset_lock_wrapper,
|
||||
._coex_bb_reset_unlock = coex_bb_reset_unlock_wrapper,
|
||||
._coex_schm_register_btdm_callback = coex_schm_register_btdm_callback_wrapper,
|
||||
._coex_schm_status_bit_clear = coex_schm_status_bit_clear_wrapper,
|
||||
._coex_schm_status_bit_set = coex_schm_status_bit_set_wrapper,
|
||||
._coex_schm_interval_get = coex_schm_interval_get_wrapper,
|
||||
._coex_schm_curr_period_get = coex_schm_curr_period_get_wrapper,
|
||||
._coex_schm_curr_phase_get = coex_schm_curr_phase_get_wrapper,
|
||||
._coex_wifi_channel_get = coex_wifi_channel_get_wrapper,
|
||||
._coex_register_wifi_channel_change_callback = coex_register_wifi_channel_change_callback_wrapper,
|
||||
._magic = OSI_MAGIC_VALUE,
|
||||
};
|
||||
|
||||
@ -1001,7 +1031,7 @@ static void coex_bt_wakeup_request_end(void)
|
||||
return;
|
||||
}
|
||||
|
||||
int IRAM_ATTR coex_bt_request_wrapper(uint32_t event, uint32_t latency, uint32_t duration)
|
||||
static int IRAM_ATTR coex_bt_request_wrapper(uint32_t event, uint32_t latency, uint32_t duration)
|
||||
{
|
||||
#if CONFIG_SW_COEXIST_ENABLE
|
||||
return coex_bt_request(event, latency, duration);
|
||||
@ -1010,7 +1040,7 @@ int IRAM_ATTR coex_bt_request_wrapper(uint32_t event, uint32_t latency, uint32_t
|
||||
#endif
|
||||
}
|
||||
|
||||
int IRAM_ATTR coex_bt_release_wrapper(uint32_t event)
|
||||
static int IRAM_ATTR coex_bt_release_wrapper(uint32_t event)
|
||||
{
|
||||
#if CONFIG_SW_COEXIST_ENABLE
|
||||
return coex_bt_release(event);
|
||||
@ -1019,7 +1049,7 @@ int IRAM_ATTR coex_bt_release_wrapper(uint32_t event)
|
||||
#endif
|
||||
}
|
||||
|
||||
int coex_register_bt_cb_wrapper(coex_func_cb_t cb)
|
||||
static int coex_register_bt_cb_wrapper(coex_func_cb_t cb)
|
||||
{
|
||||
#if CONFIG_SW_COEXIST_ENABLE
|
||||
return coex_register_bt_cb(cb);
|
||||
@ -1028,7 +1058,7 @@ int coex_register_bt_cb_wrapper(coex_func_cb_t cb)
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t IRAM_ATTR coex_bb_reset_lock_wrapper(void)
|
||||
static uint32_t IRAM_ATTR coex_bb_reset_lock_wrapper(void)
|
||||
{
|
||||
#if CONFIG_SW_COEXIST_ENABLE
|
||||
return coex_bb_reset_lock();
|
||||
@ -1037,13 +1067,81 @@ uint32_t IRAM_ATTR coex_bb_reset_lock_wrapper(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
void IRAM_ATTR coex_bb_reset_unlock_wrapper(uint32_t restore)
|
||||
static void IRAM_ATTR coex_bb_reset_unlock_wrapper(uint32_t restore)
|
||||
{
|
||||
#if CONFIG_SW_COEXIST_ENABLE
|
||||
coex_bb_reset_unlock(restore);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int coex_schm_register_btdm_callback_wrapper(void *callback)
|
||||
{
|
||||
#if CONFIG_SW_COEXIST_ENABLE
|
||||
return coex_schm_register_btdm_callback(callback);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status)
|
||||
{
|
||||
#if CONFIG_SW_COEXIST_ENABLE
|
||||
coex_schm_status_bit_clear(type, status);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void coex_schm_status_bit_set_wrapper(uint32_t type, uint32_t status)
|
||||
{
|
||||
#if CONFIG_SW_COEXIST_ENABLE
|
||||
coex_schm_status_bit_set(type, status);
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint32_t coex_schm_interval_get_wrapper(void)
|
||||
{
|
||||
#if CONFIG_SW_COEXIST_ENABLE
|
||||
return coex_schm_interval_get();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint8_t coex_schm_curr_period_get_wrapper(void)
|
||||
{
|
||||
#if CONFIG_SW_COEXIST_ENABLE
|
||||
return coex_schm_curr_period_get();
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void * coex_schm_curr_phase_get_wrapper(void)
|
||||
{
|
||||
#if CONFIG_SW_COEXIST_ENABLE
|
||||
return coex_schm_curr_phase_get();
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int coex_wifi_channel_get_wrapper(uint8_t *primary, uint8_t *secondary)
|
||||
{
|
||||
#if CONFIG_SW_COEXIST_ENABLE
|
||||
return coex_wifi_channel_get(primary, secondary);
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int coex_register_wifi_channel_change_callback_wrapper(void *cb)
|
||||
{
|
||||
#if CONFIG_SW_COEXIST_ENABLE
|
||||
return coex_register_wifi_channel_change_callback(cb);
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool esp_vhci_host_check_send_available(void)
|
||||
{
|
||||
return API_vhci_host_check_send_available();
|
||||
@ -1296,7 +1394,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
|
||||
#if CONFIG_BTDM_CTRL_LPCLK_SEL_EXT_32K_XTAL
|
||||
// check whether or not EXT_CRYS is working
|
||||
if (rtc_clk_slow_freq_get() == RTC_SLOW_FREQ_32K_XTAL) {
|
||||
btdm_lpclk_sel = BTDM_LPCLK_SEL_XTAL32K; // set default value
|
||||
btdm_lpclk_sel = BTDM_LPCLK_SEL_XTAL32K; // External 32kHz XTAL
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
s_btdm_allow_light_sleep = true;
|
||||
#endif
|
||||
@ -1365,12 +1463,6 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
|
||||
goto error;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BTDM_COEX_BLE_ADV_HIGH_PRIORITY
|
||||
coex_ble_adv_priority_high_set(true);
|
||||
#else
|
||||
coex_ble_adv_priority_high_set(false);
|
||||
#endif
|
||||
|
||||
btdm_controller_status = ESP_BT_CONTROLLER_STATUS_INITED;
|
||||
|
||||
return ESP_OK;
|
||||
@ -1442,16 +1534,12 @@ esp_err_t esp_bt_controller_deinit(void)
|
||||
static void bt_shutdown(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
ESP_LOGD(BTDM_LOG_TAG, "stop/deinit bt");
|
||||
ESP_LOGD(BTDM_LOG_TAG, "stop Bluetooth");
|
||||
|
||||
ret = esp_bt_controller_disable();
|
||||
if (ESP_OK != ret) {
|
||||
ESP_LOGW(BTDM_LOG_TAG, "controller disable ret=%d", ret);
|
||||
}
|
||||
ret = esp_bt_controller_deinit();
|
||||
if (ESP_OK != ret) {
|
||||
ESP_LOGW(BTDM_LOG_TAG, "controller deinit ret=%d", ret);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,8 @@ config BT_CTRL_BLE_MAX_ACT
|
||||
default 10
|
||||
range 1 10
|
||||
help
|
||||
BLE maximum instances of bluetooth controller.
|
||||
BLE maximum activities of bluetooth controller,both of connections,
|
||||
scan , sync and adv(periodic adv, multi-adv).
|
||||
|
||||
config BT_CTRL_BLE_MAX_ACT_EFF
|
||||
int
|
||||
@ -126,10 +127,20 @@ config BT_CTRL_RX_ANTENNA_INDEX_EFF
|
||||
|
||||
choice BT_CTRL_DFT_TX_POWER_LEVEL
|
||||
prompt "BLE default Tx power level"
|
||||
default BT_CTRL_DFT_TX_POWER_LEVEL_P9
|
||||
default BT_CTRL_DFT_TX_POWER_LEVEL_P3
|
||||
help
|
||||
Specify default Tx power level
|
||||
|
||||
config BT_CTRL_DFT_TX_POWER_LEVEL_N27
|
||||
bool "-27dBm"
|
||||
config BT_CTRL_DFT_TX_POWER_LEVEL_N24
|
||||
bool "-24dBm"
|
||||
config BT_CTRL_DFT_TX_POWER_LEVEL_N21
|
||||
bool "-21dBm"
|
||||
config BT_CTRL_DFT_TX_POWER_LEVEL_N18
|
||||
bool "-18dBm"
|
||||
config BT_CTRL_DFT_TX_POWER_LEVEL_N15
|
||||
bool "-15dBm"
|
||||
config BT_CTRL_DFT_TX_POWER_LEVEL_N12
|
||||
bool "-12dBm"
|
||||
config BT_CTRL_DFT_TX_POWER_LEVEL_N9
|
||||
@ -146,18 +157,32 @@ choice BT_CTRL_DFT_TX_POWER_LEVEL
|
||||
bool "+6dBm"
|
||||
config BT_CTRL_DFT_TX_POWER_LEVEL_P9
|
||||
bool "+9dBm"
|
||||
config BT_CTRL_DFT_TX_POWER_LEVEL_P12
|
||||
bool "+12dBm"
|
||||
config BT_CTRL_DFT_TX_POWER_LEVEL_P15
|
||||
bool "+15dBm"
|
||||
config BT_CTRL_DFT_TX_POWER_LEVEL_P18
|
||||
bool "+18dBm"
|
||||
endchoice
|
||||
|
||||
config BT_CTRL_DFT_TX_POWER_LEVEL_EFF
|
||||
int
|
||||
default 0 if BT_CTRL_DFT_TX_POWER_LEVEL_N12
|
||||
default 1 if BT_CTRL_DFT_TX_POWER_LEVEL_N9
|
||||
default 2 if BT_CTRL_DFT_TX_POWER_LEVEL_N6
|
||||
default 3 if BT_CTRL_DFT_TX_POWER_LEVEL_N3
|
||||
default 4 if BT_CTRL_DFT_TX_POWER_LEVEL_N0
|
||||
default 5 if BT_CTRL_DFT_TX_POWER_LEVEL_P3
|
||||
default 6 if BT_CTRL_DFT_TX_POWER_LEVEL_P6
|
||||
default 7 if BT_CTRL_DFT_TX_POWER_LEVEL_P9
|
||||
default 0 if BT_CTRL_DFT_TX_POWER_LEVEL_N27
|
||||
default 1 if BT_CTRL_DFT_TX_POWER_LEVEL_N24
|
||||
default 2 if BT_CTRL_DFT_TX_POWER_LEVEL_N21
|
||||
default 3 if BT_CTRL_DFT_TX_POWER_LEVEL_N18
|
||||
default 4 if BT_CTRL_DFT_TX_POWER_LEVEL_N15
|
||||
default 5 if BT_CTRL_DFT_TX_POWER_LEVEL_N12
|
||||
default 6 if BT_CTRL_DFT_TX_POWER_LEVEL_N9
|
||||
default 7 if BT_CTRL_DFT_TX_POWER_LEVEL_N6
|
||||
default 8 if BT_CTRL_DFT_TX_POWER_LEVEL_N3
|
||||
default 9 if BT_CTRL_DFT_TX_POWER_LEVEL_N0
|
||||
default 10 if BT_CTRL_DFT_TX_POWER_LEVEL_P3
|
||||
default 11 if BT_CTRL_DFT_TX_POWER_LEVEL_P6
|
||||
default 12 if BT_CTRL_DFT_TX_POWER_LEVEL_P9
|
||||
default 13 if BT_CTRL_DFT_TX_POWER_LEVEL_P12
|
||||
default 14 if BT_CTRL_DFT_TX_POWER_LEVEL_P15
|
||||
default 15 if BT_CTRL_DFT_TX_POWER_LEVEL_P18
|
||||
default 0
|
||||
|
||||
config BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_SUPP
|
||||
@ -334,7 +359,8 @@ menu "MODEM SLEEP Options"
|
||||
bool "Internal 150kHz RC oscillator"
|
||||
depends on ESP32C3_RTC_CLK_SRC_INT_RC
|
||||
help
|
||||
Internal 150kHz RC oscillator.
|
||||
Internal 150kHz RC oscillator. The accuracy of this clock is a lot larger than 500ppm which is required
|
||||
in Bluetooth communication, so don't select this option in scenarios such as BLE connection state.
|
||||
|
||||
|
||||
endchoice
|
||||
@ -358,3 +384,16 @@ config BT_CTRL_HCI_TL_EFF
|
||||
default 0 if BT_CTRL_HCI_MODE_UART_H4
|
||||
default 1 if BT_CTRL_HCI_M0DE_VHCI
|
||||
default 1
|
||||
|
||||
config BT_CTRL_AGC_RECORRECT_EN
|
||||
bool "Enable HW AGC recorrect"
|
||||
default n
|
||||
help
|
||||
Enable uncoded phy AGC recorrect
|
||||
|
||||
config BT_CTRL_CODED_AGC_RECORRECT_EN
|
||||
bool "Enable coded phy AGC recorrect"
|
||||
depends on BT_CTRL_AGC_RECORRECT_EN
|
||||
default n
|
||||
help
|
||||
Enable coded phy AGC recorrect
|
||||
|
@ -212,6 +212,7 @@ extern void btdm_controller_disable(void);
|
||||
extern uint8_t btdm_controller_get_mode(void);
|
||||
extern const char *btdm_controller_get_compile_version(void);
|
||||
extern void btdm_rf_bb_init_phase2(void); // shall be called after PHY/RF is enabled
|
||||
|
||||
/* Sleep */
|
||||
extern void btdm_controller_enable_sleep(bool enable);
|
||||
extern uint8_t btdm_controller_get_sleep_mode(void);
|
||||
@ -709,10 +710,6 @@ static void btdm_sleep_exit_phase3_wrapper(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
if(btdm_sleep_clock_sync()) {
|
||||
ESP_LOGE(BTDM_LOG_TAG, "sleep eco state err\n");
|
||||
assert(0);
|
||||
}
|
||||
if (btdm_controller_get_sleep_mode() == ESP_BT_SLEEP_MODE_1) {
|
||||
if (s_lp_stat.phy_enabled == 0) {
|
||||
esp_phy_enable();
|
||||
@ -727,6 +724,12 @@ static void btdm_sleep_exit_phase3_wrapper(void)
|
||||
esp_timer_stop(s_btdm_slp_tmr);
|
||||
s_lp_stat.wakeup_timer_started = 0;
|
||||
}
|
||||
|
||||
// wait for the sleep state to change
|
||||
// the procedure duration is at micro-second level or less
|
||||
while (btdm_sleep_clock_sync()) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
static void IRAM_ATTR btdm_sleep_exit_phase0(void *param)
|
||||
@ -740,13 +743,16 @@ static void IRAM_ATTR btdm_sleep_exit_phase0(void *param)
|
||||
}
|
||||
#endif
|
||||
|
||||
btdm_wakeup_request();
|
||||
int event = (int) param;
|
||||
if (event == BTDM_ASYNC_WAKEUP_SRC_VHCI || event == BTDM_ASYNC_WAKEUP_SRC_DISA) {
|
||||
btdm_wakeup_request();
|
||||
}
|
||||
|
||||
if (s_lp_cntl.wakeup_timer_required && s_lp_stat.wakeup_timer_started) {
|
||||
esp_timer_stop(s_btdm_slp_tmr);
|
||||
s_lp_stat.wakeup_timer_started = 0;
|
||||
}
|
||||
int event = (int) param;
|
||||
|
||||
if (event == BTDM_ASYNC_WAKEUP_SRC_VHCI || event == BTDM_ASYNC_WAKEUP_SRC_DISA) {
|
||||
semphr_give_wrapper(s_wakeup_req_sem);
|
||||
}
|
||||
@ -986,7 +992,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
|
||||
|
||||
// configure and initialize resources
|
||||
s_lp_cntl.enable = (cfg->sleep_mode == ESP_BT_SLEEP_MODE_1) ? 1 : 0;
|
||||
s_lp_cntl.no_light_sleep = 0;
|
||||
s_lp_cntl.no_light_sleep = 1;
|
||||
|
||||
if (s_lp_cntl.enable) {
|
||||
#if (CONFIG_MAC_BB_PD)
|
||||
@ -1023,31 +1029,29 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
|
||||
btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT;
|
||||
btdm_lpcycle_us = 2 << (btdm_lpcycle_us_frac);
|
||||
|
||||
// // set default bluetooth sleep clock source
|
||||
// s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL;
|
||||
// set default bluetooth sleep clock source
|
||||
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value
|
||||
#if CONFIG_BT_CTRL_LPCLK_SEL_EXT_32K_XTAL
|
||||
// check whether or not EXT_CRYS is working
|
||||
if (rtc_clk_slow_freq_get() == RTC_SLOW_FREQ_32K_XTAL) {
|
||||
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL32K; // set default value
|
||||
// #ifdef CONFIG_PM_ENABLE
|
||||
// s_btdm_allow_light_sleep = true;
|
||||
// #endif
|
||||
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL32K; // External 32 kHz XTAL
|
||||
s_lp_cntl.no_light_sleep = 0;
|
||||
} else {
|
||||
ESP_LOGW(BTDM_LOG_TAG, "32.768kHz XTAL not detected, fall back to main XTAL as Bluetooth sleep clock\n"
|
||||
"light sleep mode will not be able to apply when bluetooth is enabled");
|
||||
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value
|
||||
}
|
||||
#elif (CONFIG_BT_CTRL_LPCLK_SEL_RTC_SLOW)
|
||||
// check whether or not EXT_CRYS is working
|
||||
if (rtc_clk_slow_freq_get() == RTC_SLOW_FREQ_RTC) {
|
||||
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_RTC_SLOW; // set default value
|
||||
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_RTC_SLOW; // Internal 150 kHz RC oscillator
|
||||
ESP_LOGW(BTDM_LOG_TAG, "Internal 150kHz RC osciallator. The accuracy of this clock is a lot larger than 500ppm which is "
|
||||
"required in Bluetooth communication, so don't select this option in scenarios such as BLE connection state.");
|
||||
} else {
|
||||
ESP_LOGW(BTDM_LOG_TAG, "Internal 150kHz RC oscillator not detected, fall back to main XTAL as Bluetooth sleep clock\n"
|
||||
"light sleep mode will not be able to apply when bluetooth is enabled");
|
||||
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value
|
||||
ESP_LOGW(BT_LOG_TAG, "Internal 150kHz RC oscillator not detected.");
|
||||
assert(0);
|
||||
}
|
||||
#else
|
||||
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value
|
||||
s_lp_cntl.no_light_sleep = 1;
|
||||
#endif
|
||||
|
||||
bool select_src_ret, set_div_ret;
|
||||
@ -1331,14 +1335,51 @@ esp_bt_controller_status_t esp_bt_controller_get_status(void)
|
||||
/* extra functions */
|
||||
esp_err_t esp_ble_tx_power_set(esp_ble_power_type_t power_type, esp_power_level_t power_level)
|
||||
{
|
||||
ESP_LOGW(BTDM_LOG_TAG, "%s not implemented, return OK", __func__);
|
||||
return ESP_OK;
|
||||
esp_err_t stat = ESP_FAIL;
|
||||
|
||||
switch (power_type) {
|
||||
case ESP_BLE_PWR_TYPE_ADV:
|
||||
case ESP_BLE_PWR_TYPE_SCAN:
|
||||
case ESP_BLE_PWR_TYPE_DEFAULT:
|
||||
if (ble_txpwr_set(power_type, power_level) == 0) {
|
||||
stat = ESP_OK;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
stat = ESP_ERR_NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
return stat;
|
||||
}
|
||||
|
||||
esp_power_level_t esp_ble_tx_power_get(esp_ble_power_type_t power_type)
|
||||
{
|
||||
ESP_LOGW(BTDM_LOG_TAG, "%s not implemented, return 0", __func__);
|
||||
return 0;
|
||||
esp_power_level_t lvl;
|
||||
|
||||
switch (power_type) {
|
||||
case ESP_BLE_PWR_TYPE_ADV:
|
||||
case ESP_BLE_PWR_TYPE_SCAN:
|
||||
lvl = (esp_power_level_t)ble_txpwr_get(power_type);
|
||||
break;
|
||||
case ESP_BLE_PWR_TYPE_CONN_HDL0:
|
||||
case ESP_BLE_PWR_TYPE_CONN_HDL1:
|
||||
case ESP_BLE_PWR_TYPE_CONN_HDL2:
|
||||
case ESP_BLE_PWR_TYPE_CONN_HDL3:
|
||||
case ESP_BLE_PWR_TYPE_CONN_HDL4:
|
||||
case ESP_BLE_PWR_TYPE_CONN_HDL5:
|
||||
case ESP_BLE_PWR_TYPE_CONN_HDL6:
|
||||
case ESP_BLE_PWR_TYPE_CONN_HDL7:
|
||||
case ESP_BLE_PWR_TYPE_CONN_HDL8:
|
||||
case ESP_BLE_PWR_TYPE_DEFAULT:
|
||||
lvl = (esp_power_level_t)ble_txpwr_get(ESP_BLE_PWR_TYPE_DEFAULT);
|
||||
break;
|
||||
default:
|
||||
lvl = ESP_PWR_LVL_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
return lvl;
|
||||
}
|
||||
|
||||
esp_err_t esp_bt_sleep_enable (void)
|
||||
|
Submodule components/bt/controller/lib deleted from d1115cabc2
1
components/bt/controller/lib_esp32
Submodule
1
components/bt/controller/lib_esp32
Submodule
Submodule components/bt/controller/lib_esp32 added at fb49791b7c
1
components/bt/controller/lib_esp32c3_family
Submodule
1
components/bt/controller/lib_esp32c3_family
Submodule
Submodule components/bt/controller/lib_esp32c3_family added at 12f00c45ce
@ -33,20 +33,25 @@ if BLE_MESH
|
||||
behavior in ESP-IDF
|
||||
- Internal IRAM memory wherever applicable else internal DRAM
|
||||
|
||||
Recommended mode here is always internal, since that is most preferred
|
||||
from security perspective. But if application requirement does not allow
|
||||
sufficient free internal memory then alternate mode can be selected.
|
||||
Recommended mode here is always internal (*), since that is most preferred
|
||||
from security perspective. But if application requirement does not
|
||||
allow sufficient free internal memory then alternate mode can be
|
||||
selected.
|
||||
|
||||
(*) In case of ESP32-S2/ESP32-S3, hardware allows encryption of external
|
||||
SPIRAM contents provided hardware flash encryption feature is enabled.
|
||||
In that case, using external SPIRAM allocation strategy is also safe choice
|
||||
from security perspective.
|
||||
|
||||
config BLE_MESH_MEM_ALLOC_MODE_INTERNAL
|
||||
bool "Internal DRAM"
|
||||
|
||||
config BLE_MESH_MEM_ALLOC_MODE_EXTERNAL
|
||||
bool "External SPIRAM"
|
||||
depends on ESP32_SPIRAM_SUPPORT
|
||||
depends on SPIRAM_USE_CAPS_ALLOC || SPIRAM_USE_MALLOC
|
||||
|
||||
config BLE_MESH_MEM_ALLOC_MODE_DEFAULT
|
||||
bool "Default alloc mode"
|
||||
depends on ESP32_SPIRAM_SUPPORT
|
||||
help
|
||||
Enable this option to use the default memory allocation strategy when
|
||||
external SPIRAM is enabled. See the SPIRAM options for more details.
|
||||
@ -267,6 +272,19 @@ if BLE_MESH
|
||||
advertising bearer. This option should be enabled if PB-ADV is
|
||||
going to be used during provisioning procedure.
|
||||
|
||||
config BLE_MESH_UNPROVISIONED_BEACON_INTERVAL
|
||||
int "Interval between two consecutive Unprovisioned Device Beacon"
|
||||
depends on BLE_MESH_NODE && BLE_MESH_PB_ADV
|
||||
default 5
|
||||
default 3 if BLE_MESH_FAST_PROV
|
||||
range 1 100
|
||||
help
|
||||
This option specifies the interval of sending two consecutive unprovisioned
|
||||
device beacon, users can use this option to change the frequency of sending
|
||||
unprovisioned device beacon. For example, if the value is 5, it means the
|
||||
unprovisioned device beacon will send every 5 seconds. When the option of
|
||||
BLE_MESH_FAST_PROV is selected, the value is better to be 3 seconds, or less.
|
||||
|
||||
config BLE_MESH_PB_GATT
|
||||
bool "Provisioning support using GATT (PB-GATT)"
|
||||
select BLE_MESH_PROXY
|
||||
|
@ -69,6 +69,12 @@ esp_err_t esp_ble_mesh_node_prov_disable(esp_ble_mesh_prov_bearer_t bearers);
|
||||
/**
|
||||
* @brief Unprovisioned device set own oob public key & private key pair.
|
||||
*
|
||||
* @note In order to avoid suffering brute-forcing attack (CVE-2020-26559).
|
||||
* The Bluetooth SIG recommends that potentially vulnerable mesh provisioners
|
||||
* use an out-of-band mechanism to exchange the public keys.
|
||||
* So as an unprovisioned device, it should use this function to input
|
||||
* the Public Key exchanged through the out-of-band mechanism.
|
||||
*
|
||||
* @param[in] pub_key_x: Unprovisioned device's Public Key X
|
||||
* @param[in] pub_key_y: Unprovisioned device's Public Key Y
|
||||
* @param[in] private_key: Unprovisioned device's Private Key
|
||||
@ -121,6 +127,10 @@ esp_err_t esp_ble_mesh_set_unprovisioned_device_name(const char *name);
|
||||
/**
|
||||
* @brief Provisioner inputs unprovisioned device's oob public key.
|
||||
*
|
||||
* @note In order to avoid suffering brute-forcing attack (CVE-2020-26559).
|
||||
* The Bluetooth SIG recommends that potentially vulnerable mesh provisioners
|
||||
* use an out-of-band mechanism to exchange the public keys.
|
||||
*
|
||||
* @param[in] link_idx: The provisioning link index
|
||||
* @param[in] pub_key_x: Unprovisioned device's Public Key X
|
||||
* @param[in] pub_key_y: Unprovisioned device's Public Key Y
|
||||
@ -324,6 +334,19 @@ esp_err_t esp_ble_mesh_provisioner_set_prov_data_info(esp_ble_mesh_prov_data_inf
|
||||
/**
|
||||
* @brief This function is called by Provisioner to set static oob value used for provisioning.
|
||||
*
|
||||
* @note The Bluetooth SIG recommends that mesh implementations enforce a randomly selected
|
||||
* AuthValue using all of the available bits, where permitted by the implementation.
|
||||
* A large entropy helps ensure that a brute-force of the AuthValue, even a static
|
||||
* AuthValue, cannot normally be completed in a reasonable time (CVE-2020-26557).
|
||||
*
|
||||
* AuthValues selected using a cryptographically secure random or pseudorandom number
|
||||
* generator and having the maximum permitted entropy (128-bits) will be most difficult
|
||||
* to brute-force. AuthValues with reduced entropy or generated in a predictable manner
|
||||
* will not grant the same level of protection against this vulnerability. Selecting a
|
||||
* new AuthValue with each provisioning attempt can also make it more difficult to launch
|
||||
* a brute-force attack by requiring the attacker to restart the search with each
|
||||
* provisioning attempt (CVE-2020-26556).
|
||||
*
|
||||
* @param[in] value: Pointer to the static oob value.
|
||||
* @param[in] length: Length of the static oob value.
|
||||
*
|
||||
|
@ -22,16 +22,6 @@
|
||||
#include "proxy_server.h"
|
||||
#include "provisioner_main.h"
|
||||
|
||||
#ifdef CONFIG_BT_BLUEDROID_ENABLED
|
||||
#include "esp_bt_defs.h"
|
||||
#include "esp_bt_main.h"
|
||||
#define ESP_BLE_HOST_STATUS_ENABLED ESP_BLUEDROID_STATUS_ENABLED
|
||||
#define ESP_BLE_HOST_STATUS_CHECK(status) ESP_BLUEDROID_STATUS_CHECK(status)
|
||||
#else
|
||||
#define ESP_BLE_HOST_STATUS_ENABLED 0
|
||||
#define ESP_BLE_HOST_STATUS_CHECK(status) do {} while (0)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -582,6 +572,12 @@ typedef struct {
|
||||
/** Out of Band information field. */
|
||||
esp_ble_mesh_prov_oob_info_t oob_info;
|
||||
|
||||
/* NOTE: In order to avoid suffering brute-forcing attack (CVE-2020-26559).
|
||||
* The Bluetooth SIG recommends that potentially vulnerable mesh provisioners
|
||||
* support an out-of-band mechanism to exchange the public keys.
|
||||
* So as an unprovisioned device, it should enable this flag to support
|
||||
* using an out-of-band mechanism to exchange Public Key.
|
||||
*/
|
||||
/** Flag indicates whether unprovisioned devices support OOB public key */
|
||||
bool oob_pub_key;
|
||||
|
||||
@ -635,12 +631,29 @@ typedef struct {
|
||||
/** Provisioning Algorithm for the Provisioner */
|
||||
uint8_t prov_algorithm;
|
||||
|
||||
/* NOTE: In order to avoid suffering brute-forcing attack (CVE-2020-26559).
|
||||
* The Bluetooth SIG recommends that potentially vulnerable mesh provisioners
|
||||
* use an out-of-band mechanism to exchange the public keys.
|
||||
*/
|
||||
/** Provisioner public key oob */
|
||||
uint8_t prov_pub_key_oob;
|
||||
|
||||
/** Callback used to notify to set device OOB Public Key. Initialized by the stack. */
|
||||
esp_ble_mesh_cb_t provisioner_prov_read_oob_pub_key;
|
||||
|
||||
/* NOTE: The Bluetooth SIG recommends that mesh implementations enforce a randomly
|
||||
* selected AuthValue using all of the available bits, where permitted by the
|
||||
* implementation. A large entropy helps ensure that a brute-force of the AuthValue,
|
||||
* even a static AuthValue, cannot normally be completed in a reasonable time (CVE-2020-26557).
|
||||
*
|
||||
* AuthValues selected using a cryptographically secure random or pseudorandom number
|
||||
* generator and having the maximum permitted entropy (128-bits) will be most difficult
|
||||
* to brute-force. AuthValues with reduced entropy or generated in a predictable manner
|
||||
* will not grant the same level of protection against this vulnerability. Selecting a
|
||||
* new AuthValue with each provisioning attempt can also make it more difficult to launch
|
||||
* a brute-force attack by requiring the attacker to restart the search with each
|
||||
* provisioning attempt (CVE-2020-26556).
|
||||
*/
|
||||
/** Provisioner static oob value */
|
||||
uint8_t *prov_static_oob_val;
|
||||
/** Provisioner static oob value length */
|
||||
|
@ -22,11 +22,11 @@
|
||||
#include "provisioner_prov.h"
|
||||
#include "provisioner_main.h"
|
||||
|
||||
#if defined(CONFIG_BLE_MESH_FAST_PROV)
|
||||
#define UNPROVISIONED_INTERVAL K_SECONDS(3)
|
||||
#if defined(CONFIG_BLE_MESH_UNPROVISIONED_BEACON_INTERVAL)
|
||||
#define UNPROVISIONED_INTERVAL K_SECONDS(CONFIG_BLE_MESH_UNPROVISIONED_BEACON_INTERVAL)
|
||||
#else
|
||||
#define UNPROVISIONED_INTERVAL K_SECONDS(5)
|
||||
#endif /* CONFIG_BLE_MESH_FAST_PROV */
|
||||
#endif
|
||||
#define PROVISIONED_INTERVAL K_SECONDS(10)
|
||||
|
||||
#define BEACON_TYPE_UNPROVISIONED 0x00
|
||||
|
@ -2352,7 +2352,7 @@ send_status:
|
||||
|
||||
if (status == STATUS_SUCCESS) {
|
||||
bt_mesh_cfg_server_state_change_t change = {0};
|
||||
change.cfg_netkey_delete.net_idx = sub->net_idx;
|
||||
change.cfg_netkey_delete.net_idx = sub ? sub->net_idx : BLE_MESH_KEY_UNUSED;
|
||||
bt_mesh_config_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_CONFIG_SERVER_STATE_CHANGE,
|
||||
model, ctx, (const uint8_t *)&change, sizeof(change));
|
||||
}
|
||||
|
@ -751,7 +751,18 @@ static int prov_auth(uint8_t method, uint8_t action, uint8_t size)
|
||||
uint32_t num = 0U;
|
||||
|
||||
bt_mesh_rand(&num, sizeof(num));
|
||||
num %= div[size - 1];
|
||||
|
||||
if (output == BLE_MESH_BLINK ||
|
||||
output == BLE_MESH_BEEP ||
|
||||
output == BLE_MESH_VIBRATE) {
|
||||
/** NOTE: According to the Bluetooth Mesh Profile Specification
|
||||
* Section 5.4.2.4, blink, beep and vibrate should be a random
|
||||
* integer between 0 and 10^size.
|
||||
*/
|
||||
num = (num % (div[size - 1] - 1)) + 1;
|
||||
} else {
|
||||
num %= div[size - 1];
|
||||
}
|
||||
|
||||
sys_put_be32(num, &link.auth[12]);
|
||||
(void)memset(link.auth, 0, 12);
|
||||
|
@ -156,6 +156,7 @@ struct prov_link {
|
||||
|
||||
uint8_t *rand; /* Local Random */
|
||||
uint8_t *conf; /* Remote Confirmation */
|
||||
uint8_t *local_conf; /* Local Confirmation */
|
||||
|
||||
uint8_t *prov_salt; /* Provisioning Salt */
|
||||
|
||||
@ -1253,6 +1254,7 @@ static void prov_memory_free(const uint8_t idx)
|
||||
PROV_FREE_MEM(idx, auth);
|
||||
PROV_FREE_MEM(idx, rand);
|
||||
PROV_FREE_MEM(idx, conf);
|
||||
PROV_FREE_MEM(idx, local_conf);
|
||||
PROV_FREE_MEM(idx, conf_salt);
|
||||
PROV_FREE_MEM(idx, conf_key);
|
||||
PROV_FREE_MEM(idx, conf_inputs);
|
||||
@ -1928,6 +1930,19 @@ static int prov_auth(const uint8_t idx, uint8_t method, uint8_t action, uint8_t
|
||||
/* Provisioner ouput number/string and wait for device's Provisioning Input Complete PDU */
|
||||
link[idx].expect = PROV_INPUT_COMPLETE;
|
||||
|
||||
/* NOTE: The Bluetooth SIG recommends that mesh implementations enforce a randomly
|
||||
* selected AuthValue using all of the available bits, where permitted by the
|
||||
* implementation. A large entropy helps ensure that a brute-force of the AuthValue,
|
||||
* even a static AuthValue, cannot normally be completed in a reasonable time (CVE-2020-26557).
|
||||
*
|
||||
* AuthValues selected using a cryptographically secure random or pseudorandom number
|
||||
* generator and having the maximum permitted entropy (128-bits) will be most difficult
|
||||
* to brute-force. AuthValues with reduced entropy or generated in a predictable manner
|
||||
* will not grant the same level of protection against this vulnerability. Selecting a
|
||||
* new AuthValue with each provisioning attempt can also make it more difficult to launch
|
||||
* a brute-force attack by requiring the attacker to restart the search with each
|
||||
* provisioning attempt (CVE-2020-26556).
|
||||
*/
|
||||
if (input == BLE_MESH_ENTER_STRING) {
|
||||
unsigned char str[9] = {'\0'};
|
||||
uint8_t j = 0U;
|
||||
@ -1954,7 +1969,17 @@ static int prov_auth(const uint8_t idx, uint8_t method, uint8_t action, uint8_t
|
||||
uint32_t num = 0U;
|
||||
|
||||
bt_mesh_rand(&num, sizeof(num));
|
||||
num %= div[size - 1];
|
||||
|
||||
if (input == BLE_MESH_PUSH ||
|
||||
input == BLE_MESH_TWIST) {
|
||||
/** NOTE: According to the Bluetooth Mesh Profile Specification
|
||||
* Section 5.4.2.4, push and twist should be a random integer
|
||||
* between 0 and 10^size.
|
||||
*/
|
||||
num = (num % (div[size - 1] - 1)) + 1;
|
||||
} else {
|
||||
num %= div[size - 1];
|
||||
}
|
||||
|
||||
sys_put_be32(num, &link[idx].auth[12]);
|
||||
memset(link[idx].auth, 0, 12);
|
||||
@ -1970,6 +1995,7 @@ static int prov_auth(const uint8_t idx, uint8_t method, uint8_t action, uint8_t
|
||||
static void send_confirm(const uint8_t idx)
|
||||
{
|
||||
PROV_BUF(buf, 17);
|
||||
uint8_t *conf = NULL;
|
||||
|
||||
BT_DBG("ConfInputs[0] %s", bt_hex(link[idx].conf_inputs, 64));
|
||||
BT_DBG("ConfInputs[64] %s", bt_hex(link[idx].conf_inputs + 64, 64));
|
||||
@ -2016,12 +2042,22 @@ static void send_confirm(const uint8_t idx)
|
||||
|
||||
prov_buf_init(&buf, PROV_CONFIRM);
|
||||
|
||||
if (bt_mesh_prov_conf(link[idx].conf_key, link[idx].rand, link[idx].auth,
|
||||
net_buf_simple_add(&buf, 16))) {
|
||||
conf = net_buf_simple_add(&buf, 16);
|
||||
|
||||
if (bt_mesh_prov_conf(link[idx].conf_key, link[idx].rand,
|
||||
link[idx].auth, conf)) {
|
||||
BT_ERR("Failed to generate confirmation value");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
link[idx].local_conf = bt_mesh_calloc(PROV_CONFIRM_SIZE);
|
||||
if (!link[idx].local_conf) {
|
||||
BT_ERR("%s, Out of memory", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
memcpy(link[idx].local_conf, conf, PROV_CONFIRM_SIZE);
|
||||
|
||||
if (prov_send(idx, &buf)) {
|
||||
BT_ERR("Failed to send Provisioning Confirm");
|
||||
goto fail;
|
||||
@ -2057,7 +2093,7 @@ int bt_mesh_provisioner_set_oob_input_data(const uint8_t idx, const uint8_t *val
|
||||
memset(link[idx].auth, 0, 16);
|
||||
if (num_flag) {
|
||||
/* Provisioner inputs number */
|
||||
memcpy(link[idx].auth + 12, val, sizeof(uint32_t));
|
||||
sys_memcpy_swap(link[idx].auth + 12, val, sizeof(uint32_t));
|
||||
} else {
|
||||
/* Provisioner inputs string */
|
||||
memcpy(link[idx].auth, val, link[idx].auth_size);
|
||||
@ -2094,7 +2130,7 @@ int bt_mesh_provisioner_set_oob_output_data(const uint8_t idx, const uint8_t *nu
|
||||
if (num_flag) {
|
||||
/* Provisioner output number */
|
||||
memset(link[idx].auth, 0, 16);
|
||||
memcpy(link[idx].auth + 16 - size, num, size);
|
||||
sys_memcpy_swap(link[idx].auth + 16 - size, num, size);
|
||||
} else {
|
||||
/* Provisioner output string */
|
||||
memset(link[idx].auth, 0, 16);
|
||||
@ -2289,6 +2325,17 @@ static void prov_confirm(const uint8_t idx, const uint8_t *data)
|
||||
|
||||
BT_DBG("Remote Confirm: %s", bt_hex(data, 16));
|
||||
|
||||
/* NOTE: The Bluetooth SIG recommends that potentially vulnerable mesh provisioners
|
||||
* restrict the authentication procedure and not accept provisioning random and
|
||||
* provisioning confirmation numbers from a remote peer that are the same as those
|
||||
* selected by the local device (CVE-2020-26560).
|
||||
*/
|
||||
if (!memcmp(data, link[idx].local_conf, 16)) {
|
||||
BT_ERR("Confirmation value is identical to ours, rejecting.");
|
||||
close_link(idx, CLOSE_REASON_FAILED);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Make sure received pdu is ok and cancel the timeout timer */
|
||||
if (bt_mesh_atomic_test_and_clear_bit(link[idx].flags, TIMEOUT_START)) {
|
||||
k_delayed_work_cancel(&link[idx].timeout);
|
||||
@ -2499,6 +2546,16 @@ static void prov_random(const uint8_t idx, const uint8_t *data)
|
||||
|
||||
BT_DBG("Remote Random: %s", bt_hex(data, 16));
|
||||
|
||||
/* NOTE: The Bluetooth SIG recommends that potentially vulnerable mesh provisioners
|
||||
* restrict the authentication procedure and not accept provisioning random and
|
||||
* provisioning confirmation numbers from a remote peer that are the same as those
|
||||
* selected by the local device (CVE-2020-26560).
|
||||
*/
|
||||
if (!memcmp(data, link[idx].rand, 16)) {
|
||||
BT_ERR("Random value is identical to ours, rejecting.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (bt_mesh_prov_conf(link[idx].conf_key, data, link[idx].auth, conf_verify)) {
|
||||
BT_ERR("Failed to calculate confirmation verification");
|
||||
goto fail;
|
||||
|
@ -143,6 +143,16 @@ config BT_BLE_BLUFI_ENABLE
|
||||
help
|
||||
This option can be close when the app does not require blufi function.
|
||||
|
||||
config BT_GATT_MAX_SR_PROFILES
|
||||
int "Max GATT Server Profiles"
|
||||
depends on BT_GATTS_ENABLE && BT_BLUEDROID_ENABLED
|
||||
range 1 32
|
||||
default 8
|
||||
help
|
||||
Maximum GATT Server Profiles Count
|
||||
|
||||
|
||||
|
||||
choice BT_GATTS_SEND_SERVICE_CHANGE_MODE
|
||||
prompt "GATTS Service Change Mode"
|
||||
default BT_GATTS_SEND_SERVICE_CHANGE_AUTO
|
||||
@ -183,6 +193,14 @@ config BT_GATTC_CACHE_NVS_FLASH
|
||||
help
|
||||
This select can save gattc cache data to nvs flash
|
||||
|
||||
config BT_GATTC_CONNECT_RETRY_COUNT
|
||||
int "The number of attempts to reconnect if the connection establishment failed"
|
||||
depends on BT_GATTC_ENABLE
|
||||
range 0 7
|
||||
default 3
|
||||
help
|
||||
The number of attempts to reconnect if the connection establishment failed
|
||||
|
||||
config BT_BLE_SMP_ENABLE
|
||||
bool "Include BLE security module(SMP)"
|
||||
depends on BT_BLE_ENABLED
|
||||
@ -945,7 +963,6 @@ menu "BT DEBUG LOG LEVEL"
|
||||
|
||||
endmenu #BT DEBUG LOG LEVEL
|
||||
|
||||
|
||||
config BT_ACL_CONNECTIONS
|
||||
int "BT/BLE MAX ACL CONNECTIONS(1~7)"
|
||||
depends on BT_BLUEDROID_ENABLED
|
||||
@ -954,6 +971,13 @@ config BT_ACL_CONNECTIONS
|
||||
help
|
||||
Maximum BT/BLE connection count
|
||||
|
||||
config BT_MULTI_CONNECTION_ENBALE
|
||||
bool "Enable BLE multi-conections"
|
||||
depends on BT_BLUEDROID_ENABLED
|
||||
default y
|
||||
help
|
||||
Enable this option if there are multiple connections
|
||||
|
||||
config BT_ALLOCATION_FROM_SPIRAM_FIRST
|
||||
bool "BT/BLE will first malloc the memory from the PSRAM"
|
||||
depends on BT_BLUEDROID_ENABLED
|
||||
@ -1004,10 +1028,20 @@ config BT_BLE_ESTAB_LINK_CONN_TOUT
|
||||
|
||||
config BT_BLE_RPA_SUPPORTED
|
||||
bool "Update RPA to Controller"
|
||||
depends on (BT_BLUEDROID_ENABLED && (IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3))
|
||||
default y
|
||||
depends on BT_BLUEDROID_ENABLED
|
||||
default y if (IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3)
|
||||
default n if IDF_TARGET_ESP32
|
||||
help
|
||||
This enables controller RPA list function.
|
||||
For ESP32, ESP32 only support network privacy mode. If this option is enabled, ESP32 will only accept
|
||||
advertising packets from peer devices that contain private address, HW will not receive the advertising
|
||||
packets contain identity address after IRK changed. If this option is disabled, address resolution will
|
||||
be performed in the host, so the functions that require controller to resolve address in the white list
|
||||
cannot be used. This option is disabled by default on ESP32, please enable or disable this option according
|
||||
to your own needs.
|
||||
|
||||
For ESP32C3 and esp32s3, devices support network privacy mode and device privacy mode, users can switch the
|
||||
two modes according to their own needs. So this option is enabled by default.
|
||||
|
||||
config BT_BLE_50_FEATURES_SUPPORTED
|
||||
bool "Enable BLE 5.0 features"
|
||||
|
@ -133,7 +133,8 @@ esp_err_t esp_spp_start_srv(esp_spp_sec_t sec_mask,
|
||||
btc_spp_args_t arg;
|
||||
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
|
||||
|
||||
if (strlen(name) > ESP_SPP_SERVER_NAME_MAX) {
|
||||
if (name == NULL || strlen(name) > ESP_SPP_SERVER_NAME_MAX) {
|
||||
LOG_ERROR("Invalid server name!\n");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
@ -157,13 +158,34 @@ esp_err_t esp_spp_start_srv(esp_spp_sec_t sec_mask,
|
||||
esp_err_t esp_spp_stop_srv(void)
|
||||
{
|
||||
btc_msg_t msg;
|
||||
btc_spp_args_t arg;
|
||||
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
|
||||
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_SPP;
|
||||
msg.act = BTC_SPP_ACT_STOP_SRV;
|
||||
arg.stop_srv.scn = BTC_SPP_INVALID_SCN;
|
||||
|
||||
return (btc_transfer_context(&msg, NULL, sizeof(btc_spp_args_t), NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
|
||||
return (btc_transfer_context(&msg, &arg, sizeof(btc_spp_args_t), NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
|
||||
}
|
||||
|
||||
esp_err_t esp_spp_stop_srv_scn(uint8_t scn)
|
||||
{
|
||||
btc_msg_t msg;
|
||||
btc_spp_args_t arg;
|
||||
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
|
||||
|
||||
if ((scn == 0) || (scn >= PORT_MAX_RFC_PORTS)) {
|
||||
LOG_ERROR("Invalid SCN!\n");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_SPP;
|
||||
msg.act = BTC_SPP_ACT_STOP_SRV;
|
||||
arg.stop_srv.scn = scn;
|
||||
|
||||
return (btc_transfer_context(&msg, &arg, sizeof(btc_spp_args_t), NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
|
||||
}
|
||||
|
||||
|
||||
|
@ -259,7 +259,7 @@ typedef union {
|
||||
/**
|
||||
* @brief GATT Client callback function type
|
||||
* @param event : Event type
|
||||
* @param gatts_if : GATT client access interface, normally
|
||||
* @param gattc_if : GATT client access interface, normally
|
||||
* different gattc_if correspond to different profile
|
||||
* @param param : Point to callback parameter, currently is union type
|
||||
*/
|
||||
@ -313,7 +313,7 @@ esp_err_t esp_ble_gattc_app_unregister(esp_gatt_if_t gattc_if);
|
||||
* @param[in] gattc_if: Gatt client access interface.
|
||||
* @param[in] remote_bda: remote device bluetooth device address.
|
||||
* @param[in] remote_addr_type: remote device bluetooth device the address type.
|
||||
* @param[in] is_direct: direct connection or background auto connection
|
||||
* @param[in] is_direct: direct connection or background auto connection(by now, background auto connection is not supported).
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
|
@ -188,7 +188,7 @@ typedef void (* esp_hf_incoming_data_cb_t)(const uint8_t *buf, uint32_t len);
|
||||
*
|
||||
* @param[in] len : size(in bytes) in buf
|
||||
*
|
||||
* @param[out] length of data successfully read
|
||||
* @return length of data successfully read
|
||||
*/
|
||||
typedef uint32_t (* esp_hf_outgoing_data_cb_t) (uint8_t *buf, uint32_t len);
|
||||
|
||||
|
@ -273,7 +273,7 @@ typedef void (* esp_hf_client_incoming_data_cb_t)(const uint8_t *buf, uint32_t l
|
||||
*
|
||||
* @param[in] len : size(in bytes) in buf
|
||||
*
|
||||
* @param[out] length of data successfully read
|
||||
* @return length of data successfully read
|
||||
*
|
||||
*/
|
||||
typedef uint32_t (* esp_hf_client_outgoing_data_cb_t)(uint8_t *buf, uint32_t len);
|
||||
|
@ -26,11 +26,12 @@ typedef enum {
|
||||
ESP_SPP_SUCCESS = 0, /*!< Successful operation. */
|
||||
ESP_SPP_FAILURE, /*!< Generic failure. */
|
||||
ESP_SPP_BUSY, /*!< Temporarily can not handle this request. */
|
||||
ESP_SPP_NO_DATA, /*!< no data. */
|
||||
ESP_SPP_NO_DATA, /*!< No data */
|
||||
ESP_SPP_NO_RESOURCE, /*!< No more resource */
|
||||
ESP_SPP_NEED_INIT, /*!< SPP module shall init first */
|
||||
ESP_SPP_NEED_DEINIT, /*!< SPP module shall deinit first */
|
||||
ESP_SPP_NO_CONNECTION, /*!< connection may have been closed */
|
||||
ESP_SPP_NO_CONNECTION, /*!< Connection may have been closed */
|
||||
ESP_SPP_NO_SERVER, /*!< No SPP server */
|
||||
} esp_spp_status_t;
|
||||
|
||||
/* Security Setting Mask
|
||||
@ -101,9 +102,10 @@ typedef union {
|
||||
* @brief SPP_DISCOVERY_COMP_EVT
|
||||
*/
|
||||
struct spp_discovery_comp_evt_param {
|
||||
esp_spp_status_t status; /*!< status */
|
||||
uint8_t scn_num; /*!< The num of scn_num */
|
||||
uint8_t scn[ESP_SPP_MAX_SCN]; /*!< channel # */
|
||||
esp_spp_status_t status; /*!< status */
|
||||
uint8_t scn_num; /*!< The num of scn_num */
|
||||
uint8_t scn[ESP_SPP_MAX_SCN]; /*!< channel # */
|
||||
const char *service_name[ESP_SPP_MAX_SCN]; /*!< service_name */
|
||||
} disc_comp; /*!< SPP callback param of SPP_DISCOVERY_COMP_EVT */
|
||||
|
||||
/**
|
||||
@ -143,6 +145,7 @@ typedef union {
|
||||
esp_spp_status_t status; /*!< status */
|
||||
uint32_t handle; /*!< The connection handle */
|
||||
uint8_t sec_id; /*!< security ID used by this server */
|
||||
uint8_t scn; /*!< Server channel number */
|
||||
bool use_co; /*!< TRUE to use co_rfc_data */
|
||||
} start; /*!< SPP callback param of ESP_SPP_START_EVT */
|
||||
|
||||
@ -151,6 +154,7 @@ typedef union {
|
||||
*/
|
||||
struct spp_srv_stop_evt_param {
|
||||
esp_spp_status_t status; /*!< status */
|
||||
uint8_t scn; /*!< Server channel number */
|
||||
} srv_stop; /*!< SPP callback param of ESP_SPP_SRV_STOP_EVT */
|
||||
|
||||
/**
|
||||
@ -304,7 +308,7 @@ esp_err_t esp_spp_disconnect(uint32_t handle);
|
||||
esp_err_t esp_spp_start_srv(esp_spp_sec_t sec_mask, esp_spp_role_t role, uint8_t local_scn, const char *name);
|
||||
|
||||
/**
|
||||
* @brief This function stops a SPP server.
|
||||
* @brief This function stops all SPP servers.
|
||||
* The operation will close all active SPP connection first, then the callback function will be called
|
||||
* with ESP_SPP_CLOSE_EVT, and the number of ESP_SPP_CLOSE_EVT is equal to the number of connection.
|
||||
* When the operation is completed, the callback is called with ESP_SPP_SRV_STOP_EVT.
|
||||
@ -314,8 +318,24 @@ esp_err_t esp_spp_start_srv(esp_spp_sec_t sec_mask, esp_spp_role_t role, uint8_t
|
||||
* - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
|
||||
esp_err_t esp_spp_stop_srv(void);
|
||||
|
||||
/**
|
||||
* @brief This function stops a specific SPP server.
|
||||
* The operation will close all active SPP connection first on the specific SPP server, then the callback function will be called
|
||||
* with ESP_SPP_CLOSE_EVT, and the number of ESP_SPP_CLOSE_EVT is equal to the number of connection.
|
||||
* When the operation is completed, the callback is called with ESP_SPP_SRV_STOP_EVT.
|
||||
* This funciton must be called after esp_spp_init() successful and before esp_spp_deinit().
|
||||
*
|
||||
* @param[in] scn: Server channel number.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_spp_stop_srv_scn(uint8_t scn);
|
||||
|
||||
/**
|
||||
* @brief This function is used to write data, only for ESP_SPP_MODE_CB.
|
||||
* When this function need to be called repeatedly, it is strongly recommended to call this function again after
|
||||
|
@ -5354,19 +5354,39 @@ void bta_dm_ble_set_scan_rsp_raw (tBTA_DM_MSG *p_data)
|
||||
*******************************************************************************/
|
||||
void bta_dm_ble_set_data_length(tBTA_DM_MSG *p_data)
|
||||
{
|
||||
UINT8 status = BTM_SUCCESS;
|
||||
tACL_CONN *p_acl_cb = btm_bda_to_acl(p_data->ble_set_data_length.remote_bda, BT_TRANSPORT_LE);
|
||||
if (p_acl_cb == NULL) {
|
||||
APPL_TRACE_ERROR("%s error: Invalid connection remote_bda.", __func__);
|
||||
return;
|
||||
}
|
||||
if(p_acl_cb->data_len_updating) {
|
||||
// aleady have one cmd
|
||||
if(p_acl_cb->data_len_waiting) {
|
||||
status = BTM_ILLEGAL_ACTION;
|
||||
} else {
|
||||
// save the command
|
||||
p_acl_cb->p_set_data_len_cback_waiting = p_data->ble_set_data_length.p_set_pkt_data_cback;
|
||||
p_acl_cb->tx_len_waiting = p_data->ble_set_data_length.tx_data_length;
|
||||
p_acl_cb->data_len_waiting = true;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
p_acl_cb->p_set_pkt_data_cback = p_data->ble_set_data_length.p_set_pkt_data_cback;
|
||||
}
|
||||
UINT8 status = BTM_SetBleDataLength(p_data->ble_set_data_length.remote_bda,
|
||||
// if the value of the data length is same, triger callback directly
|
||||
if(p_data->ble_set_data_length.tx_data_length == p_acl_cb->data_length_params.tx_len) {
|
||||
if(p_data->ble_set_data_length.p_set_pkt_data_cback) {
|
||||
(*p_data->ble_set_data_length.p_set_pkt_data_cback)(status, &p_acl_cb->data_length_params);
|
||||
}
|
||||
return;
|
||||
}
|
||||
status = BTM_SetBleDataLength(p_data->ble_set_data_length.remote_bda,
|
||||
p_data->ble_set_data_length.tx_data_length);
|
||||
}
|
||||
if (status != BTM_SUCCESS) {
|
||||
APPL_TRACE_ERROR("%s failed\n", __FUNCTION__);
|
||||
}
|
||||
if (p_data->ble_set_data_length.p_set_pkt_data_cback) {
|
||||
if (p_data->ble_set_data_length.p_set_pkt_data_cback && status != BTM_SUCCESS) {
|
||||
if (p_acl_cb->data_length_params.tx_len == 0){
|
||||
uint16_t length = controller_get_interface()->get_acl_data_size_ble();
|
||||
p_acl_cb->data_length_params.rx_len = length;
|
||||
|
@ -973,10 +973,11 @@ void bta_gattc_start_discover(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
|
||||
p_clcb->p_srcb->srvc_hdl_chg = FALSE;
|
||||
p_clcb->p_srcb->update_count = 0;
|
||||
p_clcb->p_srcb->state = BTA_GATTC_SERV_DISC_ACT;
|
||||
|
||||
#if (BT_MULTI_CONNECTION_ENBALE == FALSE)
|
||||
if (p_clcb->transport == BTA_TRANSPORT_LE) {
|
||||
L2CA_EnableUpdateBleConnParams(p_clcb->p_srcb->server_bda, FALSE);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* set all srcb related clcb into discovery ST */
|
||||
bta_gattc_set_discover_st(p_clcb->p_srcb);
|
||||
@ -1683,8 +1684,7 @@ static void bta_gattc_conn_cback(tGATT_IF gattc_if, BD_ADDR bda, UINT16 conn_id,
|
||||
tBTA_GATTC_DATA *p_buf;
|
||||
|
||||
if (reason != 0) {
|
||||
APPL_TRACE_WARNING("%s() - cif=%d connected=%d conn_id=%d reason=0x%04x",
|
||||
__FUNCTION__, gattc_if, connected, conn_id, reason);
|
||||
APPL_TRACE_WARNING("gattc_conn_cb: if=%d st=%d id=%d rsn=0x%x", gattc_if, connected, conn_id, reason);
|
||||
}
|
||||
|
||||
bt_bdaddr_t bdaddr;
|
||||
@ -1702,7 +1702,7 @@ static void bta_gattc_conn_cback(tGATT_IF gattc_if, BD_ADDR bda, UINT16 conn_id,
|
||||
p_buf->int_conn.conn_params.latency = p_lcb->current_used_conn_latency;
|
||||
p_buf->int_conn.conn_params.timeout = p_lcb->current_used_conn_timeout;
|
||||
} else {
|
||||
APPL_TRACE_WARNING("%s not found connection parameters of the device ", __func__);
|
||||
APPL_TRACE_WARNING("gattc_conn_cb: conn params not found");
|
||||
}
|
||||
}
|
||||
p_buf->int_conn.hdr.layer_specific = conn_id;
|
||||
|
@ -616,9 +616,11 @@ static void bta_gattc_explore_srvc(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb)
|
||||
|
||||
//server discover end, update connection parameters
|
||||
#if BLE_INCLUDED == TRUE
|
||||
#if (BT_MULTI_CONNECTION_ENBALE == FALSE)
|
||||
if (p_clcb->transport == BTA_TRANSPORT_LE) {
|
||||
L2CA_EnableUpdateBleConnParams(p_clcb->p_srcb->server_bda, TRUE);
|
||||
}
|
||||
#endif
|
||||
//discover service complete, trigger callback
|
||||
tBTA_GATTC cb_data;
|
||||
cb_data.dis_cmpl.status = p_clcb->status;
|
||||
|
@ -394,6 +394,8 @@ void bta_gattc_co_cache_addr_init(void)
|
||||
return;
|
||||
}
|
||||
|
||||
memset(cache_env, 0x0, sizeof(cache_env_t));
|
||||
|
||||
if ((err_code = nvs_open(cache_addr, NVS_READWRITE, &fp)) == ESP_OK) {
|
||||
cache_env->addr_fp = fp;
|
||||
cache_env->is_open = TRUE;
|
||||
|
@ -172,9 +172,10 @@ typedef struct {
|
||||
|
||||
/* data associated with BTA_JV_DISCOVERY_COMP_EVT_ */
|
||||
typedef struct {
|
||||
tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
|
||||
UINT8 scn_num; /* num of channel */
|
||||
UINT8 scn[BTA_JV_MAX_SCN]; /* channel # */
|
||||
tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
|
||||
UINT8 scn_num; /* num of channel */
|
||||
UINT8 scn[BTA_JV_MAX_SCN]; /* channel # */
|
||||
const char *service_name[BTA_JV_MAX_SCN]; /* service_name */
|
||||
} tBTA_JV_DISCOVERY_COMP;
|
||||
|
||||
/* data associated with BTA_JV_CREATE_RECORD_EVT */
|
||||
@ -305,6 +306,7 @@ typedef struct {
|
||||
tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
|
||||
UINT32 handle; /* The connection handle */
|
||||
UINT8 sec_id; /* security ID used by this server */
|
||||
UINT8 scn; /* Server channe number */
|
||||
BOOLEAN use_co; /* TRUE to use co_rfc_data */
|
||||
} tBTA_JV_RFCOMM_START;
|
||||
|
||||
@ -376,8 +378,9 @@ typedef struct {
|
||||
|
||||
/* data associated with BTA_JV_FREE_SCN_EVT */
|
||||
typedef struct {
|
||||
tBTA_JV_STATUS status; /* Status of the operation */
|
||||
tBTA_JV_SERVER_STATUS server_status;
|
||||
tBTA_JV_STATUS status; /* Status of the operation */
|
||||
tBTA_JV_SERVER_STATUS server_status; /* Server status */
|
||||
UINT8 scn; /* Server channe number */
|
||||
} tBTA_JV_FREE_SCN;
|
||||
|
||||
|
||||
|
@ -856,6 +856,7 @@ void bta_jv_free_scn(tBTA_JV_MSG *p_data)
|
||||
tBTA_JV_FREE_SCN evt_data = {
|
||||
.status = BTA_JV_SUCCESS,
|
||||
.server_status = BTA_JV_SERVER_STATUS_MAX,
|
||||
.scn = scn
|
||||
};
|
||||
|
||||
tBTA_JV_FREE_SCN_USER_DATA *user_data = NULL;
|
||||
@ -949,6 +950,7 @@ static void bta_jv_start_discovery_cback(UINT16 result, void *user_data)
|
||||
status = BTA_JV_FAILURE;
|
||||
if (result == SDP_SUCCESS || result == SDP_DB_FULL) {
|
||||
tSDP_DISC_REC *p_sdp_rec = NULL;
|
||||
tSDP_DISC_ATTR *p_attr = NULL;
|
||||
tSDP_PROTOCOL_ELEM pe;
|
||||
logu("bta_jv_cb.uuid", bta_jv_cb.uuid.uu.uuid128);
|
||||
tBT_UUID su = shorten_sdp_uuid(&bta_jv_cb.uuid);
|
||||
@ -957,7 +959,13 @@ static void bta_jv_start_discovery_cback(UINT16 result, void *user_data)
|
||||
p_sdp_rec = SDP_FindServiceUUIDInDb(p_bta_jv_cfg->p_sdp_db, &su, p_sdp_rec);
|
||||
APPL_TRACE_DEBUG("p_sdp_rec:%p", p_sdp_rec);
|
||||
if (p_sdp_rec && SDP_FindProtocolListElemInRec(p_sdp_rec, UUID_PROTOCOL_RFCOMM, &pe)){
|
||||
dcomp.scn[dcomp.scn_num++] = (UINT8) pe.params[0];
|
||||
dcomp.scn[dcomp.scn_num] = (UINT8) pe.params[0];
|
||||
if ((p_attr = SDP_FindAttributeInRec(p_sdp_rec, ATTR_ID_SERVICE_NAME)) != NULL) {
|
||||
dcomp.service_name[dcomp.scn_num] = (char *)p_attr->attr_value.v.array;
|
||||
} else {
|
||||
dcomp.service_name[dcomp.scn_num] = NULL;
|
||||
}
|
||||
dcomp.scn_num++;
|
||||
status = BTA_JV_SUCCESS;
|
||||
}
|
||||
} while (p_sdp_rec);
|
||||
@ -2154,6 +2162,7 @@ void bta_jv_rfcomm_start_server(tBTA_JV_MSG *p_data)
|
||||
evt_data.status = BTA_JV_SUCCESS;
|
||||
evt_data.handle = p_pcb->handle;
|
||||
evt_data.sec_id = sec_id;
|
||||
evt_data.scn = rs->local_scn;
|
||||
evt_data.use_co = TRUE;
|
||||
|
||||
PORT_ClearKeepHandleFlag(handle);
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "common/bt_defs.h"
|
||||
#include "osi/allocator.h"
|
||||
#include "osi/mutex.h"
|
||||
#include "osi/semaphore.h"
|
||||
#include "osi/thread.h"
|
||||
#include "osi/fixed_queue.h"
|
||||
#include "stack/a2d_api.h"
|
||||
@ -86,8 +87,8 @@ enum {
|
||||
layers we might need to temporarily buffer up data */
|
||||
|
||||
/* 18 frames is equivalent to 6.89*18*2.9 ~= 360 ms @ 44.1 khz, 20 ms mediatick */
|
||||
#define JITTER_BUFFER_WATER_LEVEL (15)
|
||||
#define MAX_OUTPUT_A2DP_SNK_FRAME_QUEUE_SZ (18 + JITTER_BUFFER_WATER_LEVEL)
|
||||
#define MAX_OUTPUT_A2DP_SNK_FRAME_QUEUE_SZ (25)
|
||||
#define JITTER_BUFFER_WATER_LEVEL (5)
|
||||
|
||||
typedef struct {
|
||||
uint32_t sig;
|
||||
@ -104,6 +105,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
BOOLEAN rx_flush; /* discards any incoming data when true */
|
||||
UINT8 channel_count;
|
||||
osi_sem_t post_sem;
|
||||
fixed_queue_t *RxSbcQ;
|
||||
UINT32 sample_rate;
|
||||
} tBTC_A2DP_SINK_CB;
|
||||
@ -153,7 +155,6 @@ static inline void btc_a2d_data_cb_to_app(const uint8_t *data, uint32_t len)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
** Misc helper functions
|
||||
*****************************************************************************/
|
||||
@ -351,7 +352,9 @@ void btc_a2dp_sink_reset_decoder(UINT8 *p_av)
|
||||
static void btc_a2dp_sink_data_ready(UNUSED_ATTR void *context)
|
||||
{
|
||||
tBT_SBC_HDR *p_msg;
|
||||
int nb_of_msgs_to_process = 0;
|
||||
|
||||
osi_sem_give(&a2dp_sink_local_param.btc_aa_snk_cb.post_sem);
|
||||
if (fixed_queue_is_empty(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ)) {
|
||||
APPL_TRACE_DEBUG(" QUE EMPTY ");
|
||||
} else {
|
||||
@ -359,18 +362,20 @@ static void btc_a2dp_sink_data_ready(UNUSED_ATTR void *context)
|
||||
btc_a2dp_sink_flush_q(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ);
|
||||
return;
|
||||
}
|
||||
|
||||
while ((p_msg = (tBT_SBC_HDR *)fixed_queue_try_peek_first(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ)) != NULL ) {
|
||||
nb_of_msgs_to_process = fixed_queue_length(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ);
|
||||
APPL_TRACE_DEBUG("nb:%d", nb_of_msgs_to_process);
|
||||
while (nb_of_msgs_to_process > 0) {
|
||||
if (btc_a2dp_sink_state != BTC_A2DP_SINK_STATE_ON){
|
||||
return;
|
||||
}
|
||||
btc_a2dp_sink_handle_inc_media(p_msg);
|
||||
p_msg = (tBT_SBC_HDR *)fixed_queue_dequeue(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ, 0);
|
||||
if ( p_msg == NULL ) {
|
||||
APPL_TRACE_ERROR("Insufficient data in que ");
|
||||
break;
|
||||
}
|
||||
btc_a2dp_sink_handle_inc_media(p_msg);
|
||||
osi_free(p_msg);
|
||||
nb_of_msgs_to_process--;
|
||||
}
|
||||
APPL_TRACE_DEBUG(" Process Frames - ");
|
||||
}
|
||||
@ -671,12 +676,11 @@ UINT8 btc_a2dp_sink_enque_buf(BT_HDR *p_pkt)
|
||||
p_msg->num_frames_to_be_processed = (*((UINT8 *)(p_msg + 1) + p_msg->offset)) & 0x0f;
|
||||
APPL_TRACE_VERBOSE("btc_a2dp_sink_enque_buf %d + \n", p_msg->num_frames_to_be_processed);
|
||||
fixed_queue_enqueue(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ, p_msg, FIXED_QUEUE_MAX_TIMEOUT);
|
||||
|
||||
if (fixed_queue_length(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ) < JITTER_BUFFER_WATER_LEVEL) {
|
||||
return fixed_queue_length(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ);
|
||||
if (fixed_queue_length(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ) >= JITTER_BUFFER_WATER_LEVEL) {
|
||||
if (osi_sem_take(&a2dp_sink_local_param.btc_aa_snk_cb.post_sem, 0) == 0) {
|
||||
btc_a2dp_sink_data_post();
|
||||
}
|
||||
}
|
||||
|
||||
btc_a2dp_sink_data_post();
|
||||
} else {
|
||||
/* let caller deal with a failed allocation */
|
||||
APPL_TRACE_WARNING("btc_a2dp_sink_enque_buf No Buffer left - ");
|
||||
@ -711,7 +715,9 @@ static void btc_a2dp_sink_thread_init(UNUSED_ATTR void *context)
|
||||
memset(&a2dp_sink_local_param.btc_aa_snk_cb, 0, sizeof(a2dp_sink_local_param.btc_aa_snk_cb));
|
||||
|
||||
btc_a2dp_sink_state = BTC_A2DP_SINK_STATE_ON;
|
||||
|
||||
if (!a2dp_sink_local_param.btc_aa_snk_cb.post_sem) {
|
||||
osi_sem_new(&a2dp_sink_local_param.btc_aa_snk_cb.post_sem, 1, 1);
|
||||
}
|
||||
a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ = fixed_queue_new(QUEUE_SIZE_MAX);
|
||||
|
||||
btc_a2dp_control_init();
|
||||
@ -728,6 +734,11 @@ static void btc_a2dp_sink_thread_cleanup(UNUSED_ATTR void *context)
|
||||
fixed_queue_free(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ, osi_free_func);
|
||||
|
||||
a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ = NULL;
|
||||
|
||||
if (a2dp_sink_local_param.btc_aa_snk_cb.post_sem) {
|
||||
osi_sem_free(&a2dp_sink_local_param.btc_aa_snk_cb.post_sem);
|
||||
a2dp_sink_local_param.btc_aa_snk_cb.post_sem = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* BTC_AV_SINK_INCLUDED */
|
||||
|
@ -53,7 +53,11 @@
|
||||
/* Max HF Clients Supported From App */
|
||||
static UINT16 btc_max_hf_clients = 1;
|
||||
/* HF Param Definition */
|
||||
#if HFP_DYNAMIC_MEMORY == FALSE
|
||||
static hf_local_param_t hf_local_param[BTC_HF_NUM_CB];
|
||||
#else
|
||||
static hf_local_param_t *hf_local_param;
|
||||
#endif
|
||||
|
||||
#if (BTM_WBS_INCLUDED == TRUE)
|
||||
#ifndef BTC_HF_FEATURES
|
||||
@ -296,7 +300,15 @@ bt_status_t btc_hf_execute_service(BOOLEAN b_enable)
|
||||
************************************************************************************/
|
||||
bt_status_t btc_hf_init(bt_bdaddr_t *bd_addr)
|
||||
{
|
||||
int idx = btc_hf_idx_by_bdaddr(bd_addr);
|
||||
int idx = 0;
|
||||
UNUSED(bd_addr);
|
||||
|
||||
#if HFP_DYNAMIC_MEMORY == TRUE
|
||||
if ((hf_local_param = (hf_local_param_t *)osi_malloc(sizeof(hf_local_param_t) * BTC_HF_NUM_CB)) == NULL) {
|
||||
return BT_STATUS_FAIL;
|
||||
}
|
||||
#endif
|
||||
|
||||
BTC_TRACE_DEBUG("%s - max_hf_clients=%d", __func__, btc_max_hf_clients);
|
||||
/* Invoke the enable service API to the core to set the appropriate service_id
|
||||
* Internally, the HSP_SERVICE_ID shall also be enabled if HFP is enabled (phone)
|
||||
@ -322,10 +334,18 @@ bt_status_t btc_hf_init(bt_bdaddr_t *bd_addr)
|
||||
|
||||
void btc_hf_deinit(bt_bdaddr_t *bd_addr)
|
||||
{
|
||||
int idx = btc_hf_idx_by_bdaddr(bd_addr);
|
||||
UNUSED(bd_addr);
|
||||
|
||||
BTC_TRACE_EVENT("%s", __FUNCTION__);
|
||||
btc_dm_disable_service(BTA_HFP_SERVICE_ID);
|
||||
hf_local_param[idx].btc_hf_cb.initialized = false;
|
||||
#if HFP_DYNAMIC_MEMORY == TRUE
|
||||
if (hf_local_param) {
|
||||
osi_free(hf_local_param);
|
||||
hf_local_param = NULL;
|
||||
}
|
||||
#else
|
||||
hf_local_param[0].btc_hf_cb.initialized = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bt_status_t connect_init(bt_bdaddr_t *bd_addr, uint16_t uuid)
|
||||
@ -917,6 +937,10 @@ void btc_hf_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
|
||||
|
||||
case BTC_HF_COPS_RESPONSE_EVT:
|
||||
{
|
||||
if (src->cops_rep.name == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
dst->cops_rep.name = (char *)osi_malloc(strlen(src->cops_rep.name)+1);
|
||||
if(dst->cops_rep.name) {
|
||||
memcpy(dst->cops_rep.name, src->cops_rep.name, strlen(src->cops_rep.name)+1);
|
||||
@ -930,6 +954,10 @@ void btc_hf_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
|
||||
|
||||
case BTC_HF_CLCC_RESPONSE_EVT:
|
||||
{
|
||||
if (src->clcc_rep.number == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
dst->clcc_rep.number = (char *)osi_malloc(strlen(src->clcc_rep.number)+1);
|
||||
if(dst->clcc_rep.number) {
|
||||
memcpy(dst->clcc_rep.number, src->clcc_rep.number, strlen(src->clcc_rep.number)+1);
|
||||
@ -943,6 +971,10 @@ void btc_hf_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
|
||||
|
||||
case BTC_HF_CNUM_RESPONSE_EVT:
|
||||
{
|
||||
if (src->cnum_rep.number == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
dst->cnum_rep.number = (char *)osi_malloc(strlen(src->cnum_rep.number)+1);
|
||||
if(dst->cnum_rep.number) {
|
||||
memcpy(dst->cnum_rep.number, src->cnum_rep.number, strlen(src->cnum_rep.number)+1);
|
||||
@ -959,6 +991,10 @@ void btc_hf_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
|
||||
case BTC_HF_OUT_CALL_EVT:
|
||||
case BTC_HF_END_CALL_EVT:
|
||||
{
|
||||
if (src->phone.number == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
dst->phone.number = (char *)osi_malloc(strlen(src->phone.number)+1);
|
||||
if(dst->phone.number) {
|
||||
memcpy(dst->phone.number, src->phone.number, strlen(src->phone.number)+1);
|
||||
|
@ -329,9 +329,11 @@ uint32_t bta_hf_client_sco_co_out_data(UINT8 *p_buf)
|
||||
return btc_hf_client_outgoing_data_cb_to_app(p_buf, hf_raw_pkt_size);
|
||||
} else if (hf_air_mode == BTM_SCO_AIR_MODE_TRANSPNT) {
|
||||
// mSBC
|
||||
#if (HFP_DYNAMIC_MEMORY == TRUE)
|
||||
if(bta_hf_client_co_cb_ptr == NULL) {
|
||||
return 0;
|
||||
}
|
||||
#endif /* HFP_DYNAMIC_MEMORY == TRUE */
|
||||
if (hf_inout_pkt_size == BTM_MSBC_FRAME_SIZE / 2) {
|
||||
if (bta_hf_client_co_cb.encode_first_pkt){
|
||||
UINT32 size = btc_hf_client_outgoing_data_cb_to_app((UINT8 *)bta_hf_client_co_cb.encoder.as16PcmBuffer, HF_SBC_ENC_RAW_DATA_SIZE);
|
||||
|
@ -206,11 +206,6 @@ typedef union
|
||||
/* APP ID definition*/
|
||||
#define BTC_HF_ID_1 0
|
||||
|
||||
#if HFP_DYNAMIC_MEMORY == TRUE
|
||||
extern hf_local_param_t *hf_local_param_ptr;
|
||||
#define hf_local_param (*hf_local_param_ptr)
|
||||
#endif
|
||||
|
||||
/* BTC-AG control block to map bdaddr to BTA handle */
|
||||
typedef struct
|
||||
{
|
||||
|
@ -28,6 +28,8 @@
|
||||
|
||||
#define ESP_SPP_RINGBUF_SIZE 1000
|
||||
|
||||
#define BTC_SPP_INVALID_SCN 0x00
|
||||
|
||||
typedef enum {
|
||||
BTC_SPP_ACT_INIT = 0,
|
||||
BTC_SPP_ACT_UNINIT,
|
||||
@ -74,6 +76,10 @@ typedef union {
|
||||
UINT8 max_session;
|
||||
char name[ESP_SPP_SERVER_NAME_MAX + 1];
|
||||
} start_srv;
|
||||
//BTC_SPP_ACT_STOP_SRV
|
||||
struct stop_srv_arg {
|
||||
UINT8 scn;
|
||||
} stop_srv;
|
||||
//BTC_SPP_ACT_WRITE
|
||||
struct write_arg {
|
||||
UINT32 handle;
|
||||
|
@ -265,6 +265,10 @@ static void btc_create_server_fail_cb(void)
|
||||
{
|
||||
esp_spp_cb_param_t param;
|
||||
param.start.status = ESP_SPP_FAILURE;
|
||||
param.start.handle = 0;
|
||||
param.start.sec_id = 0;
|
||||
param.start.scn = BTC_SPP_INVALID_SCN;
|
||||
param.start.use_co = FALSE;
|
||||
btc_spp_cb_to_app(ESP_SPP_START_EVT, ¶m);
|
||||
}
|
||||
|
||||
@ -531,6 +535,7 @@ static void btc_spp_uninit(void)
|
||||
esp_spp_cb_param_t param;
|
||||
BTC_TRACE_ERROR("%s unable to malloc user data!", __func__);
|
||||
param.srv_stop.status = ESP_SPP_NO_RESOURCE;
|
||||
param.srv_stop.scn = spp_local_param.spp_slots[i]->scn;
|
||||
btc_spp_cb_to_app(ESP_SPP_SRV_STOP_EVT, ¶m);
|
||||
}
|
||||
BTA_JvFreeChannel(spp_local_param.spp_slots[i]->scn, BTA_JV_CONN_TYPE_RFCOMM,
|
||||
@ -672,61 +677,117 @@ static void btc_spp_start_srv(btc_spp_args_t *arg)
|
||||
if (ret != ESP_SPP_SUCCESS) {
|
||||
esp_spp_cb_param_t param;
|
||||
param.start.status = ret;
|
||||
param.start.handle = 0;
|
||||
param.start.sec_id = 0;
|
||||
param.start.scn = BTC_SPP_INVALID_SCN;
|
||||
param.start.use_co = FALSE;
|
||||
btc_spp_cb_to_app(ESP_SPP_START_EVT, ¶m);
|
||||
}
|
||||
}
|
||||
|
||||
static void btc_spp_stop_srv(void)
|
||||
static void btc_spp_stop_srv(btc_spp_args_t *arg)
|
||||
{
|
||||
esp_spp_status_t ret = ESP_SPP_SUCCESS;
|
||||
bool is_remove_all = false;
|
||||
uint8_t i, j, srv_cnt = 0;
|
||||
uint8_t *srv_scn_arr = osi_malloc(MAX_RFC_PORTS);
|
||||
if (arg->stop_srv.scn == BTC_SPP_INVALID_SCN) {
|
||||
is_remove_all = true;
|
||||
}
|
||||
|
||||
do {
|
||||
if (!is_spp_init()) {
|
||||
BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
|
||||
ret = ESP_SPP_NEED_INIT;
|
||||
break;
|
||||
}
|
||||
if (srv_scn_arr == NULL) {
|
||||
BTC_TRACE_ERROR("%s malloc srv_scn_arr failed\n", __func__);
|
||||
ret = ESP_SPP_NO_RESOURCE;
|
||||
break;
|
||||
}
|
||||
|
||||
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
// first, remove all connection
|
||||
for (size_t i = 1; i <= MAX_RFC_PORTS; i++) {
|
||||
if (spp_local_param.spp_slots[i] != NULL && spp_local_param.spp_slots[i]->connected) {
|
||||
BTA_JvRfcommClose(spp_local_param.spp_slots[i]->rfc_handle, (tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb,
|
||||
(void *)spp_local_param.spp_slots[i]->id);
|
||||
// [1] find all server
|
||||
for (i = 1; i <= MAX_RFC_PORTS; i++) {
|
||||
if (spp_local_param.spp_slots[i] != NULL && !spp_local_param.spp_slots[i]->connected &&
|
||||
spp_local_param.spp_slots[i]->sdp_handle > 0) {
|
||||
if (is_remove_all) {
|
||||
srv_scn_arr[srv_cnt++] = spp_local_param.spp_slots[i]->scn;
|
||||
} else if (spp_local_param.spp_slots[i]->scn == arg->stop_srv.scn) {
|
||||
srv_scn_arr[srv_cnt++] = spp_local_param.spp_slots[i]->scn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// second, remove all server
|
||||
for (size_t i = 1; i <= MAX_RFC_PORTS; i++) {
|
||||
if (spp_local_param.spp_slots[i] != NULL && !spp_local_param.spp_slots[i]->connected) {
|
||||
if (spp_local_param.spp_slots[i]->sdp_handle > 0) {
|
||||
BTA_JvDeleteRecord(spp_local_param.spp_slots[i]->sdp_handle);
|
||||
}
|
||||
if (srv_cnt == 0) {
|
||||
if (is_remove_all) {
|
||||
BTC_TRACE_ERROR("%s can not find any server!\n", __func__);
|
||||
} else {
|
||||
BTC_TRACE_ERROR("%s can not find server:%d!\n", __func__, arg->stop_srv.scn);
|
||||
}
|
||||
ret = ESP_SPP_NO_SERVER;
|
||||
break;
|
||||
}
|
||||
|
||||
if (spp_local_param.spp_slots[i]->rfc_handle > 0) {
|
||||
BTA_JvRfcommStopServer(spp_local_param.spp_slots[i]->rfc_handle,
|
||||
(void *)spp_local_param.spp_slots[i]->id);
|
||||
// [2] remove all local related connection
|
||||
for (j = 0; j < srv_cnt; j++) {
|
||||
for (i = 1; i <= MAX_RFC_PORTS; i++) {
|
||||
if (spp_local_param.spp_slots[i] != NULL && spp_local_param.spp_slots[i]->connected &&
|
||||
spp_local_param.spp_slots[i]->sdp_handle > 0 &&
|
||||
spp_local_param.spp_slots[i]->scn == srv_scn_arr[j]) {
|
||||
BTA_JvRfcommClose(spp_local_param.spp_slots[i]->rfc_handle,
|
||||
(tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb,
|
||||
(void *)spp_local_param.spp_slots[i]->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tBTA_JV_FREE_SCN_USER_DATA *user_data = osi_malloc(sizeof(tBTA_JV_FREE_SCN_USER_DATA));
|
||||
if (user_data) {
|
||||
user_data->server_status = BTA_JV_SERVER_RUNNING;
|
||||
user_data->slot_id = spp_local_param.spp_slots[i]->id;
|
||||
} else {
|
||||
esp_spp_cb_param_t param;
|
||||
BTC_TRACE_ERROR("%s unable to malloc user data!", __func__);
|
||||
param.srv_stop.status = ESP_SPP_NO_RESOURCE;
|
||||
btc_spp_cb_to_app(ESP_SPP_SRV_STOP_EVT, ¶m);
|
||||
// [3] remove all server
|
||||
for (j = 0; j < srv_cnt; j++) {
|
||||
for (i = 1; i <= MAX_RFC_PORTS; i++) {
|
||||
if (spp_local_param.spp_slots[i] != NULL && !spp_local_param.spp_slots[i]->connected &&
|
||||
spp_local_param.spp_slots[i]->sdp_handle > 0 &&
|
||||
spp_local_param.spp_slots[i]->scn == srv_scn_arr[j]) {
|
||||
if (spp_local_param.spp_slots[i]->sdp_handle > 0) {
|
||||
BTA_JvDeleteRecord(spp_local_param.spp_slots[i]->sdp_handle);
|
||||
}
|
||||
|
||||
if (spp_local_param.spp_slots[i]->rfc_handle > 0) {
|
||||
BTA_JvRfcommStopServer(spp_local_param.spp_slots[i]->rfc_handle,
|
||||
(void *)spp_local_param.spp_slots[i]->id);
|
||||
}
|
||||
|
||||
tBTA_JV_FREE_SCN_USER_DATA *user_data = osi_malloc(sizeof(tBTA_JV_FREE_SCN_USER_DATA));
|
||||
if (user_data) {
|
||||
user_data->server_status = BTA_JV_SERVER_RUNNING;
|
||||
user_data->slot_id = spp_local_param.spp_slots[i]->id;
|
||||
} else {
|
||||
esp_spp_cb_param_t param;
|
||||
BTC_TRACE_ERROR("%s unable to malloc user data!", __func__);
|
||||
param.srv_stop.status = ESP_SPP_NO_RESOURCE;
|
||||
param.srv_stop.scn = spp_local_param.spp_slots[i]->scn;
|
||||
btc_spp_cb_to_app(ESP_SPP_SRV_STOP_EVT, ¶m);
|
||||
}
|
||||
BTA_JvFreeChannel(spp_local_param.spp_slots[i]->scn, BTA_JV_CONN_TYPE_RFCOMM,
|
||||
(tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb, (void *)user_data);
|
||||
}
|
||||
BTA_JvFreeChannel(spp_local_param.spp_slots[i]->scn, BTA_JV_CONN_TYPE_RFCOMM,
|
||||
(tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb, (void *)user_data);
|
||||
}
|
||||
}
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
} while(0);
|
||||
} while (0);
|
||||
|
||||
if (ret != ESP_SPP_SUCCESS) {
|
||||
esp_spp_cb_param_t param;
|
||||
param.srv_stop.status = ret;
|
||||
param.srv_stop.scn = BTC_SPP_INVALID_SCN;
|
||||
btc_spp_cb_to_app(ESP_SPP_SRV_STOP_EVT, ¶m);
|
||||
}
|
||||
|
||||
if (srv_scn_arr) {
|
||||
osi_free(srv_scn_arr);
|
||||
srv_scn_arr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void btc_spp_write(btc_spp_args_t *arg)
|
||||
@ -849,7 +910,7 @@ void btc_spp_call_handler(btc_msg_t *msg)
|
||||
btc_spp_start_srv(arg);
|
||||
break;
|
||||
case BTC_SPP_ACT_STOP_SRV:
|
||||
btc_spp_stop_srv();
|
||||
btc_spp_stop_srv(arg);
|
||||
break;
|
||||
case BTC_SPP_ACT_WRITE:
|
||||
btc_spp_write(arg);
|
||||
@ -876,6 +937,8 @@ void btc_spp_cb_handler(btc_msg_t *msg)
|
||||
param.disc_comp.status = p_data->disc_comp.status;
|
||||
param.disc_comp.scn_num = p_data->disc_comp.scn_num;
|
||||
memcpy(param.disc_comp.scn, p_data->disc_comp.scn, p_data->disc_comp.scn_num);
|
||||
memcpy(param.disc_comp.service_name, p_data->disc_comp.service_name,
|
||||
p_data->disc_comp.scn_num * sizeof(const char *));
|
||||
btc_spp_cb_to_app(ESP_SPP_DISCOVERY_COMP_EVT, ¶m);
|
||||
break;
|
||||
case BTA_JV_RFCOMM_CL_INIT_EVT:
|
||||
@ -909,6 +972,7 @@ void btc_spp_cb_handler(btc_msg_t *msg)
|
||||
param.start.status = p_data->rfc_start.status;
|
||||
param.start.handle = p_data->rfc_start.handle;
|
||||
param.start.sec_id = p_data->rfc_start.sec_id;
|
||||
param.start.scn = p_data->rfc_start.scn;
|
||||
param.start.use_co = p_data->rfc_start.use_co;
|
||||
btc_spp_cb_to_app(ESP_SPP_START_EVT, ¶m);
|
||||
break;
|
||||
@ -1130,6 +1194,7 @@ void btc_spp_cb_handler(btc_msg_t *msg)
|
||||
case BTA_JV_FREE_SCN_EVT:
|
||||
if (p_data->free_scn.server_status == BTA_JV_SERVER_RUNNING) {
|
||||
param.srv_stop.status = p_data->free_scn.status;
|
||||
param.srv_stop.scn = p_data->free_scn.scn;
|
||||
btc_spp_cb_to_app(ESP_SPP_SRV_STOP_EVT, ¶m);
|
||||
}
|
||||
break;
|
||||
|
@ -120,13 +120,6 @@
|
||||
#define UC_BT_GATTC_ENABLE FALSE
|
||||
#endif
|
||||
|
||||
//BLUFI
|
||||
#ifdef CONFIG_BT_BLE_BLUFI_ENABLE
|
||||
#define UC_BT_BLUFI_ENABLE CONFIG_BT_BLE_BLUFI_ENABLE
|
||||
#else
|
||||
#define UC_BT_BLUFI_ENABLE FALSE
|
||||
#endif
|
||||
|
||||
//GATTC CACHE
|
||||
#ifdef CONFIG_BT_GATTC_CACHE_NVS_FLASH
|
||||
#define UC_BT_GATTC_CACHE_NVS_FLASH_ENABLED CONFIG_BT_GATTC_CACHE_NVS_FLASH
|
||||
@ -134,6 +127,13 @@
|
||||
#define UC_BT_GATTC_CACHE_NVS_FLASH_ENABLED FALSE
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_GATTC_CONNECT_RETRY_COUNT
|
||||
#define UC_BT_GATTC_CONNECT_RETRY_COUNT CONFIG_BT_GATTC_CONNECT_RETRY_COUNT
|
||||
#else
|
||||
#define UC_BT_GATTC_CONNECT_RETRY_COUNT 0
|
||||
#endif
|
||||
|
||||
|
||||
//SMP
|
||||
#ifdef CONFIG_BT_SMP_ENABLE
|
||||
#define UC_BT_SMP_ENABLE CONFIG_BT_SMP_ENABLE
|
||||
@ -203,6 +203,12 @@
|
||||
#define UC_BT_ACL_CONNECTIONS 5
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_MULTI_CONNECTION_ENBALE
|
||||
#define UC_BT_MULTI_CONNECTION_ENBALE CONFIG_BT_MULTI_CONNECTION_ENBALE
|
||||
#else
|
||||
#define UC_BT_MULTI_CONNECTION_ENBALE FALSE
|
||||
#endif
|
||||
|
||||
//BT_BLE_ESTAB_LINK_CONN_TOUT
|
||||
#ifdef CONFIG_BT_BLE_ESTAB_LINK_CONN_TOUT
|
||||
#define UC_BT_BLE_ESTAB_LINK_CONN_TOUT CONFIG_BT_BLE_ESTAB_LINK_CONN_TOUT
|
||||
@ -224,6 +230,14 @@
|
||||
#define UC_CONFIG_BT_GATTS_PPCP_CHAR_GAP FALSE
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CONFIG_BT_GATT_MAX_SR_PROFILES
|
||||
#define UC_CONFIG_BT_GATT_MAX_SR_PROFILES CONFIG_BT_GATT_MAX_SR_PROFILES
|
||||
#else
|
||||
#define UC_CONFIG_BT_GATT_MAX_SR_PROFILES 8
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MODE
|
||||
#define UC_BT_GATTS_SEND_SERVICE_CHANGE_MODE CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MODE
|
||||
#else
|
||||
@ -381,10 +395,4 @@
|
||||
#define UC_BT_LOG_BTIF_TRACE_LEVEL UC_TRACE_LEVEL_WARNING
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_LOG_BLUFI_TRACE_LEVEL
|
||||
#define UC_BT_LOG_BLUFI_TRACE_LEVEL CONFIG_BT_LOG_BLUFI_TRACE_LEVEL
|
||||
#else
|
||||
#define UC_BT_LOG_BLUFI_TRACE_LEVEL UC_TRACE_LEVEL_WARNING
|
||||
#endif
|
||||
|
||||
#endif /* __BLUEDROID_USER_CONFIG_H__ */
|
||||
|
@ -21,6 +21,7 @@
|
||||
#define BT_TARGET_H
|
||||
|
||||
#include <bt_common.h>
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#ifndef BUILDCFG
|
||||
#define BUILDCFG
|
||||
@ -190,18 +191,24 @@
|
||||
#define GATTC_INCLUDED FALSE
|
||||
#endif /* UC_BT_GATTC_ENABLE */
|
||||
|
||||
#if (UC_BT_BLUFI_ENABLE)
|
||||
#define BLUFI_INCLUDED TRUE
|
||||
#else
|
||||
#define BLUFI_INCLUDED FALSE
|
||||
#endif /* UC_BT_BLUFI_ENABLE */
|
||||
|
||||
#if (UC_BT_GATTC_ENABLE && UC_BT_GATTC_CACHE_NVS_FLASH_ENABLED)
|
||||
#define GATTC_CACHE_NVS TRUE
|
||||
#else
|
||||
#define GATTC_CACHE_NVS FALSE
|
||||
#endif /* UC_BT_GATTC_ENABLE && UC_BT_GATTC_CACHE_NVS_FLASH_ENABLED */
|
||||
|
||||
#if (UC_BT_GATTC_ENABLE && UC_BT_GATTC_CONNECT_RETRY_COUNT)
|
||||
#define GATTC_CONNECT_RETRY_COUNT UC_BT_GATTC_CONNECT_RETRY_COUNT
|
||||
#else
|
||||
#define GATTC_CONNECT_RETRY_COUNT 0
|
||||
#endif /* UC_BT_GATTC_ENABLE && UC_BT_GATTC_CONNECT_RETRY_COUNT */
|
||||
|
||||
#if (GATTC_CONNECT_RETRY_COUNT > 0)
|
||||
#define GATTC_CONNECT_RETRY_EN TRUE
|
||||
#else
|
||||
#define GATTC_CONNECT_RETRY_EN FALSE
|
||||
#endif
|
||||
|
||||
#if (UC_BT_SMP_ENABLE)
|
||||
#define SMP_INCLUDED TRUE
|
||||
#if (BLE_INCLUDED == TRUE)
|
||||
@ -237,10 +244,25 @@
|
||||
#define GATT_MAX_PHY_CHANNEL UC_BT_ACL_CONNECTIONS
|
||||
#endif /* UC_BT_ACL_CONNECTIONS */
|
||||
|
||||
#ifdef UC_BT_MULTI_CONNECTION_ENBALE
|
||||
#define BT_MULTI_CONNECTION_ENBALE UC_BT_MULTI_CONNECTION_ENBALE
|
||||
#endif
|
||||
|
||||
#if(BT_MULTI_CONNECTION_ENBALE && (CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3))
|
||||
#define BLE_CE_LEN_MIN 5
|
||||
#else
|
||||
#define BLE_CE_LEN_MIN 0
|
||||
#endif
|
||||
|
||||
#ifdef UC_BT_BLE_ESTAB_LINK_CONN_TOUT
|
||||
#define BLE_ESTABLISH_LINK_CONNECTION_TIMEOUT UC_BT_BLE_ESTAB_LINK_CONN_TOUT
|
||||
#endif
|
||||
|
||||
#ifdef SOC_BLE_DONT_UPDATE_OWN_RPA
|
||||
#define BLE_UPDATE_BLE_ADDR_TYPE_RPA FALSE
|
||||
#else
|
||||
#define BLE_UPDATE_BLE_ADDR_TYPE_RPA TRUE
|
||||
#endif
|
||||
//------------------Added from bdroid_buildcfg.h---------------------
|
||||
#ifndef L2CAP_EXTFEA_SUPPORTED_MASK
|
||||
#define L2CAP_EXTFEA_SUPPORTED_MASK (L2CAP_EXTFEA_ENH_RETRANS | L2CAP_EXTFEA_STREAM_MODE | L2CAP_EXTFEA_NO_CRC | L2CAP_EXTFEA_FIXED_CHNLS)
|
||||
@ -1224,7 +1246,7 @@
|
||||
#endif
|
||||
|
||||
#ifndef GATT_MAX_SR_PROFILES
|
||||
#define GATT_MAX_SR_PROFILES 8 /* max is 32 */
|
||||
#define GATT_MAX_SR_PROFILES UC_CONFIG_BT_GATT_MAX_SR_PROFILES
|
||||
#endif
|
||||
|
||||
#ifndef GATT_MAX_APPS
|
||||
|
@ -203,7 +203,6 @@ static inline void trc_dump_buffer(const char *prefix, uint8_t *data, uint16_t l
|
||||
#define GATT_INITIAL_TRACE_LEVEL UC_BT_LOG_GATT_TRACE_LEVEL
|
||||
#define SMP_INITIAL_TRACE_LEVEL UC_BT_LOG_SMP_TRACE_LEVEL
|
||||
#define BTIF_INITIAL_TRACE_LEVEL UC_BT_LOG_BTIF_TRACE_LEVEL
|
||||
#define BLUFI_INITIAL_TRACE_LEVEL UC_BT_LOG_BLUFI_TRACE_LEVEL
|
||||
|
||||
// btla-specific --
|
||||
|
||||
@ -360,14 +359,6 @@ extern UINT8 btif_trace_level;
|
||||
#define HCI_TRACE_EVENT(fmt, args...) {if (HCI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_EVENT && BT_LOG_LEVEL_CHECK(HCI,EVENT)) BT_PRINT_D("BT_HCI", fmt,## args);}
|
||||
#define HCI_TRACE_DEBUG(fmt, args...) {if (HCI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_DEBUG && BT_LOG_LEVEL_CHECK(HCI,DEBUG)) BT_PRINT_D("BT_HCI", fmt,## args);}
|
||||
|
||||
/* define traces for BLUFI */
|
||||
#define BLUFI_TRACE_ERROR(fmt, args...) {if (BLUFI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_ERROR && BT_LOG_LEVEL_CHECK(BLUFI, ERROR)) BT_PRINT_E("BT_BLUFI", fmt, ## args);}
|
||||
#define BLUFI_TRACE_WARNING(fmt, args...) {if (BLUFI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_WARNING && BT_LOG_LEVEL_CHECK(BLUFI, WARNING)) BT_PRINT_W("BT_BLUFI", fmt, ## args);}
|
||||
#define BLUFI_TRACE_API(fmt, args...) {if (BLUFI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_API && BT_LOG_LEVEL_CHECK(BLUFI,API)) BT_PRINT_I("BT_BLUFI", fmt, ## args);}
|
||||
#define BLUFI_TRACE_EVENT(fmt, args...) {if (BLUFI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_EVENT && BT_LOG_LEVEL_CHECK(BLUFI,EVENT)) BT_PRINT_D("BT_BLUFI", fmt, ## args);}
|
||||
#define BLUFI_TRACE_DEBUG(fmt, args...) {if (BLUFI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_DEBUG && BT_LOG_LEVEL_CHECK(BLUFI,DEBUG)) BT_PRINT_D("BT_BLUFI", fmt, ## args);}
|
||||
#define BLUFI_TRACE_VERBOSE(fmt, args...) {if (BLUFI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_VERBOSE && BT_LOG_LEVEL_CHECK(BLUFI,VERBOSE)) BT_PRINT_V("BT_BLUFI", fmt, ## args);}
|
||||
|
||||
#else
|
||||
#define LOG_ERROR(fmt, args...)
|
||||
#define LOG_WARN(fmt, args...)
|
||||
@ -518,13 +509,6 @@ extern UINT8 btif_trace_level;
|
||||
#define APPL_TRACE_DEBUG(fmt, args...)
|
||||
#define APPL_TRACE_VERBOSE(fmt, args...)
|
||||
|
||||
/* define traces for BLUFI */
|
||||
#define BLUFI_TRACE_ERROR(fmt, args...)
|
||||
#define BLUFI_TRACE_WARNING(fmt, args...)
|
||||
#define BLUFI_TRACE_API(fmt, args...)
|
||||
#define BLUFI_TRACE_EVENT(fmt, args...)
|
||||
#define BLUFI_TRACE_DEBUG(fmt, args...)
|
||||
#define BLUFI_TRACE_VERBOSE(fmt, args...)
|
||||
#endif ///!UC_BT_STACK_NO_LOG
|
||||
|
||||
|
||||
|
@ -177,30 +177,16 @@ bool hci_hal_h4_task_post(uint32_t timeout)
|
||||
|
||||
#if (C2H_FLOW_CONTROL_INCLUDED == TRUE)
|
||||
static void hci_packet_complete(BT_HDR *packet){
|
||||
uint8_t type, num_handle;
|
||||
uint8_t type;
|
||||
uint16_t handle;
|
||||
uint16_t handles[MAX_L2CAP_LINKS + 4];
|
||||
uint16_t num_packets[MAX_L2CAP_LINKS + 4];
|
||||
uint16_t num_packets = 1;
|
||||
uint8_t *stream = packet->data + packet->offset;
|
||||
tL2C_LCB *p_lcb = NULL;
|
||||
|
||||
STREAM_TO_UINT8(type, stream);
|
||||
if (type == DATA_TYPE_ACL/* || type == DATA_TYPE_SCO*/) {
|
||||
STREAM_TO_UINT16(handle, stream);
|
||||
handle = handle & HCI_DATA_HANDLE_MASK;
|
||||
p_lcb = l2cu_find_lcb_by_handle(handle);
|
||||
if (p_lcb) {
|
||||
p_lcb->completed_packets++;
|
||||
}
|
||||
if (esp_vhci_host_check_send_available()){
|
||||
num_handle = l2cu_find_completed_packets(handles, num_packets);
|
||||
if (num_handle > 0){
|
||||
btsnd_hcic_host_num_xmitted_pkts (num_handle, handles, num_packets);
|
||||
}
|
||||
} else {
|
||||
//Send HCI_Host_Number_of_Completed_Packets next time.
|
||||
}
|
||||
|
||||
btsnd_hcic_host_num_xmitted_pkts(1, &handle, &num_packets);
|
||||
}
|
||||
}
|
||||
#endif ///C2H_FLOW_CONTROL_INCLUDED == TRUE
|
||||
|
@ -93,6 +93,10 @@
|
||||
#include "bta_hf_client_int.h"
|
||||
#endif
|
||||
|
||||
#if BTA_AG_INCLUDED == TRUE
|
||||
#include "bta_ag_int.h"
|
||||
#endif
|
||||
|
||||
#if BTA_SDP_INCLUDED == TRUE
|
||||
#include "bta_sdp_int.h"
|
||||
#endif
|
||||
@ -216,6 +220,12 @@ void BTE_DeinitStack(void)
|
||||
osi_free(bta_hf_client_cb_ptr);
|
||||
bta_hf_client_cb_ptr = NULL;
|
||||
}
|
||||
#endif
|
||||
#if (defined BTA_AG_INCLUDED && BTA_AG_INCLUDED == TRUE)
|
||||
if (bta_ag_cb_ptr){
|
||||
osi_free(bta_ag_cb_ptr);
|
||||
bta_ag_cb_ptr = NULL;
|
||||
}
|
||||
#endif
|
||||
if (bta_dm_conn_srvcs_ptr){
|
||||
osi_free(bta_dm_conn_srvcs_ptr);
|
||||
@ -374,6 +384,12 @@ bt_status_t BTE_InitStack(void)
|
||||
}
|
||||
memset((void *)bta_hf_client_cb_ptr, 0, sizeof(tBTA_HF_CLIENT_CB));
|
||||
#endif
|
||||
#if (defined BTA_AG_INCLUDED && BTA_AG_INCLUDED == TRUE)
|
||||
if ((bta_ag_cb_ptr = (tBTA_AG_CB *)osi_malloc(sizeof(tBTA_AG_CB))) == NULL) {
|
||||
goto error_exit;
|
||||
}
|
||||
memset((void *)bta_ag_cb_ptr, 0, sizeof(tBTA_AG_CB));
|
||||
#endif
|
||||
#if (defined BTA_JV_INCLUDED && BTA_JV_INCLUDED == TRUE)
|
||||
if ((bta_jv_cb_ptr = (tBTA_JV_CB *)osi_malloc(sizeof(tBTA_JV_CB))) == NULL) {
|
||||
goto error_exit;
|
||||
|
@ -954,6 +954,7 @@ void btm_read_remote_version_complete (UINT8 *p)
|
||||
if (HCI_LE_DATA_LEN_EXT_SUPPORTED(p_acl_cb->peer_le_features)) {
|
||||
uint16_t data_length = controller_get_interface()->get_ble_default_data_packet_length();
|
||||
uint16_t data_txtime = controller_get_interface()->get_ble_default_data_packet_txtime();
|
||||
p_acl_cb->data_len_updating = true;
|
||||
btsnd_hcic_ble_set_data_length(p_acl_cb->hci_handle, data_length, data_txtime);
|
||||
}
|
||||
l2cble_notify_le_connection (p_acl_cb->remote_addr);
|
||||
|
@ -2076,6 +2076,30 @@ void btm_ble_create_ll_conn_complete (UINT8 status)
|
||||
btm_ble_update_mode_operation(HCI_ROLE_UNKNOWN, NULL, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
** Function btm_ble_create_conn_cancel_complete
|
||||
**
|
||||
** Description LE connection cancel complete.
|
||||
**
|
||||
******************************************************************************/
|
||||
void btm_ble_create_conn_cancel_complete (UINT8 *p)
|
||||
{
|
||||
UINT8 status;
|
||||
|
||||
STREAM_TO_UINT8 (status, p);
|
||||
|
||||
switch (status) {
|
||||
case HCI_SUCCESS:
|
||||
if (btm_ble_get_conn_st() == BLE_CONN_CANCEL) {
|
||||
btm_ble_set_conn_st (BLE_CONN_IDLE);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
** Function btm_proc_smp_cback
|
||||
**
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user