Compare commits
1104 commits
Author | SHA1 | Date | |
---|---|---|---|
1f53447813 | |||
76ccd1ea13 | |||
3f47cb300b | |||
0007835a5a | |||
c8bd1acde2 | |||
9d2f1715df | |||
02177f65e1 | |||
46430fc77a | |||
9da22fbec4 | |||
ca431d2e46 | |||
3d255ed6f8 | |||
1c8b438bca | |||
3de5c47802 | |||
ea04534281 | |||
e62f254e7e | |||
9377759d3b | |||
59b7f37e26 | |||
7fd5b7a6a7 | |||
94f4b19460 | |||
eb68b98cf5 | |||
196b169fbe | |||
d6618ade1a | |||
9b901dd28e | |||
713ffc33f2 | |||
2247c673fc | |||
a44c16a426 | |||
fb5fdca66a | |||
89d650d87b | |||
e0482d6d1b | |||
81598323c6 | |||
6695835808 | |||
b929b419af | |||
80388188f7 | |||
502842a30b | |||
aa9fc5d817 | |||
1ee36e7429 | |||
15039f6b5d | |||
e93083073c | |||
9355f678e3 | |||
4d90cd2e3f | |||
da8cd47dea | |||
e492974415 | |||
96c5d12e2a | |||
965ac84918 | |||
325e41ae6a | |||
a9cb7ab7be | |||
7fffc50d7c | |||
233cb02993 | |||
54b72dcf64 | |||
8c82ce0722 | |||
86596ac92f | |||
259827b031 | |||
3479303454 | |||
3fb61f7695 | |||
dd84558cd6 | |||
297bd14f7b | |||
30de144aea | |||
13c22c0c71 | |||
d4790c8ede | |||
5003aca5c7 | |||
cfeb8036e0 | |||
2036cda4d9 | |||
29190681cc | |||
ba62fd2dd2 | |||
ecdd101586 | |||
25d38eba2c | |||
927c0b8eac | |||
87f433d657 | |||
0b24e047c5 | |||
31ec8687e4 | |||
8b2ee08d55 | |||
aaf1e8b2b1 | |||
6694583291 | |||
fedd9cb0d7 | |||
df2b297d91 | |||
4127d0993b | |||
11525b74ae | |||
8e23d07de4 | |||
5f8be3e6ea | |||
07c21e6e7d | |||
df282f348c | |||
3a560c79f9 | |||
64b2750de3 | |||
a2f8424b74 | |||
f368875ea2 | |||
17e0b6f2cc | |||
2ef7438131 | |||
8c5b66d715 | |||
3f6cb4e795 | |||
7a6bab7b10 | |||
13c4934a37 | |||
75e8c162ed | |||
0c3a9c6b5a | |||
32afc08622 | |||
d62fe15a26 | |||
3b56d718c6 | |||
32bbd0cc71 | |||
7ea0e3b933 | |||
12ee7b7e39 | |||
cc48b88713 | |||
406fb7ea44 | |||
edc7a59091 | |||
d890a492bb | |||
3defa16553 | |||
6141e26999 | |||
dd9ba9e0ef | |||
e3784fa9c7 | |||
954da749eb | |||
6eced34422 | |||
140f43f4c1 | |||
ed638a5f5a | |||
b774d61713 | |||
bfdae2a7a7 | |||
0859e3442c | |||
5e20a17131 | |||
f576ef27ce | |||
c35be7c066 | |||
1a57b55d8f | |||
1384aad51a | |||
181e2c436e | |||
fd442fb9da | |||
719f712307 | |||
4b1580cc70 | |||
a6670d99a8 | |||
38430ac259 | |||
60c6495fa3 | |||
578dbaa431 | |||
223ea26eb4 | |||
c39e10b2e7 | |||
770bbfc6f6 | |||
a08fc6a381 | |||
a986ecf7c3 | |||
f0bddb277c | |||
5c0094cbd6 | |||
e97f3bca26 | |||
d53b6ad23e | |||
576ca6457f | |||
ea4e080bae | |||
3a53d96526 | |||
6e3387c830 | |||
c558e1a559 | |||
3800cb18a9 | |||
007f9c9798 | |||
6b78ee9a4e | |||
bb5d5546ce | |||
bb90d50ba1 | |||
ed47d47155 | |||
b4ef18b2fa | |||
18cfaf7fa2 | |||
ef9b00103e | |||
71167f0ba6 | |||
9ed56b1485 | |||
4040005056 | |||
91928592d0 | |||
22975df423 | |||
c2560498b6 | |||
5e15ec6488 | |||
3c150a5e99 | |||
3cc5505b69 | |||
7b193ee014 | |||
6a36a398bd | |||
e9aed001bc | |||
58517dfcbd | |||
ddf723f88d | |||
66fe7abf79 | |||
848f801460 | |||
38b82aeeeb | |||
52c709bdb7 | |||
391a84726f | |||
ae91d6b4b1 | |||
a08adccfd5 | |||
1fa9dde049 | |||
078359127b | |||
fa618ad86c | |||
f83f035855 | |||
d0ddb7221e | |||
0b85b76778 | |||
f6a2c4ea3f | |||
a330f59b8e | |||
51205eb809 | |||
fbffcc2dfc | |||
faeb71de00 | |||
3559402781 | |||
b7b23b712f | |||
e9ee15efde | |||
e823ead4b0 | |||
474dc33e12 | |||
22b262ce73 | |||
55f3a92211 | |||
aed5457332 | |||
f564e6bb5f | |||
e4da7c66e0 | |||
6eac73103d | |||
12f17211e6 | |||
417f32c65d | |||
093550ecbf | |||
f15b86158b | |||
a30364189a | |||
4425a67433 | |||
69c2e7e2b6 | |||
399150b142 | |||
9d003fe52f | |||
d6128852b2 | |||
55daec98dc | |||
94defe6ba2 | |||
dca85a7b6b | |||
3829dd2f20 | |||
e77dba152d | |||
bf8e77ea4e | |||
c0239b41c9 | |||
e09bdc0c07 | |||
29914b5a1f | |||
fa6c52633f | |||
9e5aed5df6 | |||
c56142ccec | |||
afde635051 | |||
c7de205029 | |||
1addd8da3a | |||
e24f500e57 | |||
fcc4f6d39f | |||
59dc4413bb | |||
612cb23759 | |||
d94efe528a | |||
5640293e8f | |||
f70adde9a9 | |||
c932ff45a3 | |||
7342a3f8a7 | |||
90ea58e206 | |||
34fa389054 | |||
432f12e156 | |||
5a0d085451 | |||
0e861e76a3 | |||
918b20f3cf | |||
99402348eb | |||
356814fe9c | |||
739b901e0d | |||
758d9aa168 | |||
7f3fcbd8e7 | |||
dc782732e0 | |||
a0134ff35e | |||
79855ff02d | |||
6d51c1a9f9 | |||
905356da13 | |||
21d6abe30b | |||
b91448dfa4 | |||
7e6d5c2971 | |||
fbb682ae15 | |||
3545f1fab5 | |||
08b12f2346 | |||
a0a2881ab0 | |||
c850bae186 | |||
3b090d97c7 | |||
dbd9d32daf | |||
cc4aa440a0 | |||
b756841522 | |||
ed1b27e40b | |||
a24ac862de | |||
c5c1979d37 | |||
9acf177036 | |||
2d42b91c7b | |||
fbf9bb9e64 | |||
baaa3da23e | |||
8df0f7dd01 | |||
b70677cce6 | |||
42cbe85a49 | |||
dbcac67aab | |||
0a85ccdc56 | |||
da45afdf27 | |||
79b06879fe | |||
9b6ba3c009 | |||
0ceb45ee78 | |||
d80f362a2b | |||
04bce213e6 | |||
ae554aa256 | |||
c37e7cfb0e | |||
2942868799 | |||
362eadd821 | |||
14baf5df6c | |||
c954d22d81 | |||
f36183f2b5 | |||
314c46b91a | |||
6af70ee511 | |||
7000323c74 | |||
a38cfc889e | |||
ae6375d900 | |||
2137a12971 | |||
4151c09e2c | |||
6677fac2ab | |||
be9711d92e | |||
8e07bab71f | |||
85f3814f67 | |||
42dee52e65 | |||
352f078be7 | |||
f5f13c968c | |||
5ea65cab08 | |||
809ca640a1 | |||
91beb8670f | |||
a26ee64dc0 | |||
8b77c5ef4c | |||
effdc6e212 | |||
25ac43dae9 | |||
6463c91a4f | |||
263af6f642 | |||
201a8174c6 | |||
6a9b6ae77b | |||
9fb2352b08 | |||
2f8549aaae | |||
8248f524f5 | |||
a6472c8dd9 | |||
cd1bcb101d | |||
7b7781360f | |||
5eb2ac15ff | |||
0cfda4c026 | |||
d59bbcf86c | |||
2d44b47050 | |||
651147df57 | |||
ac937eda24 | |||
83f2382791 | |||
2e754c7832 | |||
f80f673e21 | |||
0fb597f2fa | |||
12c930893c | |||
e5a604552e | |||
10be59cc15 | |||
37fe6a2fa6 | |||
63ac4d2a3d | |||
88d0003b75 | |||
a7b5050382 | |||
5fb226f4c9 | |||
07de8b238b | |||
ba12ed2cce | |||
82fd325b7a | |||
999b246fd2 | |||
3d40056f4f | |||
0fb4a68332 | |||
0da6e128eb | |||
f9ffa252f6 | |||
d866e6bd34 | |||
10d54f228b | |||
c1f11cfaa9 | |||
5e05a951f2 | |||
bb4f2e5678 | |||
22d10ba03a | |||
fe210b05f0 | |||
1d5fc88ae9 | |||
3dc74dc632 | |||
4069ac5262 | |||
35a1701236 | |||
0b81c0de18 | |||
667dd6a210 | |||
7d9134757f | |||
361cb612a7 | |||
82f3ce392e | |||
247d79ea7c | |||
bfef0b5d6a | |||
960b81d484 | |||
14757201a5 | |||
1537488e74 | |||
0de3563ddb | |||
42557bf484 | |||
53efcec1fa | |||
fe99f1144a | |||
6e07fd7019 | |||
6aaf1c356c | |||
92ad29ab33 | |||
cbf4a843e2 | |||
9d12801f01 | |||
a7e617657a | |||
fb9c6009a2 | |||
a98792a79f | |||
6bda852052 | |||
579620ce0e | |||
93828d867e | |||
b72110fe8a | |||
1a993da8fc | |||
9befc02331 | |||
2464cdadc9 | |||
cf2b24971b | |||
7b2c687789 | |||
0b68334e95 | |||
edec34f684 | |||
3594cf5167 | |||
7927af021e | |||
1ec48fcf37 | |||
4faf139523 | |||
da853386a6 | |||
38ff8e5283 | |||
5186fa2ef1 | |||
da29a5f8e3 | |||
586fb9a7fe | |||
f069cef73a | |||
9ef28c7eae | |||
bba5a973ba | |||
aa1f408825 | |||
c48cfb6b9d | |||
a3417b82b0 | |||
8b3f29325d | |||
5d19196e54 | |||
fb0607f0f8 | |||
a02481bc99 | |||
8fca9ced8e | |||
a6b14a0731 | |||
08439a878d | |||
fd3d733e4b | |||
a864ebbce4 | |||
d291ec53e6 | |||
7603e104c4 | |||
47bda9b6be | |||
c745199d53 | |||
5756248949 | |||
7ca3bea701 | |||
2a3edc9136 | |||
6694e69788 | |||
6b7681c516 | |||
e0e6f82c46 | |||
00944ec677 | |||
d9ea888323 | |||
d6e8e7dab4 | |||
a56b520215 | |||
43b9679bcc | |||
e73ac7d26f | |||
db54175d8d | |||
f07ed3fc01 | |||
2934c6bbe7 | |||
3a070bd332 | |||
f9e6a78882 | |||
a3c80cedb9 | |||
4d0051ad4d | |||
b67d3cc6ea | |||
ac2a31455e | |||
bd3f8fa3c5 | |||
9bb6286bb2 | |||
0812b89909 | |||
d41197e1e7 | |||
3030422830 | |||
ece7cfee38 | |||
1249d9cf8d | |||
d133ed898f | |||
52c26d31c4 | |||
5fc05b102b | |||
95b8c2683e | |||
994badaef9 | |||
16e6a20b31 | |||
353cfe723c | |||
ba241db968 | |||
5fdd731166 | |||
3872965362 | |||
f09e84976a | |||
f5d6b7ed0f | |||
f6439121b4 | |||
95f69d92a8 | |||
027f1c3e64 | |||
bad3384365 | |||
aaf0d1eb86 | |||
7ef5902c3d | |||
44edc187bc | |||
11877b4b6b | |||
88fdc46e03 | |||
938aa0db71 | |||
4f7476c084 | |||
f8a399d346 | |||
aa1670e5d4 | |||
367104166e | |||
af4f1e1c30 | |||
2be999c707 | |||
36519a9742 | |||
4a93babb58 | |||
452666b43e | |||
82b5fb5073 | |||
d6656ccde1 | |||
49808b8f1c | |||
9ccc1697cf | |||
120632b4a8 | |||
94854177e2 | |||
6565652e43 | |||
0ef0a21d9e | |||
0c65a4db9c | |||
63322fdfb2 | |||
238e8b4dcf | |||
7bb50da178 | |||
0d3ff7b785 | |||
983d858570 | |||
5e7acd4dc2 | |||
cd75e50c28 | |||
7c54b7cd50 | |||
a8acaf08d5 | |||
4ef4bdd0a5 | |||
f9b32f8139 | |||
bd1a6bf94e | |||
23a481600a | |||
1c0e33be79 | |||
cfed856720 | |||
dcbb5f6271 | |||
5c25ec4d11 | |||
cfabf0e6a2 | |||
91a6ce6576 | |||
1abc95a08e | |||
a6d348917d | |||
3cd7b7efd1 | |||
12ea1bd492 | |||
2866ae0555 | |||
062a8535ec | |||
8b57670121 | |||
c76b8235f4 | |||
0e5b18635b | |||
faf22609f4 | |||
92ecbf7064 | |||
835a6aa6e6 | |||
728e417e04 | |||
a4adc257e8 | |||
106731cec1 | |||
87337e12fc | |||
58243bc14a | |||
610eefc2ff | |||
3e00adacc0 | |||
edf3a27920 | |||
a69d78ac73 | |||
5281908018 | |||
7ba88a6800 | |||
fc582606f2 | |||
52a8dcc65b | |||
9c47f874c4 | |||
3f676a5a16 | |||
81805129f8 | |||
927e9b8150 | |||
82afa72c13 | |||
ab1491be69 | |||
9195b49c18 | |||
d3158897c2 | |||
280dc091d2 | |||
ca86d5febf | |||
5803971adc | |||
86dbd590db | |||
ecd1d57eec | |||
6a1a4b62a0 | |||
f9f923d29c | |||
b708fac68d | |||
9f40b0734c | |||
ceb4fb3298 | |||
efde9132a8 | |||
1398ff0de6 | |||
c666b18a12 | |||
d2a1f8937e | |||
1bdec853e1 | |||
d8bb685989 | |||
646bb077ef | |||
d66e402cad | |||
5ea437c170 | |||
20820a11e0 | |||
d2a650f514 | |||
79b69334df | |||
36afb693b0 | |||
869df3bc36 | |||
937fddbedf | |||
c484ee4998 | |||
1ebceb8f23 | |||
ae4801bba6 | |||
f11d344d4d | |||
6ab9822fc2 | |||
bb071a7fba | |||
a7cbbe496f | |||
5625a01baf | |||
4f13d637e6 | |||
4d61e8f997 | |||
6cdba10b1d | |||
0556557d8b | |||
17520dc4e0 | |||
0bb9052840 | |||
e6dbb8c3f2 | |||
0e7750489a | |||
3982aee329 | |||
14ccffd9d4 | |||
1d59651632 | |||
8306aded79 | |||
d690dcae31 | |||
54e676343f | |||
94174be708 | |||
5c4cc2722e | |||
8891a0ec44 | |||
b7b3f0a33a | |||
2f76fc1f77 | |||
2a84e68e6d | |||
ed1ae480f1 | |||
fd37296cdf | |||
3b28df58da | |||
47760c57e6 | |||
0fd28e0585 | |||
b8d753d35e | |||
fb4c42a357 | |||
d864e73579 | |||
c25e965b0c | |||
a152a30958 | |||
e4ab78369e | |||
14bfaffe00 | |||
8f5a033c48 | |||
548bf32990 | |||
957ac63a7c | |||
72cc19c680 | |||
e410b2ddd2 | |||
ec4b403e77 | |||
7bb10dc2a0 | |||
34adab3210 | |||
9226facda8 | |||
fa11a55a45 | |||
5d76c0a6af | |||
dfea93b2ff | |||
6157dce0b5 | |||
fd881bec19 | |||
1758eaa08c | |||
cfca07489d | |||
272c7b92d0 | |||
8302b1f762 | |||
ee5cd039a1 | |||
a37fd79426 | |||
916bebd102 | |||
04446e8da5 | |||
ae79061182 | |||
ef78b44a86 | |||
75090f648a | |||
75e260b2fc | |||
ba739f679e | |||
5dd3d03699 | |||
086499a864 | |||
622d576439 | |||
97843ed322 | |||
e206984d90 | |||
e658bdfcfe | |||
95ed9a9a91 | |||
150b97879d | |||
268330c7e5 | |||
42c4cb94e0 | |||
6aa5890e73 | |||
e648373677 | |||
a5b59e8cbb | |||
682abac7b7 | |||
6f7e68c3d4 | |||
2fd23f99ed | |||
8b1745214c | |||
28f2b2caa8 | |||
d524211c2a | |||
9e080e8aa5 | |||
2974b796d1 | |||
7803131ea8 | |||
5de29079ae | |||
fd12dcccf0 | |||
c663bb527e | |||
3f4436bac9 | |||
be1f19ad73 | |||
94d900a76f | |||
072bf74aa2 | |||
d1a7740a2c | |||
980de99472 | |||
f6795b4972 | |||
2d49edfc57 | |||
675d9325b9 | |||
8bf235ef86 | |||
2c5c7d4f26 | |||
24f23588dd | |||
5b288a5777 | |||
fa6771f058 | |||
30ddd97124 | |||
0ff474e393 | |||
6869dc7004 | |||
6d51c5f58e | |||
0201208664 | |||
958ff6e4f6 | |||
38c5382054 | |||
671b1cd9b8 | |||
830753f360 | |||
33e86042e5 | |||
ca715fdd6b | |||
ddae68bce3 | |||
406e517d52 | |||
1d32a00ebd | |||
042d077784 | |||
93757e810d | |||
0217776d6e | |||
8e0ecf9b3a | |||
41d2851a55 | |||
7cfbbe97af | |||
b69e0f6c66 | |||
61c9c21c5c | |||
4c5b70e628 | |||
448c78da5f | |||
5d4b7de426 | |||
3e5b5dca12 | |||
e25a62997d | |||
3227360b92 | |||
89c507f509 | |||
6dd17f5eec | |||
34a9135f83 | |||
26ed666948 | |||
5e400dd43b | |||
8d4888c495 | |||
4ce322b7b0 | |||
616b65c962 | |||
bc2ff5b352 | |||
61e8a174db | |||
32385b2910 | |||
26c4a81331 | |||
8cc1870663 | |||
37ea128d65 | |||
c7de6343d9 | |||
25dea7264a | |||
eeb90bab77 | |||
c276081150 | |||
4181179985 | |||
b17a936bf7 | |||
2912559061 | |||
3043f3956c | |||
ec34b8640c | |||
6a3ce86e10 | |||
3af0cc460c | |||
0190c261e2 | |||
6cf4e147ed | |||
8b887ca429 | |||
a70a51acc2 | |||
1d2447d69d | |||
12e77a1e58 | |||
6947fc7381 | |||
6f44fb8c44 | |||
cb42bafbfb | |||
4c7d8d0214 | |||
9fa777d4f4 | |||
7ddbe640be | |||
0a02f0ac7c | |||
3550d43b47 | |||
6c7dc58574 | |||
d3431a0b54 | |||
91fcc28b12 | |||
acbc482e55 | |||
cf40f59843 | |||
265d4e8723 | |||
a52a3d94d3 | |||
28cb276c70 | |||
50a34d1235 | |||
3e7177dcc8 | |||
20dc86c039 | |||
ac2dcb8b03 | |||
4922925c07 | |||
166f90e4df | |||
9e91a3832d | |||
8bca703282 | |||
23eb3756c0 | |||
1cd39a2621 | |||
70172a9eb8 | |||
9408743938 | |||
6e67d1415c | |||
d8fcaf9dec | |||
3cebc42a2a | |||
525bafcc3c | |||
63941d849a | |||
690c299bb0 | |||
1e6730758d | |||
c5a3a4e05e | |||
a8dcb6566e | |||
39e8435141 | |||
983a618a36 | |||
d7028652fe | |||
35c37f356c | |||
4a4b3a344d | |||
07f984eec2 | |||
63417cba0e | |||
32e4f0f432 | |||
fa769b98e9 | |||
b0672713bb | |||
a932dfa6df | |||
a52d50f332 | |||
dbd4f630fd | |||
0de1dc1025 | |||
1a4947499c | |||
47265c9305 | |||
c42a75d9d6 | |||
9e03df6cb7 | |||
6a2d13216a | |||
209e16890b | |||
542a921e3f | |||
ae5205f9e2 | |||
8128986ccd | |||
e1359519ab | |||
2e4c6eef54 | |||
956497a672 | |||
d43f2e2a34 | |||
c535c5b82f | |||
bde8eb35ae | |||
8402b1c151 | |||
e0fcbe672f | |||
31ad67abd7 | |||
a3c8fe6724 | |||
e50b73c9b1 | |||
2657c45f07 | |||
e4241fbeb9 | |||
836fa4d6fa | |||
520117b188 | |||
e37c522c2f | |||
dbb82f2439 | |||
cda89aaaf2 | |||
efcf38601c | |||
21387b954f | |||
ff5a4751c8 | |||
9d3e4bc591 | |||
8ab0522cec | |||
901c45e687 | |||
3bb58b7c82 | |||
f23c59644c | |||
6dfd358821 | |||
b5bc140680 | |||
2039b3a552 | |||
16f56abfad | |||
94413f99fe | |||
e7c5c36090 | |||
eec890d60e | |||
fd82603786 | |||
dc1f9fe010 | |||
9839b91be5 | |||
4495d14702 | |||
01590088d3 | |||
f6437b6086 | |||
5de7b1bbac | |||
c42cb2b0cb | |||
ccba6bdb20 | |||
0e4c02bf3b | |||
f68b77fdfa | |||
171fe8d08e | |||
788cb1e119 | |||
568973f6ec | |||
c05665a16b | |||
c87e579b06 | |||
dcad5e7e3f | |||
7fdb9849de | |||
f1c37b309a | |||
fe571c7dc3 | |||
f1637ba74d | |||
2fe4b4d5bb | |||
081ec100a4 | |||
c359e98bf1 | |||
6ef9509dfb | |||
833dc89f7c | |||
0313f9abf1 | |||
8a5886dfa1 | |||
afa8125913 | |||
0d0e726b38 | |||
fbf3daa564 | |||
d36c8762c1 | |||
a8aa778b31 | |||
f16f5b5241 | |||
6b238873ef | |||
1fc9bbe315 | |||
e7070a5f79 | |||
1a1d17143b | |||
74d04562df | |||
98a795b967 | |||
80b9bfea93 | |||
c4def60cdd | |||
4ceaaba4bd | |||
4373aecec2 | |||
e534bcaa25 | |||
6f8306a465 | |||
d5e2a779d4 | |||
c9deeb443a | |||
5d7ce4e9f2 | |||
5230562f1f | |||
5d99008afb | |||
23a0449a97 | |||
7a1576815e | |||
6360a09cc7 | |||
17d784ead3 | |||
66a2ecb19e | |||
00f2344b4a | |||
d73b229624 | |||
e584a54608 | |||
3e987ec138 | |||
b6617f17c5 | |||
5eb022fdd8 | |||
1e4141b589 | |||
9caaf26012 | |||
ffdc53718d | |||
13f18fd842 | |||
5a79bad4b1 | |||
e361c49f14 | |||
ab1652648e | |||
108e43b103 | |||
99822545c5 | |||
0034322fe0 | |||
1002b7ffee | |||
442e1be391 | |||
54957e4e03 | |||
27b20b09a3 | |||
15dc86aeb1 | |||
beb532e7e8 | |||
ab706a6f33 | |||
ee60355c9c | |||
b1dc8205f0 | |||
5a1a8e84d8 | |||
1acb69e280 | |||
f1922c13b6 | |||
c26085ec8c | |||
de18c16c9f | |||
fd9d878e1d | |||
bb4056903c | |||
adfeaa5500 | |||
f8864c67fd | |||
678f4344d2 | |||
c2a0f739f7 | |||
910f828975 | |||
373e5653e6 | |||
0fb47d0a2d | |||
d52cf767e5 | |||
63565b109d | |||
809883e632 | |||
78f04fda83 | |||
ac16fb9e2b | |||
ac6a1c5255 | |||
14cdb30886 | |||
84cd7a4e92 | |||
15d30b1125 | |||
c946c1ccbb | |||
7d60fdc8b5 | |||
b6139aabe3 | |||
19561efacb | |||
dfa4da2e98 | |||
ee1759ba4a | |||
114d7e883a | |||
408d1cabfe | |||
8ed94bf819 | |||
9f4f828976 | |||
2ae3d60203 | |||
d7a6d8560a | |||
e09abcaa96 | |||
fa53bc3241 | |||
c25dc70d26 | |||
ccaae9cd5c | |||
cead73a4d6 | |||
ff8b6d933b | |||
1aa694bba2 | |||
f61d0b2e1e | |||
4b984153ab | |||
60156d1c48 | |||
d8bc9f761c | |||
77c02d58f8 | |||
6c06f43417 | |||
4643c5d02d | |||
9df7ab3875 | |||
72da6659ed | |||
c5d25f5bfe | |||
f0f5391409 | |||
b6e20bf6c0 | |||
e65dabb119 | |||
87903b2e89 | |||
5991c3e3db | |||
d192553309 | |||
db60afb2fb | |||
df0cc061f6 | |||
a952a96b6e | |||
45dee77092 | |||
b398ab9288 | |||
e88f60feee | |||
478d91ac53 | |||
47d1c2a74d | |||
f48566d51f | |||
0c29b2b7db | |||
2d424bd259 | |||
078faa39d4 | |||
90ed9d14d2 | |||
2a63d0a972 | |||
be01bf77a9 | |||
0a5872e261 | |||
5fcac26e80 | |||
40bd9950d1 | |||
59bd18df7d | |||
598a0da30d | |||
ac79f1b596 | |||
b0c8597dbc | |||
b6e0ef1d95 | |||
f77717158d | |||
f9d67ed10c | |||
f40bf6d803 | |||
59713f6d3b | |||
67dba47c23 | |||
aa568a28a3 | |||
f9abb44d6e | |||
86cd1ec02f | |||
992e54fe25 | |||
bf6f388691 | |||
67783600aa | |||
251abdda29 | |||
d87287b745 | |||
d8d0a507e1 | |||
11b7022ce6 | |||
87028c1f60 | |||
f8c298a495 | |||
51f179eacf | |||
1f586c7735 | |||
7d354d8a37 | |||
2ddd2ba38a | |||
b50f4e2119 | |||
806de3f204 | |||
15167d541e | |||
39a830d9a9 | |||
116ce888c4 | |||
184dee491e | |||
4f05557905 | |||
1b56526fe0 | |||
aac4fcc8e1 | |||
3c0908f2da | |||
1464292188 | |||
d3eb7da297 | |||
0a14fd6a18 | |||
337be76b26 | |||
da39da39dc | |||
afa20ee0ae | |||
aea396e542 | |||
0ef2ce8e5c | |||
7b46026b52 | |||
310234e0dc | |||
7001e8fa33 | |||
a58322a62b | |||
ffae9fce58 | |||
4a981f1c47 | |||
b6bea56c27 | |||
ff227b7a04 | |||
7ee65e72a5 | |||
16c8c3853d | |||
015a6a3c65 | |||
1968ebc626 | |||
58504df2c4 | |||
d5eda89c39 | |||
9c1b87bbb9 | |||
5c3303eef0 | |||
cd715cb222 | |||
2441cc38ee | |||
11d4c9553e | |||
312a88ad39 | |||
243fd6f11e | |||
ae7b37d1c3 | |||
7478d719cf | |||
611e358ad9 | |||
b27469d218 | |||
ec5210b562 | |||
080eadc79b | |||
ef5b9474fd | |||
71f8352876 | |||
c265e72b24 | |||
8628af93e1 | |||
19ec02773f | |||
765129fde2 | |||
32d077790f | |||
cdf4da8461 | |||
797c3da239 | |||
25fb513164 | |||
ae3d5e4966 | |||
6184e5715b | |||
d8d1550400 | |||
7383f6708b | |||
3d10f4d0d1 | |||
0deca185bb | |||
6d30a5b66e | |||
8cdf981c8f | |||
8d5f623b6a | |||
85fb0b1e48 | |||
3783d5f059 | |||
86a6d88799 | |||
46010cbbd6 | |||
20e8eba08b | |||
033adfa678 | |||
057a3c3345 | |||
bba7b84a15 | |||
36e0dcf22f | |||
c8604b5a70 | |||
43b9f7a23d | |||
2a495ace3b | |||
5ee13bf528 | |||
33639c15e1 | |||
618a516182 | |||
b6c7cc8672 | |||
4d93071bf9 | |||
6d0bdab9f0 | |||
7f776ee918 | |||
a6634acc50 | |||
b31a3397e0 | |||
b6f96951be | |||
23394cd1f5 | |||
252454c016 | |||
a2387f43af | |||
641aad70a9 | |||
32ab451fff | |||
a1152fd96e | |||
356ea01a8d | |||
48217bcf80 | |||
104be3acfb | |||
ac235b9c57 | |||
b2040a6cd9 | |||
2e35f2225d | |||
ff022fce05 | |||
538bb6075c | |||
86c4214014 | |||
1f12531618 | |||
65341d8d3b | |||
90885f2168 | |||
e92678a847 | |||
17c93b259e | |||
56807ee75a | |||
2b7e7b8f8c | |||
92b835080b |
14
.gitmodules
vendored
14
.gitmodules
vendored
|
@ -4,13 +4,15 @@
|
||||||
[submodule "tools/cc2538-bsl"]
|
[submodule "tools/cc2538-bsl"]
|
||||||
path = tools/cc2538-bsl
|
path = tools/cc2538-bsl
|
||||||
url = https://github.com/JelmerT/cc2538-bsl.git
|
url = https://github.com/JelmerT/cc2538-bsl.git
|
||||||
[submodule "cpu/cc26xx-cc13xx/lib/cc26xxware"]
|
|
||||||
path = cpu/cc26xx-cc13xx/lib/cc26xxware
|
|
||||||
url = https://github.com/g-oikonomou/cc26xxware.git
|
|
||||||
[submodule "cpu/cc26xx-cc13xx/lib/cc13xxware"]
|
[submodule "cpu/cc26xx-cc13xx/lib/cc13xxware"]
|
||||||
path = cpu/cc26xx-c../.gitmodulesc13xx/lib/cc13xxware
|
path = cpu/cc26xx-cc13xx/lib/cc13xxware
|
||||||
url = https://github.com/g-oikonomou/cc13xxware.git
|
url = https://github.com/contiki-os/cc13xxware.git
|
||||||
[submodule "platform/stm32nucleo-spirit1/stm32cube-lib"]
|
[submodule "platform/stm32nucleo-spirit1/stm32cube-lib"]
|
||||||
path = platform/stm32nucleo-spirit1/stm32cube-lib
|
path = platform/stm32nucleo-spirit1/stm32cube-lib
|
||||||
url = https://github.com/STclab/stm32nucleo-spirit1-lib
|
url = https://github.com/STclab/stm32nucleo-spirit1-lib
|
||||||
|
[submodule "tools/sensniff"]
|
||||||
|
path = tools/sensniff
|
||||||
|
url = https://github.com/g-oikonomou/sensniff.git
|
||||||
|
[submodule "apps/tinydtls"]
|
||||||
|
path = apps/tinydtls
|
||||||
|
url = https://github.com/iot-lab/armour-tinydtls.git
|
||||||
|
|
10
.travis.yml
10
.travis.yml
|
@ -1,3 +1,7 @@
|
||||||
|
# Workaround for the issue found in the stable image promoted on Dec 1, 2016.
|
||||||
|
# See https://github.com/travis-ci/travis-ci/issues/6928#issuecomment-264227708
|
||||||
|
group: deprecated
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
email: false
|
email: false
|
||||||
language: c #NOTE: this will set CC=gcc which might cause trouble
|
language: c #NOTE: this will set CC=gcc which might cause trouble
|
||||||
|
@ -10,7 +14,7 @@ before_script:
|
||||||
|
|
||||||
## Install doxygen
|
## Install doxygen
|
||||||
- if [ ${BUILD_CATEGORY:-0} = doxygen ] ; then
|
- if [ ${BUILD_CATEGORY:-0} = doxygen ] ; then
|
||||||
sudo add-apt-repository ppa:libreoffice/libreoffice-4-4 -y && sudo apt-get -qq update &&
|
sudo add-apt-repository ppa:libreoffice/ppa -y && sudo apt-get -qq update &&
|
||||||
sudo apt-get --no-install-suggests --no-install-recommends -qq install doxygen &&
|
sudo apt-get --no-install-suggests --no-install-recommends -qq install doxygen &&
|
||||||
doxygen --version ;
|
doxygen --version ;
|
||||||
fi
|
fi
|
||||||
|
@ -81,7 +85,7 @@ before_script:
|
||||||
- if [ ${BUILD_ARCH:-0} = jn516x ] ; then
|
- if [ ${BUILD_ARCH:-0} = jn516x ] ; then
|
||||||
$WGET http://simonduq.github.io/resources/ba-elf-gcc-4.7.4-part1.tar.bz2 &&
|
$WGET http://simonduq.github.io/resources/ba-elf-gcc-4.7.4-part1.tar.bz2 &&
|
||||||
$WGET http://simonduq.github.io/resources/ba-elf-gcc-4.7.4-part2.tar.bz2 &&
|
$WGET http://simonduq.github.io/resources/ba-elf-gcc-4.7.4-part2.tar.bz2 &&
|
||||||
$WGET http://simonduq.github.io/resources/jn516x-sdk-4163.tar.bz2 &&
|
$WGET http://simonduq.github.io/resources/jn516x-sdk-4163-1416.tar.bz2 &&
|
||||||
mkdir /tmp/jn516x-sdk /tmp/ba-elf-gcc &&
|
mkdir /tmp/jn516x-sdk /tmp/ba-elf-gcc &&
|
||||||
tar xjf jn516x-sdk-*.tar.bz2 -C /tmp/jn516x-sdk &&
|
tar xjf jn516x-sdk-*.tar.bz2 -C /tmp/jn516x-sdk &&
|
||||||
tar xjf ba-elf-gcc-*part1.tar.bz2 -C /tmp/ba-elf-gcc &&
|
tar xjf ba-elf-gcc-*part1.tar.bz2 -C /tmp/ba-elf-gcc &&
|
||||||
|
@ -158,3 +162,5 @@ env:
|
||||||
- BUILD_TYPE='slip-radio' MAKE_TARGETS='cooja'
|
- BUILD_TYPE='slip-radio' MAKE_TARGETS='cooja'
|
||||||
- BUILD_TYPE='llsec' MAKE_TARGETS='cooja'
|
- BUILD_TYPE='llsec' MAKE_TARGETS='cooja'
|
||||||
- BUILD_TYPE='compile-avr' BUILD_CATEGORY='compile' BUILD_ARCH='avr-rss2'
|
- BUILD_TYPE='compile-avr' BUILD_CATEGORY='compile' BUILD_ARCH='avr-rss2'
|
||||||
|
- BUILD_TYPE='ieee802154'
|
||||||
|
- BUILD_TYPE='tsch'
|
||||||
|
|
494
LICENSE
494
LICENSE
|
@ -1,3 +1,37 @@
|
||||||
|
A note on Licensing (2017-03-17):
|
||||||
|
Github has recently (2017-03-01) changed their license terms:
|
||||||
|
https://help.github.com/articles/github-terms-of-service/
|
||||||
|
There were comments that this may violate some GPL and creative commons
|
||||||
|
licenses:
|
||||||
|
http://joeyh.name/blog/entry/removing_everything_from_github/
|
||||||
|
https://www.mirbsd.org/permalinks/wlog-10_e20170301-tg.htm
|
||||||
|
But also voices that don't see a problem:
|
||||||
|
https://www.earth.li/~noodles/blog/2017/03/github-tos-change.html
|
||||||
|
If your're german-speaking you may also want to read the two Heise
|
||||||
|
articles:
|
||||||
|
https://www.heise.de/developer/meldung/GitHub-eckt-mit-neuen-Nutzungsbedingungen-an-3647980.html
|
||||||
|
https://www.heise.de/developer/meldung/FSF-aeussert-sich-zu-den-GitHub-Nutzungsbedingungen-3657040.html
|
||||||
|
|
||||||
|
We trust that the problematic part in section D.5:
|
||||||
|
"If you set your pages and repositories to be viewed publicly, you grant
|
||||||
|
each User of GitHub a nonexclusive, worldwide license to access your
|
||||||
|
Content through the GitHub Service, and to use, display and perform your
|
||||||
|
Content, and to reproduce your Content solely on GitHub as permitted
|
||||||
|
through GitHub's functionality." that the part "solely on GitHub as
|
||||||
|
permitted through GitHub's functionality" also applies to "display and
|
||||||
|
perform your Content". If the latter part of the sentence would stand
|
||||||
|
alone it could be interpreted that we would grant *everybody*
|
||||||
|
essentially an unlimited license (which we cannot because the authors
|
||||||
|
from whom we forked applied other licenses). This interpretation is
|
||||||
|
further supported by the fact that Github writes "You may grant further
|
||||||
|
rights if you adopt a license." that in fact the statements above only
|
||||||
|
apply to the rendering on Github.
|
||||||
|
|
||||||
|
Note that in the following we have two licenses, the 3-clause BSD and
|
||||||
|
the LGPL license in short:
|
||||||
|
- Contiki OS (and our modification to it) are 3-clause BSD
|
||||||
|
- Our Arduino compatibility Layer on top of Contiki OS is LGPL
|
||||||
|
|
||||||
Contiki is licensed under the 3-clause BSD license. This license gives
|
Contiki is licensed under the 3-clause BSD license. This license gives
|
||||||
everyone the right to use and distribute the code, either in binary or
|
everyone the right to use and distribute the code, either in binary or
|
||||||
source code format, as long as the copyright license is retained in
|
source code format, as long as the copyright license is retained in
|
||||||
|
@ -36,3 +70,463 @@ of license. The license text is:
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
Arduino-compatibility layer if not otherwise noted is under the
|
||||||
|
following license:
|
||||||
|
|
||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
Version 2.1, February 1999
|
||||||
|
|
||||||
|
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
[This is the first released version of the Lesser GPL. It also counts
|
||||||
|
as the successor of the GNU Library Public License, version 2, hence
|
||||||
|
the version number 2.1.]
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
Licenses are intended to guarantee your freedom to share and change
|
||||||
|
free software--to make sure the software is free for all its users.
|
||||||
|
|
||||||
|
This license, the Lesser General Public License, applies to some
|
||||||
|
specially designated software packages--typically libraries--of the
|
||||||
|
Free Software Foundation and other authors who decide to use it. You
|
||||||
|
can use it too, but we suggest you first think carefully about whether
|
||||||
|
this license or the ordinary General Public License is the better
|
||||||
|
strategy to use in any particular case, based on the explanations below.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom of use,
|
||||||
|
not price. Our General Public Licenses are designed to make sure that
|
||||||
|
you have the freedom to distribute copies of free software (and charge
|
||||||
|
for this service if you wish); that you receive source code or can get
|
||||||
|
it if you want it; that you can change the software and use pieces of
|
||||||
|
it in new free programs; and that you are informed that you can do
|
||||||
|
these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
distributors to deny you these rights or to ask you to surrender these
|
||||||
|
rights. These restrictions translate to certain responsibilities for
|
||||||
|
you if you distribute copies of the library or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of the library, whether gratis
|
||||||
|
or for a fee, you must give the recipients all the rights that we gave
|
||||||
|
you. You must make sure that they, too, receive or can get the source
|
||||||
|
code. If you link other code with the library, you must provide
|
||||||
|
complete object files to the recipients, so that they can relink them
|
||||||
|
with the library after making changes to the library and recompiling
|
||||||
|
it. And you must show them these terms so they know their rights.
|
||||||
|
|
||||||
|
We protect your rights with a two-step method: (1) we copyright the
|
||||||
|
library, and (2) we offer you this license, which gives you legal
|
||||||
|
permission to copy, distribute and/or modify the library.
|
||||||
|
|
||||||
|
To protect each distributor, we want to make it very clear that
|
||||||
|
there is no warranty for the free library. Also, if the library is
|
||||||
|
modified by someone else and passed on, the recipients should know
|
||||||
|
that what they have is not the original version, so that the original
|
||||||
|
author's reputation will not be affected by problems that might be
|
||||||
|
introduced by others.
|
||||||
|
|
||||||
|
Finally, software patents pose a constant threat to the existence of
|
||||||
|
any free program. We wish to make sure that a company cannot
|
||||||
|
effectively restrict the users of a free program by obtaining a
|
||||||
|
restrictive license from a patent holder. Therefore, we insist that
|
||||||
|
any patent license obtained for a version of the library must be
|
||||||
|
consistent with the full freedom of use specified in this license.
|
||||||
|
|
||||||
|
Most GNU software, including some libraries, is covered by the
|
||||||
|
ordinary GNU General Public License. This license, the GNU Lesser
|
||||||
|
General Public License, applies to certain designated libraries, and
|
||||||
|
is quite different from the ordinary General Public License. We use
|
||||||
|
this license for certain libraries in order to permit linking those
|
||||||
|
libraries into non-free programs.
|
||||||
|
|
||||||
|
When a program is linked with a library, whether statically or using
|
||||||
|
a shared library, the combination of the two is legally speaking a
|
||||||
|
combined work, a derivative of the original library. The ordinary
|
||||||
|
General Public License therefore permits such linking only if the
|
||||||
|
entire combination fits its criteria of freedom. The Lesser General
|
||||||
|
Public License permits more lax criteria for linking other code with
|
||||||
|
the library.
|
||||||
|
|
||||||
|
We call this license the "Lesser" General Public License because it
|
||||||
|
does Less to protect the user's freedom than the ordinary General
|
||||||
|
Public License. It also provides other free software developers Less
|
||||||
|
of an advantage over competing non-free programs. These disadvantages
|
||||||
|
are the reason we use the ordinary General Public License for many
|
||||||
|
libraries. However, the Lesser license provides advantages in certain
|
||||||
|
special circumstances.
|
||||||
|
|
||||||
|
For example, on rare occasions, there may be a special need to
|
||||||
|
encourage the widest possible use of a certain library, so that it becomes
|
||||||
|
a de-facto standard. To achieve this, non-free programs must be
|
||||||
|
allowed to use the library. A more frequent case is that a free
|
||||||
|
library does the same job as widely used non-free libraries. In this
|
||||||
|
case, there is little to gain by limiting the free library to free
|
||||||
|
software only, so we use the Lesser General Public License.
|
||||||
|
|
||||||
|
In other cases, permission to use a particular library in non-free
|
||||||
|
programs enables a greater number of people to use a large body of
|
||||||
|
free software. For example, permission to use the GNU C Library in
|
||||||
|
non-free programs enables many more people to use the whole GNU
|
||||||
|
operating system, as well as its variant, the GNU/Linux operating
|
||||||
|
system.
|
||||||
|
|
||||||
|
Although the Lesser General Public License is Less protective of the
|
||||||
|
users' freedom, it does ensure that the user of a program that is
|
||||||
|
linked with the Library has the freedom and the wherewithal to run
|
||||||
|
that program using a modified version of the Library.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow. Pay close attention to the difference between a
|
||||||
|
"work based on the library" and a "work that uses the library". The
|
||||||
|
former contains code derived from the library, whereas the latter must
|
||||||
|
be combined with the library in order to run.
|
||||||
|
|
||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License Agreement applies to any software library or other
|
||||||
|
program which contains a notice placed by the copyright holder or
|
||||||
|
other authorized party saying it may be distributed under the terms of
|
||||||
|
this Lesser General Public License (also called "this License").
|
||||||
|
Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
A "library" means a collection of software functions and/or data
|
||||||
|
prepared so as to be conveniently linked with application programs
|
||||||
|
(which use some of those functions and data) to form executables.
|
||||||
|
|
||||||
|
The "Library", below, refers to any such software library or work
|
||||||
|
which has been distributed under these terms. A "work based on the
|
||||||
|
Library" means either the Library or any derivative work under
|
||||||
|
copyright law: that is to say, a work containing the Library or a
|
||||||
|
portion of it, either verbatim or with modifications and/or translated
|
||||||
|
straightforwardly into another language. (Hereinafter, translation is
|
||||||
|
included without limitation in the term "modification".)
|
||||||
|
|
||||||
|
"Source code" for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For a library, complete source code means
|
||||||
|
all the source code for all modules it contains, plus any associated
|
||||||
|
interface definition files, plus the scripts used to control compilation
|
||||||
|
and installation of the library.
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running a program using the Library is not restricted, and output from
|
||||||
|
such a program is covered only if its contents constitute a work based
|
||||||
|
on the Library (independent of the use of the Library in a tool for
|
||||||
|
writing it). Whether that is true depends on what the Library does
|
||||||
|
and what the program that uses the Library does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Library's
|
||||||
|
complete source code as you receive it, in any medium, provided that
|
||||||
|
you conspicuously and appropriately publish on each copy an
|
||||||
|
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||||
|
all the notices that refer to this License and to the absence of any
|
||||||
|
warranty; and distribute a copy of this License along with the
|
||||||
|
Library.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy,
|
||||||
|
and you may at your option offer warranty protection in exchange for a
|
||||||
|
fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Library or any portion
|
||||||
|
of it, thus forming a work based on the Library, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The modified work must itself be a software library.
|
||||||
|
|
||||||
|
b) You must cause the files modified to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
c) You must cause the whole of the work to be licensed at no
|
||||||
|
charge to all third parties under the terms of this License.
|
||||||
|
|
||||||
|
d) If a facility in the modified Library refers to a function or a
|
||||||
|
table of data to be supplied by an application program that uses
|
||||||
|
the facility, other than as an argument passed when the facility
|
||||||
|
is invoked, then you must make a good faith effort to ensure that,
|
||||||
|
in the event an application does not supply such function or
|
||||||
|
table, the facility still operates, and performs whatever part of
|
||||||
|
its purpose remains meaningful.
|
||||||
|
|
||||||
|
(For example, a function in a library to compute square roots has
|
||||||
|
a purpose that is entirely well-defined independent of the
|
||||||
|
application. Therefore, Subsection 2d requires that any
|
||||||
|
application-supplied function or table used by this function must
|
||||||
|
be optional: if the application does not supply it, the square
|
||||||
|
root function must still compute square roots.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Library,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Library, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote
|
||||||
|
it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Library.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Library
|
||||||
|
with the Library (or with a work based on the Library) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||||
|
License instead of this License to a given copy of the Library. To do
|
||||||
|
this, you must alter all the notices that refer to this License, so
|
||||||
|
that they refer to the ordinary GNU General Public License, version 2,
|
||||||
|
instead of to this License. (If a newer version than version 2 of the
|
||||||
|
ordinary GNU General Public License has appeared, then you can specify
|
||||||
|
that version instead if you wish.) Do not make any other change in
|
||||||
|
these notices.
|
||||||
|
|
||||||
|
Once this change is made in a given copy, it is irreversible for
|
||||||
|
that copy, so the ordinary GNU General Public License applies to all
|
||||||
|
subsequent copies and derivative works made from that copy.
|
||||||
|
|
||||||
|
This option is useful when you wish to copy part of the code of
|
||||||
|
the Library into a program that is not a library.
|
||||||
|
|
||||||
|
4. You may copy and distribute the Library (or a portion or
|
||||||
|
derivative of it, under Section 2) in object code or executable form
|
||||||
|
under the terms of Sections 1 and 2 above provided that you accompany
|
||||||
|
it with the complete corresponding machine-readable source code, which
|
||||||
|
must be distributed under the terms of Sections 1 and 2 above on a
|
||||||
|
medium customarily used for software interchange.
|
||||||
|
|
||||||
|
If distribution of object code is made by offering access to copy
|
||||||
|
from a designated place, then offering equivalent access to copy the
|
||||||
|
source code from the same place satisfies the requirement to
|
||||||
|
distribute the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
5. A program that contains no derivative of any portion of the
|
||||||
|
Library, but is designed to work with the Library by being compiled or
|
||||||
|
linked with it, is called a "work that uses the Library". Such a
|
||||||
|
work, in isolation, is not a derivative work of the Library, and
|
||||||
|
therefore falls outside the scope of this License.
|
||||||
|
|
||||||
|
However, linking a "work that uses the Library" with the Library
|
||||||
|
creates an executable that is a derivative of the Library (because it
|
||||||
|
contains portions of the Library), rather than a "work that uses the
|
||||||
|
library". The executable is therefore covered by this License.
|
||||||
|
Section 6 states terms for distribution of such executables.
|
||||||
|
|
||||||
|
When a "work that uses the Library" uses material from a header file
|
||||||
|
that is part of the Library, the object code for the work may be a
|
||||||
|
derivative work of the Library even though the source code is not.
|
||||||
|
Whether this is true is especially significant if the work can be
|
||||||
|
linked without the Library, or if the work is itself a library. The
|
||||||
|
threshold for this to be true is not precisely defined by law.
|
||||||
|
|
||||||
|
If such an object file uses only numerical parameters, data
|
||||||
|
structure layouts and accessors, and small macros and small inline
|
||||||
|
functions (ten lines or less in length), then the use of the object
|
||||||
|
file is unrestricted, regardless of whether it is legally a derivative
|
||||||
|
work. (Executables containing this object code plus portions of the
|
||||||
|
Library will still fall under Section 6.)
|
||||||
|
|
||||||
|
Otherwise, if the work is a derivative of the Library, you may
|
||||||
|
distribute the object code for the work under the terms of Section 6.
|
||||||
|
Any executables containing that work also fall under Section 6,
|
||||||
|
whether or not they are linked directly with the Library itself.
|
||||||
|
|
||||||
|
6. As an exception to the Sections above, you may also combine or
|
||||||
|
link a "work that uses the Library" with the Library to produce a
|
||||||
|
work containing portions of the Library, and distribute that work
|
||||||
|
under terms of your choice, provided that the terms permit
|
||||||
|
modification of the work for the customer's own use and reverse
|
||||||
|
engineering for debugging such modifications.
|
||||||
|
|
||||||
|
You must give prominent notice with each copy of the work that the
|
||||||
|
Library is used in it and that the Library and its use are covered by
|
||||||
|
this License. You must supply a copy of this License. If the work
|
||||||
|
during execution displays copyright notices, you must include the
|
||||||
|
copyright notice for the Library among them, as well as a reference
|
||||||
|
directing the user to the copy of this License. Also, you must do one
|
||||||
|
of these things:
|
||||||
|
|
||||||
|
a) Accompany the work with the complete corresponding
|
||||||
|
machine-readable source code for the Library including whatever
|
||||||
|
changes were used in the work (which must be distributed under
|
||||||
|
Sections 1 and 2 above); and, if the work is an executable linked
|
||||||
|
with the Library, with the complete machine-readable "work that
|
||||||
|
uses the Library", as object code and/or source code, so that the
|
||||||
|
user can modify the Library and then relink to produce a modified
|
||||||
|
executable containing the modified Library. (It is understood
|
||||||
|
that the user who changes the contents of definitions files in the
|
||||||
|
Library will not necessarily be able to recompile the application
|
||||||
|
to use the modified definitions.)
|
||||||
|
|
||||||
|
b) Use a suitable shared library mechanism for linking with the
|
||||||
|
Library. A suitable mechanism is one that (1) uses at run time a
|
||||||
|
copy of the library already present on the user's computer system,
|
||||||
|
rather than copying library functions into the executable, and (2)
|
||||||
|
will operate properly with a modified version of the library, if
|
||||||
|
the user installs one, as long as the modified version is
|
||||||
|
interface-compatible with the version that the work was made with.
|
||||||
|
|
||||||
|
c) Accompany the work with a written offer, valid for at
|
||||||
|
least three years, to give the same user the materials
|
||||||
|
specified in Subsection 6a, above, for a charge no more
|
||||||
|
than the cost of performing this distribution.
|
||||||
|
|
||||||
|
d) If distribution of the work is made by offering access to copy
|
||||||
|
from a designated place, offer equivalent access to copy the above
|
||||||
|
specified materials from the same place.
|
||||||
|
|
||||||
|
e) Verify that the user has already received a copy of these
|
||||||
|
materials or that you have already sent this user a copy.
|
||||||
|
|
||||||
|
For an executable, the required form of the "work that uses the
|
||||||
|
Library" must include any data and utility programs needed for
|
||||||
|
reproducing the executable from it. However, as a special exception,
|
||||||
|
the materials to be distributed need not include anything that is
|
||||||
|
normally distributed (in either source or binary form) with the major
|
||||||
|
components (compiler, kernel, and so on) of the operating system on
|
||||||
|
which the executable runs, unless that component itself accompanies
|
||||||
|
the executable.
|
||||||
|
|
||||||
|
It may happen that this requirement contradicts the license
|
||||||
|
restrictions of other proprietary libraries that do not normally
|
||||||
|
accompany the operating system. Such a contradiction means you cannot
|
||||||
|
use both them and the Library together in an executable that you
|
||||||
|
distribute.
|
||||||
|
|
||||||
|
7. You may place library facilities that are a work based on the
|
||||||
|
Library side-by-side in a single library together with other library
|
||||||
|
facilities not covered by this License, and distribute such a combined
|
||||||
|
library, provided that the separate distribution of the work based on
|
||||||
|
the Library and of the other library facilities is otherwise
|
||||||
|
permitted, and provided that you do these two things:
|
||||||
|
|
||||||
|
a) Accompany the combined library with a copy of the same work
|
||||||
|
based on the Library, uncombined with any other library
|
||||||
|
facilities. This must be distributed under the terms of the
|
||||||
|
Sections above.
|
||||||
|
|
||||||
|
b) Give prominent notice with the combined library of the fact
|
||||||
|
that part of it is a work based on the Library, and explaining
|
||||||
|
where to find the accompanying uncombined form of the same work.
|
||||||
|
|
||||||
|
8. You may not copy, modify, sublicense, link with, or distribute
|
||||||
|
the Library except as expressly provided under this License. Any
|
||||||
|
attempt otherwise to copy, modify, sublicense, link with, or
|
||||||
|
distribute the Library is void, and will automatically terminate your
|
||||||
|
rights under this License. However, parties who have received copies,
|
||||||
|
or rights, from you under this License will not have their licenses
|
||||||
|
terminated so long as such parties remain in full compliance.
|
||||||
|
|
||||||
|
9. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Library or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Library (or any work based on the
|
||||||
|
Library), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Library or works based on it.
|
||||||
|
|
||||||
|
10. Each time you redistribute the Library (or any work based on the
|
||||||
|
Library), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute, link with or modify the Library
|
||||||
|
subject to these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties with
|
||||||
|
this License.
|
||||||
|
|
||||||
|
11. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Library at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Library by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Library.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under any
|
||||||
|
particular circumstance, the balance of the section is intended to apply,
|
||||||
|
and the section as a whole is intended to apply in other circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
12. If the distribution and/or use of the Library is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Library under this License may add
|
||||||
|
an explicit geographical distribution limitation excluding those countries,
|
||||||
|
so that distribution is permitted only in or among countries not thus
|
||||||
|
excluded. In such case, this License incorporates the limitation as if
|
||||||
|
written in the body of this License.
|
||||||
|
|
||||||
|
13. The Free Software Foundation may publish revised and/or new
|
||||||
|
versions of the Lesser General Public License from time to time.
|
||||||
|
Such new versions will be similar in spirit to the present version,
|
||||||
|
but may differ in detail to address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Library
|
||||||
|
specifies a version number of this License which applies to it and
|
||||||
|
"any later version", you have the option of following the terms and
|
||||||
|
conditions either of that version or of any later version published by
|
||||||
|
the Free Software Foundation. If the Library does not specify a
|
||||||
|
license version number, you may choose any version ever published by
|
||||||
|
the Free Software Foundation.
|
||||||
|
|
||||||
|
14. If you wish to incorporate parts of the Library into other free
|
||||||
|
programs whose distribution conditions are incompatible with these,
|
||||||
|
write to the author to ask for permission. For software which is
|
||||||
|
copyrighted by the Free Software Foundation, write to the Free
|
||||||
|
Software Foundation; we sometimes make exceptions for this. Our
|
||||||
|
decision will be guided by the two goals of preserving the free status
|
||||||
|
of all derivatives of our free software and of promoting the sharing
|
||||||
|
and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||||
|
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||||
|
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||||
|
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||||
|
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||||
|
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||||
|
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||||
|
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||||
|
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||||
|
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||||
|
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||||
|
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||||
|
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||||
|
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||||
|
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
|
DAMAGES.
|
||||||
|
|
||||||
|
|
|
@ -304,6 +304,25 @@ endif
|
||||||
%.flashprof: %.$(TARGET)
|
%.flashprof: %.$(TARGET)
|
||||||
$(NM) -S -td --size-sort $< | grep -i " [t] " | cut -d' ' -f2,4
|
$(NM) -S -td --size-sort $< | grep -i " [t] " | cut -d' ' -f2,4
|
||||||
|
|
||||||
|
viewconf:
|
||||||
|
@echo "----------------- Make variables: --------------"
|
||||||
|
@echo "##### \"TARGET\": ________________________________ $(TARGET)"
|
||||||
|
@echo "##### \"BOARD\": _________________________________ $(BOARD)"
|
||||||
|
@echo "##### \"MAKE_MAC\": ______________________________ $(MAKE_MAC)"
|
||||||
|
@echo "##### \"MAKE_NET\": ______________________________ $(MAKE_NET)"
|
||||||
|
@echo "##### \"MAKE_ROUTING\": __________________________ $(MAKE_ROUTING)"
|
||||||
|
ifdef MAKE_COAP_DTLS_KEYSTORE
|
||||||
|
@echo "##### \"MAKE_COAP_DTLS_KEYSTORE\": _______________ $(MAKE_COAP_DTLS_KEYSTORE)"
|
||||||
|
endif
|
||||||
|
@echo "----------------- C variables: -----------------"
|
||||||
|
$(Q)$(CC) $(CFLAGS) -E $(CONTIKI)/tools/viewconf.c | grep \#\#\#\#\#
|
||||||
|
@echo "------------------------------------------------"
|
||||||
|
@echo "'==' Means the flag is set to a given a value"
|
||||||
|
@echo "'->' Means the flag is unset, but will default to a given value"
|
||||||
|
@echo "'><' Means the flag is unset and has no default value"
|
||||||
|
@echo "To view more Make variables, edit $(CONTIKI)/Makefile.include, rule 'viewconf'"
|
||||||
|
@echo "To view more C variables, edit $(CONTIKI)/tools/viewconf.c"
|
||||||
|
|
||||||
# Don't treat %.$(TARGET) as an intermediate file because it is
|
# Don't treat %.$(TARGET) as an intermediate file because it is
|
||||||
# in fact the primary target.
|
# in fact the primary target.
|
||||||
.PRECIOUS: %.$(TARGET)
|
.PRECIOUS: %.$(TARGET)
|
||||||
|
|
11
README.md
11
README.md
|
@ -1,8 +1,6 @@
|
||||||
The Contiki Operating System
|
The Contiki Operating System
|
||||||
============================
|
============================
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.org/contiki-os/contiki.svg?branch=master)](https://travis-ci.org/contiki-os/contiki/branches)
|
|
||||||
|
|
||||||
Contiki is an open source operating system that runs on tiny low-power
|
Contiki is an open source operating system that runs on tiny low-power
|
||||||
microcontrollers and makes it possible to develop applications that
|
microcontrollers and makes it possible to develop applications that
|
||||||
make efficient use of the hardware while providing standardized
|
make efficient use of the hardware while providing standardized
|
||||||
|
@ -17,3 +15,12 @@ and so on.
|
||||||
For more information, see the Contiki website:
|
For more information, see the Contiki website:
|
||||||
|
|
||||||
[http://contiki-os.org](http://contiki-os.org)
|
[http://contiki-os.org](http://contiki-os.org)
|
||||||
|
|
||||||
|
This fork of the Contiki Operating System adds support for our Merkur
|
||||||
|
Board, adds a lot of examples (with different hardware) and puts an
|
||||||
|
Arduino compatibility layer on top of Contiki-OS that allows Arduino
|
||||||
|
Sketches -- and a lot of drivers for Arduino compatible hardware -- to
|
||||||
|
run under Contiki-OS.
|
||||||
|
|
||||||
|
For the licensing terms (also in the light of recent debates of Github
|
||||||
|
changed Terms of Service on 2017-03-01) see the file LICENSE.
|
||||||
|
|
|
@ -49,24 +49,64 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include "arduino-process.h"
|
#include "arduino-process.h"
|
||||||
#include "hw_timer.h"
|
#include "hw_timer.h"
|
||||||
#include "adc.h"
|
#include "adc.h"
|
||||||
#include "hw-arduino.h"
|
#include "hw-arduino.h"
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "project-conf.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define DEBUG 0
|
||||||
|
#if DEBUG
|
||||||
|
#include <stdio.h>
|
||||||
|
#define PRINTF(...) printf(__VA_ARGS__)
|
||||||
|
#define PRINT6ADDR(addr) PRINTF("[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15])
|
||||||
|
#define PRINTLLADDR(lladdr) PRINTF("[%02x:%02x:%02x:%02x:%02x:%02x]", (lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3], (lladdr)->addr[4], (lladdr)->addr[5])
|
||||||
|
#else
|
||||||
|
#define PRINTF(...)
|
||||||
|
#define PRINT6ADDR(addr)
|
||||||
|
#define PRINTLLADDR(addr)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
extern volatile uint8_t mcusleepcycle;
|
extern volatile uint8_t mcusleepcycle;
|
||||||
|
#if PLATFORM_HAS_BUTTON
|
||||||
|
#include "rest-engine.h"
|
||||||
|
#include "dev/button-sensor.h"
|
||||||
|
extern resource_t res_event, res_separate;
|
||||||
|
#endif /* PLATFORM_HAS_BUTTON */
|
||||||
|
|
||||||
volatile uint8_t mcusleepcycleval;
|
volatile uint8_t mcusleepcycleval;
|
||||||
|
/* 0 dont sleep; 1 sleep */
|
||||||
|
uint8_t mcusleep;
|
||||||
|
|
||||||
/*-------------- enabled sleep mode ----------------------------------------*/
|
/*-------------- enabled sleep mode ----------------------------------------*/
|
||||||
void
|
void
|
||||||
mcu_sleep_init(void)
|
mcu_sleep_init(void)
|
||||||
{
|
{
|
||||||
mcusleepcycleval=mcusleepcycle;
|
mcusleepcycleval=mcusleepcycle;
|
||||||
|
mcu_sleep_disable(); // if a shell is active we can type
|
||||||
|
}
|
||||||
|
void
|
||||||
|
mcu_sleep_disable(void)
|
||||||
|
{
|
||||||
|
mcusleep=2;
|
||||||
|
mcu_sleep_off();
|
||||||
|
}
|
||||||
|
void
|
||||||
|
mcu_sleep_enable(void)
|
||||||
|
{
|
||||||
|
mcusleep=0;
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
mcu_sleep_on(void)
|
mcu_sleep_on(void)
|
||||||
{
|
{
|
||||||
|
if(mcusleep == 0){
|
||||||
mcusleepcycle= mcusleepcycleval;
|
mcusleepcycle= mcusleepcycleval;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/*--------------- disable sleep mode ---------------------------------------*/
|
/*--------------- disable sleep mode ---------------------------------------*/
|
||||||
void
|
void
|
||||||
|
@ -79,7 +119,7 @@ void
|
||||||
mcu_sleep_set(uint8_t value)
|
mcu_sleep_set(uint8_t value)
|
||||||
{
|
{
|
||||||
mcusleepcycleval= value;
|
mcusleepcycleval= value;
|
||||||
mcusleepcycle = mcusleepcycleval;
|
// mcusleepcycle = mcusleepcycleval;
|
||||||
}
|
}
|
||||||
|
|
||||||
PROCESS(arduino_sketch, "Arduino Sketch Wrapper");
|
PROCESS(arduino_sketch, "Arduino Sketch Wrapper");
|
||||||
|
@ -87,10 +127,12 @@ PROCESS(arduino_sketch, "Arduino Sketch Wrapper");
|
||||||
#ifndef LOOP_INTERVAL
|
#ifndef LOOP_INTERVAL
|
||||||
#define LOOP_INTERVAL (1 * CLOCK_SECOND)
|
#define LOOP_INTERVAL (1 * CLOCK_SECOND)
|
||||||
#endif
|
#endif
|
||||||
|
#define START_MCUSLEEP (10 * CLOCK_SECOND)
|
||||||
|
|
||||||
PROCESS_THREAD(arduino_sketch, ev, data)
|
PROCESS_THREAD(arduino_sketch, ev, data)
|
||||||
{
|
{
|
||||||
static struct etimer loop_periodic_timer;
|
static struct etimer loop_periodic_timer;
|
||||||
|
static struct etimer start_mcusleep_timer;
|
||||||
|
|
||||||
PROCESS_BEGIN();
|
PROCESS_BEGIN();
|
||||||
adc_init ();
|
adc_init ();
|
||||||
|
@ -98,17 +140,41 @@ PROCESS_THREAD(arduino_sketch, ev, data)
|
||||||
setup ();
|
setup ();
|
||||||
/* Define application-specific events here. */
|
/* Define application-specific events here. */
|
||||||
etimer_set(&loop_periodic_timer, LOOP_INTERVAL);
|
etimer_set(&loop_periodic_timer, LOOP_INTERVAL);
|
||||||
|
etimer_set(&start_mcusleep_timer, START_MCUSLEEP);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
PROCESS_WAIT_EVENT();
|
PROCESS_WAIT_EVENT();
|
||||||
|
#if PLATFORM_HAS_BUTTON
|
||||||
|
if(ev == sensors_event && data == &button_sensor) {
|
||||||
|
mcu_sleep_off();
|
||||||
|
PRINTF("*******BUTTON*******\n");
|
||||||
|
button ();
|
||||||
|
mcu_sleep_on();
|
||||||
|
}
|
||||||
|
#endif /* PLATFORM_HAS_BUTTON */
|
||||||
|
if(etimer_expired(&start_mcusleep_timer)) {
|
||||||
|
PRINTF("mcusleep_timer %d\n",mcusleep);
|
||||||
|
if(mcusleep == 1){
|
||||||
|
PRINTF("mcu sleep on\n");
|
||||||
|
mcu_sleep_enable();
|
||||||
|
mcu_sleep_on();
|
||||||
|
}
|
||||||
|
if (mcusleep > 0) {
|
||||||
|
mcusleep--;
|
||||||
|
}
|
||||||
|
etimer_reset(&start_mcusleep_timer);
|
||||||
|
}
|
||||||
|
|
||||||
if(etimer_expired(&loop_periodic_timer)) {
|
if(etimer_expired(&loop_periodic_timer)) {
|
||||||
|
mcu_sleep_off();
|
||||||
loop ();
|
loop ();
|
||||||
|
mcu_sleep_on();
|
||||||
etimer_reset(&loop_periodic_timer);
|
etimer_reset(&loop_periodic_timer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PROCESS_END();
|
PROCESS_END();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* VI settings, see coding style
|
* VI settings, see coding style
|
||||||
* ex:ts=8:et:sw=2
|
* ex:ts=8:et:sw=2
|
||||||
|
|
|
@ -52,8 +52,12 @@
|
||||||
#include "contiki.h"
|
#include "contiki.h"
|
||||||
|
|
||||||
/*--------------- enable sleep mode ---------------------------------------*/
|
/*--------------- enable sleep mode ---------------------------------------*/
|
||||||
void mcu_sleep_on(void);
|
void mcu_sleep_enable(void);
|
||||||
/*--------------- disable sleep mode ---------------------------------------*/
|
/*--------------- disable sleep mode ---------------------------------------*/
|
||||||
|
void mcu_sleep_disable(void);
|
||||||
|
/*--------------- sleep mode on---------------------------------------*/
|
||||||
|
void mcu_sleep_on(void);
|
||||||
|
/*--------------- sleep mode off---------------------------------------*/
|
||||||
void mcu_sleep_off(void);
|
void mcu_sleep_off(void);
|
||||||
/*---------------- set sleep value ------------------------------------*/
|
/*---------------- set sleep value ------------------------------------*/
|
||||||
void mcu_sleep_set(uint8_t value);
|
void mcu_sleep_set(uint8_t value);
|
||||||
|
@ -61,6 +65,7 @@ void mcu_sleep_set(uint8_t value);
|
||||||
extern void loop (void);
|
extern void loop (void);
|
||||||
extern void setup (void);
|
extern void setup (void);
|
||||||
extern void arduino_init (void);
|
extern void arduino_init (void);
|
||||||
|
extern void button (void);
|
||||||
|
|
||||||
extern struct process arduino_sketch;
|
extern struct process arduino_sketch;
|
||||||
|
|
||||||
|
|
|
@ -4,3 +4,18 @@ er-coap_src = er-coap.c er-coap-engine.c er-coap-transactions.c \
|
||||||
|
|
||||||
# Erbium will implement the REST Engine
|
# Erbium will implement the REST Engine
|
||||||
CFLAGS += -DREST=coap_rest_implementation
|
CFLAGS += -DREST=coap_rest_implementation
|
||||||
|
|
||||||
|
ifeq ($(WITH_DTLS_COAP),1)
|
||||||
|
er-coap_src += er-coap-dtls.c
|
||||||
|
|
||||||
|
# Load tinydtls
|
||||||
|
APPS += tinydtls
|
||||||
|
$(CONTIKI)/apps/tinydtls/Makefile.tinydtls:
|
||||||
|
@echo " You should run 'git submodule update --init' to clone 'app/tinydtls'"
|
||||||
|
@exit 1
|
||||||
|
include $(CONTIKI)/apps/tinydtls/Makefile.tinydtls
|
||||||
|
PROJECTDIRS+=$(CONTIKI)/apps/tinydtls/aes $(CONTIKI)/apps/tinydtls/sha2 $(CONTIKI)/apps/tinydtls/ecc
|
||||||
|
|
||||||
|
else
|
||||||
|
er-coap_src += er-coap-udp.c
|
||||||
|
endif
|
||||||
|
|
15
apps/er-coap/er-coap-communication.h
Normal file
15
apps/er-coap/er-coap-communication.h
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef _ER_COAP_COMMUNICATION_H_
|
||||||
|
#define _ER_COAP_COMMUNICATION_H_
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
coap_init_communication_layer(uint16_t port);
|
||||||
|
|
||||||
|
void
|
||||||
|
coap_send_message(uip_ipaddr_t *addr, uint16_t port, uint8_t *data, uint16_t length);
|
||||||
|
|
||||||
|
void
|
||||||
|
coap_handle_receive(void);
|
||||||
|
|
||||||
|
#endif
|
|
@ -94,6 +94,7 @@ typedef enum {
|
||||||
NOT_FOUND_4_04 = 132, /* NOT_FOUND */
|
NOT_FOUND_4_04 = 132, /* NOT_FOUND */
|
||||||
METHOD_NOT_ALLOWED_4_05 = 133, /* METHOD_NOT_ALLOWED */
|
METHOD_NOT_ALLOWED_4_05 = 133, /* METHOD_NOT_ALLOWED */
|
||||||
NOT_ACCEPTABLE_4_06 = 134, /* NOT_ACCEPTABLE */
|
NOT_ACCEPTABLE_4_06 = 134, /* NOT_ACCEPTABLE */
|
||||||
|
REQUEST_ENTITY_INCOMPLETE_4_08 = 136, /* REQUEST_ENTITY_INCOMPLETE */
|
||||||
PRECONDITION_FAILED_4_12 = 140, /* BAD_REQUEST */
|
PRECONDITION_FAILED_4_12 = 140, /* BAD_REQUEST */
|
||||||
REQUEST_ENTITY_TOO_LARGE_4_13 = 141, /* REQUEST_ENTITY_TOO_LARGE */
|
REQUEST_ENTITY_TOO_LARGE_4_13 = 141, /* REQUEST_ENTITY_TOO_LARGE */
|
||||||
UNSUPPORTED_MEDIA_TYPE_4_15 = 143, /* UNSUPPORTED_MEDIA_TYPE */
|
UNSUPPORTED_MEDIA_TYPE_4_15 = 143, /* UNSUPPORTED_MEDIA_TYPE */
|
||||||
|
|
161
apps/er-coap/er-coap-dtls.c
Normal file
161
apps/er-coap/er-coap-dtls.c
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "contiki-net.h"
|
||||||
|
#include "er-coap.h"
|
||||||
|
#include "er-coap-engine.h"
|
||||||
|
|
||||||
|
#include "dtls.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define DEBUG DEBUG_NONE
|
||||||
|
#include "dtls_debug.h"
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
static struct dtls_context_t *dtls_ctx = NULL;
|
||||||
|
|
||||||
|
static dtls_handler_t coap_dtls_callback = {
|
||||||
|
.write = coap_dtls_send_to_peer,
|
||||||
|
.read = coap_dtls_read_from_peer,
|
||||||
|
.event = NULL,
|
||||||
|
#ifdef DTLS_PSK
|
||||||
|
.get_psk_info = coap_dtls_get_psk_info,
|
||||||
|
#endif
|
||||||
|
#ifdef DTLS_ECC
|
||||||
|
.get_ecdsa_key = NULL,
|
||||||
|
.verify_ecdsa_key = NULL,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
coap_init_communication_layer(uint16_t port)
|
||||||
|
{
|
||||||
|
struct uip_udp_conn *udp_conn = NULL;
|
||||||
|
|
||||||
|
dtls_init();
|
||||||
|
dtls_set_log_level(DTLS_LOG_DEBUG);
|
||||||
|
|
||||||
|
udp_conn = udp_new(NULL, 0, NULL);
|
||||||
|
udp_bind(udp_conn, port);
|
||||||
|
|
||||||
|
dtls_ctx = dtls_new_context(udp_conn);
|
||||||
|
if(dtls_ctx) {
|
||||||
|
dtls_set_handler(dtls_ctx, &COAP_DTLS_CALLBACK);
|
||||||
|
}
|
||||||
|
/* new connection with remote host */
|
||||||
|
printf("COAP-DTLS listening on port %u\n", uip_ntohs(udp_conn->lport));
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
coap_send_message(uip_ipaddr_t *addr, uint16_t port,
|
||||||
|
uint8_t *data, uint16_t length)
|
||||||
|
{
|
||||||
|
session_t session;
|
||||||
|
|
||||||
|
dtls_session_init(&session);
|
||||||
|
uip_ipaddr_copy(&session.addr, addr);
|
||||||
|
session.port = port;
|
||||||
|
|
||||||
|
dtls_write(dtls_ctx, &session, data, length);
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
coap_handle_receive()
|
||||||
|
{
|
||||||
|
session_t session;
|
||||||
|
|
||||||
|
if(uip_newdata()) {
|
||||||
|
dtls_session_init(&session);
|
||||||
|
uip_ipaddr_copy(&session.addr, &UIP_IP_BUF->srcipaddr);
|
||||||
|
session.port = UIP_UDP_BUF->srcport;
|
||||||
|
|
||||||
|
dtls_handle_message(dtls_ctx, &session, uip_appdata, uip_datalen());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* DTLS Specific functions */
|
||||||
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
#ifdef DTLS_PSK
|
||||||
|
/* This function is the "key store" for tinyDTLS. It is called to
|
||||||
|
* retrieve a key for the given identiy within this particular
|
||||||
|
* session. */
|
||||||
|
int
|
||||||
|
coap_dtls_get_psk_info(struct dtls_context_t *ctx, const session_t *session,
|
||||||
|
dtls_credentials_type_t type,
|
||||||
|
const unsigned char *id, size_t id_len,
|
||||||
|
unsigned char *result, size_t result_length)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct keymap_t {
|
||||||
|
unsigned char *id;
|
||||||
|
size_t id_length;
|
||||||
|
unsigned char *key;
|
||||||
|
size_t key_length;
|
||||||
|
} psk[1] = {
|
||||||
|
{ (unsigned char *)DTLS_IDENTITY, DTLS_IDENTITY_LENGTH, (unsigned char *)DTLS_PSK_KEY_VALUE, DTLS_PSK_KEY_VALUE_LENGTH },
|
||||||
|
};
|
||||||
|
if(type == DTLS_PSK_IDENTITY) {
|
||||||
|
if(id_len) {
|
||||||
|
dtls_debug("got psk_identity_hint: '%.*s'\n", id_len, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(result_length < psk[0].id_length) {
|
||||||
|
dtls_warn("cannot set psk_identity -- buffer too small\n");
|
||||||
|
return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(result, psk[0].id, psk[0].id_length);
|
||||||
|
return psk[0].id_length;
|
||||||
|
} else if(type == DTLS_PSK_KEY) {
|
||||||
|
if(id) {
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < sizeof(psk) / sizeof(struct keymap_t); i++) {
|
||||||
|
if(id_len == psk[i].id_length && memcmp(id, psk[i].id, id_len) == 0) {
|
||||||
|
if(result_length < psk[i].key_length) {
|
||||||
|
dtls_warn("buffer too small for PSK");
|
||||||
|
return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(result, psk[i].key, psk[i].key_length);
|
||||||
|
return psk[i].key_length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dtls_alert_fatal_create(DTLS_ALERT_DECRYPT_ERROR);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
coap_dtls_send_to_peer(struct dtls_context_t *ctx,
|
||||||
|
session_t *session, uint8 *data, size_t len)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct uip_udp_conn *conn = (struct uip_udp_conn *)dtls_get_app_data(ctx);
|
||||||
|
|
||||||
|
uip_ipaddr_copy(&conn->ripaddr, &session->addr);
|
||||||
|
conn->rport = session->port;
|
||||||
|
|
||||||
|
uip_udp_packet_send(conn, data, len);
|
||||||
|
|
||||||
|
/* Restore server connection to allow data from any node */
|
||||||
|
memset(&conn->ripaddr, 0, sizeof(conn->ripaddr));
|
||||||
|
memset(&conn->rport, 0, sizeof(conn->rport));
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
coap_dtls_read_from_peer(struct dtls_context_t *ctx,
|
||||||
|
session_t *session, uint8 *data, size_t len)
|
||||||
|
{
|
||||||
|
uip_len = len;
|
||||||
|
memmove(uip_appdata, data, len);
|
||||||
|
coap_receive(ctx);
|
||||||
|
return 0;
|
||||||
|
}
|
47
apps/er-coap/er-coap-dtls.h
Normal file
47
apps/er-coap/er-coap-dtls.h
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#ifndef COAP_DTLS_H_
|
||||||
|
#define COAP_DTLS_H_
|
||||||
|
|
||||||
|
/* Internal configuration of tinydtls for er-coap-dtls */
|
||||||
|
|
||||||
|
#if defined DTLS_CONF_IDENTITY && defined DTLS_CONF_IDENTITY_LENGTH
|
||||||
|
#define DTLS_IDENTITY DTLS_CONF_IDENTITY
|
||||||
|
#define DTLS_IDENTITY_LENGTH DTLS_CONF_IDENTITY_LENGTH
|
||||||
|
#else
|
||||||
|
#define DTLS_IDENTITY "Client_identity"
|
||||||
|
#define DTLS_IDENTITY_LENGTH 15
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined DTLS_CONF_PSK_KEY && defined DTLS_CONF_PSK_KEY_LENGTH
|
||||||
|
#define DTLS_PSK_KEY_VALUE DTLS_CONF_PSK_KEY
|
||||||
|
#define DTLS_PSK_KEY_VALUE_LENGTH DTLS_CONF_PSK_KEY_LENGTH
|
||||||
|
#else
|
||||||
|
#warning "DTLS: Using default secret key !"
|
||||||
|
#define DTLS_PSK_KEY_VALUE "secretPSK"
|
||||||
|
#define DTLS_PSK_KEY_VALUE_LENGTH 9
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Structure that hold tinydtls callbacks, has type 'dtls_handler_t'. */
|
||||||
|
#ifndef COAP_DTLS_CALLBACK
|
||||||
|
#ifdef COAP_DTLS_CONF_CALLBACK
|
||||||
|
#define COAP_DTLS_CALLBACK COAP_DTLS_CONF_CALLBACK
|
||||||
|
#else /* COAP_DTLS_CONF_CALLBACK */
|
||||||
|
#define COAP_DTLS_CALLBACK coap_dtls_callback
|
||||||
|
#endif /* COAP_DTLS_CALLBACK */
|
||||||
|
|
||||||
|
/* Send 'data' to peer defined by session */
|
||||||
|
int coap_dtls_send_to_peer(struct dtls_context_t *ctx,
|
||||||
|
session_t *session, uint8 *data, size_t len);
|
||||||
|
|
||||||
|
/* Read 'data' from peer */
|
||||||
|
int coap_dtls_read_from_peer(struct dtls_context_t *ctx,
|
||||||
|
session_t *session, uint8 *data, size_t len);
|
||||||
|
#ifdef DTLS_PSK
|
||||||
|
/* Retrieve the key for given identity withing this session */
|
||||||
|
int coap_dtls_get_psk_info(struct dtls_context_t *ctx,
|
||||||
|
const session_t *session,
|
||||||
|
dtls_credentials_type_t type,
|
||||||
|
const unsigned char *id, size_t id_len,
|
||||||
|
unsigned char *result, size_t result_length);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* COAP_DTLS_H_ */
|
|
@ -41,6 +41,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "er-coap-engine.h"
|
#include "er-coap-engine.h"
|
||||||
|
#include "er-coap-communication.h"
|
||||||
|
|
||||||
#define DEBUG 0
|
#define DEBUG 0
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
@ -64,8 +65,8 @@ static service_callback_t service_cbk = NULL;
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
/*- Internal API ------------------------------------------------------------*/
|
/*- Internal API ------------------------------------------------------------*/
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
static int
|
int
|
||||||
coap_receive(void)
|
coap_receive()
|
||||||
{
|
{
|
||||||
erbium_status_code = NO_ERROR;
|
erbium_status_code = NO_ERROR;
|
||||||
|
|
||||||
|
@ -346,7 +347,7 @@ PROCESS_THREAD(coap_engine, ev, data)
|
||||||
PROCESS_YIELD();
|
PROCESS_YIELD();
|
||||||
|
|
||||||
if(ev == tcpip_event) {
|
if(ev == tcpip_event) {
|
||||||
coap_receive();
|
coap_handle_receive();
|
||||||
} else if(ev == PROCESS_EVENT_TIMER) {
|
} else if(ev == PROCESS_EVENT_TIMER) {
|
||||||
/* retransmissions are handled here */
|
/* retransmissions are handled here */
|
||||||
coap_check_transactions();
|
coap_check_transactions();
|
||||||
|
@ -482,6 +483,7 @@ const struct rest_implementation coap_rest_implementation = {
|
||||||
NOT_FOUND_4_04,
|
NOT_FOUND_4_04,
|
||||||
METHOD_NOT_ALLOWED_4_05,
|
METHOD_NOT_ALLOWED_4_05,
|
||||||
NOT_ACCEPTABLE_4_06,
|
NOT_ACCEPTABLE_4_06,
|
||||||
|
REQUEST_ENTITY_INCOMPLETE_4_08,
|
||||||
REQUEST_ENTITY_TOO_LARGE_4_13,
|
REQUEST_ENTITY_TOO_LARGE_4_13,
|
||||||
UNSUPPORTED_MEDIA_TYPE_4_15,
|
UNSUPPORTED_MEDIA_TYPE_4_15,
|
||||||
INTERNAL_SERVER_ERROR_5_00,
|
INTERNAL_SERVER_ERROR_5_00,
|
||||||
|
|
|
@ -52,6 +52,7 @@ typedef coap_packet_t rest_request_t;
|
||||||
typedef coap_packet_t rest_response_t;
|
typedef coap_packet_t rest_response_t;
|
||||||
|
|
||||||
void coap_init_engine(void);
|
void coap_init_engine(void);
|
||||||
|
int coap_receive();
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
/*- Client Part -------------------------------------------------------------*/
|
/*- Client Part -------------------------------------------------------------*/
|
||||||
|
|
|
@ -107,7 +107,7 @@ int coap_obs_remove_observee_by_token(uip_ipaddr_t *addr, uint16_t port,
|
||||||
int coap_obs_remove_observee_by_url(uip_ipaddr_t *addr, uint16_t port,
|
int coap_obs_remove_observee_by_url(uip_ipaddr_t *addr, uint16_t port,
|
||||||
const char *url);
|
const char *url);
|
||||||
|
|
||||||
void coap_handle_notification(uip_ipaddr_t *, uint16_t port,
|
void coap_handle_notification(uip_ipaddr_t *addr, uint16_t port,
|
||||||
coap_packet_t *notification);
|
coap_packet_t *notification);
|
||||||
|
|
||||||
coap_observee_t *coap_obs_request_registration(uip_ipaddr_t *addr,
|
coap_observee_t *coap_obs_request_registration(uip_ipaddr_t *addr,
|
||||||
|
|
|
@ -249,6 +249,8 @@ coap_notify_observers_sub(resource_t *resource, const char *subpath)
|
||||||
|
|
||||||
if(notification->code < BAD_REQUEST_4_00) {
|
if(notification->code < BAD_REQUEST_4_00) {
|
||||||
coap_set_header_observe(notification, (obs->obs_counter)++);
|
coap_set_header_observe(notification, (obs->obs_counter)++);
|
||||||
|
/* mask out to keep the CoAP observe option length <= 3 bytes */
|
||||||
|
obs->obs_counter &= 0xffffff;
|
||||||
}
|
}
|
||||||
coap_set_token(notification, obs->token, obs->token_len);
|
coap_set_token(notification, obs->token, obs->token_len);
|
||||||
|
|
||||||
|
@ -266,7 +268,7 @@ coap_observe_handler(resource_t *resource, void *request, void *response)
|
||||||
{
|
{
|
||||||
coap_packet_t *const coap_req = (coap_packet_t *)request;
|
coap_packet_t *const coap_req = (coap_packet_t *)request;
|
||||||
coap_packet_t *const coap_res = (coap_packet_t *)response;
|
coap_packet_t *const coap_res = (coap_packet_t *)response;
|
||||||
coap_observer_t * obs;
|
coap_observer_t *obs;
|
||||||
|
|
||||||
if(coap_req->code == COAP_GET && coap_res->code < 128) { /* GET request and response without error code */
|
if(coap_req->code == COAP_GET && coap_res->code < 128) { /* GET request and response without error code */
|
||||||
if(IS_OPTION(coap_req, COAP_OPTION_OBSERVE)) {
|
if(IS_OPTION(coap_req, COAP_OPTION_OBSERVE)) {
|
||||||
|
@ -276,6 +278,8 @@ coap_observe_handler(resource_t *resource, void *request, void *response)
|
||||||
coap_req->uri_path, coap_req->uri_path_len);
|
coap_req->uri_path, coap_req->uri_path_len);
|
||||||
if(obs) {
|
if(obs) {
|
||||||
coap_set_header_observe(coap_res, (obs->obs_counter)++);
|
coap_set_header_observe(coap_res, (obs->obs_counter)++);
|
||||||
|
/* mask out to keep the CoAP observe option length <= 3 bytes */
|
||||||
|
obs->obs_counter &= 0xffffff;
|
||||||
/*
|
/*
|
||||||
* Following payload is for demonstration purposes only.
|
* Following payload is for demonstration purposes only.
|
||||||
* A subscription should return the same representation as a normal GET.
|
* A subscription should return the same representation as a normal GET.
|
||||||
|
|
42
apps/er-coap/er-coap-udp.c
Normal file
42
apps/er-coap/er-coap-udp.c
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "contiki-net.h"
|
||||||
|
#include "er-coap-engine.h"
|
||||||
|
#include "er-coap-communication.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define DEBUG DEBUG_NONE
|
||||||
|
#include "uip-debug.h"
|
||||||
|
|
||||||
|
static struct uip_udp_conn *udp_conn = NULL;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
coap_init_communication_layer(uint16_t port)
|
||||||
|
{
|
||||||
|
/* new connection with remote host */
|
||||||
|
udp_conn = udp_new(NULL, 0, NULL);
|
||||||
|
udp_bind(udp_conn, port);
|
||||||
|
PRINTF("Listening on port %u\n", uip_ntohs(udp_conn->lport));
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
coap_send_message(uip_ipaddr_t *addr, uint16_t port, uint8_t *data, uint16_t length)
|
||||||
|
{
|
||||||
|
/* Configure connection to reply to client */
|
||||||
|
uip_ipaddr_copy(&udp_conn->ripaddr, addr);
|
||||||
|
udp_conn->rport = port;
|
||||||
|
|
||||||
|
uip_udp_packet_send(udp_conn, data, length);
|
||||||
|
PRINTF("-sent UDP datagram (%u)-\n", length);
|
||||||
|
|
||||||
|
/* Restore server connection to allow data from any node */
|
||||||
|
memset(&udp_conn->ripaddr, 0, sizeof(udp_conn->ripaddr));
|
||||||
|
udp_conn->rport = 0;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
coap_handle_receive()
|
||||||
|
{
|
||||||
|
coap_receive();
|
||||||
|
}
|
|
@ -44,6 +44,7 @@
|
||||||
|
|
||||||
#include "er-coap.h"
|
#include "er-coap.h"
|
||||||
#include "er-coap-transactions.h"
|
#include "er-coap-transactions.h"
|
||||||
|
#include "er-coap-communication.h"
|
||||||
|
|
||||||
#define DEBUG 0
|
#define DEBUG 0
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
@ -60,7 +61,6 @@
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
/*- Variables ---------------------------------------------------------------*/
|
/*- Variables ---------------------------------------------------------------*/
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
static struct uip_udp_conn *udp_conn = NULL;
|
|
||||||
static uint16_t current_mid = 0;
|
static uint16_t current_mid = 0;
|
||||||
|
|
||||||
coap_status_t erbium_status_code = NO_ERROR;
|
coap_status_t erbium_status_code = NO_ERROR;
|
||||||
|
@ -279,9 +279,7 @@ void
|
||||||
coap_init_connection(uint16_t port)
|
coap_init_connection(uint16_t port)
|
||||||
{
|
{
|
||||||
/* new connection with remote host */
|
/* new connection with remote host */
|
||||||
udp_conn = udp_new(NULL, 0, NULL);
|
coap_init_communication_layer(port);
|
||||||
udp_bind(udp_conn, port);
|
|
||||||
PRINTF("Listening on port %u\n", uip_ntohs(udp_conn->lport));
|
|
||||||
|
|
||||||
/* initialize transaction ID */
|
/* initialize transaction ID */
|
||||||
current_mid = random_rand();
|
current_mid = random_rand();
|
||||||
|
@ -422,23 +420,6 @@ coap_serialize_message(void *packet, uint8_t *buffer)
|
||||||
return (option - buffer) + coap_pkt->payload_len; /* packet length */
|
return (option - buffer) + coap_pkt->payload_len; /* packet length */
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
void
|
|
||||||
coap_send_message(uip_ipaddr_t *addr, uint16_t port, uint8_t *data,
|
|
||||||
uint16_t length)
|
|
||||||
{
|
|
||||||
/* configure connection to reply to client */
|
|
||||||
uip_ipaddr_copy(&udp_conn->ripaddr, addr);
|
|
||||||
udp_conn->rport = port;
|
|
||||||
|
|
||||||
uip_udp_packet_send(udp_conn, data, length);
|
|
||||||
|
|
||||||
PRINTF("-sent UDP datagram (%u)-\n", length);
|
|
||||||
|
|
||||||
/* restore server socket to allow data from any node */
|
|
||||||
memset(&udp_conn->ripaddr, 0, sizeof(udp_conn->ripaddr));
|
|
||||||
udp_conn->rport = 0;
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
coap_status_t
|
coap_status_t
|
||||||
coap_parse_message(void *packet, uint8_t *data, uint16_t data_len)
|
coap_parse_message(void *packet, uint8_t *data, uint16_t data_len)
|
||||||
{
|
{
|
||||||
|
@ -529,8 +510,21 @@ coap_parse_message(void *packet, uint8_t *data, uint16_t data_len)
|
||||||
++current_option;
|
++current_option;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(current_option + option_length > data + data_len) {
|
||||||
|
/* Malformed CoAP - out of bounds */
|
||||||
|
PRINTF("BAD REQUEST: options outside data packet: %u > %u\n",
|
||||||
|
(unsigned)(current_option + option_length - data), data_len);
|
||||||
|
return BAD_REQUEST_4_00;
|
||||||
|
}
|
||||||
|
|
||||||
option_number += option_delta;
|
option_number += option_delta;
|
||||||
|
|
||||||
|
if(option_number > COAP_OPTION_SIZE1) {
|
||||||
|
/* Malformed CoAP - out of bounds */
|
||||||
|
PRINTF("BAD REQUEST: option number too large: %u\n", option_number);
|
||||||
|
return BAD_REQUEST_4_00;
|
||||||
|
}
|
||||||
|
|
||||||
PRINTF("OPTION %u (delta %u, len %zu): ", option_number, option_delta,
|
PRINTF("OPTION %u (delta %u, len %zu): ", option_number, option_delta,
|
||||||
option_length);
|
option_length);
|
||||||
|
|
||||||
|
|
|
@ -119,6 +119,20 @@ static const char *get_uri (void *request)
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *get_query (void *request)
|
||||||
|
{
|
||||||
|
static char buf [MAX_QUERY_STRING_LENGTH];
|
||||||
|
const char *query;
|
||||||
|
size_t len = coap_get_header_uri_query (request, &query);
|
||||||
|
if (len > sizeof (buf) - 1) {
|
||||||
|
*buf = '\0';
|
||||||
|
} else {
|
||||||
|
strncpy (buf, query, len);
|
||||||
|
buf [len] = '\0';
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
void generic_get_handler
|
void generic_get_handler
|
||||||
( void *request
|
( void *request
|
||||||
, void *response
|
, void *response
|
||||||
|
@ -127,7 +141,12 @@ void generic_get_handler
|
||||||
, int32_t *offset
|
, int32_t *offset
|
||||||
, char *name
|
, char *name
|
||||||
, int is_str
|
, int is_str
|
||||||
, size_t (*to_str)(const char *name, const char *uri, char *buf, size_t bsize)
|
, size_t (*to_str)
|
||||||
|
( const char *name
|
||||||
|
, const char *uri
|
||||||
|
, const char *query
|
||||||
|
, char *buf, size_t bsize
|
||||||
|
)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
int success = 1;
|
int success = 1;
|
||||||
|
@ -135,6 +154,7 @@ void generic_get_handler
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
unsigned int accept = -1;
|
unsigned int accept = -1;
|
||||||
const char *uri = get_uri (request);
|
const char *uri = get_uri (request);
|
||||||
|
const char *query = get_query (request);
|
||||||
|
|
||||||
REST.get_header_accept (request, &accept);
|
REST.get_header_accept (request, &accept);
|
||||||
if ( accept != -1
|
if ( accept != -1
|
||||||
|
@ -160,7 +180,7 @@ void generic_get_handler
|
||||||
success = 0;
|
success = 0;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
len += to_str (name, uri, temp + len, sizeof (temp) - len);
|
len += to_str (name, uri, query, temp + len, sizeof (temp) - len);
|
||||||
if (len > sizeof (temp)) {
|
if (len > sizeof (temp)) {
|
||||||
success = 0;
|
success = 0;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -176,7 +196,7 @@ void generic_get_handler
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
} else { // TEXT Format
|
} else { // TEXT Format
|
||||||
len += to_str (name, uri, temp + len, sizeof (temp) - len);
|
len += to_str (name, uri, query, temp + len, sizeof (temp) - len);
|
||||||
if (len > sizeof (temp)) {
|
if (len > sizeof (temp)) {
|
||||||
success = 0;
|
success = 0;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -203,7 +223,8 @@ void generic_put_handler
|
||||||
, uint16_t preferred_size
|
, uint16_t preferred_size
|
||||||
, int32_t *offset
|
, int32_t *offset
|
||||||
, char *name
|
, char *name
|
||||||
, int (*from_str)(const char *name, const char *uri, const char *s)
|
, int (*from_str)
|
||||||
|
(const char *name, const char *uri, const char *query, const char *s)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
int success = 1;
|
int success = 1;
|
||||||
|
@ -212,6 +233,7 @@ void generic_put_handler
|
||||||
const uint8_t *bytes = NULL;
|
const uint8_t *bytes = NULL;
|
||||||
unsigned int c_ctype;
|
unsigned int c_ctype;
|
||||||
const char *uri = get_uri (request);
|
const char *uri = get_uri (request);
|
||||||
|
const char *query = get_query (request);
|
||||||
REST.get_header_content_type (request, &c_ctype);
|
REST.get_header_content_type (request, &c_ctype);
|
||||||
|
|
||||||
if (from_str && (len = coap_get_payload (request, &bytes))) {
|
if (from_str && (len = coap_get_payload (request, &bytes))) {
|
||||||
|
@ -226,7 +248,7 @@ void generic_put_handler
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (from_str (name, uri, temp) < 0) {
|
if (from_str (name, uri, query, temp) < 0) {
|
||||||
success = 0;
|
success = 0;
|
||||||
} else {
|
} else {
|
||||||
REST.set_response_status (response, REST.status.CHANGED);
|
REST.set_response_status (response, REST.status.CHANGED);
|
||||||
|
|
|
@ -52,6 +52,7 @@
|
||||||
|
|
||||||
#define MAX_GET_STRING_LENGTH 100
|
#define MAX_GET_STRING_LENGTH 100
|
||||||
#define MAX_URI_STRING_LENGTH 30
|
#define MAX_URI_STRING_LENGTH 30
|
||||||
|
#define MAX_QUERY_STRING_LENGTH 30
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A macro that extends the resource definition and also sets up the
|
* A macro that extends the resource definition and also sets up the
|
||||||
|
@ -124,11 +125,8 @@ extern int8_t json_parse_variable
|
||||||
*
|
*
|
||||||
* The callback functions get the name of the parameter as a first
|
* The callback functions get the name of the parameter as a first
|
||||||
* argument, this allows to re-use the same function for different
|
* argument, this allows to re-use the same function for different
|
||||||
* parameters.
|
* parameters. In addition it gets a buffer and the size of the buffer.
|
||||||
* For the to_str function the is_json flag allows to generate a
|
* It needs to return the number of bytes output, similar to sprintf.
|
||||||
* different string depending on the content-type. In addition it gets a
|
|
||||||
* buffer and the size of the buffer. It needs to return the number of
|
|
||||||
* bytes output, similar to sprintf.
|
|
||||||
*/
|
*/
|
||||||
extern void generic_get_handler
|
extern void generic_get_handler
|
||||||
( void *request
|
( void *request
|
||||||
|
@ -138,7 +136,13 @@ extern void generic_get_handler
|
||||||
, int32_t *offset
|
, int32_t *offset
|
||||||
, char *name
|
, char *name
|
||||||
, int is_str
|
, int is_str
|
||||||
, size_t (*to_str)(const char *name, const char *uri, char *buf, size_t bsize)
|
, size_t (*to_str)
|
||||||
|
( const char *name
|
||||||
|
, const char *uri
|
||||||
|
, const char *query
|
||||||
|
, char *buf
|
||||||
|
, size_t bsize
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -161,7 +165,8 @@ extern void generic_put_handler
|
||||||
, uint16_t preferred_size
|
, uint16_t preferred_size
|
||||||
, int32_t *offset
|
, int32_t *offset
|
||||||
, char *name
|
, char *name
|
||||||
, int (*from_str)(const char *name, const char *uri, const char *s)
|
, int (*from_str)
|
||||||
|
(const char *name, const char *uri, const char *query, const char *s)
|
||||||
);
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -65,7 +65,7 @@
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
#define DEBUG 0
|
#define DEBUG 0
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
#define PRINTF(...) PRINTF(__VA_ARGS__)
|
#define PRINTF(...) printf(__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define PRINTF(...)
|
#define PRINTF(...)
|
||||||
#endif
|
#endif
|
||||||
|
@ -130,6 +130,7 @@ typedef enum {
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
/* Protothread send macros */
|
/* Protothread send macros */
|
||||||
#define PT_MQTT_WRITE_BYTES(conn, data, len) \
|
#define PT_MQTT_WRITE_BYTES(conn, data, len) \
|
||||||
|
conn->out_write_pos = 0; \
|
||||||
while(write_bytes(conn, data, len)) { \
|
while(write_bytes(conn, data, len)) { \
|
||||||
PT_WAIT_UNTIL(pt, (conn)->out_buffer_sent); \
|
PT_WAIT_UNTIL(pt, (conn)->out_buffer_sent); \
|
||||||
}
|
}
|
||||||
|
@ -147,15 +148,19 @@ typedef enum {
|
||||||
*/
|
*/
|
||||||
#define PT_MQTT_WAIT_SEND() \
|
#define PT_MQTT_WAIT_SEND() \
|
||||||
do { \
|
do { \
|
||||||
process_post(PROCESS_CURRENT(), mqtt_continue_send_event, NULL); \
|
if (PROCESS_ERR_OK == \
|
||||||
|
process_post(PROCESS_CURRENT(), mqtt_continue_send_event, NULL)) { \
|
||||||
|
do { \
|
||||||
PROCESS_WAIT_EVENT(); \
|
PROCESS_WAIT_EVENT(); \
|
||||||
if(ev == mqtt_abort_now_event) { \
|
if(ev == mqtt_abort_now_event) { \
|
||||||
conn->state = MQTT_CONN_STATE_ABORT_IMMEDIATE; \
|
conn->state = MQTT_CONN_STATE_ABORT_IMMEDIATE; \
|
||||||
PT_EXIT(&conn->out_proto_thread); \
|
PT_INIT(&conn->out_proto_thread); \
|
||||||
process_post(PROCESS_CURRENT(), ev, data); \
|
process_post(PROCESS_CURRENT(), ev, data); \
|
||||||
} else if(ev >= mqtt_event_min && ev <= mqtt_event_max) { \
|
} else if(ev >= mqtt_event_min && ev <= mqtt_event_max) { \
|
||||||
process_post(PROCESS_CURRENT(), ev, data); \
|
process_post(PROCESS_CURRENT(), ev, data); \
|
||||||
} \
|
} \
|
||||||
|
} while (ev != mqtt_continue_send_event); \
|
||||||
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
static process_event_t mqtt_do_connect_tcp_event;
|
static process_event_t mqtt_do_connect_tcp_event;
|
||||||
|
@ -751,6 +756,8 @@ handle_connack(struct mqtt_connection *conn)
|
||||||
call_event(conn,
|
call_event(conn,
|
||||||
MQTT_EVENT_CONNECTION_REFUSED_ERROR,
|
MQTT_EVENT_CONNECTION_REFUSED_ERROR,
|
||||||
&conn->in_packet.payload[1]);
|
&conn->in_packet.payload[1]);
|
||||||
|
abort_connection(conn);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
conn->out_packet.qos_state = MQTT_QOS_STATE_GOT_ACK;
|
conn->out_packet.qos_state = MQTT_QOS_STATE_GOT_ACK;
|
||||||
|
@ -1186,8 +1193,8 @@ PROCESS_THREAD(mqtt_process, ev, data)
|
||||||
if(conn->state == MQTT_CONN_STATE_SENDING_MQTT_DISCONNECT) {
|
if(conn->state == MQTT_CONN_STATE_SENDING_MQTT_DISCONNECT) {
|
||||||
if(conn->out_buffer_sent == 1) {
|
if(conn->out_buffer_sent == 1) {
|
||||||
PT_INIT(&conn->out_proto_thread);
|
PT_INIT(&conn->out_proto_thread);
|
||||||
while(disconnect_pt(&conn->out_proto_thread, conn) < PT_EXITED &&
|
while(conn->state != MQTT_CONN_STATE_ABORT_IMMEDIATE &&
|
||||||
conn->state != MQTT_CONN_STATE_ABORT_IMMEDIATE) {
|
disconnect_pt(&conn->out_proto_thread, conn) < PT_EXITED) {
|
||||||
PT_MQTT_WAIT_SEND();
|
PT_MQTT_WAIT_SEND();
|
||||||
}
|
}
|
||||||
abort_connection(conn);
|
abort_connection(conn);
|
||||||
|
@ -1204,8 +1211,8 @@ PROCESS_THREAD(mqtt_process, ev, data)
|
||||||
if(conn->out_buffer_sent == 1 &&
|
if(conn->out_buffer_sent == 1 &&
|
||||||
conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) {
|
conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) {
|
||||||
PT_INIT(&conn->out_proto_thread);
|
PT_INIT(&conn->out_proto_thread);
|
||||||
while(pingreq_pt(&conn->out_proto_thread, conn) < PT_EXITED &&
|
while(conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER &&
|
||||||
conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) {
|
pingreq_pt(&conn->out_proto_thread, conn) < PT_EXITED) {
|
||||||
PT_MQTT_WAIT_SEND();
|
PT_MQTT_WAIT_SEND();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1217,8 +1224,8 @@ PROCESS_THREAD(mqtt_process, ev, data)
|
||||||
if(conn->out_buffer_sent == 1 &&
|
if(conn->out_buffer_sent == 1 &&
|
||||||
conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) {
|
conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) {
|
||||||
PT_INIT(&conn->out_proto_thread);
|
PT_INIT(&conn->out_proto_thread);
|
||||||
while(subscribe_pt(&conn->out_proto_thread, conn) < PT_EXITED &&
|
while(conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER &&
|
||||||
conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) {
|
subscribe_pt(&conn->out_proto_thread, conn) < PT_EXITED) {
|
||||||
PT_MQTT_WAIT_SEND();
|
PT_MQTT_WAIT_SEND();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1230,8 +1237,8 @@ PROCESS_THREAD(mqtt_process, ev, data)
|
||||||
if(conn->out_buffer_sent == 1 &&
|
if(conn->out_buffer_sent == 1 &&
|
||||||
conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) {
|
conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) {
|
||||||
PT_INIT(&conn->out_proto_thread);
|
PT_INIT(&conn->out_proto_thread);
|
||||||
while(unsubscribe_pt(&conn->out_proto_thread, conn) < PT_EXITED &&
|
while(conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER &&
|
||||||
conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) {
|
unsubscribe_pt(&conn->out_proto_thread, conn) < PT_EXITED) {
|
||||||
PT_MQTT_WAIT_SEND();
|
PT_MQTT_WAIT_SEND();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1243,8 +1250,8 @@ PROCESS_THREAD(mqtt_process, ev, data)
|
||||||
if(conn->out_buffer_sent == 1 &&
|
if(conn->out_buffer_sent == 1 &&
|
||||||
conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) {
|
conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) {
|
||||||
PT_INIT(&conn->out_proto_thread);
|
PT_INIT(&conn->out_proto_thread);
|
||||||
while(publish_pt(&conn->out_proto_thread, conn) < PT_EXITED &&
|
while(conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER &&
|
||||||
conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) {
|
publish_pt(&conn->out_proto_thread, conn) < PT_EXITED) {
|
||||||
PT_MQTT_WAIT_SEND();
|
PT_MQTT_WAIT_SEND();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1331,7 +1338,9 @@ mqtt_connect(struct mqtt_connection *conn, char *host, uint16_t port,
|
||||||
conn->connect_vhdr_flags |= MQTT_VHDR_CLEAN_SESSION_FLAG;
|
conn->connect_vhdr_flags |= MQTT_VHDR_CLEAN_SESSION_FLAG;
|
||||||
|
|
||||||
/* convert the string IPv6 address to a numeric IPv6 address */
|
/* convert the string IPv6 address to a numeric IPv6 address */
|
||||||
uiplib_ip6addrconv(host, &ip6addr);
|
if(uiplib_ip6addrconv(host, &ip6addr) == 0) {
|
||||||
|
return MQTT_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
uip_ipaddr_copy(&(conn->server_ip), ipaddr);
|
uip_ipaddr_copy(&(conn->server_ip), ipaddr);
|
||||||
|
|
||||||
|
|
|
@ -196,7 +196,7 @@ typedef enum {
|
||||||
MQTT_CONN_STATE_ERROR,
|
MQTT_CONN_STATE_ERROR,
|
||||||
MQTT_CONN_STATE_DNS_ERROR,
|
MQTT_CONN_STATE_DNS_ERROR,
|
||||||
MQTT_CONN_STATE_DISCONNECTING,
|
MQTT_CONN_STATE_DISCONNECTING,
|
||||||
|
MQTT_CONN_STATE_ABORT_IMMEDIATE,
|
||||||
MQTT_CONN_STATE_NOT_CONNECTED,
|
MQTT_CONN_STATE_NOT_CONNECTED,
|
||||||
MQTT_CONN_STATE_DNS_LOOKUP,
|
MQTT_CONN_STATE_DNS_LOOKUP,
|
||||||
MQTT_CONN_STATE_TCP_CONNECTING,
|
MQTT_CONN_STATE_TCP_CONNECTING,
|
||||||
|
@ -204,7 +204,6 @@ typedef enum {
|
||||||
MQTT_CONN_STATE_CONNECTING_TO_BROKER,
|
MQTT_CONN_STATE_CONNECTING_TO_BROKER,
|
||||||
MQTT_CONN_STATE_CONNECTED_TO_BROKER,
|
MQTT_CONN_STATE_CONNECTED_TO_BROKER,
|
||||||
MQTT_CONN_STATE_SENDING_MQTT_DISCONNECT,
|
MQTT_CONN_STATE_SENDING_MQTT_DISCONNECT,
|
||||||
MQTT_CONN_STATE_ABORT_IMMEDIATE,
|
|
||||||
} mqtt_conn_state_t;
|
} mqtt_conn_state_t;
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
struct mqtt_string {
|
struct mqtt_string {
|
||||||
|
|
|
@ -587,6 +587,40 @@ get_resource(const lwm2m_instance_t *instance, lwm2m_context_t *context)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* @brief Write a list of object instances as a CoRE Link-format list
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
write_object_instances_link(const lwm2m_object_t *object,
|
||||||
|
char *buffer, size_t size)
|
||||||
|
{
|
||||||
|
const lwm2m_instance_t *instance;
|
||||||
|
int len, rdlen, i;
|
||||||
|
|
||||||
|
PRINTF("</%d>", object->id);
|
||||||
|
rdlen = snprintf(buffer, size, "</%d>",
|
||||||
|
object->id);
|
||||||
|
if(rdlen < 0 || rdlen >= size) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < object->count; i++) {
|
||||||
|
if((object->instances[i].flag & LWM2M_INSTANCE_FLAG_USED) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
instance = &object->instances[i];
|
||||||
|
PRINTF(",</%d/%d>", object->id, instance->id);
|
||||||
|
|
||||||
|
len = snprintf(&buffer[rdlen], size - rdlen,
|
||||||
|
",<%d/%d>", object->id, instance->id);
|
||||||
|
rdlen += len;
|
||||||
|
if(len < 0 || rdlen >= size) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rdlen;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
static int
|
static int
|
||||||
write_rd_link_data(const lwm2m_object_t *object,
|
write_rd_link_data(const lwm2m_object_t *object,
|
||||||
const lwm2m_instance_t *instance,
|
const lwm2m_instance_t *instance,
|
||||||
|
@ -1052,6 +1086,23 @@ lwm2m_engine_handler(const lwm2m_object_t *object,
|
||||||
REST.set_header_content_type(response, LWM2M_JSON);
|
REST.set_header_content_type(response, LWM2M_JSON);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if(depth == 1) {
|
||||||
|
/* produce a list of instances */
|
||||||
|
if(method != METHOD_GET) {
|
||||||
|
REST.set_response_status(response, METHOD_NOT_ALLOWED_4_05);
|
||||||
|
} else {
|
||||||
|
int rdlen;
|
||||||
|
PRINTF("Sending instance list for object %u\n", object->id);
|
||||||
|
/* TODO: if(accept == APPLICATION_LINK_FORMAT) { */
|
||||||
|
rdlen = write_object_instances_link(object, (char *)buffer, preferred_size);
|
||||||
|
if(rdlen < 0) {
|
||||||
|
PRINTF("Failed to generate object response\n");
|
||||||
|
REST.set_response_status(response, SERVICE_UNAVAILABLE_5_03);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
REST.set_header_content_type(response, REST.type.APPLICATION_LINK_FORMAT);
|
||||||
|
REST.set_response_payload(response, buffer, rdlen);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
|
@ -45,6 +45,14 @@
|
||||||
#include "net/ipv6/uip-ds6-route.h"
|
#include "net/ipv6/uip-ds6-route.h"
|
||||||
#include "net/packetbuf.h"
|
#include "net/packetbuf.h"
|
||||||
#include "net/rpl/rpl-conf.h"
|
#include "net/rpl/rpl-conf.h"
|
||||||
|
#include "net/rpl/rpl-private.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The body of this rule should be compiled only when "nbr_routes" is available,
|
||||||
|
* otherwise a link error causes build failure. "nbr_routes" is compiled if
|
||||||
|
* UIP_CONF_MAX_ROUTES != 0. See uip-ds6-route.c.
|
||||||
|
*/
|
||||||
|
#if UIP_CONF_MAX_ROUTES != 0
|
||||||
|
|
||||||
#if ORCHESTRA_UNICAST_SENDER_BASED && ORCHESTRA_COLLISION_FREE_HASH
|
#if ORCHESTRA_UNICAST_SENDER_BASED && ORCHESTRA_COLLISION_FREE_HASH
|
||||||
#define UNICAST_SLOT_SHARED_FLAG ((ORCHESTRA_UNICAST_PERIOD < (ORCHESTRA_MAX_HASH + 1)) ? LINK_OPTION_SHARED : 0)
|
#define UNICAST_SLOT_SHARED_FLAG ((ORCHESTRA_UNICAST_PERIOD < (ORCHESTRA_MAX_HASH + 1)) ? LINK_OPTION_SHARED : 0)
|
||||||
|
@ -211,3 +219,5 @@ struct orchestra_rule unicast_per_neighbor_rpl_storing = {
|
||||||
child_added,
|
child_added,
|
||||||
child_removed,
|
child_removed,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif /* UIP_MAX_ROUTES */
|
||||||
|
|
1
apps/ota-update/Makefile.ota-update
Normal file
1
apps/ota-update/Makefile.ota-update
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ota-update_src = res_bootloader.c res_reboot.c res_upload_image.c
|
22
apps/ota-update/ota-update.h
Normal file
22
apps/ota-update/ota-update.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
extern resource_t res_upload_image;
|
||||||
|
extern resource_t res_part_count;
|
||||||
|
extern resource_t res_part_size;
|
||||||
|
extern resource_t res_boot_default;
|
||||||
|
extern resource_t res_boot_next;
|
||||||
|
extern resource_t res_active_part;
|
||||||
|
extern resource_t res_part_start;
|
||||||
|
extern resource_t res_part_ok;
|
||||||
|
extern resource_t res_reboot;
|
||||||
|
|
||||||
|
#define OTA_ACTIVATE_RESOURCES() \
|
||||||
|
static char resname[] = "ota/update";\
|
||||||
|
rest_activate_resource (&res_upload_image, resname);\
|
||||||
|
rest_activate_resource (&res_part_count, (char *)"ota/part_count");\
|
||||||
|
rest_activate_resource (&res_part_size, (char *)"ota/part_size");\
|
||||||
|
rest_activate_resource (&res_boot_default, (char *)"ota/boot_default");\
|
||||||
|
rest_activate_resource (&res_boot_next, (char *)"ota/boot_next");\
|
||||||
|
rest_activate_resource (&res_active_part, (char *)"ota/active_part");\
|
||||||
|
rest_activate_resource (&res_part_start, (char *)"ota/part_start");\
|
||||||
|
rest_activate_resource (&res_part_ok, (char *)"ota/part_ok");\
|
||||||
|
rest_activate_resource (&res_reboot, (char *)"ota/reboot");
|
||||||
|
|
260
apps/ota-update/res_bootloader.c
Normal file
260
apps/ota-update/res_bootloader.c
Normal file
|
@ -0,0 +1,260 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015, Ralf Schlatterbeck Open Source Consulting
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the Institute nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Bootloader ressources
|
||||||
|
* \author
|
||||||
|
* Ralf Schlatterbeck <rsc@runtux.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "contiki-net.h"
|
||||||
|
#include "rest-engine.h"
|
||||||
|
#include "er-coap-engine.h"
|
||||||
|
#include "uiplib.h"
|
||||||
|
#include "generic_resource.h"
|
||||||
|
#include "bootloader_if.h"
|
||||||
|
#include "Arduino.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Resources to be activated need to be imported through the extern keyword.
|
||||||
|
* The build system automatically compiles the resources in the
|
||||||
|
* corresponding sub-directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
part_count
|
||||||
|
( const char *name
|
||||||
|
, const char *uri
|
||||||
|
, const char *query
|
||||||
|
, char *buf
|
||||||
|
, size_t bsize
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return snprintf (buf, bsize, "%ld", bootloader_get_part_count ());
|
||||||
|
}
|
||||||
|
|
||||||
|
GENERIC_RESOURCE
|
||||||
|
( part_count
|
||||||
|
, Partition Count
|
||||||
|
, count
|
||||||
|
, 0
|
||||||
|
, NULL
|
||||||
|
, part_count
|
||||||
|
);
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
part_size
|
||||||
|
( const char *name
|
||||||
|
, const char *uri
|
||||||
|
, const char *query
|
||||||
|
, char *buf
|
||||||
|
, size_t bsize
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return snprintf (buf, bsize, "%ld", bootloader_get_part_size ());
|
||||||
|
}
|
||||||
|
|
||||||
|
GENERIC_RESOURCE
|
||||||
|
( part_size
|
||||||
|
, Partition Size
|
||||||
|
, count
|
||||||
|
, 0
|
||||||
|
, NULL
|
||||||
|
, part_size
|
||||||
|
);
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
get_boot_default
|
||||||
|
( const char *name
|
||||||
|
, const char *uri
|
||||||
|
, const char *query
|
||||||
|
, char *buf
|
||||||
|
, size_t bsize
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return snprintf (buf, bsize, "%ld", bootloader_get_boot_default ());
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
set_boot_default
|
||||||
|
(const char *name, const char *uri, const char *query, const char *s)
|
||||||
|
{
|
||||||
|
uint32_t tmp = strtoul (s, NULL, 10);
|
||||||
|
bootloader_set_boot_default (tmp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
GENERIC_RESOURCE
|
||||||
|
( boot_default
|
||||||
|
, Default boot partition
|
||||||
|
, count
|
||||||
|
, 0
|
||||||
|
, set_boot_default
|
||||||
|
, get_boot_default
|
||||||
|
);
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
get_boot_next
|
||||||
|
( const char *name
|
||||||
|
, const char *uri
|
||||||
|
, const char *query
|
||||||
|
, char *buf
|
||||||
|
, size_t bsize
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return snprintf (buf, bsize, "%ld", bootloader_get_boot_next ());
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
set_boot_next
|
||||||
|
(const char *name, const char *uri, const char *query, const char *s)
|
||||||
|
{
|
||||||
|
uint32_t tmp = strtoul (s, NULL, 10);
|
||||||
|
bootloader_set_boot_next (tmp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
GENERIC_RESOURCE
|
||||||
|
( boot_next
|
||||||
|
, Next boot partition
|
||||||
|
, count
|
||||||
|
, 0
|
||||||
|
, set_boot_next
|
||||||
|
, get_boot_next
|
||||||
|
);
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
get_active_part
|
||||||
|
( const char *name
|
||||||
|
, const char *uri
|
||||||
|
, const char *query
|
||||||
|
, char *buf
|
||||||
|
, size_t bsize
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return snprintf (buf, bsize, "%ld", bootloader_get_active_part ());
|
||||||
|
}
|
||||||
|
|
||||||
|
GENERIC_RESOURCE
|
||||||
|
( active_part
|
||||||
|
, Currently active partition
|
||||||
|
, count
|
||||||
|
, 0
|
||||||
|
, NULL
|
||||||
|
, get_active_part
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse query info. We insist that the query starts with 'part='
|
||||||
|
* Then we parse the integer following the part= string and return the
|
||||||
|
* number. The number is always positive, if something goes wrong we
|
||||||
|
* return a negative number.
|
||||||
|
*/
|
||||||
|
static int get_query_partition (const char *query)
|
||||||
|
{
|
||||||
|
if (strncmp (query, "part=", 5)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return strtoul (query + 5, NULL, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
get_part_start
|
||||||
|
( const char *name
|
||||||
|
, const char *uri
|
||||||
|
, const char *query
|
||||||
|
, char *buf
|
||||||
|
, size_t bsize
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int idx = get_query_partition (query);
|
||||||
|
if (idx < 0) {
|
||||||
|
return snprintf (buf, bsize, "Invalid: \"%s\" use part=N query", query);
|
||||||
|
}
|
||||||
|
return snprintf (buf, bsize, "%ld", bootloader_get_part_start (idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
GENERIC_RESOURCE
|
||||||
|
( part_start
|
||||||
|
, Start of partition
|
||||||
|
, count
|
||||||
|
, 0
|
||||||
|
, NULL
|
||||||
|
, get_part_start
|
||||||
|
);
|
||||||
|
|
||||||
|
static int
|
||||||
|
set_part_ok
|
||||||
|
(const char *name, const char *uri, const char *query, const char *s)
|
||||||
|
{
|
||||||
|
uint32_t tmp = strtoul (s, NULL, 10);
|
||||||
|
int idx = get_query_partition (query);
|
||||||
|
if (idx < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (tmp) {
|
||||||
|
bootloader_set_part_ok (idx);
|
||||||
|
} else {
|
||||||
|
bootloader_clr_part_ok (idx);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
get_part_ok
|
||||||
|
( const char *name
|
||||||
|
, const char *uri
|
||||||
|
, const char *query
|
||||||
|
, char *buf
|
||||||
|
, size_t bsize
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int idx = get_query_partition (query);
|
||||||
|
if (idx < 0) {
|
||||||
|
return snprintf (buf, bsize, "Invalid: \"%s\" use part=N query", query);
|
||||||
|
}
|
||||||
|
return snprintf (buf, bsize, "%ld", bootloader_get_part_ok (idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
GENERIC_RESOURCE
|
||||||
|
( part_ok
|
||||||
|
, Set/Clear Partition OK flag
|
||||||
|
, count
|
||||||
|
, 0
|
||||||
|
, set_part_ok
|
||||||
|
, get_part_ok
|
||||||
|
);
|
108
apps/ota-update/res_reboot.c
Normal file
108
apps/ota-update/res_reboot.c
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017, Marcus Priesch Open Source Consulting
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the Institute nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Reboot ressource
|
||||||
|
* \author
|
||||||
|
* Marcus Priesch <marcus@priesch.co.at>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "er-coap-engine.h"
|
||||||
|
#include "generic_resource.h"
|
||||||
|
#include "dev/watchdog.h"
|
||||||
|
|
||||||
|
PROCESS(reboot_process, "reboot");
|
||||||
|
PROCESS_THREAD(reboot_process, ev, data)
|
||||||
|
{
|
||||||
|
static struct etimer etimer;
|
||||||
|
|
||||||
|
//PROCESS_EXITHANDLER(leds_off(LEDS_ALL);)
|
||||||
|
|
||||||
|
PROCESS_BEGIN();
|
||||||
|
|
||||||
|
//shell_output_str(&reboot_command,
|
||||||
|
// "Rebooting the node in four seconds...", "");
|
||||||
|
|
||||||
|
etimer_set(&etimer, CLOCK_SECOND * 4);
|
||||||
|
PROCESS_WAIT_UNTIL(etimer_expired(&etimer));
|
||||||
|
//leds_on(LEDS_RED);
|
||||||
|
//etimer_reset(&etimer);
|
||||||
|
//PROCESS_WAIT_UNTIL(etimer_expired(&etimer));
|
||||||
|
//leds_on(LEDS_GREEN);
|
||||||
|
//etimer_reset(&etimer);
|
||||||
|
//PROCESS_WAIT_UNTIL(etimer_expired(&etimer));
|
||||||
|
//leds_on(LEDS_BLUE);
|
||||||
|
//etimer_reset(&etimer);
|
||||||
|
//PROCESS_WAIT_UNTIL(etimer_expired(&etimer));
|
||||||
|
|
||||||
|
watchdog_reboot();
|
||||||
|
|
||||||
|
PROCESS_END();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
get_reboot
|
||||||
|
( const char *name
|
||||||
|
, const char *uri
|
||||||
|
, const char *query
|
||||||
|
, char *buf
|
||||||
|
, size_t bsize
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return snprintf (buf, bsize, "put 'OK' to reboot.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
do_reboot
|
||||||
|
(const char *name, const char *uri, const char *query, const char *s)
|
||||||
|
{
|
||||||
|
if (strncmp (s, "OK", 2) == 0) {
|
||||||
|
process_start (&reboot_process, NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
GENERIC_RESOURCE
|
||||||
|
( reboot
|
||||||
|
, Reboot node
|
||||||
|
, count
|
||||||
|
, 0
|
||||||
|
, do_reboot
|
||||||
|
, get_reboot
|
||||||
|
);
|
||||||
|
|
243
apps/ota-update/res_upload_image.c
Normal file
243
apps/ota-update/res_upload_image.c
Normal file
|
@ -0,0 +1,243 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2017, Marcus Priesch, Ralf Schlatterbeck
|
||||||
|
* with code from the res-plugtest-large-update.c by
|
||||||
|
* Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the Institute nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Over-the-air update using blockwise transfer
|
||||||
|
* \author
|
||||||
|
* Marcus Priesch <marcus@priesch.co.at>
|
||||||
|
* Ralf Schlatterbeck <rsc@runtux.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include "sys/cc.h"
|
||||||
|
#include "rest-engine.h"
|
||||||
|
#include "er-coap.h"
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "contiki-net.h"
|
||||||
|
#include "er-coap.h"
|
||||||
|
#include "Arduino.h"
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include "bootloader_if.h"
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
#include <stdio.h>
|
||||||
|
#define PRINTF(x) printf x
|
||||||
|
#else
|
||||||
|
#define PRINTF(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// We allocate this statically, otherwise we cannot flash a new image
|
||||||
|
// when ram is exhausted!
|
||||||
|
static uint8_t current_page [256];
|
||||||
|
static uint32_t current_offset = 0;
|
||||||
|
#define PAGESIZE (sizeof (current_page))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note that the current code relies on the fact that the bootloader
|
||||||
|
* used only supports two images. This may change in the future. We
|
||||||
|
* mainly need to relax some of the checks and use a different algorithm
|
||||||
|
* for computing imgidx, the index of the partition to be overwritten.
|
||||||
|
* If the bootloader supports more than two partitions at some point we
|
||||||
|
* may want the uploader to explicitly define the partition to be used.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
res_put_handler
|
||||||
|
( void *request
|
||||||
|
, void *response
|
||||||
|
, uint8_t *buffer
|
||||||
|
, uint16_t preferred_size
|
||||||
|
, int32_t *offset
|
||||||
|
)
|
||||||
|
{
|
||||||
|
coap_packet_t *const packet = (coap_packet_t *)request;
|
||||||
|
uint8_t *in_data = NULL;
|
||||||
|
size_t len = 0;
|
||||||
|
uint32_t partition_start = 0;
|
||||||
|
const uint32_t partition_size = bootloader_get_part_size ();
|
||||||
|
uint32_t imgidx = 0;
|
||||||
|
unsigned int ct = -1;
|
||||||
|
|
||||||
|
/* If the currently-booted partition is not the default partition we
|
||||||
|
* do not allow overwriting a partition: Neither the currently-booted
|
||||||
|
* one (this would crash) nor the only partition that is marked
|
||||||
|
* bootable. We also insist that boot_next == boot_default.
|
||||||
|
*/
|
||||||
|
if (bootloader_get_boot_default () != bootloader_get_boot_next ()) {
|
||||||
|
REST.set_response_status (response, REST.status.BAD_REQUEST);
|
||||||
|
const char *error_msg = "Won't overwrite boot_next";
|
||||||
|
REST.set_response_payload (response, error_msg, strlen (error_msg));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (bootloader_get_boot_default () != bootloader_get_active_part ()) {
|
||||||
|
REST.set_response_status (response, REST.status.BAD_REQUEST);
|
||||||
|
const char *error_msg = "Won't overwrite current";
|
||||||
|
REST.set_response_payload (response, error_msg, strlen (error_msg));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
imgidx = !bootloader_get_active_part ();
|
||||||
|
partition_start = bootloader_get_part_start (imgidx);
|
||||||
|
|
||||||
|
REST.get_header_content_type (request, &ct);
|
||||||
|
|
||||||
|
/* Require content_type APPLICATION_OCTET_STREAM */
|
||||||
|
if (ct != REST.type.APPLICATION_OCTET_STREAM) {
|
||||||
|
REST.set_response_status (response, REST.status.BAD_REQUEST);
|
||||||
|
const char *error_msg = "ContentType";
|
||||||
|
REST.set_response_payload (response, error_msg, strlen (error_msg));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = REST.get_request_payload (request, (const uint8_t **)&in_data);
|
||||||
|
PRINTF (("cur: %lu len: %lu, offset: %lu\n",
|
||||||
|
(uint32_t)current_offset, (uint32_t)len, (uint32_t)*offset));
|
||||||
|
PRINTF (("b1-offs: %lu, b1-size: %u, b1-num: %lu b1-more: %d b1-size1: %lu\n",
|
||||||
|
packet->block1_offset, packet->block1_size, packet->block1_num,
|
||||||
|
packet->block1_more, packet->size1));
|
||||||
|
if (len == 0 || NULL == in_data) {
|
||||||
|
REST.set_response_status (response, REST.status.BAD_REQUEST);
|
||||||
|
const char *error_msg = "NoPayload";
|
||||||
|
REST.set_response_payload (response, error_msg, strlen (error_msg));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if the block1_offset is 0 a new transmission has started */
|
||||||
|
if (!packet->block1_offset) {
|
||||||
|
current_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packet->block1_offset > current_offset) {
|
||||||
|
REST.set_response_status (response, REST.status.REQUEST_ENTITY_INCOMPLETE);
|
||||||
|
const char *error_msg = "OutOfSequence";
|
||||||
|
REST.set_response_payload (response, error_msg, strlen (error_msg));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Old packet or retransmission, immediately confirm */
|
||||||
|
if (packet->block1_offset && packet->block1_offset + len <= current_offset) {
|
||||||
|
REST.set_response_status (response, REST.status.CHANGED);
|
||||||
|
coap_set_header_block1
|
||||||
|
(response, packet->block1_num, 0, packet->block1_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: blocksize may be larger than our flash page size
|
||||||
|
if (len > PAGESIZE) {
|
||||||
|
REST.set_response_status (response, REST.status.INTERNAL_SERVER_ERROR);
|
||||||
|
const char *error_msg = "GRMPF: PageSize";
|
||||||
|
REST.set_response_payload (response, error_msg, strlen (error_msg));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// FIXME: blocksize may be larger than our flash page size
|
||||||
|
// So we should handle this case and repeatedly flash a block until the
|
||||||
|
// received data is written.
|
||||||
|
if (current_offset % PAGESIZE + len > PAGESIZE) {
|
||||||
|
REST.set_response_status (response, REST.status.INTERNAL_SERVER_ERROR);
|
||||||
|
const char *error_msg = "GRMPF: blocksize";
|
||||||
|
REST.set_response_payload (response, error_msg, strlen (error_msg));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Should never happen, we test for < and > earlier.
|
||||||
|
if (packet->block1_offset != current_offset) {
|
||||||
|
REST.set_response_status (response, REST.status.INTERNAL_SERVER_ERROR);
|
||||||
|
const char *error_msg = "GRMPF: Offset";
|
||||||
|
REST.set_response_payload (response, error_msg, strlen (error_msg));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packet->block1_offset + len > partition_size) {
|
||||||
|
REST.set_response_status
|
||||||
|
(response, REST.status.REQUEST_ENTITY_TOO_LARGE);
|
||||||
|
REST.set_response_payload
|
||||||
|
(response, buffer, sprintf ((char *)buffer, "%luB max.", partition_size));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy (current_page + current_offset % PAGESIZE, in_data, len);
|
||||||
|
/* Whenever an upload is started for a partition mark it as not ok */
|
||||||
|
if (current_offset == 0) {
|
||||||
|
PRINTF (("Clear partition_ok: %ld\n", imgidx));
|
||||||
|
bootloader_clr_part_ok (imgidx);
|
||||||
|
}
|
||||||
|
current_offset += len;
|
||||||
|
|
||||||
|
if (current_offset % PAGESIZE == 0) {
|
||||||
|
uint32_t dst_address = partition_start + current_offset - PAGESIZE;
|
||||||
|
/* Special case: Flash irq vectors to backup position */
|
||||||
|
if (current_offset - PAGESIZE < PART_IRQVEC_SIZE) {
|
||||||
|
/* Only for images not at position 0 write first PART_IRQVEC_SIZE
|
||||||
|
* bytes also to original position. For partition 0 it will be
|
||||||
|
* copied there anyway *and* we would crash if we wrote to the
|
||||||
|
* active memory!
|
||||||
|
*/
|
||||||
|
if (partition_start != 0) {
|
||||||
|
PRINTF (("Flashing: %lx to %lx\n", (uint32_t)PAGESIZE, dst_address));
|
||||||
|
bootloader_write_page_to_flash (dst_address, PAGESIZE, current_page);
|
||||||
|
}
|
||||||
|
/* Note: The partition_size returned by the bootloader does *NOT*
|
||||||
|
* include the PART_IRQVEC_SIZE
|
||||||
|
*/
|
||||||
|
dst_address = partition_start + partition_size
|
||||||
|
+ current_offset - PAGESIZE;
|
||||||
|
}
|
||||||
|
PRINTF (("Flashing: %lx to %lx\n", (uint32_t)PAGESIZE, dst_address));
|
||||||
|
bootloader_write_page_to_flash (dst_address, PAGESIZE, current_page);
|
||||||
|
} else if (!packet->block1_more) {
|
||||||
|
uint32_t dst_address =
|
||||||
|
partition_start + (current_offset / PAGESIZE) * PAGESIZE;
|
||||||
|
PRINTF (("Flashing: last %lx to %lx\n", (uint32_t)PAGESIZE, dst_address));
|
||||||
|
bootloader_write_page_to_flash (dst_address, PAGESIZE, current_page);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!packet->block1_more) {
|
||||||
|
// we are finished
|
||||||
|
bootloader_set_boot_next (imgidx);
|
||||||
|
current_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
REST.set_response_status (response, REST.status.CHANGED);
|
||||||
|
coap_set_header_block1 (response, packet->block1_num, 0, packet->block1_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
RESOURCE(
|
||||||
|
res_upload_image
|
||||||
|
, "title=\"Flash memory upgrade\";rt=\"block\""
|
||||||
|
, NULL
|
||||||
|
, NULL
|
||||||
|
, res_put_handler
|
||||||
|
, NULL
|
||||||
|
);
|
||||||
|
|
|
@ -56,6 +56,7 @@ struct rest_implementation_status {
|
||||||
const unsigned int NOT_FOUND; /* NOT_FOUND_4_04, NOT_FOUND_404 */
|
const unsigned int NOT_FOUND; /* NOT_FOUND_4_04, NOT_FOUND_404 */
|
||||||
const unsigned int METHOD_NOT_ALLOWED; /* METHOD_NOT_ALLOWED_4_05, METHOD_NOT_ALLOWED_405 */
|
const unsigned int METHOD_NOT_ALLOWED; /* METHOD_NOT_ALLOWED_4_05, METHOD_NOT_ALLOWED_405 */
|
||||||
const unsigned int NOT_ACCEPTABLE; /* NOT_ACCEPTABLE_4_06, NOT_ACCEPTABLE_406 */
|
const unsigned int NOT_ACCEPTABLE; /* NOT_ACCEPTABLE_4_06, NOT_ACCEPTABLE_406 */
|
||||||
|
const unsigned int REQUEST_ENTITY_INCOMPLETE; /* REQUEST_ENTITY_INCOMPLETE_4_08, REQUEST_ENTITY_INCOMPLETE_408 */
|
||||||
const unsigned int REQUEST_ENTITY_TOO_LARGE; /* REQUEST_ENTITY_TOO_LARGE_4_13, REQUEST_ENTITY_TOO_LARGE_413 */
|
const unsigned int REQUEST_ENTITY_TOO_LARGE; /* REQUEST_ENTITY_TOO_LARGE_4_13, REQUEST_ENTITY_TOO_LARGE_413 */
|
||||||
const unsigned int UNSUPPORTED_MEDIA_TYPE; /* UNSUPPORTED_MEDIA_TYPE_4_15, UNSUPPORTED_MEDIA_TYPE_415 */
|
const unsigned int UNSUPPORTED_MEDIA_TYPE; /* UNSUPPORTED_MEDIA_TYPE_4_15, UNSUPPORTED_MEDIA_TYPE_415 */
|
||||||
|
|
||||||
|
|
|
@ -113,6 +113,14 @@ rest_activate_resource(resource_t *resource, char *path)
|
||||||
PRINTF("Periodic resource: %p (%s)\n", resource->periodic,
|
PRINTF("Periodic resource: %p (%s)\n", resource->periodic,
|
||||||
resource->periodic->resource->url);
|
resource->periodic->resource->url);
|
||||||
list_add(restful_periodic_services, resource->periodic);
|
list_add(restful_periodic_services, resource->periodic);
|
||||||
|
if(process_is_running(&rest_engine_process)) {
|
||||||
|
PRINTF("Periodic: Set timer for /%s to %lu\n",
|
||||||
|
resource->url, resource->periodic->period);
|
||||||
|
PROCESS_CONTEXT_BEGIN(&rest_engine_process);
|
||||||
|
etimer_set(&resource->periodic->periodic_timer,
|
||||||
|
resource->periodic->period);
|
||||||
|
PROCESS_CONTEXT_END(&rest_engine_process);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "arduino-process.h"
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
PROCESS(serial_shell_process, "Contiki serial shell");
|
PROCESS(serial_shell_process, "Contiki serial shell");
|
||||||
|
@ -58,6 +58,8 @@ void
|
||||||
shell_default_output(const char *text1, int len1, const char *text2, int len2)
|
shell_default_output(const char *text1, int len1, const char *text2, int len2)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
mcu_sleep_disable();
|
||||||
if(text1 == NULL) {
|
if(text1 == NULL) {
|
||||||
text1 = "";
|
text1 = "";
|
||||||
len1 = 0;
|
len1 = 0;
|
||||||
|
@ -89,6 +91,7 @@ void
|
||||||
shell_exit(void)
|
shell_exit(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
PROCESS_THREAD(serial_shell_process, ev, data)
|
PROCESS_THREAD(serial_shell_process, ev, data)
|
||||||
{
|
{
|
||||||
|
@ -98,6 +101,7 @@ PROCESS_THREAD(serial_shell_process, ev, data)
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
PROCESS_WAIT_EVENT_UNTIL(ev == serial_line_event_message && data != NULL);
|
PROCESS_WAIT_EVENT_UNTIL(ev == serial_line_event_message && data != NULL);
|
||||||
|
mcu_sleep_disable();
|
||||||
shell_input(data, strlen(data));
|
shell_input(data, strlen(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,3 +66,11 @@ endif
|
||||||
ifeq ($(TARGET),z1)
|
ifeq ($(TARGET),z1)
|
||||||
shell_src += shell-sky.c shell-exec.c
|
shell_src += shell-sky.c shell-exec.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(TARGET),osd-merkur-256)
|
||||||
|
shell_src += shell-merkur.c
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(TARGET),osd-merkur-128)
|
||||||
|
shell_src += shell-merkur.c
|
||||||
|
endif
|
||||||
|
|
237
apps/shell/shell-merkur.c
Normal file
237
apps/shell/shell-merkur.c
Normal file
|
@ -0,0 +1,237 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2008, Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the Institute nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Merkurboard-specific Contiki shell commands
|
||||||
|
* \author
|
||||||
|
* Harald Pichler <harald@the-develop.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h> /* strtol */
|
||||||
|
#include "sys/cc.h"
|
||||||
|
#include "dev/radio.h"
|
||||||
|
#include "shell-merkur.h"
|
||||||
|
#include "params.h"
|
||||||
|
#include "arduino-process.h"
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
PROCESS(shell_txpower_process, "txpower");
|
||||||
|
SHELL_COMMAND(txpower_command,
|
||||||
|
"txpower",
|
||||||
|
"txpower <power>: change transmission power 0 (3dbm, default) to 15 (-17.2dbm)",
|
||||||
|
&shell_txpower_process);
|
||||||
|
PROCESS(shell_panid_process, "panid");
|
||||||
|
SHELL_COMMAND(panid_command,
|
||||||
|
"panid",
|
||||||
|
"panid <0xabcd>: change panid (default 0xabcd)",
|
||||||
|
&shell_panid_process);
|
||||||
|
PROCESS(shell_rfchannel_process, "rfchannel");
|
||||||
|
SHELL_COMMAND(rfchannel_command,
|
||||||
|
"rfchannel",
|
||||||
|
"rfchannel <channel>: change radio channel (11 - 26)",
|
||||||
|
&shell_rfchannel_process);
|
||||||
|
PROCESS(shell_ccathresholds_process, "ccathresholds");
|
||||||
|
SHELL_COMMAND(ccathresholds_command,
|
||||||
|
"ccathresholds",
|
||||||
|
"ccathresholds <threshold: change cca thresholds -91 to -61 dBm (default -77)",
|
||||||
|
&shell_ccathresholds_process);
|
||||||
|
PROCESS(shell_macconf_process, "macconf");
|
||||||
|
SHELL_COMMAND(macconf_command,
|
||||||
|
"macconf",
|
||||||
|
"macconf <conf>: change mac layer 0 -> do nothing; 1 -> Radio allways on",
|
||||||
|
&shell_macconf_process);
|
||||||
|
PROCESS(shell_saverfparam_process, "saverfparam");
|
||||||
|
SHELL_COMMAND(saverfparam_command,
|
||||||
|
"saverfparam",
|
||||||
|
"saverfparam <> save radio parameters txpower, channel, panid to eeprom settingsmanager",
|
||||||
|
&shell_saverfparam_process);
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
PROCESS_THREAD(shell_txpower_process, ev, data)
|
||||||
|
{
|
||||||
|
radio_value_t value;
|
||||||
|
char buf[10];
|
||||||
|
const char *newptr;
|
||||||
|
PROCESS_BEGIN();
|
||||||
|
|
||||||
|
value = shell_strtolong(data, &newptr);
|
||||||
|
|
||||||
|
/* If no transmission power was given on the command line, we print
|
||||||
|
out the current txpower. */
|
||||||
|
if(newptr == data) {
|
||||||
|
if(get_param(RADIO_PARAM_TXPOWER, &value) == RADIO_RESULT_OK) {
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
set_param(RADIO_PARAM_TXPOWER, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(buf, sizeof(buf), "%3d", value);
|
||||||
|
shell_output_str(&txpower_command, "TX Power: ", buf);
|
||||||
|
|
||||||
|
PROCESS_END();
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
PROCESS_THREAD(shell_rfchannel_process, ev, data)
|
||||||
|
{
|
||||||
|
radio_value_t value;
|
||||||
|
char buf[10];
|
||||||
|
const char *newptr;
|
||||||
|
PROCESS_BEGIN();
|
||||||
|
|
||||||
|
value = shell_strtolong(data, &newptr);
|
||||||
|
|
||||||
|
/* If no channel was given on the command line, we print out the
|
||||||
|
current channel. */
|
||||||
|
if(newptr == data) {
|
||||||
|
if(get_param(RADIO_PARAM_CHANNEL, &value) == RADIO_RESULT_OK) {
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
set_param(RADIO_PARAM_CHANNEL, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(buf, sizeof(buf), "%d", value);
|
||||||
|
shell_output_str(&rfchannel_command, "Channel: ", buf);
|
||||||
|
|
||||||
|
PROCESS_END();
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
PROCESS_THREAD(shell_ccathresholds_process, ev, data)
|
||||||
|
{
|
||||||
|
radio_value_t value;
|
||||||
|
char buf[10];
|
||||||
|
const char *newptr;
|
||||||
|
PROCESS_BEGIN();
|
||||||
|
|
||||||
|
value = shell_strtolong(data, &newptr);
|
||||||
|
|
||||||
|
/* If no channel was given on the command line, we print out the
|
||||||
|
current channel. */
|
||||||
|
if(newptr == data) {
|
||||||
|
if(get_param(RADIO_PARAM_CCA_THRESHOLD, &value) == RADIO_RESULT_OK) {
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
set_param(RADIO_PARAM_CCA_THRESHOLD, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(buf, sizeof(buf), "%d dBm", value);
|
||||||
|
shell_output_str(&rfchannel_command, "CCA Threshold: ", buf);
|
||||||
|
|
||||||
|
PROCESS_END();
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
PROCESS_THREAD(shell_macconf_process, ev, data)
|
||||||
|
{
|
||||||
|
radio_value_t value;
|
||||||
|
char buf[10];
|
||||||
|
const char *newptr;
|
||||||
|
PROCESS_BEGIN();
|
||||||
|
|
||||||
|
value = shell_strtolong(data, &newptr);
|
||||||
|
|
||||||
|
/* If no transmission power was given on the command line, we print
|
||||||
|
out the current macconf. */
|
||||||
|
if(newptr == data) {
|
||||||
|
value = params_get_macconf();
|
||||||
|
} else {
|
||||||
|
params_set_macconf(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(buf, sizeof(buf), "%3d", value);
|
||||||
|
shell_output_str(&txpower_command, "macconf: ", buf);
|
||||||
|
|
||||||
|
PROCESS_END();
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
PROCESS_THREAD(shell_panid_process, ev, data)
|
||||||
|
{
|
||||||
|
radio_value_t value;
|
||||||
|
char buf[10];
|
||||||
|
char *newptr;
|
||||||
|
PROCESS_BEGIN();
|
||||||
|
|
||||||
|
value = strtol(data, &newptr, 0);
|
||||||
|
|
||||||
|
/* If no channel was given on the command line, we print out the
|
||||||
|
current channel. */
|
||||||
|
if(newptr == data) {
|
||||||
|
if(get_param(RADIO_PARAM_PAN_ID, &value) != RADIO_RESULT_OK) {
|
||||||
|
// printf("error: get_param RADIO_PARAM_PAN_ID\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
set_param(RADIO_PARAM_PAN_ID, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(buf, sizeof(buf),"0x%02x%02x\n", (value >> 8) & 0xFF, value & 0xFF);
|
||||||
|
shell_output_str(&panid_command, "panid: ", buf);
|
||||||
|
|
||||||
|
PROCESS_END();
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
PROCESS_THREAD(shell_saverfparam_process, ev, data)
|
||||||
|
{
|
||||||
|
PROCESS_BEGIN();
|
||||||
|
/* Save txpower */
|
||||||
|
params_save_txpower();
|
||||||
|
/* Save rfchannel */
|
||||||
|
params_save_channel();
|
||||||
|
/* Save ccathresholds */
|
||||||
|
// todo
|
||||||
|
|
||||||
|
/* Save panid */
|
||||||
|
params_save_panid();
|
||||||
|
/* Save macconf */
|
||||||
|
params_save_macconf();
|
||||||
|
|
||||||
|
shell_output_str(&rfchannel_command, "saverfparam done ", 0);
|
||||||
|
|
||||||
|
PROCESS_END();
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
shell_merkur_init(void)
|
||||||
|
{
|
||||||
|
// shell_ps_init();
|
||||||
|
shell_reboot_init();
|
||||||
|
shell_register_command(&txpower_command);
|
||||||
|
shell_register_command(&rfchannel_command);
|
||||||
|
shell_register_command(&ccathresholds_command);
|
||||||
|
shell_register_command(&panid_command);
|
||||||
|
shell_register_command(&macconf_command);
|
||||||
|
shell_register_command(&saverfparam_command);
|
||||||
|
// shell_register_command(&s_command);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
47
apps/shell/shell-merkur.h
Normal file
47
apps/shell/shell-merkur.h
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2008, Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the Institute nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Header file for Tmote Sky-specific Contiki shell commands
|
||||||
|
* \author
|
||||||
|
* harald pichler <harald@the-develop.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SHELL_MERKUR_H_
|
||||||
|
#define SHELL_MERKUR_H_
|
||||||
|
|
||||||
|
#include "shell.h"
|
||||||
|
|
||||||
|
void shell_merkur_init(void);
|
||||||
|
|
||||||
|
#endif /* SHELL_MERKUR_H_ */
|
|
@ -35,7 +35,8 @@ static size_t get_index_from_uri (const char *uri)
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
int crontab_from_string (const char *name, const char *uri, const char *s)
|
int crontab_from_string
|
||||||
|
(const char *name, const char *uri, const char *query, const char *s)
|
||||||
{
|
{
|
||||||
const char *err;
|
const char *err;
|
||||||
int res;
|
int res;
|
||||||
|
@ -52,7 +53,13 @@ int crontab_from_string (const char *name, const char *uri, const char *s)
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
crontab_to_string (const char *name, const char *uri, char *buf, size_t bsize)
|
crontab_to_string
|
||||||
|
( const char *name
|
||||||
|
, const char *uri
|
||||||
|
, const char *query
|
||||||
|
, char *buf
|
||||||
|
, size_t bsize
|
||||||
|
)
|
||||||
{
|
{
|
||||||
/* FIXME: For now we only return "valid" or "invalid" until someone
|
/* FIXME: For now we only return "valid" or "invalid" until someone
|
||||||
* comes up with a clever algorithm to reconstruct a crontab string
|
* comes up with a clever algorithm to reconstruct a crontab string
|
||||||
|
|
|
@ -17,7 +17,8 @@
|
||||||
#include "er-coap.h"
|
#include "er-coap.h"
|
||||||
#include "generic_resource.h"
|
#include "generic_resource.h"
|
||||||
|
|
||||||
size_t time_to_string (const char *name, const char *uri, char *buf, size_t bs)
|
size_t time_to_string
|
||||||
|
(const char *name, const char *uri, const char *query, char *buf, size_t bs)
|
||||||
{
|
{
|
||||||
struct xtimeval tv;
|
struct xtimeval tv;
|
||||||
struct xtm tm;
|
struct xtm tm;
|
||||||
|
|
|
@ -21,7 +21,8 @@
|
||||||
#include "er-coap.h"
|
#include "er-coap.h"
|
||||||
#include "generic_resource.h"
|
#include "generic_resource.h"
|
||||||
|
|
||||||
int timestamp_from_string (const char *name, const char *uri, const char *s)
|
int timestamp_from_string
|
||||||
|
(const char *name, const char *uri, const char *query, const char *s)
|
||||||
{
|
{
|
||||||
struct xtimeval tv;
|
struct xtimeval tv;
|
||||||
// FIXME: Platform has no strtoll (long long)?
|
// FIXME: Platform has no strtoll (long long)?
|
||||||
|
@ -31,7 +32,13 @@ int timestamp_from_string (const char *name, const char *uri, const char *s)
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
timestamp_to_string (const char *name, const char *uri, char *buf, size_t bsize)
|
timestamp_to_string
|
||||||
|
( const char *name
|
||||||
|
, const char *uri
|
||||||
|
, const char *query
|
||||||
|
, char *buf
|
||||||
|
, size_t bsize
|
||||||
|
)
|
||||||
{
|
{
|
||||||
struct xtimeval tv;
|
struct xtimeval tv;
|
||||||
xgettimeofday (&tv, NULL);
|
xgettimeofday (&tv, NULL);
|
||||||
|
|
|
@ -17,14 +17,21 @@
|
||||||
#include "er-coap.h"
|
#include "er-coap.h"
|
||||||
#include "generic_resource.h"
|
#include "generic_resource.h"
|
||||||
|
|
||||||
int timezone_from_string (const char *name, const char *uri, const char *s)
|
int timezone_from_string
|
||||||
|
(const char *name, const char *uri, const char *query, const char *s)
|
||||||
{
|
{
|
||||||
set_tz (s);
|
set_tz (s);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
timezone_to_string (const char *name, const char *uri, char *buf, size_t bsize)
|
timezone_to_string
|
||||||
|
( const char *name
|
||||||
|
, const char *uri
|
||||||
|
, const char *query
|
||||||
|
, char *buf
|
||||||
|
, size_t bsize
|
||||||
|
)
|
||||||
{
|
{
|
||||||
if (get_tz (buf, bsize) == NULL) {
|
if (get_tz (buf, bsize) == NULL) {
|
||||||
*buf = '\0';
|
*buf = '\0';
|
||||||
|
|
1
apps/tinydtls
Submodule
1
apps/tinydtls
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit e95b02584a0041817da67c8c01f2a197d0c26915
|
|
@ -410,6 +410,7 @@ parse_tag(void)
|
||||||
switch_majorstate(s.lastmajorstate);
|
switch_majorstate(s.lastmajorstate);
|
||||||
break;
|
break;
|
||||||
case TAG_BODY:
|
case TAG_BODY:
|
||||||
|
do_word();
|
||||||
s.majorstate = s.lastmajorstate = MAJORSTATE_BODY;
|
s.majorstate = s.lastmajorstate = MAJORSTATE_BODY;
|
||||||
break;
|
break;
|
||||||
case TAG_IMG:
|
case TAG_IMG:
|
||||||
|
|
|
@ -155,10 +155,13 @@ make_tcp_stats(void *arg)
|
||||||
{
|
{
|
||||||
struct uip_conn *conn;
|
struct uip_conn *conn;
|
||||||
struct httpd_state *s = (struct httpd_state *)arg;
|
struct httpd_state *s = (struct httpd_state *)arg;
|
||||||
|
#if NETSTACK_CONF_WITH_IPV6
|
||||||
|
char buf[48];
|
||||||
|
#endif
|
||||||
|
|
||||||
conn = &uip_conns[s->u.count];
|
conn = &uip_conns[s->u.count];
|
||||||
|
|
||||||
#if NETSTACK_CONF_WITH_IPV6
|
#if NETSTACK_CONF_WITH_IPV6
|
||||||
char buf[48];
|
|
||||||
httpd_sprint_ip6(conn->ripaddr, buf);
|
httpd_sprint_ip6(conn->ripaddr, buf);
|
||||||
return snprintf((char *)uip_appdata, uip_mss(),
|
return snprintf((char *)uip_appdata, uip_mss(),
|
||||||
"<tr align=\"center\"><td>%d</td><td>%s:%u</td><td>%s</td><td>%u</td><td>%u</td><td>%c %c</td></tr>\r\n",
|
"<tr align=\"center\"><td>%d</td><td>%s:%u</td><td>%s</td><td>%u</td><td>%u</td><td>%c %c</td></tr>\r\n",
|
||||||
|
@ -249,8 +252,9 @@ extern uip_ds6_netif_t uip_ds6_if;
|
||||||
static unsigned short
|
static unsigned short
|
||||||
make_addresses(void *p)
|
make_addresses(void *p)
|
||||||
{
|
{
|
||||||
uint8_t i,j=0;
|
uint8_t i, j = 0;
|
||||||
uint16_t numprinted;
|
uint16_t numprinted;
|
||||||
|
|
||||||
numprinted = httpd_snprintf((char *)uip_appdata, uip_mss(),httpd_cgi_addrh);
|
numprinted = httpd_snprintf((char *)uip_appdata, uip_mss(),httpd_cgi_addrh);
|
||||||
for (i=0; i<UIP_DS6_ADDR_NB;i++) {
|
for (i=0; i<UIP_DS6_ADDR_NB;i++) {
|
||||||
if (uip_ds6_if.addr_list[i].isused) {
|
if (uip_ds6_if.addr_list[i].isused) {
|
||||||
|
@ -277,7 +281,7 @@ PT_THREAD(addresses(struct httpd_state *s, char *ptr))
|
||||||
static unsigned short
|
static unsigned short
|
||||||
make_neighbors(void *p)
|
make_neighbors(void *p)
|
||||||
{
|
{
|
||||||
uint8_t i,j=0;
|
uint8_t j=0;
|
||||||
uint16_t numprinted;
|
uint16_t numprinted;
|
||||||
numprinted = httpd_snprintf((char *)uip_appdata, uip_mss(),httpd_cgi_addrh);
|
numprinted = httpd_snprintf((char *)uip_appdata, uip_mss(),httpd_cgi_addrh);
|
||||||
uip_ds6_nbr_t *nbr;
|
uip_ds6_nbr_t *nbr;
|
||||||
|
@ -309,7 +313,7 @@ make_routes(void *p)
|
||||||
static const char httpd_cgi_rtes1[] HTTPD_STRING_ATTR = "(%u (via ";
|
static const char httpd_cgi_rtes1[] HTTPD_STRING_ATTR = "(%u (via ";
|
||||||
static const char httpd_cgi_rtes2[] HTTPD_STRING_ATTR = ") %lus<br>";
|
static const char httpd_cgi_rtes2[] HTTPD_STRING_ATTR = ") %lus<br>";
|
||||||
static const char httpd_cgi_rtes3[] HTTPD_STRING_ATTR = ")<br>";
|
static const char httpd_cgi_rtes3[] HTTPD_STRING_ATTR = ")<br>";
|
||||||
uint8_t i,j=0;
|
uint8_t j=0;
|
||||||
uint16_t numprinted;
|
uint16_t numprinted;
|
||||||
uip_ds6_route_t *r;
|
uip_ds6_route_t *r;
|
||||||
|
|
||||||
|
@ -320,7 +324,7 @@ make_routes(void *p)
|
||||||
j++;
|
j++;
|
||||||
numprinted += httpd_cgi_sprint_ip6(r->ipaddr, uip_appdata + numprinted);
|
numprinted += httpd_cgi_sprint_ip6(r->ipaddr, uip_appdata + numprinted);
|
||||||
numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_rtes1, r->length);
|
numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_rtes1, r->length);
|
||||||
numprinted += httpd_cgi_sprint_ip6(uip_ds6_route_nexthop(r), uip_appdata + numprinted);
|
numprinted += httpd_cgi_sprint_ip6(*(uip_ds6_route_nexthop(r)), uip_appdata + numprinted);
|
||||||
if(r->state.lifetime < 3600) {
|
if(r->state.lifetime < 3600) {
|
||||||
numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_rtes2, r->state.lifetime);
|
numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_rtes2, r->state.lifetime);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1309,7 +1309,6 @@ cfs_coffee_configure_log(const char *filename, unsigned log_size,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
#if COFFEE_IO_SEMANTICS
|
|
||||||
int
|
int
|
||||||
cfs_coffee_set_io_semantics(int fd, unsigned flags)
|
cfs_coffee_set_io_semantics(int fd, unsigned flags)
|
||||||
{
|
{
|
||||||
|
@ -1321,7 +1320,6 @@ cfs_coffee_set_io_semantics(int fd, unsigned flags)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
int
|
int
|
||||||
cfs_coffee_format(void)
|
cfs_coffee_format(void)
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#define CFS_IMPL 1
|
||||||
#include "cfs/cfs.h"
|
#include "cfs/cfs.h"
|
||||||
|
|
||||||
struct cfs_posix_dir {
|
struct cfs_posix_dir {
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define CFS_IMPL 1
|
||||||
#include "cfs/cfs.h"
|
#include "cfs/cfs.h"
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
|
@ -148,13 +148,6 @@
|
||||||
#endif /* NBR_TABLE_FIND_REMOVABLE */
|
#endif /* NBR_TABLE_FIND_REMOVABLE */
|
||||||
#endif /* UIP_CONF_IPV6_RPL */
|
#endif /* UIP_CONF_IPV6_RPL */
|
||||||
|
|
||||||
/* RPL_CONF_MOP specifies the RPL mode of operation that will be
|
|
||||||
* advertised by the RPL root. Possible values: RPL_MOP_NO_DOWNWARD_ROUTES,
|
|
||||||
* RPL_MOP_NON_STORING, RPL_MOP_STORING_NO_MULTICAST, RPL_MOP_STORING_MULTICAST */
|
|
||||||
#ifndef RPL_CONF_MOP
|
|
||||||
#define RPL_CONF_MOP RPL_MOP_STORING_NO_MULTICAST
|
|
||||||
#endif /* RPL_CONF_MOP */
|
|
||||||
|
|
||||||
/* UIP_CONF_MAX_ROUTES specifies the maximum number of routes that each
|
/* UIP_CONF_MAX_ROUTES specifies the maximum number of routes that each
|
||||||
node will be able to handle. */
|
node will be able to handle. */
|
||||||
#ifndef UIP_CONF_MAX_ROUTES
|
#ifndef UIP_CONF_MAX_ROUTES
|
||||||
|
@ -211,7 +204,7 @@
|
||||||
#define UIP_CONF_ND6_SEND_RA (NETSTACK_CONF_WITH_IPV6 && !UIP_CONF_IPV6_RPL)
|
#define UIP_CONF_ND6_SEND_RA (NETSTACK_CONF_WITH_IPV6 && !UIP_CONF_IPV6_RPL)
|
||||||
#endif /* UIP_CONF_ND6_SEND_RA */
|
#endif /* UIP_CONF_ND6_SEND_RA */
|
||||||
|
|
||||||
/* UIP_CONF_ND6_SEND_NA enables standard IPv6 Neighbor Discovery Protocol.
|
/* UIP_CONF_ND6_SEND_NS enables standard IPv6 Neighbor Discovery Protocol.
|
||||||
We enable it by default when IPv6 is used without RPL.
|
We enable it by default when IPv6 is used without RPL.
|
||||||
With RPL, the neighbor cache (link-local IPv6 <-> MAC address mapping)
|
With RPL, the neighbor cache (link-local IPv6 <-> MAC address mapping)
|
||||||
is fed whenever receiving DIO and DAO messages. This is always sufficient
|
is fed whenever receiving DIO and DAO messages. This is always sufficient
|
||||||
|
@ -221,9 +214,15 @@
|
||||||
neighbor to us is weak, if DIO transmissions are suppressed (Trickle
|
neighbor to us is weak, if DIO transmissions are suppressed (Trickle
|
||||||
timer) or if the neighbor chooses not to transmit DIOs because it is
|
timer) or if the neighbor chooses not to transmit DIOs because it is
|
||||||
a leaf node or for any reason. */
|
a leaf node or for any reason. */
|
||||||
|
#ifndef UIP_CONF_ND6_SEND_NS
|
||||||
|
#define UIP_CONF_ND6_SEND_NS (NETSTACK_CONF_WITH_IPV6 && !UIP_CONF_IPV6_RPL)
|
||||||
|
#endif /* UIP_CONF_ND6_SEND_NS */
|
||||||
|
/* UIP_CONF_ND6_SEND_NA allows to still comply with NDP even if the host does
|
||||||
|
not perform NUD or DAD processes. By default it is activated so the host
|
||||||
|
can still communicate with a full NDP peer. */
|
||||||
#ifndef UIP_CONF_ND6_SEND_NA
|
#ifndef UIP_CONF_ND6_SEND_NA
|
||||||
#define UIP_CONF_ND6_SEND_NA (NETSTACK_CONF_WITH_IPV6 && !UIP_CONF_IPV6_RPL)
|
#define UIP_CONF_ND6_SEND_NA (NETSTACK_CONF_WITH_IPV6)
|
||||||
#endif /* UIP_CONF_ND6_SEND_NA */
|
#endif /* UIP_CONF_ND6_SEND_NS */
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
/* 6lowpan configuration options.
|
/* 6lowpan configuration options.
|
||||||
|
|
|
@ -47,6 +47,8 @@
|
||||||
|
|
||||||
#define IGNORE_CHAR(c) (c == 0x0d)
|
#define IGNORE_CHAR(c) (c == 0x0d)
|
||||||
#define END 0x0a
|
#define END 0x0a
|
||||||
|
//#define IGNORE_CHAR(c) (c == 0x0a)
|
||||||
|
//#define END 0x0d
|
||||||
|
|
||||||
static struct ringbuf rxbuf;
|
static struct ringbuf rxbuf;
|
||||||
static uint8_t rxbuf_data[BUFSIZE];
|
static uint8_t rxbuf_data[BUFSIZE];
|
||||||
|
|
188
core/dev/slip.c
188
core/dev/slip.c
|
@ -81,7 +81,7 @@ enum {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static uint8_t state = STATE_TWOPACKETS;
|
static uint8_t state = STATE_TWOPACKETS;
|
||||||
static uint16_t begin, end;
|
static uint16_t begin, next_free;
|
||||||
static uint8_t rxbuf[RX_BUFSIZE];
|
static uint8_t rxbuf[RX_BUFSIZE];
|
||||||
static uint16_t pkt_end; /* SLIP_END tracker. */
|
static uint16_t pkt_end; /* SLIP_END tracker. */
|
||||||
|
|
||||||
|
@ -107,9 +107,6 @@ slip_send(void)
|
||||||
|
|
||||||
ptr = &uip_buf[UIP_LLH_LEN];
|
ptr = &uip_buf[UIP_LLH_LEN];
|
||||||
for(i = 0; i < uip_len; ++i) {
|
for(i = 0; i < uip_len; ++i) {
|
||||||
if(i == UIP_TCPIP_HLEN) {
|
|
||||||
ptr = (uint8_t *)uip_appdata;
|
|
||||||
}
|
|
||||||
c = *ptr++;
|
c = *ptr++;
|
||||||
if(c == SLIP_END) {
|
if(c == SLIP_END) {
|
||||||
slip_arch_writeb(SLIP_ESC);
|
slip_arch_writeb(SLIP_ESC);
|
||||||
|
@ -153,7 +150,7 @@ slip_write(const void *_ptr, int len)
|
||||||
static void
|
static void
|
||||||
rxbuf_init(void)
|
rxbuf_init(void)
|
||||||
{
|
{
|
||||||
begin = end = pkt_end = 0;
|
begin = next_free = pkt_end = 0;
|
||||||
state = STATE_OK;
|
state = STATE_OK;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
@ -161,10 +158,11 @@ rxbuf_init(void)
|
||||||
static uint16_t
|
static uint16_t
|
||||||
slip_poll_handler(uint8_t *outbuf, uint16_t blen)
|
slip_poll_handler(uint8_t *outbuf, uint16_t blen)
|
||||||
{
|
{
|
||||||
|
#ifdef SLIP_CONF_MICROSOFT_CHAT
|
||||||
/* This is a hack and won't work across buffer edge! */
|
/* This is a hack and won't work across buffer edge! */
|
||||||
if(rxbuf[begin] == 'C') {
|
if(rxbuf[begin] == 'C') {
|
||||||
int i;
|
int i;
|
||||||
if(begin < end && (end - begin) >= 6
|
if(begin < next_free && (next_free - begin) >= 6
|
||||||
&& memcmp(&rxbuf[begin], "CLIENT", 6) == 0) {
|
&& memcmp(&rxbuf[begin], "CLIENT", 6) == 0) {
|
||||||
state = STATE_TWOPACKETS; /* Interrupts do nothing. */
|
state = STATE_TWOPACKETS; /* Interrupts do nothing. */
|
||||||
memset(&rxbuf[begin], 0x0, 6);
|
memset(&rxbuf[begin], 0x0, 6);
|
||||||
|
@ -177,12 +175,14 @@ slip_poll_handler(uint8_t *outbuf, uint16_t blen)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif /* SLIP_CONF_MICROSOFT_CHAT */
|
||||||
|
|
||||||
#ifdef SLIP_CONF_ANSWER_MAC_REQUEST
|
#ifdef SLIP_CONF_ANSWER_MAC_REQUEST
|
||||||
else if(rxbuf[begin] == '?') {
|
else if(rxbuf[begin] == '?') {
|
||||||
/* Used by tapslip6 to request mac for auto configure */
|
/* Used by tapslip6 to request mac for auto configure */
|
||||||
int i, j;
|
int i, j;
|
||||||
char* hexchar = "0123456789abcdef";
|
char* hexchar = "0123456789abcdef";
|
||||||
if(begin < end && (end - begin) >= 2
|
if(begin < next_free && (next_free - begin) >= 2
|
||||||
&& rxbuf[begin + 1] == 'M') {
|
&& rxbuf[begin + 1] == 'M') {
|
||||||
state = STATE_TWOPACKETS; /* Interrupts do nothing. */
|
state = STATE_TWOPACKETS; /* Interrupts do nothing. */
|
||||||
rxbuf[begin] = 0;
|
rxbuf[begin] = 0;
|
||||||
|
@ -210,37 +210,109 @@ slip_poll_handler(uint8_t *outbuf, uint16_t blen)
|
||||||
*/
|
*/
|
||||||
if(begin != pkt_end) {
|
if(begin != pkt_end) {
|
||||||
uint16_t len;
|
uint16_t len;
|
||||||
|
uint16_t cur_next_free;
|
||||||
|
uint16_t cur_ptr;
|
||||||
|
int esc = 0;
|
||||||
|
|
||||||
if(begin < pkt_end) {
|
if(begin < pkt_end) {
|
||||||
len = pkt_end - begin;
|
uint16_t i;
|
||||||
|
len = 0;
|
||||||
|
for(i = begin; i < pkt_end; ++i) {
|
||||||
if(len > blen) {
|
if(len > blen) {
|
||||||
len = 0;
|
len = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (esc) {
|
||||||
|
if(rxbuf[i] == SLIP_ESC_ESC) {
|
||||||
|
outbuf[len] = SLIP_ESC;
|
||||||
|
len++;
|
||||||
|
} else if(rxbuf[i] == SLIP_ESC_END) {
|
||||||
|
outbuf[len] = SLIP_END;
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
esc = 0;
|
||||||
|
} else if(rxbuf[i] == SLIP_ESC) {
|
||||||
|
esc = 1;
|
||||||
} else {
|
} else {
|
||||||
memcpy(outbuf, &rxbuf[begin], len);
|
outbuf[len] = rxbuf[i];
|
||||||
|
len++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
len = (RX_BUFSIZE - begin) + (pkt_end - 0);
|
uint16_t i;
|
||||||
|
len = 0;
|
||||||
|
for(i = begin; i < RX_BUFSIZE; ++i) {
|
||||||
if(len > blen) {
|
if(len > blen) {
|
||||||
len = 0;
|
len = 0;
|
||||||
} else {
|
break;
|
||||||
unsigned i;
|
|
||||||
for(i = begin; i < RX_BUFSIZE; i++) {
|
|
||||||
*outbuf++ = rxbuf[i];
|
|
||||||
}
|
}
|
||||||
for(i = 0; i < pkt_end; i++) {
|
if (esc) {
|
||||||
*outbuf++ = rxbuf[i];
|
if(rxbuf[i] == SLIP_ESC_ESC) {
|
||||||
|
outbuf[len] = SLIP_ESC;
|
||||||
|
len++;
|
||||||
|
} else if(rxbuf[i] == SLIP_ESC_END) {
|
||||||
|
outbuf[len] = SLIP_END;
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
esc = 0;
|
||||||
|
} else if(rxbuf[i] == SLIP_ESC) {
|
||||||
|
esc = 1;
|
||||||
|
} else {
|
||||||
|
outbuf[len] = rxbuf[i];
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(i = 0; i < pkt_end; ++i) {
|
||||||
|
if(len > blen) {
|
||||||
|
len = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (esc) {
|
||||||
|
if(rxbuf[i] == SLIP_ESC_ESC) {
|
||||||
|
outbuf[len] = SLIP_ESC;
|
||||||
|
len++;
|
||||||
|
} else if(rxbuf[i] == SLIP_ESC_END) {
|
||||||
|
outbuf[len] = SLIP_END;
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
esc = 0;
|
||||||
|
} else if(rxbuf[i] == SLIP_ESC) {
|
||||||
|
esc = 1;
|
||||||
|
} else {
|
||||||
|
outbuf[len] = rxbuf[i];
|
||||||
|
len++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove data from buffer together with the copied packet. */
|
/* Remove data from buffer together with the copied packet. */
|
||||||
begin = pkt_end;
|
pkt_end = pkt_end + 1;
|
||||||
if(state == STATE_TWOPACKETS) {
|
if(pkt_end == RX_BUFSIZE) {
|
||||||
pkt_end = end;
|
pkt_end = 0;
|
||||||
state = STATE_OK; /* Assume no bytes where lost! */
|
}
|
||||||
|
if(pkt_end != next_free) {
|
||||||
|
cur_next_free = next_free;
|
||||||
|
cur_ptr = pkt_end;
|
||||||
|
while(cur_ptr != cur_next_free) {
|
||||||
|
if(rxbuf[cur_ptr] == SLIP_END) {
|
||||||
|
uint16_t tmp_begin = pkt_end;
|
||||||
|
pkt_end = cur_ptr;
|
||||||
|
begin = tmp_begin;
|
||||||
/* One more packet is buffered, need to be polled again! */
|
/* One more packet is buffered, need to be polled again! */
|
||||||
process_poll(&slip_process);
|
process_poll(&slip_process);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cur_ptr++;
|
||||||
|
if(cur_ptr == RX_BUFSIZE) {
|
||||||
|
cur_ptr = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(cur_ptr == cur_next_free) {
|
||||||
|
/* no more pending full packet found */
|
||||||
|
begin = pkt_end;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
begin = pkt_end;
|
||||||
}
|
}
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
@ -316,6 +388,7 @@ PROCESS_THREAD(slip_process, ev, data)
|
||||||
int
|
int
|
||||||
slip_input_byte(unsigned char c)
|
slip_input_byte(unsigned char c)
|
||||||
{
|
{
|
||||||
|
uint16_t cur_end;
|
||||||
switch(state) {
|
switch(state) {
|
||||||
case STATE_RUBBISH:
|
case STATE_RUBBISH:
|
||||||
if(c == SLIP_END) {
|
if(c == SLIP_END) {
|
||||||
|
@ -323,70 +396,63 @@ slip_input_byte(unsigned char c)
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case STATE_TWOPACKETS: /* Two packets are already buffered! */
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case STATE_ESC:
|
case STATE_ESC:
|
||||||
if(c == SLIP_ESC_END) {
|
if(c != SLIP_ESC_END && c != SLIP_ESC_ESC) {
|
||||||
c = SLIP_END;
|
|
||||||
} else if(c == SLIP_ESC_ESC) {
|
|
||||||
c = SLIP_ESC;
|
|
||||||
} else {
|
|
||||||
state = STATE_RUBBISH;
|
state = STATE_RUBBISH;
|
||||||
SLIP_STATISTICS(slip_rubbish++);
|
SLIP_STATISTICS(slip_rubbish++);
|
||||||
end = pkt_end; /* remove rubbish */
|
next_free = pkt_end; /* remove rubbish */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
state = STATE_OK;
|
state = STATE_OK;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case STATE_OK:
|
|
||||||
if(c == SLIP_ESC) {
|
if(c == SLIP_ESC) {
|
||||||
state = STATE_ESC;
|
state = STATE_ESC;
|
||||||
return 0;
|
|
||||||
} else if(c == SLIP_END) {
|
|
||||||
/*
|
|
||||||
* We have a new packet, possibly of zero length.
|
|
||||||
*
|
|
||||||
* There may already be one packet buffered.
|
|
||||||
*/
|
|
||||||
if(end != pkt_end) { /* Non zero length. */
|
|
||||||
if(begin == pkt_end) { /* None buffered. */
|
|
||||||
pkt_end = end;
|
|
||||||
} else {
|
|
||||||
state = STATE_TWOPACKETS;
|
|
||||||
SLIP_STATISTICS(slip_twopackets++);
|
|
||||||
}
|
|
||||||
process_poll(&slip_process);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add_char: */
|
/* add_char: */
|
||||||
{
|
cur_end = next_free;
|
||||||
unsigned next;
|
next_free = next_free + 1;
|
||||||
next = end + 1;
|
if(next_free == RX_BUFSIZE) {
|
||||||
if(next == RX_BUFSIZE) {
|
next_free = 0;
|
||||||
next = 0;
|
|
||||||
}
|
}
|
||||||
if(next == begin) { /* rxbuf is full */
|
if(next_free == begin) { /* rxbuf is full */
|
||||||
state = STATE_RUBBISH;
|
state = STATE_RUBBISH;
|
||||||
SLIP_STATISTICS(slip_overflow++);
|
SLIP_STATISTICS(slip_overflow++);
|
||||||
end = pkt_end; /* remove rubbish */
|
next_free = pkt_end; /* remove rubbish */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
rxbuf[end] = c;
|
rxbuf[cur_end] = c;
|
||||||
end = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
#ifdef SLIP_CONF_MICROSOFT_CHAT
|
||||||
/* There could be a separate poll routine for this. */
|
/* There could be a separate poll routine for this. */
|
||||||
if(c == 'T' && rxbuf[begin] == 'C') {
|
if(c == 'T' && rxbuf[begin] == 'C') {
|
||||||
process_poll(&slip_process);
|
process_poll(&slip_process);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
#endif /* SLIP_CONF_MICROSOFT_CHAT */
|
||||||
|
|
||||||
|
if(c == SLIP_END) {
|
||||||
|
/*
|
||||||
|
* We have a new packet, possibly of zero length.
|
||||||
|
*
|
||||||
|
* There may already be one packet buffered.
|
||||||
|
*/
|
||||||
|
if(cur_end != pkt_end) { /* Non zero length. */
|
||||||
|
if(begin == pkt_end) { /* None buffered. */
|
||||||
|
pkt_end = cur_end;
|
||||||
|
} else {
|
||||||
|
SLIP_STATISTICS(slip_twopackets++);
|
||||||
|
}
|
||||||
|
process_poll(&slip_process);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
/* Empty packet, reset the pointer */
|
||||||
|
next_free = cur_end;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,7 +83,7 @@ ringbufindex_peek_put(const struct ringbufindex *r)
|
||||||
if(((r->put_ptr - r->get_ptr) & r->mask) == r->mask) {
|
if(((r->put_ptr - r->get_ptr) & r->mask) == r->mask) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return (r->put_ptr + 1) & r->mask;
|
return r->put_ptr;
|
||||||
}
|
}
|
||||||
/* Remove the first element and return its index */
|
/* Remove the first element and return its index */
|
||||||
int
|
int
|
||||||
|
@ -118,7 +118,7 @@ ringbufindex_peek_get(const struct ringbufindex *r)
|
||||||
first one. If there are no bytes left, we return -1.
|
first one. If there are no bytes left, we return -1.
|
||||||
*/
|
*/
|
||||||
if(((r->put_ptr - r->get_ptr) & r->mask) > 0) {
|
if(((r->put_ptr - r->get_ptr) & r->mask) > 0) {
|
||||||
return (r->get_ptr + 1) & r->mask;
|
return r->get_ptr;
|
||||||
} else {
|
} else {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,25 +48,72 @@ struct ringbufindex {
|
||||||
uint8_t put_ptr, get_ptr;
|
uint8_t put_ptr, get_ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Initialize a ring buffer. The size must be a power of two */
|
/**
|
||||||
|
* \brief Initialize a ring buffer. The size must be a power of two
|
||||||
|
* \param r Pointer to ringbufindex
|
||||||
|
* \param size Size of ring buffer
|
||||||
|
*/
|
||||||
void ringbufindex_init(struct ringbufindex *r, uint8_t size);
|
void ringbufindex_init(struct ringbufindex *r, uint8_t size);
|
||||||
/* Put one element to the ring buffer */
|
|
||||||
|
/**
|
||||||
|
* \brief Put one element to the ring buffer
|
||||||
|
* \param r Pointer to ringbufindex
|
||||||
|
* \retval 0 Failure; the ring buffer is full
|
||||||
|
* \retval 1 Success; an element is added
|
||||||
|
*/
|
||||||
int ringbufindex_put(struct ringbufindex *r);
|
int ringbufindex_put(struct ringbufindex *r);
|
||||||
/* Check if there is space to put an element.
|
|
||||||
* Return the index where the next element is to be added */
|
/**
|
||||||
|
* \brief Check if there is space to put an element.
|
||||||
|
* \param r Pinter to ringbufindex
|
||||||
|
* \retval >= 0 The index where the next element is to be added.
|
||||||
|
* \retval -1 Failure; the ring buffer is full
|
||||||
|
*/
|
||||||
int ringbufindex_peek_put(const struct ringbufindex *r);
|
int ringbufindex_peek_put(const struct ringbufindex *r);
|
||||||
/* Remove the first element and return its index */
|
|
||||||
|
/**
|
||||||
|
* \brief Remove the first element and return its index
|
||||||
|
* \param r Pinter to ringbufindex
|
||||||
|
* \retval >= 0 The index of the first element
|
||||||
|
* \retval -1 No element in the ring buffer
|
||||||
|
*/
|
||||||
int ringbufindex_get(struct ringbufindex *r);
|
int ringbufindex_get(struct ringbufindex *r);
|
||||||
/* Return the index of the first element
|
|
||||||
* (which will be removed if calling ringbufindex_peek) */
|
/**
|
||||||
|
* \brief Return the index of the first element which will be removed if calling
|
||||||
|
* ringbufindex_get.
|
||||||
|
* \param r Pinter to ringbufindex
|
||||||
|
* \retval >= 0 The index of the first element
|
||||||
|
* \retval -1 No element in the ring buffer
|
||||||
|
*/
|
||||||
int ringbufindex_peek_get(const struct ringbufindex *r);
|
int ringbufindex_peek_get(const struct ringbufindex *r);
|
||||||
/* Return the ring buffer size */
|
|
||||||
|
/**
|
||||||
|
* \brief Return the ring buffer size
|
||||||
|
* \param r Pinter to ringbufindex
|
||||||
|
* \return The size of the ring buffer
|
||||||
|
*/
|
||||||
int ringbufindex_size(const struct ringbufindex *r);
|
int ringbufindex_size(const struct ringbufindex *r);
|
||||||
/* Return the number of elements currently in the ring buffer */
|
|
||||||
|
/**
|
||||||
|
* \brief Return the number of elements currently in the ring buffer.
|
||||||
|
* \param r Pinter to ringbufindex
|
||||||
|
* \return The number of elements in the ring buffer
|
||||||
|
*/
|
||||||
int ringbufindex_elements(const struct ringbufindex *r);
|
int ringbufindex_elements(const struct ringbufindex *r);
|
||||||
/* Is the ring buffer full? */
|
|
||||||
|
/**
|
||||||
|
* \brief Is the ring buffer full?
|
||||||
|
* \retval 0 Not full
|
||||||
|
* \retval 1 Full
|
||||||
|
*/
|
||||||
int ringbufindex_full(const struct ringbufindex *r);
|
int ringbufindex_full(const struct ringbufindex *r);
|
||||||
/* Is the ring buffer empty? */
|
|
||||||
|
/**
|
||||||
|
* \brief Is the ring buffer empty?
|
||||||
|
* \retval 0 Not empty
|
||||||
|
* \retval 1 Empty
|
||||||
|
*/
|
||||||
int ringbufindex_empty(const struct ringbufindex *r);
|
int ringbufindex_empty(const struct ringbufindex *r);
|
||||||
|
|
||||||
#endif /* __RINGBUFINDEX_H__ */
|
#endif /* __RINGBUFINDEX_H__ */
|
||||||
|
|
|
@ -130,7 +130,7 @@ typedef uint16_t settings_length_t;
|
||||||
|
|
||||||
#define SETTINGS_KEY_RDC_INDEX TCC('R','D') /*!< RDC index, uint8_t */
|
#define SETTINGS_KEY_RDC_INDEX TCC('R','D') /*!< RDC index, uint8_t */
|
||||||
#define SETTINGS_KEY_CHANNEL_MASK TCC('C','M') /*!< Channel mask, uint16_t */
|
#define SETTINGS_KEY_CHANNEL_MASK TCC('C','M') /*!< Channel mask, uint16_t */
|
||||||
|
#define SETTINGS_KEY_MAC_CONF TCC('M','C') /*!< MAC Layer Config, uint8_t */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
// MARK: - Constants
|
// MARK: - Constants
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,10 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define printf(...)
|
#define printf(...)
|
||||||
|
|
||||||
|
static uip_ip6addr_t ip64_prefix = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 0, 0, 0}};
|
||||||
|
static uint8_t ip64_prefix_len = 96;
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
void
|
void
|
||||||
ip64_addr_copy4(uip_ip4addr_t *dest, const uip_ip4addr_t *src)
|
ip64_addr_copy4(uip_ip4addr_t *dest, const uip_ip4addr_t *src)
|
||||||
|
@ -56,20 +60,7 @@ ip64_addr_4to6(const uip_ip4addr_t *ipv4addr,
|
||||||
addresses. It returns 0 if it failed to convert the address and
|
addresses. It returns 0 if it failed to convert the address and
|
||||||
non-zero if it could successfully convert the address. */
|
non-zero if it could successfully convert the address. */
|
||||||
|
|
||||||
/* The IPv4 address is encoded as an IPv6-encoded IPv4 address in
|
uip_ipaddr_copy(ipv6addr, &ip64_prefix);
|
||||||
the ::ffff:0000/24 prefix.*/
|
|
||||||
ipv6addr->u8[0] = 0;
|
|
||||||
ipv6addr->u8[1] = 0;
|
|
||||||
ipv6addr->u8[2] = 0;
|
|
||||||
ipv6addr->u8[3] = 0;
|
|
||||||
ipv6addr->u8[4] = 0;
|
|
||||||
ipv6addr->u8[5] = 0;
|
|
||||||
ipv6addr->u8[6] = 0;
|
|
||||||
ipv6addr->u8[7] = 0;
|
|
||||||
ipv6addr->u8[8] = 0;
|
|
||||||
ipv6addr->u8[9] = 0;
|
|
||||||
ipv6addr->u8[10] = 0xff;
|
|
||||||
ipv6addr->u8[11] = 0xff;
|
|
||||||
ipv6addr->u8[12] = ipv4addr->u8[0];
|
ipv6addr->u8[12] = ipv4addr->u8[0];
|
||||||
ipv6addr->u8[13] = ipv4addr->u8[1];
|
ipv6addr->u8[13] = ipv4addr->u8[1];
|
||||||
ipv6addr->u8[14] = ipv4addr->u8[2];
|
ipv6addr->u8[14] = ipv4addr->u8[2];
|
||||||
|
@ -90,21 +81,7 @@ ip64_addr_6to4(const uip_ip6addr_t *ipv6addr,
|
||||||
returns 0 if it failed to convert the address and non-zero if it
|
returns 0 if it failed to convert the address and non-zero if it
|
||||||
could successfully convert the address. */
|
could successfully convert the address. */
|
||||||
|
|
||||||
/* If the IPv6 address is an IPv6-encoded
|
if(ip64_addr_is_ip64(ipv6addr)) {
|
||||||
IPv4 address (i.e. in the ::ffff:0/8 prefix), we simply use the
|
|
||||||
IPv4 addresses directly. */
|
|
||||||
if(ipv6addr->u8[0] == 0 &&
|
|
||||||
ipv6addr->u8[1] == 0 &&
|
|
||||||
ipv6addr->u8[2] == 0 &&
|
|
||||||
ipv6addr->u8[3] == 0 &&
|
|
||||||
ipv6addr->u8[4] == 0 &&
|
|
||||||
ipv6addr->u8[5] == 0 &&
|
|
||||||
ipv6addr->u8[6] == 0 &&
|
|
||||||
ipv6addr->u8[7] == 0 &&
|
|
||||||
ipv6addr->u8[8] == 0 &&
|
|
||||||
ipv6addr->u8[9] == 0 &&
|
|
||||||
ipv6addr->u8[10] == 0xff &&
|
|
||||||
ipv6addr->u8[11] == 0xff) {
|
|
||||||
ipv4addr->u8[0] = ipv6addr->u8[12];
|
ipv4addr->u8[0] = ipv6addr->u8[12];
|
||||||
ipv4addr->u8[1] = ipv6addr->u8[13];
|
ipv4addr->u8[1] = ipv6addr->u8[13];
|
||||||
ipv4addr->u8[2] = ipv6addr->u8[14];
|
ipv4addr->u8[2] = ipv6addr->u8[14];
|
||||||
|
@ -121,3 +98,16 @@ ip64_addr_6to4(const uip_ip6addr_t *ipv6addr,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
ip64_addr_is_ip64(const uip_ip6addr_t *ipv6addr)
|
||||||
|
{
|
||||||
|
return uip_ipaddr_prefixcmp(ipv6addr, &ip64_prefix, ip64_prefix_len);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
ip64_addr_set_prefix(const uip_ip6addr_t *prefix, uint8_t prefix_len)
|
||||||
|
{
|
||||||
|
uip_ipaddr_copy(&ip64_prefix, prefix);
|
||||||
|
ip64_prefix_len = prefix_len;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
|
@ -58,6 +58,9 @@ int ip64_addr_6to4(const uip_ip6addr_t *ipv6addr,
|
||||||
int ip64_addr_4to6(const uip_ip4addr_t *ipv4addr,
|
int ip64_addr_4to6(const uip_ip4addr_t *ipv4addr,
|
||||||
uip_ip6addr_t *ipv6addr);
|
uip_ip6addr_t *ipv6addr);
|
||||||
|
|
||||||
|
int ip64_addr_is_ip64(const uip_ip6addr_t *ipv6addr);
|
||||||
|
|
||||||
|
void ip64_addr_set_prefix(const uip_ip6addr_t *prefix, uint8_t prefix_len);
|
||||||
|
|
||||||
#endif /* IP64_ADDR_H */
|
#endif /* IP64_ADDR_H */
|
||||||
|
|
||||||
|
|
|
@ -1094,7 +1094,7 @@ resolv_set_hostname(const char *hostname)
|
||||||
/* Add the .local suffix if it isn't already there */
|
/* Add the .local suffix if it isn't already there */
|
||||||
if(strlen(resolv_hostname) < 7 ||
|
if(strlen(resolv_hostname) < 7 ||
|
||||||
strcasecmp(resolv_hostname + strlen(resolv_hostname) - 6, ".local") != 0) {
|
strcasecmp(resolv_hostname + strlen(resolv_hostname) - 6, ".local") != 0) {
|
||||||
strncat(resolv_hostname, ".local", RESOLV_CONF_MAX_DOMAIN_NAME_SIZE);
|
strncat(resolv_hostname, ".local", RESOLV_CONF_MAX_DOMAIN_NAME_SIZE - strlen(resolv_hostname));
|
||||||
}
|
}
|
||||||
|
|
||||||
PRINTF("resolver: hostname changed to \"%s\"\n", resolv_hostname);
|
PRINTF("resolver: hostname changed to \"%s\"\n", resolv_hostname);
|
||||||
|
@ -1248,8 +1248,8 @@ remove_trailing_dots(const char *name) {
|
||||||
static char dns_name_without_dots[RESOLV_CONF_MAX_DOMAIN_NAME_SIZE + 1];
|
static char dns_name_without_dots[RESOLV_CONF_MAX_DOMAIN_NAME_SIZE + 1];
|
||||||
size_t len = strlen(name);
|
size_t len = strlen(name);
|
||||||
|
|
||||||
if(name[len - 1] == '.') {
|
if(len && name[len - 1] == '.') {
|
||||||
strncpy(dns_name_without_dots, name, sizeof(dns_name_without_dots));
|
strncpy(dns_name_without_dots, name, RESOLV_CONF_MAX_DOMAIN_NAME_SIZE);
|
||||||
while(len && (dns_name_without_dots[len - 1] == '.')) {
|
while(len && (dns_name_without_dots[len - 1] == '.')) {
|
||||||
dns_name_without_dots[--len] = 0;
|
dns_name_without_dots[--len] = 0;
|
||||||
}
|
}
|
||||||
|
@ -1309,7 +1309,7 @@ resolv_query(const char *name)
|
||||||
|
|
||||||
memset(nameptr, 0, sizeof(*nameptr));
|
memset(nameptr, 0, sizeof(*nameptr));
|
||||||
|
|
||||||
strncpy(nameptr->name, name, sizeof(nameptr->name));
|
strncpy(nameptr->name, name, sizeof(nameptr->name) - 1);
|
||||||
nameptr->state = STATE_NEW;
|
nameptr->state = STATE_NEW;
|
||||||
nameptr->seqno = seqno;
|
nameptr->seqno = seqno;
|
||||||
++seqno;
|
++seqno;
|
||||||
|
@ -1479,7 +1479,7 @@ resolv_found(char *name, uip_ipaddr_t * ipaddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Re-add the .local suffix */
|
/* Re-add the .local suffix */
|
||||||
strncat(resolv_hostname, ".local", RESOLV_CONF_MAX_DOMAIN_NAME_SIZE);
|
strncat(resolv_hostname, ".local", RESOLV_CONF_MAX_DOMAIN_NAME_SIZE - strlen(resolv_hostname));
|
||||||
|
|
||||||
start_name_collision_check(CLOCK_SECOND * 5);
|
start_name_collision_check(CLOCK_SECOND * 5);
|
||||||
} else if(mdns_state == MDNS_STATE_READY) {
|
} else if(mdns_state == MDNS_STATE_READY) {
|
||||||
|
|
|
@ -102,9 +102,6 @@ slipdev_send(void)
|
||||||
|
|
||||||
ptr = &uip_buf[UIP_LLH_LEN];
|
ptr = &uip_buf[UIP_LLH_LEN];
|
||||||
for(i = 0; i < uip_len; ++i) {
|
for(i = 0; i < uip_len; ++i) {
|
||||||
if(i == UIP_TCPIP_HLEN) {
|
|
||||||
ptr = (uint8_t *)uip_appdata;
|
|
||||||
}
|
|
||||||
c = *ptr++;
|
c = *ptr++;
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case SLIP_END:
|
case SLIP_END:
|
||||||
|
|
|
@ -29,6 +29,9 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define DEBUG DEBUG_NONE
|
||||||
|
#include "net/ip/uip-debug.h"
|
||||||
|
|
||||||
#include "contiki.h"
|
#include "contiki.h"
|
||||||
#include "sys/cc.h"
|
#include "sys/cc.h"
|
||||||
#include "contiki-net.h"
|
#include "contiki-net.h"
|
||||||
|
@ -37,10 +40,8 @@
|
||||||
|
|
||||||
#include "tcp-socket.h"
|
#include "tcp-socket.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
static void relisten(struct tcp_socket *s);
|
static void relisten(struct tcp_socket *s);
|
||||||
|
|
||||||
LIST(socketlist);
|
LIST(socketlist);
|
||||||
|
@ -80,7 +81,7 @@ acked(struct tcp_socket *s)
|
||||||
s->output_data_maxlen - s->output_data_send_nxt);
|
s->output_data_maxlen - s->output_data_send_nxt);
|
||||||
}
|
}
|
||||||
if(s->output_data_len < s->output_data_send_nxt) {
|
if(s->output_data_len < s->output_data_send_nxt) {
|
||||||
printf("tcp: acked assertion failed s->output_data_len (%d) < s->output_data_send_nxt (%d)\n",
|
PRINTF("tcp: acked assertion failed s->output_data_len (%d) < s->output_data_send_nxt (%d)\n",
|
||||||
s->output_data_len,
|
s->output_data_len,
|
||||||
s->output_data_send_nxt);
|
s->output_data_send_nxt);
|
||||||
tcp_markconn(uip_conn, NULL);
|
tcp_markconn(uip_conn, NULL);
|
||||||
|
@ -121,7 +122,7 @@ newdata(struct tcp_socket *s)
|
||||||
bytesleft = 0;
|
bytesleft = 0;
|
||||||
}
|
}
|
||||||
if(bytesleft > 0) {
|
if(bytesleft > 0) {
|
||||||
printf("tcp: newdata, bytesleft > 0 (%d) not implemented\n", bytesleft);
|
PRINTF("tcp: newdata, bytesleft > 0 (%d) not implemented\n", bytesleft);
|
||||||
}
|
}
|
||||||
dataptr += copylen;
|
dataptr += copylen;
|
||||||
len -= copylen;
|
len -= copylen;
|
||||||
|
@ -356,6 +357,8 @@ tcp_socket_send(struct tcp_socket *s,
|
||||||
s->output_senddata_len = s->output_data_len;
|
s->output_senddata_len = s->output_data_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tcpip_poll_tcp(s->c);
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
@ -398,3 +401,9 @@ tcp_socket_max_sendlen(struct tcp_socket *s)
|
||||||
return s->output_data_maxlen - s->output_data_len;
|
return s->output_data_maxlen - s->output_data_len;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
tcp_socket_queuelen(struct tcp_socket *s)
|
||||||
|
{
|
||||||
|
return s->output_data_len;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
|
@ -284,4 +284,16 @@ int tcp_socket_unregister(struct tcp_socket *s);
|
||||||
*/
|
*/
|
||||||
int tcp_socket_max_sendlen(struct tcp_socket *s);
|
int tcp_socket_max_sendlen(struct tcp_socket *s);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief The number of bytes waiting to be sent
|
||||||
|
* \param s A pointer to a TCP socket
|
||||||
|
* \return The number of bytes that have not yet been acknowledged by the receiver.
|
||||||
|
*
|
||||||
|
* This function queries the TCP socket and returns the
|
||||||
|
* number of bytes that are currently not yet known to
|
||||||
|
* have been successfully received by the receiver.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int tcp_socket_queuelen(struct tcp_socket *s);
|
||||||
|
|
||||||
#endif /* TCP_SOCKET_H */
|
#endif /* TCP_SOCKET_H */
|
||||||
|
|
|
@ -548,6 +548,15 @@ tcpip_ipv6_output(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if UIP_CONF_IPV6_RPL
|
||||||
|
if(!rpl_update_header()) {
|
||||||
|
/* Packet can not be forwarded */
|
||||||
|
PRINTF("tcpip_ipv6_output: RPL header update error\n");
|
||||||
|
uip_clear_buf();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif /* UIP_CONF_IPV6_RPL */
|
||||||
|
|
||||||
if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
|
if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
|
||||||
/* Next hop determination */
|
/* Next hop determination */
|
||||||
|
|
||||||
|
@ -651,15 +660,9 @@ tcpip_ipv6_output(void)
|
||||||
|
|
||||||
/* End of next hop determination */
|
/* End of next hop determination */
|
||||||
|
|
||||||
#if UIP_CONF_IPV6_RPL
|
|
||||||
if(!rpl_finalize_header(nexthop)) {
|
|
||||||
uip_clear_buf();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif /* UIP_CONF_IPV6_RPL */
|
|
||||||
nbr = uip_ds6_nbr_lookup(nexthop);
|
nbr = uip_ds6_nbr_lookup(nexthop);
|
||||||
if(nbr == NULL) {
|
if(nbr == NULL) {
|
||||||
#if UIP_ND6_SEND_NA
|
#if UIP_ND6_SEND_NS
|
||||||
if((nbr = uip_ds6_nbr_add(nexthop, NULL, 0, NBR_INCOMPLETE, NBR_TABLE_REASON_IPV6_ND, NULL)) == NULL) {
|
if((nbr = uip_ds6_nbr_add(nexthop, NULL, 0, NBR_INCOMPLETE, NBR_TABLE_REASON_IPV6_ND, NULL)) == NULL) {
|
||||||
uip_clear_buf();
|
uip_clear_buf();
|
||||||
PRINTF("tcpip_ipv6_output: failed to add neighbor to cache\n");
|
PRINTF("tcpip_ipv6_output: failed to add neighbor to cache\n");
|
||||||
|
@ -688,13 +691,13 @@ tcpip_ipv6_output(void)
|
||||||
nbr->nscount = 1;
|
nbr->nscount = 1;
|
||||||
/* Send the first NS try from here (multicast destination IP address). */
|
/* Send the first NS try from here (multicast destination IP address). */
|
||||||
}
|
}
|
||||||
#else /* UIP_ND6_SEND_NA */
|
#else /* UIP_ND6_SEND_NS */
|
||||||
PRINTF("tcpip_ipv6_output: neighbor not in cache\n");
|
PRINTF("tcpip_ipv6_output: neighbor not in cache\n");
|
||||||
uip_len = 0;
|
uip_len = 0;
|
||||||
return;
|
return;
|
||||||
#endif /* UIP_ND6_SEND_NA */
|
#endif /* UIP_ND6_SEND_NS */
|
||||||
} else {
|
} else {
|
||||||
#if UIP_ND6_SEND_NA
|
#if UIP_ND6_SEND_NS
|
||||||
if(nbr->state == NBR_INCOMPLETE) {
|
if(nbr->state == NBR_INCOMPLETE) {
|
||||||
PRINTF("tcpip_ipv6_output: nbr cache entry incomplete\n");
|
PRINTF("tcpip_ipv6_output: nbr cache entry incomplete\n");
|
||||||
#if UIP_CONF_IPV6_QUEUE_PKT
|
#if UIP_CONF_IPV6_QUEUE_PKT
|
||||||
|
@ -716,7 +719,7 @@ tcpip_ipv6_output(void)
|
||||||
nbr->nscount = 0;
|
nbr->nscount = 0;
|
||||||
PRINTF("tcpip_ipv6_output: nbr cache entry stale moving to delay\n");
|
PRINTF("tcpip_ipv6_output: nbr cache entry stale moving to delay\n");
|
||||||
}
|
}
|
||||||
#endif /* UIP_ND6_SEND_NA */
|
#endif /* UIP_ND6_SEND_NS */
|
||||||
|
|
||||||
tcpip_output(uip_ds6_nbr_get_ll(nbr));
|
tcpip_output(uip_ds6_nbr_get_ll(nbr));
|
||||||
|
|
||||||
|
|
4
core/net/ip/uip-debug.c
Normal file → Executable file
4
core/net/ip/uip-debug.c
Normal file → Executable file
|
@ -56,7 +56,7 @@ uip_debug_ipaddr_print(const uip_ipaddr_t *addr)
|
||||||
#if NETSTACK_CONF_WITH_IPV6
|
#if NETSTACK_CONF_WITH_IPV6
|
||||||
if(ip64_addr_is_ipv4_mapped_addr(addr)) {
|
if(ip64_addr_is_ipv4_mapped_addr(addr)) {
|
||||||
/*
|
/*
|
||||||
* Printing IPv4-mapped addresses is done according to RFC 3513 [1]
|
* Printing IPv4-mapped addresses is done according to RFC 4291 [1]
|
||||||
*
|
*
|
||||||
* "An alternative form that is sometimes more
|
* "An alternative form that is sometimes more
|
||||||
* convenient when dealing with a mixed environment
|
* convenient when dealing with a mixed environment
|
||||||
|
@ -67,7 +67,7 @@ uip_debug_ipaddr_print(const uip_ipaddr_t *addr)
|
||||||
* low-order 8-bit pieces of the address (standard
|
* low-order 8-bit pieces of the address (standard
|
||||||
* IPv4 representation)."
|
* IPv4 representation)."
|
||||||
*
|
*
|
||||||
* [1] https://tools.ietf.org/html/rfc3513#page-5
|
* [1] https://tools.ietf.org/html/rfc4291#page-4
|
||||||
*/
|
*/
|
||||||
PRINTA("::FFFF:%u.%u.%u.%u", addr->u8[12], addr->u8[13], addr->u8[14], addr->u8[15]);
|
PRINTA("::FFFF:%u.%u.%u.%u", addr->u8[12], addr->u8[13], addr->u8[14], addr->u8[15]);
|
||||||
} else {
|
} else {
|
||||||
|
|
28
core/net/ip/uip.h
Normal file → Executable file
28
core/net/ip/uip.h
Normal file → Executable file
|
@ -490,26 +490,8 @@ void uip_reass_over(void);
|
||||||
*
|
*
|
||||||
* The uip_aligned_buf array is used to hold incoming and outgoing
|
* The uip_aligned_buf array is used to hold incoming and outgoing
|
||||||
* packets. The device driver should place incoming data into this
|
* packets. The device driver should place incoming data into this
|
||||||
* buffer. When sending data, the device driver should read the link
|
* buffer. When sending data, the device driver should read the
|
||||||
* level headers and the TCP/IP headers from this buffer. The size of
|
* outgoing data from this buffer.
|
||||||
* the link level headers is configured by the UIP_LLH_LEN define.
|
|
||||||
*
|
|
||||||
* \note The application data need not be placed in this buffer, so
|
|
||||||
* the device driver must read it from the place pointed to by the
|
|
||||||
* uip_appdata pointer as illustrated by the following example:
|
|
||||||
\code
|
|
||||||
void
|
|
||||||
devicedriver_send(void)
|
|
||||||
{
|
|
||||||
hwsend(&uip_buf[0], UIP_LLH_LEN);
|
|
||||||
if(uip_len <= UIP_LLH_LEN + UIP_TCPIP_HLEN) {
|
|
||||||
hwsend(&uip_buf[UIP_LLH_LEN], uip_len - UIP_LLH_LEN);
|
|
||||||
} else {
|
|
||||||
hwsend(&uip_buf[UIP_LLH_LEN], UIP_TCPIP_HLEN);
|
|
||||||
hwsend(uip_appdata, uip_len - UIP_TCPIP_HLEN - UIP_LLH_LEN);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
\endcode
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
|
@ -2012,7 +1994,7 @@ CCIF extern uip_lladdr_t uip_lladdr;
|
||||||
(((a)->u8[15]) == 0x02))
|
(((a)->u8[15]) == 0x02))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief is addr (a) a link local unicast address, see RFC3513
|
* \brief is addr (a) a link local unicast address, see RFC 4291
|
||||||
* i.e. is (a) on prefix FE80::/10
|
* i.e. is (a) on prefix FE80::/10
|
||||||
* a is of type uip_ipaddr_t*
|
* a is of type uip_ipaddr_t*
|
||||||
*/
|
*/
|
||||||
|
@ -2036,7 +2018,7 @@ CCIF extern uip_lladdr_t uip_lladdr;
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief is addr (a) a solicited node multicast address, see RFC3513
|
* \brief is addr (a) a solicited node multicast address, see RFC 4291
|
||||||
* a is of type uip_ipaddr_t*
|
* a is of type uip_ipaddr_t*
|
||||||
*/
|
*/
|
||||||
#define uip_is_addr_solicited_node(a) \
|
#define uip_is_addr_solicited_node(a) \
|
||||||
|
@ -2097,7 +2079,7 @@ CCIF extern uip_lladdr_t uip_lladdr;
|
||||||
#endif /*UIP_CONF_LL_802154*/
|
#endif /*UIP_CONF_LL_802154*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief is address a multicast address, see RFC 3513
|
* \brief is address a multicast address, see RFC 4291
|
||||||
* a is of type uip_ipaddr_t*
|
* a is of type uip_ipaddr_t*
|
||||||
* */
|
* */
|
||||||
#define uip_is_addr_mcast(a) \
|
#define uip_is_addr_mcast(a) \
|
||||||
|
|
|
@ -120,10 +120,6 @@ uint16_t uip_ipchksum(void);
|
||||||
* The TCP checksum is the Internet checksum of data contents of the
|
* The TCP checksum is the Internet checksum of data contents of the
|
||||||
* TCP segment, and a pseudo-header as defined in RFC793.
|
* TCP segment, and a pseudo-header as defined in RFC793.
|
||||||
*
|
*
|
||||||
* \note The uip_appdata pointer that points to the packet data may
|
|
||||||
* point anywhere in memory, so it is not possible to simply calculate
|
|
||||||
* the Internet checksum of the contents of the uip_buf buffer.
|
|
||||||
*
|
|
||||||
* \return The TCP checksum of the TCP segment in uip_buf and pointed
|
* \return The TCP checksum of the TCP segment in uip_buf and pointed
|
||||||
* to by uip_appdata.
|
* to by uip_appdata.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -163,7 +163,6 @@ create_msg(CC_REGISTER_ARG struct dhcp_msg *m)
|
||||||
memset(&m->chaddr[s.mac_len], 0, sizeof(m->chaddr) - s.mac_len);
|
memset(&m->chaddr[s.mac_len], 0, sizeof(m->chaddr) - s.mac_len);
|
||||||
|
|
||||||
memset(m->sname, 0, sizeof(m->sname));
|
memset(m->sname, 0, sizeof(m->sname));
|
||||||
strcpy((char *)m->sname, "Thingsquare");
|
|
||||||
memset(m->file, 0, sizeof(m->file));
|
memset(m->file, 0, sizeof(m->file));
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,9 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define DEBUG DEBUG_NONE
|
||||||
|
#include "net/ip/uip-debug.h"
|
||||||
|
|
||||||
PROCESS(ip64_ipv4_dhcp_process, "IPv4 DHCP");
|
PROCESS(ip64_ipv4_dhcp_process, "IPv4 DHCP");
|
||||||
|
|
||||||
uip_ipaddr_t uip_hostaddr; /* Needed because it is referenced by dhcpc.c */
|
uip_ipaddr_t uip_hostaddr; /* Needed because it is referenced by dhcpc.c */
|
||||||
|
@ -48,7 +51,7 @@ uip_ipaddr_t uip_hostaddr; /* Needed because it is referenced by dhcpc.c */
|
||||||
void
|
void
|
||||||
ip64_ipv4_dhcp_init(void)
|
ip64_ipv4_dhcp_init(void)
|
||||||
{
|
{
|
||||||
printf("Starting DHCPv4\n");
|
printf("IP64: Starting DHCPv4\n");
|
||||||
process_start(&ip64_ipv4_dhcp_process, NULL);
|
process_start(&ip64_ipv4_dhcp_process, NULL);
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
@ -58,10 +61,10 @@ PROCESS_THREAD(ip64_ipv4_dhcp_process, ev, data)
|
||||||
|
|
||||||
ip64_dhcpc_init(&ip64_eth_addr, sizeof(ip64_eth_addr));
|
ip64_dhcpc_init(&ip64_eth_addr, sizeof(ip64_eth_addr));
|
||||||
|
|
||||||
printf("Inited\n");
|
PRINTF("IP64: Inited\n");
|
||||||
|
|
||||||
ip64_dhcpc_request();
|
ip64_dhcpc_request();
|
||||||
printf("Requested\n");
|
PRINTF("IP64: Requested\n");
|
||||||
while(1) {
|
while(1) {
|
||||||
PROCESS_WAIT_EVENT();
|
PROCESS_WAIT_EVENT();
|
||||||
|
|
||||||
|
@ -78,15 +81,22 @@ void
|
||||||
ip64_dhcpc_configured(const struct ip64_dhcpc_state *s)
|
ip64_dhcpc_configured(const struct ip64_dhcpc_state *s)
|
||||||
{
|
{
|
||||||
uip_ip6addr_t ip6dnsaddr;
|
uip_ip6addr_t ip6dnsaddr;
|
||||||
printf("DHCP Configured with %d.%d.%d.%d\n",
|
PRINTF("IP64: DHCP Configured with %d.%d.%d.%d\n",
|
||||||
s->ipaddr.u8[0], s->ipaddr.u8[1],
|
s->ipaddr.u8[0], s->ipaddr.u8[1],
|
||||||
s->ipaddr.u8[2], s->ipaddr.u8[3]);
|
s->ipaddr.u8[2], s->ipaddr.u8[3]);
|
||||||
|
|
||||||
ip64_set_hostaddr((uip_ip4addr_t *)&s->ipaddr);
|
ip64_set_hostaddr((uip_ip4addr_t *)&s->ipaddr);
|
||||||
ip64_set_netmask((uip_ip4addr_t *)&s->netmask);
|
ip64_set_netmask((uip_ip4addr_t *)&s->netmask);
|
||||||
ip64_set_draddr((uip_ip4addr_t *)&s->default_router);
|
ip64_set_draddr((uip_ip4addr_t *)&s->default_router);
|
||||||
|
if(!uip_ip4addr_cmp((uip_ip4addr_t *)&s->dnsaddr, &uip_all_zeroes_addr)) {
|
||||||
|
/* Note: Currently we assume only one DNS server */
|
||||||
|
uip_ipaddr_t * dns = uip_nameserver_get(0);
|
||||||
|
/* Only update DNS entry if it is empty or already IPv4 */
|
||||||
|
if(uip_is_addr_unspecified(dns) || ip64_addr_is_ip64(dns)) {
|
||||||
ip64_addr_4to6((uip_ip4addr_t *)&s->dnsaddr, &ip6dnsaddr);
|
ip64_addr_4to6((uip_ip4addr_t *)&s->dnsaddr, &ip6dnsaddr);
|
||||||
// mdns_conf(&ip6dnsaddr);
|
uip_nameserver_update(&ip6dnsaddr, uip_ntohs(s->lease_time[0])*65536ul + uip_ntohs(s->lease_time[1]));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
void
|
void
|
||||||
|
|
|
@ -7,8 +7,14 @@ What does it do
|
||||||
These files, alongside some core modifications, add support for IPv6 multicast
|
These files, alongside some core modifications, add support for IPv6 multicast
|
||||||
to contiki's uIPv6 engine.
|
to contiki's uIPv6 engine.
|
||||||
|
|
||||||
Currently, two modes are supported:
|
Currently, three modes are supported:
|
||||||
|
|
||||||
|
* 'Enhanced Stateless Multicast RPL Forwarding' (ESMRF)
|
||||||
|
ESMRF is an enhanced version of the SMRF engine with the aim
|
||||||
|
of resolving the sending limitation of SMRF to allow any node
|
||||||
|
within the DODAG to send multicast traffic up and down the RPL tree.
|
||||||
|
ESMRF is documented here:
|
||||||
|
http://dl.acm.org/citation.cfm?id=2753479
|
||||||
* 'Stateless Multicast RPL Forwarding' (SMRF)
|
* 'Stateless Multicast RPL Forwarding' (SMRF)
|
||||||
RPL in MOP 3 handles group management as per the RPL docs,
|
RPL in MOP 3 handles group management as per the RPL docs,
|
||||||
SMRF is a lightweight engine which handles datagram forwarding.
|
SMRF is a lightweight engine which handles datagram forwarding.
|
||||||
|
|
|
@ -162,7 +162,7 @@ struct uip_mcast6_driver {
|
||||||
#define UIP_MCAST6 smrf_driver
|
#define UIP_MCAST6 smrf_driver
|
||||||
|
|
||||||
#elif UIP_MCAST6_ENGINE == UIP_MCAST6_ENGINE_ESMRF
|
#elif UIP_MCAST6_ENGINE == UIP_MCAST6_ENGINE_ESMRF
|
||||||
#define RPL_CONF_MULTICAST 1
|
#define RPL_WITH_MULTICAST 1
|
||||||
#define UIP_MCAST6 esmrf_driver
|
#define UIP_MCAST6 esmrf_driver
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -88,19 +88,23 @@ uip_ds6_nbr_add(const uip_ipaddr_t *ipaddr, const uip_lladdr_t *lladdr,
|
||||||
, reason, data);
|
, reason, data);
|
||||||
if(nbr) {
|
if(nbr) {
|
||||||
uip_ipaddr_copy(&nbr->ipaddr, ipaddr);
|
uip_ipaddr_copy(&nbr->ipaddr, ipaddr);
|
||||||
#if UIP_ND6_SEND_NA || UIP_ND6_SEND_RA || !UIP_CONF_ROUTER
|
#if UIP_ND6_SEND_RA || !UIP_CONF_ROUTER
|
||||||
nbr->isrouter = isrouter;
|
nbr->isrouter = isrouter;
|
||||||
#endif /* UIP_ND6_SEND_NA || UIP_ND6_SEND_RA || !UIP_CONF_ROUTER */
|
#endif /* UIP_ND6_SEND_RA || !UIP_CONF_ROUTER */
|
||||||
nbr->state = state;
|
nbr->state = state;
|
||||||
#if UIP_CONF_IPV6_QUEUE_PKT
|
#if UIP_CONF_IPV6_QUEUE_PKT
|
||||||
uip_packetqueue_new(&nbr->packethandle);
|
uip_packetqueue_new(&nbr->packethandle);
|
||||||
#endif /* UIP_CONF_IPV6_QUEUE_PKT */
|
#endif /* UIP_CONF_IPV6_QUEUE_PKT */
|
||||||
#if UIP_ND6_SEND_NA
|
#if UIP_ND6_SEND_NS
|
||||||
/* timers are set separately, for now we put them in expired state */
|
if(nbr->state == NBR_REACHABLE) {
|
||||||
|
stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
|
||||||
|
} else {
|
||||||
|
/* We set the timer in expired state */
|
||||||
stimer_set(&nbr->reachable, 0);
|
stimer_set(&nbr->reachable, 0);
|
||||||
|
}
|
||||||
stimer_set(&nbr->sendns, 0);
|
stimer_set(&nbr->sendns, 0);
|
||||||
nbr->nscount = 0;
|
nbr->nscount = 0;
|
||||||
#endif /* UIP_ND6_SEND_NA */
|
#endif /* UIP_ND6_SEND_NS */
|
||||||
PRINTF("Adding neighbor with ip addr ");
|
PRINTF("Adding neighbor with ip addr ");
|
||||||
PRINT6ADDR(ipaddr);
|
PRINT6ADDR(ipaddr);
|
||||||
PRINTF(" link addr ");
|
PRINTF(" link addr ");
|
||||||
|
@ -241,7 +245,7 @@ uip_ds6_link_neighbor_callback(int status, int numtx)
|
||||||
#endif /* UIP_DS6_LL_NUD */
|
#endif /* UIP_DS6_LL_NUD */
|
||||||
|
|
||||||
}
|
}
|
||||||
#if UIP_ND6_SEND_NA
|
#if UIP_ND6_SEND_NS
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
/** Periodic processing on neighbors */
|
/** Periodic processing on neighbors */
|
||||||
void
|
void
|
||||||
|
@ -322,6 +326,18 @@ uip_ds6_neighbor_periodic(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
uip_ds6_nbr_refresh_reachable_state(const uip_ipaddr_t *ipaddr)
|
||||||
|
{
|
||||||
|
uip_ds6_nbr_t *nbr;
|
||||||
|
nbr = uip_ds6_nbr_lookup(ipaddr);
|
||||||
|
if(nbr != NULL) {
|
||||||
|
nbr->state = NBR_REACHABLE;
|
||||||
|
nbr->nscount = 0;
|
||||||
|
stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
uip_ds6_nbr_t *
|
uip_ds6_nbr_t *
|
||||||
uip_ds6_get_least_lifetime_neighbor(void)
|
uip_ds6_get_least_lifetime_neighbor(void)
|
||||||
{
|
{
|
||||||
|
@ -340,6 +356,6 @@ uip_ds6_get_least_lifetime_neighbor(void)
|
||||||
}
|
}
|
||||||
return nbr_expiring;
|
return nbr_expiring;
|
||||||
}
|
}
|
||||||
#endif /* UIP_ND6_SEND_NA */
|
#endif /* UIP_ND6_SEND_NS */
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
|
@ -50,8 +50,6 @@
|
||||||
#include "net/nbr-table.h"
|
#include "net/nbr-table.h"
|
||||||
#include "sys/stimer.h"
|
#include "sys/stimer.h"
|
||||||
#include "net/ipv6/uip-ds6.h"
|
#include "net/ipv6/uip-ds6.h"
|
||||||
#include "net/nbr-table.h"
|
|
||||||
|
|
||||||
#if UIP_CONF_IPV6_QUEUE_PKT
|
#if UIP_CONF_IPV6_QUEUE_PKT
|
||||||
#include "net/ip/uip-packetqueue.h"
|
#include "net/ip/uip-packetqueue.h"
|
||||||
#endif /*UIP_CONF_QUEUE_PKT */
|
#endif /*UIP_CONF_QUEUE_PKT */
|
||||||
|
@ -71,11 +69,11 @@ typedef struct uip_ds6_nbr {
|
||||||
uip_ipaddr_t ipaddr;
|
uip_ipaddr_t ipaddr;
|
||||||
uint8_t isrouter;
|
uint8_t isrouter;
|
||||||
uint8_t state;
|
uint8_t state;
|
||||||
#if UIP_ND6_SEND_NA || UIP_ND6_SEND_RA
|
#if UIP_ND6_SEND_NS || UIP_ND6_SEND_RA
|
||||||
struct stimer reachable;
|
struct stimer reachable;
|
||||||
struct stimer sendns;
|
struct stimer sendns;
|
||||||
uint8_t nscount;
|
uint8_t nscount;
|
||||||
#endif /* UIP_ND6_SEND_NA || UIP_ND6_SEND_RA */
|
#endif /* UIP_ND6_SEND_NS || UIP_ND6_SEND_RA */
|
||||||
#if UIP_CONF_IPV6_QUEUE_PKT
|
#if UIP_CONF_IPV6_QUEUE_PKT
|
||||||
struct uip_packetqueue_handle packethandle;
|
struct uip_packetqueue_handle packethandle;
|
||||||
#define UIP_DS6_NBR_PACKET_LIFETIME CLOCK_SECOND * 4
|
#define UIP_DS6_NBR_PACKET_LIFETIME CLOCK_SECOND * 4
|
||||||
|
@ -100,6 +98,17 @@ void uip_ds6_link_neighbor_callback(int status, int numtx);
|
||||||
void uip_ds6_neighbor_periodic(void);
|
void uip_ds6_neighbor_periodic(void);
|
||||||
int uip_ds6_nbr_num(void);
|
int uip_ds6_nbr_num(void);
|
||||||
|
|
||||||
|
#if UIP_ND6_SEND_NS
|
||||||
|
/**
|
||||||
|
* \brief Refresh the reachable state of a neighbor. This function
|
||||||
|
* may be called when a node receives an IPv6 message that confirms the
|
||||||
|
* reachability of a neighbor.
|
||||||
|
* \param ipaddr pointer to the IPv6 address whose neighbor reachability state
|
||||||
|
* should be refreshed.
|
||||||
|
*/
|
||||||
|
void uip_ds6_nbr_refresh_reachable_state(const uip_ipaddr_t *ipaddr);
|
||||||
|
#endif /* UIP_ND6_SEND_NS */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief
|
* \brief
|
||||||
* This searches inside the neighbor table for the neighbor that is about to
|
* This searches inside the neighbor table for the neighbor that is about to
|
||||||
|
|
|
@ -573,6 +573,12 @@ uip_ds6_route_rm_by_nexthop(uip_ipaddr_t *nexthop)
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
uip_ds6_defrt_t *
|
uip_ds6_defrt_t *
|
||||||
|
uip_ds6_defrt_head(void)
|
||||||
|
{
|
||||||
|
return list_head(defaultrouterlist);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
uip_ds6_defrt_t *
|
||||||
uip_ds6_defrt_add(uip_ipaddr_t *ipaddr, unsigned long interval)
|
uip_ds6_defrt_add(uip_ipaddr_t *ipaddr, unsigned long interval)
|
||||||
{
|
{
|
||||||
uip_ds6_defrt_t *d;
|
uip_ds6_defrt_t *d;
|
||||||
|
|
|
@ -82,14 +82,10 @@ void uip_ds6_notification_rm(struct uip_ds6_notification *n);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Routing table */
|
/* Routing table */
|
||||||
#ifndef UIP_CONF_MAX_ROUTES
|
#ifdef UIP_CONF_MAX_ROUTES
|
||||||
#ifdef UIP_CONF_DS6_ROUTE_NBU
|
|
||||||
#define UIP_DS6_ROUTE_NB UIP_CONF_DS6_ROUTE_NBU
|
|
||||||
#else /* UIP_CONF_DS6_ROUTE_NBU */
|
|
||||||
#define UIP_DS6_ROUTE_NB 4
|
|
||||||
#endif /* UIP_CONF_DS6_ROUTE_NBU */
|
|
||||||
#else /* UIP_CONF_MAX_ROUTES */
|
|
||||||
#define UIP_DS6_ROUTE_NB UIP_CONF_MAX_ROUTES
|
#define UIP_DS6_ROUTE_NB UIP_CONF_MAX_ROUTES
|
||||||
|
#else /* UIP_CONF_MAX_ROUTES */
|
||||||
|
#define UIP_DS6_ROUTE_NB 4
|
||||||
#endif /* UIP_CONF_MAX_ROUTES */
|
#endif /* UIP_CONF_MAX_ROUTES */
|
||||||
|
|
||||||
/** \brief define some additional RPL related route state and
|
/** \brief define some additional RPL related route state and
|
||||||
|
@ -181,6 +177,7 @@ typedef struct uip_ds6_defrt {
|
||||||
|
|
||||||
/** \name Default router list basic routines */
|
/** \name Default router list basic routines */
|
||||||
/** @{ */
|
/** @{ */
|
||||||
|
uip_ds6_defrt_t *uip_ds6_defrt_head(void);
|
||||||
uip_ds6_defrt_t *uip_ds6_defrt_add(uip_ipaddr_t *ipaddr,
|
uip_ds6_defrt_t *uip_ds6_defrt_add(uip_ipaddr_t *ipaddr,
|
||||||
unsigned long interval);
|
unsigned long interval);
|
||||||
void uip_ds6_defrt_rm(uip_ds6_defrt_t *defrt);
|
void uip_ds6_defrt_rm(uip_ds6_defrt_t *defrt);
|
||||||
|
|
|
@ -187,9 +187,9 @@ uip_ds6_periodic(void)
|
||||||
}
|
}
|
||||||
#endif /* !UIP_CONF_ROUTER */
|
#endif /* !UIP_CONF_ROUTER */
|
||||||
|
|
||||||
#if UIP_ND6_SEND_NA
|
#if UIP_ND6_SEND_NS
|
||||||
uip_ds6_neighbor_periodic();
|
uip_ds6_neighbor_periodic();
|
||||||
#endif /* UIP_ND6_SEND_RA */
|
#endif /* UIP_ND6_SEND_NS */
|
||||||
|
|
||||||
#if UIP_CONF_ROUTER && UIP_ND6_SEND_RA
|
#if UIP_CONF_ROUTER && UIP_ND6_SEND_RA
|
||||||
/* Periodic RA sending */
|
/* Periodic RA sending */
|
||||||
|
|
|
@ -56,6 +56,8 @@
|
||||||
* - the number of elements requested by the user in contiki configuration (name suffixed by _NBU)
|
* - the number of elements requested by the user in contiki configuration (name suffixed by _NBU)
|
||||||
* - the number of elements assigned by the system (name suffixed by _NBS)
|
* - the number of elements assigned by the system (name suffixed by _NBS)
|
||||||
* - the total number of elements is the sum (name suffixed by _NB)
|
* - the total number of elements is the sum (name suffixed by _NB)
|
||||||
|
* The routing table definitions can be found in uip-ds6-route.h
|
||||||
|
* The Neighbor cache definitions can be found in nbr-table.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Default router list */
|
/* Default router list */
|
||||||
|
|
|
@ -160,11 +160,6 @@ echo_request_input(void)
|
||||||
uip_ext_len = 0;
|
uip_ext_len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Insert RPL extension headers */
|
|
||||||
#if UIP_CONF_IPV6_RPL
|
|
||||||
rpl_insert_header();
|
|
||||||
#endif /* UIP_CONF_IPV6_RPL */
|
|
||||||
|
|
||||||
/* Below is important for the correctness of UIP_ICMP_BUF and the
|
/* Below is important for the correctness of UIP_ICMP_BUF and the
|
||||||
* checksum
|
* checksum
|
||||||
*/
|
*/
|
||||||
|
@ -260,10 +255,6 @@ uip_icmp6_error_output(uint8_t type, uint8_t code, uint32_t param) {
|
||||||
UIP_ICMP_BUF->icmpchksum = 0;
|
UIP_ICMP_BUF->icmpchksum = 0;
|
||||||
UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum();
|
UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum();
|
||||||
|
|
||||||
#if UIP_CONF_IPV6_RPL
|
|
||||||
rpl_insert_header();
|
|
||||||
#endif /* UIP_CONF_IPV6_RPL */
|
|
||||||
|
|
||||||
UIP_STAT(++uip_stat.icmp.sent);
|
UIP_STAT(++uip_stat.icmp.sent);
|
||||||
|
|
||||||
PRINTF("Sending ICMPv6 ERROR message type %d code %d to ", type, code);
|
PRINTF("Sending ICMPv6 ERROR message type %d code %d to ", type, code);
|
||||||
|
@ -301,9 +292,6 @@ uip_icmp6_send(const uip_ipaddr_t *dest, int type, int code, int payload_len)
|
||||||
UIP_STAT(++uip_stat.icmp.sent);
|
UIP_STAT(++uip_stat.icmp.sent);
|
||||||
UIP_STAT(++uip_stat.ip.sent);
|
UIP_STAT(++uip_stat.ip.sent);
|
||||||
|
|
||||||
#if UIP_CONF_IPV6_RPL
|
|
||||||
rpl_insert_header();
|
|
||||||
#endif /* UIP_CONF_IPV6_RPL */
|
|
||||||
tcpip_ipv6_output();
|
tcpip_ipv6_output();
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
|
@ -116,13 +116,16 @@ void uip_log(char *msg);
|
||||||
#define UIP_ND6_OPT_RDNSS_BUF ((uip_nd6_opt_dns *)&uip_buf[uip_l2_l3_icmp_hdr_len + nd6_opt_offset])
|
#define UIP_ND6_OPT_RDNSS_BUF ((uip_nd6_opt_dns *)&uip_buf[uip_l2_l3_icmp_hdr_len + nd6_opt_offset])
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
#if UIP_ND6_SEND_NA || UIP_ND6_SEND_RA || !UIP_CONF_ROUTER
|
#if UIP_ND6_SEND_NS || UIP_ND6_SEND_NA || UIP_ND6_SEND_RA || !UIP_CONF_ROUTER
|
||||||
static uint8_t nd6_opt_offset; /** Offset from the end of the icmpv6 header to the option in uip_buf*/
|
static uint8_t nd6_opt_offset; /** Offset from the end of the icmpv6 header to the option in uip_buf*/
|
||||||
static uint8_t *nd6_opt_llao; /** Pointer to llao option in uip_buf */
|
static uint8_t *nd6_opt_llao; /** Pointer to llao option in uip_buf */
|
||||||
static uip_ds6_nbr_t *nbr; /** Pointer to a nbr cache entry*/
|
static uip_ds6_nbr_t *nbr; /** Pointer to a nbr cache entry*/
|
||||||
static uip_ds6_defrt_t *defrt; /** Pointer to a router list entry */
|
|
||||||
static uip_ds6_addr_t *addr; /** Pointer to an interface address */
|
static uip_ds6_addr_t *addr; /** Pointer to an interface address */
|
||||||
#endif /* UIP_ND6_SEND_NA || UIP_ND6_SEND_RA || !UIP_CONF_ROUTER */
|
#endif /* UIP_ND6_SEND_NS || UIP_ND6_SEND_NA || UIP_ND6_SEND_RA || !UIP_CONF_ROUTER */
|
||||||
|
|
||||||
|
#if UIP_ND6_SEND_NS || UIP_ND6_SEND_RA || !UIP_CONF_ROUTER
|
||||||
|
static uip_ds6_defrt_t *defrt; /** Pointer to a router list entry */
|
||||||
|
#endif /* UIP_ND6_SEND_NS || UIP_ND6_SEND_RA || !UIP_CONF_ROUTER */
|
||||||
|
|
||||||
#if !UIP_CONF_ROUTER // TBD see if we move it to ra_input
|
#if !UIP_CONF_ROUTER // TBD see if we move it to ra_input
|
||||||
static uip_nd6_opt_prefix_info *nd6_opt_prefix_info; /** Pointer to prefix information option in uip_buf */
|
static uip_nd6_opt_prefix_info *nd6_opt_prefix_info; /** Pointer to prefix information option in uip_buf */
|
||||||
|
@ -157,7 +160,27 @@ create_llao(uint8_t *llao, uint8_t type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*------------------------------------------------------------------*/
|
/*------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* Neighbor Solicitation Processing
|
||||||
|
*
|
||||||
|
* The NS can be received in 3 cases (procedures):
|
||||||
|
* - sender is performing DAD (ip src = unspecified, no SLLAO option)
|
||||||
|
* - sender is performing NUD (ip dst = unicast)
|
||||||
|
* - sender is performing address resolution (ip dest = solicited node mcast
|
||||||
|
* address)
|
||||||
|
*
|
||||||
|
* We do:
|
||||||
|
* - if the tgt belongs to me, reply, otherwise ignore
|
||||||
|
* - if i was performing DAD for the same address, two cases:
|
||||||
|
* -- I already sent a NS, hence I win
|
||||||
|
* -- I did not send a NS yet, hence I lose
|
||||||
|
*
|
||||||
|
* If we need to send a NA in response (i.e. the NS was done for NUD, or
|
||||||
|
* address resolution, or DAD and there is a conflict), we do it in this
|
||||||
|
* function: set src, dst, tgt address in the three cases, then for all cases
|
||||||
|
* set the rest, including SLLAO
|
||||||
|
*
|
||||||
|
*/
|
||||||
#if UIP_ND6_SEND_NA
|
#if UIP_ND6_SEND_NA
|
||||||
static void
|
static void
|
||||||
ns_input(void)
|
ns_input(void)
|
||||||
|
@ -238,9 +261,9 @@ ns_input(void)
|
||||||
|
|
||||||
addr = uip_ds6_addr_lookup(&UIP_ND6_NS_BUF->tgtipaddr);
|
addr = uip_ds6_addr_lookup(&UIP_ND6_NS_BUF->tgtipaddr);
|
||||||
if(addr != NULL) {
|
if(addr != NULL) {
|
||||||
#if UIP_ND6_DEF_MAXDADNS > 0
|
|
||||||
if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) {
|
if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) {
|
||||||
/* DAD CASE */
|
/* DAD CASE */
|
||||||
|
#if UIP_ND6_DEF_MAXDADNS > 0
|
||||||
#if UIP_CONF_IPV6_CHECKS
|
#if UIP_CONF_IPV6_CHECKS
|
||||||
if(!uip_is_addr_solicited_node(&UIP_IP_BUF->destipaddr)) {
|
if(!uip_is_addr_solicited_node(&UIP_IP_BUF->destipaddr)) {
|
||||||
PRINTF("NS received is bad\n");
|
PRINTF("NS received is bad\n");
|
||||||
|
@ -258,9 +281,7 @@ ns_input(void)
|
||||||
goto discard;
|
goto discard;
|
||||||
}
|
}
|
||||||
#else /* UIP_ND6_DEF_MAXDADNS > 0 */
|
#else /* UIP_ND6_DEF_MAXDADNS > 0 */
|
||||||
if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) {
|
goto discard; /* DAD CASE */
|
||||||
/* DAD CASE */
|
|
||||||
goto discard;
|
|
||||||
#endif /* UIP_ND6_DEF_MAXDADNS > 0 */
|
#endif /* UIP_ND6_DEF_MAXDADNS > 0 */
|
||||||
}
|
}
|
||||||
#if UIP_CONF_IPV6_CHECKS
|
#if UIP_CONF_IPV6_CHECKS
|
||||||
|
@ -348,6 +369,7 @@ discard:
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------*/
|
/*------------------------------------------------------------------*/
|
||||||
|
#if UIP_ND6_SEND_NS
|
||||||
void
|
void
|
||||||
uip_nd6_ns_output(uip_ipaddr_t * src, uip_ipaddr_t * dest, uip_ipaddr_t * tgt)
|
uip_nd6_ns_output(uip_ipaddr_t * src, uip_ipaddr_t * dest, uip_ipaddr_t * tgt)
|
||||||
{
|
{
|
||||||
|
@ -410,7 +432,9 @@ uip_nd6_ns_output(uip_ipaddr_t * src, uip_ipaddr_t * dest, uip_ipaddr_t * tgt)
|
||||||
PRINTF("\n");
|
PRINTF("\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#if UIP_ND6_SEND_NA
|
#endif /* UIP_ND6_SEND_NS */
|
||||||
|
|
||||||
|
#if UIP_ND6_SEND_NS
|
||||||
/*------------------------------------------------------------------*/
|
/*------------------------------------------------------------------*/
|
||||||
/**
|
/**
|
||||||
* Neighbor Advertisement Processing
|
* Neighbor Advertisement Processing
|
||||||
|
@ -522,14 +546,11 @@ na_input(void)
|
||||||
goto discard;
|
goto discard;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(is_solicited) {
|
/* Note: No need to refresh the state of the nbr here.
|
||||||
nbr->state = NBR_REACHABLE;
|
* It has already been refreshed upon receiving the unicast IPv6 ND packet.
|
||||||
nbr->nscount = 0;
|
* See: uip_ds6_nbr_refresh_reachable_state()
|
||||||
|
*/
|
||||||
/* reachable time is stored in ms */
|
if(!is_solicited) {
|
||||||
stimer_set(&(nbr->reachable), uip_ds6_if.reachable_time / 1000);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
nbr->state = NBR_STALE;
|
nbr->state = NBR_STALE;
|
||||||
}
|
}
|
||||||
nbr->isrouter = is_router;
|
nbr->isrouter = is_router;
|
||||||
|
@ -552,11 +573,10 @@ na_input(void)
|
||||||
goto discard;
|
goto discard;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(is_solicited) {
|
/* Note: No need to refresh the state of the nbr here.
|
||||||
nbr->state = NBR_REACHABLE;
|
* It has already been refreshed upon receiving the unicast IPv6 ND packet.
|
||||||
/* reachable time is stored in ms */
|
* See: uip_ds6_nbr_refresh_reachable_state()
|
||||||
stimer_set(&(nbr->reachable), uip_ds6_if.reachable_time / 1000);
|
*/
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(nbr->isrouter && !is_router) {
|
if(nbr->isrouter && !is_router) {
|
||||||
|
@ -589,7 +609,7 @@ discard:
|
||||||
uip_clear_buf();
|
uip_clear_buf();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif /* UIP_ND6_SEND_NA */
|
#endif /* UIP_ND6_SEND_NS */
|
||||||
|
|
||||||
#if UIP_CONF_ROUTER
|
#if UIP_CONF_ROUTER
|
||||||
#if UIP_ND6_SEND_RA
|
#if UIP_ND6_SEND_RA
|
||||||
|
@ -662,7 +682,8 @@ rs_input(void)
|
||||||
}
|
}
|
||||||
if(memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET],
|
if(memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET],
|
||||||
lladdr, UIP_LLADDR_LEN) != 0) {
|
lladdr, UIP_LLADDR_LEN) != 0) {
|
||||||
uip_ds6_nbr_t nbr_data = *nbr;
|
uip_ds6_nbr_t nbr_data;
|
||||||
|
nbr_data = *nbr;
|
||||||
uip_ds6_nbr_rm(nbr);
|
uip_ds6_nbr_rm(nbr);
|
||||||
nbr = uip_ds6_nbr_add(&UIP_IP_BUF->srcipaddr, &lladdr_aligned,
|
nbr = uip_ds6_nbr_add(&UIP_IP_BUF->srcipaddr, &lladdr_aligned,
|
||||||
0, NBR_STALE, NBR_TABLE_REASON_IPV6_ND, NULL);
|
0, NBR_STALE, NBR_TABLE_REASON_IPV6_ND, NULL);
|
||||||
|
@ -1082,6 +1103,8 @@ discard:
|
||||||
#if UIP_ND6_SEND_NA
|
#if UIP_ND6_SEND_NA
|
||||||
UIP_ICMP6_HANDLER(ns_input_handler, ICMP6_NS, UIP_ICMP6_HANDLER_CODE_ANY,
|
UIP_ICMP6_HANDLER(ns_input_handler, ICMP6_NS, UIP_ICMP6_HANDLER_CODE_ANY,
|
||||||
ns_input);
|
ns_input);
|
||||||
|
#endif
|
||||||
|
#if UIP_ND6_SEND_NS
|
||||||
UIP_ICMP6_HANDLER(na_input_handler, ICMP6_NA, UIP_ICMP6_HANDLER_CODE_ANY,
|
UIP_ICMP6_HANDLER(na_input_handler, ICMP6_NA, UIP_ICMP6_HANDLER_CODE_ANY,
|
||||||
na_input);
|
na_input);
|
||||||
#endif
|
#endif
|
||||||
|
@ -1099,19 +1122,16 @@ UIP_ICMP6_HANDLER(ra_input_handler, ICMP6_RA, UIP_ICMP6_HANDLER_CODE_ANY,
|
||||||
void
|
void
|
||||||
uip_nd6_init()
|
uip_nd6_init()
|
||||||
{
|
{
|
||||||
|
|
||||||
#if UIP_ND6_SEND_NA
|
#if UIP_ND6_SEND_NA
|
||||||
/* Only handle NSs if we are prepared to send out NAs */
|
/* Only handle NSs if we are prepared to send out NAs */
|
||||||
uip_icmp6_register_input_handler(&ns_input_handler);
|
uip_icmp6_register_input_handler(&ns_input_handler);
|
||||||
|
|
||||||
/*
|
|
||||||
* Only handle NAs if we are prepared to send out NAs.
|
|
||||||
* This is perhaps logically incorrect, but this condition was present in
|
|
||||||
* uip_process and we keep it until proven wrong
|
|
||||||
*/
|
|
||||||
uip_icmp6_register_input_handler(&na_input_handler);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if UIP_ND6_SEND_NS
|
||||||
|
/*
|
||||||
|
* Only handle NAs if we are prepared to send out NSs. */
|
||||||
|
uip_icmp6_register_input_handler(&na_input_handler);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if UIP_CONF_ROUTER && UIP_ND6_SEND_RA
|
#if UIP_CONF_ROUTER && UIP_ND6_SEND_RA
|
||||||
/* Only accept RS if we are a router and happy to send out RAs */
|
/* Only accept RS if we are a router and happy to send out RAs */
|
||||||
|
|
|
@ -60,11 +60,23 @@
|
||||||
/** \name RFC 4861 Host constant */
|
/** \name RFC 4861 Host constant */
|
||||||
/** @{ */
|
/** @{ */
|
||||||
/** \brief Maximum router solicitation delay */
|
/** \brief Maximum router solicitation delay */
|
||||||
|
#ifndef UIP_CONF_ND6_MAX_RTR_SOLICITATION_DELAY
|
||||||
#define UIP_ND6_MAX_RTR_SOLICITATION_DELAY 1
|
#define UIP_ND6_MAX_RTR_SOLICITATION_DELAY 1
|
||||||
|
#else
|
||||||
|
#define UIP_ND6_MAX_RTR_SOLICITATION_DELAY UIP_CONF_ND6_MAX_RTR_SOLICITATION_DELAY
|
||||||
|
#endif
|
||||||
/** \brief Router solicitation interval */
|
/** \brief Router solicitation interval */
|
||||||
|
#ifndef UIP_CONF_ND6_RTR_SOLICITATION_INTERVAL
|
||||||
#define UIP_ND6_RTR_SOLICITATION_INTERVAL 4
|
#define UIP_ND6_RTR_SOLICITATION_INTERVAL 4
|
||||||
|
#else
|
||||||
|
#define UIP_ND6_RTR_SOLICITATION_INTERVAL UIP_CONF_ND6_RTR_SOLICITATION_INTERVAL
|
||||||
|
#endif
|
||||||
/** \brief Maximum router solicitations */
|
/** \brief Maximum router solicitations */
|
||||||
|
#ifndef UIP_CONF_ND6_MAX_RTR_SOLICITATIONS
|
||||||
#define UIP_ND6_MAX_RTR_SOLICITATIONS 3
|
#define UIP_ND6_MAX_RTR_SOLICITATIONS 3
|
||||||
|
#else
|
||||||
|
#define UIP_ND6_MAX_RTR_SOLICITATIONS UIP_CONF_ND6_MAX_RTR_SOLICITATIONS
|
||||||
|
#endif
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
/** \name RFC 4861 Router constants */
|
/** \name RFC 4861 Router constants */
|
||||||
|
@ -74,6 +86,11 @@
|
||||||
#else
|
#else
|
||||||
#define UIP_ND6_SEND_RA UIP_CONF_ND6_SEND_RA
|
#define UIP_ND6_SEND_RA UIP_CONF_ND6_SEND_RA
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef UIP_CONF_ND6_SEND_NS
|
||||||
|
#define UIP_ND6_SEND_NS 1 /* enable/disable NS sending */
|
||||||
|
#else
|
||||||
|
#define UIP_ND6_SEND_NS UIP_CONF_ND6_SEND_NS
|
||||||
|
#endif
|
||||||
#ifndef UIP_CONF_ND6_SEND_NA
|
#ifndef UIP_CONF_ND6_SEND_NA
|
||||||
#define UIP_ND6_SEND_NA 1 /* enable/disable NA sending */
|
#define UIP_ND6_SEND_NA 1 /* enable/disable NA sending */
|
||||||
#else
|
#else
|
||||||
|
@ -91,7 +108,11 @@
|
||||||
#endif
|
#endif
|
||||||
#define UIP_ND6_M_FLAG 0
|
#define UIP_ND6_M_FLAG 0
|
||||||
#define UIP_ND6_O_FLAG (UIP_ND6_RA_RDNSS || UIP_ND6_RA_DNSSL)
|
#define UIP_ND6_O_FLAG (UIP_ND6_RA_RDNSS || UIP_ND6_RA_DNSSL)
|
||||||
|
#ifndef UIP_CONF_ROUTER_LIFETIME
|
||||||
#define UIP_ND6_ROUTER_LIFETIME 3 * UIP_ND6_MAX_RA_INTERVAL
|
#define UIP_ND6_ROUTER_LIFETIME 3 * UIP_ND6_MAX_RA_INTERVAL
|
||||||
|
#else
|
||||||
|
#define UIP_ND6_ROUTER_LIFETIME UIP_CONF_ROUTER_LIFETIME
|
||||||
|
#endif
|
||||||
|
|
||||||
#define UIP_ND6_MAX_INITIAL_RA_INTERVAL 16 /*seconds*/
|
#define UIP_ND6_MAX_INITIAL_RA_INTERVAL 16 /*seconds*/
|
||||||
#define UIP_ND6_MAX_INITIAL_RAS 3 /*transmissions*/
|
#define UIP_ND6_MAX_INITIAL_RAS 3 /*transmissions*/
|
||||||
|
@ -109,7 +130,7 @@
|
||||||
#if UIP_CONF_LL_802154
|
#if UIP_CONF_LL_802154
|
||||||
#define UIP_ND6_DEF_MAXDADNS 0
|
#define UIP_ND6_DEF_MAXDADNS 0
|
||||||
#else /* UIP_CONF_LL_802154 */
|
#else /* UIP_CONF_LL_802154 */
|
||||||
#define UIP_ND6_DEF_MAXDADNS UIP_ND6_SEND_NA
|
#define UIP_ND6_DEF_MAXDADNS UIP_ND6_SEND_NS
|
||||||
#endif /* UIP_CONF_LL_802154 */
|
#endif /* UIP_CONF_LL_802154 */
|
||||||
#else /* UIP_CONF_ND6_DEF_MAXDADNS */
|
#else /* UIP_CONF_ND6_DEF_MAXDADNS */
|
||||||
#define UIP_ND6_DEF_MAXDADNS UIP_CONF_ND6_DEF_MAXDADNS
|
#define UIP_ND6_DEF_MAXDADNS UIP_CONF_ND6_DEF_MAXDADNS
|
||||||
|
@ -336,30 +357,6 @@ typedef struct uip_nd6_opt_redirected_hdr {
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* \brief Process a neighbor solicitation
|
|
||||||
*
|
|
||||||
* The NS can be received in 3 cases (procedures):
|
|
||||||
* - sender is performing DAD (ip src = unspecified, no SLLAO option)
|
|
||||||
* - sender is performing NUD (ip dst = unicast)
|
|
||||||
* - sender is performing address resolution (ip dest = solicited node mcast
|
|
||||||
* address)
|
|
||||||
*
|
|
||||||
* We do:
|
|
||||||
* - if the tgt belongs to me, reply, otherwise ignore
|
|
||||||
* - if i was performing DAD for the same address, two cases:
|
|
||||||
* -- I already sent a NS, hence I win
|
|
||||||
* -- I did not send a NS yet, hence I lose
|
|
||||||
*
|
|
||||||
* If we need to send a NA in response (i.e. the NS was done for NUD, or
|
|
||||||
* address resolution, or DAD and there is a conflict), we do it in this
|
|
||||||
* function: set src, dst, tgt address in the three cases, then for all cases
|
|
||||||
* set the rest, including SLLAO
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
uip_nd6_ns_input(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Send a neighbor solicitation, send a Neighbor Advertisement
|
* \brief Send a neighbor solicitation, send a Neighbor Advertisement
|
||||||
* \param src pointer to the src of the NS if known
|
* \param src pointer to the src of the NS if known
|
||||||
* \param dest pointer to ip address to send the NS, for DAD or ADDR Resol,
|
* \param dest pointer to ip address to send the NS, for DAD or ADDR Resol,
|
||||||
|
|
|
@ -73,6 +73,7 @@
|
||||||
|
|
||||||
#include "sys/cc.h"
|
#include "sys/cc.h"
|
||||||
#include "net/ip/uip.h"
|
#include "net/ip/uip.h"
|
||||||
|
#include "net/ip/uip_arch.h"
|
||||||
#include "net/ip/uipopt.h"
|
#include "net/ip/uipopt.h"
|
||||||
#include "net/ipv6/uip-icmp6.h"
|
#include "net/ipv6/uip-icmp6.h"
|
||||||
#include "net/ipv6/uip-nd6.h"
|
#include "net/ipv6/uip-nd6.h"
|
||||||
|
@ -84,6 +85,10 @@
|
||||||
#include "rpl/rpl-private.h"
|
#include "rpl/rpl-private.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if UIP_ND6_SEND_NS
|
||||||
|
#include "net/ipv6/uip-ds6-nbr.h"
|
||||||
|
#endif /* UIP_ND6_SEND_NS */
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
@ -890,7 +895,7 @@ ext_hdr_options_process(void)
|
||||||
*/
|
*/
|
||||||
#if UIP_CONF_IPV6_RPL
|
#if UIP_CONF_IPV6_RPL
|
||||||
PRINTF("Processing RPL option\n");
|
PRINTF("Processing RPL option\n");
|
||||||
if(rpl_verify_hbh_header(uip_ext_opt_offset)) {
|
if(!rpl_verify_hbh_header(uip_ext_opt_offset)) {
|
||||||
PRINTF("RPL Option Error: Dropping Packet\n");
|
PRINTF("RPL Option Error: Dropping Packet\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -1150,6 +1155,13 @@ uip_process(uint8_t flag)
|
||||||
goto drop;
|
goto drop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Refresh neighbor state after receiving a unicast message */
|
||||||
|
#if UIP_ND6_SEND_NS
|
||||||
|
if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
|
||||||
|
uip_ds6_nbr_refresh_reachable_state(&UIP_IP_BUF->srcipaddr);
|
||||||
|
}
|
||||||
|
#endif /* UIP_ND6_SEND_NS */
|
||||||
|
|
||||||
#if UIP_CONF_ROUTER
|
#if UIP_CONF_ROUTER
|
||||||
/*
|
/*
|
||||||
* Next header field processing. In IPv6, we can have extension headers,
|
* Next header field processing. In IPv6, we can have extension headers,
|
||||||
|
@ -1228,14 +1240,6 @@ uip_process(uint8_t flag)
|
||||||
goto send;
|
goto send;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if UIP_CONF_IPV6_RPL
|
|
||||||
if(!rpl_update_header()) {
|
|
||||||
/* Packet can not be forwarded */
|
|
||||||
PRINTF("RPL header update error\n");
|
|
||||||
goto drop;
|
|
||||||
}
|
|
||||||
#endif /* UIP_CONF_IPV6_RPL */
|
|
||||||
|
|
||||||
UIP_IP_BUF->ttl = UIP_IP_BUF->ttl - 1;
|
UIP_IP_BUF->ttl = UIP_IP_BUF->ttl - 1;
|
||||||
PRINTF("Forwarding packet to ");
|
PRINTF("Forwarding packet to ");
|
||||||
PRINT6ADDR(&UIP_IP_BUF->destipaddr);
|
PRINT6ADDR(&UIP_IP_BUF->destipaddr);
|
||||||
|
@ -1582,10 +1586,6 @@ uip_process(uint8_t flag)
|
||||||
}
|
}
|
||||||
#endif /* UIP_UDP_CHECKSUMS */
|
#endif /* UIP_UDP_CHECKSUMS */
|
||||||
|
|
||||||
#if UIP_CONF_IPV6_RPL
|
|
||||||
rpl_insert_header();
|
|
||||||
#endif /* UIP_CONF_IPV6_RPL */
|
|
||||||
|
|
||||||
UIP_STAT(++uip_stat.udp.sent);
|
UIP_STAT(++uip_stat.udp.sent);
|
||||||
goto ip_send_nolen;
|
goto ip_send_nolen;
|
||||||
#endif /* UIP_UDP */
|
#endif /* UIP_UDP */
|
||||||
|
@ -1854,8 +1854,10 @@ uip_process(uint8_t flag)
|
||||||
if((UIP_TCP_BUF->flags & TCP_SYN)) {
|
if((UIP_TCP_BUF->flags & TCP_SYN)) {
|
||||||
if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_SYN_RCVD) {
|
if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_SYN_RCVD) {
|
||||||
goto tcp_send_synack;
|
goto tcp_send_synack;
|
||||||
|
#if UIP_ACTIVE_OPEN
|
||||||
} else if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_SYN_SENT) {
|
} else if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_SYN_SENT) {
|
||||||
goto tcp_send_syn;
|
goto tcp_send_syn;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
goto tcp_send_ack;
|
goto tcp_send_ack;
|
||||||
|
|
347
core/net/ipv6/websocket-http-client.c
Normal file
347
core/net/ipv6/websocket-http-client.c
Normal file
|
@ -0,0 +1,347 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Thingsquare, http://www.thingsquare.com/.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the copyright holder nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||||
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "websocket-http-client.h"
|
||||||
|
#include "net/ip/uiplib.h"
|
||||||
|
#include "net/ip/resolv.h"
|
||||||
|
|
||||||
|
#include "ip64-addr.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define DEBUG DEBUG_NONE
|
||||||
|
#include "net/ip/uip-debug.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
STATE_WAITING_FOR_HEADER,
|
||||||
|
STATE_WAITING_FOR_CONNECTED,
|
||||||
|
STATE_STEADY_STATE,
|
||||||
|
};
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
send_get(struct websocket_http_client_state *s)
|
||||||
|
{
|
||||||
|
struct tcp_socket *tcps;
|
||||||
|
|
||||||
|
tcps = &s->s;
|
||||||
|
tcp_socket_send_str(tcps, "GET ");
|
||||||
|
tcp_socket_send_str(tcps, s->file);
|
||||||
|
tcp_socket_send_str(tcps, " HTTP/1.1\r\n");
|
||||||
|
tcp_socket_send_str(tcps, "Host: ");
|
||||||
|
tcp_socket_send_str(tcps, s->host);
|
||||||
|
tcp_socket_send_str(tcps, "\r\n");
|
||||||
|
if(strlen(s->header) > 0) {
|
||||||
|
tcp_socket_send_str(tcps, s->header);
|
||||||
|
}
|
||||||
|
/* The Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== header is
|
||||||
|
supposed to be a random value, encoded as base64, that is SHA1
|
||||||
|
hashed by the server and returned in a HTTP header. This is used
|
||||||
|
to make sure that we are not seeing some cached version of this
|
||||||
|
conversation. But we have no SHA1 code by default in Contiki, so
|
||||||
|
we can't check the return value. Therefore we just use a
|
||||||
|
hardcoded value here. */
|
||||||
|
tcp_socket_send_str(tcps,
|
||||||
|
"Connection: Upgrade\r\n"
|
||||||
|
"Upgrade: websocket\r\n"
|
||||||
|
"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r\n"
|
||||||
|
"Sec-WebSocket-Version: 13\r\n"
|
||||||
|
"Sec-WebSocket-Protocol:");
|
||||||
|
tcp_socket_send_str(tcps, s->subprotocol);
|
||||||
|
tcp_socket_send_str(tcps, "\r\n");
|
||||||
|
tcp_socket_send_str(tcps, "\r\n");
|
||||||
|
PRINTF("websocket-http-client: send_get(): output buffer left %d\n", tcp_socket_max_sendlen(tcps));
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
send_connect(struct websocket_http_client_state *s)
|
||||||
|
{
|
||||||
|
struct tcp_socket *tcps;
|
||||||
|
char buf[20];
|
||||||
|
|
||||||
|
tcps = &s->s;
|
||||||
|
tcp_socket_send_str(tcps, "CONNECT ");
|
||||||
|
tcp_socket_send_str(tcps, s->host);
|
||||||
|
tcp_socket_send_str(tcps, ":");
|
||||||
|
sprintf(buf, "%d", s->port);
|
||||||
|
tcp_socket_send_str(tcps, buf);
|
||||||
|
tcp_socket_send_str(tcps, " HTTP/1.1\r\n");
|
||||||
|
tcp_socket_send_str(tcps, "Host: ");
|
||||||
|
tcp_socket_send_str(tcps, s->host);
|
||||||
|
tcp_socket_send_str(tcps, "\r\n");
|
||||||
|
tcp_socket_send_str(tcps, "Proxy-Connection: Keep-Alive\r\n\r\n");
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
event(struct tcp_socket *tcps, void *ptr,
|
||||||
|
tcp_socket_event_t e)
|
||||||
|
{
|
||||||
|
struct websocket_http_client_state *s = ptr;
|
||||||
|
|
||||||
|
if(e == TCP_SOCKET_CONNECTED) {
|
||||||
|
if(s->proxy_port != 0) {
|
||||||
|
send_connect(s);
|
||||||
|
} else {
|
||||||
|
send_get(s);
|
||||||
|
}
|
||||||
|
} else if(e == TCP_SOCKET_CLOSED) {
|
||||||
|
websocket_http_client_closed(s);
|
||||||
|
} else if(e == TCP_SOCKET_TIMEDOUT) {
|
||||||
|
websocket_http_client_timedout(s);
|
||||||
|
} else if(e == TCP_SOCKET_ABORTED) {
|
||||||
|
websocket_http_client_aborted(s);
|
||||||
|
} else if(e == TCP_SOCKET_DATA_SENT) {
|
||||||
|
/* We could feed this information up to the websocket.c layer, but
|
||||||
|
we currently do not do that. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static int
|
||||||
|
parse_header_byte(struct websocket_http_client_state *s,
|
||||||
|
uint8_t b)
|
||||||
|
{
|
||||||
|
static const char *endmarker = "\r\n\r\n";
|
||||||
|
|
||||||
|
PT_BEGIN(&s->parse_header_pt);
|
||||||
|
|
||||||
|
/* Skip the first part of the HTTP response */
|
||||||
|
while(b != ' ') {
|
||||||
|
PT_YIELD(&s->parse_header_pt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip the space that follow the first part */
|
||||||
|
PT_YIELD(&s->parse_header_pt);
|
||||||
|
|
||||||
|
/* Read the first three bytes that constistute the HTTP status
|
||||||
|
code. We store the HTTP status code as an integer in the
|
||||||
|
s->http_status field. */
|
||||||
|
s->http_status = (b - '0');
|
||||||
|
PT_YIELD(&s->parse_header_pt);
|
||||||
|
s->http_status = s->http_status * 10 + (b - '0');
|
||||||
|
PT_YIELD(&s->parse_header_pt);
|
||||||
|
s->http_status = s->http_status * 10 + (b - '0');
|
||||||
|
|
||||||
|
if((s->proxy_port != 0 && !(s->http_status == 200 || s->http_status == 101)) ||
|
||||||
|
(s->proxy_port == 0 && s->http_status != 101)) {
|
||||||
|
/* This is a websocket request, so the server should have answered
|
||||||
|
with a 101 Switching protocols response. */
|
||||||
|
PRINTF("Websocket HTTP client didn't get the 101 status code (got %d), closing connection\n",
|
||||||
|
s->http_status);
|
||||||
|
websocket_http_client_close(s);
|
||||||
|
while(1) {
|
||||||
|
PT_YIELD(&s->parse_header_pt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keep eating header bytes until we reach the end of it. The end is
|
||||||
|
indicated by the string "\r\n\r\n". We don't actually look at any
|
||||||
|
of the headers.
|
||||||
|
|
||||||
|
The s->i variable contains the number of consecutive bytes
|
||||||
|
matched. If we match the total length of the string, we stop.
|
||||||
|
*/
|
||||||
|
|
||||||
|
s->i = 0;
|
||||||
|
do {
|
||||||
|
PT_YIELD(&s->parse_header_pt);
|
||||||
|
if(b == (uint8_t)endmarker[s->i]) {
|
||||||
|
s->i++;
|
||||||
|
} else {
|
||||||
|
s->i = 0;
|
||||||
|
}
|
||||||
|
} while(s->i < strlen(endmarker));
|
||||||
|
|
||||||
|
if(s->proxy_port != 0 && s->state == STATE_WAITING_FOR_HEADER) {
|
||||||
|
send_get(s);
|
||||||
|
s->state = STATE_WAITING_FOR_CONNECTED;
|
||||||
|
} else {
|
||||||
|
s->state = STATE_STEADY_STATE;
|
||||||
|
websocket_http_client_connected(s);
|
||||||
|
}
|
||||||
|
PT_END(&s->parse_header_pt);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static int
|
||||||
|
input(struct tcp_socket *tcps, void *ptr,
|
||||||
|
const uint8_t *inputptr, int inputdatalen)
|
||||||
|
{
|
||||||
|
struct websocket_http_client_state *s = ptr;
|
||||||
|
|
||||||
|
if(s->state == STATE_WAITING_FOR_HEADER ||
|
||||||
|
s->state == STATE_WAITING_FOR_CONNECTED) {
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < inputdatalen; i++) {
|
||||||
|
parse_header_byte(s, inputptr[i]);
|
||||||
|
if(s->state == STATE_STEADY_STATE) {
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(i < inputdatalen && s->state == STATE_STEADY_STATE) {
|
||||||
|
websocket_http_client_datahandler(s, &inputptr[i], inputdatalen - i);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
websocket_http_client_datahandler(s, inputptr, inputdatalen);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; /* all data consumed */
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
websocket_http_client_register(struct websocket_http_client_state *s,
|
||||||
|
const char *host,
|
||||||
|
uint16_t port,
|
||||||
|
const char *file,
|
||||||
|
const char *subprotocol,
|
||||||
|
const char *header)
|
||||||
|
{
|
||||||
|
if(host == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
strncpy(s->host, host, sizeof(s->host));
|
||||||
|
|
||||||
|
if(file == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
strncpy(s->file, file, sizeof(s->file));
|
||||||
|
|
||||||
|
if(subprotocol == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
strncpy(s->subprotocol, subprotocol, sizeof(s->subprotocol));
|
||||||
|
|
||||||
|
if(header == NULL) {
|
||||||
|
strncpy(s->header, "", sizeof(s->header));
|
||||||
|
} else {
|
||||||
|
strncpy(s->header, header, sizeof(s->header));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(port == 0) {
|
||||||
|
s->port = 80;
|
||||||
|
} else {
|
||||||
|
s->port = port;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
websocket_http_client_get(struct websocket_http_client_state *s)
|
||||||
|
{
|
||||||
|
uip_ip4addr_t ip4addr;
|
||||||
|
uip_ip6addr_t ip6addr;
|
||||||
|
uip_ip6addr_t *addr;
|
||||||
|
uint16_t port;
|
||||||
|
|
||||||
|
PRINTF("websocket_http_client_get: connecting to %s with file %s subprotocol %s header %s\n",
|
||||||
|
s->host, s->file, s->subprotocol, s->header);
|
||||||
|
|
||||||
|
|
||||||
|
s->state = STATE_WAITING_FOR_HEADER;
|
||||||
|
|
||||||
|
if(tcp_socket_register(&s->s, s,
|
||||||
|
s->inputbuf, sizeof(s->inputbuf),
|
||||||
|
s->outputbuf, sizeof(s->outputbuf),
|
||||||
|
input, event) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
port = s->port;
|
||||||
|
if(s->proxy_port != 0) {
|
||||||
|
/* The proxy address should be an IPv6 address. */
|
||||||
|
uip_ipaddr_copy(&ip6addr, &s->proxy_addr);
|
||||||
|
port = s->proxy_port;
|
||||||
|
} else if(uiplib_ip6addrconv(s->host, &ip6addr) == 0) {
|
||||||
|
/* First check if the host is an IP address. */
|
||||||
|
if(uiplib_ip4addrconv(s->host, &ip4addr) != 0) {
|
||||||
|
ip64_addr_4to6(&ip4addr, &ip6addr);
|
||||||
|
} else {
|
||||||
|
/* Try to lookup the hostname. If it fails, we initiate a hostname
|
||||||
|
lookup. */
|
||||||
|
if(resolv_lookup(s->host, &addr) != RESOLV_STATUS_CACHED) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return tcp_socket_connect(&s->s, addr, s->port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tcp_socket_connect(&s->s, &ip6addr, port);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
websocket_http_client_send(struct websocket_http_client_state *s,
|
||||||
|
const uint8_t *data,
|
||||||
|
uint16_t datalen)
|
||||||
|
{
|
||||||
|
if(s->state == STATE_STEADY_STATE) {
|
||||||
|
return tcp_socket_send(&s->s, data, datalen);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
websocket_http_client_sendbuflen(struct websocket_http_client_state *s)
|
||||||
|
{
|
||||||
|
return tcp_socket_max_sendlen(&s->s);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
websocket_http_client_close(struct websocket_http_client_state *s)
|
||||||
|
{
|
||||||
|
tcp_socket_close(&s->s);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
const char *
|
||||||
|
websocket_http_client_hostname(struct websocket_http_client_state *s)
|
||||||
|
{
|
||||||
|
return s->host;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
websocket_http_client_init(struct websocket_http_client_state *s)
|
||||||
|
{
|
||||||
|
uip_create_unspecified(&s->proxy_addr);
|
||||||
|
s->proxy_port = 0;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
websocket_http_client_set_proxy(struct websocket_http_client_state *s,
|
||||||
|
const uip_ipaddr_t *addr, uint16_t port)
|
||||||
|
{
|
||||||
|
uip_ipaddr_copy(&s->proxy_addr, addr);
|
||||||
|
s->proxy_port = port;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
websocket_http_client_queuelen(struct websocket_http_client_state *s)
|
||||||
|
{
|
||||||
|
return tcp_socket_queuelen(&s->s);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
123
core/net/ipv6/websocket-http-client.h
Normal file
123
core/net/ipv6/websocket-http-client.h
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Thingsquare, http://www.thingsquare.com/.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the copyright holder nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||||
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef WEBSOCKET_HTTP_CLIENT_H_
|
||||||
|
#define WEBSOCKET_HTTP_CLIENT_H_
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "tcp-socket.h"
|
||||||
|
|
||||||
|
#ifdef WEBSOCKET_HTTP_CLIENT_CONF_INPUTBUFSIZE
|
||||||
|
#define WEBSOCKET_HTTP_CLIENT_INPUTBUFSIZE WEBSOCKET_HTTP_CLIENT_CONF_INPUTBUFSIZE
|
||||||
|
#else /* WEBSOCKET_HTTP_CLIENT_CONF_INPUTBUFSIZE */
|
||||||
|
#define WEBSOCKET_HTTP_CLIENT_INPUTBUFSIZE 100
|
||||||
|
#endif /* WEBSOCKET_HTTP_CLIENT_CONF_INPUTBUFSIZE */
|
||||||
|
|
||||||
|
#ifdef WEBSOCKET_HTTP_CLIENT_CONF_OUTPUTBUFSIZE
|
||||||
|
#define WEBSOCKET_HTTP_CLIENT_OUTPUTBUFSIZE WEBSOCKET_HTTP_CLIENT_CONF_OUTPUTBUFSIZE
|
||||||
|
#else /* WEBSOCKET_HTTP_CLIENT_CONF_OUTPUTBUFSIZE */
|
||||||
|
#define WEBSOCKET_HTTP_CLIENT_OUTPUTBUFSIZE 300
|
||||||
|
#endif /* WEBSOCKET_HTTP_CLIENT_CONF_OUTPUTBUFSIZE */
|
||||||
|
|
||||||
|
#ifdef WEBSOCKET_HTTP_CLIENT_CONF_MAX_HOSTLEN
|
||||||
|
#define WEBSOCKET_HTTP_CLIENT_MAX_HOSTLEN WEBSOCKET_HTTP_CLIENT_CONF_MAX_HOSTLEN
|
||||||
|
#else /* WEBSOCKET_HTTP_CLIENT_CONF_MAX_HOSTLEN */
|
||||||
|
#define WEBSOCKET_HTTP_CLIENT_MAX_HOSTLEN 32
|
||||||
|
#endif /* WEBSOCKET_HTTP_CLIENT_CONF_MAX_HOSTLEN */
|
||||||
|
|
||||||
|
#ifdef WEBSOCKET_HTTP_CLIENT_CONF_MAX_FILELEN
|
||||||
|
#define WEBSOCKET_HTTP_CLIENT_MAX_FILELEN WEBSOCKET_HTTP_CLIENT_CONF_MAX_FILELEN
|
||||||
|
#else /* WEBSOCKET_HTTP_CLIENT_CONF_MAX_FILELEN */
|
||||||
|
#define WEBSOCKET_HTTP_CLIENT_MAX_FILELEN 32
|
||||||
|
#endif /* WEBSOCKET_HTTP_CLIENT_CONF_MAX_FILELEN */
|
||||||
|
|
||||||
|
#ifdef WEBSOCKET_HTTP_CLIENT_CONF_MAX_SUBPROTOCOLLEN
|
||||||
|
#define WEBSOCKET_HTTP_CLIENT_MAX_SUBPROTOCOLLEN WEBSOCKET_HTTP_CLIENT_CONF_MAX_SUBPROTOCOLLEN
|
||||||
|
#else /* WEBSOCKET_HTTP_CLIENT_CONF_MAX_SUBPROTOCOLLEN */
|
||||||
|
#define WEBSOCKET_HTTP_CLIENT_MAX_SUBPROTOCOLLEN 24
|
||||||
|
#endif /* WEBSOCKET_HTTP_CLIENT_CONF_MAX_SUBPROTOCOLLEN */
|
||||||
|
|
||||||
|
#ifdef WEBSOCKET_HTTP_CLIENT_CONF_MAX_HEADERLEN
|
||||||
|
#define WEBSOCKET_HTTP_CLIENT_MAX_HEADERLEN WEBSOCKET_HTTP_CLIENT_CONF_MAX_HEADERLEN
|
||||||
|
#else /* WEBSOCKET_HTTP_CLIENT_CONF_MAX_HEADERLEN */
|
||||||
|
#define WEBSOCKET_HTTP_CLIENT_MAX_HEADERLEN 128
|
||||||
|
#endif /* WEBSOCKET_HTTP_CLIENT_CONF_MAX_HEADERLEN */
|
||||||
|
|
||||||
|
struct websocket_http_client_state {
|
||||||
|
struct tcp_socket s;
|
||||||
|
uint8_t inputbuf[WEBSOCKET_HTTP_CLIENT_INPUTBUFSIZE];
|
||||||
|
uint8_t outputbuf[WEBSOCKET_HTTP_CLIENT_OUTPUTBUFSIZE];
|
||||||
|
char host[WEBSOCKET_HTTP_CLIENT_MAX_HOSTLEN];
|
||||||
|
char file[WEBSOCKET_HTTP_CLIENT_MAX_FILELEN];
|
||||||
|
char subprotocol[WEBSOCKET_HTTP_CLIENT_MAX_SUBPROTOCOLLEN];
|
||||||
|
char header[WEBSOCKET_HTTP_CLIENT_MAX_HEADERLEN];
|
||||||
|
uint16_t port;
|
||||||
|
|
||||||
|
int state;
|
||||||
|
struct pt parse_header_pt;
|
||||||
|
int http_status;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
uip_ipaddr_t proxy_addr;
|
||||||
|
uint16_t proxy_port;
|
||||||
|
};
|
||||||
|
|
||||||
|
void websocket_http_client_init(struct websocket_http_client_state *s);
|
||||||
|
void websocket_http_client_set_proxy(struct websocket_http_client_state *s,
|
||||||
|
const uip_ipaddr_t *addr, uint16_t port);
|
||||||
|
|
||||||
|
int websocket_http_client_register(struct websocket_http_client_state *s,
|
||||||
|
const char *host,
|
||||||
|
uint16_t port,
|
||||||
|
const char *file,
|
||||||
|
const char *subprotocol,
|
||||||
|
const char *hdr);
|
||||||
|
int websocket_http_client_get(struct websocket_http_client_state *s);
|
||||||
|
int websocket_http_client_send(struct websocket_http_client_state *s,
|
||||||
|
const uint8_t *data,
|
||||||
|
uint16_t datalen);
|
||||||
|
int websocket_http_client_sendbuflen(struct websocket_http_client_state *s);
|
||||||
|
|
||||||
|
void websocket_http_client_close(struct websocket_http_client_state *s);
|
||||||
|
|
||||||
|
const char *websocket_http_client_hostname(struct websocket_http_client_state *s);
|
||||||
|
|
||||||
|
int websocket_http_client_queuelen(struct websocket_http_client_state *s);
|
||||||
|
|
||||||
|
/* Callback functions that have to be implemented by the application
|
||||||
|
program. */
|
||||||
|
void websocket_http_client_datahandler(struct websocket_http_client_state *s,
|
||||||
|
const uint8_t *data, uint16_t len);
|
||||||
|
void websocket_http_client_connected(struct websocket_http_client_state *s);
|
||||||
|
void websocket_http_client_timedout(struct websocket_http_client_state *s);
|
||||||
|
void websocket_http_client_aborted(struct websocket_http_client_state *s);
|
||||||
|
void websocket_http_client_closed(struct websocket_http_client_state *s);
|
||||||
|
|
||||||
|
#endif /* WEBSOCKET_HTTP_CLIENT_H_ */
|
724
core/net/ipv6/websocket.c
Normal file
724
core/net/ipv6/websocket.c
Normal file
|
@ -0,0 +1,724 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012, Thingsquare, http://www.thingsquare.com/.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the copyright holder nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||||
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "contiki-net.h"
|
||||||
|
#include "lib/petsciiconv.h"
|
||||||
|
|
||||||
|
#include "websocket.h"
|
||||||
|
|
||||||
|
PROCESS(websocket_process, "Websockets process");
|
||||||
|
|
||||||
|
#define MAX_HOSTLEN 64
|
||||||
|
#define MAX_PATHLEN 100
|
||||||
|
|
||||||
|
LIST(websocketlist);
|
||||||
|
|
||||||
|
#define WEBSOCKET_FIN_BIT 0x80
|
||||||
|
|
||||||
|
#define WEBSOCKET_OPCODE_MASK 0x0f
|
||||||
|
#define WEBSOCKET_OPCODE_CONT 0x00
|
||||||
|
#define WEBSOCKET_OPCODE_TEXT 0x01
|
||||||
|
#define WEBSOCKET_OPCODE_BIN 0x02
|
||||||
|
#define WEBSOCKET_OPCODE_CLOSE 0x08
|
||||||
|
#define WEBSOCKET_OPCODE_PING 0x09
|
||||||
|
#define WEBSOCKET_OPCODE_PONG 0x0a
|
||||||
|
|
||||||
|
#define WEBSOCKET_MASK_BIT 0x80
|
||||||
|
#define WEBSOCKET_LEN_MASK 0x7f
|
||||||
|
struct websocket_frame_hdr {
|
||||||
|
uint8_t opcode;
|
||||||
|
uint8_t len;
|
||||||
|
uint8_t extlen[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct websocket_frame_mask {
|
||||||
|
uint8_t mask[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DEBUG DEBUG_NONE
|
||||||
|
#include "net/ip/uip-debug.h"
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static int
|
||||||
|
parse_url(const char *url, char *host, uint16_t *portptr, char *path)
|
||||||
|
{
|
||||||
|
const char *urlptr;
|
||||||
|
int i;
|
||||||
|
const char *file;
|
||||||
|
uint16_t port;
|
||||||
|
|
||||||
|
if(url == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Don't even try to go further if the URL is empty. */
|
||||||
|
if(strlen(url) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See if the URL starts with http:// or ws:// and remove it. */
|
||||||
|
if(strncmp(url, "http://", strlen("http://")) == 0) {
|
||||||
|
urlptr = url + strlen("http://");
|
||||||
|
} else if(strncmp(url, "ws://", strlen("ws://")) == 0) {
|
||||||
|
urlptr = url + strlen("ws://");
|
||||||
|
} else {
|
||||||
|
urlptr = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find host part of the URL. */
|
||||||
|
for(i = 0; i < MAX_HOSTLEN; ++i) {
|
||||||
|
if(*urlptr == 0 ||
|
||||||
|
*urlptr == '/' ||
|
||||||
|
*urlptr == ' ' ||
|
||||||
|
*urlptr == ':') {
|
||||||
|
if(host != NULL) {
|
||||||
|
host[i] = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(host != NULL) {
|
||||||
|
host[i] = *urlptr;
|
||||||
|
}
|
||||||
|
++urlptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the port. Default is 0, which lets the underlying transport
|
||||||
|
select its default port. */
|
||||||
|
port = 0;
|
||||||
|
if(*urlptr == ':') {
|
||||||
|
port = 0;
|
||||||
|
do {
|
||||||
|
++urlptr;
|
||||||
|
if(*urlptr >= '0' && *urlptr <= '9') {
|
||||||
|
port = (10 * port) + (*urlptr - '0');
|
||||||
|
}
|
||||||
|
} while(*urlptr >= '0' &&
|
||||||
|
*urlptr <= '9');
|
||||||
|
}
|
||||||
|
if(portptr != NULL) {
|
||||||
|
*portptr = port;
|
||||||
|
}
|
||||||
|
/* Find file part of the URL. */
|
||||||
|
while(*urlptr != '/' && *urlptr != 0) {
|
||||||
|
++urlptr;
|
||||||
|
}
|
||||||
|
if(*urlptr == '/') {
|
||||||
|
file = urlptr;
|
||||||
|
} else {
|
||||||
|
file = "/";
|
||||||
|
}
|
||||||
|
if(path != NULL) {
|
||||||
|
strncpy(path, file, MAX_PATHLEN);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static int
|
||||||
|
start_get(struct websocket *s)
|
||||||
|
{
|
||||||
|
if(websocket_http_client_get(&(s->s)) == 0) {
|
||||||
|
PRINTF("Out of memory error\n");
|
||||||
|
s->state = WEBSOCKET_STATE_CLOSED;
|
||||||
|
return WEBSOCKET_ERR;
|
||||||
|
} else {
|
||||||
|
PRINTF("Connecting...\n");
|
||||||
|
s->state = WEBSOCKET_STATE_HTTP_REQUEST_SENT;
|
||||||
|
return WEBSOCKET_OK;
|
||||||
|
}
|
||||||
|
return WEBSOCKET_ERR;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
call(struct websocket *s, websocket_result_t r,
|
||||||
|
const uint8_t *data, uint16_t datalen)
|
||||||
|
{
|
||||||
|
if(s != NULL && s->callback != NULL) {
|
||||||
|
s->callback(s, r, data, datalen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
PROCESS_THREAD(websocket_process, ev, data)
|
||||||
|
{
|
||||||
|
PROCESS_BEGIN();
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
|
||||||
|
PROCESS_WAIT_EVENT();
|
||||||
|
|
||||||
|
if(ev == resolv_event_found && data != NULL) {
|
||||||
|
int ret;
|
||||||
|
struct websocket *s;
|
||||||
|
const char *name = data;
|
||||||
|
/* Either found a hostname, or not. We need to go through the
|
||||||
|
list of websocketsand figure out to which connection this
|
||||||
|
reply corresponds, then either restart the HTTP get, or kill
|
||||||
|
it (if no hostname was found). */
|
||||||
|
for(s = list_head(websocketlist);
|
||||||
|
s != NULL;
|
||||||
|
s = list_item_next(s)) {
|
||||||
|
if(strcmp(name, websocket_http_client_hostname(&s->s)) == 0) {
|
||||||
|
ret = resolv_lookup(name, NULL);
|
||||||
|
if(ret == RESOLV_STATUS_CACHED) {
|
||||||
|
/* Hostname found, restart get. */
|
||||||
|
if(s->state == WEBSOCKET_STATE_DNS_REQUEST_SENT) {
|
||||||
|
PRINTF("Restarting get\n");
|
||||||
|
start_get(s);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(s->state == WEBSOCKET_STATE_DNS_REQUEST_SENT) {
|
||||||
|
/* Hostname not found, kill connection. */
|
||||||
|
/* PRINTF("XXX killing connection\n");*/
|
||||||
|
call(s, WEBSOCKET_HOSTNAME_NOT_FOUND, NULL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PROCESS_END();
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Callback function. Called from the webclient when the HTTP
|
||||||
|
* connection was abruptly aborted.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
websocket_http_client_aborted(struct websocket_http_client_state *client_state)
|
||||||
|
{
|
||||||
|
if(client_state != NULL) {
|
||||||
|
struct websocket *s = (struct websocket *)
|
||||||
|
((char *)client_state - offsetof(struct websocket, s));
|
||||||
|
PRINTF("Websocket reset\n");
|
||||||
|
s->state = WEBSOCKET_STATE_CLOSED;
|
||||||
|
call(s, WEBSOCKET_RESET, NULL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Callback function. Called from the webclient when the HTTP
|
||||||
|
* connection timed out.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
websocket_http_client_timedout(struct websocket_http_client_state *client_state)
|
||||||
|
{
|
||||||
|
if(client_state != NULL) {
|
||||||
|
struct websocket *s = (struct websocket *)
|
||||||
|
((char *)client_state - offsetof(struct websocket, s));
|
||||||
|
PRINTF("Websocket timed out\n");
|
||||||
|
s->state = WEBSOCKET_STATE_CLOSED;
|
||||||
|
call(s, WEBSOCKET_TIMEDOUT, NULL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Callback function. Called from the webclient when the HTTP
|
||||||
|
* connection was closed after a request from the "websocket_http_client_close()"
|
||||||
|
* function. .
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
websocket_http_client_closed(struct websocket_http_client_state *client_state)
|
||||||
|
{
|
||||||
|
if(client_state != NULL) {
|
||||||
|
struct websocket *s = (struct websocket *)
|
||||||
|
((char *)client_state - offsetof(struct websocket, s));
|
||||||
|
PRINTF("Websocket closed.\n");
|
||||||
|
s->state = WEBSOCKET_STATE_CLOSED;
|
||||||
|
call(s, WEBSOCKET_CLOSED, NULL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Callback function. Called from the webclient when the HTTP
|
||||||
|
* connection is connected.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
websocket_http_client_connected(struct websocket_http_client_state *client_state)
|
||||||
|
{
|
||||||
|
struct websocket *s = (struct websocket *)
|
||||||
|
((char *)client_state - offsetof(struct websocket, s));
|
||||||
|
|
||||||
|
PRINTF("Websocket connected\n");
|
||||||
|
s->state = WEBSOCKET_STATE_WAITING_FOR_HEADER;
|
||||||
|
call(s, WEBSOCKET_CONNECTED, NULL, 0);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* The websocket header may potentially be split into multiple TCP
|
||||||
|
segments. This function eats one byte each, puts it into
|
||||||
|
s->headercache, and checks whether or not the full header has been
|
||||||
|
received. */
|
||||||
|
static int
|
||||||
|
receive_header_byte(struct websocket *s, uint8_t byte)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
int expected_len;
|
||||||
|
struct websocket_frame_hdr *hdr;
|
||||||
|
|
||||||
|
/* Take the next byte of data and place it in the header cache. */
|
||||||
|
if(s->state == WEBSOCKET_STATE_RECEIVING_HEADER) {
|
||||||
|
s->headercache[s->headercacheptr] = byte;
|
||||||
|
s->headercacheptr++;
|
||||||
|
if(s->headercacheptr >= sizeof(s->headercache)) {
|
||||||
|
/* Something bad happened: we ad read 10 bytes and had not yet
|
||||||
|
found a reasonable header, so we close the socket. */
|
||||||
|
websocket_close(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
len = s->headercacheptr;
|
||||||
|
hdr = (struct websocket_frame_hdr *)s->headercache;
|
||||||
|
|
||||||
|
/* Check the header that we have received to see if it is long
|
||||||
|
enough. */
|
||||||
|
|
||||||
|
/* We start with expecting a length of at least two bytes (opcode +
|
||||||
|
1 length byte). */
|
||||||
|
expected_len = 2;
|
||||||
|
|
||||||
|
if(len >= expected_len) {
|
||||||
|
|
||||||
|
/* We check how many more bytes we should expect to see. The
|
||||||
|
length byte determines how many length bytes are included in
|
||||||
|
the header. */
|
||||||
|
if((hdr->len & WEBSOCKET_LEN_MASK) == 126) {
|
||||||
|
expected_len += 2;
|
||||||
|
} else if((hdr->len & WEBSOCKET_LEN_MASK) == 127) {
|
||||||
|
expected_len += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the option has the mask bit set, we should expect to see 4
|
||||||
|
mask bytes at the end of the header. */
|
||||||
|
if((hdr->len & WEBSOCKET_MASK_BIT ) != 0) {
|
||||||
|
expected_len += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now we know how long our header if expected to be. If it is
|
||||||
|
this long, we are done and we set the state to reflect this. */
|
||||||
|
if(len == expected_len) {
|
||||||
|
s->state = WEBSOCKET_STATE_HEADER_RECEIVED;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Callback function. Called from the webclient module when HTTP data
|
||||||
|
* has arrived.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
websocket_http_client_datahandler(struct websocket_http_client_state *client_state,
|
||||||
|
const uint8_t *data, uint16_t datalen)
|
||||||
|
{
|
||||||
|
struct websocket *s = (struct websocket *)
|
||||||
|
((char *)client_state - offsetof(struct websocket, s));
|
||||||
|
struct websocket_frame_hdr *hdr;
|
||||||
|
struct websocket_frame_mask *maskptr;
|
||||||
|
|
||||||
|
if(data == NULL) {
|
||||||
|
call(s, WEBSOCKET_CLOSED, NULL, 0);
|
||||||
|
} else {
|
||||||
|
/* This function is a state machine that does different things
|
||||||
|
depending on the state. If we are waiting for header (the
|
||||||
|
default state), we change to the RECEIVING_HEADER state when we
|
||||||
|
get the first byte. If we are receiving header, we put all
|
||||||
|
bytes we have into a header buffer until the full header has
|
||||||
|
been received. If we have received the header, we parse it. If
|
||||||
|
we have received and parsed the header, we are ready to receive
|
||||||
|
data. Finally, if there is data left in the incoming packet, we
|
||||||
|
repeat the process. */
|
||||||
|
|
||||||
|
if(s->state == WEBSOCKET_STATE_WAITING_FOR_HEADER) {
|
||||||
|
s->state = WEBSOCKET_STATE_RECEIVING_HEADER;
|
||||||
|
s->headercacheptr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(s->state == WEBSOCKET_STATE_RECEIVING_HEADER) {
|
||||||
|
while(datalen > 0 && s->state == WEBSOCKET_STATE_RECEIVING_HEADER) {
|
||||||
|
receive_header_byte(s, data[0]);
|
||||||
|
data++;
|
||||||
|
datalen--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(s->state == WEBSOCKET_STATE_HEADER_RECEIVED) {
|
||||||
|
/* If this is the start of an incoming websocket data frame, we
|
||||||
|
decode the header and check if we should act on in. If not, we
|
||||||
|
pipe the data to the application through a callback handler. If
|
||||||
|
data arrives in multiple packets, it is up to the application to
|
||||||
|
put it back together again. */
|
||||||
|
|
||||||
|
/* The websocket header is at the start of the incoming data. */
|
||||||
|
hdr = (struct websocket_frame_hdr *)s->headercache;
|
||||||
|
|
||||||
|
/* The s->left field holds the length of the application data
|
||||||
|
* chunk that we are about to receive. */
|
||||||
|
s->len = s->left = 0;
|
||||||
|
|
||||||
|
/* The s->mask field holds the bitmask of the data chunk, if
|
||||||
|
* any. */
|
||||||
|
memset(s->mask, 0, sizeof(s->mask));
|
||||||
|
|
||||||
|
/* We first read out the length of the application data
|
||||||
|
chunk. The length may be encoded over multiple bytes. If the
|
||||||
|
length is >= 126 bytes, it is encoded as two or more
|
||||||
|
bytes. The first length field determines if it is in 2 or 4
|
||||||
|
bytes. We also keep track of where the bitmask is held - its
|
||||||
|
place also differs depending on how the length is encoded. */
|
||||||
|
maskptr = (struct websocket_frame_mask *)hdr->extlen;
|
||||||
|
if((hdr->len & WEBSOCKET_LEN_MASK) < 126) {
|
||||||
|
s->len = s->left = hdr->len & WEBSOCKET_LEN_MASK;
|
||||||
|
} else if(hdr->len == 126) {
|
||||||
|
s->len = s->left = (hdr->extlen[0] << 8) + hdr->extlen[1];
|
||||||
|
maskptr = (struct websocket_frame_mask *)&hdr->extlen[2];
|
||||||
|
} else if(hdr->len == 127) {
|
||||||
|
s->len = s->left = ((uint32_t)hdr->extlen[0] << 24) +
|
||||||
|
((uint32_t)hdr->extlen[1] << 16) +
|
||||||
|
((uint32_t)hdr->extlen[2] << 8) +
|
||||||
|
hdr->extlen[3];
|
||||||
|
maskptr = (struct websocket_frame_mask *)&hdr->extlen[4];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set user_data to point to the first byte of application data.
|
||||||
|
See if the application data chunk is masked or not. If it is,
|
||||||
|
we copy the bitmask into the s->mask field. */
|
||||||
|
if((hdr->len & WEBSOCKET_MASK_BIT) == 0) {
|
||||||
|
/* PRINTF("No mask\n");*/
|
||||||
|
} else {
|
||||||
|
memcpy(s->mask, &maskptr->mask, sizeof(s->mask));
|
||||||
|
/* PRINTF("There was a mask, %02x %02x %02x %02x\n",
|
||||||
|
s->mask[0], s->mask[1], s->mask[2], s->mask[3]);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remember the opcode of the application chunk, put it in the
|
||||||
|
* s->opcode field. */
|
||||||
|
s->opcode = hdr->opcode & WEBSOCKET_OPCODE_MASK;
|
||||||
|
|
||||||
|
if(s->opcode == WEBSOCKET_OPCODE_PING) {
|
||||||
|
/* If the opcode is ping, we change the opcode to a pong, and
|
||||||
|
* send the data back. */
|
||||||
|
hdr->opcode = (hdr->opcode & (~WEBSOCKET_OPCODE_MASK)) |
|
||||||
|
WEBSOCKET_OPCODE_PONG;
|
||||||
|
websocket_http_client_send(&s->s, (const uint8_t*)hdr, 2);
|
||||||
|
if(s->left > 0) {
|
||||||
|
websocket_http_client_send(&s->s, (const uint8_t*)data, s->left);
|
||||||
|
}
|
||||||
|
PRINTF("Got ping\n");
|
||||||
|
call(s, WEBSOCKET_PINGED, NULL, 0);
|
||||||
|
s->state = WEBSOCKET_STATE_WAITING_FOR_HEADER;
|
||||||
|
} else if(s->opcode == WEBSOCKET_OPCODE_PONG) {
|
||||||
|
/* If the opcode is pong, we call the application to let it
|
||||||
|
know we got a pong. */
|
||||||
|
PRINTF("Got pong\n");
|
||||||
|
call(s, WEBSOCKET_PONG_RECEIVED, NULL, 0);
|
||||||
|
s->state = WEBSOCKET_STATE_WAITING_FOR_HEADER;
|
||||||
|
} else if(s->opcode == WEBSOCKET_OPCODE_CLOSE) {
|
||||||
|
/* If the opcode is a close, we send a close frame back. */
|
||||||
|
hdr->opcode = (hdr->opcode & (~WEBSOCKET_OPCODE_MASK)) |
|
||||||
|
WEBSOCKET_OPCODE_CLOSE;
|
||||||
|
websocket_http_client_send(&s->s, (const uint8_t*)hdr, 2);
|
||||||
|
if(s->left > 0) {
|
||||||
|
websocket_http_client_send(&s->s, (const uint8_t*)data, s->left);
|
||||||
|
}
|
||||||
|
PRINTF("websocket: got close, sending close\n");
|
||||||
|
s->state = WEBSOCKET_STATE_WAITING_FOR_HEADER;
|
||||||
|
websocket_http_client_close(&s->s);
|
||||||
|
} else if(s->opcode == WEBSOCKET_OPCODE_BIN ||
|
||||||
|
s->opcode == WEBSOCKET_OPCODE_TEXT) {
|
||||||
|
|
||||||
|
/* If the opcode is bin or text, and there is application
|
||||||
|
* layer data in the packet, we call the application to
|
||||||
|
* process it. */
|
||||||
|
if(s->left > 0) {
|
||||||
|
s->state = WEBSOCKET_STATE_RECEIVING_DATA;
|
||||||
|
if(datalen > 0) {
|
||||||
|
int len;
|
||||||
|
|
||||||
|
len = MIN(s->left, datalen);
|
||||||
|
/* XXX todo: mask if needed. */
|
||||||
|
call(s, WEBSOCKET_DATA, data, len);
|
||||||
|
data += len;
|
||||||
|
s->left -= len;
|
||||||
|
datalen -= len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(s->left == 0) {
|
||||||
|
call(s, WEBSOCKET_DATA_RECEIVED, NULL, s->len);
|
||||||
|
s->state = WEBSOCKET_STATE_WAITING_FOR_HEADER;
|
||||||
|
|
||||||
|
/* Need to keep parsing the incoming data to check for more
|
||||||
|
frames, if the incoming datalen is > than s->left. */
|
||||||
|
if(datalen > 0) {
|
||||||
|
PRINTF("XXX 1 again\n");
|
||||||
|
websocket_http_client_datahandler(client_state,
|
||||||
|
data, datalen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(s->state == WEBSOCKET_STATE_RECEIVING_DATA) {
|
||||||
|
/* XXX todo: mask if needed. */
|
||||||
|
/* PRINTF("Calling with s->left %d datalen %d\n",
|
||||||
|
s->left, datalen);*/
|
||||||
|
if(datalen > 0) {
|
||||||
|
if(datalen < s->left) {
|
||||||
|
call(s, WEBSOCKET_DATA, data, datalen);
|
||||||
|
s->left -= datalen;
|
||||||
|
data += datalen;
|
||||||
|
datalen = 0;
|
||||||
|
} else {
|
||||||
|
call(s, WEBSOCKET_DATA, data, s->left);
|
||||||
|
data += s->left;
|
||||||
|
datalen -= s->left;
|
||||||
|
s->left = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(s->left == 0) {
|
||||||
|
call(s, WEBSOCKET_DATA_RECEIVED, NULL, s->len);
|
||||||
|
s->state = WEBSOCKET_STATE_WAITING_FOR_HEADER;
|
||||||
|
/* Need to keep parsing the incoming data to check for more
|
||||||
|
frames, if the incoming datalen is > than len. */
|
||||||
|
if(datalen > 0) {
|
||||||
|
PRINTF("XXX 2 again (datalen %d s->left %d)\n", datalen, (int)s->left);
|
||||||
|
websocket_http_client_datahandler(client_state,
|
||||||
|
data, datalen);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
init(void)
|
||||||
|
{
|
||||||
|
static uint8_t inited = 0;
|
||||||
|
if(!inited) {
|
||||||
|
process_start(&websocket_process, NULL);
|
||||||
|
list_init(websocketlist);
|
||||||
|
inited = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
websocket_init(struct websocket *s)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
websocket_http_client_init(&s->s);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
websocket_set_proxy(struct websocket *s,
|
||||||
|
const uip_ipaddr_t *addr, uint16_t port)
|
||||||
|
{
|
||||||
|
websocket_http_client_set_proxy(&s->s, addr, port);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
websocket_result_t
|
||||||
|
websocket_open(struct websocket *s, const char *url,
|
||||||
|
const char *subprotocol, const char *hdr,
|
||||||
|
websocket_callback c)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
char host[MAX_HOSTLEN + 1] = {0};
|
||||||
|
char path[MAX_PATHLEN + 1] = {0};
|
||||||
|
uint16_t port;
|
||||||
|
uip_ipaddr_t addr;
|
||||||
|
|
||||||
|
init();
|
||||||
|
|
||||||
|
if(s == NULL) {
|
||||||
|
return WEBSOCKET_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(s->state != WEBSOCKET_STATE_CLOSED) {
|
||||||
|
PRINTF("websocket_open: closing websocket before opening it again.\n");
|
||||||
|
websocket_close(s);
|
||||||
|
}
|
||||||
|
s->callback = c;
|
||||||
|
|
||||||
|
if(parse_url(url, host, &port, path)) {
|
||||||
|
list_add(websocketlist, s);
|
||||||
|
websocket_http_client_register(&s->s, host, port, path, subprotocol, hdr);
|
||||||
|
|
||||||
|
/* First check if the host is an IP address. */
|
||||||
|
if(uiplib_ip4addrconv(host, (uip_ip4addr_t *)&addr) == 0 &&
|
||||||
|
uiplib_ip6addrconv(host, (uip_ip6addr_t *)&addr) == 0) {
|
||||||
|
/* Try to lookup the hostname. If it fails, we initiate a hostname
|
||||||
|
lookup and print out an informative message on the
|
||||||
|
statusbar. */
|
||||||
|
ret = resolv_lookup(host, NULL);
|
||||||
|
if(ret != RESOLV_STATUS_CACHED) {
|
||||||
|
resolv_query(host);
|
||||||
|
s->state = WEBSOCKET_STATE_DNS_REQUEST_SENT;
|
||||||
|
PRINTF("Resolving host...\n");
|
||||||
|
return WEBSOCKET_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PROCESS_CONTEXT_BEGIN(&websocket_process);
|
||||||
|
ret = start_get(s);
|
||||||
|
PROCESS_CONTEXT_END();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
websocket_close(struct websocket *s)
|
||||||
|
{
|
||||||
|
websocket_http_client_close(&s->s);
|
||||||
|
s->state = WEBSOCKET_STATE_CLOSED;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static int
|
||||||
|
send_data(struct websocket *s, const void *data,
|
||||||
|
uint16_t datalen, uint8_t data_type_opcode)
|
||||||
|
{
|
||||||
|
uint8_t buf[WEBSOCKET_MAX_MSGLEN + 4 + 4]; /* The extra + 4 + 4 here
|
||||||
|
comes from the size of
|
||||||
|
the websocket framing
|
||||||
|
header. */
|
||||||
|
struct websocket_frame_hdr *hdr;
|
||||||
|
struct websocket_frame_mask *mask;
|
||||||
|
|
||||||
|
PRINTF("websocket send data len %d %.*s\n", datalen, datalen, (char *)data);
|
||||||
|
if(s->state == WEBSOCKET_STATE_CLOSED ||
|
||||||
|
s->state == WEBSOCKET_STATE_DNS_REQUEST_SENT ||
|
||||||
|
s->state == WEBSOCKET_STATE_HTTP_REQUEST_SENT) {
|
||||||
|
/* Trying to send data on a non-connected websocket. */
|
||||||
|
PRINTF("websocket send fail: not connected\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We need to have 4 + 4 additional bytes for the websocket framing
|
||||||
|
header. */
|
||||||
|
if(4 + 4 + datalen > websocket_http_client_sendbuflen(&s->s)) {
|
||||||
|
PRINTF("websocket: too few bytes left (%d left, %d needed)\n",
|
||||||
|
websocket_http_client_sendbuflen(&s->s),
|
||||||
|
4 + 4 + datalen);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(datalen > sizeof(buf) - 4 - 4) {
|
||||||
|
PRINTF("websocket: trying to send too large data chunk %d > %d\n",
|
||||||
|
datalen, sizeof(buf) - 4 - 4);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
hdr = (struct websocket_frame_hdr *)&buf[0];
|
||||||
|
hdr->opcode = WEBSOCKET_FIN_BIT | data_type_opcode;
|
||||||
|
|
||||||
|
/* If the datalen is larger than 125 bytes, we need to send the data
|
||||||
|
length as two bytes. If the data length would be larger than 64k,
|
||||||
|
we should send the length as 4 bytes, but since we specify the
|
||||||
|
datalen as an unsigned 16-bit int, we do not handle the 64k case
|
||||||
|
here. */
|
||||||
|
if(datalen > 125) {
|
||||||
|
/* Data from client must always have the mask bit set, and a data
|
||||||
|
mask sent right after the header. */
|
||||||
|
hdr->len = 126 | WEBSOCKET_MASK_BIT;
|
||||||
|
hdr->extlen[0] = datalen >> 8;
|
||||||
|
hdr->extlen[1] = datalen & 0xff;
|
||||||
|
|
||||||
|
mask = (struct websocket_frame_mask *)&buf[4];
|
||||||
|
mask->mask[0] =
|
||||||
|
mask->mask[1] =
|
||||||
|
mask->mask[2] =
|
||||||
|
mask->mask[3] = 0;
|
||||||
|
memcpy(&buf[8], data, datalen);
|
||||||
|
return websocket_http_client_send(&s->s, buf, 8 + datalen);
|
||||||
|
} else {
|
||||||
|
/* Data from client must always have the mask bit set, and a data
|
||||||
|
mask sent right after the header. */
|
||||||
|
hdr->len = datalen | WEBSOCKET_MASK_BIT;
|
||||||
|
|
||||||
|
mask = (struct websocket_frame_mask *)&buf[2];
|
||||||
|
mask->mask[0] =
|
||||||
|
mask->mask[1] =
|
||||||
|
mask->mask[2] =
|
||||||
|
mask->mask[3] = 0;
|
||||||
|
memcpy(&buf[6], data, datalen);
|
||||||
|
return websocket_http_client_send(&s->s, buf, 6 + datalen);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
websocket_send_str(struct websocket *s, const char *str)
|
||||||
|
{
|
||||||
|
return send_data(s, str, strlen(str), WEBSOCKET_OPCODE_TEXT);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
websocket_send(struct websocket *s, const uint8_t *data,
|
||||||
|
uint16_t datalen)
|
||||||
|
{
|
||||||
|
return send_data(s, data, datalen, WEBSOCKET_OPCODE_BIN);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
websocket_ping(struct websocket *s)
|
||||||
|
{
|
||||||
|
uint8_t buf[sizeof(struct websocket_frame_hdr) +
|
||||||
|
sizeof(struct websocket_frame_mask)];
|
||||||
|
struct websocket_frame_hdr *hdr;
|
||||||
|
struct websocket_frame_mask *mask;
|
||||||
|
|
||||||
|
/* We need 2 + 4 additional bytes for the websocket framing
|
||||||
|
header. */
|
||||||
|
if(2 + 4 > websocket_http_client_sendbuflen(&s->s)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
hdr = (struct websocket_frame_hdr *)&buf[0];
|
||||||
|
mask = (struct websocket_frame_mask *)&buf[2];
|
||||||
|
hdr->opcode = WEBSOCKET_FIN_BIT | WEBSOCKET_OPCODE_PING;
|
||||||
|
|
||||||
|
/* Data from client must always have the mask bit set, and a data
|
||||||
|
mask sent right after the header. */
|
||||||
|
hdr->len = 0 | WEBSOCKET_MASK_BIT;
|
||||||
|
|
||||||
|
/* XXX: We just set a dummy mask of 0 for now and hope that this
|
||||||
|
works. */
|
||||||
|
mask->mask[0] =
|
||||||
|
mask->mask[1] =
|
||||||
|
mask->mask[2] =
|
||||||
|
mask->mask[3] = 0;
|
||||||
|
websocket_http_client_send(&s->s, buf, 2 + 4);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
websocket_queuelen(struct websocket *s)
|
||||||
|
{
|
||||||
|
return websocket_http_client_queuelen(&s->s);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
113
core/net/ipv6/websocket.h
Normal file
113
core/net/ipv6/websocket.h
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012, Thingsquare, http://www.thingsquare.com/.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the copyright holder nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||||
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef WEBSOCKET_H
|
||||||
|
#define WEBSOCKET_H
|
||||||
|
|
||||||
|
#include "websocket-http-client.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
WEBSOCKET_ERR = 0,
|
||||||
|
WEBSOCKET_OK = 1,
|
||||||
|
WEBSOCKET_IN_PROGRESS = 2,
|
||||||
|
WEBSOCKET_HOSTNAME_NOT_FOUND = 3,
|
||||||
|
WEBSOCKET_CONNECTED = 4,
|
||||||
|
WEBSOCKET_DATA = 5,
|
||||||
|
WEBSOCKET_RESET = 6,
|
||||||
|
WEBSOCKET_TIMEDOUT = 7,
|
||||||
|
WEBSOCKET_CLOSED = 8,
|
||||||
|
WEBSOCKET_PINGED = 9,
|
||||||
|
WEBSOCKET_DATA_RECEIVED = 10,
|
||||||
|
WEBSOCKET_PONG_RECEIVED = 11,
|
||||||
|
} websocket_result_t;
|
||||||
|
|
||||||
|
struct websocket;
|
||||||
|
|
||||||
|
typedef void (* websocket_callback)(struct websocket *s,
|
||||||
|
websocket_result_t result,
|
||||||
|
const uint8_t *data,
|
||||||
|
uint16_t datalen);
|
||||||
|
#ifdef WEBSOCKET_CONF_MAX_MSGLEN
|
||||||
|
#define WEBSOCKET_MAX_MSGLEN WEBSOCKET_CONF_MAX_MSGLEN
|
||||||
|
#else /* WEBSOCKET_CONF_MAX_MSGLEN */
|
||||||
|
#define WEBSOCKET_MAX_MSGLEN 200
|
||||||
|
#endif /* WEBSOCKET_CONF_MAX_MSGLEN */
|
||||||
|
|
||||||
|
struct websocket {
|
||||||
|
struct websocket *next; /* Must be first. */
|
||||||
|
struct websocket_http_client_state s;
|
||||||
|
websocket_callback callback;
|
||||||
|
|
||||||
|
uint8_t mask[4];
|
||||||
|
uint32_t left, len;
|
||||||
|
uint8_t opcode;
|
||||||
|
|
||||||
|
uint8_t state;
|
||||||
|
|
||||||
|
uint8_t headercacheptr;
|
||||||
|
uint8_t headercache[10]; /* The maximum websocket header + mask is 6
|
||||||
|
+ 4 bytes long */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
WEBSOCKET_STATE_CLOSED = 0,
|
||||||
|
WEBSOCKET_STATE_DNS_REQUEST_SENT = 1,
|
||||||
|
WEBSOCKET_STATE_HTTP_REQUEST_SENT = 2,
|
||||||
|
WEBSOCKET_STATE_WAITING_FOR_HEADER = 3,
|
||||||
|
WEBSOCKET_STATE_RECEIVING_HEADER = 4,
|
||||||
|
WEBSOCKET_STATE_HEADER_RECEIVED = 5,
|
||||||
|
WEBSOCKET_STATE_RECEIVING_DATA = 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void websocket_init(struct websocket *s);
|
||||||
|
|
||||||
|
void websocket_set_proxy(struct websocket *s,
|
||||||
|
const uip_ipaddr_t *addr, uint16_t port);
|
||||||
|
|
||||||
|
websocket_result_t websocket_open(struct websocket *s,
|
||||||
|
const char *url,
|
||||||
|
const char *subprotocol,
|
||||||
|
const char *hdr,
|
||||||
|
websocket_callback c);
|
||||||
|
|
||||||
|
int websocket_send(struct websocket *s,
|
||||||
|
const uint8_t *data, uint16_t datalen);
|
||||||
|
|
||||||
|
int websocket_send_str(struct websocket *s,
|
||||||
|
const char *strptr);
|
||||||
|
|
||||||
|
void websocket_close(struct websocket *s);
|
||||||
|
|
||||||
|
int websocket_ping(struct websocket *s);
|
||||||
|
|
||||||
|
int websocket_queuelen(struct websocket *s);
|
||||||
|
|
||||||
|
#endif /* WEBSOCKET_H */
|
|
@ -51,7 +51,7 @@
|
||||||
/* Maximum value for the freshness counter */
|
/* Maximum value for the freshness counter */
|
||||||
#define FRESHNESS_MAX 16
|
#define FRESHNESS_MAX 16
|
||||||
/* Statistics with no update in FRESHNESS_EXPIRATION_TIMEOUT is not fresh */
|
/* Statistics with no update in FRESHNESS_EXPIRATION_TIMEOUT is not fresh */
|
||||||
#define FRESHNESS_EXPIRATION_TIME (10 * 60 * CLOCK_SECOND)
|
#define FRESHNESS_EXPIRATION_TIME (10 * 60 * (clock_time_t)CLOCK_SECOND)
|
||||||
|
|
||||||
/* EWMA (exponential moving average) used to maintain statistics over time */
|
/* EWMA (exponential moving average) used to maintain statistics over time */
|
||||||
#define EWMA_SCALE 100
|
#define EWMA_SCALE 100
|
||||||
|
@ -206,6 +206,6 @@ void
|
||||||
link_stats_init(void)
|
link_stats_init(void)
|
||||||
{
|
{
|
||||||
nbr_table_register(link_stats, NULL);
|
nbr_table_register(link_stats, NULL);
|
||||||
ctimer_set(&periodic_timer, 60 * CLOCK_SECOND * FRESHNESS_HALF_LIFE,
|
ctimer_set(&periodic_timer, 60 * (clock_time_t)CLOCK_SECOND * FRESHNESS_HALF_LIFE,
|
||||||
periodic, NULL);
|
periodic, NULL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,9 @@ const linkaddr_t linkaddr_null = { { 0, 0 } };
|
||||||
#if LINKADDR_SIZE == 8
|
#if LINKADDR_SIZE == 8
|
||||||
const linkaddr_t linkaddr_null = { { 0, 0, 0, 0, 0, 0, 0, 0 } };
|
const linkaddr_t linkaddr_null = { { 0, 0, 0, 0, 0, 0, 0, 0 } };
|
||||||
#endif /*LINKADDR_SIZE == 8*/
|
#endif /*LINKADDR_SIZE == 8*/
|
||||||
|
#if LINKADDR_SIZE == 6
|
||||||
|
const linkaddr_t linkaddr_null = { { 0, 0, 0, 0, 0, 0 } };
|
||||||
|
#endif /*LINKADDR_SIZE == 6*/
|
||||||
#endif /*LINKADDR_SIZE == 2*/
|
#endif /*LINKADDR_SIZE == 2*/
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -207,13 +207,13 @@ static int we_are_receiving_burst = 0;
|
||||||
#define INTER_PACKET_INTERVAL RTIMER_ARCH_SECOND / 2500
|
#define INTER_PACKET_INTERVAL RTIMER_ARCH_SECOND / 2500
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* AFTER_ACK_DETECTECT_WAIT_TIME is the time to wait after a potential
|
/* AFTER_ACK_DETECTED_WAIT_TIME is the time to wait after a potential
|
||||||
ACK packet has been detected until we can read it out from the
|
ACK packet has been detected until we can read it out from the
|
||||||
radio. */
|
radio. */
|
||||||
#ifdef CONTIKIMAC_CONF_AFTER_ACK_DETECTECT_WAIT_TIME
|
#ifdef CONTIKIMAC_CONF_AFTER_ACK_DETECTED_WAIT_TIME
|
||||||
#define AFTER_ACK_DETECTECT_WAIT_TIME CONTIKIMAC_CONF_AFTER_ACK_DETECTECT_WAIT_TIME
|
#define AFTER_ACK_DETECTED_WAIT_TIME CONTIKIMAC_CONF_AFTER_ACK_DETECTED_WAIT_TIME
|
||||||
#else
|
#else
|
||||||
#define AFTER_ACK_DETECTECT_WAIT_TIME RTIMER_ARCH_SECOND / 1500
|
#define AFTER_ACK_DETECTED_WAIT_TIME RTIMER_ARCH_SECOND / 1500
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* MAX_PHASE_STROBE_TIME is the time that we transmit repeated packets
|
/* MAX_PHASE_STROBE_TIME is the time that we transmit repeated packets
|
||||||
|
@ -289,9 +289,15 @@ off(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
static volatile rtimer_clock_t cycle_start;
|
|
||||||
static void powercycle_wrapper(struct rtimer *t, void *ptr);
|
static void powercycle_wrapper(struct rtimer *t, void *ptr);
|
||||||
static char powercycle(struct rtimer *t, void *ptr);
|
static char powercycle(struct rtimer *t, void *ptr);
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static volatile rtimer_clock_t cycle_start;
|
||||||
|
#if SYNC_CYCLE_STARTS
|
||||||
|
static volatile rtimer_clock_t sync_cycle_start;
|
||||||
|
static volatile uint8_t sync_cycle_phase;
|
||||||
|
#endif
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
static void
|
static void
|
||||||
schedule_powercycle(struct rtimer *t, rtimer_clock_t time)
|
schedule_powercycle(struct rtimer *t, rtimer_clock_t time)
|
||||||
{
|
{
|
||||||
|
@ -367,13 +373,34 @@ powercycle_wrapper(struct rtimer *t, void *ptr)
|
||||||
powercycle(t, ptr);
|
powercycle(t, ptr);
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
advance_cycle_start(void)
|
||||||
|
{
|
||||||
|
#if SYNC_CYCLE_STARTS
|
||||||
|
|
||||||
|
/* Compute cycle start when RTIMER_ARCH_SECOND is not a multiple
|
||||||
|
of CHANNEL_CHECK_RATE */
|
||||||
|
if(sync_cycle_phase++ == NETSTACK_RDC_CHANNEL_CHECK_RATE) {
|
||||||
|
sync_cycle_phase = 0;
|
||||||
|
sync_cycle_start += RTIMER_ARCH_SECOND;
|
||||||
|
cycle_start = sync_cycle_start;
|
||||||
|
} else if( (RTIMER_ARCH_SECOND * NETSTACK_RDC_CHANNEL_CHECK_RATE) > 65535) {
|
||||||
|
uint32_t phase_time = sync_cycle_phase*RTIMER_ARCH_SECOND;
|
||||||
|
|
||||||
|
cycle_start = sync_cycle_start + phase_time/NETSTACK_RDC_CHANNEL_CHECK_RATE;
|
||||||
|
} else {
|
||||||
|
unsigned phase_time = sync_cycle_phase*RTIMER_ARCH_SECOND;
|
||||||
|
|
||||||
|
cycle_start = sync_cycle_start + phase_time/NETSTACK_RDC_CHANNEL_CHECK_RATE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
cycle_start += CYCLE_TIME;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
static char
|
static char
|
||||||
powercycle(struct rtimer *t, void *ptr)
|
powercycle(struct rtimer *t, void *ptr)
|
||||||
{
|
{
|
||||||
#if SYNC_CYCLE_STARTS
|
|
||||||
static volatile rtimer_clock_t sync_cycle_start;
|
|
||||||
static volatile uint8_t sync_cycle_phase;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PT_BEGIN(&pt);
|
PT_BEGIN(&pt);
|
||||||
|
|
||||||
|
@ -387,24 +414,6 @@ powercycle(struct rtimer *t, void *ptr)
|
||||||
static uint8_t packet_seen;
|
static uint8_t packet_seen;
|
||||||
static uint8_t count;
|
static uint8_t count;
|
||||||
|
|
||||||
#if SYNC_CYCLE_STARTS
|
|
||||||
/* Compute cycle start when RTIMER_ARCH_SECOND is not a multiple
|
|
||||||
of CHANNEL_CHECK_RATE */
|
|
||||||
if(sync_cycle_phase++ == NETSTACK_RDC_CHANNEL_CHECK_RATE) {
|
|
||||||
sync_cycle_phase = 0;
|
|
||||||
sync_cycle_start += RTIMER_ARCH_SECOND;
|
|
||||||
cycle_start = sync_cycle_start;
|
|
||||||
} else {
|
|
||||||
#if (RTIMER_ARCH_SECOND * NETSTACK_RDC_CHANNEL_CHECK_RATE) > 65535
|
|
||||||
cycle_start = sync_cycle_start + ((unsigned long)(sync_cycle_phase*RTIMER_ARCH_SECOND))/NETSTACK_RDC_CHANNEL_CHECK_RATE;
|
|
||||||
#else
|
|
||||||
cycle_start = sync_cycle_start + (sync_cycle_phase*RTIMER_ARCH_SECOND)/NETSTACK_RDC_CHANNEL_CHECK_RATE;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
cycle_start += CYCLE_TIME;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
packet_seen = 0;
|
packet_seen = 0;
|
||||||
|
|
||||||
for(count = 0; count < CCA_COUNT_MAX; ++count) {
|
for(count = 0; count < CCA_COUNT_MAX; ++count) {
|
||||||
|
@ -472,8 +481,8 @@ powercycle(struct rtimer *t, void *ptr)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
schedule_powercycle(t, CCA_CHECK_TIME + CCA_SLEEP_TIME);
|
// schedule_powercycle(t, CCA_CHECK_TIME + CCA_SLEEP_TIME);
|
||||||
PT_YIELD(&pt);
|
// PT_YIELD(&pt);
|
||||||
}
|
}
|
||||||
if(radio_is_on) {
|
if(radio_is_on) {
|
||||||
if(!(NETSTACK_RADIO.receiving_packet() ||
|
if(!(NETSTACK_RADIO.receiving_packet() ||
|
||||||
|
@ -485,24 +494,26 @@ powercycle(struct rtimer *t, void *ptr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(RTIMER_CLOCK_LT(RTIMER_NOW() - cycle_start, CYCLE_TIME - CHECK_TIME * 4)) {
|
advance_cycle_start();
|
||||||
|
|
||||||
|
if(RTIMER_CLOCK_LT(RTIMER_NOW() , cycle_start - CHECK_TIME * 4)) {
|
||||||
/* Schedule the next powercycle interrupt, or sleep the mcu
|
/* Schedule the next powercycle interrupt, or sleep the mcu
|
||||||
until then. Sleeping will not exit from this interrupt, so
|
until then. Sleeping will not exit from this interrupt, so
|
||||||
ensure an occasional wake cycle or foreground processing will
|
ensure an occasional wake cycle or foreground processing will
|
||||||
be blocked until a packet is detected */
|
be blocked until a packet is detected */
|
||||||
#if RDC_CONF_MCU_SLEEP
|
#if RDC_CONF_MCU_SLEEP
|
||||||
static uint8_t sleepcycle;
|
static uint8_t sleepcycle;
|
||||||
if((sleepcycle++ < mcusleepcycle) && !we_are_sending && !radio_is_on) {
|
if((sleepcycle++ < mcusleepcycle) && !we_are_sending && !radio_is_on && !(NETSTACK_RADIO.receiving_packet() || NETSTACK_RADIO.pending_packet())) {
|
||||||
rtimer_arch_sleep(CYCLE_TIME - (RTIMER_NOW() - cycle_start));
|
rtimer_arch_sleep(cycle_start - RTIMER_NOW());
|
||||||
} else {
|
} else {
|
||||||
sleepcycle = 0;
|
sleepcycle = 0;
|
||||||
#ifndef RDC_CONF_PT_YIELD_OFF
|
#ifndef RDC_CONF_PT_YIELD_OFF
|
||||||
schedule_powercycle_fixed(t, CYCLE_TIME + cycle_start);
|
schedule_powercycle_fixed(t, cycle_start);
|
||||||
PT_YIELD(&pt);
|
PT_YIELD(&pt);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
schedule_powercycle_fixed(t, CYCLE_TIME + cycle_start);
|
schedule_powercycle_fixed(t, cycle_start);
|
||||||
PT_YIELD(&pt);
|
PT_YIELD(&pt);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -755,7 +766,7 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr,
|
||||||
NETSTACK_RADIO.channel_clear() == 0)) {
|
NETSTACK_RADIO.channel_clear() == 0)) {
|
||||||
uint8_t ackbuf[ACK_LEN];
|
uint8_t ackbuf[ACK_LEN];
|
||||||
wt = RTIMER_NOW();
|
wt = RTIMER_NOW();
|
||||||
while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + AFTER_ACK_DETECTECT_WAIT_TIME)) { }
|
while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + AFTER_ACK_DETECTED_WAIT_TIME)) { }
|
||||||
|
|
||||||
len = NETSTACK_RADIO.read(ackbuf, ACK_LEN);
|
len = NETSTACK_RADIO.read(ackbuf, ACK_LEN);
|
||||||
if(len == ACK_LEN && seqno == ackbuf[ACK_LEN - 1]) {
|
if(len == ACK_LEN && seqno == ackbuf[ACK_LEN - 1]) {
|
||||||
|
@ -867,6 +878,10 @@ qsend_list(mac_callback_t sent, void *ptr, struct rdc_buf_list *buf_list)
|
||||||
if(next != NULL) {
|
if(next != NULL) {
|
||||||
packetbuf_set_attr(PACKETBUF_ATTR_PENDING, 1);
|
packetbuf_set_attr(PACKETBUF_ATTR_PENDING, 1);
|
||||||
}
|
}
|
||||||
|
#if !NETSTACK_CONF_BRIDGE_MODE
|
||||||
|
/* If NETSTACK_CONF_BRIDGE_MODE is set, assume PACKETBUF_ADDR_SENDER is already set. */
|
||||||
|
packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &linkaddr_node_addr);
|
||||||
|
#endif
|
||||||
packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);
|
packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);
|
||||||
if(NETSTACK_FRAMER.create() < 0) {
|
if(NETSTACK_FRAMER.create() < 0) {
|
||||||
PRINTF("contikimac: framer failed\n");
|
PRINTF("contikimac: framer failed\n");
|
||||||
|
|
|
@ -231,10 +231,12 @@ tx_done(int status, struct rdc_buf_list *q, struct neighbor_queue *n)
|
||||||
mac_callback_t sent;
|
mac_callback_t sent;
|
||||||
struct qbuf_metadata *metadata;
|
struct qbuf_metadata *metadata;
|
||||||
void *cptr;
|
void *cptr;
|
||||||
|
uint8_t ntx;
|
||||||
|
|
||||||
metadata = (struct qbuf_metadata *)q->ptr;
|
metadata = (struct qbuf_metadata *)q->ptr;
|
||||||
sent = metadata->sent;
|
sent = metadata->sent;
|
||||||
cptr = metadata->cptr;
|
cptr = metadata->cptr;
|
||||||
|
ntx = n->transmissions;
|
||||||
|
|
||||||
switch(status) {
|
switch(status) {
|
||||||
case MAC_TX_OK:
|
case MAC_TX_OK:
|
||||||
|
@ -251,7 +253,7 @@ tx_done(int status, struct rdc_buf_list *q, struct neighbor_queue *n)
|
||||||
}
|
}
|
||||||
|
|
||||||
free_packet(n, q, status);
|
free_packet(n, q, status);
|
||||||
mac_call_sent_callback(sent, cptr, status, n->transmissions);
|
mac_call_sent_callback(sent, cptr, status, ntx);
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -146,36 +146,45 @@ frame802154_has_panid(frame802154_fcf_t *fcf, int *has_src_pan_id, int *has_dest
|
||||||
}
|
}
|
||||||
|
|
||||||
if(fcf->frame_version == FRAME802154_IEEE802154E_2012) {
|
if(fcf->frame_version == FRAME802154_IEEE802154E_2012) {
|
||||||
if(!fcf->panid_compression) {
|
/*
|
||||||
/* Compressed PAN ID == no PAN ID at all */
|
* IEEE 802.15.4-2015
|
||||||
if(fcf->dest_addr_mode == fcf->dest_addr_mode) {
|
* Table 7-2, PAN ID Compression value for frame version 0b10
|
||||||
/* No address or both addresses: include destination PAN ID */
|
*/
|
||||||
|
if((fcf->dest_addr_mode == FRAME802154_NOADDR &&
|
||||||
|
fcf->src_addr_mode == FRAME802154_NOADDR &&
|
||||||
|
fcf->panid_compression == 1) ||
|
||||||
|
(fcf->dest_addr_mode != FRAME802154_NOADDR &&
|
||||||
|
fcf->src_addr_mode == FRAME802154_NOADDR &&
|
||||||
|
fcf->panid_compression == 0) ||
|
||||||
|
(fcf->dest_addr_mode == FRAME802154_LONGADDRMODE &&
|
||||||
|
fcf->src_addr_mode == FRAME802154_LONGADDRMODE &&
|
||||||
|
fcf->panid_compression == 0) ||
|
||||||
|
((fcf->dest_addr_mode == FRAME802154_SHORTADDRMODE &&
|
||||||
|
fcf->src_addr_mode != FRAME802154_NOADDR) ||
|
||||||
|
(fcf->dest_addr_mode != FRAME802154_NOADDR &&
|
||||||
|
fcf->src_addr_mode == FRAME802154_SHORTADDRMODE)) ){
|
||||||
dest_pan_id = 1;
|
dest_pan_id = 1;
|
||||||
} else if(fcf->dest_addr_mode) {
|
}
|
||||||
/* Only dest address, include dest PAN ID */
|
|
||||||
dest_pan_id = 1;
|
if(fcf->panid_compression == 0 &&
|
||||||
} else if(fcf->src_addr_mode) {
|
((fcf->dest_addr_mode == FRAME802154_NOADDR &&
|
||||||
/* Only src address, include src PAN ID */
|
fcf->src_addr_mode == FRAME802154_LONGADDRMODE) ||
|
||||||
|
(fcf->dest_addr_mode == FRAME802154_NOADDR &&
|
||||||
|
fcf->src_addr_mode == FRAME802154_SHORTADDRMODE) ||
|
||||||
|
(fcf->dest_addr_mode == FRAME802154_SHORTADDRMODE &&
|
||||||
|
fcf->src_addr_mode == FRAME802154_SHORTADDRMODE) ||
|
||||||
|
(fcf->dest_addr_mode == FRAME802154_SHORTADDRMODE &&
|
||||||
|
fcf->src_addr_mode == FRAME802154_LONGADDRMODE) ||
|
||||||
|
(fcf->dest_addr_mode == FRAME802154_LONGADDRMODE &&
|
||||||
|
fcf->src_addr_mode == FRAME802154_SHORTADDRMODE))) {
|
||||||
src_pan_id = 1;
|
src_pan_id = 1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if(fcf->dest_addr_mode == 0 && fcf->dest_addr_mode == 1) {
|
|
||||||
/* No address included, include dest PAN ID conditionally */
|
|
||||||
if(!fcf->panid_compression) {
|
|
||||||
dest_pan_id = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Remove the following rule the day rows 2 and 3 from table 2a are fixed: */
|
|
||||||
if(fcf->dest_addr_mode == 0 && fcf->dest_addr_mode == 0) {
|
|
||||||
/* Not meaningful, we include a PAN ID iff the compress flag is set, but
|
|
||||||
* this is what the standard currently stipulates */
|
|
||||||
dest_pan_id = fcf->panid_compression;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
/* No PAN ID in ACK */
|
/* No PAN ID in ACK */
|
||||||
if(fcf->frame_type != FRAME802154_ACKFRAME) {
|
if(fcf->frame_type != FRAME802154_ACKFRAME) {
|
||||||
if(!fcf->panid_compression && fcf->src_addr_mode & 3) {
|
if(!fcf->panid_compression && (fcf->src_addr_mode & 3)) {
|
||||||
/* If compressed, don't inclue source PAN ID */
|
/* If compressed, don't include source PAN ID */
|
||||||
src_pan_id = 1;
|
src_pan_id = 1;
|
||||||
}
|
}
|
||||||
if(fcf->dest_addr_mode & 3) {
|
if(fcf->dest_addr_mode & 3) {
|
||||||
|
@ -196,7 +205,7 @@ frame802154_has_panid(frame802154_fcf_t *fcf, int *has_src_pan_id, int *has_dest
|
||||||
int
|
int
|
||||||
frame802154_check_dest_panid(frame802154_t *frame)
|
frame802154_check_dest_panid(frame802154_t *frame)
|
||||||
{
|
{
|
||||||
int has_dest_panid;
|
int has_dest_panid = 0;
|
||||||
|
|
||||||
if(frame == NULL) {
|
if(frame == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -295,7 +304,7 @@ field_len(frame802154_t *p, field_length_t *flen)
|
||||||
* up to the caller. */
|
* up to the caller. */
|
||||||
if(p->fcf.frame_version < FRAME802154_IEEE802154E_2012) {
|
if(p->fcf.frame_version < FRAME802154_IEEE802154E_2012) {
|
||||||
/* Set PAN ID compression bit if src pan id matches dest pan id. */
|
/* Set PAN ID compression bit if src pan id matches dest pan id. */
|
||||||
if(p->fcf.dest_addr_mode & 3 && p->fcf.src_addr_mode & 3 &&
|
if((p->fcf.dest_addr_mode & 3) && (p->fcf.src_addr_mode & 3) &&
|
||||||
p->src_pid == p->dest_pid) {
|
p->src_pid == p->dest_pid) {
|
||||||
p->fcf.panid_compression = 1;
|
p->fcf.panid_compression = 1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -353,6 +362,20 @@ frame802154_hdrlen(frame802154_t *p)
|
||||||
return 2 + flen.seqno_len + flen.dest_pid_len + flen.dest_addr_len +
|
return 2 + flen.seqno_len + flen.dest_pid_len + flen.dest_addr_len +
|
||||||
flen.src_pid_len + flen.src_addr_len + flen.aux_sec_len;
|
flen.src_pid_len + flen.src_addr_len + flen.aux_sec_len;
|
||||||
}
|
}
|
||||||
|
void
|
||||||
|
frame802154_create_fcf(frame802154_fcf_t *fcf, uint8_t *buf)
|
||||||
|
{
|
||||||
|
buf[0] = (fcf->frame_type & 7) |
|
||||||
|
((fcf->security_enabled & 1) << 3) |
|
||||||
|
((fcf->frame_pending & 1) << 4) |
|
||||||
|
((fcf->ack_required & 1) << 5) |
|
||||||
|
((fcf->panid_compression & 1) << 6);
|
||||||
|
buf[1] = ((fcf->sequence_number_suppression & 1)) |
|
||||||
|
((fcf->ie_list_present & 1)) << 1 |
|
||||||
|
((fcf->dest_addr_mode & 3) << 2) |
|
||||||
|
((fcf->frame_version & 3) << 4) |
|
||||||
|
((fcf->src_addr_mode & 3) << 6);
|
||||||
|
}
|
||||||
/*----------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------*/
|
||||||
/**
|
/**
|
||||||
* \brief Creates a frame for transmission over the air. This function is
|
* \brief Creates a frame for transmission over the air. This function is
|
||||||
|
@ -379,17 +402,7 @@ frame802154_create(frame802154_t *p, uint8_t *buf)
|
||||||
|
|
||||||
/* OK, now we have field lengths. Time to actually construct */
|
/* OK, now we have field lengths. Time to actually construct */
|
||||||
/* the outgoing frame, and store it in buf */
|
/* the outgoing frame, and store it in buf */
|
||||||
buf[0] = (p->fcf.frame_type & 7) |
|
frame802154_create_fcf(&p->fcf, buf);
|
||||||
((p->fcf.security_enabled & 1) << 3) |
|
|
||||||
((p->fcf.frame_pending & 1) << 4) |
|
|
||||||
((p->fcf.ack_required & 1) << 5) |
|
|
||||||
((p->fcf.panid_compression & 1) << 6);
|
|
||||||
buf[1] = ((p->fcf.sequence_number_suppression & 1)) |
|
|
||||||
((p->fcf.ie_list_present & 1)) << 1 |
|
|
||||||
((p->fcf.dest_addr_mode & 3) << 2) |
|
|
||||||
((p->fcf.frame_version & 3) << 4) |
|
|
||||||
((p->fcf.src_addr_mode & 3) << 6);
|
|
||||||
|
|
||||||
pos = 2;
|
pos = 2;
|
||||||
|
|
||||||
/* Sequence number */
|
/* Sequence number */
|
||||||
|
@ -451,6 +464,28 @@ frame802154_create(frame802154_t *p, uint8_t *buf)
|
||||||
|
|
||||||
return (int)pos;
|
return (int)pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
frame802154_parse_fcf(uint8_t *data, frame802154_fcf_t *pfcf)
|
||||||
|
{
|
||||||
|
frame802154_fcf_t fcf;
|
||||||
|
|
||||||
|
/* decode the FCF */
|
||||||
|
fcf.frame_type = data[0] & 7;
|
||||||
|
fcf.security_enabled = (data[0] >> 3) & 1;
|
||||||
|
fcf.frame_pending = (data[0] >> 4) & 1;
|
||||||
|
fcf.ack_required = (data[0] >> 5) & 1;
|
||||||
|
fcf.panid_compression = (data[0] >> 6) & 1;
|
||||||
|
|
||||||
|
fcf.sequence_number_suppression = data[1] & 1;
|
||||||
|
fcf.ie_list_present = (data[1] >> 1) & 1;
|
||||||
|
fcf.dest_addr_mode = (data[1] >> 2) & 3;
|
||||||
|
fcf.frame_version = (data[1] >> 4) & 3;
|
||||||
|
fcf.src_addr_mode = (data[1] >> 6) & 3;
|
||||||
|
|
||||||
|
/* copy fcf */
|
||||||
|
memcpy(pfcf, &fcf, sizeof(frame802154_fcf_t));
|
||||||
|
}
|
||||||
/*----------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------*/
|
||||||
/**
|
/**
|
||||||
* \brief Parses an input frame. Scans the input frame to find each
|
* \brief Parses an input frame. Scans the input frame to find each
|
||||||
|
@ -480,19 +515,7 @@ frame802154_parse(uint8_t *data, int len, frame802154_t *pf)
|
||||||
p = data;
|
p = data;
|
||||||
|
|
||||||
/* decode the FCF */
|
/* decode the FCF */
|
||||||
fcf.frame_type = p[0] & 7;
|
frame802154_parse_fcf(p, &fcf);
|
||||||
fcf.security_enabled = (p[0] >> 3) & 1;
|
|
||||||
fcf.frame_pending = (p[0] >> 4) & 1;
|
|
||||||
fcf.ack_required = (p[0] >> 5) & 1;
|
|
||||||
fcf.panid_compression = (p[0] >> 6) & 1;
|
|
||||||
|
|
||||||
fcf.sequence_number_suppression = p[1] & 1;
|
|
||||||
fcf.ie_list_present = (p[1] >> 1) & 1;
|
|
||||||
fcf.dest_addr_mode = (p[1] >> 2) & 3;
|
|
||||||
fcf.frame_version = (p[1] >> 4) & 3;
|
|
||||||
fcf.src_addr_mode = (p[1] >> 6) & 3;
|
|
||||||
|
|
||||||
/* copy fcf and seqNum */
|
|
||||||
memcpy(&pf->fcf, &fcf, sizeof(frame802154_fcf_t));
|
memcpy(&pf->fcf, &fcf, sizeof(frame802154_fcf_t));
|
||||||
p += 2; /* Skip first two bytes */
|
p += 2; /* Skip first two bytes */
|
||||||
|
|
||||||
|
|
|
@ -207,8 +207,10 @@ typedef struct {
|
||||||
/* Prototypes */
|
/* Prototypes */
|
||||||
|
|
||||||
int frame802154_hdrlen(frame802154_t *p);
|
int frame802154_hdrlen(frame802154_t *p);
|
||||||
|
void frame802154_create_fcf(frame802154_fcf_t *fcf, uint8_t *buf);
|
||||||
int frame802154_create(frame802154_t *p, uint8_t *buf);
|
int frame802154_create(frame802154_t *p, uint8_t *buf);
|
||||||
int frame802154_parse(uint8_t *data, int length, frame802154_t *pf);
|
int frame802154_parse(uint8_t *data, int length, frame802154_t *pf);
|
||||||
|
void frame802154_parse_fcf(uint8_t *data, frame802154_fcf_t *pfcf);
|
||||||
|
|
||||||
/* Get current PAN ID */
|
/* Get current PAN ID */
|
||||||
uint16_t frame802154_get_pan_id(void);
|
uint16_t frame802154_get_pan_id(void);
|
||||||
|
|
|
@ -70,7 +70,7 @@ struct ieee802154_ies {
|
||||||
uint16_t ie_mlme_len;
|
uint16_t ie_mlme_len;
|
||||||
/* Payload Short MLME IEs */
|
/* Payload Short MLME IEs */
|
||||||
uint8_t ie_tsch_synchronization_offset;
|
uint8_t ie_tsch_synchronization_offset;
|
||||||
struct asn_t ie_asn;
|
struct tsch_asn_t ie_asn;
|
||||||
uint8_t ie_join_priority;
|
uint8_t ie_join_priority;
|
||||||
uint8_t ie_tsch_timeslot_id;
|
uint8_t ie_tsch_timeslot_id;
|
||||||
uint16_t ie_tsch_timeslot[tsch_ts_elements_count];
|
uint16_t ie_tsch_timeslot[tsch_ts_elements_count];
|
||||||
|
|
|
@ -86,14 +86,16 @@ create_frame(int type, int do_create)
|
||||||
params.fcf.frame_pending = packetbuf_attr(PACKETBUF_ATTR_PENDING);
|
params.fcf.frame_pending = packetbuf_attr(PACKETBUF_ATTR_PENDING);
|
||||||
if(packetbuf_holds_broadcast()) {
|
if(packetbuf_holds_broadcast()) {
|
||||||
params.fcf.ack_required = 0;
|
params.fcf.ack_required = 0;
|
||||||
|
/* Suppress seqno on broadcast if supported (frame v2 or more) */
|
||||||
|
params.fcf.sequence_number_suppression = FRAME802154_VERSION >= FRAME802154_IEEE802154E_2012;
|
||||||
} else {
|
} else {
|
||||||
params.fcf.ack_required = packetbuf_attr(PACKETBUF_ATTR_MAC_ACK);
|
params.fcf.ack_required = packetbuf_attr(PACKETBUF_ATTR_MAC_ACK);
|
||||||
|
params.fcf.sequence_number_suppression = FRAME802154_SUPPR_SEQNO;
|
||||||
}
|
}
|
||||||
/* We do not compress PAN ID in outgoing frames, i.e. include one PAN ID (dest by default)
|
/* We do not compress PAN ID in outgoing frames, i.e. include one PAN ID (dest by default)
|
||||||
* There is one exception, seemingly a typo in Table 2a: rows 2 and 3: when there is no
|
* There is one exception, seemingly a typo in Table 2a: rows 2 and 3: when there is no
|
||||||
* source nor destination address, we have dest PAN ID iff compression is *set*. */
|
* source nor destination address, we have dest PAN ID iff compression is *set*. */
|
||||||
params.fcf.panid_compression = 0;
|
params.fcf.panid_compression = 0;
|
||||||
params.fcf.sequence_number_suppression = FRAME802154_SUPPR_SEQNO;
|
|
||||||
|
|
||||||
/* Insert IEEE 802.15.4 version bits. */
|
/* Insert IEEE 802.15.4 version bits. */
|
||||||
params.fcf.frame_version = FRAME802154_VERSION;
|
params.fcf.frame_version = FRAME802154_VERSION;
|
||||||
|
@ -171,7 +173,8 @@ create_frame(int type, int do_create)
|
||||||
* Set up the source address using only the long address mode for
|
* Set up the source address using only the long address mode for
|
||||||
* phase 1.
|
* phase 1.
|
||||||
*/
|
*/
|
||||||
linkaddr_copy((linkaddr_t *)¶ms.src_addr, &linkaddr_node_addr);
|
linkaddr_copy((linkaddr_t *)¶ms.src_addr,
|
||||||
|
packetbuf_addr(PACKETBUF_ADDR_SENDER));
|
||||||
|
|
||||||
params.payload = packetbuf_dataptr();
|
params.payload = packetbuf_dataptr();
|
||||||
params.payload_len = packetbuf_datalen();
|
params.payload_len = packetbuf_datalen();
|
||||||
|
|
|
@ -51,9 +51,16 @@
|
||||||
|
|
||||||
struct seqno {
|
struct seqno {
|
||||||
linkaddr_t sender;
|
linkaddr_t sender;
|
||||||
|
clock_time_t timestamp;
|
||||||
uint8_t seqno;
|
uint8_t seqno;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef NETSTACK_CONF_MAC_SEQNO_MAX_AGE
|
||||||
|
#define SEQNO_MAX_AGE NETSTACK_CONF_MAC_SEQNO_MAX_AGE
|
||||||
|
#else /* NETSTACK_CONF_MAC_SEQNO_MAX_AGE */
|
||||||
|
#define SEQNO_MAX_AGE (20 * CLOCK_SECOND)
|
||||||
|
#endif /* NETSTACK_CONF_MAC_SEQNO_MAX_AGE */
|
||||||
|
|
||||||
#ifdef NETSTACK_CONF_MAC_SEQNO_HISTORY
|
#ifdef NETSTACK_CONF_MAC_SEQNO_HISTORY
|
||||||
#define MAX_SEQNOS NETSTACK_CONF_MAC_SEQNO_HISTORY
|
#define MAX_SEQNOS NETSTACK_CONF_MAC_SEQNO_HISTORY
|
||||||
#else /* NETSTACK_CONF_MAC_SEQNO_HISTORY */
|
#else /* NETSTACK_CONF_MAC_SEQNO_HISTORY */
|
||||||
|
@ -66,6 +73,7 @@ int
|
||||||
mac_sequence_is_duplicate(void)
|
mac_sequence_is_duplicate(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
clock_time_t now = clock_time();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for duplicate packet by comparing the sequence number of the incoming
|
* Check for duplicate packet by comparing the sequence number of the incoming
|
||||||
|
@ -75,9 +83,15 @@ mac_sequence_is_duplicate(void)
|
||||||
if(linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_SENDER),
|
if(linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_SENDER),
|
||||||
&received_seqnos[i].sender)) {
|
&received_seqnos[i].sender)) {
|
||||||
if(packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO) == received_seqnos[i].seqno) {
|
if(packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO) == received_seqnos[i].seqno) {
|
||||||
|
#if SEQNO_MAX_AGE > 0
|
||||||
|
if(now - received_seqnos[i].timestamp <= SEQNO_MAX_AGE) {
|
||||||
/* Duplicate packet. */
|
/* Duplicate packet. */
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
#else /* SEQNO_MAX_AGE > 0 */
|
||||||
|
return 1;
|
||||||
|
#endif /* SEQNO_MAX_AGE > 0 */
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,6 +117,7 @@ mac_sequence_register_seqno(void)
|
||||||
memcpy(&received_seqnos[j], &received_seqnos[j - 1], sizeof(struct seqno));
|
memcpy(&received_seqnos[j], &received_seqnos[j - 1], sizeof(struct seqno));
|
||||||
}
|
}
|
||||||
received_seqnos[0].seqno = packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO);
|
received_seqnos[0].seqno = packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO);
|
||||||
|
received_seqnos[0].timestamp = clock_time();
|
||||||
linkaddr_copy(&received_seqnos[0].sender,
|
linkaddr_copy(&received_seqnos[0].sender,
|
||||||
packetbuf_addr(PACKETBUF_ADDR_SENDER));
|
packetbuf_addr(PACKETBUF_ADDR_SENDER));
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,10 +46,10 @@
|
||||||
#include "net/rime/rimestats.h"
|
#include "net/rime/rimestats.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#if CONTIKI_TARGET_COOJA
|
#if CONTIKI_TARGET_COOJA || CONTIKI_TARGET_COOJA_IP64
|
||||||
#include "lib/simEnvChange.h"
|
#include "lib/simEnvChange.h"
|
||||||
#include "sys/cooja_mt.h"
|
#include "sys/cooja_mt.h"
|
||||||
#endif /* CONTIKI_TARGET_COOJA */
|
#endif /* CONTIKI_TARGET_COOJA || CONTIKI_TARGET_COOJA_IP64 */
|
||||||
|
|
||||||
#define DEBUG 0
|
#define DEBUG 0
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
@ -158,10 +158,10 @@ send_one_packet(mac_callback_t sent, void *ptr)
|
||||||
wt = RTIMER_NOW();
|
wt = RTIMER_NOW();
|
||||||
watchdog_periodic();
|
watchdog_periodic();
|
||||||
while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + ACK_WAIT_TIME)) {
|
while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + ACK_WAIT_TIME)) {
|
||||||
#if CONTIKI_TARGET_COOJA
|
#if CONTIKI_TARGET_COOJA || CONTIKI_TARGET_COOJA_IP64
|
||||||
simProcessRunValue = 1;
|
simProcessRunValue = 1;
|
||||||
cooja_mt_yield();
|
cooja_mt_yield();
|
||||||
#endif /* CONTIKI_TARGET_COOJA */
|
#endif /* CONTIKI_TARGET_COOJA || CONTIKI_TARGET_COOJA_IP64 */
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = MAC_TX_NOACK;
|
ret = MAC_TX_NOACK;
|
||||||
|
@ -176,10 +176,10 @@ send_one_packet(mac_callback_t sent, void *ptr)
|
||||||
watchdog_periodic();
|
watchdog_periodic();
|
||||||
while(RTIMER_CLOCK_LT(RTIMER_NOW(),
|
while(RTIMER_CLOCK_LT(RTIMER_NOW(),
|
||||||
wt + AFTER_ACK_DETECTED_WAIT_TIME)) {
|
wt + AFTER_ACK_DETECTED_WAIT_TIME)) {
|
||||||
#if CONTIKI_TARGET_COOJA
|
#if CONTIKI_TARGET_COOJA || CONTIKI_TARGET_COOJA_IP64
|
||||||
simProcessRunValue = 1;
|
simProcessRunValue = 1;
|
||||||
cooja_mt_yield();
|
cooja_mt_yield();
|
||||||
#endif /* CONTIKI_TARGET_COOJA */
|
#endif /* CONTIKI_TARGET_COOJA || CONTIKI_TARGET_COOJA_IP64 */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# IEEE 802.15.4e TSCH (TimeSlotted Channel Hopping)
|
# IEEE 802.15.4-2015 TSCH and IETF 6TiSCH
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
TSCH is a MAC layer of the [IEEE 802.15.4e-2012 amendment][ieee802.15.4e-2012],
|
Time Slotted Channel Hopping (TSCH) is a MAC layer of the [IEEE 802.15.4e-2012 amendment][ieee802.15.4e-2012],
|
||||||
currently being integrated as part of the new IEEE 802.15.4-2015.
|
currently being integrated as part of the new IEEE 802.15.4-2015.
|
||||||
[6TiSCH][ietf-6tisch-wg] is an IETF Working Group focused on IPv6 over TSCH.
|
[6TiSCH][ietf-6tisch-wg] is an IETF Working Group focused on IPv6 over TSCH.
|
||||||
This is a Contiki implementation of TSCH and the 6TiSCH so-called "minimal configuration",
|
This is a Contiki implementation of TSCH and the 6TiSCH so-called "minimal configuration",
|
||||||
|
@ -11,8 +11,11 @@ which defines how to run a basic RPL+TSCH network.
|
||||||
It was developped by:
|
It was developped by:
|
||||||
* Simon Duquennoy, SICS, simonduq@sics.se, github user: [simonduq](https://github.com/simonduq)
|
* Simon Duquennoy, SICS, simonduq@sics.se, github user: [simonduq](https://github.com/simonduq)
|
||||||
* Beshr Al Nahas, SICS (now Chalmers University), beshr@chalmers.se, github user: [beshrns](https://github.com/beshrns)
|
* Beshr Al Nahas, SICS (now Chalmers University), beshr@chalmers.se, github user: [beshrns](https://github.com/beshrns)
|
||||||
|
* Atis Elsts, Univ. Bristol, atis.elsts@bristol.ac.uk, github user: [atiselsts](https://github.com/atiselsts)
|
||||||
|
|
||||||
You can find an extensive evaluation of this implementation in our paper [*Orchestra: Robust Mesh Networks Through Autonomously Scheduled TSCH*](http://www.simonduquennoy.net/papers/duquennoy15orchestra.pdf), ACM SenSys'15.
|
|
||||||
|
This implementation is presented in depth and evaluated in our paper: [*TSCH and 6TiSCH for Contiki: Challenges, Design and Evaluation*](http://www.simonduquennoy.net/papers/duquennoy17tsch.pdf), IEEE DCOSS'17.
|
||||||
|
The scheduler Orchestra is detailled in [*Orchestra: Robust Mesh Networks Through Autonomously Scheduled TSCH*](http://www.simonduquennoy.net/papers/duquennoy15orchestra.pdf), ACM SenSys'15.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
|
@ -26,11 +29,12 @@ This implementation includes:
|
||||||
* Standard TSCH link selection and slot operation (10ms slots by default)
|
* Standard TSCH link selection and slot operation (10ms slots by default)
|
||||||
* Standard TSCH synchronization, including with ACK/NACK time correction Information Element
|
* Standard TSCH synchronization, including with ACK/NACK time correction Information Element
|
||||||
* Standard TSCH queues and CSMA-CA mechanism
|
* Standard TSCH queues and CSMA-CA mechanism
|
||||||
* Standard TSCH security
|
* Standard TSCH and 6TiSCH security
|
||||||
* Standard 6TiSCH TSCH-RPL interaction (6TiSCH Minimal Configuration and Minimal Schedule)
|
* Standard 6TiSCH TSCH-RPL interaction (6TiSCH Minimal Configuration and Minimal Schedule)
|
||||||
* A scheduling API to add/remove slotframes and links
|
* A scheduling API to add/remove slotframes and links
|
||||||
* A system for logging from TSCH timeslot operation interrupt, with postponed printout
|
* A system for logging from TSCH timeslot operation interrupt, with postponed printout
|
||||||
* Orchestra: an autonomous scheduler for TSCH+RPL networks
|
* Orchestra: an autonomous scheduler for TSCH+RPL networks
|
||||||
|
* A drift compensation mechanism
|
||||||
|
|
||||||
It has been tested on the following platforms:
|
It has been tested on the following platforms:
|
||||||
* NXP JN516x (`jn516x`, tested on hardware)
|
* NXP JN516x (`jn516x`, tested on hardware)
|
||||||
|
@ -38,7 +42,9 @@ It has been tested on the following platforms:
|
||||||
* Zolertia Z1 (`z1`, tested in cooja only)
|
* Zolertia Z1 (`z1`, tested in cooja only)
|
||||||
* CC2538DK (`cc2538dk`, tested on hardware)
|
* CC2538DK (`cc2538dk`, tested on hardware)
|
||||||
* Zolertia Zoul (`zoul`, tested on hardware)
|
* Zolertia Zoul (`zoul`, tested on hardware)
|
||||||
|
* OpenMote-CC2538 (`openmote-cc2538`, tested on hardware)
|
||||||
* CC2650 (`srf06-cc26xx`, tested on hardware)
|
* CC2650 (`srf06-cc26xx`, tested on hardware)
|
||||||
|
* Cooja mote (`cooja`, tested with cooja)
|
||||||
|
|
||||||
This implementation was present at the ETSI Plugtest
|
This implementation was present at the ETSI Plugtest
|
||||||
event in Prague in July 2015, and did successfully inter-operate with all
|
event in Prague in July 2015, and did successfully inter-operate with all
|
||||||
|
@ -71,6 +77,7 @@ Implements the 6TiSCH minimal configuration K1-K2 keys pair.
|
||||||
* `tsch-rpl.[ch]`: used for TSCH+RPL networks, to align TSCH and RPL states (preferred parent -> time source,
|
* `tsch-rpl.[ch]`: used for TSCH+RPL networks, to align TSCH and RPL states (preferred parent -> time source,
|
||||||
rank -> join priority) as defined in the 6TiSCH minimal configuration.
|
rank -> join priority) as defined in the 6TiSCH minimal configuration.
|
||||||
* `tsch-log.[ch]`: logging system for TSCH, including delayed messages for logging from slot operation interrupt.
|
* `tsch-log.[ch]`: logging system for TSCH, including delayed messages for logging from slot operation interrupt.
|
||||||
|
* `tsch-adaptive-timesync.c`: used to learn the relative drift to the node's time source and automatically compensate for it.
|
||||||
|
|
||||||
Orchestra is implemented in:
|
Orchestra is implemented in:
|
||||||
* `apps/orchestra`: see `apps/orchestra/README.md` for more information.
|
* `apps/orchestra`: see `apps/orchestra/README.md` for more information.
|
||||||
|
@ -79,7 +86,7 @@ Orchestra is implemented in:
|
||||||
|
|
||||||
A simple TSCH+RPL example is included under `examples/ipv6/rpl-tsch`.
|
A simple TSCH+RPL example is included under `examples/ipv6/rpl-tsch`.
|
||||||
To use TSCH, first make sure your platform supports it.
|
To use TSCH, first make sure your platform supports it.
|
||||||
Currently, `jn516x`, `sky`, `z1`, `cc2538dk`, `zoul` and `srf06-cc26xx` are the supported platforms.
|
Currently, `jn516x`, `sky`, `z1`, `cc2538dk`, `zoul`, `openmote-cc2538`, `srf06-cc26xx`, and `cooja` are the supported platforms.
|
||||||
To add your own, we refer the reader to the next section.
|
To add your own, we refer the reader to the next section.
|
||||||
|
|
||||||
To add TSCH to your application, first include the TSCH module from your makefile with:
|
To add TSCH to your application, first include the TSCH module from your makefile with:
|
||||||
|
@ -165,7 +172,7 @@ Finally, one can also implement his own scheduler, centralized or distributed, b
|
||||||
## Porting TSCH to a new platform
|
## Porting TSCH to a new platform
|
||||||
|
|
||||||
Porting TSCH to a new platform requires a few new features in the radio driver, a number of timing-related configuration paramters.
|
Porting TSCH to a new platform requires a few new features in the radio driver, a number of timing-related configuration paramters.
|
||||||
The easiest is probably to start from one of the existing port: `jn516x`, `sky`, `z1`, `cc2538dk`, `zoul`, `srf06-cc26xx`.
|
The easiest is probably to start from one of the existing port: `jn516x`, `sky`, `z1`, `cc2538dk`, `zoul`, `openmote-cc2538`, `srf06-cc26xx`.
|
||||||
|
|
||||||
### Radio features required for TSCH
|
### Radio features required for TSCH
|
||||||
|
|
||||||
|
@ -175,7 +182,7 @@ Instead, TSCH will poll the driver for incoming packets, from interrupt, exactly
|
||||||
|
|
||||||
TSCH will check when initializing (in `tsch_init`) that the radio driver supports all required features, namely:
|
TSCH will check when initializing (in `tsch_init`) that the radio driver supports all required features, namely:
|
||||||
* get and set Rx mode (`RADIO_PARAM_RX_MODE`) as follows:
|
* get and set Rx mode (`RADIO_PARAM_RX_MODE`) as follows:
|
||||||
* enable address filtering with `RADIO_RX_MODE_ADDRESS_FILTER`
|
* disable address filtering with `RADIO_RX_MODE_ADDRESS_FILTER`
|
||||||
* disable auto-ack with `RADIO_RX_MODE_AUTOACK`
|
* disable auto-ack with `RADIO_RX_MODE_AUTOACK`
|
||||||
* enable poll mode with `RADIO_RX_MODE_POLL_MODE`
|
* enable poll mode with `RADIO_RX_MODE_POLL_MODE`
|
||||||
* get and set Tx mode (`RADIO_PARAM_TX_MODE`) as follows:
|
* get and set Tx mode (`RADIO_PARAM_TX_MODE`) as follows:
|
||||||
|
@ -199,6 +206,8 @@ too slow for the default 10ms timeslots.
|
||||||
|
|
||||||
1. [IEEE 802.15.4e-2012 ammendment][ieee802.15.4e-2012]
|
1. [IEEE 802.15.4e-2012 ammendment][ieee802.15.4e-2012]
|
||||||
2. [IETF 6TiSCH Working Group][ietf-6tisch-wg]
|
2. [IETF 6TiSCH Working Group][ietf-6tisch-wg]
|
||||||
|
3. [A test procedure for Contiki timers in TSCH][tsch-sync-test]
|
||||||
|
|
||||||
[ieee802.15.4e-2012]: http://standards.ieee.org/getieee802/download/802.15.4e-2012.pdf
|
[ieee802.15.4e-2012]: http://standards.ieee.org/getieee802/download/802.15.4e-2012.pdf
|
||||||
[ietf-6tisch-wg]: https://datatracker.ietf.org/wg/6tisch
|
[ietf-6tisch-wg]: https://datatracker.ietf.org/wg/6tisch
|
||||||
|
[tsch-sync-test]: https://github.com/abbypjoby/Contiki-Synchronisation-Test
|
||||||
|
|
|
@ -38,8 +38,10 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "tsch-adaptive-timesync.h"
|
#include "net/mac/tsch/tsch.h"
|
||||||
#include "tsch-log.h"
|
#include "net/mac/tsch/tsch-conf.h"
|
||||||
|
#include "net/mac/tsch/tsch-adaptive-timesync.h"
|
||||||
|
#include "net/mac/tsch/tsch-log.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#if TSCH_ADAPTIVE_TIMESYNC
|
#if TSCH_ADAPTIVE_TIMESYNC
|
||||||
|
@ -72,6 +74,10 @@ timesync_entry_add(int32_t val, uint32_t time_delta)
|
||||||
buffer[pos] = val;
|
buffer[pos] = val;
|
||||||
if(timesync_entry_count < NUM_TIMESYNC_ENTRIES) {
|
if(timesync_entry_count < NUM_TIMESYNC_ENTRIES) {
|
||||||
timesync_entry_count++;
|
timesync_entry_count++;
|
||||||
|
} else {
|
||||||
|
/* We now have accurate drift compensation.
|
||||||
|
* Increase keep-alive timeout. */
|
||||||
|
tsch_set_ka_timeout(TSCH_MAX_KEEPALIVE_TIMEOUT);
|
||||||
}
|
}
|
||||||
pos = (pos + 1) % NUM_TIMESYNC_ENTRIES;
|
pos = (pos + 1) % NUM_TIMESYNC_ENTRIES;
|
||||||
|
|
||||||
|
|
|
@ -44,13 +44,13 @@
|
||||||
/************ Types ***********/
|
/************ Types ***********/
|
||||||
|
|
||||||
/* The ASN is an absolute slot number over 5 bytes. */
|
/* The ASN is an absolute slot number over 5 bytes. */
|
||||||
struct asn_t {
|
struct tsch_asn_t {
|
||||||
uint32_t ls4b; /* least significant 4 bytes */
|
uint32_t ls4b; /* least significant 4 bytes */
|
||||||
uint8_t ms1b; /* most significant 1 byte */
|
uint8_t ms1b; /* most significant 1 byte */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* For quick modulo operation on ASN */
|
/* For quick modulo operation on ASN */
|
||||||
struct asn_divisor_t {
|
struct tsch_asn_divisor_t {
|
||||||
uint16_t val; /* Divisor value */
|
uint16_t val; /* Divisor value */
|
||||||
uint16_t asn_ms1b_remainder; /* Remainder of the operation 0x100000000 / val */
|
uint16_t asn_ms1b_remainder; /* Remainder of the operation 0x100000000 / val */
|
||||||
};
|
};
|
||||||
|
@ -58,38 +58,38 @@ struct asn_divisor_t {
|
||||||
/************ Macros **********/
|
/************ Macros **********/
|
||||||
|
|
||||||
/* Initialize ASN */
|
/* Initialize ASN */
|
||||||
#define ASN_INIT(asn, ms1b_, ls4b_) do { \
|
#define TSCH_ASN_INIT(asn, ms1b_, ls4b_) do { \
|
||||||
(asn).ms1b = (ms1b_); \
|
(asn).ms1b = (ms1b_); \
|
||||||
(asn).ls4b = (ls4b_); \
|
(asn).ls4b = (ls4b_); \
|
||||||
} while(0);
|
} while(0);
|
||||||
|
|
||||||
/* Increment an ASN by inc (32 bits) */
|
/* Increment an ASN by inc (32 bits) */
|
||||||
#define ASN_INC(asn, inc) do { \
|
#define TSCH_ASN_INC(asn, inc) do { \
|
||||||
uint32_t new_ls4b = (asn).ls4b + (inc); \
|
uint32_t new_ls4b = (asn).ls4b + (inc); \
|
||||||
if(new_ls4b < (asn).ls4b) { (asn).ms1b++; } \
|
if(new_ls4b < (asn).ls4b) { (asn).ms1b++; } \
|
||||||
(asn).ls4b = new_ls4b; \
|
(asn).ls4b = new_ls4b; \
|
||||||
} while(0);
|
} while(0);
|
||||||
|
|
||||||
/* Decrement an ASN by inc (32 bits) */
|
/* Decrement an ASN by inc (32 bits) */
|
||||||
#define ASN_DEC(asn, dec) do { \
|
#define TSCH_ASN_DEC(asn, dec) do { \
|
||||||
uint32_t new_ls4b = (asn).ls4b - (dec); \
|
uint32_t new_ls4b = (asn).ls4b - (dec); \
|
||||||
if(new_ls4b > (asn).ls4b) { (asn).ms1b--; } \
|
if(new_ls4b > (asn).ls4b) { (asn).ms1b--; } \
|
||||||
(asn).ls4b = new_ls4b; \
|
(asn).ls4b = new_ls4b; \
|
||||||
} while(0);
|
} while(0);
|
||||||
|
|
||||||
/* Returns the 32-bit diff between asn1 and asn2 */
|
/* Returns the 32-bit diff between asn1 and asn2 */
|
||||||
#define ASN_DIFF(asn1, asn2) \
|
#define TSCH_ASN_DIFF(asn1, asn2) \
|
||||||
((asn1).ls4b - (asn2).ls4b)
|
((asn1).ls4b - (asn2).ls4b)
|
||||||
|
|
||||||
/* Initialize a struct asn_divisor_t */
|
/* Initialize a struct asn_divisor_t */
|
||||||
#define ASN_DIVISOR_INIT(div, val_) do { \
|
#define TSCH_ASN_DIVISOR_INIT(div, val_) do { \
|
||||||
(div).val = (val_); \
|
(div).val = (val_); \
|
||||||
(div).asn_ms1b_remainder = ((0xffffffff % (val_)) + 1) % (val_); \
|
(div).asn_ms1b_remainder = ((0xffffffff % (val_)) + 1) % (val_); \
|
||||||
} while(0);
|
} while(0);
|
||||||
|
|
||||||
/* Returns the result (16 bits) of a modulo operation on ASN,
|
/* Returns the result (16 bits) of a modulo operation on ASN,
|
||||||
* with divisor being a struct asn_divisor_t */
|
* with divisor being a struct asn_divisor_t */
|
||||||
#define ASN_MOD(asn, div) \
|
#define TSCH_ASN_MOD(asn, div) \
|
||||||
((uint16_t)((asn).ls4b % (div).val) \
|
((uint16_t)((asn).ls4b % (div).val) \
|
||||||
+ (uint16_t)((asn).ms1b * (div).asn_ms1b_remainder % (div).val)) \
|
+ (uint16_t)((asn).ms1b * (div).asn_ms1b_remainder % (div).val)) \
|
||||||
% (div).val
|
% (div).val
|
||||||
|
|
|
@ -174,7 +174,7 @@
|
||||||
#ifdef TSCH_CONF_ADAPTIVE_TIMESYNC
|
#ifdef TSCH_CONF_ADAPTIVE_TIMESYNC
|
||||||
#define TSCH_ADAPTIVE_TIMESYNC TSCH_CONF_ADAPTIVE_TIMESYNC
|
#define TSCH_ADAPTIVE_TIMESYNC TSCH_CONF_ADAPTIVE_TIMESYNC
|
||||||
#else
|
#else
|
||||||
#define TSCH_ADAPTIVE_TIMESYNC 0
|
#define TSCH_ADAPTIVE_TIMESYNC 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* HW frame filtering enabled */
|
/* HW frame filtering enabled */
|
||||||
|
|
|
@ -132,7 +132,7 @@ tsch_log_prepare_add(void)
|
||||||
int log_index = ringbufindex_peek_put(&log_ringbuf);
|
int log_index = ringbufindex_peek_put(&log_ringbuf);
|
||||||
if(log_index != -1) {
|
if(log_index != -1) {
|
||||||
struct tsch_log_t *log = &log_array[log_index];
|
struct tsch_log_t *log = &log_array[log_index];
|
||||||
log->asn = current_asn;
|
log->asn = tsch_current_asn;
|
||||||
log->link = current_link;
|
log->link = current_link;
|
||||||
return log;
|
return log;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -81,7 +81,7 @@ struct tsch_log_t {
|
||||||
tsch_log_rx,
|
tsch_log_rx,
|
||||||
tsch_log_message
|
tsch_log_message
|
||||||
} type;
|
} type;
|
||||||
struct asn_t asn;
|
struct tsch_asn_t asn;
|
||||||
struct tsch_link *link;
|
struct tsch_link *link;
|
||||||
union {
|
union {
|
||||||
char message[48];
|
char message[48];
|
||||||
|
|
|
@ -66,7 +66,7 @@
|
||||||
/* Construct enhanced ACK packet and return ACK length */
|
/* Construct enhanced ACK packet and return ACK length */
|
||||||
int
|
int
|
||||||
tsch_packet_create_eack(uint8_t *buf, int buf_size,
|
tsch_packet_create_eack(uint8_t *buf, int buf_size,
|
||||||
linkaddr_t *dest_addr, uint8_t seqno, int16_t drift, int nack)
|
const linkaddr_t *dest_addr, uint8_t seqno, int16_t drift, int nack)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
uint8_t curr_len = 0;
|
uint8_t curr_len = 0;
|
||||||
|
@ -85,12 +85,12 @@ tsch_packet_create_eack(uint8_t *buf, int buf_size,
|
||||||
p.seq = seqno;
|
p.seq = seqno;
|
||||||
#if TSCH_PACKET_EACK_WITH_DEST_ADDR
|
#if TSCH_PACKET_EACK_WITH_DEST_ADDR
|
||||||
if(dest_addr != NULL) {
|
if(dest_addr != NULL) {
|
||||||
p.fcf.dest_addr_mode = FRAME802154_LONGADDRMODE;
|
p.fcf.dest_addr_mode = LINKADDR_SIZE > 2 ? FRAME802154_LONGADDRMODE : FRAME802154_SHORTADDRMODE;;
|
||||||
linkaddr_copy((linkaddr_t *)&p.dest_addr, dest_addr);
|
linkaddr_copy((linkaddr_t *)&p.dest_addr, dest_addr);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if TSCH_PACKET_EACK_WITH_SRC_ADDR
|
#if TSCH_PACKET_EACK_WITH_SRC_ADDR
|
||||||
p.fcf.src_addr_mode = FRAME802154_LONGADDRMODE;
|
p.fcf.src_addr_mode = LINKADDR_SIZE > 2 ? FRAME802154_LONGADDRMODE : FRAME802154_SHORTADDRMODE;;
|
||||||
p.src_pid = IEEE802154_PANID;
|
p.src_pid = IEEE802154_PANID;
|
||||||
linkaddr_copy((linkaddr_t *)&p.src_addr, &linkaddr_node_addr);
|
linkaddr_copy((linkaddr_t *)&p.src_addr, &linkaddr_node_addr);
|
||||||
#endif
|
#endif
|
||||||
|
@ -189,7 +189,7 @@ tsch_packet_parse_eack(const uint8_t *buf, int buf_size,
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
/* Create an EB packet */
|
/* Create an EB packet */
|
||||||
int
|
int
|
||||||
tsch_packet_create_eb(uint8_t *buf, int buf_size, uint8_t seqno,
|
tsch_packet_create_eb(uint8_t *buf, int buf_size,
|
||||||
uint8_t *hdr_len, uint8_t *tsch_sync_ie_offset)
|
uint8_t *hdr_len, uint8_t *tsch_sync_ie_offset)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -208,10 +208,9 @@ tsch_packet_create_eb(uint8_t *buf, int buf_size, uint8_t seqno,
|
||||||
p.fcf.frame_type = FRAME802154_BEACONFRAME;
|
p.fcf.frame_type = FRAME802154_BEACONFRAME;
|
||||||
p.fcf.ie_list_present = 1;
|
p.fcf.ie_list_present = 1;
|
||||||
p.fcf.frame_version = FRAME802154_IEEE802154E_2012;
|
p.fcf.frame_version = FRAME802154_IEEE802154E_2012;
|
||||||
p.fcf.src_addr_mode = FRAME802154_LONGADDRMODE;
|
p.fcf.src_addr_mode = LINKADDR_SIZE > 2 ? FRAME802154_LONGADDRMODE : FRAME802154_SHORTADDRMODE;
|
||||||
p.fcf.dest_addr_mode = FRAME802154_SHORTADDRMODE;
|
p.fcf.dest_addr_mode = FRAME802154_SHORTADDRMODE;
|
||||||
p.seq = seqno;
|
p.fcf.sequence_number_suppression = 1;
|
||||||
p.fcf.sequence_number_suppression = FRAME802154_SUPPR_SEQNO;
|
|
||||||
/* It is important not to compress PAN ID, as this would result in not including either
|
/* It is important not to compress PAN ID, as this would result in not including either
|
||||||
* source nor destination PAN ID, leaving potential joining devices unaware of the PAN ID. */
|
* source nor destination PAN ID, leaving potential joining devices unaware of the PAN ID. */
|
||||||
p.fcf.panid_compression = 0;
|
p.fcf.panid_compression = 0;
|
||||||
|
@ -339,7 +338,7 @@ int
|
||||||
tsch_packet_update_eb(uint8_t *buf, int buf_size, uint8_t tsch_sync_ie_offset)
|
tsch_packet_update_eb(uint8_t *buf, int buf_size, uint8_t tsch_sync_ie_offset)
|
||||||
{
|
{
|
||||||
struct ieee802154_ies ies;
|
struct ieee802154_ies ies;
|
||||||
ies.ie_asn = current_asn;
|
ies.ie_asn = tsch_current_asn;
|
||||||
ies.ie_join_priority = tsch_join_priority;
|
ies.ie_join_priority = tsch_join_priority;
|
||||||
frame80215e_create_ie_tsch_synchronization(buf+tsch_sync_ie_offset, buf_size-tsch_sync_ie_offset, &ies);
|
frame80215e_create_ie_tsch_synchronization(buf+tsch_sync_ie_offset, buf_size-tsch_sync_ie_offset, &ies);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -88,13 +88,13 @@ by default, useful in case of duplicate seqno */
|
||||||
|
|
||||||
/* Construct enhanced ACK packet and return ACK length */
|
/* Construct enhanced ACK packet and return ACK length */
|
||||||
int tsch_packet_create_eack(uint8_t *buf, int buf_size,
|
int tsch_packet_create_eack(uint8_t *buf, int buf_size,
|
||||||
linkaddr_t *dest_addr, uint8_t seqno, int16_t drift, int nack);
|
const linkaddr_t *dest_addr, uint8_t seqno, int16_t drift, int nack);
|
||||||
/* Parse enhanced ACK packet, extract drift and nack */
|
/* Parse enhanced ACK packet, extract drift and nack */
|
||||||
int tsch_packet_parse_eack(const uint8_t *buf, int buf_size,
|
int tsch_packet_parse_eack(const uint8_t *buf, int buf_size,
|
||||||
uint8_t seqno, frame802154_t *frame, struct ieee802154_ies *ies, uint8_t *hdr_len);
|
uint8_t seqno, frame802154_t *frame, struct ieee802154_ies *ies, uint8_t *hdr_len);
|
||||||
/* Create an EB packet */
|
/* Create an EB packet */
|
||||||
int tsch_packet_create_eb(uint8_t *buf, int buf_size,
|
int tsch_packet_create_eb(uint8_t *buf, int buf_size,
|
||||||
uint8_t seqno, uint8_t *hdr_len, uint8_t *tsch_sync_ie_ptr);
|
uint8_t *hdr_len, uint8_t *tsch_sync_ie_ptr);
|
||||||
/* Update ASN in EB packet */
|
/* Update ASN in EB packet */
|
||||||
int tsch_packet_update_eb(uint8_t *buf, int buf_size, uint8_t tsch_sync_ie_offset);
|
int tsch_packet_update_eb(uint8_t *buf, int buf_size, uint8_t tsch_sync_ie_offset);
|
||||||
/* Parse EB and extract ASN and join priority */
|
/* Parse EB and extract ASN and join priority */
|
||||||
|
|
|
@ -48,6 +48,10 @@
|
||||||
#include "net/linkaddr.h"
|
#include "net/linkaddr.h"
|
||||||
#include "net/mac/tsch/tsch-asn.h"
|
#include "net/mac/tsch/tsch-asn.h"
|
||||||
#include "net/mac/tsch/tsch-conf.h"
|
#include "net/mac/tsch/tsch-conf.h"
|
||||||
|
#if CONTIKI_TARGET_COOJA || CONTIKI_TARGET_COOJA_IP64
|
||||||
|
#include "lib/simEnvChange.h"
|
||||||
|
#include "sys/cooja_mt.h"
|
||||||
|
#endif /* CONTIKI_TARGET_COOJA || CONTIKI_TARGET_COOJA_IP64 */
|
||||||
|
|
||||||
/************ Types ***********/
|
/************ Types ***********/
|
||||||
|
|
||||||
|
@ -76,12 +80,12 @@ extern const linkaddr_t tsch_broadcast_address;
|
||||||
/* The address we use to identify EB queue */
|
/* The address we use to identify EB queue */
|
||||||
extern const linkaddr_t tsch_eb_address;
|
extern const linkaddr_t tsch_eb_address;
|
||||||
/* The current Absolute Slot Number (ASN) */
|
/* The current Absolute Slot Number (ASN) */
|
||||||
extern struct asn_t current_asn;
|
extern struct tsch_asn_t tsch_current_asn;
|
||||||
extern uint8_t tsch_join_priority;
|
extern uint8_t tsch_join_priority;
|
||||||
extern struct tsch_link *current_link;
|
extern struct tsch_link *current_link;
|
||||||
/* TSCH channel hopping sequence */
|
/* TSCH channel hopping sequence */
|
||||||
extern uint8_t tsch_hopping_sequence[TSCH_HOPPING_SEQUENCE_MAX_LEN];
|
extern uint8_t tsch_hopping_sequence[TSCH_HOPPING_SEQUENCE_MAX_LEN];
|
||||||
extern struct asn_divisor_t tsch_hopping_sequence_length;
|
extern struct tsch_asn_divisor_t tsch_hopping_sequence_length;
|
||||||
/* TSCH timeslot timing (in rtimer ticks) */
|
/* TSCH timeslot timing (in rtimer ticks) */
|
||||||
extern rtimer_clock_t tsch_timing[tsch_ts_elements_count];
|
extern rtimer_clock_t tsch_timing[tsch_ts_elements_count];
|
||||||
|
|
||||||
|
@ -109,7 +113,14 @@ void tsch_disassociate(void);
|
||||||
#define TSCH_CLOCK_TO_SLOTS(c, timeslot_length) (TSCH_CLOCK_TO_TICKS(c) / timeslot_length)
|
#define TSCH_CLOCK_TO_SLOTS(c, timeslot_length) (TSCH_CLOCK_TO_TICKS(c) / timeslot_length)
|
||||||
|
|
||||||
/* Wait for a condition with timeout t0+offset. */
|
/* Wait for a condition with timeout t0+offset. */
|
||||||
|
#if CONTIKI_TARGET_COOJA || CONTIKI_TARGET_COOJA_IP64
|
||||||
|
#define BUSYWAIT_UNTIL_ABS(cond, t0, offset) \
|
||||||
|
while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), (t0) + (offset))) { \
|
||||||
|
simProcessRunValue = 1; \
|
||||||
|
cooja_mt_yield(); \
|
||||||
|
};
|
||||||
|
#else
|
||||||
#define BUSYWAIT_UNTIL_ABS(cond, t0, offset) \
|
#define BUSYWAIT_UNTIL_ABS(cond, t0, offset) \
|
||||||
while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), (t0) + (offset))) ;
|
while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), (t0) + (offset))) ;
|
||||||
|
#endif /* CONTIKI_TARGET_COOJA || CONTIKI_TARGET_COOJA_IP64 */
|
||||||
#endif /* __TSCH_PRIVATE_H__ */
|
#endif /* __TSCH_PRIVATE_H__ */
|
||||||
|
|
|
@ -163,6 +163,13 @@ tsch_queue_update_time_source(const linkaddr_t *new_addr)
|
||||||
/* Update time source */
|
/* Update time source */
|
||||||
if(new_time_src != NULL) {
|
if(new_time_src != NULL) {
|
||||||
new_time_src->is_time_source = 1;
|
new_time_src->is_time_source = 1;
|
||||||
|
/* (Re)set keep-alive timeout */
|
||||||
|
tsch_set_ka_timeout(TSCH_KEEPALIVE_TIMEOUT);
|
||||||
|
/* Start sending keepalives */
|
||||||
|
tsch_schedule_keepalive();
|
||||||
|
} else {
|
||||||
|
/* Stop sending keepalives */
|
||||||
|
tsch_set_ka_timeout(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(old_time_src != NULL) {
|
if(old_time_src != NULL) {
|
||||||
|
@ -195,6 +202,7 @@ tsch_queue_flush_nbr_queue(struct tsch_neighbor *n)
|
||||||
/* Free packet queuebuf */
|
/* Free packet queuebuf */
|
||||||
tsch_queue_free_packet(p);
|
tsch_queue_free_packet(p);
|
||||||
}
|
}
|
||||||
|
PRINTF("TSCH-queue: packet is deleted packet=%p\n", p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
@ -246,6 +254,8 @@ tsch_queue_add_packet(const linkaddr_t *addr, mac_callback_t sent, void *ptr)
|
||||||
/* Add to ringbuf (actual add committed through atomic operation) */
|
/* Add to ringbuf (actual add committed through atomic operation) */
|
||||||
n->tx_array[put_index] = p;
|
n->tx_array[put_index] = p;
|
||||||
ringbufindex_put(&n->tx_ringbuf);
|
ringbufindex_put(&n->tx_ringbuf);
|
||||||
|
PRINTF("TSCH-queue: packet is added put_index=%u, packet=%p\n",
|
||||||
|
put_index, p);
|
||||||
return p;
|
return p;
|
||||||
} else {
|
} else {
|
||||||
memb_free(&packet_memb, p);
|
memb_free(&packet_memb, p);
|
||||||
|
@ -281,6 +291,7 @@ tsch_queue_remove_packet_from_queue(struct tsch_neighbor *n)
|
||||||
/* Get and remove packet from ringbuf (remove committed through an atomic operation */
|
/* Get and remove packet from ringbuf (remove committed through an atomic operation */
|
||||||
int16_t get_index = ringbufindex_get(&n->tx_ringbuf);
|
int16_t get_index = ringbufindex_get(&n->tx_ringbuf);
|
||||||
if(get_index != -1) {
|
if(get_index != -1) {
|
||||||
|
PRINTF("TSCH-queue: packet is removed, get_index=%u\n", get_index);
|
||||||
return n->tx_array[get_index];
|
return n->tx_array[get_index];
|
||||||
} else {
|
} else {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -85,7 +85,7 @@ tsch_rpl_callback_new_dio_interval(uint8_t dio_interval)
|
||||||
tsch_set_coordinator(1);
|
tsch_set_coordinator(1);
|
||||||
}
|
}
|
||||||
/* Set EB period */
|
/* Set EB period */
|
||||||
tsch_set_eb_period(TSCH_EB_PERIOD);
|
tsch_set_eb_period((CLOCK_SECOND * 1UL << dag->instance->dio_intcurrent) / 1000);
|
||||||
/* Set join priority based on RPL rank */
|
/* Set join priority based on RPL rank */
|
||||||
tsch_set_join_priority(DAG_RANK(dag->rank, dag->instance) - 1);
|
tsch_set_join_priority(DAG_RANK(dag->rank, dag->instance) - 1);
|
||||||
} else {
|
} else {
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue