Compare commits
1693 Commits
master_at_
...
v2.1.3-amb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6297b80812 | ||
|
|
5d6edaaaf0 | ||
|
|
26fed6b1a7 | ||
|
|
be44894e32 | ||
|
|
57abad9790 | ||
|
|
3bf1dde1df | ||
|
|
6ca936f6b5 | ||
|
|
e7b74570d9 | ||
|
|
018c64ab94 | ||
|
|
7e92fb3d7f | ||
|
|
051fbea5e6 | ||
|
|
214e2d90f3 | ||
|
|
4022a19cbc | ||
|
|
a32ea1e793 | ||
|
|
f67f2692d4 | ||
|
|
3b745f7154 | ||
|
|
d876d3c4df | ||
|
|
e8b0c52806 | ||
|
|
5bd7518343 | ||
|
|
51265f3f7d | ||
|
|
2e4932f23b | ||
|
|
dbd0bc8a2c | ||
|
|
e5627ec649 | ||
|
|
5c8fd3158d | ||
|
|
d5843944cc | ||
|
|
f62be85576 | ||
|
|
f1bd63046e | ||
|
|
ed6c951a19 | ||
|
|
ad9e7a6d87 | ||
|
|
6f7b26b1a8 | ||
|
|
ecd6009a5e | ||
|
|
6ffe30d9ba | ||
|
|
8f5a0aaacb | ||
|
|
ba3b04e7fe | ||
|
|
379d55044e | ||
|
|
843a116155 | ||
|
|
1c6202c414 | ||
|
|
066a2b022d | ||
|
|
aca41b0beb | ||
|
|
b5e8ab6c15 | ||
|
|
896c8a9f72 | ||
|
|
59ecea3d8c | ||
|
|
b1f8ce8769 | ||
|
|
8c43d83689 | ||
|
|
87d44bbfcd | ||
|
|
07d3b3330d | ||
|
|
61349cf124 | ||
|
|
7316b26740 | ||
|
|
d4b3a006dc | ||
|
|
2f8886794f | ||
|
|
02ab8c91a9 | ||
|
|
74ea1e43ca | ||
|
|
e9000658fb | ||
|
|
d58e0f1a1a | ||
|
|
674c4ed080 | ||
|
|
a68d6f1a9a | ||
|
|
c0643e21ed | ||
|
|
3fbb84f950 | ||
|
|
053f5aa10d | ||
|
|
6b9264b49e | ||
|
|
e60f9bb24f | ||
|
|
1bb6e7f52d | ||
|
|
108ca1521e | ||
|
|
ea2bb9cd5b | ||
|
|
e6d05db86f | ||
|
|
d1f920a7d1 | ||
|
|
fee64d7515 | ||
|
|
aad77fcacb | ||
|
|
bebf072b77 | ||
|
|
7f53f7ced4 | ||
|
|
91a4d59eb4 | ||
|
|
1bd34ea364 | ||
|
|
a9a215c52e | ||
|
|
5cea646b12 | ||
|
|
ff14bbb3c1 | ||
|
|
89be04ce7a | ||
|
|
4b3c59e4cc | ||
|
|
beeb300c18 | ||
|
|
79732693f3 | ||
|
|
ef3d12c60e | ||
|
|
608a2f9741 | ||
|
|
174cc87227 | ||
|
|
0d6d8922f2 | ||
|
|
67350e3c01 | ||
|
|
1a6455bc25 | ||
|
|
e1528e084d | ||
|
|
1892f445e2 | ||
|
|
484f0fbafa | ||
|
|
5378fd84df | ||
|
|
9d8b8d9c69 | ||
|
|
cd91647999 | ||
|
|
5cc46d7989 | ||
|
|
fe4395336a | ||
|
|
9d97a467ca | ||
|
|
039056370d | ||
|
|
159e31b689 | ||
|
|
17c60d2728 | ||
|
|
52e75369c1 | ||
|
|
66706f469d | ||
|
|
98d1cb1c00 | ||
|
|
1940cae827 | ||
|
|
d184463e2a | ||
|
|
3b53b6e481 | ||
|
|
78ee1ee2cf | ||
|
|
422623a87b | ||
|
|
4aa6df7633 | ||
|
|
2d2336014c | ||
|
|
def427bcaf | ||
|
|
ba3a39957d | ||
|
|
f58324b576 | ||
|
|
205cd7c1f6 | ||
|
|
398333da9a | ||
|
|
e678219bdf | ||
|
|
830217ac78 | ||
|
|
e4db22d9f5 | ||
|
|
c8e9772cd0 | ||
|
|
437b11f869 | ||
|
|
b7bee87fb5 | ||
|
|
2f3ef94ad4 | ||
|
|
7154e51ff2 | ||
|
|
db46863f75 | ||
|
|
ebb0dc14a7 | ||
|
|
368128a647 | ||
|
|
bc25863d1b | ||
|
|
130f947037 | ||
|
|
e6a8415df3 | ||
|
|
54a8112eb9 | ||
|
|
b9fc8cae68 | ||
|
|
a044c807f8 | ||
|
|
6229f9ef71 | ||
|
|
66838a70f3 | ||
|
|
dea74a24aa | ||
|
|
effdeef2fe | ||
|
|
c18df357d9 | ||
|
|
74c5ac7302 | ||
|
|
0189e7b02f | ||
|
|
796f98beb2 | ||
|
|
fc24d4139f | ||
|
|
bbf80b05c8 | ||
|
|
bc48eb512e | ||
|
|
cdfa3dfa9d | ||
|
|
be18fa98e4 | ||
|
|
257dc1d6fd | ||
|
|
236d6df495 | ||
|
|
93b2074f2b | ||
|
|
7749088a83 | ||
|
|
24fc93e12f | ||
|
|
264b89764d | ||
|
|
fa3826a1d3 | ||
|
|
dac4cb05f7 | ||
|
|
7b7bc349ae | ||
|
|
bcd6c8a2d3 | ||
|
|
0674aa60fe | ||
|
|
e351937ea4 | ||
|
|
e8683ea9df | ||
|
|
6363edc1db | ||
|
|
a19ea8b8d6 | ||
|
|
aafc0adfe1 | ||
|
|
298951c738 | ||
|
|
258cab1b22 | ||
|
|
c3d8b1ca80 | ||
|
|
b5b31d86b2 | ||
|
|
5bef7ea72f | ||
|
|
633205ba78 | ||
|
|
eeb2218b3d | ||
|
|
0985e925a1 | ||
|
|
cffb5cc087 | ||
|
|
8b4a8159a8 | ||
|
|
4e74421dac | ||
|
|
cd1dd4f5b1 | ||
|
|
8841fdc8ea | ||
|
|
02d6716ffd | ||
|
|
07dd2aec23 | ||
|
|
cf330c50e6 | ||
|
|
d3191e4835 | ||
|
|
29364d2a50 | ||
|
|
d65681a7d7 | ||
|
|
7b8a784c4f | ||
|
|
d73efd7d38 | ||
|
|
596f742066 | ||
|
|
2bd1e313b9 | ||
|
|
341623c8be | ||
|
|
dccdbdd309 | ||
|
|
82fc0e8937 | ||
|
|
2d65251c6c | ||
|
|
b398a2a394 | ||
|
|
eeee2b1c55 | ||
|
|
9b638e7c05 | ||
|
|
58be2b1573 | ||
|
|
e942818940 | ||
|
|
88ef663334 | ||
|
|
fd0af07d2d | ||
|
|
1e24f9c9cd | ||
|
|
19a929f5fb | ||
|
|
cc8995823a | ||
|
|
af2cbad64a | ||
|
|
8090afa4f9 | ||
|
|
4506db4331 | ||
|
|
814341a6ed | ||
|
|
11e82e5355 | ||
|
|
6067edfed3 | ||
|
|
9f1196fb53 | ||
|
|
8223a8c73c | ||
|
|
b1487e6480 | ||
|
|
0610b34372 | ||
|
|
0c209dba4b | ||
|
|
f3e14585ad | ||
|
|
8435fbb048 | ||
|
|
4027a2ae58 | ||
|
|
a56e61c942 | ||
|
|
d80e84864e | ||
|
|
0acf37fd75 | ||
|
|
58f928a181 | ||
|
|
b9b74b2d92 | ||
|
|
fb21bc1609 | ||
|
|
9992b48e90 | ||
|
|
824ebbe0e9 | ||
|
|
3cdfc67dd8 | ||
|
|
7577e587be | ||
|
|
ce16f8c498 | ||
|
|
871f27628b | ||
|
|
e4e0fc4193 | ||
|
|
58b5a5fc5a | ||
|
|
a057caee45 | ||
|
|
dbc16e6765 | ||
|
|
f31160a6cb | ||
|
|
738a2fe846 | ||
|
|
5278202f66 | ||
|
|
98008cb1ab | ||
|
|
a56519032e | ||
|
|
047c3c6528 | ||
|
|
5b8760601b | ||
|
|
b9fe13c105 | ||
|
|
a48ff4aaf2 | ||
|
|
a51c92b617 | ||
|
|
6ac21515ca | ||
|
|
e61b925709 | ||
|
|
944f286d87 | ||
|
|
39faa8f61d | ||
|
|
313664c59c | ||
|
|
7c03f4cf46 | ||
|
|
b0e5eeb7d2 | ||
|
|
1bdc669b45 | ||
|
|
47ebb2b267 | ||
|
|
a9d6ea5953 | ||
|
|
66f7f06601 | ||
|
|
8e23b8d903 | ||
|
|
a75332a407 | ||
|
|
25497bb387 | ||
|
|
38614e4f3e | ||
|
|
61e3f49f69 | ||
|
|
3f2227f04c | ||
|
|
392c676ef5 | ||
|
|
0c5133d7cf | ||
|
|
eb91fdd861 | ||
|
|
a26a2e1340 | ||
|
|
1bf323e12f | ||
|
|
e7c0619189 | ||
|
|
31bc2f9b20 | ||
|
|
342d0eadfb | ||
|
|
6ea2483546 | ||
|
|
1fd145fbc9 | ||
|
|
2837bb310c | ||
|
|
288d3c2802 | ||
|
|
f8e7cccf21 | ||
|
|
31e07f90bd | ||
|
|
4fa33c17bc | ||
|
|
1a294622d0 | ||
|
|
fd050b8a97 | ||
|
|
d4845abac6 | ||
|
|
ab922582dc | ||
|
|
b1ffb3a8d3 | ||
|
|
d996d0f486 | ||
|
|
11c294e973 | ||
|
|
0c2fdfcf42 | ||
|
|
0f165ff136 | ||
|
|
8f3df7c862 | ||
|
|
ec8c764fcb | ||
|
|
795f05c5d3 | ||
|
|
ffaee59f3e | ||
|
|
070e449690 | ||
|
|
a445172661 | ||
|
|
059bc952f6 | ||
|
|
f116bc37d1 | ||
|
|
9672b4c3af | ||
|
|
ab5bc1e766 | ||
|
|
d40c3251d7 | ||
|
|
ad8e08a08b | ||
|
|
c61a0570b1 | ||
|
|
2291f9a8fa | ||
|
|
e05a96550f | ||
|
|
b2ef9d9046 | ||
|
|
373bf8c36d | ||
|
|
c34120e855 | ||
|
|
91bc7a02c9 | ||
|
|
4355a23ad2 | ||
|
|
b60df2df20 | ||
|
|
b2948c08f7 | ||
|
|
d4ee483280 | ||
|
|
9fd8222479 | ||
|
|
9980d09bc8 | ||
|
|
4b3e996617 | ||
|
|
4a22d6d5a2 | ||
|
|
7d1c6ba549 | ||
|
|
d320b27a5f | ||
|
|
ef3073aaf9 | ||
|
|
71c13c6079 | ||
|
|
3abc8ae161 | ||
|
|
41fea4ad7d | ||
|
|
1090e9cdec | ||
|
|
b1fe8cf4b8 | ||
|
|
f65911a84b | ||
|
|
66800925cf | ||
|
|
533c97f0c3 | ||
|
|
e935faf2bc | ||
|
|
fa55458c42 | ||
|
|
4cc953d0e3 | ||
|
|
ffdd44ec74 | ||
|
|
b0ae967660 | ||
|
|
82d8f08451 | ||
|
|
e46b9ad4ac | ||
|
|
2d4da92eeb | ||
|
|
81acaf0ff1 | ||
|
|
b693056bb6 | ||
|
|
97a9fe1b10 | ||
|
|
e9ee3c4b58 | ||
|
|
8adfc730ec | ||
|
|
ac03107036 | ||
|
|
a4b9beef04 | ||
|
|
c974fc9d43 | ||
|
|
c881c48eed | ||
|
|
600527dde7 | ||
|
|
e19d908f0e | ||
|
|
104a629a51 | ||
|
|
d79416eee6 | ||
|
|
6070a7ef6a | ||
|
|
08bcfa2b29 | ||
|
|
0074022bb5 | ||
|
|
10ae311a93 | ||
|
|
909037c2ca | ||
|
|
16afe566ff | ||
|
|
253fcc8dcd | ||
|
|
8d8572354b | ||
|
|
b86f9b97e0 | ||
|
|
61a1b98cc9 | ||
|
|
972f32dd47 | ||
|
|
971404ff90 | ||
|
|
0411332856 | ||
|
|
b6d9bb6b2a | ||
|
|
91a2d9e237 | ||
|
|
5474498f7e | ||
|
|
b28e979739 | ||
|
|
53ddb9244b | ||
|
|
b1258bf8e6 | ||
|
|
91038e4979 | ||
|
|
08bf8b7121 | ||
|
|
282e1601ef | ||
|
|
ab0e457066 | ||
|
|
a137e16ff8 | ||
|
|
6e62baaa6c | ||
|
|
cb746a1aea | ||
|
|
fcccc47be4 | ||
|
|
002ba1a66b | ||
|
|
43778e5334 | ||
|
|
43a55003da | ||
|
|
d9770d2c5f | ||
|
|
3a8af612b3 | ||
|
|
2a5b66c9b1 | ||
|
|
3a93029e92 | ||
|
|
fe68fa49f7 | ||
|
|
5e91cd47c9 | ||
|
|
4f059fea76 | ||
|
|
569464ffd3 | ||
|
|
6e6eb620df | ||
|
|
3c71e3fc77 | ||
|
|
2e2c607727 | ||
|
|
49acdae8d0 | ||
|
|
7db978ca03 | ||
|
|
731b83ac5f | ||
|
|
fb5bbca1d9 | ||
|
|
a022590f40 | ||
|
|
c28aa02820 | ||
|
|
e7766297de | ||
|
|
265f6f5047 | ||
|
|
7697a45405 | ||
|
|
59e98ccb19 | ||
|
|
56124bf53b | ||
|
|
a3034a442b | ||
|
|
2ce3c79ec5 | ||
|
|
a8d789e7b3 | ||
|
|
c510e92cf4 | ||
|
|
69eaafecca | ||
|
|
10209ee788 | ||
|
|
f595445ec0 | ||
|
|
aa04944ae0 | ||
|
|
d2ee10977f | ||
|
|
7ad680c2bf | ||
|
|
7d007cfee5 | ||
|
|
8600259a78 | ||
|
|
76a13054ee | ||
|
|
37b4494921 | ||
|
|
0ee0393936 | ||
|
|
fe3bb8bb78 | ||
|
|
e93cecf527 | ||
|
|
1f0867299d | ||
|
|
7b9e145fc5 | ||
|
|
2753eb1fb1 | ||
|
|
a0e900dd02 | ||
|
|
325cdf3c0b | ||
|
|
a7b43dae49 | ||
|
|
d66c0e3381 | ||
|
|
bcff67b00e | ||
|
|
3bd87e3815 | ||
|
|
333fff3e66 | ||
|
|
fc3c186289 | ||
|
|
3a41f4fe8a | ||
|
|
e9bd31b190 | ||
|
|
a894140bb0 | ||
|
|
842b9f4429 | ||
|
|
5b33d33e34 | ||
|
|
2501913cde | ||
|
|
47c55c3d96 | ||
|
|
ef29f2d401 | ||
|
|
ca0a356221 | ||
|
|
e6f0700c81 | ||
|
|
b5448a86fd | ||
|
|
5b459c1282 | ||
|
|
2b09c18c4e | ||
|
|
2648d30843 | ||
|
|
bd656efd64 | ||
|
|
e87392cc85 | ||
|
|
3dafa72ec8 | ||
|
|
d4c4b0eec5 | ||
|
|
58de2af5f2 | ||
|
|
cd1516e2e4 | ||
|
|
216f21dcd1 | ||
|
|
5d5b8fbb46 | ||
|
|
133bf70ab5 | ||
|
|
eea95459c9 | ||
|
|
546a8c4860 | ||
|
|
e926779510 | ||
|
|
731336223f | ||
|
|
618a28fc53 | ||
|
|
2390eb6826 | ||
|
|
5ee77262bc | ||
|
|
bcb6819715 | ||
|
|
d4047ea1d1 | ||
|
|
e20e9bc3d4 | ||
|
|
d5d635cdce | ||
|
|
47946a29e9 | ||
|
|
b5e67f142a | ||
|
|
7b6d2870ca | ||
|
|
cff31ba5de | ||
|
|
093adf8322 | ||
|
|
8fa55e32d2 | ||
|
|
010b0210ba | ||
|
|
f201d261b2 | ||
|
|
3cf906e073 | ||
|
|
d785561eae | ||
|
|
f7be3d10ae | ||
|
|
e8d7e82c8c | ||
|
|
f9300c1fb0 | ||
|
|
6934bb4428 | ||
|
|
030ffdee82 | ||
|
|
b1b6275110 | ||
|
|
fe828634ac | ||
|
|
dc882801bb | ||
|
|
2a4dd0dc7b | ||
|
|
f9bc3cae5d | ||
|
|
c6b5527710 | ||
|
|
9d087ad2d2 | ||
|
|
ea2e628ac3 | ||
|
|
1a75112b47 | ||
|
|
053a5e6e13 | ||
|
|
d5d30d49f2 | ||
|
|
23c933fd16 | ||
|
|
d6e58d02a6 | ||
|
|
6706b3778e | ||
|
|
ab281cb750 | ||
|
|
7edbd95b50 | ||
|
|
31c71fee46 | ||
|
|
fa9082116f | ||
|
|
77d0ee0961 | ||
|
|
0e85582bc0 | ||
|
|
ebe782ba16 | ||
|
|
ce79811bce | ||
|
|
61671d6df0 | ||
|
|
9fb86f6e4b | ||
|
|
2c3c578475 | ||
|
|
64a351cbe0 | ||
|
|
0ee7a39594 | ||
|
|
424c33bcb7 | ||
|
|
9128a51944 | ||
|
|
1570dd8ad1 | ||
|
|
fdbc9f9b32 | ||
|
|
dd6c43ecbd | ||
|
|
ad3937df58 | ||
|
|
c597cfd6ca | ||
|
|
40997c4a08 | ||
|
|
83ff2014ae | ||
|
|
d6cf8a3e38 | ||
|
|
93f9c56c32 | ||
|
|
05ba509e33 | ||
|
|
de68c5bed6 | ||
|
|
6606c4013f | ||
|
|
fe2c249fb7 | ||
|
|
ebda5cb04e | ||
|
|
5b75ad9019 | ||
|
|
84fcd6290e | ||
|
|
76826c1622 | ||
|
|
9dbfa9ca0a | ||
|
|
a696b2b515 | ||
|
|
a7a8d9273c | ||
|
|
9cf6bbf573 | ||
|
|
2fd2b6810e | ||
|
|
d12d6abae8 | ||
|
|
f3c289d966 | ||
|
|
8a27408eb2 | ||
|
|
42f14a96fb | ||
|
|
c7106cc57f | ||
|
|
30ddfe1a98 | ||
|
|
51369854b5 | ||
|
|
72fc4a6ca5 | ||
|
|
2fd83c9d2e | ||
|
|
330793d94d | ||
|
|
28c8693683 | ||
|
|
f343a67b40 | ||
|
|
e645d00484 | ||
|
|
4a99721751 | ||
|
|
734b6ab57a | ||
|
|
fa75ffed9d | ||
|
|
452c6a5378 | ||
|
|
d115b28057 | ||
|
|
0b2b22338a | ||
|
|
eb51b683ed | ||
|
|
94ad523357 | ||
|
|
46cb0a796b | ||
|
|
653313cb37 | ||
|
|
67ad6e45db | ||
|
|
990c25d4f3 | ||
|
|
6ccd12b97c | ||
|
|
eab1b45cba | ||
|
|
b6b14438b7 | ||
|
|
c257b56a39 | ||
|
|
39ada6ec0e | ||
|
|
2d06483d8e | ||
|
|
deab51c36d | ||
|
|
0795e289eb | ||
|
|
efa90d4294 | ||
|
|
05ded5516d | ||
|
|
1affbb4bd5 | ||
|
|
8801cbdb30 | ||
|
|
d7566216c9 | ||
|
|
bb0ba64fb0 | ||
|
|
5eced48869 | ||
|
|
b6c0c52d66 | ||
|
|
b4768f1711 | ||
|
|
bbb2e50327 | ||
|
|
3f30bfae28 | ||
|
|
a31f8837b5 | ||
|
|
eaca067c7d | ||
|
|
2b4dde84e3 | ||
|
|
dd3861720f | ||
|
|
da2478b761 | ||
|
|
e415151cf2 | ||
|
|
40c0f21b9e | ||
|
|
c4867b878c | ||
|
|
8fc20142f7 | ||
|
|
1623c3e2cc | ||
|
|
8de4900641 | ||
|
|
8542556a03 | ||
|
|
756b7431a7 | ||
|
|
40fecab313 | ||
|
|
b16f5f0e19 | ||
|
|
6b2ef1a89b | ||
|
|
2cb220d7fe | ||
|
|
25f1c6ef2c | ||
|
|
3b79c60e41 | ||
|
|
01e227d2c0 | ||
|
|
913a7e0638 | ||
|
|
744e69334d | ||
|
|
fa345b0f22 | ||
|
|
004b13ca09 | ||
|
|
d569a22c73 | ||
|
|
d87740bb96 | ||
|
|
1c7a024297 | ||
|
|
53499f5e9f | ||
|
|
04b983b4f3 | ||
|
|
f334ac68b6 | ||
|
|
10c50dffce | ||
|
|
b33b3bb8bb | ||
|
|
36d160686a | ||
|
|
dfd6a31ecb | ||
|
|
a8755b8530 | ||
|
|
c20d50acec | ||
|
|
6c7e7153bc | ||
|
|
b536fd9767 | ||
|
|
1b57284bb4 | ||
|
|
a98d3a4efb | ||
|
|
e77099673c | ||
|
|
27ca731242 | ||
|
|
8f6b876ef9 | ||
|
|
61e90d9fc0 | ||
|
|
4cfef8acab | ||
|
|
5b9f79680c | ||
|
|
c6887522fe | ||
|
|
b07a481f66 | ||
|
|
7c1f844782 | ||
|
|
2505c6019e | ||
|
|
db68c6df6a | ||
|
|
50a5d85f45 | ||
|
|
31c60775b6 | ||
|
|
0527c1bdf5 | ||
|
|
df563e74f9 | ||
|
|
892e30d8c1 | ||
|
|
4c90858482 | ||
|
|
82483073f0 | ||
|
|
ba270c2414 | ||
|
|
920ee2d07e | ||
|
|
60063b98e1 | ||
|
|
ec9f227eae | ||
|
|
eb30dbfdc5 | ||
|
|
975e23bf5e | ||
|
|
2ceedfe097 | ||
|
|
ad47a46815 | ||
|
|
32788f2c74 | ||
|
|
f8f31218d1 | ||
|
|
6e624f8035 | ||
|
|
0397ff9ba4 | ||
|
|
6cbee37a58 | ||
|
|
5cd6c38893 | ||
|
|
b48106c662 | ||
|
|
5500a36b29 | ||
|
|
444dfeada8 | ||
|
|
5dc3072af8 | ||
|
|
26f55f1eb3 | ||
|
|
839e5ecec6 | ||
|
|
cdabdcb00d | ||
|
|
ebcae98ae6 | ||
|
|
6af3b4accc | ||
|
|
2aed2fc215 | ||
|
|
8b6bb1a503 | ||
|
|
f5c37c8cbb | ||
|
|
d99144eef1 | ||
|
|
2ff0ef027e | ||
|
|
8c6884b2db | ||
|
|
0853d1e7d1 | ||
|
|
db3a4e3158 | ||
|
|
2b309bd1ae | ||
|
|
fa73f130f1 | ||
|
|
926805bcf1 | ||
|
|
1e0501c31a | ||
|
|
b0344518e8 | ||
|
|
da01bc4d15 | ||
|
|
8bd670430a | ||
|
|
5d6b39f1ce | ||
|
|
c47d161d4a | ||
|
|
40a563cdd3 | ||
|
|
d20a7aba0c | ||
|
|
a73eb7ae72 | ||
|
|
5290eacf08 | ||
|
|
245a6835f3 | ||
|
|
bd2e820829 | ||
|
|
6ef5f68c72 | ||
|
|
1fdc7571e0 | ||
|
|
2c1a152880 | ||
|
|
a56ea1b19f | ||
|
|
1a1478551e | ||
|
|
a82054d24f | ||
|
|
1665fcba83 | ||
|
|
365e031340 | ||
|
|
1147b9ce38 | ||
|
|
637bce91b4 | ||
|
|
d864f8c3a3 | ||
|
|
7a241b6b52 | ||
|
|
a8acca5902 | ||
|
|
a78dbb25c5 | ||
|
|
d8b6cdffcb | ||
|
|
41cf4012af | ||
|
|
c1efb9e296 | ||
|
|
7eb462867b | ||
|
|
849dfb17c7 | ||
|
|
93f4245e89 | ||
|
|
a9a3d473ac | ||
|
|
de991b1158 | ||
|
|
472f7985b5 | ||
|
|
d39e8cd827 | ||
|
|
08ec234127 | ||
|
|
4a9e845a53 | ||
|
|
b953bd0393 | ||
|
|
283fec0a36 | ||
|
|
0f685e4fb5 | ||
|
|
b296d2c7bb | ||
|
|
b18e6a8734 | ||
|
|
22dacc38c0 | ||
|
|
98d5e06dba | ||
|
|
a7f2ef4aec | ||
|
|
ddcf9cc764 | ||
|
|
33ce04019d | ||
|
|
a8edee8268 | ||
|
|
9c175835d5 | ||
|
|
1960937df3 | ||
|
|
f41b5b84b1 | ||
|
|
cf07fddf96 | ||
|
|
8d04f3d622 | ||
|
|
4f2dc05c7c | ||
|
|
b3a379c239 | ||
|
|
8a46a853d2 | ||
|
|
26b2628f01 | ||
|
|
33f29af0b6 | ||
|
|
84b2a0f55b | ||
|
|
d020bfc0df | ||
|
|
558bd73a6d | ||
|
|
001e1f1127 | ||
|
|
921f601b5d | ||
|
|
4d21d8da23 | ||
|
|
0882e0ba89 | ||
|
|
653a1e7778 | ||
|
|
ada6a84785 | ||
|
|
5d8d21fcae | ||
|
|
de531131c5 | ||
|
|
0794d88f09 | ||
|
|
856b0c3260 | ||
|
|
8fc69c9858 | ||
|
|
de5b693e7d | ||
|
|
47138f92d0 | ||
|
|
ad4358592a | ||
|
|
a61aee337b | ||
|
|
1710fc1a89 | ||
|
|
f058364d7f | ||
|
|
5e187bb8bc | ||
|
|
7115384b15 | ||
|
|
6cdfae1245 | ||
|
|
0c2d94a283 | ||
|
|
68d75a58df | ||
|
|
1152fd02c0 | ||
|
|
333f1bf2bd | ||
|
|
983eb8ebb4 | ||
|
|
61e0a42cce | ||
|
|
60356514c7 | ||
|
|
dbd726959c | ||
|
|
7dcc407c53 | ||
|
|
8f459cc242 | ||
|
|
6d2b181cc0 | ||
|
|
f48c71e17f | ||
|
|
8faf765632 | ||
|
|
6447a583e2 | ||
|
|
fa11461f84 | ||
|
|
675c6e4428 | ||
|
|
72171c12b5 | ||
|
|
acb4b60517 | ||
|
|
7b27df1b83 | ||
|
|
6d1c067719 | ||
|
|
931b5e643c | ||
|
|
8c59be74c1 | ||
|
|
3ed24085fa | ||
|
|
6e7fe4520a | ||
|
|
2ab73ad572 | ||
|
|
52d65ed1d0 | ||
|
|
be5bcc172d | ||
|
|
914a20728e | ||
|
|
014420bfa0 | ||
|
|
6164f0cd34 | ||
|
|
c35b1099a4 | ||
|
|
438cfd3f14 | ||
|
|
fa33db1448 | ||
|
|
dc9115334e | ||
|
|
771ac7ac44 | ||
|
|
bfae233e3e | ||
|
|
3d60024f9b | ||
|
|
75847c8b4d | ||
|
|
2b977a4a6a | ||
|
|
30152cea78 | ||
|
|
cdbba6e0d8 | ||
|
|
bd94297115 | ||
|
|
ab1c9548e0 | ||
|
|
27b7ed17fc | ||
|
|
67bf0a6d0a | ||
|
|
c5c98cbb00 | ||
|
|
14919e34a1 | ||
|
|
5c0054d8ee | ||
|
|
7ba479e482 | ||
|
|
92b6f83eb2 | ||
|
|
72a00ca79c | ||
|
|
445eef2b0e | ||
|
|
558480a5b9 | ||
|
|
630c4a3de3 | ||
|
|
b7e5de389e | ||
|
|
86abfbe087 | ||
|
|
a8ac37f419 | ||
|
|
48c687ea84 | ||
|
|
cf651e7e0f | ||
|
|
fca38fda1a | ||
|
|
8c04009357 | ||
|
|
dc7a9c8c37 | ||
|
|
28e519b72d | ||
|
|
1d4ca0bff6 | ||
|
|
e749678eed | ||
|
|
c7edfdf987 | ||
|
|
f582c88339 | ||
|
|
2e4867fcde | ||
|
|
1ed1cfe83a | ||
|
|
22ee33951b | ||
|
|
bd8709bc82 | ||
|
|
3c5398403d | ||
|
|
b9d3812ee8 | ||
|
|
fa51a7225a | ||
|
|
6082251854 | ||
|
|
f457769fe8 | ||
|
|
d0e0afb46a | ||
|
|
3bdb34886c | ||
|
|
339ec17cf0 | ||
|
|
e58e398267 | ||
|
|
9d74883491 | ||
|
|
c6fac10b62 | ||
|
|
aaee7ed1e7 | ||
|
|
2013f4cbd4 | ||
|
|
772bf96752 | ||
|
|
01bbbdb19f | ||
|
|
8878a042dc | ||
|
|
9844049cb1 | ||
|
|
0cf405e24f | ||
|
|
3d82155d29 | ||
|
|
b8a3cf3a4a | ||
|
|
ba7a3204cb | ||
|
|
90873d6c71 | ||
|
|
6a01607004 | ||
|
|
902d393aef | ||
|
|
fed916b852 | ||
|
|
991f751305 | ||
|
|
07434aa73a | ||
|
|
47a4be83e4 | ||
|
|
6d28e9de79 | ||
|
|
bc3edfb4d7 | ||
|
|
0486100a2b | ||
|
|
ee89d906ec | ||
|
|
9d120c59ea | ||
|
|
8b1a4ef711 | ||
|
|
60dd518887 | ||
|
|
145d6ab5d2 | ||
|
|
ae7c76c773 | ||
|
|
6209c8d347 | ||
|
|
e65a388c1f | ||
|
|
1c91118f4a | ||
|
|
0eb8d19e82 | ||
|
|
5193844ac4 | ||
|
|
79a08c9fee | ||
|
|
b54bf3ccca | ||
|
|
51c4bc55a0 | ||
|
|
629ec98dd8 | ||
|
|
42fd01547d | ||
|
|
4fb7fab850 | ||
|
|
ff588fc771 | ||
|
|
a1c7924cb6 | ||
|
|
1981cf39d1 | ||
|
|
a681f6b04f | ||
|
|
cd80e38db8 | ||
|
|
7b41aba126 | ||
|
|
65ac160e99 | ||
|
|
22ccc2e2b8 | ||
|
|
1e5870ce85 | ||
|
|
47f55b02bf | ||
|
|
4cec20230e | ||
|
|
6fa5d02435 | ||
|
|
5ea7f507c3 | ||
|
|
2781d7abd7 | ||
|
|
5d2be3460f | ||
|
|
a81b19aa62 | ||
|
|
2b2ea50cb1 | ||
|
|
006bb84368 | ||
|
|
500598658d | ||
|
|
3dedfa3d1f | ||
|
|
f1072fee8a | ||
|
|
ca76c302f1 | ||
|
|
ff03ae6f55 | ||
|
|
925f3944d3 | ||
|
|
a6432c46aa | ||
|
|
45fb7d7220 | ||
|
|
a92a281455 | ||
|
|
ecd6c7ceae | ||
|
|
0d23d686eb | ||
|
|
0dabc8df9b | ||
|
|
b5fe13d818 | ||
|
|
b7e24fdc58 | ||
|
|
aa4d978448 | ||
|
|
f5d7535323 | ||
|
|
3ec8b22f14 | ||
|
|
4c13c32473 | ||
|
|
c5db278746 | ||
|
|
0ee6ad0a3a | ||
|
|
a2e4dd2de7 | ||
|
|
9b06d71aeb | ||
|
|
9b5d8f14a9 | ||
|
|
64bceabc03 | ||
|
|
2e78b6dcae | ||
|
|
afee9013ad | ||
|
|
6d51b3ff37 | ||
|
|
f934ca7a03 | ||
|
|
597d5459bb | ||
|
|
66a84cb2ef | ||
|
|
d01b3177fd | ||
|
|
99e1f37b82 | ||
|
|
5cd475d91b | ||
|
|
26771d0800 | ||
|
|
5eff45cac0 | ||
|
|
7b13fae833 | ||
|
|
328134fdba | ||
|
|
3c371e4d52 | ||
|
|
aa317dcb18 | ||
|
|
d62d3edc08 | ||
|
|
30a2283993 | ||
|
|
c08459490d | ||
|
|
66df84a5b5 | ||
|
|
d021972785 | ||
|
|
449eb64fcb | ||
|
|
57b1471254 | ||
|
|
9130d37df7 | ||
|
|
6f28a874b8 | ||
|
|
f3c860958f | ||
|
|
866d6c8637 | ||
|
|
c730a404d4 | ||
|
|
b8ecfe640c | ||
|
|
2594f1a423 | ||
|
|
694fc7e472 | ||
|
|
9d61e36466 | ||
|
|
44f7a3cb0d | ||
|
|
c5607d3889 | ||
|
|
ba6b504cc0 | ||
|
|
9a40597ced | ||
|
|
debf34ff9c | ||
|
|
2b2fa0ed71 | ||
|
|
0b91888eb1 | ||
|
|
b1a90ad74a | ||
|
|
1a1c360f1d | ||
|
|
6796bcf7ad | ||
|
|
b1a3c37c3c | ||
|
|
d262132b92 | ||
|
|
94beb4eddf | ||
|
|
41177cfd1c | ||
|
|
c636072362 | ||
|
|
5d10e1b6c3 | ||
|
|
ca9eae26e1 | ||
|
|
79f2200b27 | ||
|
|
5bddbdd914 | ||
|
|
48e55b1e5d | ||
|
|
229c9edad2 | ||
|
|
092c6c1f07 | ||
|
|
5efe26ebd3 | ||
|
|
5b15234833 | ||
|
|
197166d906 | ||
|
|
af0f4d4020 | ||
|
|
c12aa3fb40 | ||
|
|
d02a73c285 | ||
|
|
b4921dc401 | ||
|
|
c9e7e56389 | ||
|
|
48213650cd | ||
|
|
c094fcc086 | ||
|
|
10a5afeee7 | ||
|
|
68d36f19f0 | ||
|
|
79d69ce526 | ||
|
|
11da4ef024 | ||
|
|
aa98747d6f | ||
|
|
d4c8a1ac78 | ||
|
|
f13b1340f2 | ||
|
|
112e370457 | ||
|
|
faf74b36a4 | ||
|
|
fc23257ca0 | ||
|
|
b92bcc5f02 | ||
|
|
6e62b6090b | ||
|
|
02aaf12f48 | ||
|
|
c923d00340 | ||
|
|
7197bf25f0 | ||
|
|
82b9f86b45 | ||
|
|
5a27e97baf | ||
|
|
67d1970059 | ||
|
|
3073affaaf | ||
|
|
3611b583f5 | ||
|
|
4af438916a | ||
|
|
d5cdb91611 | ||
|
|
6b4cc984ad | ||
|
|
7b45f3fa3f | ||
|
|
e1ce5dc491 | ||
|
|
bab7a32eec | ||
|
|
117d3abdf8 | ||
|
|
07cc25a9df | ||
|
|
ef5e44b2d3 | ||
|
|
a92e838687 | ||
|
|
35ba3a877d | ||
|
|
85a85906d9 | ||
|
|
3eaf976152 | ||
|
|
0df2c4f2be | ||
|
|
dc2bdc2a21 | ||
|
|
3aca7885a7 | ||
|
|
ba1cf2fa44 | ||
|
|
84502e5ae0 | ||
|
|
fb9fabb87c | ||
|
|
cbbfb1356c | ||
|
|
356da76cc8 | ||
|
|
5c65402fd6 | ||
|
|
10abb6b5ec | ||
|
|
8db0001e32 | ||
|
|
5dd037ea49 | ||
|
|
0bbf6490f5 | ||
|
|
8345e9035f | ||
|
|
5c35bab26c | ||
|
|
e80b2eb4cf | ||
|
|
c8b7759e10 | ||
|
|
20fd844935 | ||
|
|
46f2e25ce0 | ||
|
|
79bd47736c | ||
|
|
9dee346000 | ||
|
|
ec9096be40 | ||
|
|
035bf4dcb0 | ||
|
|
ae210967f2 | ||
|
|
5bbe190b3b | ||
|
|
f5f34f138c | ||
|
|
b9d5399ec1 | ||
|
|
c03fef9a3c | ||
|
|
d87b11e8f9 | ||
|
|
4171f39a72 | ||
|
|
3e909bafa8 | ||
|
|
a942582b4b | ||
|
|
89d825f603 | ||
|
|
749e078d36 | ||
|
|
5967380c20 | ||
|
|
9bbb741247 | ||
|
|
d36306e30b | ||
|
|
bf510fee51 | ||
|
|
fe8c62e7b6 | ||
|
|
72a8db7867 | ||
|
|
f00d7db409 | ||
|
|
eff97c04ef | ||
|
|
6c236b047e | ||
|
|
ccf10a5023 | ||
|
|
ddf4e17411 | ||
|
|
4cf6f9ed51 | ||
|
|
778206798e | ||
|
|
39316bb9de | ||
|
|
b9c47c5089 | ||
|
|
5c0aab7bd5 | ||
|
|
2b9a132772 | ||
|
|
d32492e953 | ||
|
|
7defe372b9 | ||
|
|
082fe71c0c | ||
|
|
676dd74140 | ||
|
|
e835707814 | ||
|
|
5800cf51be | ||
|
|
c144e5b1ec | ||
|
|
bc0fafdeca | ||
|
|
e3289116b9 | ||
|
|
6a754325dc | ||
|
|
c7e3519f46 | ||
|
|
eab2ae5d78 | ||
|
|
0545eba002 | ||
|
|
13ffc86aef | ||
|
|
20fed63297 | ||
|
|
83d0607acf | ||
|
|
1add8c14ca | ||
|
|
975e29d76e | ||
|
|
1aa24ee21b | ||
|
|
a09a8e4a06 | ||
|
|
6aac9377ee | ||
|
|
7617a76b19 | ||
|
|
4c9b316e6b | ||
|
|
fc7a68b5af | ||
|
|
c686261e1e | ||
|
|
728aaeb528 | ||
|
|
eac45ca284 | ||
|
|
0b6e2d9c15 | ||
|
|
842a235a68 | ||
|
|
eb269e61b5 | ||
|
|
e57552d401 | ||
|
|
3a01c32e55 | ||
|
|
836c0cf42e | ||
|
|
2fef874494 | ||
|
|
471daba011 | ||
|
|
2f117add7a | ||
|
|
ca961b9bc2 | ||
|
|
d02bc6481f | ||
|
|
135d506065 | ||
|
|
dd811bca06 | ||
|
|
4b68605276 | ||
|
|
dcb2cb99a1 | ||
|
|
42eb98c9fc | ||
|
|
9c6da979ca | ||
|
|
16a71473c1 | ||
|
|
bd483fa229 | ||
|
|
b71878f02e | ||
|
|
13f51a0318 | ||
|
|
ad779e5c9c | ||
|
|
f4730e78f8 | ||
|
|
65b8316459 | ||
|
|
554f5d7f9e | ||
|
|
84461e90e2 | ||
|
|
a50ba9c748 | ||
|
|
de90d03e48 | ||
|
|
e1f2c8b30c | ||
|
|
2358a5ac32 | ||
|
|
2c767a1d60 | ||
|
|
1ada106d61 | ||
|
|
4d6b90727f | ||
|
|
dbc969c139 | ||
|
|
b93572dca8 | ||
|
|
131d656c23 | ||
|
|
3770adccfd | ||
|
|
d54240bdea | ||
|
|
302d84f5b2 | ||
|
|
32aa9a41e2 | ||
|
|
8e83e206f4 | ||
|
|
7ac3056da9 | ||
|
|
0952e618bd | ||
|
|
0b2a652317 | ||
|
|
f28c1c851b | ||
|
|
1e02f9e88b | ||
|
|
5cc168c0f1 | ||
|
|
bf01941b23 | ||
|
|
dfc57f0289 | ||
|
|
5310d8f13c | ||
|
|
e0a2472706 | ||
|
|
064044eeae | ||
|
|
58c21eb13c | ||
|
|
b6fdb61654 | ||
|
|
b0af09ec45 | ||
|
|
7b477b32b8 | ||
|
|
92997756d1 | ||
|
|
26d3466f50 | ||
|
|
8695e6e6cb | ||
|
|
7ba5cc3d52 | ||
|
|
557a11047d | ||
|
|
b34f2d5605 | ||
|
|
0f4ad57033 | ||
|
|
9c78909857 | ||
|
|
77df9ccd5a | ||
|
|
2a30fedbea | ||
|
|
97f4033a8a | ||
|
|
8ed2bd4771 | ||
|
|
e65a0950b2 | ||
|
|
6fe66771cb | ||
|
|
648b2b6f2b | ||
|
|
34c9e30225 | ||
|
|
6559ffd848 | ||
|
|
33466ee6a8 | ||
|
|
1c57c84200 | ||
|
|
aa0601a66d | ||
|
|
3aa854409a | ||
|
|
4313bf2a74 | ||
|
|
51dbd1a7c0 | ||
|
|
4a7569fc2d | ||
|
|
132c285fd4 | ||
|
|
2673e635a3 | ||
|
|
8d149e63a6 | ||
|
|
c722261142 | ||
|
|
720f9b3a0b | ||
|
|
856b49a057 | ||
|
|
5d600f72d2 | ||
|
|
ca9f57c09f | ||
|
|
5b6c654dd1 | ||
|
|
172dab1289 | ||
|
|
33e3ee0790 | ||
|
|
8fd90ea136 | ||
|
|
fbcdb4d9f1 | ||
|
|
2ca717e18d | ||
|
|
40df1474cc | ||
|
|
3266511ebb | ||
|
|
9b6192bd65 | ||
|
|
f7ac739022 | ||
|
|
b9dffc5e4b | ||
|
|
3826bcceab | ||
|
|
38651b8069 | ||
|
|
b09b3fa4e6 | ||
|
|
898d3832a7 | ||
|
|
537c258efa | ||
|
|
7599706808 | ||
|
|
1c5237b6c4 | ||
|
|
8b6b270287 | ||
|
|
8673610f3f | ||
|
|
26a6e034fc | ||
|
|
1dfe916808 | ||
|
|
881ab3011e | ||
|
|
ca43e64d35 | ||
|
|
751ee7a534 | ||
|
|
cc77b308a4 | ||
|
|
2fa9cd8530 | ||
|
|
9323ad3211 | ||
|
|
596bddac47 | ||
|
|
425b2dda61 | ||
|
|
1ab89ed5e6 | ||
|
|
6add16e36b | ||
|
|
0581a77731 | ||
|
|
540b527cf4 | ||
|
|
a2bc02d682 | ||
|
|
1ddb125e2c | ||
|
|
d71653f049 | ||
|
|
819224f0e5 | ||
|
|
a49e040072 | ||
|
|
5149141790 | ||
|
|
1e26652d2e | ||
|
|
ab736a4764 | ||
|
|
7e12240af3 | ||
|
|
d04dc46ccb | ||
|
|
060a47f88a | ||
|
|
f7d215043c | ||
|
|
7eba14cb76 | ||
|
|
08cb949aea | ||
|
|
8360054884 | ||
|
|
89b6fa479e | ||
|
|
d386374449 | ||
|
|
afaa7d9561 | ||
|
|
2f3b00efb4 | ||
|
|
967d4fc3b0 | ||
|
|
c18393b52b | ||
|
|
a46664eab2 | ||
|
|
82d9e45f74 | ||
|
|
e8e247f22e | ||
|
|
d58457de43 | ||
|
|
ee5021deb1 | ||
|
|
ba20cd229e | ||
|
|
eba1b971c0 | ||
|
|
9e20fe2cfb | ||
|
|
c3912e35f6 | ||
|
|
ec24a2a4e8 | ||
|
|
66fb52ff5c | ||
|
|
d11292505b | ||
|
|
2d9ef2215b | ||
|
|
972b7c2bfd | ||
|
|
81e4726607 | ||
|
|
0a5a18e703 | ||
|
|
551d76eadd | ||
|
|
4c78ec7931 | ||
|
|
02e957de1e | ||
|
|
aef2accfa3 | ||
|
|
dffb75c5fa | ||
|
|
59fba75cd8 | ||
|
|
aa129f35a2 | ||
|
|
e1d818bb5f | ||
|
|
b0444a63b0 | ||
|
|
a42d1678eb | ||
|
|
3fd8440ab9 | ||
|
|
d9a738d85f | ||
|
|
53fcd50870 | ||
|
|
d820fb2f8d | ||
|
|
fc47f846ed | ||
|
|
8313c4d870 | ||
|
|
2d8e17aa89 | ||
|
|
e71dbec587 | ||
|
|
b9a40a5163 | ||
|
|
da0714d7cb | ||
|
|
d9b279d150 | ||
|
|
6328da87aa | ||
|
|
2dcf31d6b1 | ||
|
|
946b231516 | ||
|
|
51a07661cc | ||
|
|
1f1f2e1c46 | ||
|
|
754e49643f | ||
|
|
eb1aadb218 | ||
|
|
59973c96e4 | ||
|
|
cb1a271c61 | ||
|
|
15918d8971 | ||
|
|
1371400c2b | ||
|
|
681951c175 | ||
|
|
7bcb4eafec | ||
|
|
5752b24d38 | ||
|
|
8bf402fd67 | ||
|
|
1b14c2e7b0 | ||
|
|
2c77560870 | ||
|
|
e9e9ec23b8 | ||
|
|
7ffe5bfb3c | ||
|
|
5827c168c2 | ||
|
|
b90a54f989 | ||
|
|
fd9ac30062 | ||
|
|
e16d10ade6 | ||
|
|
aff1935e40 | ||
|
|
c9efb7a72c | ||
|
|
c797222407 | ||
|
|
c9d0192b4a | ||
|
|
270fdfff07 | ||
|
|
4dd378b126 | ||
|
|
5c33efe430 | ||
|
|
194803a3a7 | ||
|
|
c6c693923e | ||
|
|
53f717338b | ||
|
|
b71d4477ea | ||
|
|
f0bc2fa968 | ||
|
|
f02119af62 | ||
|
|
04bff63f49 | ||
|
|
c77a7fe824 | ||
|
|
30be7b582e | ||
|
|
49414826af | ||
|
|
c295717ce7 | ||
|
|
1945582c10 | ||
|
|
b86787c39c | ||
|
|
e15e504217 | ||
|
|
dd4ded3978 | ||
|
|
02be2f8f42 | ||
|
|
9719c52e62 | ||
|
|
c961ac70b6 | ||
|
|
6f485cc870 | ||
|
|
461f1fe1a9 | ||
|
|
ecb3867803 | ||
|
|
927990d94e | ||
|
|
2980f7cc58 | ||
|
|
3feb748fee | ||
|
|
5c3bb19923 | ||
|
|
593b211d1b | ||
|
|
1b3aaef525 | ||
|
|
3fa3bf0570 | ||
|
|
0065cd915f | ||
|
|
83de16678c | ||
|
|
05a595f745 | ||
|
|
5f0fbdcde9 | ||
|
|
ea41480232 | ||
|
|
4ef21e2597 | ||
|
|
78cdbff1b3 | ||
|
|
576a8228c2 | ||
|
|
fef7ce3c0d | ||
|
|
f0605a510f | ||
|
|
3b8bb580e4 | ||
|
|
4b97f2bb8e | ||
|
|
46df850cb9 | ||
|
|
f8f3cc039a | ||
|
|
f092d09121 | ||
|
|
78806001e5 | ||
|
|
8fd09d4608 | ||
|
|
ec044e826e | ||
|
|
a9bfe7b72f | ||
|
|
0d585d55d3 | ||
|
|
f978a7ed31 | ||
|
|
18c7c5d81c | ||
|
|
7c9a6317b9 | ||
|
|
ec4f00179d | ||
|
|
d8135f9ae2 | ||
|
|
1741edf159 | ||
|
|
f85eed0ab3 | ||
|
|
d3fc398580 | ||
|
|
27c835aa56 | ||
|
|
e4b356f08c | ||
|
|
01f9a04e4a | ||
|
|
9ab2eefc37 | ||
|
|
08931b33c1 | ||
|
|
36b9a45c3b | ||
|
|
36fa1a97d4 | ||
|
|
0da9cf70ea | ||
|
|
a38e937dd6 | ||
|
|
f4d13d52d3 | ||
|
|
8bb43e7388 | ||
|
|
6786c9f143 | ||
|
|
9afe10e23d | ||
|
|
f1f6050ad7 | ||
|
|
d73e225519 | ||
|
|
3107d4a0fa | ||
|
|
01cc06bcb8 | ||
|
|
76763c9bcd | ||
|
|
e94e2da3ec | ||
|
|
2cf3bbddd4 | ||
|
|
0f6d8ccd90 | ||
|
|
62c44138da | ||
|
|
0a7734cf64 | ||
|
|
0eeb10d4bb | ||
|
|
2e1b12d09f | ||
|
|
5c55978f10 | ||
|
|
5d6c9ce77b | ||
|
|
d1049511cc | ||
|
|
703a22fae5 | ||
|
|
ff3fe1f489 | ||
|
|
4c76fd500c | ||
|
|
deaa6e9406 | ||
|
|
19d63e6aa0 | ||
|
|
6dca664217 | ||
|
|
d7b51b5906 | ||
|
|
3c9e05a6d9 | ||
|
|
498913b982 | ||
|
|
35e148e26d | ||
|
|
454927151d | ||
|
|
d46d8bcda2 | ||
|
|
4434762a08 | ||
|
|
bbedb35bf3 | ||
|
|
f4f204b850 | ||
|
|
feba38a1f4 | ||
|
|
1b2c8974b8 | ||
|
|
8025b85694 | ||
|
|
b2beb42c14 | ||
|
|
7dd21e93c4 | ||
|
|
3c1713406e | ||
|
|
58c48af58f | ||
|
|
0b257f71e7 | ||
|
|
45f3c28eb2 | ||
|
|
400c41ffd9 | ||
|
|
d4d8fd819d | ||
|
|
32954e9d4f | ||
|
|
c01096097c | ||
|
|
44068e3109 | ||
|
|
693a74c286 | ||
|
|
06c84cb110 | ||
|
|
de05424ff6 | ||
|
|
def87c0c23 | ||
|
|
6ce9a01c3e | ||
|
|
ab8119360e | ||
|
|
4a9db56f4c | ||
|
|
a3fc38037a | ||
|
|
240cf62056 | ||
|
|
b9e66bfcfb | ||
|
|
239498f37c | ||
|
|
bc07fd9db5 | ||
|
|
82711e069c | ||
|
|
2cab253b34 | ||
|
|
3a7e03aaff | ||
|
|
852993029d | ||
|
|
c396dd4554 | ||
|
|
702091d548 | ||
|
|
4d8fec3b67 | ||
|
|
c1c470fc4c | ||
|
|
eae4129863 | ||
|
|
fb0a750970 | ||
|
|
a826b1aeeb | ||
|
|
ea093d3a53 | ||
|
|
5743864744 | ||
|
|
819bfbb943 | ||
|
|
03f47e58a3 | ||
|
|
fffd61c746 | ||
|
|
21737f57e5 | ||
|
|
0284961d61 | ||
|
|
22b892571b | ||
|
|
a0a64a59ba | ||
|
|
8a34570b83 | ||
|
|
46f4584796 | ||
|
|
55e6bf7e3d | ||
|
|
d857344aa8 | ||
|
|
ef758082ed | ||
|
|
1fd56658b8 | ||
|
|
be7ae5e36b | ||
|
|
2903b476c7 | ||
|
|
f60a2e8f85 | ||
|
|
4fb7d74165 | ||
|
|
3d80e51b2a | ||
|
|
29ddfd1d71 | ||
|
|
1839153609 | ||
|
|
855ea02b15 | ||
|
|
3e30dbc75c | ||
|
|
b6c995fed8 | ||
|
|
ff04c2046e | ||
|
|
2ad03b0ebd | ||
|
|
29b7c75a72 | ||
|
|
e8d5499d72 | ||
|
|
4b091cfc2a | ||
|
|
48d2243845 | ||
|
|
2685d742e8 | ||
|
|
a1df0c5d77 | ||
|
|
2e528ad510 | ||
|
|
abef0b44a8 | ||
|
|
ee3154999a | ||
|
|
7a99d2f8e9 | ||
|
|
6fbec25c8f | ||
|
|
fbfe987ae8 | ||
|
|
d297d466ed | ||
|
|
0ef298b21f | ||
|
|
9e0b36747a | ||
|
|
b5011e7012 | ||
|
|
e158f87286 | ||
|
|
edac92d03a | ||
|
|
1b20e664bf | ||
|
|
9c80a66253 | ||
|
|
645ca84704 | ||
|
|
7aaa888d1d | ||
|
|
c362c6a02c | ||
|
|
47bac3c11f | ||
|
|
199c38de29 | ||
|
|
b198c877db | ||
|
|
141b5def46 | ||
|
|
30aedfc3f7 | ||
|
|
df8e404abd | ||
|
|
9898d406bc | ||
|
|
0043bf78b6 | ||
|
|
e1598b0b11 | ||
|
|
861dab5b22 | ||
|
|
5c58e25de5 | ||
|
|
1d7f375992 | ||
|
|
92511f4711 | ||
|
|
6748aa0818 | ||
|
|
bc583c993a | ||
|
|
2c3538cb8f | ||
|
|
9713baea55 | ||
|
|
7cedf7ae71 | ||
|
|
b17c050861 | ||
|
|
2b1ebda6f1 | ||
|
|
5e9df2c698 | ||
|
|
f8ef8c48f7 | ||
|
|
a038e1502f | ||
|
|
2e265310c4 | ||
|
|
713146eeba | ||
|
|
a1130f8c7b | ||
|
|
0b9d7a386c | ||
|
|
08de0e9617 | ||
|
|
22c2fd1b58 | ||
|
|
901664eca1 | ||
|
|
d99334573b | ||
|
|
2ff04a931a | ||
|
|
e0c5e1988f | ||
|
|
3cc7b319d9 | ||
|
|
19f075a92a | ||
|
|
e3435401f1 | ||
|
|
b59472cf63 | ||
|
|
162cc4d343 | ||
|
|
aea7062223 | ||
|
|
52f448978f | ||
|
|
6d5ddb7139 | ||
|
|
a2915b7142 | ||
|
|
7faa4bcbe2 | ||
|
|
6c9a9b9d99 | ||
|
|
02eec304c3 | ||
|
|
3a20ae3830 | ||
|
|
0ffaccaec3 | ||
|
|
e94c9ffa70 | ||
|
|
72316bdb5b | ||
|
|
803a711e6a | ||
|
|
8760fb677f | ||
|
|
d2631e6a53 | ||
|
|
4059748b47 | ||
|
|
644a21b8a5 | ||
|
|
a3876314b7 | ||
|
|
e3c2b8a339 | ||
|
|
e12bb2a4eb | ||
|
|
2096f1a657 | ||
|
|
1f3c18fcbe | ||
|
|
edfeab7932 | ||
|
|
b8bc7b7c71 | ||
|
|
f874d15185 | ||
|
|
ee034bd811 | ||
|
|
a2a16d4193 | ||
|
|
98fc82fa71 | ||
|
|
1884c7e83f | ||
|
|
1466b7ac61 | ||
|
|
748e2e925b | ||
|
|
1fd69ddee9 | ||
|
|
3a8368ef04 | ||
|
|
c1258e5c72 | ||
|
|
211a71cf11 | ||
|
|
55199fc62c | ||
|
|
45ad6f2e61 | ||
|
|
df365adf9a | ||
|
|
7b40d1eb6f | ||
|
|
c1d16c61eb | ||
|
|
83b1c397a0 | ||
|
|
bfa0358a52 | ||
|
|
2e4b368c8c | ||
|
|
4e34851c57 | ||
|
|
3a557baedd | ||
|
|
6e219b6b11 | ||
|
|
ec1450bac4 | ||
|
|
5be91de56c | ||
|
|
24fa1c457e | ||
|
|
71810d0415 | ||
|
|
d5bc856f45 | ||
|
|
876720593b | ||
|
|
dd96c71253 | ||
|
|
be57134810 | ||
|
|
16b895b466 | ||
|
|
dcb761637d | ||
|
|
02f4610b1c | ||
|
|
b6a131edfb | ||
|
|
12bc2c0425 | ||
|
|
14e36866f5 | ||
|
|
1e82465766 | ||
|
|
fb07d47b82 | ||
|
|
c71733252c | ||
|
|
e0c0ba7e1b | ||
|
|
7f319f5ec5 | ||
|
|
c21763f6cb | ||
|
|
f488c5b7bc | ||
|
|
5c1dd6a4c6 | ||
|
|
102a50fa96 | ||
|
|
bb8088d498 | ||
|
|
11780f037b | ||
|
|
cceea73c3f | ||
|
|
fcd2daf57c | ||
|
|
b5f51dbd0c | ||
|
|
d9f461e4e4 | ||
|
|
c13a43e5c8 | ||
|
|
844c201702 | ||
|
|
62e340067e | ||
|
|
a8b986bbb6 | ||
|
|
da15132aa0 | ||
|
|
e3925cc359 | ||
|
|
6b1950ec24 | ||
|
|
4e3cf61571 | ||
|
|
53b9f2a5bd | ||
|
|
cd5dfa2bc5 | ||
|
|
bd1defc1d8 | ||
|
|
281ef5d094 | ||
|
|
e8461f9994 | ||
|
|
60cd25c6a1 | ||
|
|
4c16ea920c | ||
|
|
69a7039f75 | ||
|
|
06ff89cbe4 | ||
|
|
cee59ba8cd | ||
|
|
d4fad5929c | ||
|
|
1a53c106e1 | ||
|
|
7d119fd86b | ||
|
|
74a5537e15 | ||
|
|
afb21603dc | ||
|
|
002e077dbd | ||
|
|
9d199a6d72 | ||
|
|
86b01e4f29 | ||
|
|
1c184da615 | ||
|
|
e5f9f187ad | ||
|
|
f2a5aa2866 | ||
|
|
7a1b38db6e | ||
|
|
26e02e84a6 | ||
|
|
8347d3b623 | ||
|
|
a83c4e0897 | ||
|
|
ac4d994249 | ||
|
|
f308694dd4 | ||
|
|
0e883bbbc5 | ||
|
|
5774fdfe75 | ||
|
|
85817e7611 | ||
|
|
a2ad9d36ca | ||
|
|
33bdf9fa76 | ||
|
|
55fd567a84 | ||
|
|
b359b8c3e0 | ||
|
|
bb6df52ed5 | ||
|
|
8a9ab9968c | ||
|
|
a420d2530f | ||
|
|
89cb7b7aa1 | ||
|
|
9c3bbcf4e6 | ||
|
|
f446194c8a | ||
|
|
1dd563a0ae | ||
|
|
aae0fc4908 | ||
|
|
5bb83301dd | ||
|
|
0ca82df062 | ||
|
|
ff3656f4f5 | ||
|
|
b31b0c8148 | ||
|
|
c87855423c | ||
|
|
e00a131160 | ||
|
|
cb29a49a64 | ||
|
|
795acf020e | ||
|
|
cc25c2634b | ||
|
|
1687721600 | ||
|
|
a6bc422729 | ||
|
|
92183bb354 | ||
|
|
bcaf2f08aa | ||
|
|
4bbed75cc4 | ||
|
|
7d0aeaf539 | ||
|
|
f28e63b2a3 | ||
|
|
7f48289fcd | ||
|
|
12e35c4c12 | ||
|
|
182d7c138a | ||
|
|
47fd67a35c | ||
|
|
b934c3f471 | ||
|
|
2a882b6387 | ||
|
|
ca9342c549 | ||
|
|
6f1304e03e | ||
|
|
cac3dc8a46 | ||
|
|
aea872431c | ||
|
|
1d4cbe768d | ||
|
|
0e07ed4b13 | ||
|
|
2ed755764e | ||
|
|
f419231dc3 | ||
|
|
8ba7363d11 | ||
|
|
4c8620e03b | ||
|
|
eb1de78ce1 | ||
|
|
5030fa81a0 | ||
|
|
0f87cb92b8 | ||
|
|
09547832ba | ||
|
|
8c3c96baf7 | ||
|
|
03a9aac157 | ||
|
|
68ec20fffc | ||
|
|
4076b12ee9 | ||
|
|
0034abfa45 | ||
|
|
31b0237c50 | ||
|
|
9366c0eaab | ||
|
|
5d5eeca008 | ||
|
|
4b7e0f50b7 | ||
|
|
44e430ebc2 | ||
|
|
180ba72a06 | ||
|
|
792224ead0 | ||
|
|
e8e853f2cb | ||
|
|
80a24c0399 | ||
|
|
d026a3954a | ||
|
|
1712b06a64 | ||
|
|
010f3550b6 | ||
|
|
b70ddf7b54 | ||
|
|
1dd97e7d53 | ||
|
|
2f37dc0606 | ||
|
|
c1eb6d8aa4 | ||
|
|
ad17f345e7 | ||
|
|
ee7a2f346c | ||
|
|
b99b7577fc | ||
|
|
f79eabd24b | ||
|
|
81a32e9b06 | ||
|
|
6dc3a2108a | ||
|
|
f965034366 | ||
|
|
fdcd8f6faf | ||
|
|
b90682dc8b | ||
|
|
b9dc415178 |
6
.gitattributes
vendored
6
.gitattributes
vendored
@@ -2,3 +2,9 @@
|
||||
*.txt text
|
||||
*.c text
|
||||
*.h text
|
||||
|
||||
# For git archive
|
||||
.gitignore export-ignore
|
||||
.gitattributes export-ignore
|
||||
.travis.yml export-ignore
|
||||
.vscode export-ignore
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -1,3 +1,5 @@
|
||||
*.o
|
||||
*.a
|
||||
/doc/doxygen/output/html
|
||||
/src/apps/snmp/LwipMibCompiler/CCodeGeneration/bin/
|
||||
/src/apps/snmp/LwipMibCompiler/CCodeGeneration/obj/
|
||||
@@ -11,3 +13,7 @@
|
||||
/src/apps/snmp/LwipMibCompiler/SharpSnmpLib/obj/
|
||||
/src/apps/snmp/LwipMibCompiler/LwipMibCompiler.userprefs
|
||||
/src/apps/snmp/LwipMibCompiler/*.suo
|
||||
/test/fuzz/output
|
||||
/test/fuzz/lwip_fuzz
|
||||
/test/fuzz/.depend
|
||||
/build
|
||||
418
CHANGELOG
418
CHANGELOG
@@ -1,9 +1,427 @@
|
||||
HISTORY
|
||||
* These are only the most important changes. For a full list, use git log:
|
||||
http://git.savannah.nongnu.org/cgit/lwip.git
|
||||
|
||||
(git master)
|
||||
|
||||
* [Enter new changes just after this line - do not remove this line]
|
||||
|
||||
(STABLE-2.1.2):
|
||||
|
||||
++ Bugfixes:
|
||||
|
||||
2018-11-21: Jens Nielsen
|
||||
* netbiosns.c: fix expecting too large packet (bug #55069)
|
||||
|
||||
2018-11-19: Dirk Ziegelmeier
|
||||
* smtp.c: fix compiling with strict C compatibility because of strnlen (bug #55034)
|
||||
|
||||
2018-11-12: Simon Goldschmidt
|
||||
* tcp.c: fix overflow check in tcp_recved triggering invalid assertion (bug #55015)
|
||||
|
||||
2018-11-12: Simon Goldschmidt
|
||||
* tcp.c: fix a bug in sending RST segments (sent from port 0)
|
||||
|
||||
(STABLE-2.1.1):
|
||||
|
||||
++ Bugfixes:
|
||||
|
||||
2018-11-01: Joan Lledó
|
||||
* sockets.c: fix bad assertion in lwip_poll_dec_sockets_used() (bug #54933)
|
||||
|
||||
2018-11-01: Dirk Ziegelmeier
|
||||
* ip4.c: don't send 127.* to default netif (bug #54670)
|
||||
|
||||
2018-10-23: David Girault
|
||||
* altcp_tls_mbedtls.c: fix use-after free (bug #54774)
|
||||
|
||||
2018-10-23: Ognjen Bjelica, Dirk Ziegelmeier
|
||||
* snmp_scalar.c: Avoid NULL pointer dereference (bug #54886)
|
||||
|
||||
2018-10-23: Simon Goldschmidt
|
||||
* Fix missing standard includes in multiple files
|
||||
|
||||
2018-10-17: Ivan Warren
|
||||
* def.h: fix casting htonX and ntohX to u16_t (bug #54850)
|
||||
|
||||
2018-10-12: Simon Goldschmidt
|
||||
* Revert "tcp_abandon: no need to buffer pcb->local_port" (fix that source port was 0 for RST
|
||||
called when aborting a connection)
|
||||
|
||||
2018-10-11: Jonas Rabenstein
|
||||
* tcp.c: tcp_recved: check for overflow and warn about too big values (patch #9699)
|
||||
|
||||
2018-10-06: Joan Lledó
|
||||
* sockets.c: alloc_socket(): Check for LWIP_SOCKET_POLL when setting select-
|
||||
related variables (patch #9696)
|
||||
|
||||
2018-10-04: Spencer
|
||||
* tcp.c: Update prev pointer when skipping entries in tcp_slowtmr (patch #9694)
|
||||
|
||||
2018-09-27: Martine Lenders
|
||||
* lowpan6.c: Fix IEEE 802.15.4 address setting (bug #54749)
|
||||
|
||||
(STABLE-2.1.0):
|
||||
|
||||
++ New features:
|
||||
|
||||
2018-06-17: Simon Goldschmidt
|
||||
* lwiperf: implemented iPerf client mode
|
||||
|
||||
2018-04-23: Dirk Ziegelmeier
|
||||
* added cmake build files
|
||||
|
||||
2018-03-04: Ray Abram
|
||||
* netbios responder: respond to '*' queries
|
||||
|
||||
2018-02-23: Benjamin Aigner
|
||||
* 6lowpan: add 6lowpan-over-BLE netif (based on existing 6lowpan netif)
|
||||
|
||||
2018-02-22: Simon Goldschmidt
|
||||
* ipv6: add support for stateless DHCPv6 (to get DNS servers in SLAAC nets)
|
||||
|
||||
2018-02-16: Simon Goldschmidt
|
||||
* add raw API http(s) client (with proxy support)
|
||||
|
||||
2018-02-01: Simon Goldschmidt
|
||||
* tcp: add hooks to implement additional socket options
|
||||
|
||||
2018-02-01: Simon Goldschmidt
|
||||
* tcp: add hooks to implement tcp md5 signatures or similar (see contrib/addons for an example)
|
||||
|
||||
2018-01-05: Simon Goldschmidt
|
||||
* Added sys_mbox_trypost_fromisr() and tcpip_callbackmsg_trycallback_fromisr()
|
||||
These can be used to post preallocated messages from an ISR to the tcpip thread
|
||||
(e.g. when using FreeRTOS)
|
||||
|
||||
2018-01-02: Dirk Ziegelmeier
|
||||
* task #14780: Add debug helper asserts to ensure threading/locking requirements are met
|
||||
|
||||
2017-11-21: Simon Goldschmidt
|
||||
* task #14600: tcp_alloc(): kill TF_CLOSEPEND connections before other ESTABLISHED
|
||||
|
||||
2017-11-21: Simon Goldschmidt
|
||||
* makefsdata: added option "-ssi:<filename>" to control SSI tag checking/insertion
|
||||
through a list of filenames, not by checking the file extension at runtime
|
||||
|
||||
2017-11-20: Joel Cunningham
|
||||
* netconn: add LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE to use external DNS resolver (patch #9427)
|
||||
|
||||
2017-11-14: Joel Cunningham
|
||||
* netifapi: Add thread safe ARP cache APIs (task #14724)
|
||||
|
||||
2017-11-06: Axel Lin
|
||||
* TCP: kill existing connections with a LOWER priority than the one currently being opened.
|
||||
Previous implementations also kill existing connections of the SAME priority.
|
||||
|
||||
2017-09-21: Kalle Olavi Niemitalo
|
||||
* sockets: add poll() implementation (patch #9450)
|
||||
|
||||
2017-09-10: Joel Cunningham
|
||||
* sockets: add readv() implementation (task #14610)
|
||||
|
||||
2017-08-04: Simon Goldschmidt
|
||||
* Clean up DHCP a bit: no need keep msg_out and msg_in as members in struct
|
||||
dhcp - they are used in a call stack only (p_out and options_out_len as well)
|
||||
|
||||
2017-08-04: Simon Goldschmidt
|
||||
* pbuf: split pbuf_header(s16_t) into pbuf_add_header(size_t) and
|
||||
pbuf_remove_header(size_t)
|
||||
|
||||
2017-07-20: Douglas
|
||||
* sys: deprecate sys_arch_sem_wait and sys_arch_mbox_fetch returning the
|
||||
time waited rather they are now defined to return != SYS_ARCH_TIMEOUT
|
||||
on success.
|
||||
|
||||
2017-07-03: Jakub Schmidtke
|
||||
* tcp: added support for sending TCP SACKs
|
||||
|
||||
2017-06-20: Joel Cunningham
|
||||
* netconn/netdb: added core locking support to netconn_gethostbyname (task #14523)
|
||||
|
||||
2017-04-25: Simon Goldschmidt
|
||||
* dhcp: added two hooks for adding and parsing user defined DHCP options
|
||||
|
||||
2017-04-25: Joel Cunningham
|
||||
* sockets: added recvmsg for UDP (together with CMSG and IP_PKTINFO) (task #14247)
|
||||
|
||||
2017-04-20: Joel Cunningham
|
||||
* tcp: added Appropriate Byte Counting support (task #14128)
|
||||
|
||||
2017-04-11: Simon Goldschmidt
|
||||
* netconn/sockets: remove fatal error handling, fix asynchronous error handling,
|
||||
ensure data before RST can be received
|
||||
|
||||
2017-03-30: Simon Goldschmidt
|
||||
* added "application layered TCP" connection API (altcp) for seamless integration
|
||||
of TLS or proxy connections
|
||||
|
||||
2017-03-09: Simon Goldschmidt
|
||||
* sockets: add recvmsg for TCP
|
||||
|
||||
2017-03-02: Joel Cunningham
|
||||
* netconn/sockets: vectorize netconn_write for TCP, treating a vectored I/O write
|
||||
atomically in regards to TCP segmentation (patch #8882)
|
||||
|
||||
2017-03-02: Simon Goldschmidt
|
||||
* netconn: added nonblocking accept/recv to netconn API (task #14396)
|
||||
|
||||
2017-02-28: Simon Goldschmidt
|
||||
* Added LWIP_SINGLE_NETIF for small targets with only one netif
|
||||
|
||||
2017-02-10: David van Moolenbroek
|
||||
* Implement UDP and RAW multicast support for IPv6 (core API, not netconn/sockets)
|
||||
|
||||
2017-02-04: David van Moolenbroek
|
||||
* IPv6 scopes support
|
||||
|
||||
2017-01-20: Joel Cunningham
|
||||
* sockets: add interface name/index APIs (task #14314)
|
||||
|
||||
2017-01-08: David van Moolenbroek
|
||||
* Extensions to RAW API (patch #9208)
|
||||
- Connected RAW PCBs
|
||||
- Add raw_sendto_if_src()
|
||||
- Support IP_HDRINCL socket option
|
||||
|
||||
++ Bugfixes:
|
||||
|
||||
2018-06-19: Simon Goldschmidt
|
||||
* tcp: fix RTO timer not working if link is down
|
||||
|
||||
2018-06-15: Sylvain Rochet
|
||||
* ppp: multiple smaller bugfixes
|
||||
|
||||
2018-05-17: Simon Goldschmidt
|
||||
* etharp: arp table can now be bigger than 127 entries
|
||||
|
||||
2018-04-25: Jens Nielsen
|
||||
* tftp server: correctly handle retransmissions
|
||||
|
||||
2018-04-18: Simon Goldschmidt
|
||||
sockets: fix race conditions when closing full-duplex sockets
|
||||
|
||||
2018-03-09: Simon Goldschmidt
|
||||
* 6lowpan: fix to work against contiki; added ZigBee encapsulation netif for tests
|
||||
|
||||
2018-02-04: Simon Goldschmidt
|
||||
* sockets: fix inconsistencies on close (inconsistent error codes, double FIN)
|
||||
|
||||
2018-01-05: Dirk Ziegelmeier
|
||||
* Fix bug #52748: the bug in timeouts.c by reimplementing timer logic to use
|
||||
absolute instead of relative timeout values
|
||||
|
||||
2017-12-31: Dirk Ziegelmeier
|
||||
* Fix bug #52704: DHCP and bad OFFER: Stop timeout only if offer is accepted
|
||||
|
||||
2017-11-08: Joel Cunningham
|
||||
* netif: ensure link and admin states are up in issue reports (bug #52353)
|
||||
|
||||
2017-09-12: David Lockyer
|
||||
* select: allocate select_cb from memp for LWIP_MPU_COMPATIBLE = 1 (bug #51990)
|
||||
|
||||
2017-09-11: Simon Goldschmidt
|
||||
* tcp_in.c: fix bug #51937 (leaking tcp_pcbs on passive close with unacked data)
|
||||
|
||||
2017-08-11: Joel Cunningham
|
||||
* lwip_itoa: fix converting the number 0 (previously converted to '\0') (bug #51729)
|
||||
|
||||
2017-08-08: Dirk Ziegelmeier
|
||||
* ip4_route_src: parameter order is reversed: ip4_route_src(dest, src) -> ip4_route_src(src, dest)
|
||||
to make parameter order consistent with other ip*_route*() functions
|
||||
Same also applies to LWIP_HOOK_IP4_ROUTE_SRC() parameter order.
|
||||
|
||||
2017-08-04: Joel Cunningham
|
||||
* tcp: re-work persist timer to fully close window (details in bug #50837)
|
||||
|
||||
2017-07-26: Simon Goldschmidt
|
||||
* snmp_msg.c: fix bug #51578 (SNMP failed to decode some values on non 32bit platforms)
|
||||
|
||||
2017-07-20: Simon Goldschmidt
|
||||
* compatibility headers: moved from 'src/include/posix' to 'src/include/compat/posix',
|
||||
'src/include/compat/stdc' etc.
|
||||
|
||||
2017-05-09: Joel Cunningham
|
||||
* tcp: add zero-window probe timeout (bug #50837)
|
||||
|
||||
2017-04-11: Simon Goldschmidt
|
||||
* sockets.c: task #14420 (Remove sys_sem_signal from inside SYS_ARCH_PROTECT
|
||||
crit section) done for LWIP_TCPIP_CORE_LOCKING==1
|
||||
|
||||
2017-02-24: Simon Goldschmidt
|
||||
* sockets.c: fixed close race conditions in lwip_select (for LWIP_NETCONN_FULLDUPLEX)
|
||||
|
||||
2017-02-24: Simon Goldschmidt
|
||||
* sockets.c: fixed that select ignored invalid/not open sockets in the fd_sets (bug #50392)
|
||||
|
||||
2017-01-11: David van Moolenbroek
|
||||
* Lots of IPv6 related fixes and improvements
|
||||
|
||||
(STABLE-2.0.3)
|
||||
|
||||
++ Bugfixes:
|
||||
|
||||
2017-09-11: Simon Goldschmidt
|
||||
* tcp_in.c: fix bug #51937 (leaking tcp_pcbs on passive close with unacked data)
|
||||
|
||||
2017-08-02: Abroz Bizjak/Simon Goldschmidt
|
||||
* multiple fixes in IPv4 reassembly (leading to corrupted datagrams received)
|
||||
|
||||
2017-03-30: Simon Goldschmidt
|
||||
* dhcp.c: return ERR_VAL instead of asserting on offset-out-of-pbuf
|
||||
|
||||
2017-03-23: Dirk Ziegelmeier
|
||||
* dhcp.h: fix bug #50618 (dhcp_remove_struct() macro does not work)
|
||||
|
||||
(STABLE-2.0.2)
|
||||
|
||||
++ New features:
|
||||
|
||||
2017-02-10: Dirk Ziegelmeier
|
||||
* Implement task #14367: Hooks need a better place to be defined:
|
||||
We now have a #define for a header file name that is #included in every .c
|
||||
file that provides hooks.
|
||||
|
||||
2017-02-10: Simon Goldschmidt
|
||||
* tcp_close does not fail on memory error (instead, FIN is sent from tcp_tmr)
|
||||
|
||||
++ Bugfixes:
|
||||
|
||||
2017-03-08
|
||||
* tcp: do not keep sending SYNs when getting ACKs
|
||||
|
||||
2017-03-08: Joel Cunningham
|
||||
* tcp: Initialize ssthresh to TCP_SND_BUF (bug #50476)
|
||||
|
||||
2017-03-01: Simon Goldschmidt
|
||||
* httpd: LWIP_HTTPD_POST_MANUAL_WND: fixed double-free when httpd_post_data_recved
|
||||
is called nested from httpd_post_receive_data() (bug #50424)
|
||||
|
||||
2017-02-28: David van Moolenbroek/Simon Goldschmidt
|
||||
* tcp: fixed bug #50418: LWIP_EVENT_API: fix invalid calbacks for SYN_RCVD pcb
|
||||
|
||||
2017-02-17: Simon Goldschmidt
|
||||
* dns: Improved DNS_LOCAL_HOSTLIST interface (bug #50325)
|
||||
|
||||
2017-02-16: Simon Goldschmidt
|
||||
* LWIP_NETCONN_FULLDUPLEX: fixed shutdown during write (bug #50274)
|
||||
|
||||
2017-02-13: Simon Goldschmidt/Dirk Ziegelmeier
|
||||
* For tiny targtes, LWIP_RAND is optional (fix compile time checks)
|
||||
|
||||
2017-02-10: Simon Goldschmidt
|
||||
* tcp: Fixed bug #47485 (tcp_close() should not fail on memory error) by retrying
|
||||
to send FIN from tcp_fasttmr
|
||||
|
||||
2017-02-09: Simon Goldschmidt
|
||||
* sockets: Fixed bug #44032 (LWIP_NETCONN_FULLDUPLEX: select might work on
|
||||
invalid/reused socket) by not allowing to reallocate a socket that has
|
||||
"select_waiting != 0"
|
||||
|
||||
2017-02-09: Simon Goldschmidt
|
||||
* httpd: Fixed bug #50059 (httpd LWIP_HTTPD_SUPPORT_11_KEEPALIVE vs.
|
||||
LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED)
|
||||
|
||||
2017-02-08: Dirk Ziegelmeier
|
||||
* Rename "IPv6 mapped IPv4 addresses" to their correct name from RFC4191:
|
||||
"IPv4-mapped IPv6 address"
|
||||
|
||||
2017-02-08: Luc Revardel
|
||||
* mld6.c: Fix bug #50220 (mld6_leavegroup does not send ICMP6_TYPE_MLD, even
|
||||
if last reporter)
|
||||
|
||||
2017-02-08: David van Moolenbroek
|
||||
* ip6.c: Patch #9250: fix source substitution in ip6_output_if()
|
||||
|
||||
2017-02-08: Simon Goldschmidt
|
||||
* tcp_out.c: Fixed bug #50090 (last_unsent->oversize_left can become wrong value
|
||||
in tcp_write error path)
|
||||
|
||||
2017-02-02: Dirk Ziegelmeier
|
||||
* Fix bug #50206: UDP Netconn bind to IP6_ADDR_ANY fails
|
||||
|
||||
2017-01-18: Dirk Ziegelmeier
|
||||
* Fix zero-copy RX, see bug bug #50064. PBUF_REFs were not supported as ARP requests.
|
||||
|
||||
2017-01-15: Axel Lin, Dirk Ziegelmeier
|
||||
* minor bug fixes in mqtt
|
||||
|
||||
2017-01-11: Knut Andre Tidemann
|
||||
* sockets/netconn: fix broken default ICMPv6 handling of checksums
|
||||
|
||||
(STABLE-2.0.1)
|
||||
|
||||
++ New features:
|
||||
|
||||
2016-12-31: Simon Goldschmidt
|
||||
* tcp.h/.c: added function tcp_listen_with_backlog_and_err() to get the error
|
||||
reason when listening fails (bug #49861)
|
||||
|
||||
2016-12-20: Erik Andersen
|
||||
* Add MQTT client
|
||||
|
||||
2016-12-14: Jan Breuer:
|
||||
* opt.h, ndc.h/.c: add support for RDNSS option (as per RFC 6106)
|
||||
|
||||
2016-12-14: David van Moolenbroek
|
||||
* opt.h, nd6.c: Added LWIP_HOOK_ND6_GET_GW()
|
||||
|
||||
2016-12-09: Dirk Ziegelmeier
|
||||
* ip6_frag.c: Implemented support for LWIP_NETIF_TX_SINGLE_PBUF
|
||||
|
||||
2016-12-09: Simon Goldschmidt
|
||||
* dns.c: added one-shot multicast DNS queries
|
||||
|
||||
2016-11-24: Ambroz Bizjak, David van Moolenbroek
|
||||
* tcp_out.c: Optimize passing contiguous nocopy buffers to tcp_write (bug #46290)
|
||||
|
||||
2016-11-16: Dirk Ziegelmeier
|
||||
* sockets.c: added support for IPv6 mapped IPv4 addresses
|
||||
|
||||
++ Bugfixes:
|
||||
|
||||
2016-12-16: Thomas Mueller
|
||||
* api_lib.c: fixed race condition in return value of netconn_gethostbyname()
|
||||
(and thus also lwip_gethostbyname/_r() and lwip_getaddrinfo())
|
||||
|
||||
2016-12-15: David van Moolenbroek
|
||||
* opt.h, tcp: added LWIP_HOOK_TCP_ISN() to implement less predictable initial
|
||||
sequence numbers (see contrib/addons/tcp_isn for an example implementation)
|
||||
|
||||
2016-12-05: Dirk Ziegelmeier
|
||||
* fixed compiling with IPv4 disabled (IPv6 only case)
|
||||
|
||||
2016-11-28: Simon Goldschmidt
|
||||
* api_lib.c: fixed bug #49725 (send-timeout: netconn_write() can return
|
||||
ERR_OK without all bytes being written)
|
||||
|
||||
2016-11-28: Ambroz Bizjak
|
||||
* tcpi_in.c: fixed bug #49717 (window size in received SYN and SYN-ACK
|
||||
assumed scaled)
|
||||
|
||||
2016-11-25: Simon Goldschmidt
|
||||
* dhcp.c: fixed bug #49676 (Possible endless loop when parsing dhcp options)
|
||||
|
||||
2016-11-23: Dirk Ziegelmeier
|
||||
* udp.c: fixed bug #49662: multicast traffic is now only received on a UDP PCB
|
||||
(and therefore on a UDP socket/netconn) when the PCB is bound to IP_ADDR_ANY
|
||||
|
||||
2016-11-16: Dirk Ziegelmeier
|
||||
* *: Fixed dual-stack behaviour, IPv6 mapped IPv4 support in socket API
|
||||
|
||||
2016-11-14: Joel Cunningham
|
||||
* tcp_out.c: fixed bug #49533 (start persist timer when unsent seg can't fit
|
||||
in window)
|
||||
|
||||
2016-11-16: Roberto Barbieri Carrera
|
||||
* autoip.c: fixed bug #49610 (sometimes AutoIP fails to reuse the same address)
|
||||
|
||||
2016-11-11: Dirk Ziegelmeier
|
||||
* sockets.c: fixed bug #49578 (dropping multicast membership does not work
|
||||
with LWIP_SOCKET_OFFSET)
|
||||
|
||||
(STABLE-2.0.0)
|
||||
|
||||
++ New features:
|
||||
|
||||
2016-07-27: Simon Goldschmidt
|
||||
|
||||
20
CMakeLists.txt
Normal file
20
CMakeLists.txt
Normal file
@@ -0,0 +1,20 @@
|
||||
cmake_minimum_required(VERSION 3.7)
|
||||
|
||||
project(lwIP)
|
||||
|
||||
set(LWIP_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
include(src/Filelists.cmake)
|
||||
|
||||
# Package generation
|
||||
set(CPACK_SOURCE_GENERATOR "ZIP")
|
||||
set(CPACK_SOURCE_PACKAGE_DESCRIPTION_SUMMARY "lwIP lightweight IP stack")
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR "${LWIP_VERSION_MAJOR}")
|
||||
set(CPACK_PACKAGE_VERSION_MINOR "${LWIP_VERSION_MINOR}")
|
||||
set(CPACK_PACKAGE_VERSION_PATCH "${LWIP_VERSION_REVISION}")
|
||||
set(CPACK_SOURCE_IGNORE_FILES "/build/;${CPACK_SOURCE_IGNORE_FILES};.git")
|
||||
set(CPACK_SOURCE_PACKAGE_FILE_NAME "lwip-${LWIP_VERSION_MAJOR}.${LWIP_VERSION_MINOR}.${LWIP_VERSION_REVISION}")
|
||||
include(CPack)
|
||||
|
||||
# Target for package generation
|
||||
add_custom_target(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source)
|
||||
add_dependencies(dist lwipdocs)
|
||||
11
FEATURES
Normal file
11
FEATURES
Normal file
@@ -0,0 +1,11 @@
|
||||
lwIP is a small independent implementation of the TCP/IP protocol suite targeted at embedded systems.
|
||||
|
||||
The focus of the lwIP TCP/IP implementation is to reduce resource usage while still having a full scale TCP. This makes lwIP suitable for use in embedded systems with tens of kilobytes of free RAM and room for around 40 kilobytes of code ROM.
|
||||
|
||||
Main features include:
|
||||
- Protocols: IP, IPv6, ICMP, ND, MLD, UDP, TCP, IGMP, ARP, PPPoS, PPPoE, 6LowPAN (via IEEE 802.15.4, BLE or ZEP; since v2.1.0)
|
||||
- DHCP client, stateless DHCPv6 (since v2.1.0), DNS client (incl. mDNS hostname resolver), AutoIP/APIPA (Zeroconf), SNMP agent (v1, v2c, v3 (since v2.1.0), private MIB support & MIB compiler)
|
||||
- APIs: specialized APIs for enhanced performance & zero copy, optional Berkeley-alike socket API
|
||||
- Extended features: IP forwarding over multiple network interfaces
|
||||
- Extended TCP features: congestion control, RTT estimation and fast recovery/fast retransmit, sending SACKs (since v2.1.0), "altcp": nearly transparent TLS for any tcp pcb (since v2.1.0)
|
||||
- Addon applications: HTTP server (HTTPS via altcp), HTTP(S) client (since v2.1.0), SNTP client, SMTP client (SMTPS via altcp), ping, NetBIOS nameserver, mDNS responder, MQTT client (TLS support since v2.1.0), TFTP server, iPerf2 counterpart
|
||||
22
README
22
README
@@ -1,15 +1,15 @@
|
||||
INTRODUCTION
|
||||
|
||||
lwIP is a small independent implementation of the TCP/IP protocol
|
||||
suite that has been developed by Adam Dunkels at the Computer and
|
||||
Networks Architectures (CNA) lab at the Swedish Institute of Computer
|
||||
Science (SICS).
|
||||
lwIP is a small independent implementation of the TCP/IP protocol suite.
|
||||
|
||||
The focus of the lwIP TCP/IP implementation is to reduce the RAM usage
|
||||
while still having a full scale TCP. This making lwIP suitable for use
|
||||
in embedded systems with tens of kilobytes of free RAM and room for
|
||||
around 40 kilobytes of code ROM.
|
||||
|
||||
lwIP was originally developed by Adam Dunkels at the Computer and Networks
|
||||
Architectures (CNA) lab at the Swedish Institute of Computer Science (SICS)
|
||||
and is now developed and maintained by a worldwide network of developers.
|
||||
|
||||
FEATURES
|
||||
|
||||
@@ -22,22 +22,28 @@ FEATURES
|
||||
* ND (Neighbor discovery and stateless address autoconfiguration for IPv6).
|
||||
Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862
|
||||
(Address autoconfiguration)
|
||||
* DHCP, AutoIP/APIPA (Zeroconf) and (stateless) DHCPv6
|
||||
* UDP (User Datagram Protocol) including experimental UDP-lite extensions
|
||||
* TCP (Transmission Control Protocol) with congestion control, RTT estimation
|
||||
and fast recovery/fast retransmit
|
||||
fast recovery/fast retransmit and sending SACKs
|
||||
* raw/native API for enhanced performance
|
||||
* Optional Berkeley-like socket API
|
||||
* DNS (Domain names resolver)
|
||||
* TLS: optional layered TCP ("altcp") for nearly transparent TLS for any
|
||||
TCP-based protocol (ported to mbedTLS) (see changelog for more info)
|
||||
* PPPoS and PPPoE (Point-to-point protocol over Serial/Ethernet)
|
||||
* DNS (Domain name resolver incl. mDNS)
|
||||
* 6LoWPAN (via IEEE 802.15.4, BLE or ZEP)
|
||||
|
||||
|
||||
APPLICATIONS
|
||||
|
||||
* HTTP server with SSI and CGI
|
||||
* SNMPv2c agent with MIB compiler (Simple Network Management Protocol)
|
||||
* HTTP server with SSI and CGI (HTTPS via altcp)
|
||||
* SNMPv2c agent with MIB compiler (Simple Network Management Protocol), v3 via altcp
|
||||
* SNTP (Simple network time protocol)
|
||||
* NetBIOS name service responder
|
||||
* MDNS (Multicast DNS) responder
|
||||
* iPerf server implementation
|
||||
* MQTT client (TLS support via altcp)
|
||||
|
||||
|
||||
LICENSE
|
||||
|
||||
52
UPGRADING
52
UPGRADING
@@ -8,7 +8,57 @@ with newer versions.
|
||||
|
||||
* [Enter new changes just after this line - do not remove this line]
|
||||
|
||||
* TODO
|
||||
(2.1.0)
|
||||
|
||||
++ Application changes:
|
||||
|
||||
* Use the new altcp API for seamless TLS integration into existing TCP applications (see changelog)
|
||||
* TCP only kills existing connections with a LOWER priority than the one currently being opened.
|
||||
Previous implementations also kill existing connections of the SAME priority.
|
||||
* ip4_route_src: parameter order is reversed: ip4_route_src(dest, src) -> ip4_route_src(src, dest)
|
||||
to make parameter order consistent with other ip*_route*() functions.
|
||||
Same also applies to LWIP_HOOK_IP4_ROUTE_SRC() parameter order.
|
||||
* pbuf API: pbuf->type (an u8_t holding the enum 'pbuf_type') has changed to only hold a
|
||||
description of the pbuf (e.g. data following pbuf struct, data volatile, allocation
|
||||
source heap/pool/etc.). As a consequence, applications can't test pbuf->type any more.
|
||||
Use pbuf_match_type(pbuf, type) instead.
|
||||
* socket API: according to the standard, SO_ERROR now only returns asynchronous errors.
|
||||
All other/normal/synchronous errors are (and always were) available via 'errno'.
|
||||
LWIP_SOCKET_SET_ERRNO has been removed - 'errno' is always set - and required!
|
||||
* httpd LWIP_HTTPD_CGI_SSI: httpd_cgi_handler() has an additional parameter "struct fs_file *"
|
||||
|
||||
++ Port changes:
|
||||
|
||||
* tcpip_trycallback() was renamed to tcpip_callbackmsg_trycallback() to avoid confusion
|
||||
with tcpip_try_callback()
|
||||
* compatibility headers: moved from 'src/include/posix' to 'src/include/compat/posix',
|
||||
'src/include/compat/stdc' etc.
|
||||
* The IPv6 implementation now supports address scopes. (See LWIP_IPV6_SCOPES documentation
|
||||
and ip6_zone.h for more documentation)
|
||||
* LWIP_HOOK_DHCP_APPEND_OPTIONS() has changed, see description in opt.h (options_out_len is not
|
||||
available in struct dhcp any more)
|
||||
* Added debug helper asserts to ensure threading/locking requirements are met (define
|
||||
LWIP_MARK_TCPIP_THREAD() and LWIP_ASSERT_CORE_LOCKED()).
|
||||
* Added sys_mbox_trypost_fromisr() and tcpip_callbackmsg_trycallback_fromisr()
|
||||
These can be used to post preallocated messages from an ISR to the tcpip thread
|
||||
(e.g. when using FreeRTOS)
|
||||
|
||||
(2.0.2)
|
||||
|
||||
++ Application changes:
|
||||
|
||||
* slipif: The way to pass serial port number has changed. netif->num is not
|
||||
supported any more, netif->state is interpreted as an u8_t port number now
|
||||
(it's not a POINTER to an u8_t any more!)
|
||||
|
||||
(2.0.1)
|
||||
|
||||
++ Application changes:
|
||||
|
||||
* UDP does NOT receive multicast traffic from ALL netifs on an UDP PCB bound to a specific
|
||||
netif any more. Users need to bind to IP_ADDR_ANY to receive multicast traffic and compare
|
||||
ip_current_netif() to the desired netif for every packet.
|
||||
See bug #49662 for an explanation.
|
||||
|
||||
(2.0.0)
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
void eth_mac_irq()
|
||||
void
|
||||
eth_mac_irq()
|
||||
{
|
||||
/* Service MAC IRQ here */
|
||||
|
||||
@@ -17,7 +18,8 @@ void eth_mac_irq()
|
||||
}
|
||||
}
|
||||
|
||||
static err_t netif_output(struct netif *netif, struct pbuf *p)
|
||||
static err_t
|
||||
netif_output(struct netif *netif, struct pbuf *p)
|
||||
{
|
||||
LINK_STATS_INC(link.xmit);
|
||||
|
||||
@@ -38,12 +40,14 @@ static err_t netif_output(struct netif *netif, struct pbuf *p)
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static void netif_status_callback(struct netif *netif)
|
||||
static void
|
||||
netif_status_callback(struct netif *netif)
|
||||
{
|
||||
printf("netif status changed %s\n", ip4addr_ntoa(netif_ip4_addr(netif)));
|
||||
}
|
||||
|
||||
static err_t netif_init(struct netif *netif)
|
||||
static err_t
|
||||
netif_init(struct netif *netif)
|
||||
{
|
||||
netif->linkoutput = netif_output;
|
||||
netif->output = etharp_output;
|
||||
@@ -52,13 +56,14 @@ static err_t netif_init(struct netif *netif)
|
||||
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP | NETIF_FLAG_MLD6;
|
||||
MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, 100000000);
|
||||
|
||||
SMEMCPY(netif->hwaddr, your_mac_address_goes_here, sizeof(netif->hwaddr));
|
||||
netif->hwaddr_len = sizeof(netif->hwaddr);
|
||||
SMEMCPY(netif->hwaddr, your_mac_address_goes_here, ETH_HWADDR_LEN);
|
||||
netif->hwaddr_len = ETH_HWADDR_LEN;
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
void main(void)
|
||||
void
|
||||
main(void)
|
||||
{
|
||||
struct netif netif;
|
||||
|
||||
@@ -74,7 +79,7 @@ void main(void)
|
||||
netif_set_up(&netif);
|
||||
|
||||
/* Start DHCP and HTTPD */
|
||||
dhcp_init();
|
||||
dhcp_start(&netif );
|
||||
httpd_init();
|
||||
|
||||
while(1) {
|
||||
|
||||
45
doc/ZeroCopyRx.c
Normal file
45
doc/ZeroCopyRx.c
Normal file
@@ -0,0 +1,45 @@
|
||||
typedef struct my_custom_pbuf
|
||||
{
|
||||
struct pbuf_custom p;
|
||||
void* dma_descriptor;
|
||||
} my_custom_pbuf_t;
|
||||
|
||||
LWIP_MEMPOOL_DECLARE(RX_POOL, 10, sizeof(my_custom_pbuf_t), "Zero-copy RX PBUF pool");
|
||||
|
||||
void my_pbuf_free_custom(void* p)
|
||||
{
|
||||
SYS_ARCH_DECL_PROTECT(old_level);
|
||||
|
||||
my_custom_pbuf_t* my_puf = (my_custom_pbuf_t*)p;
|
||||
|
||||
// invalidate data cache here - lwIP and/or application may have written into buffer!
|
||||
// (invalidate is faster than flushing, and noone needs the correct data in the buffer)
|
||||
invalidate_cpu_cache(p->payload, p->tot_len);
|
||||
|
||||
SYS_ARCH_PROTECT(old_level);
|
||||
free_rx_dma_descriptor(my_pbuf->dma_descriptor);
|
||||
LWIP_MEMPOOL_FREE(RX_POOL, my_pbuf);
|
||||
SYS_ARCH_UNPROTECT(old_level);
|
||||
}
|
||||
|
||||
void eth_rx_irq()
|
||||
{
|
||||
dma_descriptor* dma_desc = get_RX_DMA_descriptor_from_ethernet();
|
||||
my_custom_pbuf_t* my_pbuf = (my_custom_pbuf_t*)LWIP_MEMPOOL_ALLOC(RX_POOL);
|
||||
|
||||
my_pbuf->p.custom_free_function = my_pbuf_free_custom;
|
||||
my_pbuf->dma_descriptor = dma_desc;
|
||||
|
||||
invalidate_cpu_cache(dma_desc->rx_data, dma_desc->rx_length);
|
||||
|
||||
struct pbuf* p = pbuf_alloced_custom(PBUF_RAW,
|
||||
dma_desc->rx_length,
|
||||
PBUF_REF,
|
||||
&my_pbuf->p,
|
||||
dma_desc->rx_data,
|
||||
dma_desc->max_buffer_size);
|
||||
|
||||
if(netif->input(p, netif) != ERR_OK) {
|
||||
pbuf_free(p);
|
||||
}
|
||||
}
|
||||
@@ -1 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
doxygen lwip.Doxyfile
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Doxyfile 1.8.11
|
||||
# Doxyfile 1.8.13
|
||||
|
||||
# This file describes the settings to be used by the documentation system
|
||||
# doxygen (www.doxygen.org) for a project.
|
||||
@@ -32,19 +32,19 @@ DOXYFILE_ENCODING = UTF-8
|
||||
# title of most generated pages and in a few other places.
|
||||
# The default value is: My Project.
|
||||
|
||||
PROJECT_NAME = "lwIP 2.0.0"
|
||||
PROJECT_NAME = "lwIP"
|
||||
|
||||
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = "lwIP 2.0.0"
|
||||
PROJECT_NUMBER = "2.1.3"
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
# quick idea about the purpose of the project. Keep the description short.
|
||||
|
||||
PROJECT_BRIEF = Lightweight IP stack
|
||||
PROJECT_BRIEF = "Lightweight IP stack"
|
||||
|
||||
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
|
||||
# in the documentation. The maximum height of the logo should not exceed 55
|
||||
@@ -58,7 +58,7 @@ PROJECT_LOGO =
|
||||
# entered, it will be relative to the location where doxygen was started. If
|
||||
# left blank the current directory will be used.
|
||||
|
||||
OUTPUT_DIRECTORY = output
|
||||
OUTPUT_DIRECTORY = "output"
|
||||
|
||||
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
|
||||
# directories (in 2 levels) under the output directory of each output format and
|
||||
@@ -303,6 +303,15 @@ EXTENSION_MAPPING =
|
||||
|
||||
MARKDOWN_SUPPORT = YES
|
||||
|
||||
# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
|
||||
# to that level are automatically included in the table of contents, even if
|
||||
# they do not have an id attribute.
|
||||
# Note: This feature currently applies only to Markdown headings.
|
||||
# Minimum value: 0, maximum value: 99, default value: 0.
|
||||
# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
|
||||
|
||||
TOC_INCLUDE_HEADINGS = 0
|
||||
|
||||
# When enabled doxygen tries to link words that correspond to documented
|
||||
# classes, or namespaces to their corresponding documentation. Such a link can
|
||||
# be prevented in individual cases by putting a % sign in front of the word or
|
||||
@@ -781,7 +790,8 @@ WARN_LOGFILE =
|
||||
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
||||
# Note: If this tag is empty the current directory is searched.
|
||||
|
||||
INPUT = main_page.h ../../src
|
||||
INPUT = main_page.h \
|
||||
../../src
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||
@@ -803,8 +813,8 @@ INPUT_ENCODING = UTF-8
|
||||
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
|
||||
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
|
||||
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
|
||||
# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f, *.for, *.tcl,
|
||||
# *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js.
|
||||
# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
|
||||
# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
|
||||
|
||||
FILE_PATTERNS = *.c \
|
||||
*.cc \
|
||||
@@ -875,7 +885,8 @@ EXCLUDE_SYMBOLS =
|
||||
# that contain example code fragments that are included (see the \include
|
||||
# command).
|
||||
|
||||
EXAMPLE_PATH = ../ ../../
|
||||
EXAMPLE_PATH = ../ \
|
||||
../../
|
||||
|
||||
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
|
||||
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
|
||||
@@ -2077,16 +2088,26 @@ PREDEFINED = __DOXYGEN__=1 \
|
||||
LWIP_ICMP=1 \
|
||||
LWIP_RAW=1 \
|
||||
LWIP_DHCP=1 \
|
||||
LWIP_IPV6_DHCP6=1 \
|
||||
LWIP_UDPLITE=1 \
|
||||
LWIP_UDP=1 \
|
||||
LWIP_IGMP=1 \
|
||||
LWIP_TCP=1 \
|
||||
LWIP_ALTCP=1 \
|
||||
LWIP_ALTCP_TLS=1 \
|
||||
LWIP_IPV6_SCOPES=1 \
|
||||
TCP_LISTEN_BACKLOG=1 \
|
||||
LWIP_SNMP=1 \
|
||||
SNMP_USE_NETCONN=1 \
|
||||
SNMP_USE_RAW=1 \
|
||||
MIB2_STATS=1 \
|
||||
LWIP_MDNS_RESPONDER=1 \
|
||||
HTTPD_ENABLE_HTTPS=1 \
|
||||
LWIP_HTTPD_CGI=1 \
|
||||
LWIP_HTTPD_SSI=1 \
|
||||
LWIP_HTTPD_SSI_RAW=1 \
|
||||
LWIP_HTTPD_SUPPORT_POST=1 \
|
||||
LWIP_HTTPD_POST_MANUAL_WND=1 \
|
||||
MEMP_OVERFLOW_CHECK=0 \
|
||||
MEMP_SANITY_CHECK=1 \
|
||||
LWIP_ARP=1 \
|
||||
@@ -2097,6 +2118,7 @@ PREDEFINED = __DOXYGEN__=1 \
|
||||
LWIP_NETIF_STATUS_CALLBACK=1 \
|
||||
LWIP_NETIF_REMOVE_CALLBACK=1 \
|
||||
LWIP_NETIF_LINK_CALLBACK=1 \
|
||||
LWIP_NETIF_EXT_STATUS_CALLBACK=1 \
|
||||
LWIP_NUM_NETIF_CLIENT_DATA=1 \
|
||||
ENABLE_LOOPBACK=1 \
|
||||
LWIP_AUTOIP=1 \
|
||||
@@ -2115,8 +2137,9 @@ PREDEFINED = __DOXYGEN__=1 \
|
||||
SO_REUSE=1 \
|
||||
SO_REUSE_RXTOALL=1 \
|
||||
LWIP_HAVE_SLIPIF=1 \
|
||||
LWIP_6LOWPAN=1
|
||||
|
||||
SLIP_RX_FROM_ISR=1 \
|
||||
LWIP_TCP_PCB_NUM_EXT_ARGS=1
|
||||
|
||||
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
|
||||
# tag can be used to specify a list of macro names that should be expanded. The
|
||||
# macro definition that is found in the sources will be used. Use the PREDEFINED
|
||||
@@ -2228,7 +2251,7 @@ HIDE_UNDOC_RELATIONS = YES
|
||||
# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
|
||||
# Bell Labs. The other options in this section have no effect if this option is
|
||||
# set to NO
|
||||
# The default value is: YES.
|
||||
# The default value is: NO.
|
||||
|
||||
HAVE_DOT = NO
|
||||
|
||||
@@ -2384,9 +2407,7 @@ DIRECTORY_GRAPH = YES
|
||||
# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
|
||||
# to make the SVG files visible in IE 9+ (other browsers do not have this
|
||||
# requirement).
|
||||
# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
|
||||
# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
|
||||
# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo,
|
||||
# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
|
||||
# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
|
||||
# png:gdiplus:gdiplus.
|
||||
# The default value is: png.
|
||||
@@ -2439,6 +2460,11 @@ DIAFILE_DIRS =
|
||||
|
||||
PLANTUML_JAR_PATH =
|
||||
|
||||
# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
|
||||
# configuration file for plantuml.
|
||||
|
||||
PLANTUML_CFG_FILE =
|
||||
|
||||
# When using plantuml, the specified paths are searched for files specified by
|
||||
# the !include statement in a plantuml block.
|
||||
|
||||
|
||||
2531
doc/doxygen/lwip.Doxyfile.cmake.in
Normal file
2531
doc/doxygen/lwip.Doxyfile.cmake.in
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,17 +1,90 @@
|
||||
/**
|
||||
/**
|
||||
* @defgroup lwip lwIP
|
||||
*
|
||||
* @defgroup infrastructure Infrastructure
|
||||
*
|
||||
* @defgroup api APIs
|
||||
* lwIP provides three Application Program's Interfaces (APIs) for programs
|
||||
* to use for communication with the TCP/IP code:
|
||||
* - low-level "core" / "callback" or @ref callbackstyle_api.
|
||||
* - higher-level @ref sequential_api.
|
||||
* - BSD-style @ref socket.
|
||||
*
|
||||
* The raw TCP/IP interface allows the application program to integrate
|
||||
* better with the TCP/IP code. Program execution is event based by
|
||||
* having callback functions being called from within the TCP/IP
|
||||
* code. The TCP/IP code and the application program both run in the same
|
||||
* thread. The sequential API has a much higher overhead and is not very
|
||||
* well suited for small systems since it forces a multithreaded paradigm
|
||||
* on the application.
|
||||
*
|
||||
* The raw TCP/IP interface is not only faster in terms of code execution
|
||||
* time but is also less memory intensive. The drawback is that program
|
||||
* development is somewhat harder and application programs written for
|
||||
* the raw TCP/IP interface are more difficult to understand. Still, this
|
||||
* is the preferred way of writing applications that should be small in
|
||||
* code size and memory usage.
|
||||
*
|
||||
* All APIs can be used simultaneously by different application
|
||||
* programs. In fact, the sequential API is implemented as an application
|
||||
* program using the raw TCP/IP interface.
|
||||
*
|
||||
* Do not confuse the lwIP raw API with raw Ethernet or IP sockets.
|
||||
* The former is a way of interfacing the lwIP network stack (including
|
||||
* TCP and UDP), the latter refers to processing raw Ethernet or IP data
|
||||
* instead of TCP connections or UDP packets.
|
||||
*
|
||||
* Raw API applications may never block since all packet processing
|
||||
* (input and output) as well as timer processing (TCP mainly) is done
|
||||
* in a single execution context.
|
||||
*
|
||||
* @defgroup callbackstyle_api Callback-style APIs
|
||||
* @defgroup callbackstyle_api "raw" APIs
|
||||
* @ingroup api
|
||||
* Non thread-safe APIs, callback style for maximum performance and minimum
|
||||
* memory footprint.
|
||||
* Program execution is driven by callbacks functions, which are then
|
||||
* invoked by the lwIP core when activity related to that application
|
||||
* occurs. A particular application may register to be notified via a
|
||||
* callback function for events such as incoming data available, outgoing
|
||||
* data sent, error notifications, poll timer expiration, connection
|
||||
* closed, etc. An application can provide a callback function to perform
|
||||
* processing for any or all of these events. Each callback is an ordinary
|
||||
* C function that is called from within the TCP/IP code. Every callback
|
||||
* function is passed the current TCP or UDP connection state as an
|
||||
* argument. Also, in order to be able to keep program specific state,
|
||||
* the callback functions are called with a program specified argument
|
||||
* that is independent of the TCP/IP state.
|
||||
* The raw API (sometimes called native API) is an event-driven API designed
|
||||
* to be used without an operating system that implements zero-copy send and
|
||||
* receive. This API is also used by the core stack for interaction between
|
||||
* the various protocols. It is the only API available when running lwIP
|
||||
* without an operating system.
|
||||
*
|
||||
* @defgroup sequential_api Sequential-style APIs
|
||||
* @ingroup api
|
||||
* Sequential-style APIs, blocking functions. More overhead, but can be called
|
||||
* from any thread except TCPIP thread.
|
||||
* The sequential API provides a way for ordinary, sequential, programs
|
||||
* to use the lwIP stack. It is quite similar to the BSD socket API. The
|
||||
* model of execution is based on the blocking open-read-write-close
|
||||
* paradigm. Since the TCP/IP stack is event based by nature, the TCP/IP
|
||||
* code and the application program must reside in different execution
|
||||
* contexts (threads).
|
||||
*
|
||||
* @defgroup addons Addons
|
||||
* @defgroup socket Socket API
|
||||
* @ingroup api
|
||||
* BSD-style socket API.\n
|
||||
* Thread-safe, to be called from non-TCPIP threads only.\n
|
||||
* Can be activated by defining @ref LWIP_SOCKET to 1.\n
|
||||
* Header is in posix/sys/socket.h\n
|
||||
* The socket API is a compatibility API for existing applications,
|
||||
* currently it is built on top of the sequential API. It is meant to
|
||||
* provide all functions needed to run socket API applications running
|
||||
* on other platforms (e.g. unix / windows etc.). However, due to limitations
|
||||
* in the specification of this API, there might be incompatibilities
|
||||
* that require small modifications of existing programs.
|
||||
*
|
||||
* @defgroup netifs NETIFs
|
||||
*
|
||||
* @defgroup apps Applications
|
||||
*/
|
||||
@@ -26,6 +99,25 @@
|
||||
* @verbinclude "UPGRADING"
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page changelog Changelog
|
||||
*
|
||||
* 2.1.0
|
||||
* -----
|
||||
* * Support TLS via new @ref altcp_api connection API (https, smtps, mqtt over TLS)
|
||||
* * Switch to cmake as the main build system (Makefile file lists are still
|
||||
* maintained for now)
|
||||
* * Improve IPv6 support: support address scopes, support stateless DHCPv6, bugfixes
|
||||
* * Add debug helper asserts to ensure threading/locking requirements are met
|
||||
* * Add sys_mbox_trypost_fromisr() and tcpip_callbackmsg_trycallback_fromisr()
|
||||
* (for FreeRTOS, mainly)
|
||||
* * socket API: support poll(), sendmsg() and recvmsg(); fix problems on close
|
||||
*
|
||||
* Detailed Changelog
|
||||
* ------------------
|
||||
* @verbinclude "CHANGELOG"
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page contrib How to contribute to lwIP
|
||||
* @verbinclude "contrib.txt"
|
||||
@@ -43,6 +135,8 @@
|
||||
* lwIP can be used in two basic modes: @ref lwip_nosys (no OS/RTOS
|
||||
* running on target system) or @ref lwip_os (there is an OS running
|
||||
* on the target system).
|
||||
*
|
||||
* See also: @ref multithreading (especially the part about @ref LWIP_ASSERT_CORE_LOCKED()!)
|
||||
*
|
||||
* Mainloop Mode
|
||||
* -------------
|
||||
@@ -86,6 +180,37 @@
|
||||
* @ref LOCK_TCPIP_CORE() and @ref UNLOCK_TCPIP_CORE().
|
||||
* These macros cannot be used in an interrupt context!
|
||||
* Note the OS must correctly handle priority inversion for this.
|
||||
*
|
||||
* Cache / DMA issues
|
||||
* ==================
|
||||
*
|
||||
* DMA-capable ethernet hardware and zero-copy RX
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* lwIP changes the content of RECEIVED pbufs in the TCP code path.
|
||||
* This implies one or more cacheline(s) of the RX pbuf become dirty
|
||||
* and need to be flushed before the memory is handed over to the
|
||||
* DMA ethernet hardware for the next telegram to be received.
|
||||
* See http://lists.nongnu.org/archive/html/lwip-devel/2017-12/msg00070.html
|
||||
* for a more detailed explanation.
|
||||
* Also keep in mind the user application may also write into pbufs,
|
||||
* so it is generally a bug not to flush the data cache before handing
|
||||
* a buffer to DMA hardware.
|
||||
*
|
||||
* DMA-capable ethernet hardware and cacheline alignment
|
||||
* -----------------------------------------------------
|
||||
* Nice description about DMA capable hardware and buffer handling:
|
||||
* http://www.pebblebay.com/a-guide-to-using-direct-memory-access-in-embedded-systems-part-two/
|
||||
* Read especially sections "Cache coherency" and "Buffer alignment".
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page mem_err Debugging memory pool sizes
|
||||
* If you have issues with lwIP and you are using memory pools, check that your pools
|
||||
* are correctly sized.\n
|
||||
* To debug pool sizes, \#define LWIP_STATS and MEMP_STATS to 1. Check the global variable
|
||||
* lwip_stats.memp[] using a debugger. If the "err" member of a pool is > 0, the pool
|
||||
* may be too small for your application and you need to increase its size.
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -95,6 +220,12 @@
|
||||
* https://savannah.nongnu.org/bugs/?group=lwip
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page zerocopyrx Zero-copy RX
|
||||
* The following code is an example for zero-copy RX ethernet driver:
|
||||
* @include ZeroCopyRx.c
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup lwip_nosys Mainloop mode ("NO_SYS")
|
||||
* @ingroup lwip
|
||||
@@ -103,7 +234,8 @@
|
||||
* *not* *from* *interrupt* *context*. You can allocate a @ref pbuf in interrupt
|
||||
* context and put them into a queue which is processed from mainloop.\n
|
||||
* Call sys_check_timeouts() periodically in the mainloop.\n
|
||||
* Porting: implement all functions in @ref sys_time and @ref sys_prot.\n
|
||||
* Porting: implement all functions in @ref sys_time, @ref sys_prot and
|
||||
* @ref compiler_abstraction.\n
|
||||
* You can only use @ref callbackstyle_api in this mode.\n
|
||||
* Sample code:\n
|
||||
* @include NO_SYS_SampleCode.c
|
||||
@@ -121,6 +253,160 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page raw_api lwIP API
|
||||
* @verbinclude "rawapi.txt"
|
||||
* @page sys_init System initalization
|
||||
A truly complete and generic sequence for initializing the lwIP stack
|
||||
cannot be given because it depends on additional initializations for
|
||||
your runtime environment (e.g. timers).
|
||||
|
||||
We can give you some idea on how to proceed when using the raw API.
|
||||
We assume a configuration using a single Ethernet netif and the
|
||||
UDP and TCP transport layers, IPv4 and the DHCP client.
|
||||
|
||||
Call these functions in the order of appearance:
|
||||
|
||||
- lwip_init(): Initialize the lwIP stack and all of its subsystems.
|
||||
|
||||
- netif_add(struct netif *netif, ...):
|
||||
Adds your network interface to the netif_list. Allocate a struct
|
||||
netif and pass a pointer to this structure as the first argument.
|
||||
Give pointers to cleared ip_addr structures when using DHCP,
|
||||
or fill them with sane numbers otherwise. The state pointer may be NULL.
|
||||
|
||||
The init function pointer must point to a initialization function for
|
||||
your Ethernet netif interface. The following code illustrates its use.
|
||||
|
||||
@code{.c}
|
||||
err_t netif_if_init(struct netif *netif)
|
||||
{
|
||||
u8_t i;
|
||||
|
||||
for (i = 0; i < ETHARP_HWADDR_LEN; i++) {
|
||||
netif->hwaddr[i] = some_eth_addr[i];
|
||||
}
|
||||
init_my_eth_device();
|
||||
return ERR_OK;
|
||||
}
|
||||
@endcode
|
||||
|
||||
For Ethernet drivers, the input function pointer must point to the lwIP
|
||||
function ethernet_input() declared in "netif/etharp.h". Other drivers
|
||||
must use ip_input() declared in "lwip/ip.h".
|
||||
|
||||
- netif_set_default(struct netif *netif)
|
||||
Registers the default network interface.
|
||||
|
||||
- netif_set_link_up(struct netif *netif)
|
||||
This is the hardware link state; e.g. whether cable is plugged for wired
|
||||
Ethernet interface. This function must be called even if you don't know
|
||||
the current state. Having link up and link down events is optional but
|
||||
DHCP and IPv6 discover benefit well from those events.
|
||||
|
||||
- netif_set_up(struct netif *netif)
|
||||
This is the administrative (= software) state of the netif, when the
|
||||
netif is fully configured this function must be called.
|
||||
|
||||
- dhcp_start(struct netif *netif)
|
||||
Creates a new DHCP client for this interface on the first call.
|
||||
You can peek in the netif->dhcp struct for the actual DHCP status.
|
||||
|
||||
- sys_check_timeouts()
|
||||
When the system is running, you have to periodically call
|
||||
sys_check_timeouts() which will handle all timers for all protocols in
|
||||
the stack; add this to your main loop or equivalent.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page multithreading Multithreading
|
||||
* lwIP started targeting single-threaded environments. When adding multi-
|
||||
* threading support, instead of making the core thread-safe, another
|
||||
* approach was chosen: there is one main thread running the lwIP core
|
||||
* (also known as the "tcpip_thread"). When running in a multithreaded
|
||||
* environment, raw API functions MUST only be called from the core thread
|
||||
* since raw API functions are not protected from concurrent access (aside
|
||||
* from pbuf- and memory management functions). Application threads using
|
||||
* the sequential- or socket API communicate with this main thread through
|
||||
* message passing.
|
||||
*
|
||||
* As such, the list of functions that may be called from
|
||||
* other threads or an ISR is very limited! Only functions
|
||||
* from these API header files are thread-safe:
|
||||
* - api.h
|
||||
* - netbuf.h
|
||||
* - netdb.h
|
||||
* - netifapi.h
|
||||
* - pppapi.h
|
||||
* - sockets.h
|
||||
* - sys.h
|
||||
*
|
||||
* Additionaly, memory (de-)allocation functions may be
|
||||
* called from multiple threads (not ISR!) with NO_SYS=0
|
||||
* since they are protected by @ref SYS_LIGHTWEIGHT_PROT and/or
|
||||
* semaphores.
|
||||
*
|
||||
* Netconn or Socket API functions are thread safe against the
|
||||
* core thread but they are not reentrant at the control block
|
||||
* granularity level. That is, a UDP or TCP control block must
|
||||
* not be shared among multiple threads without proper locking.
|
||||
*
|
||||
* If @ref SYS_LIGHTWEIGHT_PROT is set to 1 and
|
||||
* @ref LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT is set to 1,
|
||||
* pbuf_free() may also be called from another thread or
|
||||
* an ISR (since only then, mem_free - for PBUF_RAM - may
|
||||
* be called from an ISR: otherwise, the HEAP is only
|
||||
* protected by semaphores).
|
||||
*
|
||||
* How to get threading done right
|
||||
* -------------------------------
|
||||
*
|
||||
* It is strongly recommended to implement the LWIP_ASSERT_CORE_LOCKED()
|
||||
* macro in an application that uses multithreading. lwIP code has
|
||||
* several places where a check for a correct thread context is
|
||||
* implemented which greatly helps the user to get threading done right.
|
||||
* See the example sys_arch.c files in unix and Win32 port
|
||||
* in the contrib repository.
|
||||
*
|
||||
* In short: Copy the functions sys_mark_tcpip_thread() and
|
||||
* sys_check_core_locking() to your port and modify them to work with your OS.
|
||||
* Then let @ref LWIP_ASSERT_CORE_LOCKED() and @ref LWIP_MARK_TCPIP_THREAD()
|
||||
* point to these functions.
|
||||
*
|
||||
* If you use @ref LWIP_TCPIP_CORE_LOCKING, you also need to copy and adapt
|
||||
* the functions sys_lock_tcpip_core() and sys_unlock_tcpip_core().
|
||||
* Let @ref LOCK_TCPIP_CORE() and @ref UNLOCK_TCPIP_CORE() point
|
||||
* to these functions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page optimization Optimization hints
|
||||
The first thing you want to optimize is the lwip_standard_checksum()
|
||||
routine from src/core/inet.c. You can override this standard
|
||||
function with the \#define LWIP_CHKSUM your_checksum_routine().
|
||||
|
||||
There are C examples given in inet.c or you might want to
|
||||
craft an assembly function for this. RFC1071 is a good
|
||||
introduction to this subject.
|
||||
|
||||
Other significant improvements can be made by supplying
|
||||
assembly or inline replacements for htons() and htonl()
|
||||
if you're using a little-endian architecture.
|
||||
\#define lwip_htons(x) your_htons()
|
||||
\#define lwip_htonl(x) your_htonl()
|
||||
If you \#define them to htons() and htonl(), you should
|
||||
\#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS to prevent lwIP from
|
||||
defining htonx / ntohx compatibility macros.
|
||||
|
||||
Check your network interface driver if it reads at
|
||||
a higher speed than the maximum wire-speed. If the
|
||||
hardware isn't serviced frequently and fast enough
|
||||
buffer overflows are likely to occur.
|
||||
|
||||
E.g. when using the cs8900 driver, call cs8900if_service(ethif)
|
||||
as frequently as possible. When using an RTOS let the cs8900 interrupt
|
||||
wake a high priority task that services your driver using a binary
|
||||
semaphore or event flag. Some drivers might allow additional tuning
|
||||
to match your application and network.
|
||||
|
||||
For a production release it is recommended to set LWIP_STATS to 0.
|
||||
Note that speed performance isn't influenced much by simply setting
|
||||
high values to the memory options.
|
||||
*/
|
||||
|
||||
17
doc/mdns.txt
17
doc/mdns.txt
@@ -32,8 +32,8 @@ generated.
|
||||
The MDNS code puts its structs on the stack where suitable to reduce dynamic
|
||||
memory allocation. It may use up to 1kB of stack.
|
||||
|
||||
MDNS needs a strncasecmp() implementation. If you have one, define
|
||||
LWIP_MDNS_STRNCASECMP to it. Otherwise the code will provide an implementation
|
||||
MDNS (like other apps) needs a strncasecmp() implementation. If you have one, define
|
||||
'lwip_strnicmp' to it. Otherwise the code will provide an implementation
|
||||
for you.
|
||||
|
||||
|
||||
@@ -57,11 +57,11 @@ Answers will use the supplied TTL (in seconds)
|
||||
MDNS allows UTF-8 names, but it is recommended to stay within ASCII,
|
||||
since the default case-insensitive comparison assumes this.
|
||||
|
||||
It is recommended to call this function after an IPv4 address has been set,
|
||||
since there is currently no check if the v4 address is valid.
|
||||
Call mdns_resp_announce() every time the IP address on the netif has changed.
|
||||
|
||||
Call mdns_resp_netif_settings_changed() every time the IP address
|
||||
on the netif has changed.
|
||||
Call mdns_resp_restart() every time the network interface comes up after being
|
||||
down, for example cable connected after being disconnected, administrative
|
||||
interface comes up after being down, or the device wakes up from sleep.
|
||||
|
||||
To stop responding on a netif, run
|
||||
mdns_resp_remove_netif(struct netif *netif)
|
||||
@@ -108,6 +108,5 @@ and point them to <hostname>.local:80
|
||||
Relevant information will be sent as additional records to reduce number of
|
||||
requests required from a client.
|
||||
|
||||
Removing services is currently not supported. Services are removed when the
|
||||
netif is removed.
|
||||
|
||||
To remove a service from a netif, run
|
||||
mdns_resp_del_service(struct netif *netif, s8_t slot)
|
||||
162
doc/mqtt_client.txt
Normal file
162
doc/mqtt_client.txt
Normal file
@@ -0,0 +1,162 @@
|
||||
MQTT client for lwIP
|
||||
|
||||
Author: Erik Andersson
|
||||
|
||||
Details of the MQTT protocol can be found at:
|
||||
http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html
|
||||
|
||||
-----------------------------------------------------------------
|
||||
1. Initial steps, reserve memory and make connection to server:
|
||||
|
||||
1.1: Provide storage
|
||||
|
||||
Static allocation:
|
||||
mqtt_client_t static_client;
|
||||
example_do_connect(&static_client);
|
||||
|
||||
Dynamic allocation:
|
||||
mqtt_client_t *client = mqtt_client_new();
|
||||
if(client != NULL) {
|
||||
example_do_connect(&client);
|
||||
}
|
||||
|
||||
1.2: Establish Connection with server
|
||||
|
||||
void example_do_connect(mqtt_client_t *client)
|
||||
{
|
||||
struct mqtt_connect_client_info_t ci;
|
||||
err_t err;
|
||||
|
||||
/* Setup an empty client info structure */
|
||||
memset(&ci, 0, sizeof(ci));
|
||||
|
||||
/* Minimal amount of information required is client identifier, so set it here */
|
||||
ci.client_id = "lwip_test";
|
||||
|
||||
/* Initiate client and connect to server, if this fails immediately an error code is returned
|
||||
otherwise mqtt_connection_cb will be called with connection result after attempting
|
||||
to establish a connection with the server.
|
||||
For now MQTT version 3.1.1 is always used */
|
||||
|
||||
err = mqtt_client_connect(client, ip_addr, MQTT_PORT, mqtt_connection_cb, 0, &ci);
|
||||
|
||||
/* For now just print the result code if something goes wrong */
|
||||
if(err != ERR_OK) {
|
||||
printf("mqtt_connect return %d\n", err);
|
||||
}
|
||||
}
|
||||
|
||||
Connection to server can also be probed by calling mqtt_client_is_connected(client)
|
||||
|
||||
-----------------------------------------------------------------
|
||||
2. Implementing the connection status callback
|
||||
|
||||
|
||||
static void mqtt_connection_cb(mqtt_client_t *client, void *arg, mqtt_connection_status_t status)
|
||||
{
|
||||
err_t err;
|
||||
if(status == MQTT_CONNECT_ACCEPTED) {
|
||||
printf("mqtt_connection_cb: Successfully connected\n");
|
||||
|
||||
/* Setup callback for incoming publish requests */
|
||||
mqtt_set_inpub_callback(client, mqtt_incoming_publish_cb, mqtt_incoming_data_cb, arg);
|
||||
|
||||
/* Subscribe to a topic named "subtopic" with QoS level 1, call mqtt_sub_request_cb with result */
|
||||
err = mqtt_subscribe(client, "subtopic", 1, mqtt_sub_request_cb, arg);
|
||||
|
||||
if(err != ERR_OK) {
|
||||
printf("mqtt_subscribe return: %d\n", err);
|
||||
}
|
||||
} else {
|
||||
printf("mqtt_connection_cb: Disconnected, reason: %d\n", status);
|
||||
|
||||
/* Its more nice to be connected, so try to reconnect */
|
||||
example_do_connect(client);
|
||||
}
|
||||
}
|
||||
|
||||
static void mqtt_sub_request_cb(void *arg, err_t result)
|
||||
{
|
||||
/* Just print the result code here for simplicity,
|
||||
normal behaviour would be to take some action if subscribe fails like
|
||||
notifying user, retry subscribe or disconnect from server */
|
||||
printf("Subscribe result: %d\n", result);
|
||||
}
|
||||
|
||||
-----------------------------------------------------------------
|
||||
3. Implementing callbacks for incoming publish and data
|
||||
|
||||
/* The idea is to demultiplex topic and create some reference to be used in data callbacks
|
||||
Example here uses a global variable, better would be to use a member in arg
|
||||
If RAM and CPU budget allows it, the easiest implementation might be to just take a copy of
|
||||
the topic string and use it in mqtt_incoming_data_cb
|
||||
*/
|
||||
static int inpub_id;
|
||||
static void mqtt_incoming_publish_cb(void *arg, const char *topic, u32_t tot_len)
|
||||
{
|
||||
printf("Incoming publish at topic %s with total length %u\n", topic, (unsigned int)tot_len);
|
||||
|
||||
/* Decode topic string into a user defined reference */
|
||||
if(strcmp(topic, "print_payload") == 0) {
|
||||
inpub_id = 0;
|
||||
} else if(topic[0] == 'A') {
|
||||
/* All topics starting with 'A' might be handled at the same way */
|
||||
inpub_id = 1;
|
||||
} else {
|
||||
/* For all other topics */
|
||||
inpub_id = 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void mqtt_incoming_data_cb(void *arg, const u8_t *data, u16_t len, u8_t flags)
|
||||
{
|
||||
printf("Incoming publish payload with length %d, flags %u\n", len, (unsigned int)flags);
|
||||
|
||||
if(flags & MQTT_DATA_FLAG_LAST) {
|
||||
/* Last fragment of payload received (or whole part if payload fits receive buffer
|
||||
See MQTT_VAR_HEADER_BUFFER_LEN) */
|
||||
|
||||
/* Call function or do action depending on reference, in this case inpub_id */
|
||||
if(inpub_id == 0) {
|
||||
/* Don't trust the publisher, check zero termination */
|
||||
if(data[len-1] == 0) {
|
||||
printf("mqtt_incoming_data_cb: %s\n", (const char *)data);
|
||||
}
|
||||
} else if(inpub_id == 1) {
|
||||
/* Call an 'A' function... */
|
||||
} else {
|
||||
printf("mqtt_incoming_data_cb: Ignoring payload...\n");
|
||||
}
|
||||
} else {
|
||||
/* Handle fragmented payload, store in buffer, write to file or whatever */
|
||||
}
|
||||
}
|
||||
|
||||
-----------------------------------------------------------------
|
||||
4. Using outgoing publish
|
||||
|
||||
|
||||
void example_publish(mqtt_client_t *client, void *arg)
|
||||
{
|
||||
const char *pub_payload= "PubSubHubLubJub";
|
||||
err_t err;
|
||||
u8_t qos = 2; /* 0 1 or 2, see MQTT specification */
|
||||
u8_t retain = 0; /* No don't retain such crappy payload... */
|
||||
err = mqtt_publish(client, "pub_topic", pub_payload, strlen(pub_payload), qos, retain, mqtt_pub_request_cb, arg);
|
||||
if(err != ERR_OK) {
|
||||
printf("Publish err: %d\n", err);
|
||||
}
|
||||
}
|
||||
|
||||
/* Called when publish is complete either with sucess or failure */
|
||||
static void mqtt_pub_request_cb(void *arg, err_t result)
|
||||
{
|
||||
if(result != ERR_OK) {
|
||||
printf("Publish result: %d\n", result);
|
||||
}
|
||||
}
|
||||
|
||||
-----------------------------------------------------------------
|
||||
5. Disconnecting
|
||||
|
||||
Simply call mqtt_disconnect(client)
|
||||
499
doc/rawapi.txt
499
doc/rawapi.txt
@@ -1,499 +0,0 @@
|
||||
Raw TCP/IP interface for lwIP
|
||||
|
||||
Authors: Adam Dunkels, Leon Woestenberg, Christiaan Simons
|
||||
|
||||
lwIP provides three Application Program's Interfaces (APIs) for programs
|
||||
to use for communication with the TCP/IP code:
|
||||
* low-level "core" / "callback" or "raw" API.
|
||||
* higher-level "sequential" API.
|
||||
* BSD-style socket API.
|
||||
|
||||
The raw API (sometimes called native API) is an event-driven API designed
|
||||
to be used without an operating system that implements zero-copy send and
|
||||
receive. This API is also used by the core stack for interaction between
|
||||
the various protocols. It is the only API available when running lwIP
|
||||
without an operating system.
|
||||
|
||||
The sequential API provides a way for ordinary, sequential, programs
|
||||
to use the lwIP stack. It is quite similar to the BSD socket API. The
|
||||
model of execution is based on the blocking open-read-write-close
|
||||
paradigm. Since the TCP/IP stack is event based by nature, the TCP/IP
|
||||
code and the application program must reside in different execution
|
||||
contexts (threads).
|
||||
|
||||
The socket API is a compatibility API for existing applications,
|
||||
currently it is built on top of the sequential API. It is meant to
|
||||
provide all functions needed to run socket API applications running
|
||||
on other platforms (e.g. unix / windows etc.). However, due to limitations
|
||||
in the specification of this API, there might be incompatibilities
|
||||
that require small modifications of existing programs.
|
||||
|
||||
** Multithreading
|
||||
|
||||
lwIP started targeting single-threaded environments. When adding multi-
|
||||
threading support, instead of making the core thread-safe, another
|
||||
approach was chosen: there is one main thread running the lwIP core
|
||||
(also known as the "tcpip_thread"). When running in a multithreaded
|
||||
environment, raw API functions MUST only be called from the core thread
|
||||
since raw API functions are not protected from concurrent access (aside
|
||||
from pbuf- and memory management functions). Application threads using
|
||||
the sequential- or socket API communicate with this main thread through
|
||||
message passing.
|
||||
|
||||
As such, the list of functions that may be called from
|
||||
other threads or an ISR is very limited! Only functions
|
||||
from these API header files are thread-safe:
|
||||
- api.h
|
||||
- netbuf.h
|
||||
- netdb.h
|
||||
- netifapi.h
|
||||
- pppapi.h
|
||||
- sockets.h
|
||||
- sys.h
|
||||
|
||||
Additionaly, memory (de-)allocation functions may be
|
||||
called from multiple threads (not ISR!) with NO_SYS=0
|
||||
since they are protected by SYS_LIGHTWEIGHT_PROT and/or
|
||||
semaphores.
|
||||
|
||||
Netconn or Socket API functions are thread safe against the
|
||||
core thread but they are not reentrant at the control block
|
||||
granularity level. That is, a UDP or TCP control block must
|
||||
not be shared among multiple threads without proper locking.
|
||||
|
||||
If SYS_LIGHTWEIGHT_PROT is set to 1 and
|
||||
LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT is set to 1,
|
||||
pbuf_free() may also be called from another thread or
|
||||
an ISR (since only then, mem_free - for PBUF_RAM - may
|
||||
be called from an ISR: otherwise, the HEAP is only
|
||||
protected by semaphores).
|
||||
|
||||
|
||||
** The remainder of this document discusses the "raw" API. **
|
||||
|
||||
The raw TCP/IP interface allows the application program to integrate
|
||||
better with the TCP/IP code. Program execution is event based by
|
||||
having callback functions being called from within the TCP/IP
|
||||
code. The TCP/IP code and the application program both run in the same
|
||||
thread. The sequential API has a much higher overhead and is not very
|
||||
well suited for small systems since it forces a multithreaded paradigm
|
||||
on the application.
|
||||
|
||||
The raw TCP/IP interface is not only faster in terms of code execution
|
||||
time but is also less memory intensive. The drawback is that program
|
||||
development is somewhat harder and application programs written for
|
||||
the raw TCP/IP interface are more difficult to understand. Still, this
|
||||
is the preferred way of writing applications that should be small in
|
||||
code size and memory usage.
|
||||
|
||||
All APIs can be used simultaneously by different application
|
||||
programs. In fact, the sequential API is implemented as an application
|
||||
program using the raw TCP/IP interface.
|
||||
|
||||
Do not confuse the lwIP raw API with raw Ethernet or IP sockets.
|
||||
The former is a way of interfacing the lwIP network stack (including
|
||||
TCP and UDP), the later refers to processing raw Ethernet or IP data
|
||||
instead of TCP connections or UDP packets.
|
||||
|
||||
Raw API applications may never block since all packet processing
|
||||
(input and output) as well as timer processing (TCP mainly) is done
|
||||
in a single execution context.
|
||||
|
||||
--- Callbacks
|
||||
|
||||
Program execution is driven by callbacks functions, which are then
|
||||
invoked by the lwIP core when activity related to that application
|
||||
occurs. A particular application may register to be notified via a
|
||||
callback function for events such as incoming data available, outgoing
|
||||
data sent, error notifications, poll timer expiration, connection
|
||||
closed, etc. An application can provide a callback function to perform
|
||||
processing for any or all of these events. Each callback is an ordinary
|
||||
C function that is called from within the TCP/IP code. Every callback
|
||||
function is passed the current TCP or UDP connection state as an
|
||||
argument. Also, in order to be able to keep program specific state,
|
||||
the callback functions are called with a program specified argument
|
||||
that is independent of the TCP/IP state.
|
||||
|
||||
The function for setting the application connection state is:
|
||||
|
||||
- void tcp_arg(struct tcp_pcb *pcb, void *arg)
|
||||
|
||||
Specifies the program specific state that should be passed to all
|
||||
other callback functions. The "pcb" argument is the current TCP
|
||||
connection control block, and the "arg" argument is the argument
|
||||
that will be passed to the callbacks.
|
||||
|
||||
|
||||
--- TCP connection setup
|
||||
|
||||
The functions used for setting up connections is similar to that of
|
||||
the sequential API and of the BSD socket API. A new TCP connection
|
||||
identifier (i.e., a protocol control block - PCB) is created with the
|
||||
tcp_new() function. This PCB can then be either set to listen for new
|
||||
incoming connections or be explicitly connected to another host.
|
||||
|
||||
- struct tcp_pcb *tcp_new(void)
|
||||
|
||||
Creates a new connection identifier (PCB). If memory is not
|
||||
available for creating the new pcb, NULL is returned.
|
||||
|
||||
- err_t tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr,
|
||||
u16_t port)
|
||||
|
||||
Binds the pcb to a local IP address and port number. The IP address
|
||||
can be specified as IP_ADDR_ANY in order to bind the connection to
|
||||
all local IP addresses.
|
||||
|
||||
If another connection is bound to the same port, the function will
|
||||
return ERR_USE, otherwise ERR_OK is returned.
|
||||
|
||||
- struct tcp_pcb *tcp_listen(struct tcp_pcb *pcb)
|
||||
|
||||
Commands a pcb to start listening for incoming connections. When an
|
||||
incoming connection is accepted, the function specified with the
|
||||
tcp_accept() function will be called. The pcb will have to be bound
|
||||
to a local port with the tcp_bind() function.
|
||||
|
||||
The tcp_listen() function returns a new connection identifier, and
|
||||
the one passed as an argument to the function will be
|
||||
deallocated. The reason for this behavior is that less memory is
|
||||
needed for a connection that is listening, so tcp_listen() will
|
||||
reclaim the memory needed for the original connection and allocate a
|
||||
new smaller memory block for the listening connection.
|
||||
|
||||
tcp_listen() may return NULL if no memory was available for the
|
||||
listening connection. If so, the memory associated with the pcb
|
||||
passed as an argument to tcp_listen() will not be deallocated.
|
||||
|
||||
- struct tcp_pcb *tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
|
||||
|
||||
Same as tcp_listen, but limits the number of outstanding connections
|
||||
in the listen queue to the value specified by the backlog argument.
|
||||
To use it, your need to set TCP_LISTEN_BACKLOG=1 in your lwipopts.h.
|
||||
|
||||
- void tcp_accept(struct tcp_pcb *pcb,
|
||||
err_t (* accept)(void *arg, struct tcp_pcb *newpcb,
|
||||
err_t err))
|
||||
|
||||
Specified the callback function that should be called when a new
|
||||
connection arrives on a listening connection.
|
||||
|
||||
- err_t tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr,
|
||||
u16_t port, err_t (* connected)(void *arg,
|
||||
struct tcp_pcb *tpcb,
|
||||
err_t err));
|
||||
|
||||
Sets up the pcb to connect to the remote host and sends the
|
||||
initial SYN segment which opens the connection.
|
||||
|
||||
The tcp_connect() function returns immediately; it does not wait for
|
||||
the connection to be properly setup. Instead, it will call the
|
||||
function specified as the fourth argument (the "connected" argument)
|
||||
when the connection is established. If the connection could not be
|
||||
properly established, either because the other host refused the
|
||||
connection or because the other host didn't answer, the "err"
|
||||
callback function of this pcb (registered with tcp_err, see below)
|
||||
will be called.
|
||||
|
||||
The tcp_connect() function can return ERR_MEM if no memory is
|
||||
available for enqueueing the SYN segment. If the SYN indeed was
|
||||
enqueued successfully, the tcp_connect() function returns ERR_OK.
|
||||
|
||||
|
||||
--- Sending TCP data
|
||||
|
||||
TCP data is sent by enqueueing the data with a call to
|
||||
tcp_write(). When the data is successfully transmitted to the remote
|
||||
host, the application will be notified with a call to a specified
|
||||
callback function.
|
||||
|
||||
- err_t tcp_write(struct tcp_pcb *pcb, const void *dataptr, u16_t len,
|
||||
u8_t apiflags)
|
||||
|
||||
Enqueues the data pointed to by the argument dataptr. The length of
|
||||
the data is passed as the len parameter. The apiflags can be one or more of:
|
||||
- TCP_WRITE_FLAG_COPY: indicates whether the new memory should be allocated
|
||||
for the data to be copied into. If this flag is not given, no new memory
|
||||
should be allocated and the data should only be referenced by pointer. This
|
||||
also means that the memory behind dataptr must not change until the data is
|
||||
ACKed by the remote host
|
||||
- TCP_WRITE_FLAG_MORE: indicates that more data follows. If this is omitted,
|
||||
the PSH flag is set in the last segment created by this call to tcp_write.
|
||||
If this flag is given, the PSH flag is not set.
|
||||
|
||||
The tcp_write() function will fail and return ERR_MEM if the length
|
||||
of the data exceeds the current send buffer size or if the length of
|
||||
the queue of outgoing segment is larger than the upper limit defined
|
||||
in lwipopts.h. The number of bytes available in the output queue can
|
||||
be retrieved with the tcp_sndbuf() function.
|
||||
|
||||
The proper way to use this function is to call the function with at
|
||||
most tcp_sndbuf() bytes of data. If the function returns ERR_MEM,
|
||||
the application should wait until some of the currently enqueued
|
||||
data has been successfully received by the other host and try again.
|
||||
|
||||
- void tcp_sent(struct tcp_pcb *pcb,
|
||||
err_t (* sent)(void *arg, struct tcp_pcb *tpcb,
|
||||
u16_t len))
|
||||
|
||||
Specifies the callback function that should be called when data has
|
||||
successfully been received (i.e., acknowledged) by the remote
|
||||
host. The len argument passed to the callback function gives the
|
||||
amount bytes that was acknowledged by the last acknowledgment.
|
||||
|
||||
|
||||
--- Receiving TCP data
|
||||
|
||||
TCP data reception is callback based - an application specified
|
||||
callback function is called when new data arrives. When the
|
||||
application has taken the data, it has to call the tcp_recved()
|
||||
function to indicate that TCP can advertise increase the receive
|
||||
window.
|
||||
|
||||
- void tcp_recv(struct tcp_pcb *pcb,
|
||||
err_t (* recv)(void *arg, struct tcp_pcb *tpcb,
|
||||
struct pbuf *p, err_t err))
|
||||
|
||||
Sets the callback function that will be called when new data
|
||||
arrives. The callback function will be passed a NULL pbuf to
|
||||
indicate that the remote host has closed the connection. If
|
||||
there are no errors and the callback function is to return
|
||||
ERR_OK, then it must free the pbuf. Otherwise, it must not
|
||||
free the pbuf so that lwIP core code can store it.
|
||||
|
||||
- void tcp_recved(struct tcp_pcb *pcb, u16_t len)
|
||||
|
||||
Must be called when the application has received the data. The len
|
||||
argument indicates the length of the received data.
|
||||
|
||||
|
||||
--- Application polling
|
||||
|
||||
When a connection is idle (i.e., no data is either transmitted or
|
||||
received), lwIP will repeatedly poll the application by calling a
|
||||
specified callback function. This can be used either as a watchdog
|
||||
timer for killing connections that have stayed idle for too long, or
|
||||
as a method of waiting for memory to become available. For instance,
|
||||
if a call to tcp_write() has failed because memory wasn't available,
|
||||
the application may use the polling functionality to call tcp_write()
|
||||
again when the connection has been idle for a while.
|
||||
|
||||
- void tcp_poll(struct tcp_pcb *pcb,
|
||||
err_t (* poll)(void *arg, struct tcp_pcb *tpcb),
|
||||
u8_t interval)
|
||||
|
||||
Specifies the polling interval and the callback function that should
|
||||
be called to poll the application. The interval is specified in
|
||||
number of TCP coarse grained timer shots, which typically occurs
|
||||
twice a second. An interval of 10 means that the application would
|
||||
be polled every 5 seconds.
|
||||
|
||||
|
||||
--- Closing and aborting connections
|
||||
|
||||
- err_t tcp_close(struct tcp_pcb *pcb)
|
||||
|
||||
Closes the connection. The function may return ERR_MEM if no memory
|
||||
was available for closing the connection. If so, the application
|
||||
should wait and try again either by using the acknowledgment
|
||||
callback or the polling functionality. If the close succeeds, the
|
||||
function returns ERR_OK.
|
||||
|
||||
The pcb is deallocated by the TCP code after a call to tcp_close().
|
||||
|
||||
- void tcp_abort(struct tcp_pcb *pcb)
|
||||
|
||||
Aborts the connection by sending a RST (reset) segment to the remote
|
||||
host. The pcb is deallocated. This function never fails.
|
||||
|
||||
ATTENTION: When calling this from one of the TCP callbacks, make
|
||||
sure you always return ERR_ABRT (and never return ERR_ABRT otherwise
|
||||
or you will risk accessing deallocated memory or memory leaks!
|
||||
|
||||
|
||||
If a connection is aborted because of an error, the application is
|
||||
alerted of this event by the err callback. Errors that might abort a
|
||||
connection are when there is a shortage of memory. The callback
|
||||
function to be called is set using the tcp_err() function.
|
||||
|
||||
- void tcp_err(struct tcp_pcb *pcb, void (* err)(void *arg,
|
||||
err_t err))
|
||||
|
||||
The error callback function does not get the pcb passed to it as a
|
||||
parameter since the pcb may already have been deallocated.
|
||||
|
||||
|
||||
--- UDP interface
|
||||
|
||||
The UDP interface is similar to that of TCP, but due to the lower
|
||||
level of complexity of UDP, the interface is significantly simpler.
|
||||
|
||||
- struct udp_pcb *udp_new(void)
|
||||
|
||||
Creates a new UDP pcb which can be used for UDP communication. The
|
||||
pcb is not active until it has either been bound to a local address
|
||||
or connected to a remote address.
|
||||
|
||||
- void udp_remove(struct udp_pcb *pcb)
|
||||
|
||||
Removes and deallocates the pcb.
|
||||
|
||||
- err_t udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr,
|
||||
u16_t port)
|
||||
|
||||
Binds the pcb to a local address. The IP-address argument "ipaddr"
|
||||
can be IP_ADDR_ANY to indicate that it should listen to any local IP
|
||||
address. The function currently always return ERR_OK.
|
||||
|
||||
- err_t udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr,
|
||||
u16_t port)
|
||||
|
||||
Sets the remote end of the pcb. This function does not generate any
|
||||
network traffic, but only set the remote address of the pcb.
|
||||
|
||||
- err_t udp_disconnect(struct udp_pcb *pcb)
|
||||
|
||||
Remove the remote end of the pcb. This function does not generate
|
||||
any network traffic, but only removes the remote address of the pcb.
|
||||
|
||||
- err_t udp_send(struct udp_pcb *pcb, struct pbuf *p)
|
||||
|
||||
Sends the pbuf p. The pbuf is not deallocated.
|
||||
|
||||
- void udp_recv(struct udp_pcb *pcb,
|
||||
void (* recv)(void *arg, struct udp_pcb *upcb,
|
||||
struct pbuf *p,
|
||||
ip_addr_t *addr,
|
||||
u16_t port),
|
||||
void *recv_arg)
|
||||
|
||||
Specifies a callback function that should be called when a UDP
|
||||
datagram is received.
|
||||
|
||||
|
||||
--- System initalization
|
||||
|
||||
A truly complete and generic sequence for initializing the lwIP stack
|
||||
cannot be given because it depends on additional initializations for
|
||||
your runtime environment (e.g. timers).
|
||||
|
||||
We can give you some idea on how to proceed when using the raw API.
|
||||
We assume a configuration using a single Ethernet netif and the
|
||||
UDP and TCP transport layers, IPv4 and the DHCP client.
|
||||
|
||||
Call these functions in the order of appearance:
|
||||
|
||||
- lwip_init()
|
||||
|
||||
Initialize the lwIP stack and all of its subsystems.
|
||||
|
||||
- netif_add(struct netif *netif, const ip4_addr_t *ipaddr,
|
||||
const ip4_addr_t *netmask, const ip4_addr_t *gw,
|
||||
void *state, netif_init_fn init, netif_input_fn input)
|
||||
|
||||
Adds your network interface to the netif_list. Allocate a struct
|
||||
netif and pass a pointer to this structure as the first argument.
|
||||
Give pointers to cleared ip_addr structures when using DHCP,
|
||||
or fill them with sane numbers otherwise. The state pointer may be NULL.
|
||||
|
||||
The init function pointer must point to a initialization function for
|
||||
your Ethernet netif interface. The following code illustrates its use.
|
||||
|
||||
err_t netif_if_init(struct netif *netif)
|
||||
{
|
||||
u8_t i;
|
||||
|
||||
for (i = 0; i < ETHARP_HWADDR_LEN; i++) {
|
||||
netif->hwaddr[i] = some_eth_addr[i];
|
||||
}
|
||||
init_my_eth_device();
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
For Ethernet drivers, the input function pointer must point to the lwIP
|
||||
function ethernet_input() declared in "netif/etharp.h". Other drivers
|
||||
must use ip_input() declared in "lwip/ip.h".
|
||||
|
||||
- netif_set_default(struct netif *netif)
|
||||
|
||||
Registers the default network interface.
|
||||
|
||||
- netif_set_link_up(struct netif *netif)
|
||||
|
||||
This is the hardware link state; e.g. whether cable is plugged for wired
|
||||
Ethernet interface. This function must be called even if you don't know
|
||||
the current state. Having link up and link down events is optional but
|
||||
DHCP and IPv6 discover benefit well from those events.
|
||||
|
||||
- netif_set_up(struct netif *netif)
|
||||
|
||||
This is the administrative (= software) state of the netif, when the
|
||||
netif is fully configured this function must be called.
|
||||
|
||||
- dhcp_start(struct netif *netif)
|
||||
|
||||
Creates a new DHCP client for this interface on the first call.
|
||||
|
||||
You can peek in the netif->dhcp struct for the actual DHCP status.
|
||||
|
||||
- sys_check_timeouts()
|
||||
|
||||
When the system is running, you have to periodically call
|
||||
sys_check_timeouts() which will handle all timers for all protocols in
|
||||
the stack; add this to your main loop or equivalent.
|
||||
|
||||
|
||||
--- Optimalization hints
|
||||
|
||||
The first thing you want to optimize is the lwip_standard_checksum()
|
||||
routine from src/core/inet.c. You can override this standard
|
||||
function with the #define LWIP_CHKSUM <your_checksum_routine>.
|
||||
|
||||
There are C examples given in inet.c or you might want to
|
||||
craft an assembly function for this. RFC1071 is a good
|
||||
introduction to this subject.
|
||||
|
||||
Other significant improvements can be made by supplying
|
||||
assembly or inline replacements for htons() and htonl()
|
||||
if you're using a little-endian architecture.
|
||||
#define lwip_htons(x) <your_htons>
|
||||
#define lwip_htonl(x) <your_htonl>
|
||||
If you #define them to htons() and htonl(), you should
|
||||
#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS to prevent lwIP from
|
||||
defining hton*/ntoh* compatibility macros.
|
||||
|
||||
Check your network interface driver if it reads at
|
||||
a higher speed than the maximum wire-speed. If the
|
||||
hardware isn't serviced frequently and fast enough
|
||||
buffer overflows are likely to occur.
|
||||
|
||||
E.g. when using the cs8900 driver, call cs8900if_service(ethif)
|
||||
as frequently as possible. When using an RTOS let the cs8900 interrupt
|
||||
wake a high priority task that services your driver using a binary
|
||||
semaphore or event flag. Some drivers might allow additional tuning
|
||||
to match your application and network.
|
||||
|
||||
For a production release it is recommended to set LWIP_STATS to 0.
|
||||
Note that speed performance isn't influenced much by simply setting
|
||||
high values to the memory options.
|
||||
|
||||
For more optimization hints take a look at the lwIP wiki.
|
||||
|
||||
--- Zero-copy MACs
|
||||
|
||||
To achieve zero-copy on transmit, the data passed to the raw API must
|
||||
remain unchanged until sent. Because the send- (or write-)functions return
|
||||
when the packets have been enqueued for sending, data must be kept stable
|
||||
after that, too.
|
||||
|
||||
This implies that PBUF_RAM/PBUF_POOL pbufs passed to raw-API send functions
|
||||
must *not* be reused by the application unless their ref-count is 1.
|
||||
|
||||
For no-copy pbufs (PBUF_ROM/PBUF_REF), data must be kept unchanged, too,
|
||||
but the stack/driver will/must copy PBUF_REF'ed data when enqueueing, while
|
||||
PBUF_ROM-pbufs are just enqueued (as ROM-data is expected to never change).
|
||||
|
||||
Also, data passed to tcp_write without the copy-flag must not be changed!
|
||||
|
||||
Therefore, be careful which type of PBUF you use and if you copy TCP data
|
||||
or not!
|
||||
@@ -29,12 +29,12 @@ Or, obtain a specific (fixed) release as follows:
|
||||
The Savannah server uses SSH (Secure Shell) protocol 2 authentication and encryption.
|
||||
As such, Git commits to the server occur through a SSH tunnel for project members.
|
||||
To create a SSH2 key pair in UNIX-like environments, do this:
|
||||
ssh-keygen -t dsa
|
||||
ssh-keygen
|
||||
|
||||
Under Windows, a recommended SSH client is "PuTTY", freely available with good
|
||||
documentation and a graphic user interface. Use its key generator.
|
||||
|
||||
Now paste the id_dsa.pub contents into your Savannah account public key list. Wait
|
||||
Now paste the id_rsa.pub contents into your Savannah account public key list. Wait
|
||||
a while so that Savannah can update its configuration (This can take minutes).
|
||||
|
||||
Try to login using SSH:
|
||||
|
||||
303
doc/sys_arch.txt
303
doc/sys_arch.txt
@@ -1,303 +0,0 @@
|
||||
sys_arch interface for lwIP
|
||||
|
||||
Author: Adam Dunkels
|
||||
Simon Goldschmidt
|
||||
|
||||
The operating system emulation layer provides a common interface
|
||||
between the lwIP code and the underlying operating system kernel. The
|
||||
general idea is that porting lwIP to new architectures requires only
|
||||
small changes to a few header files and a new sys_arch
|
||||
implementation. It is also possible to do a sys_arch implementation
|
||||
that does not rely on any underlying operating system.
|
||||
|
||||
The sys_arch provides semaphores, mailboxes and mutexes to lwIP. For the full
|
||||
lwIP functionality, multiple threads support can be implemented in the
|
||||
sys_arch, but this is not required for the basic lwIP
|
||||
functionality. Timer scheduling is implemented in lwIP, but can be implemented
|
||||
by the sys_arch port (LWIP_TIMERS_CUSTOM==1).
|
||||
|
||||
In addition to the source file providing the functionality of sys_arch,
|
||||
the OS emulation layer must provide several header files defining
|
||||
macros used throughout lwip. The files required and the macros they
|
||||
must define are listed below the sys_arch description.
|
||||
|
||||
Semaphores can be either counting or binary - lwIP works with both
|
||||
kinds. Mailboxes should be implemented as a queue which allows multiple messages
|
||||
to be posted (implementing as a rendez-vous point where only one message can be
|
||||
posted at a time can have a highly negative impact on performance). A message
|
||||
in a mailbox is just a pointer, nothing more.
|
||||
|
||||
Semaphores are represented by the type "sys_sem_t" which is typedef'd
|
||||
in the sys_arch.h file. Mailboxes are equivalently represented by the
|
||||
type "sys_mbox_t". Mutexes are represented ny the type "sys_mutex_t".
|
||||
lwIP does not place any restrictions on how these types are represented
|
||||
internally.
|
||||
|
||||
Since lwIP 1.4.0, semaphore, mutexes and mailbox functions are prototyped in a way that
|
||||
allows both using pointers or actual OS structures to be used. This way, memory
|
||||
required for such types can be either allocated in place (globally or on the
|
||||
stack) or on the heap (allocated internally in the "*_new()" functions).
|
||||
|
||||
The following functions must be implemented by the sys_arch:
|
||||
|
||||
- void sys_init(void)
|
||||
|
||||
Is called to initialize the sys_arch layer.
|
||||
|
||||
- err_t sys_sem_new(sys_sem_t *sem, u8_t count)
|
||||
|
||||
Creates a new semaphore. The semaphore is allocated to the memory that 'sem'
|
||||
points to (which can be both a pointer or the actual OS structure).
|
||||
The "count" argument specifies the initial state of the semaphore (which is
|
||||
either 0 or 1).
|
||||
If the semaphore has been created, ERR_OK should be returned. Returning any
|
||||
other error will provide a hint what went wrong, but except for assertions,
|
||||
no real error handling is implemented.
|
||||
|
||||
- void sys_sem_free(sys_sem_t *sem)
|
||||
|
||||
Deallocates a semaphore.
|
||||
|
||||
- void sys_sem_signal(sys_sem_t *sem)
|
||||
|
||||
Signals a semaphore.
|
||||
|
||||
- u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
|
||||
|
||||
Blocks the thread while waiting for the semaphore to be
|
||||
signaled. If the "timeout" argument is non-zero, the thread should
|
||||
only be blocked for the specified time (measured in
|
||||
milliseconds). If the "timeout" argument is zero, the thread should be
|
||||
blocked until the semaphore is signalled.
|
||||
|
||||
If the timeout argument is non-zero, the return value is the number of
|
||||
milliseconds spent waiting for the semaphore to be signaled. If the
|
||||
semaphore wasn't signaled within the specified time, the return value is
|
||||
SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore
|
||||
(i.e., it was already signaled), the function may return zero.
|
||||
|
||||
Notice that lwIP implements a function with a similar name,
|
||||
sys_sem_wait(), that uses the sys_arch_sem_wait() function.
|
||||
|
||||
- int sys_sem_valid(sys_sem_t *sem)
|
||||
|
||||
Returns 1 if the semaphore is valid, 0 if it is not valid.
|
||||
When using pointers, a simple way is to check the pointer for != NULL.
|
||||
When directly using OS structures, implementing this may be more complex.
|
||||
This may also be a define, in which case the function is not prototyped.
|
||||
|
||||
- void sys_sem_set_invalid(sys_sem_t *sem)
|
||||
|
||||
Invalidate a semaphore so that sys_sem_valid() returns 0.
|
||||
ATTENTION: This does NOT mean that the semaphore shall be deallocated:
|
||||
sys_sem_free() is always called before calling this function!
|
||||
This may also be a define, in which case the function is not prototyped.
|
||||
|
||||
- void sys_mutex_new(sys_mutex_t *mutex)
|
||||
|
||||
Creates a new mutex. The mutex is allocated to the memory that 'mutex'
|
||||
points to (which can be both a pointer or the actual OS structure).
|
||||
If the mutex has been created, ERR_OK should be returned. Returning any
|
||||
other error will provide a hint what went wrong, but except for assertions,
|
||||
no real error handling is implemented.
|
||||
|
||||
- void sys_mutex_free(sys_mutex_t *mutex)
|
||||
|
||||
Deallocates a mutex.
|
||||
|
||||
- void sys_mutex_lock(sys_mutex_t *mutex)
|
||||
|
||||
Blocks the thread until the mutex can be grabbed.
|
||||
|
||||
- void sys_mutex_unlock(sys_mutex_t *mutex)
|
||||
|
||||
Releases the mutex previously locked through 'sys_mutex_lock()'.
|
||||
|
||||
- void sys_mutex_valid(sys_mutex_t *mutex)
|
||||
|
||||
Returns 1 if the mutes is valid, 0 if it is not valid.
|
||||
When using pointers, a simple way is to check the pointer for != NULL.
|
||||
When directly using OS structures, implementing this may be more complex.
|
||||
This may also be a define, in which case the function is not prototyped.
|
||||
|
||||
- void sys_mutex_set_invalid(sys_mutex_t *mutex)
|
||||
|
||||
Invalidate a mutex so that sys_mutex_valid() returns 0.
|
||||
ATTENTION: This does NOT mean that the mutex shall be deallocated:
|
||||
sys_mutex_free() is always called before calling this function!
|
||||
This may also be a define, in which case the function is not prototyped.
|
||||
|
||||
- err_t sys_mbox_new(sys_mbox_t *mbox, int size)
|
||||
|
||||
Creates an empty mailbox for maximum "size" elements. Elements stored
|
||||
in mailboxes are pointers. You have to define macros "_MBOX_SIZE"
|
||||
in your lwipopts.h, or ignore this parameter in your implementation
|
||||
and use a default size.
|
||||
If the mailbox has been created, ERR_OK should be returned. Returning any
|
||||
other error will provide a hint what went wrong, but except for assertions,
|
||||
no real error handling is implemented.
|
||||
|
||||
- void sys_mbox_free(sys_mbox_t *mbox)
|
||||
|
||||
Deallocates a mailbox. If there are messages still present in the
|
||||
mailbox when the mailbox is deallocated, it is an indication of a
|
||||
programming error in lwIP and the developer should be notified.
|
||||
|
||||
- void sys_mbox_post(sys_mbox_t *mbox, void *msg)
|
||||
|
||||
Posts the "msg" to the mailbox. This function have to block until
|
||||
the "msg" is really posted.
|
||||
|
||||
- err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
|
||||
|
||||
Try to post the "msg" to the mailbox. Returns ERR_MEM if this one
|
||||
is full, else, ERR_OK if the "msg" is posted.
|
||||
|
||||
- u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
|
||||
|
||||
Blocks the thread until a message arrives in the mailbox, but does
|
||||
not block the thread longer than "timeout" milliseconds (similar to
|
||||
the sys_arch_sem_wait() function). If "timeout" is 0, the thread should
|
||||
be blocked until a message arrives. The "msg" argument is a result
|
||||
parameter that is set by the function (i.e., by doing "*msg =
|
||||
ptr"). The "msg" parameter maybe NULL to indicate that the message
|
||||
should be dropped.
|
||||
|
||||
The return values are the same as for the sys_arch_sem_wait() function:
|
||||
Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a
|
||||
timeout.
|
||||
|
||||
Note that a function with a similar name, sys_mbox_fetch(), is
|
||||
implemented by lwIP.
|
||||
|
||||
- u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
|
||||
|
||||
This is similar to sys_arch_mbox_fetch, however if a message is not
|
||||
present in the mailbox, it immediately returns with the code
|
||||
SYS_MBOX_EMPTY. On success 0 is returned.
|
||||
|
||||
To allow for efficient implementations, this can be defined as a
|
||||
function-like macro in sys_arch.h instead of a normal function. For
|
||||
example, a naive implementation could be:
|
||||
#define sys_arch_mbox_tryfetch(mbox,msg) \
|
||||
sys_arch_mbox_fetch(mbox,msg,1)
|
||||
although this would introduce unnecessary delays.
|
||||
|
||||
- int sys_mbox_valid(sys_mbox_t *mbox)
|
||||
|
||||
Returns 1 if the mailbox is valid, 0 if it is not valid.
|
||||
When using pointers, a simple way is to check the pointer for != NULL.
|
||||
When directly using OS structures, implementing this may be more complex.
|
||||
This may also be a define, in which case the function is not prototyped.
|
||||
|
||||
- void sys_mbox_set_invalid(sys_mbox_t *mbox)
|
||||
|
||||
Invalidate a mailbox so that sys_mbox_valid() returns 0.
|
||||
ATTENTION: This does NOT mean that the mailbox shall be deallocated:
|
||||
sys_mbox_free() is always called before calling this function!
|
||||
This may also be a define, in which case the function is not prototyped.
|
||||
|
||||
If threads are supported by the underlying operating system and if
|
||||
such functionality is needed in lwIP, the following function will have
|
||||
to be implemented as well:
|
||||
|
||||
- sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio)
|
||||
|
||||
Starts a new thread named "name" with priority "prio" that will begin its
|
||||
execution in the function "thread()". The "arg" argument will be passed as an
|
||||
argument to the thread() function. The stack size to used for this thread is
|
||||
the "stacksize" parameter. The id of the new thread is returned. Both the id
|
||||
and the priority are system dependent.
|
||||
|
||||
When lwIP is used from more than one context (e.g. from multiple threads OR from
|
||||
main-loop and from interrupts), the SYS_LIGHTWEIGHT_PROT protection SHOULD be enabled!
|
||||
|
||||
- sys_prot_t sys_arch_protect(void)
|
||||
|
||||
This optional function does a "fast" critical region protection and returns
|
||||
the previous protection level. This function is only called during very short
|
||||
critical regions. An embedded system which supports ISR-based drivers might
|
||||
want to implement this function by disabling interrupts. Task-based systems
|
||||
might want to implement this by using a mutex or disabling tasking. This
|
||||
function should support recursive calls from the same task or interrupt. In
|
||||
other words, sys_arch_protect() could be called while already protected. In
|
||||
that case the return value indicates that it is already protected.
|
||||
|
||||
sys_arch_protect() is only required if your port is supporting an operating
|
||||
system.
|
||||
|
||||
- void sys_arch_unprotect(sys_prot_t pval)
|
||||
|
||||
This optional function does a "fast" set of critical region protection to the
|
||||
value specified by pval. See the documentation for sys_arch_protect() for
|
||||
more information. This function is only required if your port is supporting
|
||||
an operating system.
|
||||
|
||||
For some configurations, you also need:
|
||||
|
||||
- u32_t sys_now(void)
|
||||
|
||||
This optional function returns the current time in milliseconds (don't care
|
||||
for wraparound, this is only used for time diffs).
|
||||
Not implementing this function means you cannot use some modules (e.g. TCP
|
||||
timestamps, internal timeouts for NO_SYS==1).
|
||||
|
||||
|
||||
Note:
|
||||
|
||||
Be careful with using mem_malloc() in sys_arch. When malloc() refers to
|
||||
mem_malloc() you can run into a circular function call problem. In mem.c
|
||||
mem_init() tries to allcate a semaphore using mem_malloc, which of course
|
||||
can't be performed when sys_arch uses mem_malloc.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Additional files required for the "OS support" emulation layer:
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
cc.h - Architecture environment, some compiler specific, some
|
||||
environment specific (probably should move env stuff
|
||||
to sys_arch.h.)
|
||||
|
||||
Typedefs for the types used by lwip -
|
||||
u8_t, s8_t, u16_t, s16_t, u32_t, s32_t, mem_ptr_t
|
||||
|
||||
Compiler hints for packing lwip's structures -
|
||||
PACK_STRUCT_FIELD(x)
|
||||
PACK_STRUCT_STRUCT
|
||||
PACK_STRUCT_BEGIN
|
||||
PACK_STRUCT_END
|
||||
|
||||
Platform specific diagnostic output -
|
||||
LWIP_PLATFORM_DIAG(x) - non-fatal, print a message.
|
||||
LWIP_PLATFORM_ASSERT(x) - fatal, print message and abandon execution.
|
||||
Portability defines for printf formatters:
|
||||
U16_F, S16_F, X16_F, U32_F, S32_F, X32_F, SZT_F
|
||||
|
||||
"lightweight" synchronization mechanisms -
|
||||
SYS_ARCH_DECL_PROTECT(x) - declare a protection state variable.
|
||||
SYS_ARCH_PROTECT(x) - enter protection mode.
|
||||
SYS_ARCH_UNPROTECT(x) - leave protection mode.
|
||||
|
||||
If the compiler does not provide memset() this file must include a
|
||||
definition of it, or include a file which defines it.
|
||||
|
||||
This file must either include a system-local <errno.h> which defines
|
||||
the standard *nix error codes, or it should #define LWIP_PROVIDE_ERRNO
|
||||
to make lwip/arch.h define the codes which are used throughout.
|
||||
|
||||
|
||||
perf.h - Architecture specific performance measurement.
|
||||
Measurement calls made throughout lwip, these can be defined to nothing.
|
||||
PERF_START - start measuring something.
|
||||
PERF_STOP(x) - stop measuring something, and record the result.
|
||||
|
||||
sys_arch.h - Tied to sys_arch.c
|
||||
|
||||
Arch dependent types for the following objects:
|
||||
sys_sem_t, sys_mbox_t, sys_thread_t,
|
||||
And, optionally:
|
||||
sys_prot_t
|
||||
|
||||
Defines to set vars of sys_mbox_t and sys_sem_t to NULL.
|
||||
SYS_MBOX_NULL NULL
|
||||
SYS_SEM_NULL NULL
|
||||
5
package.json
Normal file
5
package.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "library-lwip",
|
||||
"version": "2.1.3-amb1",
|
||||
"description": "lwIP - A Lightweight TCPIP stack"
|
||||
}
|
||||
36
port/realtek/arch/bpstruct.h
Normal file
36
port/realtek/arch/bpstruct.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2003 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. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(__IAR_SYSTEMS_ICC__)|| defined (__GNUC__)
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
|
||||
95
port/realtek/arch/cc.h
Normal file
95
port/realtek/arch/cc.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2003 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. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
#ifndef __CC_H__
|
||||
#define __CC_H__
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
typedef int sys_prot_t;
|
||||
|
||||
#define U16_F "d"
|
||||
#define S16_F "d"
|
||||
#define X16_F "x"
|
||||
#define U32_F "d"
|
||||
#define S32_F "d"
|
||||
#define X32_F "x"
|
||||
#define SZT_F "uz"
|
||||
|
||||
/* define compiler specific symbols */
|
||||
#if defined (__ICCARM__)
|
||||
#if !defined (__IARSTDLIB__)
|
||||
#define _STRING
|
||||
#ifndef memcmp
|
||||
#define memcmp(dst, src, sz) _memcmp(dst, src, sz)
|
||||
#endif
|
||||
#ifndef memset
|
||||
#define memset(dst, val, sz) _memset(dst, val, sz)
|
||||
#endif
|
||||
#ifndef memcpy
|
||||
#define memcpy(dst, src, sz) _memcpy(dst, src, sz)
|
||||
#endif
|
||||
#endif // __IARSTDLIB__
|
||||
|
||||
#define PACK_STRUCT_BEGIN
|
||||
#define PACK_STRUCT_STRUCT
|
||||
#define PACK_STRUCT_END
|
||||
#define PACK_STRUCT_FIELD(x) x
|
||||
#define PACK_STRUCT_USE_INCLUDES
|
||||
|
||||
#elif defined (__CC_ARM)
|
||||
|
||||
#define PACK_STRUCT_BEGIN __packed
|
||||
#define PACK_STRUCT_STRUCT
|
||||
#define PACK_STRUCT_END
|
||||
#define PACK_STRUCT_FIELD(x) x
|
||||
|
||||
#elif defined (__GNUC__)
|
||||
|
||||
#define PACK_STRUCT_BEGIN
|
||||
#define PACK_STRUCT_STRUCT __attribute__ ((__packed__))
|
||||
#define PACK_STRUCT_END
|
||||
#define PACK_STRUCT_FIELD(x) x
|
||||
#define PACK_STRUCT_USE_INCLUDES
|
||||
|
||||
#elif defined (__TASKING__)
|
||||
|
||||
#define PACK_STRUCT_BEGIN
|
||||
#define PACK_STRUCT_STRUCT
|
||||
#define PACK_STRUCT_END
|
||||
#define PACK_STRUCT_FIELD(x) x
|
||||
|
||||
#endif
|
||||
|
||||
#define LWIP_PLATFORM_ASSERT(x) //do { if(!(x)) while(1); } while(0)
|
||||
#define LWIP_PLATFORM_DIAG printf
|
||||
|
||||
#endif /* __CC_H__ */
|
||||
37
port/realtek/arch/cpu.h
Normal file
37
port/realtek/arch/cpu.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2003 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. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
#ifndef __CPU_H__
|
||||
#define __CPU_H__
|
||||
|
||||
#define BYTE_ORDER LITTLE_ENDIAN
|
||||
|
||||
#endif /* __CPU_H__ */
|
||||
38
port/realtek/arch/epstruct.h
Normal file
38
port/realtek/arch/epstruct.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2003 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. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(__IAR_SYSTEMS_ICC__)
|
||||
#pragma pack()
|
||||
#elif defined (__GNUC__)
|
||||
#pragma pack()
|
||||
#endif
|
||||
|
||||
44
port/realtek/arch/init.h
Normal file
44
port/realtek/arch/init.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2003 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. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
#ifndef __ARCH_INIT_H__
|
||||
#define __ARCH_INIT_H__
|
||||
|
||||
#define TCPIP_INIT_DONE(arg) tcpip_init_done(arg)
|
||||
|
||||
void tcpip_init_done(void *);
|
||||
int wait_for_tcpip_init(void);
|
||||
|
||||
#endif /* __ARCH_INIT_H__ */
|
||||
|
||||
|
||||
|
||||
|
||||
38
port/realtek/arch/lib.h
Normal file
38
port/realtek/arch/lib.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2003 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. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
#ifndef __LIB_H__
|
||||
#define __LIB_H__
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#endif /* __LIB_H__ */
|
||||
38
port/realtek/arch/perf.h
Normal file
38
port/realtek/arch/perf.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2003 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. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
#ifndef __PERF_H__
|
||||
#define __PERF_H__
|
||||
|
||||
#define PERF_START /* null definition */
|
||||
#define PERF_STOP(x) /* null definition */
|
||||
|
||||
#endif /* __PERF_H__ */
|
||||
67
port/realtek/arch/sys_arch.h
Normal file
67
port/realtek/arch/sys_arch.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2003 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. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
#ifndef __SYS_RTXC_H__
|
||||
#define __SYS_RTXC_H__
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
#include "semphr.h"
|
||||
|
||||
#define SYS_MBOX_NULL (xQueueHandle)0
|
||||
#define SYS_SEM_NULL (xSemaphoreHandle)0
|
||||
#define SYS_DEFAULT_THREAD_STACK_DEPTH configMINIMAL_STACK_SIZE
|
||||
|
||||
typedef xSemaphoreHandle sys_sem_t;
|
||||
typedef xSemaphoreHandle sys_mutex_t;
|
||||
typedef xQueueHandle sys_mbox_t;
|
||||
typedef xTaskHandle sys_thread_t;
|
||||
|
||||
typedef struct _sys_arch_state_t
|
||||
{
|
||||
// Task creation data.
|
||||
char cTaskName[configMAX_TASK_NAME_LEN];
|
||||
unsigned short nStackDepth;
|
||||
unsigned short nTaskCount;
|
||||
} sys_arch_state_t;
|
||||
|
||||
|
||||
|
||||
//extern sys_arch_state_t s_sys_arch_state;
|
||||
|
||||
//void sys_set_default_state();
|
||||
//void sys_set_state(signed char *pTaskName, unsigned short nStackSize);
|
||||
|
||||
/* Message queue constants. */
|
||||
#define archMESG_QUEUE_LENGTH ( 6 )
|
||||
#endif /* __SYS_RTXC_H__ */
|
||||
|
||||
377
port/realtek/freertos/ethernetif.c
Normal file
377
port/realtek/freertos/ethernetif.c
Normal file
@@ -0,0 +1,377 @@
|
||||
/**
|
||||
* @file
|
||||
* Ethernet Interface Skeleton
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2004 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. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is a skeleton for developing Ethernet network interface
|
||||
* drivers for lwIP. Add code to the low_level functions and do a
|
||||
* search-and-replace for the word "ethernetif" to replace it with
|
||||
* something that better describes your network interface.
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/tcpip.h"
|
||||
#include "lwip/icmp.h"
|
||||
#include "lwip/lwip_timers.h"
|
||||
#include "netif/etharp.h"
|
||||
#include "err.h"
|
||||
#include "ethernetif.h"
|
||||
#include "queue.h"
|
||||
#include "lwip_netconf.h"
|
||||
|
||||
//#include "lwip/ethip6.h" //Add for ipv6
|
||||
|
||||
#include <platform/platform_stdlib.h>
|
||||
#include "platform_opts.h"
|
||||
|
||||
#if CONFIG_WLAN
|
||||
#include <lwip_intf.h>
|
||||
#endif
|
||||
|
||||
#if CONFIG_INIC_HOST
|
||||
#include "freertos/inic_intf.h"
|
||||
#endif
|
||||
|
||||
#define netifMTU (1500)
|
||||
#define netifINTERFACE_TASK_STACK_SIZE ( 350 )
|
||||
#define netifINTERFACE_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
|
||||
#define netifGUARD_BLOCK_TIME ( 250 )
|
||||
/* The time to block waiting for input. */
|
||||
#define emacBLOCK_TIME_WAITING_FOR_INPUT ( ( portTickType ) 100 )
|
||||
|
||||
|
||||
#ifdef CONFIG_CONCURRENT_MODE
|
||||
#define IF2NAME0 'r'
|
||||
#define IF2NAME1 '2'
|
||||
#endif
|
||||
|
||||
static void arp_timer(void *arg);
|
||||
|
||||
|
||||
/**
|
||||
* In this function, the hardware should be initialized.
|
||||
* Called from ethernetif_init().
|
||||
*
|
||||
* @param netif the already initialized lwip network interface structure
|
||||
* for this ethernetif
|
||||
*/
|
||||
|
||||
static void low_level_init(struct netif *netif)
|
||||
{
|
||||
|
||||
/* set netif MAC hardware address length */
|
||||
netif->hwaddr_len = ETHARP_HWADDR_LEN;
|
||||
|
||||
/* set netif maximum transfer unit */
|
||||
netif->mtu = 1500;
|
||||
|
||||
/* Accept broadcast address and ARP traffic */
|
||||
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
|
||||
|
||||
#if LWIP_IGMP
|
||||
/* make LwIP_Init do igmp_start to add group 224.0.0.1 */
|
||||
netif->flags |= NETIF_FLAG_IGMP;
|
||||
#endif
|
||||
|
||||
/* Wlan interface is initialized later */
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function should do the actual transmission of the packet. The packet is
|
||||
* contained in the pbuf that is passed to the function. This pbuf
|
||||
* might be chained.
|
||||
*
|
||||
* @param netif the lwip network interface structure for this ethernetif
|
||||
* @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
|
||||
* @return ERR_OK if the packet could be sent
|
||||
* an err_t value if the packet couldn't be sent
|
||||
*
|
||||
* @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
|
||||
* strange results. You might consider waiting for space in the DMA queue
|
||||
* to become availale since the stack doesn't retry to send a packet
|
||||
* dropped because of memory failure (except for the TCP timers).
|
||||
*/
|
||||
|
||||
static err_t low_level_output(struct netif *netif, struct pbuf *p)
|
||||
{
|
||||
|
||||
|
||||
/* Refer to eCos lwip eth_drv_send() */
|
||||
struct eth_drv_sg sg_list[MAX_ETH_DRV_SG];
|
||||
int sg_len = 0;
|
||||
struct pbuf *q;
|
||||
#if CONFIG_WLAN
|
||||
if(!rltk_wlan_running(netif_get_idx(netif)))
|
||||
return ERR_IF;
|
||||
#endif
|
||||
for (q = p; q != NULL && sg_len < MAX_ETH_DRV_SG; q = q->next) {
|
||||
sg_list[sg_len].buf = (unsigned int) q->payload;
|
||||
sg_list[sg_len++].len = q->len;
|
||||
}
|
||||
|
||||
if (sg_len) {
|
||||
#if CONFIG_WLAN
|
||||
if (rltk_wlan_send(netif_get_idx(netif), sg_list, sg_len, p->tot_len) == 0)
|
||||
#elif CONFIG_INIC_HOST
|
||||
if(rltk_inic_send( sg_list, sg_len, p->tot_len) == 0)
|
||||
#else
|
||||
if(1)
|
||||
#endif
|
||||
return ERR_OK;
|
||||
else
|
||||
return ERR_BUF; // return a non-fatal error
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/*for ethernet mii interface*/
|
||||
static err_t low_level_output_mii(struct netif *netif, struct pbuf *p)
|
||||
{
|
||||
struct eth_drv_sg sg_list[MAX_ETH_DRV_SG];
|
||||
int sg_len = 0;
|
||||
struct pbuf *q;
|
||||
for (q = p; q != NULL && sg_len < MAX_ETH_DRV_SG; q = q->next) {
|
||||
sg_list[sg_len].buf = (unsigned int) q->payload;
|
||||
sg_list[sg_len++].len = q->len;
|
||||
}
|
||||
if (sg_len) {
|
||||
if(rltk_mii_send(sg_list, sg_len, p->tot_len) == 0)
|
||||
return ERR_OK;
|
||||
else
|
||||
return ERR_BUF; // return a non-fatal error
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Should allocate a pbuf and transfer the bytes of the incoming
|
||||
* packet from the interface into the pbuf.
|
||||
*
|
||||
* @param netif the lwip network interface structure for this ethernetif
|
||||
* @return a pbuf filled with the received packet (including MAC header)
|
||||
* NULL on memory error
|
||||
*/
|
||||
//static struct pbuf * low_level_input(struct netif *netif){}
|
||||
|
||||
|
||||
/**
|
||||
* This function is the ethernetif_input task, it is processed when a packet
|
||||
* is ready to be read from the interface. It uses the function low_level_input()
|
||||
* that should handle the actual reception of bytes from the network
|
||||
* interface. Then the type of the received packet is determined and
|
||||
* the appropriate input function is called.
|
||||
*
|
||||
* @param netif the lwip network interface structure for this ethernetif
|
||||
*/
|
||||
//void ethernetif_input( void * pvParameters )
|
||||
|
||||
|
||||
/* Refer to eCos eth_drv_recv to do similarly in ethernetif_input */
|
||||
void ethernetif_recv(struct netif *netif, int total_len)
|
||||
{
|
||||
struct eth_drv_sg sg_list[MAX_ETH_DRV_SG];
|
||||
struct pbuf *p, *q;
|
||||
int sg_len = 0;
|
||||
#if CONFIG_WLAN
|
||||
if(!rltk_wlan_running(netif_get_idx(netif)))
|
||||
return;
|
||||
#endif
|
||||
if ((total_len > MAX_ETH_MSG) || (total_len < 0))
|
||||
total_len = MAX_ETH_MSG;
|
||||
|
||||
// Allocate buffer to store received packet
|
||||
p = pbuf_alloc(PBUF_RAW, total_len, PBUF_POOL);
|
||||
if (p == NULL) {
|
||||
printf("\n\rCannot allocate pbuf to receive packet");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create scatter list
|
||||
for (q = p; q != NULL && sg_len < MAX_ETH_DRV_SG; q = q->next) {
|
||||
sg_list[sg_len].buf = (unsigned int) q->payload;
|
||||
sg_list[sg_len++].len = q->len;
|
||||
}
|
||||
|
||||
// Copy received packet to scatter list from wrapper rx skb
|
||||
//printf("\n\rwlan:%c: Recv sg_len: %d, tot_len:%d", netif->name[1],sg_len, total_len);
|
||||
#if CONFIG_WLAN
|
||||
rltk_wlan_recv(netif_get_idx(netif), sg_list, sg_len);
|
||||
#elif CONFIG_INIC_HOST
|
||||
rltk_inic_recv(sg_list, sg_len);
|
||||
#endif
|
||||
// Pass received packet to the interface
|
||||
if (ERR_OK != netif->input(p, netif))
|
||||
pbuf_free(p);
|
||||
|
||||
}
|
||||
|
||||
void ethernetif_mii_recv(struct netif *netif, int total_len)
|
||||
{
|
||||
struct eth_drv_sg sg_list[MAX_ETH_DRV_SG];
|
||||
struct pbuf *p, *q;
|
||||
int sg_len = 0;
|
||||
|
||||
if ((total_len > MAX_ETH_MSG) || (total_len < 0))
|
||||
total_len = MAX_ETH_MSG;
|
||||
|
||||
// Allocate buffer to store received packet
|
||||
p = pbuf_alloc(PBUF_RAW, total_len, PBUF_POOL);
|
||||
if (p == NULL) {
|
||||
printf("\n\rCannot allocate pbuf to receive packet");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create scatter list
|
||||
for (q = p; q != NULL && sg_len < MAX_ETH_DRV_SG; q = q->next) {
|
||||
sg_list[sg_len].buf = (unsigned int) q->payload;
|
||||
sg_list[sg_len++].len = q->len;
|
||||
}
|
||||
rltk_mii_recv(sg_list, sg_len);
|
||||
|
||||
// Pass received packet to the interface
|
||||
if (ERR_OK != netif->input(p, netif))
|
||||
pbuf_free(p);
|
||||
|
||||
}
|
||||
/**
|
||||
* Should be called at the beginning of the program to set up the
|
||||
* network interface. It calls the function low_level_init() to do the
|
||||
* actual setup of the hardware.
|
||||
*
|
||||
* This function should be passed as a parameter to netif_add().
|
||||
*
|
||||
* @param netif the lwip network interface structure for this ethernetif
|
||||
* @return ERR_OK if the loopif is initialized
|
||||
* ERR_MEM if private data couldn't be allocated
|
||||
* any other err_t on error
|
||||
*/
|
||||
err_t ethernetif_init(struct netif *netif)
|
||||
{
|
||||
LWIP_ASSERT("netif != NULL", (netif != NULL));
|
||||
|
||||
#if LWIP_NETIF_HOSTNAME
|
||||
/* Initialize interface hostname */
|
||||
if(netif->name[1] == '0')
|
||||
netif->hostname = "lwip0";
|
||||
else if(netif->name[1] == '1')
|
||||
netif->hostname = "lwip1";
|
||||
#endif /* LWIP_NETIF_HOSTNAME */
|
||||
|
||||
netif->output = etharp_output;
|
||||
//#if LWIP_IPV6
|
||||
// netif->output_ip6 = ethip6_output;
|
||||
//#endif
|
||||
netif->linkoutput = low_level_output;
|
||||
|
||||
/* initialize the hardware */
|
||||
low_level_init(netif);
|
||||
|
||||
etharp_init();
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
err_t ethernetif_mii_init(struct netif *netif)
|
||||
{
|
||||
LWIP_ASSERT("netif != NULL", (netif != NULL));
|
||||
|
||||
#if LWIP_NETIF_HOSTNAME
|
||||
netif->hostname = "lwip2";
|
||||
#endif /* LWIP_NETIF_HOSTNAME */
|
||||
|
||||
netif->output = etharp_output;
|
||||
//#if LWIP_IPV6
|
||||
// netif->output_ip6 = ethip6_output;
|
||||
//#endif
|
||||
netif->linkoutput = low_level_output_mii;
|
||||
|
||||
/* initialize the hardware */
|
||||
low_level_init(netif);
|
||||
|
||||
etharp_init();
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static void arp_timer(void *arg)
|
||||
{
|
||||
etharp_tmr();
|
||||
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* For FreeRTOS tickless
|
||||
*/
|
||||
int lwip_tickless_used = 0;
|
||||
|
||||
int arp_timeout_exist(void)
|
||||
{
|
||||
struct sys_timeouts *timeouts;
|
||||
struct sys_timeo *t;
|
||||
|
||||
timeouts = sys_arch_timeouts();
|
||||
|
||||
for(t = timeouts->next; t != NULL;t = t->next)
|
||||
if(t->h == arp_timer)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Called by rltk_wlan_PRE_SLEEP_PROCESSING()
|
||||
void lwip_PRE_SLEEP_PROCESSING(void)
|
||||
{
|
||||
if(arp_timeout_exist()) {
|
||||
tcpip_untimeout(arp_timer, NULL);
|
||||
}
|
||||
lwip_tickless_used = 1;
|
||||
}
|
||||
|
||||
//Called in ips_leave() path, support tickless when wifi power wakeup due to ioctl or deinit
|
||||
void lwip_POST_SLEEP_PROCESSING(void)
|
||||
{
|
||||
if(lwip_tickless_used) {
|
||||
tcpip_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
25
port/realtek/freertos/ethernetif.h
Normal file
25
port/realtek/freertos/ethernetif.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef __ETHERNETIF_H__
|
||||
#define __ETHERNETIF_H__
|
||||
|
||||
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/netif.h"
|
||||
|
||||
//----- ------------------------------------------------------------------
|
||||
// Ethernet Buffer
|
||||
//----- ------------------------------------------------------------------
|
||||
struct eth_drv_sg {
|
||||
unsigned int buf;
|
||||
unsigned int len;
|
||||
};
|
||||
|
||||
#define MAX_ETH_DRV_SG 32
|
||||
#define MAX_ETH_MSG 1540
|
||||
|
||||
void ethernetif_recv(struct netif *netif, int total_len);
|
||||
err_t ethernetif_init(struct netif *netif);
|
||||
err_t ethernetif_mii_init(struct netif *netif);
|
||||
void lwip_PRE_SLEEP_PROCESSING(void);
|
||||
void lwip_POST_SLEEP_PROCESSING(void);
|
||||
|
||||
#endif
|
||||
633
port/realtek/freertos/sys_arch.c
Normal file
633
port/realtek/freertos/sys_arch.c
Normal file
@@ -0,0 +1,633 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2003 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. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
/* lwIP includes. */
|
||||
#include "lwip/debug.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
#include "lwip/lwip_timers.h"
|
||||
#include "autoconf.h"
|
||||
#include "tcm_heap.h"
|
||||
|
||||
xTaskHandle xTaskGetCurrentTaskHandle( void ) PRIVILEGED_FUNCTION;
|
||||
extern void * vTaskGetCurrentTCB( void );
|
||||
struct timeoutlist
|
||||
{
|
||||
struct sys_timeouts timeouts;
|
||||
xTaskHandle pid;
|
||||
};
|
||||
|
||||
/* This is the number of threads that can be started with sys_thread_new() */
|
||||
#define SYS_THREAD_MAX 6
|
||||
|
||||
static struct timeoutlist s_timeoutlist[SYS_THREAD_MAX];
|
||||
static u16_t s_nextthread = 0;
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
// Creates an empty mailbox.
|
||||
err_t sys_mbox_new(sys_mbox_t *mbox, int size)
|
||||
{
|
||||
(void ) size;
|
||||
|
||||
*mbox = xQueueCreate( size, sizeof( void * ) );
|
||||
|
||||
#if SYS_STATS
|
||||
++lwip_stats.sys.mbox.used;
|
||||
if (lwip_stats.sys.mbox.max < lwip_stats.sys.mbox.used) {
|
||||
lwip_stats.sys.mbox.max = lwip_stats.sys.mbox.used;
|
||||
}
|
||||
#endif /* SYS_STATS */
|
||||
if (*mbox == NULL)
|
||||
return ERR_MEM;
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/*
|
||||
Deallocates a mailbox. If there are messages still present in the
|
||||
mailbox when the mailbox is deallocated, it is an indication of a
|
||||
programming error in lwIP and the developer should be notified.
|
||||
*/
|
||||
void sys_mbox_free(sys_mbox_t *mbox)
|
||||
{
|
||||
if( uxQueueMessagesWaiting( *mbox ) )
|
||||
{
|
||||
/* Line for breakpoint. Should never break here! */
|
||||
portNOP();
|
||||
#if SYS_STATS
|
||||
lwip_stats.sys.mbox.err++;
|
||||
#endif /* SYS_STATS */
|
||||
|
||||
// TODO notify the user of failure.
|
||||
}
|
||||
|
||||
vQueueDelete( *mbox );
|
||||
|
||||
#if SYS_STATS
|
||||
--lwip_stats.sys.mbox.used;
|
||||
#endif /* SYS_STATS */
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
// Posts the "msg" to the mailbox.
|
||||
void sys_mbox_post(sys_mbox_t *mbox, void *data)
|
||||
{
|
||||
while ( xQueueSendToBack(*mbox, &data, portMAX_DELAY ) != pdTRUE ){}
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
// Try to post the "msg" to the mailbox.
|
||||
err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
|
||||
{
|
||||
err_t result;
|
||||
|
||||
if ( xQueueSend( *mbox, &msg, 0 ) == pdPASS )
|
||||
{
|
||||
result = ERR_OK;
|
||||
}
|
||||
else {
|
||||
// could not post, queue must be full
|
||||
result = ERR_MEM;
|
||||
|
||||
#if SYS_STATS
|
||||
lwip_stats.sys.mbox.err++;
|
||||
#endif /* SYS_STATS */
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/*
|
||||
Blocks the thread until a message arrives in the mailbox, but does
|
||||
not block the thread longer than "timeout" milliseconds (similar to
|
||||
the sys_arch_sem_wait() function). The "msg" argument is a result
|
||||
parameter that is set by the function (i.e., by doing "*msg =
|
||||
ptr"). The "msg" parameter maybe NULL to indicate that the message
|
||||
should be dropped.
|
||||
|
||||
The return values are the same as for the sys_arch_sem_wait() function:
|
||||
Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a
|
||||
timeout.
|
||||
|
||||
Note that a function with a similar name, sys_mbox_fetch(), is
|
||||
implemented by lwIP.
|
||||
*/
|
||||
u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
|
||||
{
|
||||
void *dummyptr;
|
||||
portTickType StartTime, EndTime, Elapsed;
|
||||
|
||||
StartTime = xTaskGetTickCount();
|
||||
|
||||
if ( msg == NULL )
|
||||
{
|
||||
msg = &dummyptr;
|
||||
}
|
||||
|
||||
if ( timeout != 0 )
|
||||
{
|
||||
if ( pdTRUE == xQueueReceive( *mbox, &(*msg), timeout / portTICK_RATE_MS ) )
|
||||
{
|
||||
EndTime = xTaskGetTickCount();
|
||||
Elapsed = (EndTime - StartTime) * portTICK_RATE_MS;
|
||||
|
||||
return ( Elapsed );
|
||||
}
|
||||
else // timed out blocking for message
|
||||
{
|
||||
*msg = NULL;
|
||||
|
||||
return SYS_ARCH_TIMEOUT;
|
||||
}
|
||||
}
|
||||
else // block forever for a message.
|
||||
{
|
||||
while( pdTRUE != xQueueReceive( *mbox, &(*msg), portMAX_DELAY ) ){} // time is arbitrary
|
||||
EndTime = xTaskGetTickCount();
|
||||
Elapsed = (EndTime - StartTime) * portTICK_RATE_MS;
|
||||
|
||||
return ( Elapsed ); // return time blocked TODO test
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/*
|
||||
Similar to sys_arch_mbox_fetch, but if message is not ready immediately, we'll
|
||||
return with SYS_MBOX_EMPTY. On success, 0 is returned.
|
||||
*/
|
||||
u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
|
||||
{
|
||||
void *dummyptr;
|
||||
|
||||
if ( msg == NULL )
|
||||
{
|
||||
msg = &dummyptr;
|
||||
}
|
||||
|
||||
if ( pdTRUE == xQueueReceive( *mbox, &(*msg), 0 ) )
|
||||
{
|
||||
return ERR_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return SYS_MBOX_EMPTY;
|
||||
}
|
||||
}
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
int sys_mbox_valid(sys_mbox_t *mbox)
|
||||
{
|
||||
if (*mbox == SYS_MBOX_NULL)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void sys_mbox_set_invalid(sys_mbox_t *mbox)
|
||||
{
|
||||
*mbox = SYS_MBOX_NULL;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
// Creates a new semaphore. The "count" argument specifies
|
||||
// the initial state of the semaphore.
|
||||
err_t sys_sem_new(sys_sem_t *sem, u8_t count)
|
||||
{
|
||||
vSemaphoreCreateBinary(*sem );
|
||||
if(*sem == NULL)
|
||||
{
|
||||
|
||||
#if SYS_STATS
|
||||
++lwip_stats.sys.sem.err;
|
||||
#endif /* SYS_STATS */
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
if(count == 0) // Means it can't be taken
|
||||
{
|
||||
xSemaphoreTake(*sem,1);
|
||||
}
|
||||
|
||||
#if SYS_STATS
|
||||
++lwip_stats.sys.sem.used;
|
||||
if (lwip_stats.sys.sem.max < lwip_stats.sys.sem.used) {
|
||||
lwip_stats.sys.sem.max = lwip_stats.sys.sem.used;
|
||||
}
|
||||
#endif /* SYS_STATS */
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/*
|
||||
Blocks the thread while waiting for the semaphore to be
|
||||
signaled. If the "timeout" argument is non-zero, the thread should
|
||||
only be blocked for the specified time (measured in
|
||||
milliseconds).
|
||||
|
||||
If the timeout argument is non-zero, the return value is the number of
|
||||
milliseconds spent waiting for the semaphore to be signaled. If the
|
||||
semaphore wasn't signaled within the specified time, the return value is
|
||||
SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore
|
||||
(i.e., it was already signaled), the function may return zero.
|
||||
|
||||
Notice that lwIP implements a function with a similar name,
|
||||
sys_sem_wait(), that uses the sys_arch_sem_wait() function.
|
||||
*/
|
||||
u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
|
||||
{
|
||||
portTickType StartTime, EndTime, Elapsed;
|
||||
|
||||
StartTime = xTaskGetTickCount();
|
||||
|
||||
if( timeout != 0)
|
||||
{
|
||||
if( xSemaphoreTake( *sem, timeout / portTICK_RATE_MS ) == pdTRUE )
|
||||
{
|
||||
EndTime = xTaskGetTickCount();
|
||||
Elapsed = (EndTime - StartTime) * portTICK_RATE_MS;
|
||||
|
||||
return (Elapsed); // return time blocked TODO test
|
||||
}
|
||||
else
|
||||
{
|
||||
return SYS_ARCH_TIMEOUT;
|
||||
}
|
||||
}
|
||||
else // must block without a timeout
|
||||
{
|
||||
while( xSemaphoreTake(*sem, portMAX_DELAY) != pdTRUE){}
|
||||
EndTime = xTaskGetTickCount();
|
||||
Elapsed = (EndTime - StartTime) * portTICK_RATE_MS;
|
||||
|
||||
return ( Elapsed ); // return time blocked
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
// Signals a semaphore
|
||||
void sys_sem_signal(sys_sem_t *sem)
|
||||
{
|
||||
xSemaphoreGive(*sem);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
// Deallocates a semaphore
|
||||
void sys_sem_free(sys_sem_t *sem)
|
||||
{
|
||||
#if SYS_STATS
|
||||
--lwip_stats.sys.sem.used;
|
||||
#endif /* SYS_STATS */
|
||||
|
||||
vQueueDelete(*sem);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
int sys_sem_valid(sys_sem_t *sem)
|
||||
{
|
||||
if (*sem == SYS_SEM_NULL)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void sys_sem_set_invalid(sys_sem_t *sem)
|
||||
{
|
||||
*sem = SYS_SEM_NULL;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
// Initialize sys arch
|
||||
void sys_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
// Initialize the the per-thread sys_timeouts structures
|
||||
// make sure there are no valid pids in the list
|
||||
for(i = 0; i < SYS_THREAD_MAX; i++)
|
||||
{
|
||||
s_timeoutlist[i].pid = 0;
|
||||
s_timeoutlist[i].timeouts.next = NULL;
|
||||
}
|
||||
|
||||
// keep track of how many threads have been created
|
||||
s_nextthread = 0;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/*
|
||||
Returns a pointer to the per-thread sys_timeouts structure. In lwIP,
|
||||
each thread has a list of timeouts which is represented as a linked
|
||||
list of sys_timeout structures. The sys_timeouts structure holds a
|
||||
pointer to a linked list of timeouts. This function is called by
|
||||
the lwIP timeout scheduler and must not return a NULL value.
|
||||
|
||||
In a single threaded sys_arch implementation, this function will
|
||||
simply return a pointer to a global sys_timeouts variable stored in
|
||||
the sys_arch module.
|
||||
*/
|
||||
struct sys_timeouts *sys_arch_timeouts(void)
|
||||
{
|
||||
int i;
|
||||
xTaskHandle pid;
|
||||
struct timeoutlist *tl;
|
||||
|
||||
pid = xTaskGetCurrentTaskHandle();
|
||||
|
||||
for(i = 0; i < s_nextthread; i++)
|
||||
{
|
||||
tl = &(s_timeoutlist[i]);
|
||||
if(tl->pid == pid)
|
||||
{
|
||||
return &(tl->timeouts);
|
||||
}
|
||||
}
|
||||
// Error
|
||||
return NULL;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Mutexes*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
#if LWIP_COMPAT_MUTEX == 0
|
||||
/* Create a new mutex*/
|
||||
err_t sys_mutex_new(sys_mutex_t *mutex) {
|
||||
|
||||
*mutex = xSemaphoreCreateMutex();
|
||||
if(*mutex == NULL)
|
||||
{
|
||||
#if SYS_STATS
|
||||
++lwip_stats.sys.mutex.err;
|
||||
#endif /* SYS_STATS */
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
#if SYS_STATS
|
||||
++lwip_stats.sys.mutex.used;
|
||||
if (lwip_stats.sys.mutex.max < lwip_stats.sys.mutex.used) {
|
||||
lwip_stats.sys.mutex.max = lwip_stats.sys.mutex.used;
|
||||
}
|
||||
#endif /* SYS_STATS */
|
||||
return ERR_OK;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Deallocate a mutex*/
|
||||
void sys_mutex_free(sys_mutex_t *mutex)
|
||||
{
|
||||
#if SYS_STATS
|
||||
--lwip_stats.sys.mutex.used;
|
||||
#endif /* SYS_STATS */
|
||||
|
||||
vQueueDelete(*mutex);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Lock a mutex*/
|
||||
void sys_mutex_lock(sys_mutex_t *mutex)
|
||||
{
|
||||
sys_arch_sem_wait(*mutex, 0);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Unlock a mutex*/
|
||||
void sys_mutex_unlock(sys_mutex_t *mutex)
|
||||
{
|
||||
xSemaphoreGive(*mutex);
|
||||
}
|
||||
#endif /*LWIP_COMPAT_MUTEX*/
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
// TODO
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/*
|
||||
Starts a new thread with priority "prio" that will begin its execution in the
|
||||
function "thread()". The "arg" argument will be passed as an argument to the
|
||||
thread() function. The id of the new thread is returned. Both the id and
|
||||
the priority are system dependent.
|
||||
*/
|
||||
sys_thread_t sys_thread_new_tcm(const char *name, lwip_thread_fn thread , void *arg, int stacksize, int prio)
|
||||
{
|
||||
xTaskHandle CreatedTask;
|
||||
int result;
|
||||
|
||||
if ( s_nextthread < SYS_THREAD_MAX )
|
||||
{
|
||||
vPortEnterCritical();
|
||||
#if CONFIG_USE_TCM_HEAP
|
||||
{
|
||||
void *stack_addr = tcm_heap_malloc(stacksize * sizeof(int));
|
||||
|
||||
if(stack_addr == NULL){
|
||||
}
|
||||
|
||||
result = xTaskGenericCreate(
|
||||
thread,
|
||||
( signed portCHAR * ) name,
|
||||
stacksize,
|
||||
arg,
|
||||
prio,
|
||||
&CreatedTask,
|
||||
stack_addr,
|
||||
NULL);
|
||||
}
|
||||
#else
|
||||
result = xTaskCreate( thread, ( signed portCHAR * ) name, stacksize, arg, prio, &CreatedTask );
|
||||
#endif
|
||||
|
||||
// For each task created, store the task handle (pid) in the timers array.
|
||||
// This scheme doesn't allow for threads to be deleted
|
||||
s_timeoutlist[s_nextthread++].pid = CreatedTask;
|
||||
vPortExitCritical();
|
||||
|
||||
if(result == pdPASS)
|
||||
{
|
||||
return CreatedTask;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
// TODO
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/*
|
||||
Starts a new thread with priority "prio" that will begin its execution in the
|
||||
function "thread()". The "arg" argument will be passed as an argument to the
|
||||
thread() function. The id of the new thread is returned. Both the id and
|
||||
the priority are system dependent.
|
||||
*/
|
||||
sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread , void *arg, int stacksize, int prio)
|
||||
{
|
||||
xTaskHandle CreatedTask;
|
||||
int result;
|
||||
|
||||
if ( s_nextthread < SYS_THREAD_MAX )
|
||||
{
|
||||
vPortEnterCritical();
|
||||
result = xTaskCreate( thread, ( signed portCHAR * ) name, stacksize, arg, prio, &CreatedTask );
|
||||
|
||||
// For each task created, store the task handle (pid) in the timers array.
|
||||
// This scheme doesn't allow for threads to be deleted
|
||||
s_timeoutlist[s_nextthread++].pid = CreatedTask;
|
||||
vPortExitCritical();
|
||||
|
||||
if(result == pdPASS)
|
||||
{
|
||||
return CreatedTask;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int sys_thread_delete(xTaskHandle pid)
|
||||
{
|
||||
int i, isFind = 0;
|
||||
struct timeoutlist *tl, *tend = NULL;
|
||||
|
||||
pid = (( pid == NULL)?(xTaskHandle) vTaskGetCurrentTCB() : pid);
|
||||
|
||||
if (s_nextthread)
|
||||
{
|
||||
vPortEnterCritical();
|
||||
|
||||
tend = &(s_timeoutlist[s_nextthread-1]);//the last one
|
||||
for(i = 0; i < s_nextthread; i++)
|
||||
{
|
||||
tl = &(s_timeoutlist[i]);
|
||||
if(tl->pid == pid)
|
||||
{//find the task, exchange with the last one
|
||||
memcpy(tl, tend, sizeof(struct timeoutlist));
|
||||
memset(tend, 0, sizeof(struct timeoutlist));
|
||||
s_nextthread --;
|
||||
isFind = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isFind) {
|
||||
vTaskDelete( pid);
|
||||
}
|
||||
|
||||
vPortExitCritical();
|
||||
|
||||
if (isFind)
|
||||
{
|
||||
return pdPASS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return pdFAIL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return pdFAIL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
This optional function does a "fast" critical region protection and returns
|
||||
the previous protection level. This function is only called during very short
|
||||
critical regions. An embedded system which supports ISR-based drivers might
|
||||
want to implement this function by disabling interrupts. Task-based systems
|
||||
might want to implement this by using a mutex or disabling tasking. This
|
||||
function should support recursive calls from the same task or interrupt. In
|
||||
other words, sys_arch_protect() could be called while already protected. In
|
||||
that case the return value indicates that it is already protected.
|
||||
|
||||
sys_arch_protect() is only required if your port is supporting an operating
|
||||
system.
|
||||
*/
|
||||
sys_prot_t sys_arch_protect(void)
|
||||
{
|
||||
vPortEnterCritical();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
This optional function does a "fast" set of critical region protection to the
|
||||
value specified by pval. See the documentation for sys_arch_protect() for
|
||||
more information. This function is only required if your port is supporting
|
||||
an operating system.
|
||||
*/
|
||||
void sys_arch_unprotect(sys_prot_t pval)
|
||||
{
|
||||
( void ) pval;
|
||||
vPortExitCritical();
|
||||
}
|
||||
|
||||
/*
|
||||
* Prints an assertion messages and aborts execution.
|
||||
*/
|
||||
void sys_assert( const char *msg )
|
||||
{
|
||||
( void ) msg;
|
||||
/*FSL:only needed for debugging
|
||||
printf(msg);
|
||||
printf("\n\r");
|
||||
*/
|
||||
vPortEnterCritical( );
|
||||
for(;;)
|
||||
;
|
||||
}
|
||||
|
||||
u32_t sys_now(void)
|
||||
{
|
||||
return xTaskGetTickCount();
|
||||
}
|
||||
|
||||
u32_t sys_jiffies(void)
|
||||
{
|
||||
return xTaskGetTickCount();
|
||||
}
|
||||
66
port/realtek/freertos/sys_arch.h
Normal file
66
port/realtek/freertos/sys_arch.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2003 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. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
#ifndef __SYS_RTXC_H__
|
||||
#define __SYS_RTXC_H__
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
#include "semphr.h"
|
||||
|
||||
#define SYS_MBOX_NULL (xQueueHandle)0
|
||||
#define SYS_SEM_NULL (xSemaphoreHandle)0
|
||||
#define SYS_DEFAULT_THREAD_STACK_DEPTH configMINIMAL_STACK_SIZE
|
||||
|
||||
typedef xSemaphoreHandle sys_sem_t;
|
||||
typedef xQueueHandle sys_mbox_t;
|
||||
typedef xTaskHandle sys_thread_t;
|
||||
|
||||
typedef struct _sys_arch_state_t
|
||||
{
|
||||
// Task creation data.
|
||||
char cTaskName[configMAX_TASK_NAME_LEN];
|
||||
unsigned short nStackDepth;
|
||||
unsigned short nTaskCount;
|
||||
} sys_arch_state_t;
|
||||
|
||||
|
||||
|
||||
//extern sys_arch_state_t s_sys_arch_state;
|
||||
|
||||
//void sys_set_default_state();
|
||||
//void sys_set_state(signed char *pTaskName, unsigned short nStackSize);
|
||||
|
||||
/* Message queue constants. */
|
||||
#define archMESG_QUEUE_LENGTH ( 6 )
|
||||
#endif /* __SYS_RTXC_H__ */
|
||||
|
||||
279
src/Filelists.cmake
Normal file
279
src/Filelists.cmake
Normal file
@@ -0,0 +1,279 @@
|
||||
# This file is indended to be included in end-user CMakeLists.txt
|
||||
# include(/path/to/Filelists.cmake)
|
||||
# It assumes the variable LWIP_DIR is defined pointing to the
|
||||
# root path of lwIP sources.
|
||||
#
|
||||
# This file is NOT designed (on purpose) to be used as cmake
|
||||
# subdir via add_subdirectory()
|
||||
# The intention is to provide greater flexibility to users to
|
||||
# create their own targets using the *_SRCS variables.
|
||||
|
||||
set(LWIP_VERSION_MAJOR "2")
|
||||
set(LWIP_VERSION_MINOR "1")
|
||||
set(LWIP_VERSION_REVISION "3")
|
||||
# LWIP_VERSION_RC is set to LWIP_RC_RELEASE for official releases
|
||||
# LWIP_VERSION_RC is set to LWIP_RC_DEVELOPMENT for Git versions
|
||||
# Numbers 1..31 are reserved for release candidates
|
||||
set(LWIP_VERSION_RC "LWIP_RC_RELEASE")
|
||||
|
||||
if ("${LWIP_VERSION_RC}" STREQUAL "LWIP_RC_RELEASE")
|
||||
set(LWIP_VERSION_STRING
|
||||
"${LWIP_VERSION_MAJOR}.${LWIP_VERSION_MINOR}.${LWIP_VERSION_REVISION}"
|
||||
)
|
||||
elseif ("${LWIP_VERSION_RC}" STREQUAL "LWIP_RC_DEVELOPMENT")
|
||||
set(LWIP_VERSION_STRING
|
||||
"${LWIP_VERSION_MAJOR}.${LWIP_VERSION_MINOR}.${LWIP_VERSION_REVISION}.dev"
|
||||
)
|
||||
else ("${LWIP_VERSION_RC}" STREQUAL "LWIP_RC_RELEASE")
|
||||
set(LWIP_VERSION_STRING
|
||||
"${LWIP_VERSION_MAJOR}.${LWIP_VERSION_MINOR}.${LWIP_VERSION_REVISION}.rc${LWIP_VERSION_RC}"
|
||||
)
|
||||
endif ("${LWIP_VERSION_RC}" STREQUAL "LWIP_RC_RELEASE")
|
||||
|
||||
# The minimum set of files needed for lwIP.
|
||||
set(lwipcore_SRCS
|
||||
${LWIP_DIR}/src/core/init.c
|
||||
${LWIP_DIR}/src/core/def.c
|
||||
${LWIP_DIR}/src/core/dns.c
|
||||
${LWIP_DIR}/src/core/inet_chksum.c
|
||||
${LWIP_DIR}/src/core/ip.c
|
||||
${LWIP_DIR}/src/core/mem.c
|
||||
${LWIP_DIR}/src/core/memp.c
|
||||
${LWIP_DIR}/src/core/netif.c
|
||||
${LWIP_DIR}/src/core/pbuf.c
|
||||
${LWIP_DIR}/src/core/raw.c
|
||||
${LWIP_DIR}/src/core/stats.c
|
||||
${LWIP_DIR}/src/core/sys.c
|
||||
${LWIP_DIR}/src/core/altcp.c
|
||||
${LWIP_DIR}/src/core/altcp_alloc.c
|
||||
${LWIP_DIR}/src/core/altcp_tcp.c
|
||||
${LWIP_DIR}/src/core/tcp.c
|
||||
${LWIP_DIR}/src/core/tcp_in.c
|
||||
${LWIP_DIR}/src/core/tcp_out.c
|
||||
${LWIP_DIR}/src/core/timeouts.c
|
||||
${LWIP_DIR}/src/core/udp.c
|
||||
)
|
||||
set(lwipcore4_SRCS
|
||||
${LWIP_DIR}/src/core/ipv4/autoip.c
|
||||
${LWIP_DIR}/src/core/ipv4/dhcp.c
|
||||
${LWIP_DIR}/src/core/ipv4/etharp.c
|
||||
${LWIP_DIR}/src/core/ipv4/icmp.c
|
||||
${LWIP_DIR}/src/core/ipv4/igmp.c
|
||||
${LWIP_DIR}/src/core/ipv4/ip4_frag.c
|
||||
${LWIP_DIR}/src/core/ipv4/ip4.c
|
||||
${LWIP_DIR}/src/core/ipv4/ip4_addr.c
|
||||
)
|
||||
set(lwipcore6_SRCS
|
||||
${LWIP_DIR}/src/core/ipv6/dhcp6.c
|
||||
${LWIP_DIR}/src/core/ipv6/ethip6.c
|
||||
${LWIP_DIR}/src/core/ipv6/icmp6.c
|
||||
${LWIP_DIR}/src/core/ipv6/inet6.c
|
||||
${LWIP_DIR}/src/core/ipv6/ip6.c
|
||||
${LWIP_DIR}/src/core/ipv6/ip6_addr.c
|
||||
${LWIP_DIR}/src/core/ipv6/ip6_frag.c
|
||||
${LWIP_DIR}/src/core/ipv6/mld6.c
|
||||
${LWIP_DIR}/src/core/ipv6/nd6.c
|
||||
)
|
||||
|
||||
# APIFILES: The files which implement the sequential and socket APIs.
|
||||
set(lwipapi_SRCS
|
||||
${LWIP_DIR}/src/api/api_lib.c
|
||||
${LWIP_DIR}/src/api/api_msg.c
|
||||
${LWIP_DIR}/src/api/err.c
|
||||
${LWIP_DIR}/src/api/if_api.c
|
||||
${LWIP_DIR}/src/api/netbuf.c
|
||||
${LWIP_DIR}/src/api/netdb.c
|
||||
${LWIP_DIR}/src/api/netifapi.c
|
||||
${LWIP_DIR}/src/api/sockets.c
|
||||
${LWIP_DIR}/src/api/tcpip.c
|
||||
)
|
||||
|
||||
# Files implementing various generic network interface functions
|
||||
set(lwipnetif_SRCS
|
||||
${LWIP_DIR}/src/netif/ethernet.c
|
||||
${LWIP_DIR}/src/netif/bridgeif.c
|
||||
${LWIP_DIR}/src/netif/bridgeif_fdb.c
|
||||
${LWIP_DIR}/src/netif/slipif.c
|
||||
)
|
||||
|
||||
# 6LoWPAN
|
||||
set(lwipsixlowpan_SRCS
|
||||
${LWIP_DIR}/src/netif/lowpan6_common.c
|
||||
${LWIP_DIR}/src/netif/lowpan6.c
|
||||
${LWIP_DIR}/src/netif/lowpan6_ble.c
|
||||
${LWIP_DIR}/src/netif/zepif.c
|
||||
)
|
||||
|
||||
# PPP
|
||||
set(lwipppp_SRCS
|
||||
${LWIP_DIR}/src/netif/ppp/auth.c
|
||||
${LWIP_DIR}/src/netif/ppp/ccp.c
|
||||
${LWIP_DIR}/src/netif/ppp/chap-md5.c
|
||||
${LWIP_DIR}/src/netif/ppp/chap_ms.c
|
||||
${LWIP_DIR}/src/netif/ppp/chap-new.c
|
||||
${LWIP_DIR}/src/netif/ppp/demand.c
|
||||
${LWIP_DIR}/src/netif/ppp/eap.c
|
||||
${LWIP_DIR}/src/netif/ppp/ecp.c
|
||||
${LWIP_DIR}/src/netif/ppp/eui64.c
|
||||
${LWIP_DIR}/src/netif/ppp/fsm.c
|
||||
${LWIP_DIR}/src/netif/ppp/ipcp.c
|
||||
${LWIP_DIR}/src/netif/ppp/ipv6cp.c
|
||||
${LWIP_DIR}/src/netif/ppp/lcp.c
|
||||
${LWIP_DIR}/src/netif/ppp/magic.c
|
||||
${LWIP_DIR}/src/netif/ppp/mppe.c
|
||||
${LWIP_DIR}/src/netif/ppp/multilink.c
|
||||
${LWIP_DIR}/src/netif/ppp/ppp.c
|
||||
${LWIP_DIR}/src/netif/ppp/pppapi.c
|
||||
${LWIP_DIR}/src/netif/ppp/pppcrypt.c
|
||||
${LWIP_DIR}/src/netif/ppp/pppoe.c
|
||||
${LWIP_DIR}/src/netif/ppp/pppol2tp.c
|
||||
${LWIP_DIR}/src/netif/ppp/pppos.c
|
||||
${LWIP_DIR}/src/netif/ppp/upap.c
|
||||
${LWIP_DIR}/src/netif/ppp/utils.c
|
||||
${LWIP_DIR}/src/netif/ppp/vj.c
|
||||
${LWIP_DIR}/src/netif/ppp/polarssl/arc4.c
|
||||
${LWIP_DIR}/src/netif/ppp/polarssl/des.c
|
||||
${LWIP_DIR}/src/netif/ppp/polarssl/md4.c
|
||||
${LWIP_DIR}/src/netif/ppp/polarssl/md5.c
|
||||
${LWIP_DIR}/src/netif/ppp/polarssl/sha1.c
|
||||
)
|
||||
|
||||
# SNMPv3 agent
|
||||
set(lwipsnmp_SRCS
|
||||
${LWIP_DIR}/src/apps/snmp/snmp_asn1.c
|
||||
${LWIP_DIR}/src/apps/snmp/snmp_core.c
|
||||
${LWIP_DIR}/src/apps/snmp/snmp_mib2.c
|
||||
${LWIP_DIR}/src/apps/snmp/snmp_mib2_icmp.c
|
||||
${LWIP_DIR}/src/apps/snmp/snmp_mib2_interfaces.c
|
||||
${LWIP_DIR}/src/apps/snmp/snmp_mib2_ip.c
|
||||
${LWIP_DIR}/src/apps/snmp/snmp_mib2_snmp.c
|
||||
${LWIP_DIR}/src/apps/snmp/snmp_mib2_system.c
|
||||
${LWIP_DIR}/src/apps/snmp/snmp_mib2_tcp.c
|
||||
${LWIP_DIR}/src/apps/snmp/snmp_mib2_udp.c
|
||||
${LWIP_DIR}/src/apps/snmp/snmp_snmpv2_framework.c
|
||||
${LWIP_DIR}/src/apps/snmp/snmp_snmpv2_usm.c
|
||||
${LWIP_DIR}/src/apps/snmp/snmp_msg.c
|
||||
${LWIP_DIR}/src/apps/snmp/snmpv3.c
|
||||
${LWIP_DIR}/src/apps/snmp/snmp_netconn.c
|
||||
${LWIP_DIR}/src/apps/snmp/snmp_pbuf_stream.c
|
||||
${LWIP_DIR}/src/apps/snmp/snmp_raw.c
|
||||
${LWIP_DIR}/src/apps/snmp/snmp_scalar.c
|
||||
${LWIP_DIR}/src/apps/snmp/snmp_table.c
|
||||
${LWIP_DIR}/src/apps/snmp/snmp_threadsync.c
|
||||
${LWIP_DIR}/src/apps/snmp/snmp_traps.c
|
||||
)
|
||||
|
||||
# HTTP server + client
|
||||
set(lwiphttp_SRCS
|
||||
${LWIP_DIR}/src/apps/http/altcp_proxyconnect.c
|
||||
${LWIP_DIR}/src/apps/http/fs.c
|
||||
${LWIP_DIR}/src/apps/http/http_client.c
|
||||
${LWIP_DIR}/src/apps/http/httpd.c
|
||||
)
|
||||
|
||||
# MAKEFSDATA HTTP server host utility
|
||||
set(lwipmakefsdata_SRCS
|
||||
${LWIP_DIR}/src/apps/http/makefsdata/makefsdata.c
|
||||
)
|
||||
|
||||
# IPERF server
|
||||
set(lwipiperf_SRCS
|
||||
${LWIP_DIR}/src/apps/lwiperf/lwiperf.c
|
||||
)
|
||||
|
||||
# SMTP client
|
||||
set(lwipsmtp_SRCS
|
||||
${LWIP_DIR}/src/apps/smtp/smtp.c
|
||||
)
|
||||
|
||||
# SNTP client
|
||||
set(lwipsntp_SRCS
|
||||
${LWIP_DIR}/src/apps/sntp/sntp.c
|
||||
)
|
||||
|
||||
# MDNS responder
|
||||
set(lwipmdns_SRCS
|
||||
${LWIP_DIR}/src/apps/mdns/mdns.c
|
||||
)
|
||||
|
||||
# NetBIOS name server
|
||||
set(lwipnetbios_SRCS
|
||||
${LWIP_DIR}/src/apps/netbiosns/netbiosns.c
|
||||
)
|
||||
|
||||
# TFTP server files
|
||||
set(lwiptftp_SRCS
|
||||
${LWIP_DIR}/src/apps/tftp/tftp_server.c
|
||||
)
|
||||
|
||||
# MQTT client files
|
||||
set(lwipmqtt_SRCS
|
||||
${LWIP_DIR}/src/apps/mqtt/mqtt.c
|
||||
)
|
||||
|
||||
# ARM MBEDTLS related files of lwIP rep
|
||||
set(lwipmbedtls_SRCS
|
||||
${LWIP_DIR}/src/apps/altcp_tls/altcp_tls_mbedtls.c
|
||||
${LWIP_DIR}/src/apps/altcp_tls/altcp_tls_mbedtls_mem.c
|
||||
${LWIP_DIR}/src/apps/snmp/snmpv3_mbedtls.c
|
||||
)
|
||||
|
||||
# All LWIP files without apps
|
||||
set(lwipnoapps_SRCS
|
||||
${lwipcore_SRCS}
|
||||
${lwipcore4_SRCS}
|
||||
${lwipcore6_SRCS}
|
||||
${lwipapi_SRCS}
|
||||
${lwipnetif_SRCS}
|
||||
${lwipsixlowpan_SRCS}
|
||||
${lwipppp_SRCS}
|
||||
)
|
||||
|
||||
# LWIPAPPFILES: All LWIP APPs
|
||||
set(lwipallapps_SRCS
|
||||
${lwipsnmp_SRCS}
|
||||
${lwiphttp_SRCS}
|
||||
${lwipiperf_SRCS}
|
||||
${lwipsmtp_SRCS}
|
||||
${lwipsntp_SRCS}
|
||||
${lwipmdns_SRCS}
|
||||
${lwipnetbios_SRCS}
|
||||
${lwiptftp_SRCS}
|
||||
${lwipmqtt_SRCS}
|
||||
${lwipmbedtls_SRCS}
|
||||
)
|
||||
|
||||
# Generate lwip/init.h (version info)
|
||||
configure_file(${LWIP_DIR}/src/include/lwip/init.h.cmake.in ${LWIP_DIR}/src/include/lwip/init.h)
|
||||
|
||||
# Documentation
|
||||
set(DOXYGEN_DIR ${LWIP_DIR}/doc/doxygen)
|
||||
set(DOXYGEN_OUTPUT_DIR output)
|
||||
set(DOXYGEN_IN ${LWIP_DIR}/doc/doxygen/lwip.Doxyfile.cmake.in)
|
||||
set(DOXYGEN_OUT ${LWIP_DIR}/doc/doxygen/lwip.Doxyfile)
|
||||
configure_file(${DOXYGEN_IN} ${DOXYGEN_OUT})
|
||||
|
||||
find_package(Doxygen)
|
||||
if (DOXYGEN_FOUND)
|
||||
message("Doxygen build started")
|
||||
|
||||
add_custom_target(lwipdocs
|
||||
COMMAND ${CMAKE_COMMAND} -E remove_directory ${DOXYGEN_DIR}/${DOXYGEN_OUTPUT_DIR}/html
|
||||
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT}
|
||||
WORKING_DIRECTORY ${DOXYGEN_DIR}
|
||||
COMMENT "Generating API documentation with Doxygen"
|
||||
VERBATIM)
|
||||
else (DOXYGEN_FOUND)
|
||||
message("Doxygen needs to be installed to generate the doxygen documentation")
|
||||
endif (DOXYGEN_FOUND)
|
||||
|
||||
# lwIP libraries
|
||||
add_library(lwipcore EXCLUDE_FROM_ALL ${lwipnoapps_SRCS})
|
||||
target_compile_options(lwipcore PRIVATE ${LWIP_COMPILER_FLAGS})
|
||||
target_compile_definitions(lwipcore PRIVATE ${LWIP_DEFINITIONS} ${LWIP_MBEDTLS_DEFINITIONS})
|
||||
target_include_directories(lwipcore PRIVATE ${LWIP_INCLUDE_DIRS} ${LWIP_MBEDTLS_INCLUDE_DIRS})
|
||||
|
||||
add_library(lwipallapps EXCLUDE_FROM_ALL ${lwipallapps_SRCS})
|
||||
target_compile_options(lwipallapps PRIVATE ${LWIP_COMPILER_FLAGS})
|
||||
target_compile_definitions(lwipallapps PRIVATE ${LWIP_DEFINITIONS} ${LWIP_MBEDTLS_DEFINITIONS})
|
||||
target_include_directories(lwipallapps PRIVATE ${LWIP_INCLUDE_DIRS} ${LWIP_MBEDTLS_INCLUDE_DIRS})
|
||||
@@ -42,6 +42,9 @@ COREFILES=$(LWIPDIR)/core/init.c \
|
||||
$(LWIPDIR)/core/raw.c \
|
||||
$(LWIPDIR)/core/stats.c \
|
||||
$(LWIPDIR)/core/sys.c \
|
||||
$(LWIPDIR)/core/altcp.c \
|
||||
$(LWIPDIR)/core/altcp_alloc.c \
|
||||
$(LWIPDIR)/core/altcp_tcp.c \
|
||||
$(LWIPDIR)/core/tcp.c \
|
||||
$(LWIPDIR)/core/tcp_in.c \
|
||||
$(LWIPDIR)/core/tcp_out.c \
|
||||
@@ -71,6 +74,7 @@ CORE6FILES=$(LWIPDIR)/core/ipv6/dhcp6.c \
|
||||
APIFILES=$(LWIPDIR)/api/api_lib.c \
|
||||
$(LWIPDIR)/api/api_msg.c \
|
||||
$(LWIPDIR)/api/err.c \
|
||||
$(LWIPDIR)/api/if_api.c \
|
||||
$(LWIPDIR)/api/netbuf.c \
|
||||
$(LWIPDIR)/api/netdb.c \
|
||||
$(LWIPDIR)/api/netifapi.c \
|
||||
@@ -79,10 +83,15 @@ APIFILES=$(LWIPDIR)/api/api_lib.c \
|
||||
|
||||
# NETIFFILES: Files implementing various generic network interface functions
|
||||
NETIFFILES=$(LWIPDIR)/netif/ethernet.c \
|
||||
$(LWIPDIR)/netif/bridgeif.c \
|
||||
$(LWIPDIR)/netif/bridgeif_fdb.c \
|
||||
$(LWIPDIR)/netif/slipif.c
|
||||
|
||||
# SIXLOWPAN: 6LoWPAN
|
||||
SIXLOWPAN=$(LWIPDIR)/netif/lowpan6.c \
|
||||
SIXLOWPAN=$(LWIPDIR)/netif/lowpan6_common.c \
|
||||
$(LWIPDIR)/netif/lowpan6.c \
|
||||
$(LWIPDIR)/netif/lowpan6_ble.c \
|
||||
$(LWIPDIR)/netif/zepif.c
|
||||
|
||||
# PPPFILES: PPP
|
||||
PPPFILES=$(LWIPDIR)/netif/ppp/auth.c \
|
||||
@@ -136,6 +145,8 @@ SNMPFILES=$(LWIPDIR)/apps/snmp/snmp_asn1.c \
|
||||
$(LWIPDIR)/apps/snmp/snmp_mib2_system.c \
|
||||
$(LWIPDIR)/apps/snmp/snmp_mib2_tcp.c \
|
||||
$(LWIPDIR)/apps/snmp/snmp_mib2_udp.c \
|
||||
$(LWIPDIR)/apps/snmp/snmp_snmpv2_framework.c \
|
||||
$(LWIPDIR)/apps/snmp/snmp_snmpv2_usm.c \
|
||||
$(LWIPDIR)/apps/snmp/snmp_msg.c \
|
||||
$(LWIPDIR)/apps/snmp/snmpv3.c \
|
||||
$(LWIPDIR)/apps/snmp/snmp_netconn.c \
|
||||
@@ -144,17 +155,23 @@ SNMPFILES=$(LWIPDIR)/apps/snmp/snmp_asn1.c \
|
||||
$(LWIPDIR)/apps/snmp/snmp_scalar.c \
|
||||
$(LWIPDIR)/apps/snmp/snmp_table.c \
|
||||
$(LWIPDIR)/apps/snmp/snmp_threadsync.c \
|
||||
$(LWIPDIR)/apps/snmp/snmp_traps.c \
|
||||
$(LWIPDIR)/apps/snmp/snmpv3_mbedtls.c \
|
||||
$(LWIPDIR)/apps/snmp/snmpv3_dummy.c
|
||||
$(LWIPDIR)/apps/snmp/snmp_traps.c
|
||||
|
||||
# HTTPDFILES: HTTP server
|
||||
HTTPDFILES=$(LWIPDIR)/apps/httpd/fs.c \
|
||||
$(LWIPDIR)/apps/httpd/httpd.c
|
||||
# HTTPFILES: HTTP server + client
|
||||
HTTPFILES=$(LWIPDIR)/apps/http/altcp_proxyconnect.c \
|
||||
$(LWIPDIR)/apps/http/fs.c \
|
||||
$(LWIPDIR)/apps/http/http_client.c \
|
||||
$(LWIPDIR)/apps/http/httpd.c
|
||||
|
||||
# MAKEFSDATA: MAKEFSDATA HTTP server host utility
|
||||
MAKEFSDATAFILES=$(LWIPDIR)/apps/http/makefsdata/makefsdata.c
|
||||
|
||||
# LWIPERFFILES: IPERF server
|
||||
LWIPERFFILES=$(LWIPDIR)/apps/lwiperf/lwiperf.c
|
||||
|
||||
# SMTPFILES: SMTP client
|
||||
SMTPFILES=$(LWIPDIR)/apps/smtp/smtp.c
|
||||
|
||||
# SNTPFILES: SNTP client
|
||||
SNTPFILES=$(LWIPDIR)/apps/sntp/sntp.c
|
||||
|
||||
@@ -167,11 +184,22 @@ NETBIOSNSFILES=$(LWIPDIR)/apps/netbiosns/netbiosns.c
|
||||
# TFTPFILES: TFTP server files
|
||||
TFTPFILES=$(LWIPDIR)/apps/tftp/tftp_server.c
|
||||
|
||||
# MQTTFILES: MQTT client files
|
||||
MQTTFILES=$(LWIPDIR)/apps/mqtt/mqtt.c
|
||||
|
||||
# MBEDTLS_FILES: MBEDTLS related files of lwIP rep
|
||||
MBEDTLS_FILES=$(LWIPDIR)/apps/altcp_tls/altcp_tls_mbedtls.c \
|
||||
$(LWIPDIR)/apps/altcp_tls/altcp_tls_mbedtls_mem.c \
|
||||
$(LWIPDIR)/apps/snmp/snmpv3_mbedtls.c
|
||||
|
||||
# LWIPAPPFILES: All LWIP APPs
|
||||
LWIPAPPFILES=$(SNMPFILES) \
|
||||
$(HTTPDFILES) \
|
||||
$(HTTPFILES) \
|
||||
$(LWIPERFFILES) \
|
||||
$(SMTPFILES) \
|
||||
$(SNTPFILES) \
|
||||
$(MDNSFILES) \
|
||||
$(NETBIOSNSFILES) \
|
||||
$(TFTPFILES)
|
||||
$(TFTPFILES) \
|
||||
$(MQTTFILES) \
|
||||
$(MBEDTLS_FILES)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
1239
src/api/api_msg.c
1239
src/api/api_msg.c
File diff suppressed because it is too large
Load Diff
@@ -64,28 +64,37 @@ static const int err_to_errno_table[] = {
|
||||
ENOTCONN, /* ERR_CLSD -15 Connection closed. */
|
||||
EIO /* ERR_ARG -16 Illegal argument. */
|
||||
};
|
||||
|
||||
int
|
||||
err_to_errno(err_t err)
|
||||
{
|
||||
if ((err > 0) || (-err >= (err_t)LWIP_ARRAYSIZE(err_to_errno_table))) {
|
||||
return EIO;
|
||||
}
|
||||
return err_to_errno_table[-err];
|
||||
}
|
||||
#endif /* !NO_SYS */
|
||||
|
||||
#ifdef LWIP_DEBUG
|
||||
|
||||
static const char *err_strerr[] = {
|
||||
"Ok.", /* ERR_OK 0 */
|
||||
"Out of memory error.", /* ERR_MEM -1 */
|
||||
"Buffer error.", /* ERR_BUF -2 */
|
||||
"Timeout.", /* ERR_TIMEOUT -3 */
|
||||
"Routing problem.", /* ERR_RTE -4 */
|
||||
"Operation in progress.", /* ERR_INPROGRESS -5 */
|
||||
"Illegal value.", /* ERR_VAL -6 */
|
||||
"Operation would block.", /* ERR_WOULDBLOCK -7 */
|
||||
"Address in use.", /* ERR_USE -8 */
|
||||
"Already connecting.", /* ERR_ALREADY -9 */
|
||||
"Already connected.", /* ERR_ISCONN -10 */
|
||||
"Not connected.", /* ERR_CONN -11 */
|
||||
"Low-level netif error.", /* ERR_IF -12 */
|
||||
"Connection aborted.", /* ERR_ABRT -13 */
|
||||
"Connection reset.", /* ERR_RST -14 */
|
||||
"Connection closed.", /* ERR_CLSD -15 */
|
||||
"Illegal argument." /* ERR_ARG -16 */
|
||||
"Ok.", /* ERR_OK 0 */
|
||||
"Out of memory error.", /* ERR_MEM -1 */
|
||||
"Buffer error.", /* ERR_BUF -2 */
|
||||
"Timeout.", /* ERR_TIMEOUT -3 */
|
||||
"Routing problem.", /* ERR_RTE -4 */
|
||||
"Operation in progress.", /* ERR_INPROGRESS -5 */
|
||||
"Illegal value.", /* ERR_VAL -6 */
|
||||
"Operation would block.", /* ERR_WOULDBLOCK -7 */
|
||||
"Address in use.", /* ERR_USE -8 */
|
||||
"Already connecting.", /* ERR_ALREADY -9 */
|
||||
"Already connected.", /* ERR_ISCONN -10 */
|
||||
"Not connected.", /* ERR_CONN -11 */
|
||||
"Low-level netif error.", /* ERR_IF -12 */
|
||||
"Connection aborted.", /* ERR_ABRT -13 */
|
||||
"Connection reset.", /* ERR_RST -14 */
|
||||
"Connection closed.", /* ERR_CLSD -15 */
|
||||
"Illegal argument." /* ERR_ARG -16 */
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -104,14 +113,3 @@ lwip_strerr(err_t err)
|
||||
}
|
||||
|
||||
#endif /* LWIP_DEBUG */
|
||||
|
||||
#if !NO_SYS
|
||||
int
|
||||
err_to_errno(err_t err)
|
||||
{
|
||||
if ((err > 0) || (-err >= (err_t)LWIP_ARRAYSIZE(err_to_errno_table))) {
|
||||
return EIO;
|
||||
}
|
||||
return err_to_errno_table[-err];
|
||||
}
|
||||
#endif /* !NO_SYS */
|
||||
|
||||
102
src/api/if_api.c
Normal file
102
src/api/if_api.c
Normal file
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* @file
|
||||
* Interface Identification APIs from:
|
||||
* RFC 3493: Basic Socket Interface Extensions for IPv6
|
||||
* Section 4: Interface Identification
|
||||
*
|
||||
* @defgroup if_api Interface Identification API
|
||||
* @ingroup socket
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Joel Cunningham, Garmin International, Inc. <joel.cunningham@garmin.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. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Joel Cunningham <joel.cunningham@me.com>
|
||||
*
|
||||
*/
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_SOCKET
|
||||
|
||||
#include "lwip/errno.h"
|
||||
#include "lwip/if_api.h"
|
||||
#include "lwip/netifapi.h"
|
||||
#include "lwip/priv/sockets_priv.h"
|
||||
|
||||
/**
|
||||
* @ingroup if_api
|
||||
* Maps an interface index to its corresponding name.
|
||||
* @param ifindex interface index
|
||||
* @param ifname shall point to a buffer of at least {IF_NAMESIZE} bytes
|
||||
* @return If ifindex is an interface index, then the function shall return the
|
||||
* value supplied in ifname, which points to a buffer now containing the interface name.
|
||||
* Otherwise, the function shall return a NULL pointer.
|
||||
*/
|
||||
char *
|
||||
lwip_if_indextoname(unsigned int ifindex, char *ifname)
|
||||
{
|
||||
#if LWIP_NETIF_API
|
||||
if (ifindex <= 0xff) {
|
||||
err_t err = netifapi_netif_index_to_name((u8_t)ifindex, ifname);
|
||||
if (!err && ifname[0] != '\0') {
|
||||
return ifname;
|
||||
}
|
||||
}
|
||||
#else /* LWIP_NETIF_API */
|
||||
LWIP_UNUSED_ARG(ifindex);
|
||||
LWIP_UNUSED_ARG(ifname);
|
||||
#endif /* LWIP_NETIF_API */
|
||||
set_errno(ENXIO);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup if_api
|
||||
* Returs the interface index corresponding to name ifname.
|
||||
* @param ifname Interface name
|
||||
* @return The corresponding index if ifname is the name of an interface;
|
||||
* otherwise, zero.
|
||||
*/
|
||||
unsigned int
|
||||
lwip_if_nametoindex(const char *ifname)
|
||||
{
|
||||
#if LWIP_NETIF_API
|
||||
err_t err;
|
||||
u8_t idx;
|
||||
|
||||
err = netifapi_netif_name_to_index(ifname, &idx);
|
||||
if (!err) {
|
||||
return idx;
|
||||
}
|
||||
#else /* LWIP_NETIF_API */
|
||||
LWIP_UNUSED_ARG(ifname);
|
||||
#endif /* LWIP_NETIF_API */
|
||||
return 0; /* invalid index */
|
||||
}
|
||||
|
||||
#endif /* LWIP_SOCKET */
|
||||
@@ -109,10 +109,10 @@ netbuf_alloc(struct netbuf *buf, u16_t size)
|
||||
}
|
||||
buf->p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM);
|
||||
if (buf->p == NULL) {
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
LWIP_ASSERT("check that first pbuf can hold size",
|
||||
(buf->p->len >= size));
|
||||
(buf->p->len >= size));
|
||||
buf->ptr = buf->p;
|
||||
return buf->p->payload;
|
||||
}
|
||||
@@ -131,6 +131,10 @@ netbuf_free(struct netbuf *buf)
|
||||
pbuf_free(buf->p);
|
||||
}
|
||||
buf->p = buf->ptr = NULL;
|
||||
#if LWIP_CHECKSUM_ON_COPY
|
||||
buf->flags = 0;
|
||||
buf->toport_chksum = 0;
|
||||
#endif /* LWIP_CHECKSUM_ON_COPY */
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -155,7 +159,7 @@ netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size)
|
||||
buf->ptr = NULL;
|
||||
return ERR_MEM;
|
||||
}
|
||||
((struct pbuf_rom*)buf->p)->payload = dataptr;
|
||||
((struct pbuf_rom *)buf->p)->payload = dataptr;
|
||||
buf->p->len = buf->p->tot_len = size;
|
||||
buf->ptr = buf->p;
|
||||
return ERR_OK;
|
||||
|
||||
@@ -46,8 +46,8 @@
|
||||
#include "lwip/api.h"
|
||||
#include "lwip/dns.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h> /* memset */
|
||||
#include <stdlib.h> /* atoi */
|
||||
|
||||
/** helper struct for gethostbyname_r to access the char* buffer */
|
||||
struct gethostbyname_r_helper {
|
||||
@@ -83,7 +83,7 @@ int h_errno;
|
||||
* @return an entry containing addresses of address family AF_INET
|
||||
* for the host with name name
|
||||
*/
|
||||
struct hostent*
|
||||
struct hostent *
|
||||
lwip_gethostbyname(const char *name)
|
||||
{
|
||||
err_t err;
|
||||
@@ -115,21 +115,20 @@ lwip_gethostbyname(const char *name)
|
||||
s_hostent.h_aliases = &s_aliases;
|
||||
s_hostent.h_addrtype = AF_INET;
|
||||
s_hostent.h_length = sizeof(ip_addr_t);
|
||||
s_hostent.h_addr_list = (char**)&s_phostent_addr;
|
||||
s_hostent.h_addr_list = (char **)&s_phostent_addr;
|
||||
|
||||
#if DNS_DEBUG
|
||||
/* dump hostent */
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name == %s\n", s_hostent.h_name));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases == %p\n", (void*)s_hostent.h_aliases));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases == %p\n", (void *)s_hostent.h_aliases));
|
||||
/* h_aliases are always empty */
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype == %d\n", s_hostent.h_addrtype));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length == %d\n", s_hostent.h_length));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list == %p\n", (void*)s_hostent.h_addr_list));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list == %p\n", (void *)s_hostent.h_addr_list));
|
||||
if (s_hostent.h_addr_list != NULL) {
|
||||
u8_t idx;
|
||||
for (idx=0; s_hostent.h_addr_list[idx]; idx++) {
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i] == %p\n", idx, s_hostent.h_addr_list[idx]));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, ipaddr_ntoa((ip_addr_t*)s_hostent.h_addr_list[idx])));
|
||||
for (idx = 0; s_hostent.h_addr_list[idx]; idx++) {
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, ipaddr_ntoa(s_phostent_addr[idx])));
|
||||
}
|
||||
}
|
||||
#endif /* DNS_DEBUG */
|
||||
@@ -160,7 +159,7 @@ lwip_gethostbyname(const char *name)
|
||||
*/
|
||||
int
|
||||
lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
|
||||
size_t buflen, struct hostent **result, int *h_errnop)
|
||||
size_t buflen, struct hostent **result, int *h_errnop)
|
||||
{
|
||||
err_t err;
|
||||
struct gethostbyname_r_helper *h;
|
||||
@@ -187,14 +186,14 @@ lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
|
||||
}
|
||||
|
||||
namelen = strlen(name);
|
||||
if (buflen < (sizeof(struct gethostbyname_r_helper) + namelen + 1 + (MEM_ALIGNMENT - 1))) {
|
||||
if (buflen < (sizeof(struct gethostbyname_r_helper) + LWIP_MEM_ALIGN_BUFFER(namelen + 1))) {
|
||||
/* buf can't hold the data needed + a copy of name */
|
||||
*h_errnop = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
h = (struct gethostbyname_r_helper*)LWIP_MEM_ALIGN(buf);
|
||||
hostname = ((char*)h) + sizeof(struct gethostbyname_r_helper);
|
||||
h = (struct gethostbyname_r_helper *)LWIP_MEM_ALIGN(buf);
|
||||
hostname = ((char *)h) + sizeof(struct gethostbyname_r_helper);
|
||||
|
||||
/* query host IP address */
|
||||
err = netconn_gethostbyname(name, &h->addr);
|
||||
@@ -216,7 +215,7 @@ lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
|
||||
ret->h_aliases = &h->aliases;
|
||||
ret->h_addrtype = AF_INET;
|
||||
ret->h_length = sizeof(ip_addr_t);
|
||||
ret->h_addr_list = (char**)&h->addr_list;
|
||||
ret->h_addr_list = (char **)&h->addr_list;
|
||||
|
||||
/* set result != NULL */
|
||||
*result = ret;
|
||||
@@ -267,7 +266,7 @@ lwip_freeaddrinfo(struct addrinfo *ai)
|
||||
*/
|
||||
int
|
||||
lwip_getaddrinfo(const char *nodename, const char *servname,
|
||||
const struct addrinfo *hints, struct addrinfo **res)
|
||||
const struct addrinfo *hints, struct addrinfo **res)
|
||||
{
|
||||
err_t err;
|
||||
ip_addr_t addr;
|
||||
@@ -290,12 +289,12 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
|
||||
ai_family = hints->ai_family;
|
||||
if ((ai_family != AF_UNSPEC)
|
||||
#if LWIP_IPV4
|
||||
&& (ai_family != AF_INET)
|
||||
&& (ai_family != AF_INET)
|
||||
#endif /* LWIP_IPV4 */
|
||||
#if LWIP_IPV6
|
||||
&& (ai_family != AF_INET6)
|
||||
&& (ai_family != AF_INET6)
|
||||
#endif /* LWIP_IPV6 */
|
||||
) {
|
||||
) {
|
||||
return EAI_FAMILY;
|
||||
}
|
||||
} else {
|
||||
@@ -306,7 +305,11 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
|
||||
/* service name specified: convert to port number
|
||||
* @todo?: currently, only ASCII integers (port numbers) are supported (AI_NUMERICSERV)! */
|
||||
port_nr = atoi(servname);
|
||||
if ((port_nr <= 0) || (port_nr > 0xffff)) {
|
||||
if (port_nr == 0 && (servname[0] != '0')) {
|
||||
/* atoi failed - service was not numeric */
|
||||
return EAI_SERVICE;
|
||||
}
|
||||
if ((port_nr < 0) || (port_nr > 0xffff)) {
|
||||
return EAI_SERVICE;
|
||||
}
|
||||
}
|
||||
@@ -342,9 +345,9 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
|
||||
} else {
|
||||
/* service location specified, use loopback address */
|
||||
if ((hints != NULL) && (hints->ai_flags & AI_PASSIVE)) {
|
||||
ip_addr_set_any(ai_family == AF_INET6, &addr);
|
||||
ip_addr_set_any_val(ai_family == AF_INET6, addr);
|
||||
} else {
|
||||
ip_addr_set_loopback(ai_family == AF_INET6, &addr);
|
||||
ip_addr_set_loopback_val(ai_family == AF_INET6, addr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,29 +363,30 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
|
||||
}
|
||||
/* If this fails, please report to lwip-devel! :-) */
|
||||
LWIP_ASSERT("total_size <= NETDB_ELEM_SIZE: please report this!",
|
||||
total_size <= NETDB_ELEM_SIZE);
|
||||
total_size <= NETDB_ELEM_SIZE);
|
||||
ai = (struct addrinfo *)memp_malloc(MEMP_NETDB);
|
||||
if (ai == NULL) {
|
||||
return EAI_MEMORY;
|
||||
}
|
||||
memset(ai, 0, total_size);
|
||||
/* cast through void* to get rid of alignment warnings */
|
||||
sa = (struct sockaddr_storage *)(void*)((u8_t*)ai + sizeof(struct addrinfo));
|
||||
sa = (struct sockaddr_storage *)(void *)((u8_t *)ai + sizeof(struct addrinfo));
|
||||
if (IP_IS_V6_VAL(addr)) {
|
||||
#if LWIP_IPV6
|
||||
struct sockaddr_in6 *sa6 = (struct sockaddr_in6*)sa;
|
||||
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
|
||||
/* set up sockaddr */
|
||||
inet6_addr_from_ip6addr(&sa6->sin6_addr, ip_2_ip6(&addr));
|
||||
sa6->sin6_family = AF_INET6;
|
||||
sa6->sin6_len = sizeof(struct sockaddr_in6);
|
||||
sa6->sin6_port = lwip_htons((u16_t)port_nr);
|
||||
sa6->sin6_scope_id = ip6_addr_zone(ip_2_ip6(&addr));
|
||||
ai->ai_family = AF_INET6;
|
||||
#endif /* LWIP_IPV6 */
|
||||
} else {
|
||||
#if LWIP_IPV4
|
||||
struct sockaddr_in *sa4 = (struct sockaddr_in*)sa;
|
||||
struct sockaddr_in *sa4 = (struct sockaddr_in *)sa;
|
||||
/* set up sockaddr */
|
||||
inet_addr_from_ipaddr(&sa4->sin_addr, ip_2_ip4(&addr));
|
||||
inet_addr_from_ip4addr(&sa4->sin_addr, ip_2_ip4(&addr));
|
||||
sa4->sin_family = AF_INET;
|
||||
sa4->sin_len = sizeof(struct sockaddr_in);
|
||||
sa4->sin_port = lwip_htons((u16_t)port_nr);
|
||||
@@ -398,12 +402,12 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
|
||||
}
|
||||
if (nodename != NULL) {
|
||||
/* copy nodename to canonname if specified */
|
||||
ai->ai_canonname = ((char*)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_storage));
|
||||
ai->ai_canonname = ((char *)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_storage));
|
||||
MEMCPY(ai->ai_canonname, nodename, namelen);
|
||||
ai->ai_canonname[namelen] = 0;
|
||||
}
|
||||
ai->ai_addrlen = sizeof(struct sockaddr_storage);
|
||||
ai->ai_addr = (struct sockaddr*)sa;
|
||||
ai->ai_addr = (struct sockaddr *)sa;
|
||||
|
||||
*res = ai;
|
||||
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
* @defgroup netifapi NETIF API
|
||||
* @ingroup sequential_api
|
||||
* Thread-safe functions to be called from non-TCPIP threads
|
||||
*
|
||||
*
|
||||
* @defgroup netifapi_netif NETIF related
|
||||
* @ingroup netifapi
|
||||
* To be called from non-TCPIP threads
|
||||
* To be called from non-TCPIP threads
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -42,10 +42,13 @@
|
||||
|
||||
#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/etharp.h"
|
||||
#include "lwip/netifapi.h"
|
||||
#include "lwip/memp.h"
|
||||
#include "lwip/priv/tcpip_priv.h"
|
||||
|
||||
#include <string.h> /* strncpy */
|
||||
|
||||
#define NETIFAPI_VAR_REF(name) API_VAR_REF(name)
|
||||
#define NETIFAPI_VAR_DECLARE(name) API_VAR_DECLARE(struct netifapi_msg, name)
|
||||
#define NETIFAPI_VAR_ALLOC(name) API_VAR_ALLOC(struct netifapi_msg, MEMP_NETIFAPI_MSG, name, ERR_MEM)
|
||||
@@ -57,10 +60,10 @@
|
||||
static err_t
|
||||
netifapi_do_netif_add(struct tcpip_api_call_data *m)
|
||||
{
|
||||
/* cast through void* to silence alignment warnings.
|
||||
/* cast through void* to silence alignment warnings.
|
||||
* We know it works because the structs have been instantiated as struct netifapi_msg */
|
||||
struct netifapi_msg *msg = (struct netifapi_msg*)(void*)m;
|
||||
|
||||
struct netifapi_msg *msg = (struct netifapi_msg *)(void *)m;
|
||||
|
||||
if (!netif_add( msg->netif,
|
||||
#if LWIP_IPV4
|
||||
API_EXPR_REF(msg->msg.add.ipaddr),
|
||||
@@ -83,9 +86,9 @@ netifapi_do_netif_add(struct tcpip_api_call_data *m)
|
||||
static err_t
|
||||
netifapi_do_netif_set_addr(struct tcpip_api_call_data *m)
|
||||
{
|
||||
/* cast through void* to silence alignment warnings.
|
||||
/* cast through void* to silence alignment warnings.
|
||||
* We know it works because the structs have been instantiated as struct netifapi_msg */
|
||||
struct netifapi_msg *msg = (struct netifapi_msg*)(void*)m;
|
||||
struct netifapi_msg *msg = (struct netifapi_msg *)(void *)m;
|
||||
|
||||
netif_set_addr( msg->netif,
|
||||
API_EXPR_REF(msg->msg.add.ipaddr),
|
||||
@@ -95,6 +98,37 @@ netifapi_do_netif_set_addr(struct tcpip_api_call_data *m)
|
||||
}
|
||||
#endif /* LWIP_IPV4 */
|
||||
|
||||
/**
|
||||
* Call netif_name_to_index() inside the tcpip_thread context.
|
||||
*/
|
||||
static err_t
|
||||
netifapi_do_name_to_index(struct tcpip_api_call_data *m)
|
||||
{
|
||||
/* cast through void* to silence alignment warnings.
|
||||
* We know it works because the structs have been instantiated as struct netifapi_msg */
|
||||
struct netifapi_msg *msg = (struct netifapi_msg *)(void *)m;
|
||||
|
||||
msg->msg.ifs.index = netif_name_to_index(msg->msg.ifs.name);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call netif_index_to_name() inside the tcpip_thread context.
|
||||
*/
|
||||
static err_t
|
||||
netifapi_do_index_to_name(struct tcpip_api_call_data *m)
|
||||
{
|
||||
/* cast through void* to silence alignment warnings.
|
||||
* We know it works because the structs have been instantiated as struct netifapi_msg */
|
||||
struct netifapi_msg *msg = (struct netifapi_msg *)(void *)m;
|
||||
|
||||
if (!netif_index_to_name(msg->msg.ifs.index, msg->msg.ifs.name)) {
|
||||
/* return failure via empty name */
|
||||
msg->msg.ifs.name[0] = '\0';
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) inside the
|
||||
* tcpip_thread context.
|
||||
@@ -102,9 +136,9 @@ netifapi_do_netif_set_addr(struct tcpip_api_call_data *m)
|
||||
static err_t
|
||||
netifapi_do_netif_common(struct tcpip_api_call_data *m)
|
||||
{
|
||||
/* cast through void* to silence alignment warnings.
|
||||
/* cast through void* to silence alignment warnings.
|
||||
* We know it works because the structs have been instantiated as struct netifapi_msg */
|
||||
struct netifapi_msg *msg = (struct netifapi_msg*)(void*)m;
|
||||
struct netifapi_msg *msg = (struct netifapi_msg *)(void *)m;
|
||||
|
||||
if (msg->msg.common.errtfunc != NULL) {
|
||||
return msg->msg.common.errtfunc(msg->netif);
|
||||
@@ -114,6 +148,69 @@ netifapi_do_netif_common(struct tcpip_api_call_data *m)
|
||||
}
|
||||
}
|
||||
|
||||
#if LWIP_ARP && LWIP_IPV4
|
||||
/**
|
||||
* @ingroup netifapi_arp
|
||||
* Add or update an entry in the ARP cache.
|
||||
* For an update, ipaddr is used to find the cache entry.
|
||||
*
|
||||
* @param ipaddr IPv4 address of cache entry
|
||||
* @param ethaddr hardware address mapped to ipaddr
|
||||
* @param type type of ARP cache entry
|
||||
* @return ERR_OK: entry added/updated, else error from err_t
|
||||
*/
|
||||
err_t
|
||||
netifapi_arp_add(const ip4_addr_t *ipaddr, struct eth_addr *ethaddr, enum netifapi_arp_entry type)
|
||||
{
|
||||
err_t err;
|
||||
|
||||
/* We only support permanent entries currently */
|
||||
LWIP_UNUSED_ARG(type);
|
||||
|
||||
#if ETHARP_SUPPORT_STATIC_ENTRIES && LWIP_TCPIP_CORE_LOCKING
|
||||
LOCK_TCPIP_CORE();
|
||||
err = etharp_add_static_entry(ipaddr, ethaddr);
|
||||
UNLOCK_TCPIP_CORE();
|
||||
#else
|
||||
/* @todo add new vars to struct netifapi_msg and create a 'do' func */
|
||||
LWIP_UNUSED_ARG(ipaddr);
|
||||
LWIP_UNUSED_ARG(ethaddr);
|
||||
err = ERR_VAL;
|
||||
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES && LWIP_TCPIP_CORE_LOCKING */
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup netifapi_arp
|
||||
* Remove an entry in the ARP cache identified by ipaddr
|
||||
*
|
||||
* @param ipaddr IPv4 address of cache entry
|
||||
* @param type type of ARP cache entry
|
||||
* @return ERR_OK: entry removed, else error from err_t
|
||||
*/
|
||||
err_t
|
||||
netifapi_arp_remove(const ip4_addr_t *ipaddr, enum netifapi_arp_entry type)
|
||||
{
|
||||
err_t err;
|
||||
|
||||
/* We only support permanent entries currently */
|
||||
LWIP_UNUSED_ARG(type);
|
||||
|
||||
#if ETHARP_SUPPORT_STATIC_ENTRIES && LWIP_TCPIP_CORE_LOCKING
|
||||
LOCK_TCPIP_CORE();
|
||||
err = etharp_remove_static_entry(ipaddr);
|
||||
UNLOCK_TCPIP_CORE();
|
||||
#else
|
||||
/* @todo add new vars to struct netifapi_msg and create a 'do' func */
|
||||
LWIP_UNUSED_ARG(ipaddr);
|
||||
err = ERR_VAL;
|
||||
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES && LWIP_TCPIP_CORE_LOCKING */
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif /* LWIP_ARP && LWIP_IPV4 */
|
||||
|
||||
/**
|
||||
* @ingroup netifapi_netif
|
||||
* Call netif_add() in a thread-safe way by running that function inside the
|
||||
@@ -204,7 +301,7 @@ netifapi_netif_set_addr(struct netif *netif,
|
||||
*/
|
||||
err_t
|
||||
netifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc,
|
||||
netifapi_errt_fn errtfunc)
|
||||
netifapi_errt_fn errtfunc)
|
||||
{
|
||||
err_t err;
|
||||
NETIFAPI_VAR_DECLARE(msg);
|
||||
@@ -218,4 +315,66 @@ netifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc,
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup netifapi_netif
|
||||
* Call netif_name_to_index() in a thread-safe way by running that function inside the
|
||||
* tcpip_thread context.
|
||||
*
|
||||
* @param name the interface name of the netif
|
||||
* @param idx output index of the found netif
|
||||
*/
|
||||
err_t
|
||||
netifapi_netif_name_to_index(const char *name, u8_t *idx)
|
||||
{
|
||||
err_t err;
|
||||
NETIFAPI_VAR_DECLARE(msg);
|
||||
NETIFAPI_VAR_ALLOC(msg);
|
||||
|
||||
*idx = 0;
|
||||
|
||||
#if LWIP_MPU_COMPATIBLE
|
||||
strncpy(NETIFAPI_VAR_REF(msg).msg.ifs.name, name, NETIF_NAMESIZE - 1);
|
||||
NETIFAPI_VAR_REF(msg).msg.ifs.name[NETIF_NAMESIZE - 1] = '\0';
|
||||
#else
|
||||
NETIFAPI_VAR_REF(msg).msg.ifs.name = LWIP_CONST_CAST(char *, name);
|
||||
#endif /* LWIP_MPU_COMPATIBLE */
|
||||
err = tcpip_api_call(netifapi_do_name_to_index, &API_VAR_REF(msg).call);
|
||||
if (!err) {
|
||||
*idx = NETIFAPI_VAR_REF(msg).msg.ifs.index;
|
||||
}
|
||||
NETIFAPI_VAR_FREE(msg);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup netifapi_netif
|
||||
* Call netif_index_to_name() in a thread-safe way by running that function inside the
|
||||
* tcpip_thread context.
|
||||
*
|
||||
* @param idx the interface index of the netif
|
||||
* @param name output name of the found netif, empty '\0' string if netif not found.
|
||||
* name should be of at least NETIF_NAMESIZE bytes
|
||||
*/
|
||||
err_t
|
||||
netifapi_netif_index_to_name(u8_t idx, char *name)
|
||||
{
|
||||
err_t err;
|
||||
NETIFAPI_VAR_DECLARE(msg);
|
||||
NETIFAPI_VAR_ALLOC(msg);
|
||||
|
||||
NETIFAPI_VAR_REF(msg).msg.ifs.index = idx;
|
||||
#if !LWIP_MPU_COMPATIBLE
|
||||
NETIFAPI_VAR_REF(msg).msg.ifs.name = name;
|
||||
#endif /* LWIP_MPU_COMPATIBLE */
|
||||
err = tcpip_api_call(netifapi_do_index_to_name, &API_VAR_REF(msg).call);
|
||||
#if LWIP_MPU_COMPATIBLE
|
||||
if (!err) {
|
||||
strncpy(name, NETIFAPI_VAR_REF(msg).msg.ifs.name, NETIF_NAMESIZE - 1);
|
||||
name[NETIF_NAMESIZE - 1] = '\0';
|
||||
}
|
||||
#endif /* LWIP_MPU_COMPATIBLE */
|
||||
NETIFAPI_VAR_FREE(msg);
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif /* LWIP_NETIF_API */
|
||||
|
||||
3839
src/api/sockets.c
3839
src/api/sockets.c
File diff suppressed because it is too large
Load Diff
254
src/api/tcpip.c
254
src/api/tcpip.c
@@ -50,6 +50,8 @@
|
||||
#include "lwip/etharp.h"
|
||||
#include "netif/ethernet.h"
|
||||
|
||||
#include "osdep_service.h"
|
||||
|
||||
#define TCPIP_MSG_VAR_REF(name) API_VAR_REF(name)
|
||||
#define TCPIP_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct tcpip_msg, name)
|
||||
#define TCPIP_MSG_VAR_ALLOC(name) API_VAR_ALLOC(struct tcpip_msg, MEMP_TCPIP_MSG_API, name, ERR_MEM)
|
||||
@@ -58,20 +60,60 @@
|
||||
/* global variables */
|
||||
static tcpip_init_done_fn tcpip_init_done;
|
||||
static void *tcpip_init_done_arg;
|
||||
static sys_mbox_t mbox;
|
||||
static sys_mbox_t tcpip_mbox;
|
||||
|
||||
#if LWIP_TCPIP_CORE_LOCKING
|
||||
/** The global semaphore to lock the stack. */
|
||||
sys_mutex_t lock_tcpip_core;
|
||||
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
||||
|
||||
#if LWIP_TIMERS
|
||||
/* wait for a message, timeouts are processed while waiting */
|
||||
#define TCPIP_MBOX_FETCH(mbox, msg) sys_timeouts_mbox_fetch(mbox, msg)
|
||||
#else /* LWIP_TIMERS */
|
||||
static void tcpip_thread_handle_msg(struct tcpip_msg *msg);
|
||||
|
||||
#if !LWIP_TIMERS
|
||||
/* wait for a message with timers disabled (e.g. pass a timer-check trigger into tcpip_thread) */
|
||||
#define TCPIP_MBOX_FETCH(mbox, msg) sys_mbox_fetch(mbox, msg)
|
||||
#endif /* LWIP_TIMERS */
|
||||
#else /* !LWIP_TIMERS */
|
||||
/* wait for a message, timeouts are processed while waiting */
|
||||
#define TCPIP_MBOX_FETCH(mbox, msg) tcpip_timeouts_mbox_fetch(mbox, msg)
|
||||
/**
|
||||
* Wait (forever) for a message to arrive in an mbox.
|
||||
* While waiting, timeouts are processed.
|
||||
*
|
||||
* @param mbox the mbox to fetch the message from
|
||||
* @param msg the place to store the message
|
||||
*/
|
||||
static void
|
||||
tcpip_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg)
|
||||
{
|
||||
u32_t sleeptime, res;
|
||||
|
||||
again:
|
||||
LWIP_ASSERT_CORE_LOCKED();
|
||||
|
||||
sleeptime = sys_timeouts_sleeptime();
|
||||
if (sleeptime == SYS_TIMEOUTS_SLEEPTIME_INFINITE) {
|
||||
UNLOCK_TCPIP_CORE();
|
||||
sys_arch_mbox_fetch(mbox, msg, 0);
|
||||
LOCK_TCPIP_CORE();
|
||||
return;
|
||||
} else if (sleeptime == 0) {
|
||||
sys_check_timeouts();
|
||||
/* We try again to fetch a message from the mbox. */
|
||||
goto again;
|
||||
}
|
||||
|
||||
UNLOCK_TCPIP_CORE();
|
||||
res = sys_arch_mbox_fetch(mbox, msg, sleeptime);
|
||||
LOCK_TCPIP_CORE();
|
||||
if (res == SYS_ARCH_TIMEOUT) {
|
||||
/* If a SYS_ARCH_TIMEOUT value is returned, a timeout occurred
|
||||
before a message could be fetched. */
|
||||
sys_check_timeouts();
|
||||
/* We try again to fetch a message from the mbox. */
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
#endif /* !LWIP_TIMERS */
|
||||
|
||||
/**
|
||||
* The main lwIP thread. This thread has exclusive access to lwIP core functions
|
||||
@@ -89,23 +131,33 @@ tcpip_thread(void *arg)
|
||||
struct tcpip_msg *msg;
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
|
||||
LWIP_MARK_TCPIP_THREAD();
|
||||
|
||||
LOCK_TCPIP_CORE();
|
||||
if (tcpip_init_done != NULL) {
|
||||
tcpip_init_done(tcpip_init_done_arg);
|
||||
}
|
||||
|
||||
LOCK_TCPIP_CORE();
|
||||
while (1) { /* MAIN Loop */
|
||||
UNLOCK_TCPIP_CORE();
|
||||
LWIP_TCPIP_THREAD_ALIVE();
|
||||
/* wait for a message, timeouts are processed while waiting */
|
||||
TCPIP_MBOX_FETCH(&mbox, (void **)&msg);
|
||||
LOCK_TCPIP_CORE();
|
||||
TCPIP_MBOX_FETCH(&tcpip_mbox, (void **)&msg);
|
||||
if (msg == NULL) {
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: NULL\n"));
|
||||
LWIP_ASSERT("tcpip_thread: invalid message", 0);
|
||||
continue;
|
||||
}
|
||||
switch (msg->type) {
|
||||
tcpip_thread_handle_msg(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle a single tcpip_msg
|
||||
* This is in its own function for access by tests only.
|
||||
*/
|
||||
static void
|
||||
tcpip_thread_handle_msg(struct tcpip_msg *msg)
|
||||
{
|
||||
switch (msg->type) {
|
||||
#if !LWIP_TCPIP_CORE_LOCKING
|
||||
case TCPIP_MSG_API:
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));
|
||||
@@ -121,7 +173,9 @@ tcpip_thread(void *arg)
|
||||
#if !LWIP_TCPIP_CORE_LOCKING_INPUT
|
||||
case TCPIP_MSG_INPKT:
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg));
|
||||
msg->msg.inp.input_fn(msg->msg.inp.p, msg->msg.inp.netif);
|
||||
if (msg->msg.inp.input_fn(msg->msg.inp.p, msg->msg.inp.netif) != ERR_OK) {
|
||||
pbuf_free(msg->msg.inp.p);
|
||||
}
|
||||
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
|
||||
break;
|
||||
#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */
|
||||
@@ -154,10 +208,29 @@ tcpip_thread(void *arg)
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type));
|
||||
LWIP_ASSERT("tcpip_thread: invalid message", 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TCPIP_THREAD_TEST
|
||||
/** Work on queued items in single-threaded test mode */
|
||||
int
|
||||
tcpip_thread_poll_one(void)
|
||||
{
|
||||
int ret = 0;
|
||||
struct tcpip_msg *msg;
|
||||
|
||||
if (sys_arch_mbox_tryfetch(&tcpip_mbox, (void **)&msg) != SYS_MBOX_EMPTY) {
|
||||
LOCK_TCPIP_CORE();
|
||||
if (msg != NULL) {
|
||||
tcpip_thread_handle_msg(msg);
|
||||
ret = 1;
|
||||
}
|
||||
UNLOCK_TCPIP_CORE();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Pass a received packet to tcpip_thread for input processing
|
||||
*
|
||||
@@ -178,7 +251,7 @@ tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn)
|
||||
#else /* LWIP_TCPIP_CORE_LOCKING_INPUT */
|
||||
struct tcpip_msg *msg;
|
||||
|
||||
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox));
|
||||
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
|
||||
|
||||
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT);
|
||||
if (msg == NULL) {
|
||||
@@ -189,7 +262,7 @@ tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn)
|
||||
msg->msg.inp.p = p;
|
||||
msg->msg.inp.netif = inp;
|
||||
msg->msg.inp.input_fn = input_fn;
|
||||
if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
|
||||
if (sys_mbox_trypost(&tcpip_mbox, msg) != ERR_OK) {
|
||||
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
|
||||
return ERR_MEM;
|
||||
}
|
||||
@@ -216,26 +289,30 @@ tcpip_input(struct pbuf *p, struct netif *inp)
|
||||
return tcpip_inpkt(p, inp, ethernet_input);
|
||||
} else
|
||||
#endif /* LWIP_ETHERNET */
|
||||
return tcpip_inpkt(p, inp, ip_input);
|
||||
return tcpip_inpkt(p, inp, ip_input);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup lwip_os
|
||||
* Call a specific function in the thread context of
|
||||
* tcpip_thread for easy access synchronization.
|
||||
* A function called in that way may access lwIP core code
|
||||
* without fearing concurrent access.
|
||||
* Blocks until the request is posted.
|
||||
* Must not be called from interrupt context!
|
||||
*
|
||||
* @param function the function to call
|
||||
* @param ctx parameter passed to f
|
||||
* @param block 1 to block until the request is posted, 0 to non-blocking mode
|
||||
* @return ERR_OK if the function was called, another err_t if not
|
||||
*
|
||||
* @see tcpip_try_callback
|
||||
*/
|
||||
err_t
|
||||
tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block)
|
||||
tcpip_callback(tcpip_callback_fn function, void *ctx)
|
||||
{
|
||||
struct tcpip_msg *msg;
|
||||
|
||||
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox));
|
||||
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
|
||||
|
||||
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
|
||||
if (msg == NULL) {
|
||||
@@ -245,13 +322,46 @@ tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block)
|
||||
msg->type = TCPIP_MSG_CALLBACK;
|
||||
msg->msg.cb.function = function;
|
||||
msg->msg.cb.ctx = ctx;
|
||||
if (block) {
|
||||
sys_mbox_post(&mbox, msg);
|
||||
} else {
|
||||
if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
|
||||
memp_free(MEMP_TCPIP_MSG_API, msg);
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
sys_mbox_post(&tcpip_mbox, msg);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup lwip_os
|
||||
* Call a specific function in the thread context of
|
||||
* tcpip_thread for easy access synchronization.
|
||||
* A function called in that way may access lwIP core code
|
||||
* without fearing concurrent access.
|
||||
* Does NOT block when the request cannot be posted because the
|
||||
* tcpip_mbox is full, but returns ERR_MEM instead.
|
||||
* Can be called from interrupt context.
|
||||
*
|
||||
* @param function the function to call
|
||||
* @param ctx parameter passed to f
|
||||
* @return ERR_OK if the function was called, another err_t if not
|
||||
*
|
||||
* @see tcpip_callback
|
||||
*/
|
||||
err_t
|
||||
tcpip_try_callback(tcpip_callback_fn function, void *ctx)
|
||||
{
|
||||
struct tcpip_msg *msg;
|
||||
|
||||
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
|
||||
|
||||
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
|
||||
if (msg == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
msg->type = TCPIP_MSG_CALLBACK;
|
||||
msg->msg.cb.function = function;
|
||||
msg->msg.cb.ctx = ctx;
|
||||
|
||||
if (sys_mbox_trypost(&tcpip_mbox, msg) != ERR_OK) {
|
||||
memp_free(MEMP_TCPIP_MSG_API, msg);
|
||||
return ERR_MEM;
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
@@ -270,7 +380,7 @@ tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
|
||||
{
|
||||
struct tcpip_msg *msg;
|
||||
|
||||
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox));
|
||||
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
|
||||
|
||||
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
|
||||
if (msg == NULL) {
|
||||
@@ -281,7 +391,7 @@ tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
|
||||
msg->msg.tmo.msecs = msecs;
|
||||
msg->msg.tmo.h = h;
|
||||
msg->msg.tmo.arg = arg;
|
||||
sys_mbox_post(&mbox, msg);
|
||||
sys_mbox_post(&tcpip_mbox, msg);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
@@ -297,7 +407,7 @@ tcpip_untimeout(sys_timeout_handler h, void *arg)
|
||||
{
|
||||
struct tcpip_msg *msg;
|
||||
|
||||
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox));
|
||||
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
|
||||
|
||||
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
|
||||
if (msg == NULL) {
|
||||
@@ -307,7 +417,7 @@ tcpip_untimeout(sys_timeout_handler h, void *arg)
|
||||
msg->type = TCPIP_MSG_UNTIMEOUT;
|
||||
msg->msg.tmo.h = h;
|
||||
msg->msg.tmo.arg = arg;
|
||||
sys_mbox_post(&mbox, msg);
|
||||
sys_mbox_post(&tcpip_mbox, msg);
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */
|
||||
@@ -326,7 +436,7 @@ tcpip_untimeout(sys_timeout_handler h, void *arg)
|
||||
* @return ERR_OK if the function was called, another err_t if not
|
||||
*/
|
||||
err_t
|
||||
tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t* sem)
|
||||
tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t *sem)
|
||||
{
|
||||
#if LWIP_TCPIP_CORE_LOCKING
|
||||
LWIP_UNUSED_ARG(sem);
|
||||
@@ -338,14 +448,19 @@ tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t* sem)
|
||||
TCPIP_MSG_VAR_DECLARE(msg);
|
||||
|
||||
LWIP_ASSERT("semaphore not initialized", sys_sem_valid(sem));
|
||||
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox));
|
||||
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
|
||||
|
||||
UBaseType_t prio = uxTaskPriorityGet(NULL); // add to prevent switch to tcpip thread between mbox post and sem wait
|
||||
if((TCPIP_THREAD_PRIO + 1) > prio)
|
||||
vTaskPrioritySet(NULL, TCPIP_THREAD_PRIO + 1); // set priority higher than tcpip thread
|
||||
|
||||
TCPIP_MSG_VAR_ALLOC(msg);
|
||||
TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API;
|
||||
TCPIP_MSG_VAR_REF(msg).msg.api_msg.function = fn;
|
||||
TCPIP_MSG_VAR_REF(msg).msg.api_msg.msg = apimsg;
|
||||
sys_mbox_post(&mbox, &TCPIP_MSG_VAR_REF(msg));
|
||||
sys_mbox_post(&tcpip_mbox, &TCPIP_MSG_VAR_REF(msg));
|
||||
sys_arch_sem_wait(sem, 0);
|
||||
vTaskPrioritySet(NULL, prio); // restore to original priority
|
||||
TCPIP_MSG_VAR_FREE(msg);
|
||||
return ERR_OK;
|
||||
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
||||
@@ -354,7 +469,7 @@ tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t* sem)
|
||||
/**
|
||||
* Synchronously calls function in TCPIP thread and waits for its completion.
|
||||
* It is recommended to use LWIP_TCPIP_CORE_LOCKING (preferred) or
|
||||
* LWIP_NETCONN_SEM_PER_THREAD.
|
||||
* LWIP_NETCONN_SEM_PER_THREAD.
|
||||
* If not, a semaphore is created and destroyed on every call which is usually
|
||||
* an expensive/slow operation.
|
||||
* @param fn Function to call
|
||||
@@ -380,7 +495,7 @@ tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call)
|
||||
}
|
||||
#endif /* LWIP_NETCONN_SEM_PER_THREAD */
|
||||
|
||||
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox));
|
||||
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
|
||||
|
||||
TCPIP_MSG_VAR_ALLOC(msg);
|
||||
TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API_CALL;
|
||||
@@ -391,7 +506,7 @@ tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call)
|
||||
#else /* LWIP_NETCONN_SEM_PER_THREAD */
|
||||
TCPIP_MSG_VAR_REF(msg).msg.api_call.sem = &call->sem;
|
||||
#endif /* LWIP_NETCONN_SEM_PER_THREAD */
|
||||
sys_mbox_post(&mbox, &TCPIP_MSG_VAR_REF(msg));
|
||||
sys_mbox_post(&tcpip_mbox, &TCPIP_MSG_VAR_REF(msg));
|
||||
sys_arch_sem_wait(TCPIP_MSG_VAR_REF(msg).msg.api_call.sem, 0);
|
||||
TCPIP_MSG_VAR_FREE(msg);
|
||||
|
||||
@@ -404,14 +519,22 @@ tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call)
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup lwip_os
|
||||
* Allocate a structure for a static callback message and initialize it.
|
||||
* This is intended to be used to send "static" messages from interrupt context.
|
||||
*
|
||||
* The message has a special type such that lwIP never frees it.
|
||||
* This is intended to be used to send "static" messages from interrupt context,
|
||||
* e.g. the message is allocated once and posted several times from an IRQ
|
||||
* using tcpip_callbackmsg_trycallback().
|
||||
* Example usage: Trigger execution of an ethernet IRQ DPC routine in lwIP thread context.
|
||||
*
|
||||
* @param function the function to call
|
||||
* @param ctx parameter passed to function
|
||||
* @return a struct pointer to pass to tcpip_trycallback().
|
||||
* @return a struct pointer to pass to tcpip_callbackmsg_trycallback().
|
||||
*
|
||||
* @see tcpip_callbackmsg_trycallback()
|
||||
* @see tcpip_callbackmsg_delete()
|
||||
*/
|
||||
struct tcpip_callback_msg*
|
||||
struct tcpip_callback_msg *
|
||||
tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx)
|
||||
{
|
||||
struct tcpip_msg *msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
|
||||
@@ -421,32 +544,56 @@ tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx)
|
||||
msg->type = TCPIP_MSG_CALLBACK_STATIC;
|
||||
msg->msg.cb.function = function;
|
||||
msg->msg.cb.ctx = ctx;
|
||||
return (struct tcpip_callback_msg*)msg;
|
||||
return (struct tcpip_callback_msg *)msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup lwip_os
|
||||
* Free a callback message allocated by tcpip_callbackmsg_new().
|
||||
*
|
||||
* @param msg the message to free
|
||||
*
|
||||
* @see tcpip_callbackmsg_new()
|
||||
*/
|
||||
void
|
||||
tcpip_callbackmsg_delete(struct tcpip_callback_msg* msg)
|
||||
tcpip_callbackmsg_delete(struct tcpip_callback_msg *msg)
|
||||
{
|
||||
memp_free(MEMP_TCPIP_MSG_API, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to post a callback-message to the tcpip_thread mbox
|
||||
* This is intended to be used to send "static" messages from interrupt context.
|
||||
* @ingroup lwip_os
|
||||
* Try to post a callback-message to the tcpip_thread tcpip_mbox.
|
||||
*
|
||||
* @param msg pointer to the message to post
|
||||
* @return sys_mbox_trypost() return code
|
||||
*
|
||||
* @see tcpip_callbackmsg_new()
|
||||
*/
|
||||
err_t
|
||||
tcpip_trycallback(struct tcpip_callback_msg* msg)
|
||||
tcpip_callbackmsg_trycallback(struct tcpip_callback_msg *msg)
|
||||
{
|
||||
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox));
|
||||
return sys_mbox_trypost(&mbox, msg);
|
||||
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
|
||||
return sys_mbox_trypost(&tcpip_mbox, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup lwip_os
|
||||
* Try to post a callback-message to the tcpip_thread mbox.
|
||||
* Same as @ref tcpip_callbackmsg_trycallback but calls sys_mbox_trypost_fromisr(),
|
||||
* mainly to help FreeRTOS, where calls differ between task level and ISR level.
|
||||
*
|
||||
* @param msg pointer to the message to post
|
||||
* @return sys_mbox_trypost_fromisr() return code (without change, so this
|
||||
* knowledge can be used to e.g. propagate "bool needs_scheduling")
|
||||
*
|
||||
* @see tcpip_callbackmsg_new()
|
||||
*/
|
||||
err_t
|
||||
tcpip_callbackmsg_trycallback_fromisr(struct tcpip_callback_msg *msg)
|
||||
{
|
||||
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
|
||||
return sys_mbox_trypost_fromisr(&tcpip_mbox, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -465,7 +612,7 @@ tcpip_init(tcpip_init_done_fn initfunc, void *arg)
|
||||
|
||||
tcpip_init_done = initfunc;
|
||||
tcpip_init_done_arg = arg;
|
||||
if (sys_mbox_new(&mbox, TCPIP_MBOX_SIZE) != ERR_OK) {
|
||||
if (sys_mbox_new(&tcpip_mbox, TCPIP_MBOX_SIZE) != ERR_OK) {
|
||||
LWIP_ASSERT("failed to create tcpip_thread mbox", 0);
|
||||
}
|
||||
#if LWIP_TCPIP_CORE_LOCKING
|
||||
@@ -473,8 +620,11 @@ tcpip_init(tcpip_init_done_fn initfunc, void *arg)
|
||||
LWIP_ASSERT("failed to create lock_tcpip_core", 0);
|
||||
}
|
||||
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
||||
|
||||
sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);
|
||||
#if CONFIG_USE_TCM_HEAP
|
||||
sys_thread_new_tcm(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);
|
||||
#else
|
||||
sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -499,7 +649,7 @@ pbuf_free_int(void *p)
|
||||
err_t
|
||||
pbuf_free_callback(struct pbuf *p)
|
||||
{
|
||||
return tcpip_callback_with_block(pbuf_free_int, p, 0);
|
||||
return tcpip_try_callback(pbuf_free_int, p);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -512,7 +662,7 @@ pbuf_free_callback(struct pbuf *p)
|
||||
err_t
|
||||
mem_free_callback(void *m)
|
||||
{
|
||||
return tcpip_callback_with_block(mem_free, m, 0);
|
||||
return tcpip_try_callback(mem_free, m);
|
||||
}
|
||||
|
||||
#endif /* !NO_SYS */
|
||||
|
||||
1270
src/apps/altcp_tls/altcp_tls_mbedtls.c
Normal file
1270
src/apps/altcp_tls/altcp_tls_mbedtls.c
Normal file
File diff suppressed because it is too large
Load Diff
210
src/apps/altcp_tls/altcp_tls_mbedtls_mem.c
Normal file
210
src/apps/altcp_tls/altcp_tls_mbedtls_mem.c
Normal file
@@ -0,0 +1,210 @@
|
||||
/**
|
||||
* @file
|
||||
* Application layered TCP connection API (to be used from TCPIP thread)
|
||||
*
|
||||
* This file contains memory management functions for a TLS layer using mbedTLS.
|
||||
*
|
||||
* ATTENTION: For production usage, you might want to override this file with
|
||||
* your own implementation since this implementation simply uses the
|
||||
* lwIP heap without caring for fragmentation or leaving heap for
|
||||
* other parts of lwIP!
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Simon Goldschmidt
|
||||
* 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. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Simon Goldschmidt <goldsimon@gmx.de>
|
||||
*
|
||||
* Missing things / @todo:
|
||||
* - RX data is acknowledged after receiving (tcp_recved is called when enqueueing
|
||||
* the pbuf for mbedTLS receive, not when processed by mbedTLS or the inner
|
||||
* connection; altcp_recved() from inner connection does nothing)
|
||||
* - TX data is marked as 'sent' (i.e. acknowledged; sent callback is called) right
|
||||
* after enqueueing for transmission, not when actually ACKed be the remote host.
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/apps/altcp_tls_mbedtls_opts.h"
|
||||
|
||||
#if LWIP_ALTCP_TLS && LWIP_ALTCP_TLS_MBEDTLS
|
||||
|
||||
#include "altcp_tls_mbedtls_mem.h"
|
||||
#include "altcp_tls_mbedtls_structs.h"
|
||||
#include "lwip/mem.h"
|
||||
|
||||
#include "mbedtls/platform.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifndef ALTCP_MBEDTLS_MEM_DEBUG
|
||||
#define ALTCP_MBEDTLS_MEM_DEBUG LWIP_DBG_OFF
|
||||
#endif
|
||||
|
||||
#if defined(MBEDTLS_PLATFORM_MEMORY) && \
|
||||
(!defined(MBEDTLS_PLATFORM_FREE_MACRO) || \
|
||||
defined(MBEDTLS_PLATFORM_CALLOC_MACRO))
|
||||
#define ALTCP_MBEDTLS_PLATFORM_ALLOC 1
|
||||
#else
|
||||
#define ALTCP_MBEDTLS_PLATFORM_ALLOC 0
|
||||
#endif
|
||||
|
||||
#if ALTCP_MBEDTLS_PLATFORM_ALLOC
|
||||
|
||||
#ifndef ALTCP_MBEDTLS_PLATFORM_ALLOC_STATS
|
||||
#define ALTCP_MBEDTLS_PLATFORM_ALLOC_STATS 0
|
||||
#endif
|
||||
|
||||
/* This is an example/debug implementation of alloc/free functions only */
|
||||
typedef struct altcp_mbedtls_malloc_helper_s {
|
||||
size_t c;
|
||||
size_t len;
|
||||
} altcp_mbedtls_malloc_helper_t;
|
||||
|
||||
#if ALTCP_MBEDTLS_PLATFORM_ALLOC_STATS
|
||||
typedef struct altcp_mbedtls_malloc_stats_s {
|
||||
size_t allocedBytes;
|
||||
size_t allocCnt;
|
||||
size_t maxBytes;
|
||||
size_t totalBytes;
|
||||
} altcp_mbedtls_malloc_stats_t;
|
||||
altcp_mbedtls_malloc_stats_t altcp_mbedtls_malloc_stats;
|
||||
volatile int altcp_mbedtls_malloc_clear_stats;
|
||||
#endif
|
||||
|
||||
static void *
|
||||
tls_malloc(size_t c, size_t len)
|
||||
{
|
||||
altcp_mbedtls_malloc_helper_t *hlpr;
|
||||
void *ret;
|
||||
size_t alloc_size;
|
||||
#if ALTCP_MBEDTLS_PLATFORM_ALLOC_STATS
|
||||
if (altcp_mbedtls_malloc_clear_stats) {
|
||||
altcp_mbedtls_malloc_clear_stats = 0;
|
||||
memset(&altcp_mbedtls_malloc_stats, 0, sizeof(altcp_mbedtls_malloc_stats));
|
||||
}
|
||||
#endif
|
||||
alloc_size = sizeof(altcp_mbedtls_malloc_helper_t) + (c * len);
|
||||
/* check for maximum allocation size, mainly to prevent mem_size_t overflow */
|
||||
if (alloc_size > MEM_SIZE) {
|
||||
LWIP_DEBUGF(ALTCP_MBEDTLS_MEM_DEBUG, ("mbedtls allocation too big: %c * %d bytes vs MEM_SIZE=%d",
|
||||
(int)c, (int)len, (int)MEM_SIZE));
|
||||
return NULL;
|
||||
}
|
||||
hlpr = (altcp_mbedtls_malloc_helper_t *)mem_malloc((mem_size_t)alloc_size);
|
||||
if (hlpr == NULL) {
|
||||
LWIP_DEBUGF(ALTCP_MBEDTLS_MEM_DEBUG, ("mbedtls alloc callback failed for %c * %d bytes", (int)c, (int)len));
|
||||
return NULL;
|
||||
}
|
||||
#if ALTCP_MBEDTLS_PLATFORM_ALLOC_STATS
|
||||
altcp_mbedtls_malloc_stats.allocCnt++;
|
||||
altcp_mbedtls_malloc_stats.allocedBytes += c * len;
|
||||
if (altcp_mbedtls_malloc_stats.allocedBytes > altcp_mbedtls_malloc_stats.maxBytes) {
|
||||
altcp_mbedtls_malloc_stats.maxBytes = altcp_mbedtls_malloc_stats.allocedBytes;
|
||||
}
|
||||
altcp_mbedtls_malloc_stats.totalBytes += c * len;
|
||||
#endif
|
||||
hlpr->c = c;
|
||||
hlpr->len = len;
|
||||
ret = hlpr + 1;
|
||||
/* zeroing the allocated chunk is required by mbedTLS! */
|
||||
memset(ret, 0, c * len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
tls_free(void *ptr)
|
||||
{
|
||||
altcp_mbedtls_malloc_helper_t *hlpr;
|
||||
if (ptr == NULL) {
|
||||
/* this obviously happened in mbedtls... */
|
||||
return;
|
||||
}
|
||||
hlpr = ((altcp_mbedtls_malloc_helper_t *)ptr) - 1;
|
||||
#if ALTCP_MBEDTLS_PLATFORM_ALLOC_STATS
|
||||
if (!altcp_mbedtls_malloc_clear_stats) {
|
||||
altcp_mbedtls_malloc_stats.allocedBytes -= hlpr->c * hlpr->len;
|
||||
}
|
||||
#endif
|
||||
mem_free(hlpr);
|
||||
}
|
||||
#endif /* ALTCP_MBEDTLS_PLATFORM_ALLOC*/
|
||||
|
||||
void
|
||||
altcp_mbedtls_mem_init(void)
|
||||
{
|
||||
/* not much to do here when using the heap */
|
||||
|
||||
#if ALTCP_MBEDTLS_PLATFORM_ALLOC
|
||||
/* set mbedtls allocation methods */
|
||||
mbedtls_platform_set_calloc_free(&tls_malloc, &tls_free);
|
||||
#endif
|
||||
}
|
||||
|
||||
altcp_mbedtls_state_t *
|
||||
altcp_mbedtls_alloc(void *conf)
|
||||
{
|
||||
altcp_mbedtls_state_t *ret = (altcp_mbedtls_state_t *)mem_calloc(1, sizeof(altcp_mbedtls_state_t));
|
||||
if (ret != NULL) {
|
||||
ret->conf = conf;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
altcp_mbedtls_free(void *conf, altcp_mbedtls_state_t *state)
|
||||
{
|
||||
LWIP_UNUSED_ARG(conf);
|
||||
LWIP_ASSERT("state != NULL", state != NULL);
|
||||
mem_free(state);
|
||||
}
|
||||
|
||||
void *
|
||||
altcp_mbedtls_alloc_config(size_t size)
|
||||
{
|
||||
void *ret;
|
||||
size_t checked_size = (mem_size_t)size;
|
||||
if (size != checked_size) {
|
||||
/* allocation too big (mem_size_t overflow) */
|
||||
return NULL;
|
||||
}
|
||||
ret = (altcp_mbedtls_state_t *)mem_calloc(1, (mem_size_t)size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
altcp_mbedtls_free_config(void *item)
|
||||
{
|
||||
LWIP_ASSERT("item != NULL", item != NULL);
|
||||
mem_free(item);
|
||||
}
|
||||
|
||||
#endif /* LWIP_ALTCP_TLS && LWIP_ALTCP_TLS_MBEDTLS */
|
||||
#endif /* LWIP_ALTCP */
|
||||
72
src/apps/altcp_tls/altcp_tls_mbedtls_mem.h
Normal file
72
src/apps/altcp_tls/altcp_tls_mbedtls_mem.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* @file
|
||||
* Application layered TCP/TLS connection API (to be used from TCPIP thread)
|
||||
*
|
||||
* This file contains memory management function prototypes for a TLS layer using mbedTLS.
|
||||
*
|
||||
* Memory management contains:
|
||||
* - allocating/freeing altcp_mbedtls_state_t
|
||||
* - allocating/freeing memory used in the mbedTLS library
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Simon Goldschmidt
|
||||
* 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. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Simon Goldschmidt <goldsimon@gmx.de>
|
||||
*
|
||||
*/
|
||||
#ifndef LWIP_HDR_ALTCP_MBEDTLS_MEM_H
|
||||
#define LWIP_HDR_ALTCP_MBEDTLS_MEM_H
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/apps/altcp_tls_mbedtls_opts.h"
|
||||
|
||||
#if LWIP_ALTCP_TLS && LWIP_ALTCP_TLS_MBEDTLS
|
||||
|
||||
#include "altcp_tls_mbedtls_structs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void altcp_mbedtls_mem_init(void);
|
||||
altcp_mbedtls_state_t *altcp_mbedtls_alloc(void *conf);
|
||||
void altcp_mbedtls_free(void *conf, altcp_mbedtls_state_t *state);
|
||||
void *altcp_mbedtls_alloc_config(size_t size);
|
||||
void altcp_mbedtls_free_config(void *item);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LWIP_ALTCP_TLS && LWIP_ALTCP_TLS_MBEDTLS */
|
||||
#endif /* LWIP_ALTCP */
|
||||
#endif /* LWIP_HDR_ALTCP_MBEDTLS_MEM_H */
|
||||
83
src/apps/altcp_tls/altcp_tls_mbedtls_structs.h
Normal file
83
src/apps/altcp_tls/altcp_tls_mbedtls_structs.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* @file
|
||||
* Application layered TCP/TLS connection API (to be used from TCPIP thread)
|
||||
*
|
||||
* This file contains structure definitions for a TLS layer using mbedTLS.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Simon Goldschmidt
|
||||
* 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. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Simon Goldschmidt <goldsimon@gmx.de>
|
||||
*
|
||||
*/
|
||||
#ifndef LWIP_HDR_ALTCP_MBEDTLS_STRUCTS_H
|
||||
#define LWIP_HDR_ALTCP_MBEDTLS_STRUCTS_H
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/apps/altcp_tls_mbedtls_opts.h"
|
||||
|
||||
#if LWIP_ALTCP_TLS && LWIP_ALTCP_TLS_MBEDTLS
|
||||
|
||||
#include "lwip/altcp.h"
|
||||
#include "lwip/pbuf.h"
|
||||
|
||||
#include "mbedtls/ssl.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE 0x01
|
||||
#define ALTCP_MBEDTLS_FLAGS_UPPER_CALLED 0x02
|
||||
#define ALTCP_MBEDTLS_FLAGS_RX_CLOSE_QUEUED 0x04
|
||||
#define ALTCP_MBEDTLS_FLAGS_RX_CLOSED 0x08
|
||||
#define ALTCP_MBEDTLS_FLAGS_APPLDATA_SENT 0x10
|
||||
|
||||
typedef struct altcp_mbedtls_state_s {
|
||||
void *conf;
|
||||
mbedtls_ssl_context ssl_context;
|
||||
/* chain of rx pbufs (before decryption) */
|
||||
struct pbuf *rx;
|
||||
struct pbuf *rx_app;
|
||||
u8_t flags;
|
||||
int rx_passed_unrecved;
|
||||
int bio_bytes_read;
|
||||
int bio_bytes_appl;
|
||||
} altcp_mbedtls_state_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LWIP_ALTCP_TLS && LWIP_ALTCP_TLS_MBEDTLS */
|
||||
#endif /* LWIP_ALTCP */
|
||||
#endif /* LWIP_HDR_ALTCP_MBEDTLS_STRUCTS_H */
|
||||
584
src/apps/http/altcp_proxyconnect.c
Normal file
584
src/apps/http/altcp_proxyconnect.c
Normal file
@@ -0,0 +1,584 @@
|
||||
/**
|
||||
* @file
|
||||
* Application layered TCP connection API that executes a proxy-connect.
|
||||
*
|
||||
* This file provides a starting layer that executes a proxy-connect e.g. to
|
||||
* set up TLS connections through a http proxy.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2018 Simon Goldschmidt
|
||||
* 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. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Simon Goldschmidt <goldsimon@gmx.de>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lwip/apps/altcp_proxyconnect.h"
|
||||
|
||||
#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/altcp.h"
|
||||
#include "lwip/priv/altcp_priv.h"
|
||||
|
||||
#include "lwip/altcp_tcp.h"
|
||||
#include "lwip/altcp_tls.h"
|
||||
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/init.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/** This string is passed in the HTTP header as "User-Agent: " */
|
||||
#ifndef ALTCP_PROXYCONNECT_CLIENT_AGENT
|
||||
#define ALTCP_PROXYCONNECT_CLIENT_AGENT "lwIP/" LWIP_VERSION_STRING " (http://savannah.nongnu.org/projects/lwip)"
|
||||
#endif
|
||||
|
||||
#define ALTCP_PROXYCONNECT_FLAGS_CONNECT_STARTED 0x01
|
||||
#define ALTCP_PROXYCONNECT_FLAGS_HANDSHAKE_DONE 0x02
|
||||
|
||||
typedef struct altcp_proxyconnect_state_s
|
||||
{
|
||||
ip_addr_t outer_addr;
|
||||
u16_t outer_port;
|
||||
struct altcp_proxyconnect_config *conf;
|
||||
u8_t flags;
|
||||
} altcp_proxyconnect_state_t;
|
||||
|
||||
/* Variable prototype, the actual declaration is at the end of this file
|
||||
since it contains pointers to static functions declared here */
|
||||
extern const struct altcp_functions altcp_proxyconnect_functions;
|
||||
|
||||
/* memory management functions: */
|
||||
|
||||
static altcp_proxyconnect_state_t *
|
||||
altcp_proxyconnect_state_alloc(void)
|
||||
{
|
||||
altcp_proxyconnect_state_t *ret = (altcp_proxyconnect_state_t *)mem_calloc(1, sizeof(altcp_proxyconnect_state_t));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
altcp_proxyconnect_state_free(altcp_proxyconnect_state_t *state)
|
||||
{
|
||||
LWIP_ASSERT("state != NULL", state != NULL);
|
||||
mem_free(state);
|
||||
}
|
||||
|
||||
/* helper functions */
|
||||
|
||||
#define PROXY_CONNECT "CONNECT %s:%d HTTP/1.1\r\n" /* HOST, PORT */ \
|
||||
"User-Agent: %s\r\n" /* User-Agent */\
|
||||
"Proxy-Connection: keep-alive\r\n" \
|
||||
"Connection: keep-alive\r\n" \
|
||||
"\r\n"
|
||||
#define PROXY_CONNECT_FORMAT(host, port) PROXY_CONNECT, host, port, ALTCP_PROXYCONNECT_CLIENT_AGENT
|
||||
|
||||
/* Format the http proxy connect request via snprintf */
|
||||
static int
|
||||
altcp_proxyconnect_format_request(char *buffer, size_t bufsize, const char *host, int port)
|
||||
{
|
||||
return snprintf(buffer, bufsize, PROXY_CONNECT_FORMAT(host, port));
|
||||
}
|
||||
|
||||
/* Create and send the http proxy connect request */
|
||||
static err_t
|
||||
altcp_proxyconnect_send_request(struct altcp_pcb *conn)
|
||||
{
|
||||
int len, len2;
|
||||
mem_size_t alloc_len;
|
||||
char *buffer, *host;
|
||||
altcp_proxyconnect_state_t *state = (altcp_proxyconnect_state_t *)conn->state;
|
||||
|
||||
if (!state) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
/* Use printf with zero length to get the required allocation size */
|
||||
len = altcp_proxyconnect_format_request(NULL, 0, "", state->outer_port);
|
||||
if (len < 0) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
/* add allocation size for IP address strings */
|
||||
#if LWIP_IPV6
|
||||
len += 40; /* worst-case IPv6 address length */
|
||||
#else
|
||||
len += 16; /* worst-case IPv4 address length */
|
||||
#endif
|
||||
alloc_len = (mem_size_t)len;
|
||||
if ((len < 0) || (int)alloc_len != len) {
|
||||
/* overflow */
|
||||
return ERR_MEM;
|
||||
}
|
||||
/* Allocate a bufer for the request string */
|
||||
buffer = (char *)mem_malloc(alloc_len);
|
||||
if (buffer == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
host = ipaddr_ntoa(&state->outer_addr);
|
||||
len2 = altcp_proxyconnect_format_request(buffer, alloc_len, host, state->outer_port);
|
||||
if ((len2 > 0) && (len2 <= len) && (len2 <= 0xFFFF)) {
|
||||
err_t err = altcp_write(conn->inner_conn, buffer, (u16_t)len2, TCP_WRITE_FLAG_COPY);
|
||||
if (err != ERR_OK) {
|
||||
/* @todo: abort? */
|
||||
mem_free(buffer);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
mem_free(buffer);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/* callback functions from inner/lower connection: */
|
||||
|
||||
/** Connected callback from lower connection (i.e. TCP).
|
||||
* Not really implemented/tested yet...
|
||||
*/
|
||||
static err_t
|
||||
altcp_proxyconnect_lower_connected(void *arg, struct altcp_pcb *inner_conn, err_t err)
|
||||
{
|
||||
struct altcp_pcb *conn = (struct altcp_pcb *)arg;
|
||||
if (conn && conn->state) {
|
||||
LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn);
|
||||
LWIP_UNUSED_ARG(inner_conn); /* for LWIP_NOASSERT */
|
||||
/* upper connected is called when handshake is done */
|
||||
if (err != ERR_OK) {
|
||||
if (conn->connected) {
|
||||
if (conn->connected(conn->arg, conn, err) == ERR_ABRT) {
|
||||
return ERR_ABRT;
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
/* send proxy connect request here */
|
||||
return altcp_proxyconnect_send_request(conn);
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
/** Recv callback from lower connection (i.e. TCP)
|
||||
* This one mainly differs between connection setup (wait for proxy OK string)
|
||||
* and application phase (data is passed on to the application).
|
||||
*/
|
||||
static err_t
|
||||
altcp_proxyconnect_lower_recv(void *arg, struct altcp_pcb *inner_conn, struct pbuf *p, err_t err)
|
||||
{
|
||||
altcp_proxyconnect_state_t *state;
|
||||
struct altcp_pcb *conn = (struct altcp_pcb *)arg;
|
||||
|
||||
LWIP_ASSERT("no err expected", err == ERR_OK);
|
||||
LWIP_UNUSED_ARG(err);
|
||||
|
||||
if (!conn) {
|
||||
/* no connection given as arg? should not happen, but prevent pbuf/conn leaks */
|
||||
if (p != NULL) {
|
||||
pbuf_free(p);
|
||||
}
|
||||
altcp_close(inner_conn);
|
||||
return ERR_CLSD;
|
||||
}
|
||||
state = (altcp_proxyconnect_state_t *)conn->state;
|
||||
LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn);
|
||||
if (!state) {
|
||||
/* already closed */
|
||||
if (p != NULL) {
|
||||
pbuf_free(p);
|
||||
}
|
||||
altcp_close(inner_conn);
|
||||
return ERR_CLSD;
|
||||
}
|
||||
if (state->flags & ALTCP_PROXYCONNECT_FLAGS_HANDSHAKE_DONE) {
|
||||
/* application phase, just pass this through */
|
||||
if (conn->recv) {
|
||||
return conn->recv(conn->arg, conn, p, err);
|
||||
}
|
||||
pbuf_free(p);
|
||||
return ERR_OK;
|
||||
} else {
|
||||
/* setup phase */
|
||||
/* handle NULL pbuf (inner connection closed) */
|
||||
if (p == NULL) {
|
||||
if (altcp_close(conn) != ERR_OK) {
|
||||
altcp_abort(conn);
|
||||
return ERR_ABRT;
|
||||
}
|
||||
return ERR_OK;
|
||||
} else {
|
||||
/* @todo: parse setup phase rx data
|
||||
for now, we just wait for the end of the header... */
|
||||
u16_t idx = pbuf_memfind(p, "\r\n\r\n", 4, 0);
|
||||
altcp_recved(inner_conn, p->tot_len);
|
||||
pbuf_free(p);
|
||||
if (idx != 0xFFFF) {
|
||||
state->flags |= ALTCP_PROXYCONNECT_FLAGS_HANDSHAKE_DONE;
|
||||
if (conn->connected) {
|
||||
return conn->connected(conn->arg, conn, ERR_OK);
|
||||
}
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Sent callback from lower connection (i.e. TCP)
|
||||
* This only informs the upper layer to try to send more, not about
|
||||
* the number of ACKed bytes.
|
||||
*/
|
||||
static err_t
|
||||
altcp_proxyconnect_lower_sent(void *arg, struct altcp_pcb *inner_conn, u16_t len)
|
||||
{
|
||||
struct altcp_pcb *conn = (struct altcp_pcb *)arg;
|
||||
LWIP_UNUSED_ARG(len);
|
||||
if (conn) {
|
||||
altcp_proxyconnect_state_t *state = (altcp_proxyconnect_state_t *)conn->state;
|
||||
LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn);
|
||||
LWIP_UNUSED_ARG(inner_conn); /* for LWIP_NOASSERT */
|
||||
if (!state || !(state->flags & ALTCP_PROXYCONNECT_FLAGS_HANDSHAKE_DONE)) {
|
||||
/* @todo: do something here? */
|
||||
return ERR_OK;
|
||||
}
|
||||
/* pass this on to upper sent */
|
||||
if (conn->sent) {
|
||||
return conn->sent(conn->arg, conn, len);
|
||||
}
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/** Poll callback from lower connection (i.e. TCP)
|
||||
* Just pass this on to the application.
|
||||
* @todo: retry sending?
|
||||
*/
|
||||
static err_t
|
||||
altcp_proxyconnect_lower_poll(void *arg, struct altcp_pcb *inner_conn)
|
||||
{
|
||||
struct altcp_pcb *conn = (struct altcp_pcb *)arg;
|
||||
if (conn) {
|
||||
LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn);
|
||||
LWIP_UNUSED_ARG(inner_conn); /* for LWIP_NOASSERT */
|
||||
if (conn->poll) {
|
||||
return conn->poll(conn->arg, conn);
|
||||
}
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
altcp_proxyconnect_lower_err(void *arg, err_t err)
|
||||
{
|
||||
struct altcp_pcb *conn = (struct altcp_pcb *)arg;
|
||||
if (conn) {
|
||||
conn->inner_conn = NULL; /* already freed */
|
||||
if (conn->err) {
|
||||
conn->err(conn->arg, err);
|
||||
}
|
||||
altcp_free(conn);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* setup functions */
|
||||
|
||||
static void
|
||||
altcp_proxyconnect_setup_callbacks(struct altcp_pcb *conn, struct altcp_pcb *inner_conn)
|
||||
{
|
||||
altcp_arg(inner_conn, conn);
|
||||
altcp_recv(inner_conn, altcp_proxyconnect_lower_recv);
|
||||
altcp_sent(inner_conn, altcp_proxyconnect_lower_sent);
|
||||
altcp_err(inner_conn, altcp_proxyconnect_lower_err);
|
||||
/* tcp_poll is set when interval is set by application */
|
||||
/* listen is set totally different :-) */
|
||||
}
|
||||
|
||||
static err_t
|
||||
altcp_proxyconnect_setup(struct altcp_proxyconnect_config *config, struct altcp_pcb *conn, struct altcp_pcb *inner_conn)
|
||||
{
|
||||
altcp_proxyconnect_state_t *state;
|
||||
if (!config) {
|
||||
return ERR_ARG;
|
||||
}
|
||||
LWIP_ASSERT("invalid inner_conn", conn != inner_conn);
|
||||
|
||||
/* allocate proxyconnect context */
|
||||
state = altcp_proxyconnect_state_alloc();
|
||||
if (state == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
state->flags = 0;
|
||||
state->conf = config;
|
||||
altcp_proxyconnect_setup_callbacks(conn, inner_conn);
|
||||
conn->inner_conn = inner_conn;
|
||||
conn->fns = &altcp_proxyconnect_functions;
|
||||
conn->state = state;
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/** Allocate a new altcp layer connecting through a proxy.
|
||||
* This function gets the inner pcb passed.
|
||||
*
|
||||
* @param config struct altcp_proxyconnect_config that contains the proxy settings
|
||||
* @param inner_pcb pcb that makes the connection to the proxy (i.e. tcp pcb)
|
||||
*/
|
||||
struct altcp_pcb *
|
||||
altcp_proxyconnect_new(struct altcp_proxyconnect_config *config, struct altcp_pcb *inner_pcb)
|
||||
{
|
||||
struct altcp_pcb *ret;
|
||||
if (inner_pcb == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ret = altcp_alloc();
|
||||
if (ret != NULL) {
|
||||
if (altcp_proxyconnect_setup(config, ret, inner_pcb) != ERR_OK) {
|
||||
altcp_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Allocate a new altcp layer connecting through a proxy.
|
||||
* This function allocates the inner pcb as tcp pcb, resulting in a direct tcp
|
||||
* connection to the proxy.
|
||||
*
|
||||
* @param config struct altcp_proxyconnect_config that contains the proxy settings
|
||||
* @param ip_type IP type of the connection (@ref lwip_ip_addr_type)
|
||||
*/
|
||||
struct altcp_pcb *
|
||||
altcp_proxyconnect_new_tcp(struct altcp_proxyconnect_config *config, u8_t ip_type)
|
||||
{
|
||||
struct altcp_pcb *inner_pcb, *ret;
|
||||
|
||||
/* inner pcb is tcp */
|
||||
inner_pcb = altcp_tcp_new_ip_type(ip_type);
|
||||
if (inner_pcb == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ret = altcp_proxyconnect_new(config, inner_pcb);
|
||||
if (ret == NULL) {
|
||||
altcp_close(inner_pcb);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Allocator function to allocate a proxy connect altcp pcb connecting directly
|
||||
* via tcp to the proxy.
|
||||
*
|
||||
* The returned pcb is a chain: altcp_proxyconnect - altcp_tcp - tcp pcb
|
||||
*
|
||||
* This function is meant for use with @ref altcp_new.
|
||||
*
|
||||
* @param arg struct altcp_proxyconnect_config that contains the proxy settings
|
||||
* @param ip_type IP type of the connection (@ref lwip_ip_addr_type)
|
||||
*/
|
||||
struct altcp_pcb *
|
||||
altcp_proxyconnect_alloc(void *arg, u8_t ip_type)
|
||||
{
|
||||
return altcp_proxyconnect_new_tcp((struct altcp_proxyconnect_config *)arg, ip_type);
|
||||
}
|
||||
|
||||
|
||||
#if LWIP_ALTCP_TLS
|
||||
|
||||
/** Allocator function to allocate a TLS connection through a proxy.
|
||||
*
|
||||
* The returned pcb is a chain: altcp_tls - altcp_proxyconnect - altcp_tcp - tcp pcb
|
||||
*
|
||||
* This function is meant for use with @ref altcp_new.
|
||||
*
|
||||
* @param arg struct altcp_proxyconnect_tls_config that contains the proxy settings
|
||||
* and tls settings
|
||||
* @param ip_type IP type of the connection (@ref lwip_ip_addr_type)
|
||||
*/
|
||||
struct altcp_pcb *
|
||||
altcp_proxyconnect_tls_alloc(void *arg, u8_t ip_type)
|
||||
{
|
||||
struct altcp_proxyconnect_tls_config *cfg = (struct altcp_proxyconnect_tls_config *)arg;
|
||||
struct altcp_pcb *proxy_pcb;
|
||||
struct altcp_pcb *tls_pcb;
|
||||
|
||||
proxy_pcb = altcp_proxyconnect_new_tcp(&cfg->proxy, ip_type);
|
||||
tls_pcb = altcp_tls_wrap(cfg->tls_config, proxy_pcb);
|
||||
|
||||
if (tls_pcb == NULL) {
|
||||
altcp_close(proxy_pcb);
|
||||
}
|
||||
return tls_pcb;
|
||||
}
|
||||
#endif /* LWIP_ALTCP_TLS */
|
||||
|
||||
/* "virtual" functions */
|
||||
static void
|
||||
altcp_proxyconnect_set_poll(struct altcp_pcb *conn, u8_t interval)
|
||||
{
|
||||
if (conn != NULL) {
|
||||
altcp_poll(conn->inner_conn, altcp_proxyconnect_lower_poll, interval);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
altcp_proxyconnect_recved(struct altcp_pcb *conn, u16_t len)
|
||||
{
|
||||
altcp_proxyconnect_state_t *state;
|
||||
if (conn == NULL) {
|
||||
return;
|
||||
}
|
||||
state = (altcp_proxyconnect_state_t *)conn->state;
|
||||
if (state == NULL) {
|
||||
return;
|
||||
}
|
||||
if (!(state->flags & ALTCP_PROXYCONNECT_FLAGS_HANDSHAKE_DONE)) {
|
||||
return;
|
||||
}
|
||||
altcp_recved(conn->inner_conn, len);
|
||||
}
|
||||
|
||||
static err_t
|
||||
altcp_proxyconnect_connect(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port, altcp_connected_fn connected)
|
||||
{
|
||||
altcp_proxyconnect_state_t *state;
|
||||
|
||||
if ((conn == NULL) || (ipaddr == NULL)) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
state = (altcp_proxyconnect_state_t *)conn->state;
|
||||
if (state == NULL) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
if (state->flags & ALTCP_PROXYCONNECT_FLAGS_CONNECT_STARTED) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
state->flags |= ALTCP_PROXYCONNECT_FLAGS_CONNECT_STARTED;
|
||||
|
||||
conn->connected = connected;
|
||||
/* connect to our proxy instead, but store the requested address and port */
|
||||
ip_addr_copy(state->outer_addr, *ipaddr);
|
||||
state->outer_port = port;
|
||||
|
||||
return altcp_connect(conn->inner_conn, &state->conf->proxy_addr, state->conf->proxy_port, altcp_proxyconnect_lower_connected);
|
||||
}
|
||||
|
||||
static struct altcp_pcb *
|
||||
altcp_proxyconnect_listen(struct altcp_pcb *conn, u8_t backlog, err_t *err)
|
||||
{
|
||||
LWIP_UNUSED_ARG(conn);
|
||||
LWIP_UNUSED_ARG(backlog);
|
||||
LWIP_UNUSED_ARG(err);
|
||||
/* listen not supported! */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
altcp_proxyconnect_abort(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn != NULL) {
|
||||
if (conn->inner_conn != NULL) {
|
||||
altcp_abort(conn->inner_conn);
|
||||
}
|
||||
altcp_free(conn);
|
||||
}
|
||||
}
|
||||
|
||||
static err_t
|
||||
altcp_proxyconnect_close(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn == NULL) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
if (conn->inner_conn != NULL) {
|
||||
err_t err = altcp_close(conn->inner_conn);
|
||||
if (err != ERR_OK) {
|
||||
/* closing inner conn failed, return the error */
|
||||
return err;
|
||||
}
|
||||
}
|
||||
/* no inner conn or closing it succeeded, deallocate myself */
|
||||
altcp_free(conn);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static err_t
|
||||
altcp_proxyconnect_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags)
|
||||
{
|
||||
altcp_proxyconnect_state_t *state;
|
||||
|
||||
LWIP_UNUSED_ARG(apiflags);
|
||||
|
||||
if (conn == NULL) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
state = (altcp_proxyconnect_state_t *)conn->state;
|
||||
if (state == NULL) {
|
||||
/* @todo: which error? */
|
||||
return ERR_CLSD;
|
||||
}
|
||||
if (!(state->flags & ALTCP_PROXYCONNECT_FLAGS_HANDSHAKE_DONE)) {
|
||||
/* @todo: which error? */
|
||||
return ERR_VAL;
|
||||
}
|
||||
return altcp_write(conn->inner_conn, dataptr, len, apiflags);
|
||||
}
|
||||
|
||||
static void
|
||||
altcp_proxyconnect_dealloc(struct altcp_pcb *conn)
|
||||
{
|
||||
/* clean up and free tls state */
|
||||
if (conn) {
|
||||
altcp_proxyconnect_state_t *state = (altcp_proxyconnect_state_t *)conn->state;
|
||||
if (state) {
|
||||
altcp_proxyconnect_state_free(state);
|
||||
conn->state = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
const struct altcp_functions altcp_proxyconnect_functions = {
|
||||
altcp_proxyconnect_set_poll,
|
||||
altcp_proxyconnect_recved,
|
||||
altcp_default_bind,
|
||||
altcp_proxyconnect_connect,
|
||||
altcp_proxyconnect_listen,
|
||||
altcp_proxyconnect_abort,
|
||||
altcp_proxyconnect_close,
|
||||
altcp_default_shutdown,
|
||||
altcp_proxyconnect_write,
|
||||
altcp_default_output,
|
||||
altcp_default_mss,
|
||||
altcp_default_sndbuf,
|
||||
altcp_default_sndqueuelen,
|
||||
altcp_default_nagle_disable,
|
||||
altcp_default_nagle_enable,
|
||||
altcp_default_nagle_disabled,
|
||||
altcp_default_setprio,
|
||||
altcp_proxyconnect_dealloc,
|
||||
altcp_default_get_tcp_addrinfo,
|
||||
altcp_default_get_ip,
|
||||
altcp_default_get_port
|
||||
#ifdef LWIP_DEBUG
|
||||
, altcp_default_dbg_get_tcp_state
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* LWIP_ALTCP */
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* 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,
|
||||
@@ -11,21 +11,21 @@
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
|
||||
*
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
@@ -33,15 +33,10 @@
|
||||
#include "lwip/apps/httpd_opts.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/apps/fs.h"
|
||||
#include "fsdata.h"
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#if HTTPD_USE_CUSTOM_FSDATA
|
||||
#include "fsdata_custom.c"
|
||||
#else /* HTTPD_USE_CUSTOM_FSDATA */
|
||||
#include "fsdata.c"
|
||||
#endif /* HTTPD_USE_CUSTOM_FSDATA */
|
||||
#include HTTPD_FSDATA_FILE
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
@@ -64,7 +59,7 @@ fs_open(struct fs_file *file, const char *name)
|
||||
const struct fsdata_file *f;
|
||||
|
||||
if ((file == NULL) || (name == NULL)) {
|
||||
return ERR_ARG;
|
||||
return ERR_ARG;
|
||||
}
|
||||
|
||||
#if LWIP_HTTPD_CUSTOM_FILES
|
||||
@@ -121,7 +116,7 @@ fs_read(struct fs_file *file, char *buffer, int count)
|
||||
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
|
||||
{
|
||||
int read;
|
||||
if(file->index == file->len) {
|
||||
if (file->index == file->len) {
|
||||
return FS_READ_EOF;
|
||||
}
|
||||
#if LWIP_HTTPD_FS_ASYNC_READ
|
||||
@@ -139,14 +134,14 @@ fs_read(struct fs_file *file, char *buffer, int count)
|
||||
#endif /* LWIP_HTTPD_CUSTOM_FILES */
|
||||
|
||||
read = file->len - file->index;
|
||||
if(read > count) {
|
||||
if (read > count) {
|
||||
read = count;
|
||||
}
|
||||
|
||||
MEMCPY(buffer, (file->data + file->index), read);
|
||||
file->index += read;
|
||||
|
||||
return(read);
|
||||
return (read);
|
||||
}
|
||||
#endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
Before Width: | Height: | Size: 724 B After Width: | Height: | Size: 724 B |
@@ -1,13 +1,33 @@
|
||||
#include "lwip/apps/fs.h"
|
||||
#include "lwip/def.h"
|
||||
#include "fsdata.h"
|
||||
|
||||
|
||||
#define file_NULL (struct fsdata_file *) NULL
|
||||
|
||||
|
||||
#ifndef FS_FILE_FLAGS_HEADER_INCLUDED
|
||||
#define FS_FILE_FLAGS_HEADER_INCLUDED 1
|
||||
#endif
|
||||
#ifndef FS_FILE_FLAGS_HEADER_PERSISTENT
|
||||
#define FS_FILE_FLAGS_HEADER_PERSISTENT 0
|
||||
#endif
|
||||
/* FSDATA_FILE_ALIGNMENT: 0=off, 1=by variable, 2=by include */
|
||||
#ifndef FSDATA_FILE_ALIGNMENT
|
||||
#define FSDATA_FILE_ALIGNMENT 0
|
||||
#endif
|
||||
#ifndef FSDATA_ALIGN_PRE
|
||||
#define FSDATA_ALIGN_PRE
|
||||
#endif
|
||||
#ifndef FSDATA_ALIGN_POST
|
||||
#define FSDATA_ALIGN_POST
|
||||
#endif
|
||||
#if FSDATA_FILE_ALIGNMENT==2
|
||||
#include "fsdata_alignment.h"
|
||||
#endif
|
||||
#if FSDATA_FILE_ALIGNMENT==1
|
||||
static const unsigned int dummy_align__img_sics_gif = 0;
|
||||
static const unsigned char data__img_sics_gif[] = {
|
||||
#endif
|
||||
static const unsigned char FSDATA_ALIGN_PRE data__img_sics_gif[] FSDATA_ALIGN_POST = {
|
||||
/* /img/sics.gif (14 chars) */
|
||||
0x2f,0x69,0x6d,0x67,0x2f,0x73,0x69,0x63,0x73,0x2e,0x67,0x69,0x66,0x00,0x00,0x00,
|
||||
|
||||
@@ -16,16 +36,21 @@ static const unsigned char data__img_sics_gif[] = {
|
||||
" (17 bytes) */
|
||||
0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x30,0x20,0x32,0x30,0x30,0x20,0x4f,0x4b,0x0d,
|
||||
0x0a,
|
||||
/* "Server: lwIP/1.3.1 (http://savannah.nongnu.org/projects/lwip)
|
||||
" (63 bytes) */
|
||||
0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x31,0x2e,0x33,
|
||||
0x2e,0x31,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,0x6e,
|
||||
0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,0x70,
|
||||
0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a,
|
||||
/* "Content-type: image/gif
|
||||
/* "Server: lwIP/2.0.3d (http://savannah.nongnu.org/projects/lwip)
|
||||
" (64 bytes) */
|
||||
0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x32,0x2e,0x30,
|
||||
0x2e,0x33,0x64,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,
|
||||
0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,
|
||||
0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a,
|
||||
|
||||
/* "Content-Length: 724
|
||||
" (18+ bytes) */
|
||||
0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20,
|
||||
0x37,0x32,0x34,0x0d,0x0a,
|
||||
/* "Content-Type: image/gif
|
||||
|
||||
" (27 bytes) */
|
||||
0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,0x79,0x70,0x65,0x3a,0x20,0x69,0x6d,
|
||||
0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x69,0x6d,
|
||||
0x61,0x67,0x65,0x2f,0x67,0x69,0x66,0x0d,0x0a,0x0d,0x0a,
|
||||
/* raw file data (724 bytes) */
|
||||
0x47,0x49,0x46,0x38,0x39,0x61,0x46,0x00,0x22,0x00,0xa5,0x00,0x00,0xd9,0x2b,0x39,
|
||||
@@ -75,8 +100,10 @@ static const unsigned char data__img_sics_gif[] = {
|
||||
0x82,0x0c,0x36,0xe8,0xe0,0x83,0x10,0x46,0x28,0xe1,0x84,0x14,0x56,0x68,0xa1,0x10,
|
||||
0x41,0x00,0x00,0x3b,};
|
||||
|
||||
#if FSDATA_FILE_ALIGNMENT==1
|
||||
static const unsigned int dummy_align__404_html = 1;
|
||||
static const unsigned char data__404_html[] = {
|
||||
#endif
|
||||
static const unsigned char FSDATA_ALIGN_PRE data__404_html[] FSDATA_ALIGN_POST = {
|
||||
/* /404.html (10 chars) */
|
||||
0x2f,0x34,0x30,0x34,0x2e,0x68,0x74,0x6d,0x6c,0x00,0x00,0x00,
|
||||
|
||||
@@ -85,16 +112,21 @@ static const unsigned char data__404_html[] = {
|
||||
" (29 bytes) */
|
||||
0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x30,0x20,0x34,0x30,0x34,0x20,0x46,0x69,0x6c,
|
||||
0x65,0x20,0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x0d,0x0a,
|
||||
/* "Server: lwIP/1.3.1 (http://savannah.nongnu.org/projects/lwip)
|
||||
" (63 bytes) */
|
||||
0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x31,0x2e,0x33,
|
||||
0x2e,0x31,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,0x6e,
|
||||
0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,0x70,
|
||||
0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a,
|
||||
/* "Content-type: text/html
|
||||
/* "Server: lwIP/2.0.3d (http://savannah.nongnu.org/projects/lwip)
|
||||
" (64 bytes) */
|
||||
0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x32,0x2e,0x30,
|
||||
0x2e,0x33,0x64,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,
|
||||
0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,
|
||||
0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a,
|
||||
|
||||
/* "Content-Length: 565
|
||||
" (18+ bytes) */
|
||||
0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20,
|
||||
0x35,0x36,0x35,0x0d,0x0a,
|
||||
/* "Content-Type: text/html
|
||||
|
||||
" (27 bytes) */
|
||||
0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,0x79,0x70,0x65,0x3a,0x20,0x74,0x65,
|
||||
0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65,
|
||||
0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x0d,0x0a,0x0d,0x0a,
|
||||
/* raw file data (565 bytes) */
|
||||
0x3c,0x68,0x74,0x6d,0x6c,0x3e,0x0d,0x0a,0x3c,0x68,0x65,0x61,0x64,0x3e,0x3c,0x74,
|
||||
@@ -134,8 +166,10 @@ static const unsigned char data__404_html[] = {
|
||||
0x3e,0x0d,0x0a,0x3c,0x2f,0x62,0x6f,0x64,0x79,0x3e,0x0d,0x0a,0x3c,0x2f,0x68,0x74,
|
||||
0x6d,0x6c,0x3e,0x0d,0x0a,};
|
||||
|
||||
#if FSDATA_FILE_ALIGNMENT==1
|
||||
static const unsigned int dummy_align__index_html = 2;
|
||||
static const unsigned char data__index_html[] = {
|
||||
#endif
|
||||
static const unsigned char FSDATA_ALIGN_PRE data__index_html[] FSDATA_ALIGN_POST = {
|
||||
/* /index.html (12 chars) */
|
||||
0x2f,0x69,0x6e,0x64,0x65,0x78,0x2e,0x68,0x74,0x6d,0x6c,0x00,
|
||||
|
||||
@@ -144,16 +178,21 @@ static const unsigned char data__index_html[] = {
|
||||
" (17 bytes) */
|
||||
0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x30,0x20,0x32,0x30,0x30,0x20,0x4f,0x4b,0x0d,
|
||||
0x0a,
|
||||
/* "Server: lwIP/1.3.1 (http://savannah.nongnu.org/projects/lwip)
|
||||
" (63 bytes) */
|
||||
0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x31,0x2e,0x33,
|
||||
0x2e,0x31,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,0x6e,
|
||||
0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,0x70,
|
||||
0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a,
|
||||
/* "Content-type: text/html
|
||||
/* "Server: lwIP/2.0.3d (http://savannah.nongnu.org/projects/lwip)
|
||||
" (64 bytes) */
|
||||
0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x32,0x2e,0x30,
|
||||
0x2e,0x33,0x64,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,
|
||||
0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,
|
||||
0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a,
|
||||
|
||||
/* "Content-Length: 1751
|
||||
" (18+ bytes) */
|
||||
0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20,
|
||||
0x31,0x37,0x35,0x31,0x0d,0x0a,
|
||||
/* "Content-Type: text/html
|
||||
|
||||
" (27 bytes) */
|
||||
0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,0x79,0x70,0x65,0x3a,0x20,0x74,0x65,
|
||||
0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65,
|
||||
0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x0d,0x0a,0x0d,0x0a,
|
||||
/* raw file data (1751 bytes) */
|
||||
0x3c,0x68,0x74,0x6d,0x6c,0x3e,0x0d,0x0a,0x3c,0x68,0x65,0x61,0x64,0x3e,0x3c,0x74,
|
||||
@@ -274,7 +313,7 @@ file_NULL,
|
||||
data__img_sics_gif,
|
||||
data__img_sics_gif + 16,
|
||||
sizeof(data__img_sics_gif) - 16,
|
||||
1,
|
||||
FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT,
|
||||
}};
|
||||
|
||||
const struct fsdata_file file__404_html[] = { {
|
||||
@@ -282,7 +321,7 @@ file__img_sics_gif,
|
||||
data__404_html,
|
||||
data__404_html + 12,
|
||||
sizeof(data__404_html) - 12,
|
||||
1,
|
||||
FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT,
|
||||
}};
|
||||
|
||||
const struct fsdata_file file__index_html[] = { {
|
||||
@@ -290,7 +329,7 @@ file__404_html,
|
||||
data__index_html,
|
||||
data__index_html + 12,
|
||||
sizeof(data__index_html) - 12,
|
||||
1,
|
||||
FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT,
|
||||
}};
|
||||
|
||||
#define FS_ROOT file__index_html
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* 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,
|
||||
@@ -11,21 +11,21 @@
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
|
||||
*
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
@@ -35,16 +35,7 @@
|
||||
#include "lwip/apps/httpd_opts.h"
|
||||
#include "lwip/apps/fs.h"
|
||||
|
||||
struct fsdata_file {
|
||||
const struct fsdata_file *next;
|
||||
const unsigned char *name;
|
||||
const unsigned char *data;
|
||||
int len;
|
||||
u8_t flags;
|
||||
#if HTTPD_PRECALCULATED_CHECKSUM
|
||||
u16_t chksum_count;
|
||||
const struct fsdata_chksum *chksum;
|
||||
#endif /* HTTPD_PRECALCULATED_CHECKSUM */
|
||||
};
|
||||
/* THIS FILE IS DEPRECATED AND WILL BE REMOVED IN THE FUTURE */
|
||||
/* content was moved to fs.h to simplify #include structure */
|
||||
|
||||
#endif /* LWIP_FSDATA_H */
|
||||
909
src/apps/http/http_client.c
Normal file
909
src/apps/http/http_client.c
Normal file
@@ -0,0 +1,909 @@
|
||||
/**
|
||||
* @file
|
||||
* HTTP client
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2018 Simon Goldschmidt <goldsimon@gmx.de>
|
||||
* 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. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Simon Goldschmidt <goldsimon@gmx.de>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup httpc HTTP client
|
||||
* @ingroup apps
|
||||
* @todo:
|
||||
* - persistent connections
|
||||
* - select outgoing http version
|
||||
* - optionally follow redirect
|
||||
* - check request uri for invalid characters? (e.g. encode spaces)
|
||||
* - IPv6 support
|
||||
*/
|
||||
|
||||
#include "lwip/apps/http_client.h"
|
||||
|
||||
#include "lwip/altcp_tcp.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/debug.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/altcp_tls.h"
|
||||
#include "lwip/init.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if LWIP_TCP && LWIP_CALLBACK_API
|
||||
|
||||
/**
|
||||
* HTTPC_DEBUG: Enable debugging for HTTP client.
|
||||
*/
|
||||
#ifndef HTTPC_DEBUG
|
||||
#define HTTPC_DEBUG LWIP_DBG_OFF
|
||||
#endif
|
||||
|
||||
/** Set this to 1 to keep server name and uri in request state */
|
||||
#ifndef HTTPC_DEBUG_REQUEST
|
||||
#define HTTPC_DEBUG_REQUEST 0
|
||||
#endif
|
||||
|
||||
/** This string is passed in the HTTP header as "User-Agent: " */
|
||||
#ifndef HTTPC_CLIENT_AGENT
|
||||
#define HTTPC_CLIENT_AGENT "lwIP/" LWIP_VERSION_STRING " (http://savannah.nongnu.org/projects/lwip)"
|
||||
#endif
|
||||
|
||||
/* the various debug levels for this file */
|
||||
#define HTTPC_DEBUG_TRACE (HTTPC_DEBUG | LWIP_DBG_TRACE)
|
||||
#define HTTPC_DEBUG_STATE (HTTPC_DEBUG | LWIP_DBG_STATE)
|
||||
#define HTTPC_DEBUG_WARN (HTTPC_DEBUG | LWIP_DBG_LEVEL_WARNING)
|
||||
#define HTTPC_DEBUG_WARN_STATE (HTTPC_DEBUG | LWIP_DBG_LEVEL_WARNING | LWIP_DBG_STATE)
|
||||
#define HTTPC_DEBUG_SERIOUS (HTTPC_DEBUG | LWIP_DBG_LEVEL_SERIOUS)
|
||||
|
||||
#define HTTPC_POLL_INTERVAL 1
|
||||
#define HTTPC_POLL_TIMEOUT 30 /* 15 seconds */
|
||||
|
||||
#define HTTPC_CONTENT_LEN_INVALID 0xFFFFFFFF
|
||||
|
||||
/* GET request basic */
|
||||
#define HTTPC_REQ_11 "GET %s HTTP/1.1\r\n" /* URI */\
|
||||
"User-Agent: %s\r\n" /* User-Agent */ \
|
||||
"Accept: */*\r\n" \
|
||||
"Connection: Close\r\n" /* we don't support persistent connections, yet */ \
|
||||
"\r\n"
|
||||
#define HTTPC_REQ_11_FORMAT(uri) HTTPC_REQ_11, uri, HTTPC_CLIENT_AGENT
|
||||
|
||||
/* GET request with host */
|
||||
#define HTTPC_REQ_11_HOST "GET %s HTTP/1.1\r\n" /* URI */\
|
||||
"User-Agent: %s\r\n" /* User-Agent */ \
|
||||
"Accept: */*\r\n" \
|
||||
"Host: %s\r\n" /* server name */ \
|
||||
"Connection: Close\r\n" /* we don't support persistent connections, yet */ \
|
||||
"\r\n"
|
||||
#define HTTPC_REQ_11_HOST_FORMAT(uri, srv_name) HTTPC_REQ_11_HOST, uri, HTTPC_CLIENT_AGENT, srv_name
|
||||
|
||||
/* GET request with proxy */
|
||||
#define HTTPC_REQ_11_PROXY "GET http://%s%s HTTP/1.1\r\n" /* HOST, URI */\
|
||||
"User-Agent: %s\r\n" /* User-Agent */ \
|
||||
"Accept: */*\r\n" \
|
||||
"Host: %s\r\n" /* server name */ \
|
||||
"Connection: Close\r\n" /* we don't support persistent connections, yet */ \
|
||||
"\r\n"
|
||||
#define HTTPC_REQ_11_PROXY_FORMAT(host, uri, srv_name) HTTPC_REQ_11_PROXY, host, uri, HTTPC_CLIENT_AGENT, srv_name
|
||||
|
||||
/* GET request with proxy (non-default server port) */
|
||||
#define HTTPC_REQ_11_PROXY_PORT "GET http://%s:%d%s HTTP/1.1\r\n" /* HOST, host-port, URI */\
|
||||
"User-Agent: %s\r\n" /* User-Agent */ \
|
||||
"Accept: */*\r\n" \
|
||||
"Host: %s\r\n" /* server name */ \
|
||||
"Connection: Close\r\n" /* we don't support persistent connections, yet */ \
|
||||
"\r\n"
|
||||
#define HTTPC_REQ_11_PROXY_PORT_FORMAT(host, host_port, uri, srv_name) HTTPC_REQ_11_PROXY_PORT, host, host_port, uri, HTTPC_CLIENT_AGENT, srv_name
|
||||
|
||||
typedef enum ehttpc_parse_state {
|
||||
HTTPC_PARSE_WAIT_FIRST_LINE = 0,
|
||||
HTTPC_PARSE_WAIT_HEADERS,
|
||||
HTTPC_PARSE_RX_DATA
|
||||
} httpc_parse_state_t;
|
||||
|
||||
typedef struct _httpc_state
|
||||
{
|
||||
struct altcp_pcb* pcb;
|
||||
ip_addr_t remote_addr;
|
||||
u16_t remote_port;
|
||||
int timeout_ticks;
|
||||
struct pbuf *request;
|
||||
struct pbuf *rx_hdrs;
|
||||
u16_t rx_http_version;
|
||||
u16_t rx_status;
|
||||
altcp_recv_fn recv_fn;
|
||||
const httpc_connection_t *conn_settings;
|
||||
void* callback_arg;
|
||||
u32_t rx_content_len;
|
||||
u32_t hdr_content_len;
|
||||
httpc_parse_state_t parse_state;
|
||||
#if HTTPC_DEBUG_REQUEST
|
||||
char* server_name;
|
||||
char* uri;
|
||||
#endif
|
||||
} httpc_state_t;
|
||||
|
||||
/** Free http client state and deallocate all resources within */
|
||||
static err_t
|
||||
httpc_free_state(httpc_state_t* req)
|
||||
{
|
||||
struct altcp_pcb* tpcb;
|
||||
|
||||
if (req->request != NULL) {
|
||||
pbuf_free(req->request);
|
||||
req->request = NULL;
|
||||
}
|
||||
if (req->rx_hdrs != NULL) {
|
||||
pbuf_free(req->rx_hdrs);
|
||||
req->rx_hdrs = NULL;
|
||||
}
|
||||
|
||||
tpcb = req->pcb;
|
||||
mem_free(req);
|
||||
req = NULL;
|
||||
|
||||
if (tpcb != NULL) {
|
||||
err_t r;
|
||||
altcp_arg(tpcb, NULL);
|
||||
altcp_recv(tpcb, NULL);
|
||||
altcp_err(tpcb, NULL);
|
||||
altcp_poll(tpcb, NULL, 0);
|
||||
altcp_sent(tpcb, NULL);
|
||||
r = altcp_close(tpcb);
|
||||
if (r != ERR_OK) {
|
||||
altcp_abort(tpcb);
|
||||
return ERR_ABRT;
|
||||
}
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/** Close the connection: call finished callback and free the state */
|
||||
static err_t
|
||||
httpc_close(httpc_state_t* req, httpc_result_t result, u32_t server_response, err_t err)
|
||||
{
|
||||
if (req != NULL) {
|
||||
if (req->conn_settings != NULL) {
|
||||
if (req->conn_settings->result_fn != NULL) {
|
||||
req->conn_settings->result_fn(req->callback_arg, result, req->rx_content_len, server_response, err);
|
||||
}
|
||||
}
|
||||
return httpc_free_state(req);
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/** Parse http header response line 1 */
|
||||
static err_t
|
||||
http_parse_response_status(struct pbuf *p, u16_t *http_version, u16_t *http_status, u16_t *http_status_str_offset)
|
||||
{
|
||||
u16_t end1 = pbuf_memfind(p, "\r\n", 2, 0);
|
||||
if (end1 != 0xFFFF) {
|
||||
/* get parts of first line */
|
||||
u16_t space1, space2;
|
||||
space1 = pbuf_memfind(p, " ", 1, 0);
|
||||
if (space1 != 0xFFFF) {
|
||||
if ((pbuf_memcmp(p, 0, "HTTP/", 5) == 0) && (pbuf_get_at(p, 6) == '.')) {
|
||||
char status_num[10];
|
||||
size_t status_num_len;
|
||||
/* parse http version */
|
||||
u16_t version = pbuf_get_at(p, 5) - '0';
|
||||
version <<= 8;
|
||||
version |= pbuf_get_at(p, 7) - '0';
|
||||
*http_version = version;
|
||||
|
||||
/* parse http status number */
|
||||
space2 = pbuf_memfind(p, " ", 1, space1 + 1);
|
||||
if (space2 != 0xFFFF) {
|
||||
*http_status_str_offset = space2 + 1;
|
||||
status_num_len = space2 - space1 - 1;
|
||||
} else {
|
||||
status_num_len = end1 - space1 - 1;
|
||||
}
|
||||
memset(status_num, 0, sizeof(status_num));
|
||||
if (pbuf_copy_partial(p, status_num, (u16_t)status_num_len, space1 + 1) == status_num_len) {
|
||||
int status = atoi(status_num);
|
||||
if ((status > 0) && (status <= 0xFFFF)) {
|
||||
*http_status = (u16_t)status;
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
/** Wait for all headers to be received, return its length and content-length (if available) */
|
||||
static err_t
|
||||
http_wait_headers(struct pbuf *p, u32_t *content_length, u16_t *total_header_len)
|
||||
{
|
||||
u16_t end1 = pbuf_memfind(p, "\r\n\r\n", 4, 0);
|
||||
if (end1 < (0xFFFF - 2)) {
|
||||
/* all headers received */
|
||||
/* check if we have a content length (@todo: case insensitive?) */
|
||||
u16_t content_len_hdr;
|
||||
*content_length = HTTPC_CONTENT_LEN_INVALID;
|
||||
*total_header_len = end1 + 4;
|
||||
|
||||
content_len_hdr = pbuf_memfind(p, "Content-Length: ", 16, 0);
|
||||
if (content_len_hdr != 0xFFFF) {
|
||||
u16_t content_len_line_end = pbuf_memfind(p, "\r\n", 2, content_len_hdr);
|
||||
if (content_len_line_end != 0xFFFF) {
|
||||
char content_len_num[16];
|
||||
u16_t content_len_num_len = (u16_t)(content_len_line_end - content_len_hdr - 16);
|
||||
memset(content_len_num, 0, sizeof(content_len_num));
|
||||
if (pbuf_copy_partial(p, content_len_num, content_len_num_len, content_len_hdr + 16) == content_len_num_len) {
|
||||
int len = atoi(content_len_num);
|
||||
if ((len >= 0) && ((u32_t)len < HTTPC_CONTENT_LEN_INVALID)) {
|
||||
*content_length = (u32_t)len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
/** http client tcp recv callback */
|
||||
static err_t
|
||||
httpc_tcp_recv(void *arg, struct altcp_pcb *pcb, struct pbuf *p, err_t r)
|
||||
{
|
||||
httpc_state_t* req = (httpc_state_t*)arg;
|
||||
LWIP_UNUSED_ARG(r);
|
||||
|
||||
if (p == NULL) {
|
||||
httpc_result_t result;
|
||||
if (req->parse_state != HTTPC_PARSE_RX_DATA) {
|
||||
/* did not get RX data yet */
|
||||
result = HTTPC_RESULT_ERR_CLOSED;
|
||||
} else if ((req->hdr_content_len != HTTPC_CONTENT_LEN_INVALID) &&
|
||||
(req->hdr_content_len != req->rx_content_len)) {
|
||||
/* header has been received with content length but not all data received */
|
||||
result = HTTPC_RESULT_ERR_CONTENT_LEN;
|
||||
} else {
|
||||
/* receiving data and either all data received or no content length header */
|
||||
result = HTTPC_RESULT_OK;
|
||||
}
|
||||
return httpc_close(req, result, req->rx_status, ERR_OK);
|
||||
}
|
||||
if (req->parse_state != HTTPC_PARSE_RX_DATA) {
|
||||
if (req->rx_hdrs == NULL) {
|
||||
req->rx_hdrs = p;
|
||||
} else {
|
||||
pbuf_cat(req->rx_hdrs, p);
|
||||
}
|
||||
if (req->parse_state == HTTPC_PARSE_WAIT_FIRST_LINE) {
|
||||
u16_t status_str_off;
|
||||
err_t err = http_parse_response_status(req->rx_hdrs, &req->rx_http_version, &req->rx_status, &status_str_off);
|
||||
if (err == ERR_OK) {
|
||||
/* don't care status string */
|
||||
req->parse_state = HTTPC_PARSE_WAIT_HEADERS;
|
||||
}
|
||||
}
|
||||
if (req->parse_state == HTTPC_PARSE_WAIT_HEADERS) {
|
||||
u16_t total_header_len;
|
||||
err_t err = http_wait_headers(req->rx_hdrs, &req->hdr_content_len, &total_header_len);
|
||||
if (err == ERR_OK) {
|
||||
struct pbuf *q;
|
||||
/* full header received, send window update for header bytes and call into client callback */
|
||||
altcp_recved(pcb, total_header_len);
|
||||
if (req->conn_settings) {
|
||||
if (req->conn_settings->headers_done_fn) {
|
||||
err = req->conn_settings->headers_done_fn(req, req->callback_arg, req->rx_hdrs, total_header_len, req->hdr_content_len);
|
||||
if (err != ERR_OK) {
|
||||
return httpc_close(req, HTTPC_RESULT_LOCAL_ABORT, req->rx_status, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* hide header bytes in pbuf */
|
||||
q = pbuf_free_header(req->rx_hdrs, total_header_len);
|
||||
p = q;
|
||||
req->rx_hdrs = NULL;
|
||||
/* go on with data */
|
||||
req->parse_state = HTTPC_PARSE_RX_DATA;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((p != NULL) && (req->parse_state == HTTPC_PARSE_RX_DATA)) {
|
||||
req->rx_content_len += p->tot_len;
|
||||
if (req->recv_fn != NULL) {
|
||||
/* directly return here: the connection migth already be aborted from the callback! */
|
||||
return req->recv_fn(req->callback_arg, pcb, p, r);
|
||||
} else {
|
||||
altcp_recved(pcb, p->tot_len);
|
||||
pbuf_free(p);
|
||||
}
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/** http client tcp err callback */
|
||||
static void
|
||||
httpc_tcp_err(void *arg, err_t err)
|
||||
{
|
||||
httpc_state_t* req = (httpc_state_t*)arg;
|
||||
if (req != NULL) {
|
||||
/* pcb has already been deallocated */
|
||||
req->pcb = NULL;
|
||||
httpc_close(req, HTTPC_RESULT_ERR_CLOSED, 0, err);
|
||||
}
|
||||
}
|
||||
|
||||
/** http client tcp poll callback */
|
||||
static err_t
|
||||
httpc_tcp_poll(void *arg, struct altcp_pcb *pcb)
|
||||
{
|
||||
/* implement timeout */
|
||||
httpc_state_t* req = (httpc_state_t*)arg;
|
||||
LWIP_UNUSED_ARG(pcb);
|
||||
if (req != NULL) {
|
||||
if (req->timeout_ticks) {
|
||||
req->timeout_ticks--;
|
||||
}
|
||||
if (!req->timeout_ticks) {
|
||||
return httpc_close(req, HTTPC_RESULT_ERR_TIMEOUT, 0, ERR_OK);
|
||||
}
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/** http client tcp sent callback */
|
||||
static err_t
|
||||
httpc_tcp_sent(void *arg, struct altcp_pcb *pcb, u16_t len)
|
||||
{
|
||||
/* nothing to do here for now */
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_UNUSED_ARG(pcb);
|
||||
LWIP_UNUSED_ARG(len);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/** http client tcp connected callback */
|
||||
static err_t
|
||||
httpc_tcp_connected(void *arg, struct altcp_pcb *pcb, err_t err)
|
||||
{
|
||||
err_t r;
|
||||
httpc_state_t* req = (httpc_state_t*)arg;
|
||||
LWIP_UNUSED_ARG(pcb);
|
||||
LWIP_UNUSED_ARG(err);
|
||||
|
||||
/* send request; last char is zero termination */
|
||||
r = altcp_write(req->pcb, req->request->payload, req->request->len - 1, TCP_WRITE_FLAG_COPY);
|
||||
if (r != ERR_OK) {
|
||||
/* could not write the single small request -> fail, don't retry */
|
||||
return httpc_close(req, HTTPC_RESULT_ERR_MEM, 0, r);
|
||||
}
|
||||
/* everything written, we can free the request */
|
||||
pbuf_free(req->request);
|
||||
req->request = NULL;
|
||||
|
||||
altcp_output(req->pcb);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/** Start the http request when the server IP addr is known */
|
||||
static err_t
|
||||
httpc_get_internal_addr(httpc_state_t* req, const ip_addr_t *ipaddr)
|
||||
{
|
||||
err_t err;
|
||||
LWIP_ASSERT("req != NULL", req != NULL);
|
||||
|
||||
if (&req->remote_addr != ipaddr) {
|
||||
/* fill in remote addr if called externally */
|
||||
req->remote_addr = *ipaddr;
|
||||
}
|
||||
|
||||
err = altcp_connect(req->pcb, &req->remote_addr, req->remote_port, httpc_tcp_connected);
|
||||
if (err == ERR_OK) {
|
||||
return ERR_OK;
|
||||
}
|
||||
LWIP_DEBUGF(HTTPC_DEBUG_WARN_STATE, ("tcp_connect failed: %d\n", (int)err));
|
||||
return err;
|
||||
}
|
||||
|
||||
#if LWIP_DNS
|
||||
/** DNS callback
|
||||
* If ipaddr is non-NULL, resolving succeeded and the request can be sent, otherwise it failed.
|
||||
*/
|
||||
static void
|
||||
httpc_dns_found(const char* hostname, const ip_addr_t *ipaddr, void *arg)
|
||||
{
|
||||
httpc_state_t* req = (httpc_state_t*)arg;
|
||||
err_t err;
|
||||
httpc_result_t result;
|
||||
|
||||
LWIP_UNUSED_ARG(hostname);
|
||||
|
||||
if (ipaddr != NULL) {
|
||||
err = httpc_get_internal_addr(req, ipaddr);
|
||||
if (err == ERR_OK) {
|
||||
return;
|
||||
}
|
||||
result = HTTPC_RESULT_ERR_CONNECT;
|
||||
} else {
|
||||
LWIP_DEBUGF(HTTPC_DEBUG_WARN_STATE, ("httpc_dns_found: failed to resolve hostname: %s\n",
|
||||
hostname));
|
||||
result = HTTPC_RESULT_ERR_HOSTNAME;
|
||||
err = ERR_ARG;
|
||||
}
|
||||
httpc_close(req, result, 0, err);
|
||||
}
|
||||
#endif /* LWIP_DNS */
|
||||
|
||||
/** Start the http request after converting 'server_name' to ip address (DNS or address string) */
|
||||
static err_t
|
||||
httpc_get_internal_dns(httpc_state_t* req, const char* server_name)
|
||||
{
|
||||
err_t err;
|
||||
LWIP_ASSERT("req != NULL", req != NULL);
|
||||
|
||||
#if LWIP_DNS
|
||||
err = dns_gethostbyname(server_name, &req->remote_addr, httpc_dns_found, req);
|
||||
#else
|
||||
err = ipaddr_aton(server_name, &req->remote_addr) ? ERR_OK : ERR_ARG;
|
||||
#endif
|
||||
|
||||
if (err == ERR_OK) {
|
||||
/* cached or IP-string */
|
||||
err = httpc_get_internal_addr(req, &req->remote_addr);
|
||||
} else if (err == ERR_INPROGRESS) {
|
||||
return ERR_OK;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
httpc_create_request_string(const httpc_connection_t *settings, const char* server_name, int server_port, const char* uri,
|
||||
int use_host, char *buffer, size_t buffer_size)
|
||||
{
|
||||
if (settings->use_proxy) {
|
||||
LWIP_ASSERT("server_name != NULL", server_name != NULL);
|
||||
if (server_port != HTTP_DEFAULT_PORT) {
|
||||
return snprintf(buffer, buffer_size, HTTPC_REQ_11_PROXY_PORT_FORMAT(server_name, server_port, uri, server_name));
|
||||
} else {
|
||||
return snprintf(buffer, buffer_size, HTTPC_REQ_11_PROXY_FORMAT(server_name, uri, server_name));
|
||||
}
|
||||
} else if (use_host) {
|
||||
LWIP_ASSERT("server_name != NULL", server_name != NULL);
|
||||
return snprintf(buffer, buffer_size, HTTPC_REQ_11_HOST_FORMAT(uri, server_name));
|
||||
} else {
|
||||
return snprintf(buffer, buffer_size, HTTPC_REQ_11_FORMAT(uri));
|
||||
}
|
||||
}
|
||||
|
||||
/** Initialize the connection struct */
|
||||
static err_t
|
||||
httpc_init_connection_common(httpc_state_t **connection, const httpc_connection_t *settings, const char* server_name,
|
||||
u16_t server_port, const char* uri, altcp_recv_fn recv_fn, void* callback_arg, int use_host)
|
||||
{
|
||||
size_t alloc_len;
|
||||
mem_size_t mem_alloc_len;
|
||||
int req_len, req_len2;
|
||||
httpc_state_t *req;
|
||||
#if HTTPC_DEBUG_REQUEST
|
||||
size_t server_name_len, uri_len;
|
||||
#endif
|
||||
|
||||
LWIP_ASSERT("uri != NULL", uri != NULL);
|
||||
|
||||
/* get request len */
|
||||
req_len = httpc_create_request_string(settings, server_name, server_port, uri, use_host, NULL, 0);
|
||||
if ((req_len < 0) || (req_len > 0xFFFF)) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
/* alloc state and request in one block */
|
||||
alloc_len = sizeof(httpc_state_t);
|
||||
#if HTTPC_DEBUG_REQUEST
|
||||
server_name_len = server_name ? strlen(server_name) : 0;
|
||||
uri_len = strlen(uri);
|
||||
alloc_len += server_name_len + 1 + uri_len + 1;
|
||||
#endif
|
||||
mem_alloc_len = (mem_size_t)alloc_len;
|
||||
if ((mem_alloc_len < alloc_len) || (req_len + 1 > 0xFFFF)) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
req = (httpc_state_t*)mem_malloc((mem_size_t)alloc_len);
|
||||
if(req == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
memset(req, 0, sizeof(httpc_state_t));
|
||||
req->timeout_ticks = HTTPC_POLL_TIMEOUT;
|
||||
req->request = pbuf_alloc(PBUF_RAW, (u16_t)(req_len + 1), PBUF_RAM);
|
||||
if (req->request == NULL) {
|
||||
httpc_free_state(req);
|
||||
return ERR_MEM;
|
||||
}
|
||||
if (req->request->next != NULL) {
|
||||
/* need a pbuf in one piece */
|
||||
httpc_free_state(req);
|
||||
return ERR_MEM;
|
||||
}
|
||||
req->hdr_content_len = HTTPC_CONTENT_LEN_INVALID;
|
||||
#if HTTPC_DEBUG_REQUEST
|
||||
req->server_name = (char*)(req + 1);
|
||||
if (server_name) {
|
||||
memcpy(req->server_name, server_name, server_name_len + 1);
|
||||
}
|
||||
req->uri = req->server_name + server_name_len + 1;
|
||||
memcpy(req->uri, uri, uri_len + 1);
|
||||
#endif
|
||||
req->pcb = altcp_new(settings->altcp_allocator);
|
||||
if(req->pcb == NULL) {
|
||||
httpc_free_state(req);
|
||||
return ERR_MEM;
|
||||
}
|
||||
req->remote_port = settings->use_proxy ? settings->proxy_port : server_port;
|
||||
altcp_arg(req->pcb, req);
|
||||
altcp_recv(req->pcb, httpc_tcp_recv);
|
||||
altcp_err(req->pcb, httpc_tcp_err);
|
||||
altcp_poll(req->pcb, httpc_tcp_poll, HTTPC_POLL_INTERVAL);
|
||||
altcp_sent(req->pcb, httpc_tcp_sent);
|
||||
|
||||
/* set up request buffer */
|
||||
req_len2 = httpc_create_request_string(settings, server_name, server_port, uri, use_host,
|
||||
(char *)req->request->payload, req_len + 1);
|
||||
if (req_len2 != req_len) {
|
||||
httpc_free_state(req);
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
req->recv_fn = recv_fn;
|
||||
req->conn_settings = settings;
|
||||
req->callback_arg = callback_arg;
|
||||
|
||||
*connection = req;
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the connection struct
|
||||
*/
|
||||
static err_t
|
||||
httpc_init_connection(httpc_state_t **connection, const httpc_connection_t *settings, const char* server_name,
|
||||
u16_t server_port, const char* uri, altcp_recv_fn recv_fn, void* callback_arg)
|
||||
{
|
||||
return httpc_init_connection_common(connection, settings, server_name, server_port, uri, recv_fn, callback_arg, 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the connection struct (from IP address)
|
||||
*/
|
||||
static err_t
|
||||
httpc_init_connection_addr(httpc_state_t **connection, const httpc_connection_t *settings,
|
||||
const ip_addr_t* server_addr, u16_t server_port, const char* uri,
|
||||
altcp_recv_fn recv_fn, void* callback_arg)
|
||||
{
|
||||
char *server_addr_str = ipaddr_ntoa(server_addr);
|
||||
if (server_addr_str == NULL) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
return httpc_init_connection_common(connection, settings, server_addr_str, server_port, uri,
|
||||
recv_fn, callback_arg, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup httpc
|
||||
* HTTP client API: get a file by passing server IP address
|
||||
*
|
||||
* @param server_addr IP address of the server to connect
|
||||
* @param port tcp port of the server
|
||||
* @param uri uri to get from the server, remember leading "/"!
|
||||
* @param settings connection settings (callbacks, proxy, etc.)
|
||||
* @param recv_fn the http body (not the headers) are passed to this callback
|
||||
* @param callback_arg argument passed to all the callbacks
|
||||
* @param connection retreives the connection handle (to match in callbacks)
|
||||
* @return ERR_OK if starting the request succeeds (callback_fn will be called later)
|
||||
* or an error code
|
||||
*/
|
||||
err_t
|
||||
httpc_get_file(const ip_addr_t* server_addr, u16_t port, const char* uri, const httpc_connection_t *settings,
|
||||
altcp_recv_fn recv_fn, void* callback_arg, httpc_state_t **connection)
|
||||
{
|
||||
err_t err;
|
||||
httpc_state_t* req;
|
||||
|
||||
LWIP_ERROR("invalid parameters", (server_addr != NULL) && (uri != NULL) && (recv_fn != NULL), return ERR_ARG;);
|
||||
|
||||
err = httpc_init_connection_addr(&req, settings, server_addr, port,
|
||||
uri, recv_fn, callback_arg);
|
||||
if (err != ERR_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (settings->use_proxy) {
|
||||
err = httpc_get_internal_addr(req, &settings->proxy_addr);
|
||||
} else {
|
||||
err = httpc_get_internal_addr(req, server_addr);
|
||||
}
|
||||
if(err != ERR_OK) {
|
||||
httpc_free_state(req);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (connection != NULL) {
|
||||
*connection = req;
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup httpc
|
||||
* HTTP client API: get a file by passing server name as string (DNS name or IP address string)
|
||||
*
|
||||
* @param server_name server name as string (DNS name or IP address string)
|
||||
* @param port tcp port of the server
|
||||
* @param uri uri to get from the server, remember leading "/"!
|
||||
* @param settings connection settings (callbacks, proxy, etc.)
|
||||
* @param recv_fn the http body (not the headers) are passed to this callback
|
||||
* @param callback_arg argument passed to all the callbacks
|
||||
* @param connection retreives the connection handle (to match in callbacks)
|
||||
* @return ERR_OK if starting the request succeeds (callback_fn will be called later)
|
||||
* or an error code
|
||||
*/
|
||||
err_t
|
||||
httpc_get_file_dns(const char* server_name, u16_t port, const char* uri, const httpc_connection_t *settings,
|
||||
altcp_recv_fn recv_fn, void* callback_arg, httpc_state_t **connection)
|
||||
{
|
||||
err_t err;
|
||||
httpc_state_t* req;
|
||||
|
||||
LWIP_ERROR("invalid parameters", (server_name != NULL) && (uri != NULL) && (recv_fn != NULL), return ERR_ARG;);
|
||||
|
||||
err = httpc_init_connection(&req, settings, server_name, port, uri, recv_fn, callback_arg);
|
||||
if (err != ERR_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (settings->use_proxy) {
|
||||
err = httpc_get_internal_addr(req, &settings->proxy_addr);
|
||||
} else {
|
||||
err = httpc_get_internal_dns(req, server_name);
|
||||
}
|
||||
if(err != ERR_OK) {
|
||||
httpc_free_state(req);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (connection != NULL) {
|
||||
*connection = req;
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
#if LWIP_HTTPC_HAVE_FILE_IO
|
||||
/* Implementation to disk via fopen/fwrite/fclose follows */
|
||||
|
||||
typedef struct _httpc_filestate
|
||||
{
|
||||
const char* local_file_name;
|
||||
FILE *file;
|
||||
httpc_connection_t settings;
|
||||
const httpc_connection_t *client_settings;
|
||||
void *callback_arg;
|
||||
} httpc_filestate_t;
|
||||
|
||||
static void httpc_fs_result(void *arg, httpc_result_t httpc_result, u32_t rx_content_len,
|
||||
u32_t srv_res, err_t err);
|
||||
|
||||
/** Initalize http client state for download to file system */
|
||||
static err_t
|
||||
httpc_fs_init(httpc_filestate_t **filestate_out, const char* local_file_name,
|
||||
const httpc_connection_t *settings, void* callback_arg)
|
||||
{
|
||||
httpc_filestate_t *filestate;
|
||||
size_t file_len, alloc_len;
|
||||
FILE *f;
|
||||
|
||||
file_len = strlen(local_file_name);
|
||||
alloc_len = sizeof(httpc_filestate_t) + file_len + 1;
|
||||
|
||||
filestate = (httpc_filestate_t *)mem_malloc((mem_size_t)alloc_len);
|
||||
if (filestate == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
memset(filestate, 0, sizeof(httpc_filestate_t));
|
||||
filestate->local_file_name = (const char *)(filestate + 1);
|
||||
memcpy((char *)(filestate + 1), local_file_name, file_len + 1);
|
||||
filestate->file = NULL;
|
||||
filestate->client_settings = settings;
|
||||
filestate->callback_arg = callback_arg;
|
||||
/* copy client settings but override result callback */
|
||||
memcpy(&filestate->settings, settings, sizeof(httpc_connection_t));
|
||||
filestate->settings.result_fn = httpc_fs_result;
|
||||
|
||||
f = fopen(local_file_name, "wb");
|
||||
if(f == NULL) {
|
||||
/* could not open file */
|
||||
mem_free(filestate);
|
||||
return ERR_VAL;
|
||||
}
|
||||
filestate->file = f;
|
||||
*filestate_out = filestate;
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/** Free http client state for download to file system */
|
||||
static void
|
||||
httpc_fs_free(httpc_filestate_t *filestate)
|
||||
{
|
||||
if (filestate != NULL) {
|
||||
if (filestate->file != NULL) {
|
||||
fclose(filestate->file);
|
||||
filestate->file = NULL;
|
||||
}
|
||||
mem_free(filestate);
|
||||
}
|
||||
}
|
||||
|
||||
/** Connection closed (success or error) */
|
||||
static void
|
||||
httpc_fs_result(void *arg, httpc_result_t httpc_result, u32_t rx_content_len,
|
||||
u32_t srv_res, err_t err)
|
||||
{
|
||||
httpc_filestate_t *filestate = (httpc_filestate_t *)arg;
|
||||
if (filestate != NULL) {
|
||||
if (filestate->client_settings->result_fn != NULL) {
|
||||
filestate->client_settings->result_fn(filestate->callback_arg, httpc_result, rx_content_len,
|
||||
srv_res, err);
|
||||
}
|
||||
httpc_fs_free(filestate);
|
||||
}
|
||||
}
|
||||
|
||||
/** tcp recv callback */
|
||||
static err_t
|
||||
httpc_fs_tcp_recv(void *arg, struct altcp_pcb *pcb, struct pbuf *p, err_t err)
|
||||
{
|
||||
httpc_filestate_t *filestate = (httpc_filestate_t*)arg;
|
||||
struct pbuf* q;
|
||||
LWIP_UNUSED_ARG(err);
|
||||
|
||||
LWIP_ASSERT("p != NULL", p != NULL);
|
||||
|
||||
for (q = p; q != NULL; q = q->next) {
|
||||
fwrite(q->payload, 1, q->len, filestate->file);
|
||||
}
|
||||
altcp_recved(pcb, p->tot_len);
|
||||
pbuf_free(p);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup httpc
|
||||
* HTTP client API: get a file to disk by passing server IP address
|
||||
*
|
||||
* @param server_addr IP address of the server to connect
|
||||
* @param port tcp port of the server
|
||||
* @param uri uri to get from the server, remember leading "/"!
|
||||
* @param settings connection settings (callbacks, proxy, etc.)
|
||||
* @param callback_arg argument passed to all the callbacks
|
||||
* @param connection retreives the connection handle (to match in callbacks)
|
||||
* @return ERR_OK if starting the request succeeds (callback_fn will be called later)
|
||||
* or an error code
|
||||
*/
|
||||
err_t
|
||||
httpc_get_file_to_disk(const ip_addr_t* server_addr, u16_t port, const char* uri, const httpc_connection_t *settings,
|
||||
void* callback_arg, const char* local_file_name, httpc_state_t **connection)
|
||||
{
|
||||
err_t err;
|
||||
httpc_state_t* req;
|
||||
httpc_filestate_t *filestate;
|
||||
|
||||
LWIP_ERROR("invalid parameters", (server_addr != NULL) && (uri != NULL) && (local_file_name != NULL), return ERR_ARG;);
|
||||
|
||||
err = httpc_fs_init(&filestate, local_file_name, settings, callback_arg);
|
||||
if (err != ERR_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = httpc_init_connection_addr(&req, &filestate->settings, server_addr, port,
|
||||
uri, httpc_fs_tcp_recv, filestate);
|
||||
if (err != ERR_OK) {
|
||||
httpc_fs_free(filestate);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (settings->use_proxy) {
|
||||
err = httpc_get_internal_addr(req, &settings->proxy_addr);
|
||||
} else {
|
||||
err = httpc_get_internal_addr(req, server_addr);
|
||||
}
|
||||
if(err != ERR_OK) {
|
||||
httpc_fs_free(filestate);
|
||||
httpc_free_state(req);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (connection != NULL) {
|
||||
*connection = req;
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup httpc
|
||||
* HTTP client API: get a file to disk by passing server name as string (DNS name or IP address string)
|
||||
*
|
||||
* @param server_name server name as string (DNS name or IP address string)
|
||||
* @param port tcp port of the server
|
||||
* @param uri uri to get from the server, remember leading "/"!
|
||||
* @param settings connection settings (callbacks, proxy, etc.)
|
||||
* @param callback_arg argument passed to all the callbacks
|
||||
* @param connection retreives the connection handle (to match in callbacks)
|
||||
* @return ERR_OK if starting the request succeeds (callback_fn will be called later)
|
||||
* or an error code
|
||||
*/
|
||||
err_t
|
||||
httpc_get_file_dns_to_disk(const char* server_name, u16_t port, const char* uri, const httpc_connection_t *settings,
|
||||
void* callback_arg, const char* local_file_name, httpc_state_t **connection)
|
||||
{
|
||||
err_t err;
|
||||
httpc_state_t* req;
|
||||
httpc_filestate_t *filestate;
|
||||
|
||||
LWIP_ERROR("invalid parameters", (server_name != NULL) && (uri != NULL) && (local_file_name != NULL), return ERR_ARG;);
|
||||
|
||||
err = httpc_fs_init(&filestate, local_file_name, settings, callback_arg);
|
||||
if (err != ERR_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = httpc_init_connection(&req, &filestate->settings, server_name, port,
|
||||
uri, httpc_fs_tcp_recv, filestate);
|
||||
if (err != ERR_OK) {
|
||||
httpc_fs_free(filestate);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (settings->use_proxy) {
|
||||
err = httpc_get_internal_addr(req, &settings->proxy_addr);
|
||||
} else {
|
||||
err = httpc_get_internal_dns(req, server_name);
|
||||
}
|
||||
if(err != ERR_OK) {
|
||||
httpc_fs_free(filestate);
|
||||
httpc_free_state(req);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (connection != NULL) {
|
||||
*connection = req;
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif /* LWIP_HTTPC_HAVE_FILE_IO */
|
||||
|
||||
#endif /* LWIP_TCP && LWIP_CALLBACK_API */
|
||||
File diff suppressed because it is too large
Load Diff
123
src/apps/http/httpd_structs.h
Normal file
123
src/apps/http/httpd_structs.h
Normal file
@@ -0,0 +1,123 @@
|
||||
#ifndef LWIP_HTTPD_STRUCTS_H
|
||||
#define LWIP_HTTPD_STRUCTS_H
|
||||
|
||||
#include "lwip/apps/httpd.h"
|
||||
|
||||
#if LWIP_HTTPD_DYNAMIC_HEADERS
|
||||
/** This struct is used for a list of HTTP header strings for various
|
||||
* filename extensions. */
|
||||
typedef struct {
|
||||
const char *extension;
|
||||
const char *content_type;
|
||||
} tHTTPHeader;
|
||||
|
||||
/** A list of strings used in HTTP headers (see RFC 1945 HTTP/1.0 and
|
||||
* RFC 2616 HTTP/1.1 for header field definitions) */
|
||||
static const char *const g_psHTTPHeaderStrings[] = {
|
||||
"HTTP/1.0 200 OK\r\n",
|
||||
"HTTP/1.0 404 File not found\r\n",
|
||||
"HTTP/1.0 400 Bad Request\r\n",
|
||||
"HTTP/1.0 501 Not Implemented\r\n",
|
||||
"HTTP/1.1 200 OK\r\n",
|
||||
"HTTP/1.1 404 File not found\r\n",
|
||||
"HTTP/1.1 400 Bad Request\r\n",
|
||||
"HTTP/1.1 501 Not Implemented\r\n",
|
||||
"Content-Length: ",
|
||||
"Connection: Close\r\n",
|
||||
"Connection: keep-alive\r\n",
|
||||
"Connection: keep-alive\r\nContent-Length: ",
|
||||
"Server: "HTTPD_SERVER_AGENT"\r\n",
|
||||
"\r\n<html><body><h2>404: The requested file cannot be found.</h2></body></html>\r\n"
|
||||
#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
|
||||
, "Connection: keep-alive\r\nContent-Length: 77\r\n\r\n<html><body><h2>404: The requested file cannot be found.</h2></body></html>\r\n"
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Indexes into the g_psHTTPHeaderStrings array */
|
||||
#define HTTP_HDR_OK 0 /* 200 OK */
|
||||
#define HTTP_HDR_NOT_FOUND 1 /* 404 File not found */
|
||||
#define HTTP_HDR_BAD_REQUEST 2 /* 400 Bad request */
|
||||
#define HTTP_HDR_NOT_IMPL 3 /* 501 Not Implemented */
|
||||
#define HTTP_HDR_OK_11 4 /* 200 OK */
|
||||
#define HTTP_HDR_NOT_FOUND_11 5 /* 404 File not found */
|
||||
#define HTTP_HDR_BAD_REQUEST_11 6 /* 400 Bad request */
|
||||
#define HTTP_HDR_NOT_IMPL_11 7 /* 501 Not Implemented */
|
||||
#define HTTP_HDR_CONTENT_LENGTH 8 /* Content-Length: (HTTP 1.0)*/
|
||||
#define HTTP_HDR_CONN_CLOSE 9 /* Connection: Close (HTTP 1.1) */
|
||||
#define HTTP_HDR_CONN_KEEPALIVE 10 /* Connection: keep-alive (HTTP 1.1) */
|
||||
#define HTTP_HDR_KEEPALIVE_LEN 11 /* Connection: keep-alive + Content-Length: (HTTP 1.1)*/
|
||||
#define HTTP_HDR_SERVER 12 /* Server: HTTPD_SERVER_AGENT */
|
||||
#define DEFAULT_404_HTML 13 /* default 404 body */
|
||||
#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
|
||||
#define DEFAULT_404_HTML_PERSISTENT 14 /* default 404 body, but including Connection: keep-alive */
|
||||
#endif
|
||||
|
||||
#define HTTP_CONTENT_TYPE(contenttype) "Content-Type: "contenttype"\r\n\r\n"
|
||||
#define HTTP_CONTENT_TYPE_ENCODING(contenttype, encoding) "Content-Type: "contenttype"\r\nContent-Encoding: "encoding"\r\n\r\n"
|
||||
|
||||
#define HTTP_HDR_HTML HTTP_CONTENT_TYPE("text/html")
|
||||
#define HTTP_HDR_SSI HTTP_CONTENT_TYPE("text/html\r\nExpires: Fri, 10 Apr 2008 14:00:00 GMT\r\nPragma: no-cache")
|
||||
#define HTTP_HDR_GIF HTTP_CONTENT_TYPE("image/gif")
|
||||
#define HTTP_HDR_PNG HTTP_CONTENT_TYPE("image/png")
|
||||
#define HTTP_HDR_JPG HTTP_CONTENT_TYPE("image/jpeg")
|
||||
#define HTTP_HDR_BMP HTTP_CONTENT_TYPE("image/bmp")
|
||||
#define HTTP_HDR_ICO HTTP_CONTENT_TYPE("image/x-icon")
|
||||
#define HTTP_HDR_APP HTTP_CONTENT_TYPE("application/octet-stream")
|
||||
#define HTTP_HDR_JS HTTP_CONTENT_TYPE("application/javascript")
|
||||
#define HTTP_HDR_RA HTTP_CONTENT_TYPE("application/javascript")
|
||||
#define HTTP_HDR_CSS HTTP_CONTENT_TYPE("text/css")
|
||||
#define HTTP_HDR_SWF HTTP_CONTENT_TYPE("application/x-shockwave-flash")
|
||||
#define HTTP_HDR_XML HTTP_CONTENT_TYPE("text/xml")
|
||||
#define HTTP_HDR_PDF HTTP_CONTENT_TYPE("application/pdf")
|
||||
#define HTTP_HDR_JSON HTTP_CONTENT_TYPE("application/json")
|
||||
#define HTTP_HDR_CSV HTTP_CONTENT_TYPE("text/csv")
|
||||
#define HTTP_HDR_TSV HTTP_CONTENT_TYPE("text/tsv")
|
||||
#define HTTP_HDR_SVG HTTP_CONTENT_TYPE("image/svg+xml")
|
||||
#define HTTP_HDR_SVGZ HTTP_CONTENT_TYPE_ENCODING("image/svg+xml", "gzip")
|
||||
|
||||
#define HTTP_HDR_DEFAULT_TYPE HTTP_CONTENT_TYPE("text/plain")
|
||||
|
||||
/** A list of extension-to-HTTP header strings (see outdated RFC 1700 MEDIA TYPES
|
||||
* and http://www.iana.org/assignments/media-types for registered content types
|
||||
* and subtypes) */
|
||||
static const tHTTPHeader g_psHTTPHeaders[] = {
|
||||
{ "html", HTTP_HDR_HTML},
|
||||
{ "htm", HTTP_HDR_HTML},
|
||||
{ "shtml", HTTP_HDR_SSI},
|
||||
{ "shtm", HTTP_HDR_SSI},
|
||||
{ "ssi", HTTP_HDR_SSI},
|
||||
{ "gif", HTTP_HDR_GIF},
|
||||
{ "png", HTTP_HDR_PNG},
|
||||
{ "jpg", HTTP_HDR_JPG},
|
||||
{ "bmp", HTTP_HDR_BMP},
|
||||
{ "ico", HTTP_HDR_ICO},
|
||||
{ "class", HTTP_HDR_APP},
|
||||
{ "cls", HTTP_HDR_APP},
|
||||
{ "js", HTTP_HDR_JS},
|
||||
{ "ram", HTTP_HDR_RA},
|
||||
{ "css", HTTP_HDR_CSS},
|
||||
{ "swf", HTTP_HDR_SWF},
|
||||
{ "xml", HTTP_HDR_XML},
|
||||
{ "xsl", HTTP_HDR_XML},
|
||||
{ "pdf", HTTP_HDR_PDF},
|
||||
{ "json", HTTP_HDR_JSON}
|
||||
#ifdef HTTPD_ADDITIONAL_CONTENT_TYPES
|
||||
/* If you need to add content types not listed here:
|
||||
* #define HTTPD_ADDITIONAL_CONTENT_TYPES {"ct1", HTTP_CONTENT_TYPE("text/ct1")}, {"exe", HTTP_CONTENT_TYPE("application/exe")}
|
||||
*/
|
||||
, HTTPD_ADDITIONAL_CONTENT_TYPES
|
||||
#endif
|
||||
};
|
||||
|
||||
#define NUM_HTTP_HEADERS LWIP_ARRAYSIZE(g_psHTTPHeaders)
|
||||
|
||||
#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
|
||||
|
||||
#if LWIP_HTTPD_SSI
|
||||
static const char *const g_pcSSIExtensions[] = {
|
||||
".shtml", ".shtm", ".ssi", ".xml", ".json"
|
||||
};
|
||||
#define NUM_SHTML_EXTENSIONS LWIP_ARRAYSIZE(g_pcSSIExtensions)
|
||||
#endif /* LWIP_HTTPD_SSI */
|
||||
|
||||
#endif /* LWIP_HTTPD_STRUCTS_H */
|
||||
File diff suppressed because it is too large
Load Diff
808
src/apps/http/makefsdata/tinydir.h
Normal file
808
src/apps/http/makefsdata/tinydir.h
Normal file
@@ -0,0 +1,808 @@
|
||||
/*
|
||||
Copyright (c) 2013-2017, tinydir authors:
|
||||
- Cong Xu
|
||||
- Lautis Sun
|
||||
- Baudouin Feildel
|
||||
- Andargor <andargor@yahoo.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.
|
||||
|
||||
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 OWNER 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 TINYDIR_H
|
||||
#define TINYDIR_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if ((defined _UNICODE) && !(defined UNICODE))
|
||||
#define UNICODE
|
||||
#endif
|
||||
|
||||
#if ((defined UNICODE) && !(defined _UNICODE))
|
||||
#define _UNICODE
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef _MSC_VER
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
# include <tchar.h>
|
||||
# pragma warning(push)
|
||||
# pragma warning (disable : 4996)
|
||||
#else
|
||||
# include <dirent.h>
|
||||
# include <libgen.h>
|
||||
# include <sys/stat.h>
|
||||
# include <stddef.h>
|
||||
#endif
|
||||
#ifdef __MINGW32__
|
||||
# include <tchar.h>
|
||||
#endif
|
||||
|
||||
|
||||
/* types */
|
||||
|
||||
/* Windows UNICODE wide character support */
|
||||
#if defined _MSC_VER || defined __MINGW32__
|
||||
#define _tinydir_char_t TCHAR
|
||||
#define TINYDIR_STRING(s) _TEXT(s)
|
||||
#define _tinydir_strlen _tcslen
|
||||
#define _tinydir_strcpy _tcscpy
|
||||
#define _tinydir_strcat _tcscat
|
||||
#define _tinydir_strcmp _tcscmp
|
||||
#define _tinydir_strrchr _tcsrchr
|
||||
#define _tinydir_strncmp _tcsncmp
|
||||
#else
|
||||
#define _tinydir_char_t char
|
||||
#define TINYDIR_STRING(s) s
|
||||
#define _tinydir_strlen strlen
|
||||
#define _tinydir_strcpy strcpy
|
||||
#define _tinydir_strcat strcat
|
||||
#define _tinydir_strcmp strcmp
|
||||
#define _tinydir_strrchr strrchr
|
||||
#define _tinydir_strncmp strncmp
|
||||
#endif
|
||||
|
||||
#if (defined _MSC_VER || defined __MINGW32__)
|
||||
#include <windows.h>
|
||||
#define _TINYDIR_PATH_MAX MAX_PATH
|
||||
#elif defined __linux__
|
||||
#include <linux/limits.h>
|
||||
#define _TINYDIR_PATH_MAX PATH_MAX
|
||||
#else
|
||||
#define _TINYDIR_PATH_MAX 4096
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
/* extra chars for the "\\*" mask */
|
||||
# define _TINYDIR_PATH_EXTRA 2
|
||||
#else
|
||||
# define _TINYDIR_PATH_EXTRA 0
|
||||
#endif
|
||||
|
||||
#define _TINYDIR_FILENAME_MAX 256
|
||||
|
||||
#if (defined _MSC_VER || defined __MINGW32__)
|
||||
#define _TINYDIR_DRIVE_MAX 3
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define _TINYDIR_FUNC static __inline
|
||||
#elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
|
||||
# define _TINYDIR_FUNC static __inline__
|
||||
#else
|
||||
# define _TINYDIR_FUNC static inline
|
||||
#endif
|
||||
|
||||
/* readdir_r usage; define TINYDIR_USE_READDIR_R to use it (if supported) */
|
||||
#ifdef TINYDIR_USE_READDIR_R
|
||||
|
||||
/* readdir_r is a POSIX-only function, and may not be available under various
|
||||
* environments/settings, e.g. MinGW. Use readdir fallback */
|
||||
#if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE ||\
|
||||
_POSIX_SOURCE
|
||||
# define _TINYDIR_HAS_READDIR_R
|
||||
#endif
|
||||
#if _POSIX_C_SOURCE >= 200112L
|
||||
# define _TINYDIR_HAS_FPATHCONF
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#if _BSD_SOURCE || _SVID_SOURCE || \
|
||||
(_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700)
|
||||
# define _TINYDIR_HAS_DIRFD
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
#if defined _TINYDIR_HAS_FPATHCONF && defined _TINYDIR_HAS_DIRFD &&\
|
||||
defined _PC_NAME_MAX
|
||||
# define _TINYDIR_USE_FPATHCONF
|
||||
#endif
|
||||
#if defined __MINGW32__ || !defined _TINYDIR_HAS_READDIR_R ||\
|
||||
!(defined _TINYDIR_USE_FPATHCONF || defined NAME_MAX)
|
||||
# define _TINYDIR_USE_READDIR
|
||||
#endif
|
||||
|
||||
/* Use readdir by default */
|
||||
#else
|
||||
# define _TINYDIR_USE_READDIR
|
||||
#endif
|
||||
|
||||
/* MINGW32 has two versions of dirent, ASCII and UNICODE*/
|
||||
#ifndef _MSC_VER
|
||||
#if (defined __MINGW32__) && (defined _UNICODE)
|
||||
#define _TINYDIR_DIR _WDIR
|
||||
#define _tinydir_dirent _wdirent
|
||||
#define _tinydir_opendir _wopendir
|
||||
#define _tinydir_readdir _wreaddir
|
||||
#define _tinydir_closedir _wclosedir
|
||||
#else
|
||||
#define _TINYDIR_DIR DIR
|
||||
#define _tinydir_dirent dirent
|
||||
#define _tinydir_opendir opendir
|
||||
#define _tinydir_readdir readdir
|
||||
#define _tinydir_closedir closedir
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Allow user to use a custom allocator by defining _TINYDIR_MALLOC and _TINYDIR_FREE. */
|
||||
#if defined(_TINYDIR_MALLOC) && defined(_TINYDIR_FREE)
|
||||
#elif !defined(_TINYDIR_MALLOC) && !defined(_TINYDIR_FREE)
|
||||
#else
|
||||
#error "Either define both alloc and free or none of them!"
|
||||
#endif
|
||||
|
||||
#if !defined(_TINYDIR_MALLOC)
|
||||
#define _TINYDIR_MALLOC(_size) malloc(_size)
|
||||
#define _TINYDIR_FREE(_ptr) free(_ptr)
|
||||
#endif /* !defined(_TINYDIR_MALLOC) */
|
||||
|
||||
typedef struct tinydir_file
|
||||
{
|
||||
_tinydir_char_t path[_TINYDIR_PATH_MAX];
|
||||
_tinydir_char_t name[_TINYDIR_FILENAME_MAX];
|
||||
_tinydir_char_t *extension;
|
||||
int is_dir;
|
||||
int is_reg;
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#ifdef __MINGW32__
|
||||
struct _stat _s;
|
||||
#else
|
||||
struct stat _s;
|
||||
#endif
|
||||
#endif
|
||||
} tinydir_file;
|
||||
|
||||
typedef struct tinydir_dir
|
||||
{
|
||||
_tinydir_char_t path[_TINYDIR_PATH_MAX];
|
||||
int has_next;
|
||||
size_t n_files;
|
||||
|
||||
tinydir_file *_files;
|
||||
#ifdef _MSC_VER
|
||||
HANDLE _h;
|
||||
WIN32_FIND_DATA _f;
|
||||
#else
|
||||
_TINYDIR_DIR *_d;
|
||||
struct _tinydir_dirent *_e;
|
||||
#ifndef _TINYDIR_USE_READDIR
|
||||
struct _tinydir_dirent *_ep;
|
||||
#endif
|
||||
#endif
|
||||
} tinydir_dir;
|
||||
|
||||
|
||||
/* declarations */
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path);
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path);
|
||||
_TINYDIR_FUNC
|
||||
void tinydir_close(tinydir_dir *dir);
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_next(tinydir_dir *dir);
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file);
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i);
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_open_subdir_n(tinydir_dir *dir, size_t i);
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path);
|
||||
_TINYDIR_FUNC
|
||||
void _tinydir_get_ext(tinydir_file *file);
|
||||
_TINYDIR_FUNC
|
||||
int _tinydir_file_cmp(const void *a, const void *b);
|
||||
#ifndef _MSC_VER
|
||||
#ifndef _TINYDIR_USE_READDIR
|
||||
_TINYDIR_FUNC
|
||||
size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/* definitions*/
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path)
|
||||
{
|
||||
#ifndef _MSC_VER
|
||||
#ifndef _TINYDIR_USE_READDIR
|
||||
int error;
|
||||
int size; /* using int size */
|
||||
#endif
|
||||
#else
|
||||
_tinydir_char_t path_buf[_TINYDIR_PATH_MAX];
|
||||
#endif
|
||||
_tinydir_char_t *pathp;
|
||||
|
||||
if (dir == NULL || path == NULL || _tinydir_strlen(path) == 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
|
||||
{
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* initialise dir */
|
||||
dir->_files = NULL;
|
||||
#ifdef _MSC_VER
|
||||
dir->_h = INVALID_HANDLE_VALUE;
|
||||
#else
|
||||
dir->_d = NULL;
|
||||
#ifndef _TINYDIR_USE_READDIR
|
||||
dir->_ep = NULL;
|
||||
#endif
|
||||
#endif
|
||||
tinydir_close(dir);
|
||||
|
||||
_tinydir_strcpy(dir->path, path);
|
||||
/* Remove trailing slashes */
|
||||
pathp = &dir->path[_tinydir_strlen(dir->path) - 1];
|
||||
while (pathp != dir->path && (*pathp == TINYDIR_STRING('\\') || *pathp == TINYDIR_STRING('/')))
|
||||
{
|
||||
*pathp = TINYDIR_STRING('\0');
|
||||
pathp++;
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
_tinydir_strcpy(path_buf, dir->path);
|
||||
_tinydir_strcat(path_buf, TINYDIR_STRING("\\*"));
|
||||
#if (defined WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP)
|
||||
dir->_h = FindFirstFileEx(path_buf, FindExInfoStandard, &dir->_f, FindExSearchNameMatch, NULL, 0);
|
||||
#else
|
||||
dir->_h = FindFirstFile(path_buf, &dir->_f);
|
||||
#endif
|
||||
if (dir->_h == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
errno = ENOENT;
|
||||
#else
|
||||
dir->_d = _tinydir_opendir(path);
|
||||
if (dir->_d == NULL)
|
||||
{
|
||||
#endif
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* read first file */
|
||||
dir->has_next = 1;
|
||||
#ifndef _MSC_VER
|
||||
#ifdef _TINYDIR_USE_READDIR
|
||||
dir->_e = _tinydir_readdir(dir->_d);
|
||||
#else
|
||||
/* allocate dirent buffer for readdir_r */
|
||||
size = _tinydir_dirent_buf_size(dir->_d); /* conversion to int */
|
||||
if (size == -1) return -1;
|
||||
dir->_ep = (struct _tinydir_dirent*)_TINYDIR_MALLOC(size);
|
||||
if (dir->_ep == NULL) return -1;
|
||||
|
||||
error = readdir_r(dir->_d, dir->_ep, &dir->_e);
|
||||
if (error != 0) return -1;
|
||||
#endif
|
||||
if (dir->_e == NULL)
|
||||
{
|
||||
dir->has_next = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
bail:
|
||||
tinydir_close(dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path)
|
||||
{
|
||||
/* Count the number of files first, to pre-allocate the files array */
|
||||
size_t n_files = 0;
|
||||
if (tinydir_open(dir, path) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
while (dir->has_next)
|
||||
{
|
||||
n_files++;
|
||||
if (tinydir_next(dir) == -1)
|
||||
{
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
tinydir_close(dir);
|
||||
|
||||
if (tinydir_open(dir, path) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
dir->n_files = 0;
|
||||
dir->_files = (tinydir_file *)_TINYDIR_MALLOC(sizeof *dir->_files * n_files);
|
||||
if (dir->_files == NULL)
|
||||
{
|
||||
goto bail;
|
||||
}
|
||||
while (dir->has_next)
|
||||
{
|
||||
tinydir_file *p_file;
|
||||
dir->n_files++;
|
||||
|
||||
p_file = &dir->_files[dir->n_files - 1];
|
||||
if (tinydir_readfile(dir, p_file) == -1)
|
||||
{
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (tinydir_next(dir) == -1)
|
||||
{
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* Just in case the number of files has changed between the first and
|
||||
second reads, terminate without writing into unallocated memory */
|
||||
if (dir->n_files == n_files)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
qsort(dir->_files, dir->n_files, sizeof(tinydir_file), _tinydir_file_cmp);
|
||||
|
||||
return 0;
|
||||
|
||||
bail:
|
||||
tinydir_close(dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
void tinydir_close(tinydir_dir *dir)
|
||||
{
|
||||
if (dir == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
memset(dir->path, 0, sizeof(dir->path));
|
||||
dir->has_next = 0;
|
||||
dir->n_files = 0;
|
||||
_TINYDIR_FREE(dir->_files);
|
||||
dir->_files = NULL;
|
||||
#ifdef _MSC_VER
|
||||
if (dir->_h != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
FindClose(dir->_h);
|
||||
}
|
||||
dir->_h = INVALID_HANDLE_VALUE;
|
||||
#else
|
||||
if (dir->_d)
|
||||
{
|
||||
_tinydir_closedir(dir->_d);
|
||||
}
|
||||
dir->_d = NULL;
|
||||
dir->_e = NULL;
|
||||
#ifndef _TINYDIR_USE_READDIR
|
||||
_TINYDIR_FREE(dir->_ep);
|
||||
dir->_ep = NULL;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_next(tinydir_dir *dir)
|
||||
{
|
||||
if (dir == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (!dir->has_next)
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
if (FindNextFile(dir->_h, &dir->_f) == 0)
|
||||
#else
|
||||
#ifdef _TINYDIR_USE_READDIR
|
||||
dir->_e = _tinydir_readdir(dir->_d);
|
||||
#else
|
||||
if (dir->_ep == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (readdir_r(dir->_d, dir->_ep, &dir->_e) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
if (dir->_e == NULL)
|
||||
#endif
|
||||
{
|
||||
dir->has_next = 0;
|
||||
#ifdef _MSC_VER
|
||||
if (GetLastError() != ERROR_SUCCESS &&
|
||||
GetLastError() != ERROR_NO_MORE_FILES)
|
||||
{
|
||||
tinydir_close(dir);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file)
|
||||
{
|
||||
if (dir == NULL || file == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
if (dir->_h == INVALID_HANDLE_VALUE)
|
||||
#else
|
||||
if (dir->_e == NULL)
|
||||
#endif
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
if (_tinydir_strlen(dir->path) +
|
||||
_tinydir_strlen(
|
||||
#ifdef _MSC_VER
|
||||
dir->_f.cFileName
|
||||
#else
|
||||
dir->_e->d_name
|
||||
#endif
|
||||
) + 1 + _TINYDIR_PATH_EXTRA >=
|
||||
_TINYDIR_PATH_MAX)
|
||||
{
|
||||
/* the path for the file will be too long */
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
if (_tinydir_strlen(
|
||||
#ifdef _MSC_VER
|
||||
dir->_f.cFileName
|
||||
#else
|
||||
dir->_e->d_name
|
||||
#endif
|
||||
) >= _TINYDIR_FILENAME_MAX)
|
||||
{
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
_tinydir_strcpy(file->path, dir->path);
|
||||
_tinydir_strcat(file->path, TINYDIR_STRING("/"));
|
||||
_tinydir_strcpy(file->name,
|
||||
#ifdef _MSC_VER
|
||||
dir->_f.cFileName
|
||||
#else
|
||||
dir->_e->d_name
|
||||
#endif
|
||||
);
|
||||
_tinydir_strcat(file->path, file->name);
|
||||
#ifndef _MSC_VER
|
||||
#ifdef __MINGW32__
|
||||
if (_tstat(
|
||||
#else
|
||||
if (stat(
|
||||
#endif
|
||||
file->path, &file->_s) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
_tinydir_get_ext(file);
|
||||
|
||||
file->is_dir =
|
||||
#ifdef _MSC_VER
|
||||
!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
|
||||
#else
|
||||
S_ISDIR(file->_s.st_mode);
|
||||
#endif
|
||||
file->is_reg =
|
||||
#ifdef _MSC_VER
|
||||
!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) ||
|
||||
(
|
||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) &&
|
||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
|
||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
|
||||
#ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM
|
||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM) &&
|
||||
#endif
|
||||
#ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA
|
||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA) &&
|
||||
#endif
|
||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) &&
|
||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY));
|
||||
#else
|
||||
S_ISREG(file->_s.st_mode);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i)
|
||||
{
|
||||
if (dir == NULL || file == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (i >= dir->n_files)
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(file, &dir->_files[i], sizeof(tinydir_file));
|
||||
_tinydir_get_ext(file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_open_subdir_n(tinydir_dir *dir, size_t i)
|
||||
{
|
||||
_tinydir_char_t path[_TINYDIR_PATH_MAX];
|
||||
if (dir == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (i >= dir->n_files || !dir->_files[i].is_dir)
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
_tinydir_strcpy(path, dir->_files[i].path);
|
||||
tinydir_close(dir);
|
||||
if (tinydir_open_sorted(dir, path) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Open a single file given its path */
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path)
|
||||
{
|
||||
tinydir_dir dir;
|
||||
int result = 0;
|
||||
int found = 0;
|
||||
_tinydir_char_t dir_name_buf[_TINYDIR_PATH_MAX];
|
||||
_tinydir_char_t file_name_buf[_TINYDIR_FILENAME_MAX];
|
||||
_tinydir_char_t *dir_name;
|
||||
_tinydir_char_t *base_name;
|
||||
#if (defined _MSC_VER || defined __MINGW32__)
|
||||
_tinydir_char_t drive_buf[_TINYDIR_PATH_MAX];
|
||||
_tinydir_char_t ext_buf[_TINYDIR_FILENAME_MAX];
|
||||
#endif
|
||||
|
||||
if (file == NULL || path == NULL || _tinydir_strlen(path) == 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
|
||||
{
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the parent path */
|
||||
#if (defined _MSC_VER || defined __MINGW32__)
|
||||
#if ((defined _MSC_VER) && (_MSC_VER >= 1400))
|
||||
_tsplitpath_s(
|
||||
path,
|
||||
drive_buf, _TINYDIR_DRIVE_MAX,
|
||||
dir_name_buf, _TINYDIR_FILENAME_MAX,
|
||||
file_name_buf, _TINYDIR_FILENAME_MAX,
|
||||
ext_buf, _TINYDIR_FILENAME_MAX);
|
||||
#else
|
||||
_tsplitpath(
|
||||
path,
|
||||
drive_buf,
|
||||
dir_name_buf,
|
||||
file_name_buf,
|
||||
ext_buf);
|
||||
#endif
|
||||
|
||||
/* _splitpath_s not work fine with only filename and widechar support */
|
||||
#ifdef _UNICODE
|
||||
if (drive_buf[0] == L'\xFEFE')
|
||||
drive_buf[0] = '\0';
|
||||
if (dir_name_buf[0] == L'\xFEFE')
|
||||
dir_name_buf[0] = '\0';
|
||||
#endif
|
||||
|
||||
if (errno)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
/* Emulate the behavior of dirname by returning "." for dir name if it's
|
||||
empty */
|
||||
if (drive_buf[0] == '\0' && dir_name_buf[0] == '\0')
|
||||
{
|
||||
_tinydir_strcpy(dir_name_buf, TINYDIR_STRING("."));
|
||||
}
|
||||
/* Concatenate the drive letter and dir name to form full dir name */
|
||||
_tinydir_strcat(drive_buf, dir_name_buf);
|
||||
dir_name = drive_buf;
|
||||
/* Concatenate the file name and extension to form base name */
|
||||
_tinydir_strcat(file_name_buf, ext_buf);
|
||||
base_name = file_name_buf;
|
||||
#else
|
||||
_tinydir_strcpy(dir_name_buf, path);
|
||||
dir_name = dirname(dir_name_buf);
|
||||
_tinydir_strcpy(file_name_buf, path);
|
||||
base_name =basename(file_name_buf);
|
||||
#endif
|
||||
|
||||
/* Open the parent directory */
|
||||
if (tinydir_open(&dir, dir_name) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Read through the parent directory and look for the file */
|
||||
while (dir.has_next)
|
||||
{
|
||||
if (tinydir_readfile(&dir, file) == -1)
|
||||
{
|
||||
result = -1;
|
||||
goto bail;
|
||||
}
|
||||
if (_tinydir_strcmp(file->name, base_name) == 0)
|
||||
{
|
||||
/* File found */
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
tinydir_next(&dir);
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
result = -1;
|
||||
errno = ENOENT;
|
||||
}
|
||||
|
||||
bail:
|
||||
tinydir_close(&dir);
|
||||
return result;
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
void _tinydir_get_ext(tinydir_file *file)
|
||||
{
|
||||
_tinydir_char_t *period = _tinydir_strrchr(file->name, TINYDIR_STRING('.'));
|
||||
if (period == NULL)
|
||||
{
|
||||
file->extension = &(file->name[_tinydir_strlen(file->name)]);
|
||||
}
|
||||
else
|
||||
{
|
||||
file->extension = period + 1;
|
||||
}
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int _tinydir_file_cmp(const void *a, const void *b)
|
||||
{
|
||||
const tinydir_file *fa = (const tinydir_file *)a;
|
||||
const tinydir_file *fb = (const tinydir_file *)b;
|
||||
if (fa->is_dir != fb->is_dir)
|
||||
{
|
||||
return -(fa->is_dir - fb->is_dir);
|
||||
}
|
||||
return _tinydir_strncmp(fa->name, fb->name, _TINYDIR_FILENAME_MAX);
|
||||
}
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#ifndef _TINYDIR_USE_READDIR
|
||||
/*
|
||||
The following authored by Ben Hutchings <ben@decadent.org.uk>
|
||||
from https://womble.decadent.org.uk/readdir_r-advisory.html
|
||||
*/
|
||||
/* Calculate the required buffer size (in bytes) for directory *
|
||||
* entries read from the given directory handle. Return -1 if this *
|
||||
* this cannot be done. *
|
||||
* *
|
||||
* This code does not trust values of NAME_MAX that are less than *
|
||||
* 255, since some systems (including at least HP-UX) incorrectly *
|
||||
* define it to be a smaller value. */
|
||||
_TINYDIR_FUNC
|
||||
size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp)
|
||||
{
|
||||
long name_max;
|
||||
size_t name_end;
|
||||
/* parameter may be unused */
|
||||
(void)dirp;
|
||||
|
||||
#if defined _TINYDIR_USE_FPATHCONF
|
||||
name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
|
||||
if (name_max == -1)
|
||||
#if defined(NAME_MAX)
|
||||
name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
|
||||
#else
|
||||
return (size_t)(-1);
|
||||
#endif
|
||||
#elif defined(NAME_MAX)
|
||||
name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
|
||||
#else
|
||||
#error "buffer size for readdir_r cannot be determined"
|
||||
#endif
|
||||
name_end = (size_t)offsetof(struct _tinydir_dirent, d_name) + name_max + 1;
|
||||
return (name_end > sizeof(struct _tinydir_dirent) ?
|
||||
name_end : sizeof(struct _tinydir_dirent));
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
# if defined (_MSC_VER)
|
||||
# pragma warning(pop)
|
||||
# endif
|
||||
|
||||
#endif
|
||||
@@ -1,114 +0,0 @@
|
||||
#ifndef LWIP_HTTPD_STRUCTS_H
|
||||
#define LWIP_HTTPD_STRUCTS_H
|
||||
|
||||
#include "lwip/apps/httpd.h"
|
||||
|
||||
#if LWIP_HTTPD_DYNAMIC_HEADERS
|
||||
/** This struct is used for a list of HTTP header strings for various
|
||||
* filename extensions. */
|
||||
typedef struct
|
||||
{
|
||||
const char *extension;
|
||||
const char *content_type;
|
||||
} tHTTPHeader;
|
||||
|
||||
/** A list of strings used in HTTP headers (see RFC 1945 HTTP/1.0 and
|
||||
* RFC 2616 HTTP/1.1 for header field definitions) */
|
||||
static const char * const g_psHTTPHeaderStrings[] =
|
||||
{
|
||||
"HTTP/1.0 200 OK\r\n",
|
||||
"HTTP/1.0 404 File not found\r\n",
|
||||
"HTTP/1.0 400 Bad Request\r\n",
|
||||
"HTTP/1.0 501 Not Implemented\r\n",
|
||||
"HTTP/1.1 200 OK\r\n",
|
||||
"HTTP/1.1 404 File not found\r\n",
|
||||
"HTTP/1.1 400 Bad Request\r\n",
|
||||
"HTTP/1.1 501 Not Implemented\r\n",
|
||||
"Content-Length: ",
|
||||
"Connection: Close\r\n",
|
||||
"Connection: keep-alive\r\n",
|
||||
"Connection: keep-alive\r\nContent-Length: ",
|
||||
"Server: "HTTPD_SERVER_AGENT"\r\n",
|
||||
"\r\n<html><body><h2>404: The requested file cannot be found.</h2></body></html>\r\n"
|
||||
#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
|
||||
,"Connection: keep-alive\r\nContent-Length: 77\r\n\r\n<html><body><h2>404: The requested file cannot be found.</h2></body></html>\r\n"
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Indexes into the g_psHTTPHeaderStrings array */
|
||||
#define HTTP_HDR_OK 0 /* 200 OK */
|
||||
#define HTTP_HDR_NOT_FOUND 1 /* 404 File not found */
|
||||
#define HTTP_HDR_BAD_REQUEST 2 /* 400 Bad request */
|
||||
#define HTTP_HDR_NOT_IMPL 3 /* 501 Not Implemented */
|
||||
#define HTTP_HDR_OK_11 4 /* 200 OK */
|
||||
#define HTTP_HDR_NOT_FOUND_11 5 /* 404 File not found */
|
||||
#define HTTP_HDR_BAD_REQUEST_11 6 /* 400 Bad request */
|
||||
#define HTTP_HDR_NOT_IMPL_11 7 /* 501 Not Implemented */
|
||||
#define HTTP_HDR_CONTENT_LENGTH 8 /* Content-Length: (HTTP 1.0)*/
|
||||
#define HTTP_HDR_CONN_CLOSE 9 /* Connection: Close (HTTP 1.1) */
|
||||
#define HTTP_HDR_CONN_KEEPALIVE 10 /* Connection: keep-alive (HTTP 1.1) */
|
||||
#define HTTP_HDR_KEEPALIVE_LEN 11 /* Connection: keep-alive + Content-Length: (HTTP 1.1)*/
|
||||
#define HTTP_HDR_SERVER 12 /* Server: HTTPD_SERVER_AGENT */
|
||||
#define DEFAULT_404_HTML 13 /* default 404 body */
|
||||
#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
|
||||
#define DEFAULT_404_HTML_PERSISTENT 14 /* default 404 body, but including Connection: keep-alive */
|
||||
#endif
|
||||
|
||||
|
||||
#define HTTP_HDR_HTML "Content-type: text/html\r\n\r\n"
|
||||
#define HTTP_HDR_SSI "Content-type: text/html\r\nExpires: Fri, 10 Apr 2008 14:00:00 GMT\r\nPragma: no-cache\r\n\r\n"
|
||||
#define HTTP_HDR_GIF "Content-type: image/gif\r\n\r\n"
|
||||
#define HTTP_HDR_PNG "Content-type: image/png\r\n\r\n"
|
||||
#define HTTP_HDR_JPG "Content-type: image/jpeg\r\n\r\n"
|
||||
#define HTTP_HDR_BMP "Content-type: image/bmp\r\n\r\n"
|
||||
#define HTTP_HDR_ICO "Content-type: image/x-icon\r\n\r\n"
|
||||
#define HTTP_HDR_APP "Content-type: application/octet-stream\r\n\r\n"
|
||||
#define HTTP_HDR_JS "Content-type: application/javascript\r\n\r\n"
|
||||
#define HTTP_HDR_RA "Content-type: application/javascript\r\n\r\n"
|
||||
#define HTTP_HDR_CSS "Content-type: text/css\r\n\r\n"
|
||||
#define HTTP_HDR_SWF "Content-type: application/x-shockwave-flash\r\n\r\n"
|
||||
#define HTTP_HDR_XML "Content-type: text/xml\r\n\r\n"
|
||||
#define HTTP_HDR_PDF "Content-type: application/pdf\r\n\r\n"
|
||||
#define HTTP_HDR_JSON "Content-type: application/json\r\n\r\n"
|
||||
|
||||
#define HTTP_HDR_DEFAULT_TYPE "Content-type: text/plain\r\n\r\n"
|
||||
|
||||
/** A list of extension-to-HTTP header strings (see outdated RFC 1700 MEDIA TYPES
|
||||
* and http://www.iana.org/assignments/media-types for registered content types
|
||||
* and subtypes) */
|
||||
static const tHTTPHeader g_psHTTPHeaders[] =
|
||||
{
|
||||
{ "html", HTTP_HDR_HTML},
|
||||
{ "htm", HTTP_HDR_HTML},
|
||||
{ "shtml",HTTP_HDR_SSI},
|
||||
{ "shtm", HTTP_HDR_SSI},
|
||||
{ "ssi", HTTP_HDR_SSI},
|
||||
{ "gif", HTTP_HDR_GIF},
|
||||
{ "png", HTTP_HDR_PNG},
|
||||
{ "jpg", HTTP_HDR_JPG},
|
||||
{ "bmp", HTTP_HDR_BMP},
|
||||
{ "ico", HTTP_HDR_ICO},
|
||||
{ "class",HTTP_HDR_APP},
|
||||
{ "cls", HTTP_HDR_APP},
|
||||
{ "js", HTTP_HDR_JS},
|
||||
{ "ram", HTTP_HDR_RA},
|
||||
{ "css", HTTP_HDR_CSS},
|
||||
{ "swf", HTTP_HDR_SWF},
|
||||
{ "xml", HTTP_HDR_XML},
|
||||
{ "xsl", HTTP_HDR_XML},
|
||||
{ "pdf", HTTP_HDR_PDF},
|
||||
{ "json", HTTP_HDR_JSON}
|
||||
};
|
||||
|
||||
#define NUM_HTTP_HEADERS (sizeof(g_psHTTPHeaders) / sizeof(tHTTPHeader))
|
||||
|
||||
#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
|
||||
|
||||
#if LWIP_HTTPD_SSI
|
||||
static const char * const g_pcSSIExtensions[] = {
|
||||
".shtml", ".shtm", ".ssi", ".xml"
|
||||
};
|
||||
#define NUM_SHTML_EXTENSIONS (sizeof(g_pcSSIExtensions) / sizeof(const char *))
|
||||
#endif /* LWIP_HTTPD_SSI */
|
||||
|
||||
#endif /* LWIP_HTTPD_STRUCTS_H */
|
||||
@@ -7,11 +7,15 @@
|
||||
* @defgroup iperf Iperf server
|
||||
* @ingroup apps
|
||||
*
|
||||
* This is a simple performance measuring server to check your bandwith using
|
||||
* iPerf2 on a PC as client.
|
||||
* It is currently a minimal implementation providing an IPv4 TCP server only.
|
||||
* This is a simple performance measuring client/server to check your bandwith using
|
||||
* iPerf2 on a PC as server/client.
|
||||
* It is currently a minimal implementation providing a TCP client/server only.
|
||||
*
|
||||
* @todo: implement UDP mode and IPv6
|
||||
* @todo:
|
||||
* - implement UDP mode
|
||||
* - protect combined sessions handling (via 'related_master_state') against reallocation
|
||||
* (this is a pointer address, currently, so if the same memory is allocated again,
|
||||
* session pairs (tx/rx) can be confused on reallocation)
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -52,8 +56,8 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* Currently, only TCP-over-IPv4 is implemented (does iperf support IPv6 anyway?) */
|
||||
#if LWIP_IPV4 && LWIP_TCP
|
||||
/* Currently, only TCP is implemented */
|
||||
#if LWIP_TCP && LWIP_CALLBACK_API
|
||||
|
||||
/** Specify the idle timeout (in seconds) after that the test fails */
|
||||
#ifndef LWIPERF_TCP_MAX_IDLE_SEC
|
||||
@@ -63,6 +67,11 @@
|
||||
#error LWIPERF_TCP_MAX_IDLE_SEC must fit into an u8_t
|
||||
#endif
|
||||
|
||||
/** Change this if you don't want to lwiperf to listen to any IP version */
|
||||
#ifndef LWIPERF_SERVER_IP_TYPE
|
||||
#define LWIPERF_SERVER_IP_TYPE IPADDR_TYPE_ANY
|
||||
#endif
|
||||
|
||||
/* File internal memory allocation (struct lwiperf_*): this defaults to
|
||||
the heap */
|
||||
#ifndef LWIPERF_ALLOC
|
||||
@@ -91,101 +100,108 @@ typedef struct _lwiperf_settings {
|
||||
struct _lwiperf_state_base;
|
||||
typedef struct _lwiperf_state_base lwiperf_state_base_t;
|
||||
struct _lwiperf_state_base {
|
||||
/* linked list */
|
||||
lwiperf_state_base_t *next;
|
||||
/* 1=tcp, 0=udp */
|
||||
u8_t tcp;
|
||||
/* 1=server, 0=client */
|
||||
u8_t server;
|
||||
lwiperf_state_base_t* next;
|
||||
lwiperf_state_base_t* related_server_state;
|
||||
/* master state used to abort sessions (e.g. listener, main client) */
|
||||
lwiperf_state_base_t *related_master_state;
|
||||
};
|
||||
|
||||
/** Connection handle for a TCP iperf session */
|
||||
typedef struct _lwiperf_state_tcp {
|
||||
lwiperf_state_base_t base;
|
||||
struct tcp_pcb* server_pcb;
|
||||
struct tcp_pcb* conn_pcb;
|
||||
struct tcp_pcb *server_pcb;
|
||||
struct tcp_pcb *conn_pcb;
|
||||
u32_t time_started;
|
||||
lwiperf_report_fn report_fn;
|
||||
void* report_arg;
|
||||
void *report_arg;
|
||||
u8_t poll_count;
|
||||
u8_t next_num;
|
||||
/* 1=start server when client is closed */
|
||||
u8_t client_tradeoff_mode;
|
||||
u32_t bytes_transferred;
|
||||
lwiperf_settings_t settings;
|
||||
u8_t have_settings_buf;
|
||||
u8_t specific_remote;
|
||||
ip_addr_t remote_addr;
|
||||
} lwiperf_state_tcp_t;
|
||||
|
||||
/** List of active iperf sessions */
|
||||
static lwiperf_state_base_t* lwiperf_all_connections;
|
||||
static lwiperf_state_base_t *lwiperf_all_connections;
|
||||
/** A const buffer to send from: we want to measure sending, not copying! */
|
||||
static const u8_t lwiperf_txbuf_const[1600] = {
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
};
|
||||
|
||||
static err_t lwiperf_tcp_poll(void *arg, struct tcp_pcb *tpcb);
|
||||
static void lwiperf_tcp_err(void *arg, err_t err);
|
||||
static err_t lwiperf_start_tcp_server_impl(const ip_addr_t *local_addr, u16_t local_port,
|
||||
lwiperf_report_fn report_fn, void *report_arg,
|
||||
lwiperf_state_base_t *related_master_state, lwiperf_state_tcp_t **state);
|
||||
|
||||
|
||||
/** Add an iperf session to the 'active' list */
|
||||
static void
|
||||
lwiperf_list_add(lwiperf_state_base_t* item)
|
||||
lwiperf_list_add(lwiperf_state_base_t *item)
|
||||
{
|
||||
if (lwiperf_all_connections == NULL) {
|
||||
lwiperf_all_connections = item;
|
||||
} else {
|
||||
item = lwiperf_all_connections;
|
||||
}
|
||||
item->next = lwiperf_all_connections;
|
||||
lwiperf_all_connections = item;
|
||||
}
|
||||
|
||||
/** Remove an iperf session from the 'active' list */
|
||||
static void
|
||||
lwiperf_list_remove(lwiperf_state_base_t* item)
|
||||
lwiperf_list_remove(lwiperf_state_base_t *item)
|
||||
{
|
||||
lwiperf_state_base_t* prev = NULL;
|
||||
lwiperf_state_base_t* iter;
|
||||
lwiperf_state_base_t *prev = NULL;
|
||||
lwiperf_state_base_t *iter;
|
||||
for (iter = lwiperf_all_connections; iter != NULL; prev = iter, iter = iter->next) {
|
||||
if (iter == item) {
|
||||
if (prev == NULL) {
|
||||
lwiperf_all_connections = iter->next;
|
||||
} else {
|
||||
prev->next = item;
|
||||
prev->next = iter->next;
|
||||
}
|
||||
/* @debug: ensure this item is listed only once */
|
||||
for (iter = iter->next; iter != NULL; iter = iter->next) {
|
||||
@@ -196,9 +212,21 @@ lwiperf_list_remove(lwiperf_state_base_t* item)
|
||||
}
|
||||
}
|
||||
|
||||
static lwiperf_state_base_t *
|
||||
lwiperf_list_find(lwiperf_state_base_t *item)
|
||||
{
|
||||
lwiperf_state_base_t *iter;
|
||||
for (iter = lwiperf_all_connections; iter != NULL; iter = iter->next) {
|
||||
if (iter == item) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Call the report function of an iperf tcp session */
|
||||
static void
|
||||
lwip_tcp_conn_report(lwiperf_state_tcp_t* conn, enum lwiperf_report_type report_type)
|
||||
lwip_tcp_conn_report(lwiperf_state_tcp_t *conn, enum lwiperf_report_type report_type)
|
||||
{
|
||||
if ((conn != NULL) && (conn->report_fn != NULL)) {
|
||||
u32_t now, duration_ms, bandwidth_kbitpsec;
|
||||
@@ -210,20 +238,20 @@ lwip_tcp_conn_report(lwiperf_state_tcp_t* conn, enum lwiperf_report_type report_
|
||||
bandwidth_kbitpsec = (conn->bytes_transferred / duration_ms) * 8U;
|
||||
}
|
||||
conn->report_fn(conn->report_arg, report_type,
|
||||
&conn->conn_pcb->local_ip, conn->conn_pcb->local_port,
|
||||
&conn->conn_pcb->remote_ip, conn->conn_pcb->remote_port,
|
||||
conn->bytes_transferred, duration_ms, bandwidth_kbitpsec);
|
||||
&conn->conn_pcb->local_ip, conn->conn_pcb->local_port,
|
||||
&conn->conn_pcb->remote_ip, conn->conn_pcb->remote_port,
|
||||
conn->bytes_transferred, duration_ms, bandwidth_kbitpsec);
|
||||
}
|
||||
}
|
||||
|
||||
/** Close an iperf tcp session */
|
||||
static void
|
||||
lwiperf_tcp_close(lwiperf_state_tcp_t* conn, enum lwiperf_report_type report_type)
|
||||
lwiperf_tcp_close(lwiperf_state_tcp_t *conn, enum lwiperf_report_type report_type)
|
||||
{
|
||||
err_t err;
|
||||
|
||||
lwip_tcp_conn_report(conn, report_type);
|
||||
lwiperf_list_remove(&conn->base);
|
||||
lwip_tcp_conn_report(conn, report_type);
|
||||
if (conn->conn_pcb != NULL) {
|
||||
tcp_arg(conn->conn_pcb, NULL);
|
||||
tcp_poll(conn->conn_pcb, NULL, 0);
|
||||
@@ -236,22 +264,22 @@ lwiperf_tcp_close(lwiperf_state_tcp_t* conn, enum lwiperf_report_type report_typ
|
||||
tcp_abort(conn->conn_pcb);
|
||||
}
|
||||
} else {
|
||||
/* no conn pcb, this is the server pcb */
|
||||
/* no conn pcb, this is the listener pcb */
|
||||
err = tcp_close(conn->server_pcb);
|
||||
LWIP_ASSERT("error", err != ERR_OK);
|
||||
LWIP_ASSERT("error", err == ERR_OK);
|
||||
}
|
||||
LWIPERF_FREE(lwiperf_state_tcp_t, conn);
|
||||
}
|
||||
|
||||
/** Try to send more data on an iperf tcp session */
|
||||
static err_t
|
||||
lwiperf_tcp_client_send_more(lwiperf_state_tcp_t* conn)
|
||||
lwiperf_tcp_client_send_more(lwiperf_state_tcp_t *conn)
|
||||
{
|
||||
int send_more;
|
||||
err_t err;
|
||||
u16_t txlen;
|
||||
u16_t txlen_max;
|
||||
void* txptr;
|
||||
void *txptr;
|
||||
u8_t apiflags;
|
||||
|
||||
LWIP_ASSERT("conn invalid", (conn != NULL) && conn->base.tcp && (conn->base.server == 0));
|
||||
@@ -262,7 +290,7 @@ lwiperf_tcp_client_send_more(lwiperf_state_tcp_t* conn)
|
||||
/* this session is time-limited */
|
||||
u32_t now = sys_now();
|
||||
u32_t diff_ms = now - conn->time_started;
|
||||
u32_t time = (u32_t)-(s32_t)lwip_htonl(conn->settings.amount);
|
||||
u32_t time = (u32_t) - (s32_t)lwip_htonl(conn->settings.amount);
|
||||
u32_t time_ms = time * 10;
|
||||
if (diff_ms >= time_ms) {
|
||||
/* time specified by the client is over -> close the connection */
|
||||
@@ -282,19 +310,19 @@ lwiperf_tcp_client_send_more(lwiperf_state_tcp_t* conn)
|
||||
|
||||
if (conn->bytes_transferred < 24) {
|
||||
/* transmit the settings a first time */
|
||||
txptr = &((u8_t*)&conn->settings)[conn->bytes_transferred];
|
||||
txptr = &((u8_t *)&conn->settings)[conn->bytes_transferred];
|
||||
txlen_max = (u16_t)(24 - conn->bytes_transferred);
|
||||
apiflags = TCP_WRITE_FLAG_COPY;
|
||||
} else if (conn->bytes_transferred < 48) {
|
||||
/* transmit the settings a second time */
|
||||
txptr = &((u8_t*)&conn->settings)[conn->bytes_transferred - 24];
|
||||
txptr = &((u8_t *)&conn->settings)[conn->bytes_transferred - 24];
|
||||
txlen_max = (u16_t)(48 - conn->bytes_transferred);
|
||||
apiflags = TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE;
|
||||
send_more = 1;
|
||||
} else {
|
||||
/* transmit data */
|
||||
/* @todo: every x bytes, transmit the settings again */
|
||||
txptr = (void*)(size_t)&lwiperf_txbuf_const[conn->bytes_transferred % 10];
|
||||
txptr = LWIP_CONST_CAST(void *, &lwiperf_txbuf_const[conn->bytes_transferred % 10]);
|
||||
txlen_max = TCP_MSS;
|
||||
if (conn->bytes_transferred == 48) { /* @todo: fix this for intermediate settings, too */
|
||||
txlen_max = TCP_MSS - 24;
|
||||
@@ -308,14 +336,14 @@ lwiperf_tcp_client_send_more(lwiperf_state_tcp_t* conn)
|
||||
if (err == ERR_MEM) {
|
||||
txlen /= 2;
|
||||
}
|
||||
} while ((err == ERR_MEM) && (txlen >= (TCP_MSS/2)));
|
||||
} while ((err == ERR_MEM) && (txlen >= (TCP_MSS / 2)));
|
||||
|
||||
if (err == ERR_OK) {
|
||||
conn->bytes_transferred += txlen;
|
||||
} else {
|
||||
send_more = 0;
|
||||
}
|
||||
} while(send_more);
|
||||
} while (send_more);
|
||||
|
||||
tcp_output(conn->conn_pcb);
|
||||
return ERR_OK;
|
||||
@@ -325,7 +353,7 @@ lwiperf_tcp_client_send_more(lwiperf_state_tcp_t* conn)
|
||||
static err_t
|
||||
lwiperf_tcp_client_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
|
||||
{
|
||||
lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg;
|
||||
lwiperf_state_tcp_t *conn = (lwiperf_state_tcp_t *)arg;
|
||||
/* @todo: check 'len' (e.g. to time ACK of all data)? for now, we just send more... */
|
||||
LWIP_ASSERT("invalid conn", conn->conn_pcb == tpcb);
|
||||
LWIP_UNUSED_ARG(tpcb);
|
||||
@@ -340,7 +368,7 @@ lwiperf_tcp_client_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
|
||||
static err_t
|
||||
lwiperf_tcp_client_connected(void *arg, struct tcp_pcb *tpcb, err_t err)
|
||||
{
|
||||
lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg;
|
||||
lwiperf_state_tcp_t *conn = (lwiperf_state_tcp_t *)arg;
|
||||
LWIP_ASSERT("invalid conn", conn->conn_pcb == tpcb);
|
||||
LWIP_UNUSED_ARG(tpcb);
|
||||
if (err != ERR_OK) {
|
||||
@@ -356,41 +384,46 @@ lwiperf_tcp_client_connected(void *arg, struct tcp_pcb *tpcb, err_t err)
|
||||
* receive test has finished.
|
||||
*/
|
||||
static err_t
|
||||
lwiperf_tx_start(lwiperf_state_tcp_t* conn)
|
||||
lwiperf_tx_start_impl(const ip_addr_t *remote_ip, u16_t remote_port, lwiperf_settings_t *settings, lwiperf_report_fn report_fn,
|
||||
void *report_arg, lwiperf_state_base_t *related_master_state, lwiperf_state_tcp_t **new_conn)
|
||||
{
|
||||
err_t err;
|
||||
lwiperf_state_tcp_t* client_conn;
|
||||
struct tcp_pcb* newpcb;
|
||||
lwiperf_state_tcp_t *client_conn;
|
||||
struct tcp_pcb *newpcb;
|
||||
ip_addr_t remote_addr;
|
||||
u16_t remote_port;
|
||||
|
||||
client_conn = (lwiperf_state_tcp_t*)LWIPERF_ALLOC(lwiperf_state_tcp_t);
|
||||
LWIP_ASSERT("remote_ip != NULL", remote_ip != NULL);
|
||||
LWIP_ASSERT("remote_ip != NULL", settings != NULL);
|
||||
LWIP_ASSERT("new_conn != NULL", new_conn != NULL);
|
||||
*new_conn = NULL;
|
||||
|
||||
client_conn = (lwiperf_state_tcp_t *)LWIPERF_ALLOC(lwiperf_state_tcp_t);
|
||||
if (client_conn == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
newpcb = tcp_new();
|
||||
newpcb = tcp_new_ip_type(IP_GET_TYPE(remote_ip));
|
||||
if (newpcb == NULL) {
|
||||
LWIPERF_FREE(lwiperf_state_tcp_t, client_conn);
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
MEMCPY(client_conn, conn, sizeof(lwiperf_state_tcp_t));
|
||||
client_conn->base.server = 0;
|
||||
client_conn->server_pcb = NULL;
|
||||
memset(client_conn, 0, sizeof(lwiperf_state_tcp_t));
|
||||
client_conn->base.tcp = 1;
|
||||
client_conn->base.related_master_state = related_master_state;
|
||||
client_conn->conn_pcb = newpcb;
|
||||
client_conn->time_started = sys_now(); /* @todo: set this again on 'connected' */
|
||||
client_conn->poll_count = 0;
|
||||
client_conn->report_fn = report_fn;
|
||||
client_conn->report_arg = report_arg;
|
||||
client_conn->next_num = 4; /* initial nr is '4' since the header has 24 byte */
|
||||
client_conn->bytes_transferred = 0;
|
||||
client_conn->settings.flags = 0; /* prevent the remote side starting back as client again */
|
||||
memcpy(&client_conn->settings, settings, sizeof(*settings));
|
||||
client_conn->have_settings_buf = 1;
|
||||
|
||||
tcp_arg(newpcb, client_conn);
|
||||
tcp_sent(newpcb, lwiperf_tcp_client_sent);
|
||||
tcp_poll(newpcb, lwiperf_tcp_poll, 2U);
|
||||
tcp_err(newpcb, lwiperf_tcp_err);
|
||||
|
||||
ip_addr_copy(remote_addr, conn->conn_pcb->remote_ip);
|
||||
remote_port = (u16_t)lwip_htonl(client_conn->settings.remote_port);
|
||||
ip_addr_copy(remote_addr, *remote_ip);
|
||||
|
||||
err = tcp_connect(newpcb, &remote_addr, remote_port, lwiperf_tcp_client_connected);
|
||||
if (err != ERR_OK) {
|
||||
@@ -398,9 +431,26 @@ lwiperf_tx_start(lwiperf_state_tcp_t* conn)
|
||||
return err;
|
||||
}
|
||||
lwiperf_list_add(&client_conn->base);
|
||||
*new_conn = client_conn;
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static err_t
|
||||
lwiperf_tx_start_passive(lwiperf_state_tcp_t *conn)
|
||||
{
|
||||
err_t ret;
|
||||
lwiperf_state_tcp_t *new_conn = NULL;
|
||||
u16_t remote_port = (u16_t)lwip_htonl(conn->settings.remote_port);
|
||||
|
||||
ret = lwiperf_tx_start_impl(&conn->conn_pcb->remote_ip, remote_port, &conn->settings, conn->report_fn, conn->report_arg,
|
||||
conn->base.related_master_state, &new_conn);
|
||||
if (ret == ERR_OK) {
|
||||
LWIP_ASSERT("new_conn != NULL", new_conn != NULL);
|
||||
new_conn->settings.flags = 0; /* prevent the remote side starting back as client again */
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Receive data on an iperf tcp session */
|
||||
static err_t
|
||||
lwiperf_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
|
||||
@@ -408,8 +458,8 @@ lwiperf_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
|
||||
u8_t tmp;
|
||||
u16_t tot_len;
|
||||
u32_t packet_idx;
|
||||
struct pbuf* q;
|
||||
lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg;
|
||||
struct pbuf *q;
|
||||
lwiperf_state_tcp_t *conn = (lwiperf_state_tcp_t *)arg;
|
||||
|
||||
LWIP_ASSERT("pcb mismatch", conn->conn_pcb == tpcb);
|
||||
LWIP_UNUSED_ARG(tpcb);
|
||||
@@ -420,10 +470,11 @@ lwiperf_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
|
||||
}
|
||||
if (p == NULL) {
|
||||
/* connection closed -> test done */
|
||||
if ((conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST|LWIPERF_FLAGS_ANSWER_NOW)) ==
|
||||
PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST)) {
|
||||
/* client requested transmission after end of test */
|
||||
lwiperf_tx_start(conn);
|
||||
if (conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST)) {
|
||||
if ((conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_NOW)) == 0) {
|
||||
/* client requested transmission after end of test */
|
||||
lwiperf_tx_start_passive(conn);
|
||||
}
|
||||
}
|
||||
lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_SERVER);
|
||||
return ERR_OK;
|
||||
@@ -432,35 +483,38 @@ lwiperf_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
|
||||
|
||||
conn->poll_count = 0;
|
||||
|
||||
if ((!conn->have_settings_buf) || ((conn->bytes_transferred -24) % (1024*128) == 0)) {
|
||||
if ((!conn->have_settings_buf) || ((conn->bytes_transferred - 24) % (1024 * 128) == 0)) {
|
||||
/* wait for 24-byte header */
|
||||
if (p->tot_len < sizeof(lwiperf_settings_t)) {
|
||||
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR);
|
||||
pbuf_free(p);
|
||||
return ERR_VAL;
|
||||
return ERR_OK;
|
||||
}
|
||||
if (!conn->have_settings_buf) {
|
||||
if (pbuf_copy_partial(p, &conn->settings, sizeof(lwiperf_settings_t), 0) != sizeof(lwiperf_settings_t)) {
|
||||
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL);
|
||||
pbuf_free(p);
|
||||
return ERR_VAL;
|
||||
return ERR_OK;
|
||||
}
|
||||
conn->have_settings_buf = 1;
|
||||
if ((conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST|LWIPERF_FLAGS_ANSWER_NOW)) ==
|
||||
PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST|LWIPERF_FLAGS_ANSWER_NOW)) {
|
||||
if (conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST)) {
|
||||
if (conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_NOW)) {
|
||||
/* client requested parallel transmission test */
|
||||
err_t err2 = lwiperf_tx_start(conn);
|
||||
err_t err2 = lwiperf_tx_start_passive(conn);
|
||||
if (err2 != ERR_OK) {
|
||||
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_TXERROR);
|
||||
pbuf_free(p);
|
||||
return err2;
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (pbuf_memcmp(p, 0, &conn->settings, sizeof(lwiperf_settings_t)) != 0) {
|
||||
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR);
|
||||
pbuf_free(p);
|
||||
return ERR_VAL;
|
||||
if (conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST)) {
|
||||
if (pbuf_memcmp(p, 0, &conn->settings, sizeof(lwiperf_settings_t)) != 0) {
|
||||
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR);
|
||||
pbuf_free(p);
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
conn->bytes_transferred += sizeof(lwiperf_settings_t);
|
||||
@@ -471,14 +525,15 @@ lwiperf_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
|
||||
return ERR_OK;
|
||||
}
|
||||
conn->next_num = 4; /* 24 bytes received... */
|
||||
tmp = pbuf_header(p, -24);
|
||||
LWIP_ASSERT("pbuf_header failed", tmp == 0);
|
||||
tmp = pbuf_remove_header(p, 24);
|
||||
LWIP_ASSERT("pbuf_remove_header failed", tmp == 0);
|
||||
LWIP_UNUSED_ARG(tmp); /* for LWIP_NOASSERT */
|
||||
}
|
||||
|
||||
packet_idx = 0;
|
||||
for (q = p; q != NULL; q = q->next) {
|
||||
#if LWIPERF_CHECK_RX_DATA
|
||||
const u8_t* payload = (const u8_t*)q->payload;
|
||||
const u8_t *payload = (const u8_t *)q->payload;
|
||||
u16_t i;
|
||||
for (i = 0; i < q->len; i++) {
|
||||
u8_t val = payload[i];
|
||||
@@ -491,13 +546,11 @@ lwiperf_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
|
||||
} else {
|
||||
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR);
|
||||
pbuf_free(p);
|
||||
return ERR_VAL;
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
packet_idx += i;
|
||||
#else
|
||||
packet_idx += q->len;
|
||||
#endif
|
||||
packet_idx += q->len;
|
||||
}
|
||||
LWIP_ASSERT("count mismatch", packet_idx == p->tot_len);
|
||||
conn->bytes_transferred += packet_idx;
|
||||
@@ -510,7 +563,7 @@ lwiperf_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
|
||||
static void
|
||||
lwiperf_tcp_err(void *arg, err_t err)
|
||||
{
|
||||
lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg;
|
||||
lwiperf_state_tcp_t *conn = (lwiperf_state_tcp_t *)arg;
|
||||
LWIP_UNUSED_ARG(err);
|
||||
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE);
|
||||
}
|
||||
@@ -519,7 +572,7 @@ lwiperf_tcp_err(void *arg, err_t err)
|
||||
static err_t
|
||||
lwiperf_tcp_poll(void *arg, struct tcp_pcb *tpcb)
|
||||
{
|
||||
lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg;
|
||||
lwiperf_state_tcp_t *conn = (lwiperf_state_tcp_t *)arg;
|
||||
LWIP_ASSERT("pcb mismatch", conn->conn_pcb == tpcb);
|
||||
LWIP_UNUSED_ARG(tpcb);
|
||||
if (++conn->poll_count >= LWIPERF_TCP_MAX_IDLE_SEC) {
|
||||
@@ -543,16 +596,28 @@ lwiperf_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
s = (lwiperf_state_tcp_t*)arg;
|
||||
conn = (lwiperf_state_tcp_t*)LWIPERF_ALLOC(lwiperf_state_tcp_t);
|
||||
s = (lwiperf_state_tcp_t *)arg;
|
||||
LWIP_ASSERT("invalid session", s->base.server);
|
||||
LWIP_ASSERT("invalid listen pcb", s->server_pcb != NULL);
|
||||
LWIP_ASSERT("invalid conn pcb", s->conn_pcb == NULL);
|
||||
if (s->specific_remote) {
|
||||
LWIP_ASSERT("s->base.related_master_state != NULL", s->base.related_master_state != NULL);
|
||||
if (!ip_addr_cmp(&newpcb->remote_ip, &s->remote_addr)) {
|
||||
/* this listener belongs to a client session, and this is not the correct remote */
|
||||
return ERR_VAL;
|
||||
}
|
||||
} else {
|
||||
LWIP_ASSERT("s->base.related_master_state == NULL", s->base.related_master_state == NULL);
|
||||
}
|
||||
|
||||
conn = (lwiperf_state_tcp_t *)LWIPERF_ALLOC(lwiperf_state_tcp_t);
|
||||
if (conn == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
memset(conn, 0, sizeof(lwiperf_state_tcp_t));
|
||||
conn->base.tcp = 1;
|
||||
conn->base.server = 1;
|
||||
conn->base.related_server_state = &s->base;
|
||||
conn->server_pcb = s->server_pcb;
|
||||
conn->base.related_master_state = &s->base;
|
||||
conn->conn_pcb = newpcb;
|
||||
conn->time_started = sys_now();
|
||||
conn->report_fn = s->report_fn;
|
||||
@@ -564,11 +629,21 @@ lwiperf_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
|
||||
tcp_poll(newpcb, lwiperf_tcp_poll, 2U);
|
||||
tcp_err(conn->conn_pcb, lwiperf_tcp_err);
|
||||
|
||||
if (s->specific_remote) {
|
||||
/* this listener belongs to a client, so make the client the master of the newly created connection */
|
||||
conn->base.related_master_state = s->base.related_master_state;
|
||||
/* if dual mode or (tradeoff mode AND client is done): close the listener */
|
||||
if (!s->client_tradeoff_mode || !lwiperf_list_find(s->base.related_master_state)) {
|
||||
/* prevent report when closing: this is expected */
|
||||
s->report_fn = NULL;
|
||||
lwiperf_tcp_close(s, LWIPERF_TCP_ABORTED_LOCAL);
|
||||
}
|
||||
}
|
||||
lwiperf_list_add(&conn->base);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @ingroup iperf
|
||||
* Start a TCP iperf server on the default TCP port (5001) and listen for
|
||||
* incoming connections from iperf clients.
|
||||
@@ -576,11 +651,11 @@ lwiperf_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
|
||||
* @returns a connection handle that can be used to abort the server
|
||||
* by calling @ref lwiperf_abort()
|
||||
*/
|
||||
void*
|
||||
lwiperf_start_tcp_server_default(lwiperf_report_fn report_fn, void* report_arg)
|
||||
void *
|
||||
lwiperf_start_tcp_server_default(lwiperf_report_fn report_fn, void *report_arg)
|
||||
{
|
||||
return lwiperf_start_tcp_server(IP4_ADDR_ANY, LWIPERF_TCP_PORT_DEFAULT,
|
||||
report_fn, report_arg);
|
||||
return lwiperf_start_tcp_server(IP_ADDR_ANY, LWIPERF_TCP_PORT_DEFAULT,
|
||||
report_fn, report_arg);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -591,41 +666,63 @@ lwiperf_start_tcp_server_default(lwiperf_report_fn report_fn, void* report_arg)
|
||||
* @returns a connection handle that can be used to abort the server
|
||||
* by calling @ref lwiperf_abort()
|
||||
*/
|
||||
void*
|
||||
lwiperf_start_tcp_server(const ip_addr_t* local_addr, u16_t local_port,
|
||||
lwiperf_report_fn report_fn, void* report_arg)
|
||||
void *
|
||||
lwiperf_start_tcp_server(const ip_addr_t *local_addr, u16_t local_port,
|
||||
lwiperf_report_fn report_fn, void *report_arg)
|
||||
{
|
||||
err_t err;
|
||||
struct tcp_pcb* pcb;
|
||||
lwiperf_state_tcp_t* s;
|
||||
lwiperf_state_tcp_t *state = NULL;
|
||||
|
||||
err = lwiperf_start_tcp_server_impl(local_addr, local_port, report_fn, report_arg,
|
||||
NULL, &state);
|
||||
if (err == ERR_OK) {
|
||||
return state;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static err_t lwiperf_start_tcp_server_impl(const ip_addr_t *local_addr, u16_t local_port,
|
||||
lwiperf_report_fn report_fn, void *report_arg,
|
||||
lwiperf_state_base_t *related_master_state, lwiperf_state_tcp_t **state)
|
||||
{
|
||||
err_t err;
|
||||
struct tcp_pcb *pcb;
|
||||
lwiperf_state_tcp_t *s;
|
||||
|
||||
LWIP_ASSERT_CORE_LOCKED();
|
||||
|
||||
LWIP_ASSERT("state != NULL", state != NULL);
|
||||
|
||||
if (local_addr == NULL) {
|
||||
return NULL;
|
||||
return ERR_ARG;
|
||||
}
|
||||
|
||||
s = (lwiperf_state_tcp_t*)LWIPERF_ALLOC(lwiperf_state_tcp_t);
|
||||
s = (lwiperf_state_tcp_t *)LWIPERF_ALLOC(lwiperf_state_tcp_t);
|
||||
if (s == NULL) {
|
||||
return NULL;
|
||||
return ERR_MEM;
|
||||
}
|
||||
memset(s, 0, sizeof(lwiperf_state_tcp_t));
|
||||
s->base.tcp = 1;
|
||||
s->base.server = 1;
|
||||
s->base.related_master_state = related_master_state;
|
||||
s->report_fn = report_fn;
|
||||
s->report_arg = report_arg;
|
||||
|
||||
pcb = tcp_new();
|
||||
if (pcb != NULL) {
|
||||
err = tcp_bind(pcb, local_addr, local_port);
|
||||
if (err == ERR_OK) {
|
||||
s->server_pcb = tcp_listen_with_backlog(pcb, 1);
|
||||
}
|
||||
pcb = tcp_new_ip_type(LWIPERF_SERVER_IP_TYPE);
|
||||
if (pcb == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
err = tcp_bind(pcb, local_addr, local_port);
|
||||
if (err != ERR_OK) {
|
||||
return err;
|
||||
}
|
||||
s->server_pcb = tcp_listen_with_backlog(pcb, 1);
|
||||
if (s->server_pcb == NULL) {
|
||||
if (pcb != NULL) {
|
||||
tcp_close(pcb);
|
||||
}
|
||||
LWIPERF_FREE(lwiperf_state_tcp_t, s);
|
||||
return NULL;
|
||||
return ERR_MEM;
|
||||
}
|
||||
pcb = NULL;
|
||||
|
||||
@@ -633,7 +730,86 @@ lwiperf_start_tcp_server(const ip_addr_t* local_addr, u16_t local_port,
|
||||
tcp_accept(s->server_pcb, lwiperf_tcp_accept);
|
||||
|
||||
lwiperf_list_add(&s->base);
|
||||
return s;
|
||||
*state = s;
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iperf
|
||||
* Start a TCP iperf client to the default TCP port (5001).
|
||||
*
|
||||
* @returns a connection handle that can be used to abort the client
|
||||
* by calling @ref lwiperf_abort()
|
||||
*/
|
||||
void* lwiperf_start_tcp_client_default(const ip_addr_t* remote_addr,
|
||||
lwiperf_report_fn report_fn, void* report_arg)
|
||||
{
|
||||
return lwiperf_start_tcp_client(remote_addr, LWIPERF_TCP_PORT_DEFAULT, LWIPERF_CLIENT,
|
||||
report_fn, report_arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iperf
|
||||
* Start a TCP iperf client to a specific IP address and port.
|
||||
*
|
||||
* @returns a connection handle that can be used to abort the client
|
||||
* by calling @ref lwiperf_abort()
|
||||
*/
|
||||
void* lwiperf_start_tcp_client(const ip_addr_t* remote_addr, u16_t remote_port,
|
||||
enum lwiperf_client_type type, lwiperf_report_fn report_fn, void* report_arg)
|
||||
{
|
||||
err_t ret;
|
||||
lwiperf_settings_t settings;
|
||||
lwiperf_state_tcp_t *state = NULL;
|
||||
|
||||
memset(&settings, 0, sizeof(settings));
|
||||
switch (type) {
|
||||
case LWIPERF_CLIENT:
|
||||
/* Unidirectional tx only test */
|
||||
settings.flags = 0;
|
||||
break;
|
||||
case LWIPERF_DUAL:
|
||||
/* Do a bidirectional test simultaneously */
|
||||
settings.flags = htonl(LWIPERF_FLAGS_ANSWER_TEST | LWIPERF_FLAGS_ANSWER_NOW);
|
||||
break;
|
||||
case LWIPERF_TRADEOFF:
|
||||
/* Do a bidirectional test individually */
|
||||
settings.flags = htonl(LWIPERF_FLAGS_ANSWER_TEST);
|
||||
break;
|
||||
default:
|
||||
/* invalid argument */
|
||||
return NULL;
|
||||
}
|
||||
settings.num_threads = htonl(1);
|
||||
settings.remote_port = htonl(LWIPERF_TCP_PORT_DEFAULT);
|
||||
/* TODO: implement passing duration/amount of bytes to transfer */
|
||||
settings.amount = htonl((u32_t)-1000);
|
||||
|
||||
ret = lwiperf_tx_start_impl(remote_addr, remote_port, &settings, report_fn, report_arg, NULL, &state);
|
||||
if (ret == ERR_OK) {
|
||||
LWIP_ASSERT("state != NULL", state != NULL);
|
||||
if (type != LWIPERF_CLIENT) {
|
||||
/* start corresponding server now */
|
||||
lwiperf_state_tcp_t *server = NULL;
|
||||
ret = lwiperf_start_tcp_server_impl(&state->conn_pcb->local_ip, LWIPERF_TCP_PORT_DEFAULT,
|
||||
report_fn, report_arg, (lwiperf_state_base_t *)state, &server);
|
||||
if (ret != ERR_OK) {
|
||||
/* starting server failed, abort client */
|
||||
lwiperf_abort(state);
|
||||
return NULL;
|
||||
}
|
||||
/* make this server accept one connection only */
|
||||
server->specific_remote = 1;
|
||||
server->remote_addr = state->conn_pcb->remote_ip;
|
||||
if (type == LWIPERF_TRADEOFF) {
|
||||
/* tradeoff means that the remote host connects only after the client is done,
|
||||
so keep the listen pcb open until the client is done */
|
||||
server->client_tradeoff_mode = 1;
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -641,12 +817,14 @@ lwiperf_start_tcp_server(const ip_addr_t* local_addr, u16_t local_port,
|
||||
* Abort an iperf session (handle returned by lwiperf_start_tcp_server*())
|
||||
*/
|
||||
void
|
||||
lwiperf_abort(void* lwiperf_session)
|
||||
lwiperf_abort(void *lwiperf_session)
|
||||
{
|
||||
lwiperf_state_base_t* i, *dealloc, *last = NULL;
|
||||
lwiperf_state_base_t *i, *dealloc, *last = NULL;
|
||||
|
||||
LWIP_ASSERT_CORE_LOCKED();
|
||||
|
||||
for (i = lwiperf_all_connections; i != NULL; ) {
|
||||
if ((i == lwiperf_session) || (i->related_server_state == lwiperf_session)) {
|
||||
if ((i == lwiperf_session) || (i->related_master_state == lwiperf_session)) {
|
||||
dealloc = i;
|
||||
i = i->next;
|
||||
if (last != NULL) {
|
||||
@@ -660,4 +838,4 @@ lwiperf_abort(void* lwiperf_session)
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* LWIP_IPV4 && LWIP_TCP */
|
||||
#endif /* LWIP_TCP && LWIP_CALLBACK_API */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
1462
src/apps/mqtt/mqtt.c
Normal file
1462
src/apps/mqtt/mqtt.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
/**
|
||||
* @file
|
||||
* NetBIOS name service responder
|
||||
*/
|
||||
@@ -40,6 +40,10 @@
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Modifications by Ray Abram to respond to NetBIOS name requests when Incoming name = *
|
||||
* - based on code from "https://github.com/esp8266/Arduino/commit/1f7989b31d26d7df9776a08f36d685eae7ac8f99"
|
||||
* - with permission to relicense to BSD from original author:
|
||||
* http://www.xpablo.cz/?p=751#more-751
|
||||
*/
|
||||
|
||||
#include "lwip/apps/netbiosns.h"
|
||||
@@ -48,13 +52,12 @@
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/prot/iana.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/** default port number for "NetBIOS Name service */
|
||||
#define NETBIOS_PORT 137
|
||||
|
||||
/** size of a NetBIOS name */
|
||||
#define NETBIOS_NAME_LEN 16
|
||||
|
||||
@@ -74,6 +77,10 @@
|
||||
#define NETB_HFLAG_REPLYCODE 0x0008U
|
||||
#define NETB_HFLAG_REPLYCODE_NOERROR 0x0000U
|
||||
|
||||
/* NetBIOS question types */
|
||||
#define NETB_QTYPE_NB 0x0020U
|
||||
#define NETB_QTYPE_NBSTAT 0x0021U
|
||||
|
||||
/** NetBIOS name flags */
|
||||
#define NETB_NFLAG_UNIQUE 0x8000U
|
||||
#define NETB_NFLAG_NODETYPE 0x6000U
|
||||
@@ -82,6 +89,10 @@
|
||||
#define NETB_NFLAG_NODETYPE_PNODE 0x2000U
|
||||
#define NETB_NFLAG_NODETYPE_BNODE 0x0000U
|
||||
|
||||
#define NETB_NFLAG_NAME_IN_CONFLICT 0x0800U /* 1=Yes, 0=No */
|
||||
#define NETB_NFLAG_NAME_IS_ACTIVE 0x0400U /* 1=Yes, 0=No */
|
||||
#define NETB_NFLAG_NAME_IS_PERMANENT 0x0200U /* 1=Yes (Name is Permanent Node Name), 0=No */
|
||||
|
||||
/** NetBIOS message header */
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
@@ -100,6 +111,22 @@ PACK_STRUCT_END
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
/** NetBIOS message question part */
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct netbios_question_hdr {
|
||||
PACK_STRUCT_FLD_8(u8_t nametype);
|
||||
PACK_STRUCT_FLD_8(u8_t encname[(NETBIOS_NAME_LEN * 2) + 1]);
|
||||
PACK_STRUCT_FIELD(u16_t type);
|
||||
PACK_STRUCT_FIELD(u16_t cls);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
/** NetBIOS message name part */
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
@@ -107,7 +134,7 @@ PACK_STRUCT_END
|
||||
PACK_STRUCT_BEGIN
|
||||
struct netbios_name_hdr {
|
||||
PACK_STRUCT_FLD_8(u8_t nametype);
|
||||
PACK_STRUCT_FLD_8(u8_t encname[(NETBIOS_NAME_LEN*2)+1]);
|
||||
PACK_STRUCT_FLD_8(u8_t encname[(NETBIOS_NAME_LEN * 2) + 1]);
|
||||
PACK_STRUCT_FIELD(u16_t type);
|
||||
PACK_STRUCT_FIELD(u16_t cls);
|
||||
PACK_STRUCT_FIELD(u32_t ttl);
|
||||
@@ -125,8 +152,7 @@ PACK_STRUCT_END
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct netbios_resp
|
||||
{
|
||||
struct netbios_resp {
|
||||
struct netbios_hdr resp_hdr;
|
||||
struct netbios_name_hdr resp_name;
|
||||
} PACK_STRUCT_STRUCT;
|
||||
@@ -135,6 +161,74 @@ PACK_STRUCT_END
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
/** The NBNS Structure Responds to a Name Query */
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct netbios_answer {
|
||||
struct netbios_hdr answer_hdr;
|
||||
/** the length of the next string */
|
||||
PACK_STRUCT_FIELD(u8_t name_size);
|
||||
/** WARNING!!! this item may be of a different length (we use this struct for transmission) */
|
||||
PACK_STRUCT_FLD_8(u8_t query_name[(NETBIOS_NAME_LEN * 2) + 1]);
|
||||
PACK_STRUCT_FIELD(u16_t packet_type);
|
||||
PACK_STRUCT_FIELD(u16_t cls);
|
||||
PACK_STRUCT_FIELD(u32_t ttl);
|
||||
PACK_STRUCT_FIELD(u16_t data_length);
|
||||
#define OFFSETOF_STRUCT_NETBIOS_ANSWER_NUMBER_OF_NAMES 56
|
||||
/** number of names */
|
||||
PACK_STRUCT_FLD_8(u8_t number_of_names);
|
||||
/** node name */
|
||||
PACK_STRUCT_FLD_8(u8_t answer_name[NETBIOS_NAME_LEN]);
|
||||
/** node flags */
|
||||
PACK_STRUCT_FIELD(u16_t answer_name_flags);
|
||||
/** Unit ID */
|
||||
PACK_STRUCT_FLD_8(u8_t unit_id[6]);
|
||||
/** Jumpers */
|
||||
PACK_STRUCT_FLD_8(u8_t jumpers);
|
||||
/** Test result */
|
||||
PACK_STRUCT_FLD_8(u8_t test_result);
|
||||
/** Version number */
|
||||
PACK_STRUCT_FIELD(u16_t version_number);
|
||||
/** Period of statistics */
|
||||
PACK_STRUCT_FIELD(u16_t period_of_statistics);
|
||||
/** Statistics */
|
||||
PACK_STRUCT_FIELD(u16_t number_of_crcs);
|
||||
/** Statistics */
|
||||
PACK_STRUCT_FIELD(u16_t number_of_alignment_errors);
|
||||
/** Statistics */
|
||||
PACK_STRUCT_FIELD(u16_t number_of_collisions);
|
||||
/** Statistics */
|
||||
PACK_STRUCT_FIELD(u16_t number_of_send_aborts);
|
||||
/** Statistics */
|
||||
PACK_STRUCT_FIELD(u32_t number_of_good_sends);
|
||||
/** Statistics */
|
||||
PACK_STRUCT_FIELD(u32_t number_of_good_receives);
|
||||
/** Statistics */
|
||||
PACK_STRUCT_FIELD(u16_t number_of_retransmits);
|
||||
/** Statistics */
|
||||
PACK_STRUCT_FIELD(u16_t number_of_no_resource_condition);
|
||||
/** Statistics */
|
||||
PACK_STRUCT_FIELD(u16_t number_of_free_command_blocks);
|
||||
/** Statistics */
|
||||
PACK_STRUCT_FIELD(u16_t total_number_of_command_blocks);
|
||||
/** Statistics */
|
||||
PACK_STRUCT_FIELD(u16_t max_total_number_of_command_blocks);
|
||||
/** Statistics */
|
||||
PACK_STRUCT_FIELD(u16_t number_of_pending_sessions);
|
||||
/** Statistics */
|
||||
PACK_STRUCT_FIELD(u16_t max_number_of_pending_sessions);
|
||||
/** Statistics */
|
||||
PACK_STRUCT_FIELD(u16_t max_total_sessions_possible);
|
||||
/** Statistics */
|
||||
PACK_STRUCT_FIELD(u16_t session_data_packet_size);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
#ifdef NETBIOS_LWIP_NAME
|
||||
#define NETBIOS_LOCAL_NAME NETBIOS_LWIP_NAME
|
||||
#else
|
||||
@@ -142,16 +236,16 @@ static char netbiosns_local_name[NETBIOS_NAME_LEN];
|
||||
#define NETBIOS_LOCAL_NAME netbiosns_local_name
|
||||
#endif
|
||||
|
||||
struct udp_pcb *netbiosns_pcb;
|
||||
static struct udp_pcb *netbiosns_pcb;
|
||||
|
||||
/** Decode a NetBIOS name (from packet to string) */
|
||||
static int
|
||||
netbiosns_name_decode(char *name_enc, char *name_dec, int name_dec_len)
|
||||
netbiosns_name_decode(const char *name_enc, char *name_dec, int name_dec_len)
|
||||
{
|
||||
char *pname;
|
||||
char cname;
|
||||
char cnbname;
|
||||
int idx = 0;
|
||||
const char *pname;
|
||||
char cname;
|
||||
char cnbname;
|
||||
int idx = 0;
|
||||
|
||||
LWIP_UNUSED_ARG(name_dec_len);
|
||||
|
||||
@@ -161,11 +255,13 @@ netbiosns_name_decode(char *name_enc, char *name_dec, int name_dec_len)
|
||||
/* Every two characters of the first level-encoded name
|
||||
* turn into one character in the decoded name. */
|
||||
cname = *pname;
|
||||
if (cname == '\0')
|
||||
break; /* no more characters */
|
||||
if (cname == '.')
|
||||
break; /* scope ID follows */
|
||||
if (cname < 'A' || cname > 'Z') {
|
||||
if (cname == '\0') {
|
||||
break; /* no more characters */
|
||||
}
|
||||
if (cname == '.') {
|
||||
break; /* scope ID follows */
|
||||
}
|
||||
if (!lwip_isupper(cname)) {
|
||||
/* Not legal. */
|
||||
return -1;
|
||||
}
|
||||
@@ -174,12 +270,7 @@ netbiosns_name_decode(char *name_enc, char *name_dec, int name_dec_len)
|
||||
pname++;
|
||||
|
||||
cname = *pname;
|
||||
if (cname == '\0' || cname == '.') {
|
||||
/* No more characters in the name - but we're in
|
||||
* the middle of a pair. Not legal. */
|
||||
return -1;
|
||||
}
|
||||
if (cname < 'A' || cname > 'Z') {
|
||||
if (!lwip_isupper(cname)) {
|
||||
/* Not legal. */
|
||||
return -1;
|
||||
}
|
||||
@@ -190,7 +281,7 @@ netbiosns_name_decode(char *name_enc, char *name_dec, int name_dec_len)
|
||||
/* Do we have room to store the character? */
|
||||
if (idx < NETBIOS_NAME_LEN) {
|
||||
/* Yes - store the character. */
|
||||
name_dec[idx++] = (cnbname!=' '?cnbname:'\0');
|
||||
name_dec[idx++] = (cnbname != ' ' ? cnbname : '\0');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,10 +306,12 @@ netbiosns_name_encode(char *name_enc, char *name_dec, int name_dec_len)
|
||||
/* Every two characters of the first level-encoded name
|
||||
* turn into one character in the decoded name. */
|
||||
cname = *pname;
|
||||
if (cname == '\0')
|
||||
break; /* no more characters */
|
||||
if (cname == '.')
|
||||
break; /* scope ID follows */
|
||||
if (cname == '\0') {
|
||||
break; /* no more characters */
|
||||
}
|
||||
if (cname == '.') {
|
||||
break; /* scope ID follows */
|
||||
}
|
||||
if ((cname < 'A' || cname > 'Z') && (cname < '0' || cname > '9')) {
|
||||
/* Not legal. */
|
||||
return -1;
|
||||
@@ -231,13 +324,13 @@ netbiosns_name_encode(char *name_enc, char *name_dec, int name_dec_len)
|
||||
|
||||
/* Yes - store the character. */
|
||||
ucname = cname;
|
||||
name_dec[idx++] = ('A'+((ucname>>4) & 0x0F));
|
||||
name_dec[idx++] = ('A'+( ucname & 0x0F));
|
||||
name_dec[idx++] = ('A' + ((ucname >> 4) & 0x0F));
|
||||
name_dec[idx++] = ('A' + ( ucname & 0x0F));
|
||||
pname++;
|
||||
}
|
||||
|
||||
/* Fill with "space" coding */
|
||||
for (;idx < name_dec_len - 1;) {
|
||||
for (; idx < name_dec_len - 1;) {
|
||||
name_dec[idx++] = 'C';
|
||||
name_dec[idx++] = 'A';
|
||||
}
|
||||
@@ -257,55 +350,118 @@ netbiosns_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t
|
||||
|
||||
/* if packet is valid */
|
||||
if (p != NULL) {
|
||||
char netbios_name[NETBIOS_NAME_LEN+1];
|
||||
struct netbios_hdr* netbios_hdr = (struct netbios_hdr*)p->payload;
|
||||
struct netbios_name_hdr* netbios_name_hdr = (struct netbios_name_hdr*)(netbios_hdr+1);
|
||||
char netbios_name[NETBIOS_NAME_LEN + 1];
|
||||
struct netbios_hdr *netbios_hdr = (struct netbios_hdr *)p->payload;
|
||||
struct netbios_question_hdr *netbios_question_hdr = (struct netbios_question_hdr *)(netbios_hdr + 1);
|
||||
|
||||
/* is the packet long enough (we need the header in one piece) */
|
||||
if (p->len < (sizeof(struct netbios_hdr) + sizeof(struct netbios_question_hdr))) {
|
||||
/* packet too short */
|
||||
pbuf_free(p);
|
||||
return;
|
||||
}
|
||||
/* we only answer if we got a default interface */
|
||||
if (netif_default != NULL) {
|
||||
/* @todo: do we need to check answerRRs/authorityRRs/additionalRRs? */
|
||||
/* if the packet is a NetBIOS name query question */
|
||||
if (((netbios_hdr->flags & PP_NTOHS(NETB_HFLAG_OPCODE)) == PP_NTOHS(NETB_HFLAG_OPCODE_NAME_QUERY)) &&
|
||||
((netbios_hdr->flags & PP_NTOHS(NETB_HFLAG_RESPONSE)) == 0) &&
|
||||
(netbios_hdr->questions == PP_NTOHS(1))) {
|
||||
(netbios_hdr->questions == PP_NTOHS(1))) {
|
||||
/* decode the NetBIOS name */
|
||||
netbiosns_name_decode((char*)(netbios_name_hdr->encname), netbios_name, sizeof(netbios_name));
|
||||
/* if the packet is for us */
|
||||
if (lwip_strnicmp(netbios_name, NETBIOS_LOCAL_NAME, sizeof(NETBIOS_LOCAL_NAME)) == 0) {
|
||||
struct pbuf *q;
|
||||
struct netbios_resp *resp;
|
||||
netbiosns_name_decode((char *)(netbios_question_hdr->encname), netbios_name, sizeof(netbios_name));
|
||||
/* check the request type */
|
||||
if (netbios_question_hdr->type == PP_HTONS(NETB_QTYPE_NB)) {
|
||||
/* if the packet is for us */
|
||||
if (lwip_strnicmp(netbios_name, NETBIOS_LOCAL_NAME, sizeof(NETBIOS_LOCAL_NAME)) == 0) {
|
||||
struct pbuf *q;
|
||||
struct netbios_resp *resp;
|
||||
|
||||
q = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct netbios_resp), PBUF_RAM);
|
||||
if (q != NULL) {
|
||||
resp = (struct netbios_resp*)q->payload;
|
||||
q = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct netbios_resp), PBUF_RAM);
|
||||
if (q != NULL) {
|
||||
resp = (struct netbios_resp *)q->payload;
|
||||
|
||||
/* prepare NetBIOS header response */
|
||||
resp->resp_hdr.trans_id = netbios_hdr->trans_id;
|
||||
resp->resp_hdr.flags = PP_HTONS(NETB_HFLAG_RESPONSE |
|
||||
NETB_HFLAG_OPCODE_NAME_QUERY |
|
||||
NETB_HFLAG_AUTHORATIVE |
|
||||
NETB_HFLAG_RECURS_DESIRED);
|
||||
resp->resp_hdr.questions = 0;
|
||||
resp->resp_hdr.answerRRs = PP_HTONS(1);
|
||||
resp->resp_hdr.authorityRRs = 0;
|
||||
resp->resp_hdr.additionalRRs = 0;
|
||||
/* prepare NetBIOS header response */
|
||||
resp->resp_hdr.trans_id = netbios_hdr->trans_id;
|
||||
resp->resp_hdr.flags = PP_HTONS(NETB_HFLAG_RESPONSE |
|
||||
NETB_HFLAG_OPCODE_NAME_QUERY |
|
||||
NETB_HFLAG_AUTHORATIVE |
|
||||
NETB_HFLAG_RECURS_DESIRED);
|
||||
resp->resp_hdr.questions = 0;
|
||||
resp->resp_hdr.answerRRs = PP_HTONS(1);
|
||||
resp->resp_hdr.authorityRRs = 0;
|
||||
resp->resp_hdr.additionalRRs = 0;
|
||||
|
||||
/* prepare NetBIOS header datas */
|
||||
MEMCPY( resp->resp_name.encname, netbios_name_hdr->encname, sizeof(netbios_name_hdr->encname));
|
||||
resp->resp_name.nametype = netbios_name_hdr->nametype;
|
||||
resp->resp_name.type = netbios_name_hdr->type;
|
||||
resp->resp_name.cls = netbios_name_hdr->cls;
|
||||
resp->resp_name.ttl = PP_HTONL(NETBIOS_NAME_TTL);
|
||||
resp->resp_name.datalen = PP_HTONS(sizeof(resp->resp_name.flags)+sizeof(resp->resp_name.addr));
|
||||
resp->resp_name.flags = PP_HTONS(NETB_NFLAG_NODETYPE_BNODE);
|
||||
ip4_addr_copy(resp->resp_name.addr, *netif_ip4_addr(netif_default));
|
||||
/* prepare NetBIOS header datas */
|
||||
MEMCPY( resp->resp_name.encname, netbios_question_hdr->encname, sizeof(netbios_question_hdr->encname));
|
||||
resp->resp_name.nametype = netbios_question_hdr->nametype;
|
||||
resp->resp_name.type = netbios_question_hdr->type;
|
||||
resp->resp_name.cls = netbios_question_hdr->cls;
|
||||
resp->resp_name.ttl = PP_HTONL(NETBIOS_NAME_TTL);
|
||||
resp->resp_name.datalen = PP_HTONS(sizeof(resp->resp_name.flags) + sizeof(resp->resp_name.addr));
|
||||
resp->resp_name.flags = PP_HTONS(NETB_NFLAG_NODETYPE_BNODE);
|
||||
ip4_addr_copy(resp->resp_name.addr, *netif_ip4_addr(netif_default));
|
||||
|
||||
/* send the NetBIOS response */
|
||||
udp_sendto(upcb, q, addr, port);
|
||||
/* send the NetBIOS response */
|
||||
udp_sendto(upcb, q, addr, port);
|
||||
|
||||
/* free the "reference" pbuf */
|
||||
pbuf_free(q);
|
||||
/* free the "reference" pbuf */
|
||||
pbuf_free(q);
|
||||
}
|
||||
}
|
||||
#if LWIP_NETBIOS_RESPOND_NAME_QUERY
|
||||
} else if (netbios_question_hdr->type == PP_HTONS(NETB_QTYPE_NBSTAT)) {
|
||||
/* if the packet is for us or general query */
|
||||
if (!lwip_strnicmp(netbios_name, NETBIOS_LOCAL_NAME, sizeof(NETBIOS_LOCAL_NAME)) ||
|
||||
!lwip_strnicmp(netbios_name, "*", sizeof(NETBIOS_LOCAL_NAME))) {
|
||||
/* general query - ask for our IP address */
|
||||
struct pbuf *q;
|
||||
struct netbios_answer *resp;
|
||||
|
||||
q = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct netbios_answer), PBUF_RAM);
|
||||
if (q != NULL) {
|
||||
/* buffer to which a response is compiled */
|
||||
resp = (struct netbios_answer *) q->payload;
|
||||
|
||||
/* Init response to zero, especially the statistics fields */
|
||||
memset(resp, 0, sizeof(*resp));
|
||||
|
||||
/* copy the query to the response ID */
|
||||
resp->answer_hdr.trans_id = netbios_hdr->trans_id;
|
||||
/* acknowledgment of termination */
|
||||
resp->answer_hdr.flags = PP_HTONS(NETB_HFLAG_RESPONSE | NETB_HFLAG_OPCODE_NAME_QUERY | NETB_HFLAG_AUTHORATIVE);
|
||||
/* resp->answer_hdr.questions = PP_HTONS(0); done by memset() */
|
||||
/* serial number of the answer */
|
||||
resp->answer_hdr.answerRRs = PP_HTONS(1);
|
||||
/* resp->answer_hdr.authorityRRs = PP_HTONS(0); done by memset() */
|
||||
/* resp->answer_hdr.additionalRRs = PP_HTONS(0); done by memset() */
|
||||
/* we will copy the length of the station name */
|
||||
resp->name_size = netbios_question_hdr->nametype;
|
||||
/* we will copy the queried name */
|
||||
MEMCPY(resp->query_name, netbios_question_hdr->encname, (NETBIOS_NAME_LEN * 2) + 1);
|
||||
/* NBSTAT */
|
||||
resp->packet_type = PP_HTONS(0x21);
|
||||
/* Internet name */
|
||||
resp->cls = PP_HTONS(1);
|
||||
/* resp->ttl = PP_HTONL(0); done by memset() */
|
||||
resp->data_length = PP_HTONS(sizeof(struct netbios_answer) - offsetof(struct netbios_answer, number_of_names));
|
||||
resp->number_of_names = 1;
|
||||
|
||||
/* make windows see us as workstation, not as a server */
|
||||
memset(resp->answer_name, 0x20, NETBIOS_NAME_LEN - 1);
|
||||
/* strlen is checked to be < NETBIOS_NAME_LEN during initialization */
|
||||
MEMCPY(resp->answer_name, NETBIOS_LOCAL_NAME, strlen(NETBIOS_LOCAL_NAME));
|
||||
|
||||
/* b-node, unique, active */
|
||||
resp->answer_name_flags = PP_HTONS(NETB_NFLAG_NAME_IS_ACTIVE);
|
||||
|
||||
/* Set responder netif MAC address */
|
||||
SMEMCPY(resp->unit_id, ip_current_input_netif()->hwaddr, sizeof(resp->unit_id));
|
||||
|
||||
udp_sendto(upcb, q, addr, port);
|
||||
pbuf_free(q);
|
||||
}
|
||||
}
|
||||
#endif /* LWIP_NETBIOS_RESPOND_NAME_QUERY */
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -315,12 +471,13 @@ netbiosns_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup netbiosns
|
||||
* @ingroup netbiosns
|
||||
* Init netbios responder
|
||||
*/
|
||||
void
|
||||
netbiosns_init(void)
|
||||
{
|
||||
/* LWIP_ASSERT_CORE_LOCKED(); is checked by udp_new() */
|
||||
#ifdef NETBIOS_LWIP_NAME
|
||||
LWIP_ASSERT("NetBIOS name is too long!", strlen(NETBIOS_LWIP_NAME) < NETBIOS_NAME_LEN);
|
||||
#endif
|
||||
@@ -329,35 +486,44 @@ netbiosns_init(void)
|
||||
if (netbiosns_pcb != NULL) {
|
||||
/* we have to be allowed to send broadcast packets! */
|
||||
ip_set_option(netbiosns_pcb, SOF_BROADCAST);
|
||||
udp_bind(netbiosns_pcb, IP_ANY_TYPE, NETBIOS_PORT);
|
||||
udp_bind(netbiosns_pcb, IP_ANY_TYPE, LWIP_IANA_PORT_NETBIOS);
|
||||
udp_recv(netbiosns_pcb, netbiosns_recv, netbiosns_pcb);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NETBIOS_LWIP_NAME
|
||||
/**
|
||||
* @ingroup netbiosns
|
||||
* @ingroup netbiosns
|
||||
* Set netbios name. ATTENTION: the hostname must be less than 15 characters!
|
||||
* the NetBIOS name spec says the name MUST be upper case, so incoming name is forced into uppercase :-)
|
||||
*/
|
||||
void
|
||||
netbiosns_set_name(const char* hostname)
|
||||
netbiosns_set_name(const char *hostname)
|
||||
{
|
||||
size_t i;
|
||||
size_t copy_len = strlen(hostname);
|
||||
LWIP_ASSERT_CORE_LOCKED();
|
||||
LWIP_ASSERT("NetBIOS name is too long!", copy_len < NETBIOS_NAME_LEN);
|
||||
if (copy_len >= NETBIOS_NAME_LEN) {
|
||||
copy_len = NETBIOS_NAME_LEN - 1;
|
||||
}
|
||||
MEMCPY(netbiosns_local_name, hostname, copy_len + 1);
|
||||
|
||||
/* make name into upper case */
|
||||
for (i = 0; i < copy_len; i++ ) {
|
||||
netbiosns_local_name[i] = (char)lwip_toupper(hostname[i]);
|
||||
}
|
||||
netbiosns_local_name[copy_len] = '\0';
|
||||
}
|
||||
#endif
|
||||
#endif /* NETBIOS_LWIP_NAME */
|
||||
|
||||
/**
|
||||
* @ingroup netbiosns
|
||||
* @ingroup netbiosns
|
||||
* Stop netbios responder
|
||||
*/
|
||||
void
|
||||
netbiosns_stop(void)
|
||||
{
|
||||
LWIP_ASSERT_CORE_LOCKED();
|
||||
if (netbiosns_pcb != NULL) {
|
||||
udp_remove(netbiosns_pcb);
|
||||
netbiosns_pcb = NULL;
|
||||
|
||||
1555
src/apps/smtp/smtp.c
Normal file
1555
src/apps/smtp/smtp.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -54,7 +54,7 @@
|
||||
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
|
||||
*/
|
||||
err_t
|
||||
snmp_ans1_enc_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv)
|
||||
snmp_ans1_enc_tlv(struct snmp_pbuf_stream *pbuf_stream, struct snmp_asn1_tlv *tlv)
|
||||
{
|
||||
u8_t data;
|
||||
u8_t length_bytes_required;
|
||||
@@ -130,7 +130,7 @@ snmp_ans1_enc_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tl
|
||||
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
|
||||
*/
|
||||
err_t
|
||||
snmp_asn1_enc_raw(struct snmp_pbuf_stream* pbuf_stream, const u8_t *raw, u16_t raw_len)
|
||||
snmp_asn1_enc_raw(struct snmp_pbuf_stream *pbuf_stream, const u8_t *raw, u16_t raw_len)
|
||||
{
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_writebuf(pbuf_stream, raw, raw_len));
|
||||
|
||||
@@ -148,7 +148,7 @@ snmp_asn1_enc_raw(struct snmp_pbuf_stream* pbuf_stream, const u8_t *raw, u16_t r
|
||||
* @see snmp_asn1_enc_u32t_cnt()
|
||||
*/
|
||||
err_t
|
||||
snmp_asn1_enc_u32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, u32_t value)
|
||||
snmp_asn1_enc_u32t(struct snmp_pbuf_stream *pbuf_stream, u16_t octets_needed, u32_t value)
|
||||
{
|
||||
if (octets_needed > 5) {
|
||||
return ERR_ARG;
|
||||
@@ -169,48 +169,6 @@ snmp_asn1_enc_u32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, u3
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes u64_t (counter64) into a pbuf chained ASN1 msg.
|
||||
*
|
||||
* @param pbuf_stream points to a pbuf stream
|
||||
* @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt())
|
||||
* @param value is the host order u32_t value to be encoded
|
||||
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
|
||||
*
|
||||
* @see snmp_asn1_enc_u64t_cnt()
|
||||
*/
|
||||
err_t
|
||||
snmp_asn1_enc_u64t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, const u32_t* value)
|
||||
{
|
||||
if (octets_needed > 9) {
|
||||
return ERR_ARG;
|
||||
}
|
||||
if (octets_needed == 9) {
|
||||
/* not enough bits in 'value' add leading 0x00 */
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, 0x00));
|
||||
octets_needed--;
|
||||
}
|
||||
|
||||
while (octets_needed > 4) {
|
||||
octets_needed--;
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value >> ((octets_needed-4) << 3))));
|
||||
}
|
||||
|
||||
/* skip to low u32 */
|
||||
value++;
|
||||
|
||||
while (octets_needed > 1) {
|
||||
octets_needed--;
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value >> (octets_needed << 3))));
|
||||
}
|
||||
|
||||
/* always write at least one octet (also in case of value == 0) */
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value)));
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes s32_t integer into a pbuf chained ASN1 msg.
|
||||
*
|
||||
@@ -222,7 +180,7 @@ snmp_asn1_enc_u64t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, co
|
||||
* @see snmp_asn1_enc_s32t_cnt()
|
||||
*/
|
||||
err_t
|
||||
snmp_asn1_enc_s32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, s32_t value)
|
||||
snmp_asn1_enc_s32t(struct snmp_pbuf_stream *pbuf_stream, u16_t octets_needed, s32_t value)
|
||||
{
|
||||
while (octets_needed > 1) {
|
||||
octets_needed--;
|
||||
@@ -245,7 +203,7 @@ snmp_asn1_enc_s32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, s3
|
||||
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
|
||||
*/
|
||||
err_t
|
||||
snmp_asn1_enc_oid(struct snmp_pbuf_stream* pbuf_stream, const u32_t *oid, u16_t oid_len)
|
||||
snmp_asn1_enc_oid(struct snmp_pbuf_stream *pbuf_stream, const u32_t *oid, u16_t oid_len)
|
||||
{
|
||||
if (oid_len > 1) {
|
||||
/* write compressed first two sub id's */
|
||||
@@ -329,31 +287,6 @@ snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns octet count for an u64_t.
|
||||
*
|
||||
* @param value value to be encoded
|
||||
* @param octets_needed points to the return value
|
||||
*
|
||||
* @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
|
||||
* as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
|
||||
* of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
|
||||
*/
|
||||
void
|
||||
snmp_asn1_enc_u64t_cnt(const u32_t *value, u16_t *octets_needed)
|
||||
{
|
||||
/* check if high u32 is 0 */
|
||||
if (*value == 0x00) {
|
||||
/* only low u32 is important */
|
||||
value++;
|
||||
snmp_asn1_enc_u32t_cnt(*value, octets_needed);
|
||||
} else {
|
||||
/* low u32 does not matter for length determination */
|
||||
snmp_asn1_enc_u32t_cnt(*value, octets_needed);
|
||||
*octets_needed = *octets_needed + 4; /* add the 4 bytes of low u32 */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns octet count for an s32_t.
|
||||
*
|
||||
@@ -420,7 +353,7 @@ snmp_asn1_enc_oid_cnt(const u32_t *oid, u16_t oid_len, u16_t *octets_needed)
|
||||
* @return ERR_OK if successful, ERR_VAL if we can't decode
|
||||
*/
|
||||
err_t
|
||||
snmp_asn1_dec_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv)
|
||||
snmp_asn1_dec_tlv(struct snmp_pbuf_stream *pbuf_stream, struct snmp_asn1_tlv *tlv)
|
||||
{
|
||||
u8_t data;
|
||||
|
||||
@@ -442,6 +375,9 @@ snmp_asn1_dec_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tl
|
||||
tlv->value_len = data;
|
||||
} else if (data > 0x80) { /* long form */
|
||||
u8_t length_bytes = data - 0x80;
|
||||
if (length_bytes > pbuf_stream->length) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
tlv->length_len = length_bytes + 1; /* this byte + defined number of length bytes following */
|
||||
tlv->value_len = 0;
|
||||
|
||||
@@ -509,60 +445,6 @@ snmp_asn1_dec_u32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes large positive integer (counter64) into 2x u32_t.
|
||||
*
|
||||
* @param pbuf_stream points to a pbuf stream
|
||||
* @param len length of the coded integer field
|
||||
* @param value return host order integer
|
||||
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
|
||||
*
|
||||
* @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
|
||||
* as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
|
||||
* of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
|
||||
*/
|
||||
err_t
|
||||
snmp_asn1_dec_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value)
|
||||
{
|
||||
u8_t data;
|
||||
|
||||
if (len <= 4) {
|
||||
/* high u32 is 0 */
|
||||
*value = 0;
|
||||
/* directly skip to low u32 */
|
||||
value++;
|
||||
}
|
||||
|
||||
if ((len > 0) && (len <= 9)) {
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
|
||||
|
||||
/* expecting sign bit to be zero, only unsigned please! */
|
||||
if (((len == 9) && (data == 0x00)) || ((len < 9) && ((data & 0x80) == 0))) {
|
||||
*value = data;
|
||||
len--;
|
||||
|
||||
while (len > 0) {
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
|
||||
|
||||
if (len == 4) {
|
||||
/* skip to low u32 */
|
||||
value++;
|
||||
*value = 0;
|
||||
} else {
|
||||
*value <<= 8;
|
||||
}
|
||||
|
||||
*value |= data;
|
||||
len--;
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes integer into s32_t.
|
||||
*
|
||||
@@ -576,51 +458,26 @@ snmp_asn1_dec_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value
|
||||
err_t
|
||||
snmp_asn1_dec_s32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, s32_t *value)
|
||||
{
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
u8_t *lsb_ptr = (u8_t*)value;
|
||||
#endif
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
u8_t *lsb_ptr = (u8_t*)value + sizeof(s32_t) - 1;
|
||||
#endif
|
||||
u8_t sign;
|
||||
u8_t data;
|
||||
|
||||
if ((len > 0) && (len < 5)) {
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
|
||||
len--;
|
||||
|
||||
if (data & 0x80) {
|
||||
/* negative, start from -1 */
|
||||
*value = -1;
|
||||
sign = 1;
|
||||
*lsb_ptr &= data;
|
||||
*value = (*value << 8) | data;
|
||||
} else {
|
||||
/* positive, start from 0 */
|
||||
*value = 0;
|
||||
sign = 0;
|
||||
*lsb_ptr |= data;
|
||||
*value = data;
|
||||
}
|
||||
|
||||
/* OR/AND octets with value */
|
||||
len--;
|
||||
/* shift in the remaining value */
|
||||
while (len > 0) {
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
|
||||
*value = (*value << 8) | data;
|
||||
len--;
|
||||
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
*value <<= 8;
|
||||
#endif
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
*value >>= 8;
|
||||
#endif
|
||||
|
||||
if (sign) {
|
||||
*lsb_ptr |= 255;
|
||||
*lsb_ptr &= data;
|
||||
} else {
|
||||
*lsb_ptr |= data;
|
||||
}
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
@@ -638,7 +495,7 @@ snmp_asn1_dec_s32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, s32_t *value
|
||||
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
|
||||
*/
|
||||
err_t
|
||||
snmp_asn1_dec_oid(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t* oid, u8_t* oid_len, u8_t oid_max_len)
|
||||
snmp_asn1_dec_oid(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *oid, u8_t *oid_len, u8_t oid_max_len)
|
||||
{
|
||||
u32_t *oid_ptr;
|
||||
u8_t data;
|
||||
@@ -729,7 +586,7 @@ snmp_asn1_dec_oid(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t* oid, u
|
||||
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
|
||||
*/
|
||||
err_t
|
||||
snmp_asn1_dec_raw(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u8_t *buf, u16_t* buf_len, u16_t buf_max_len)
|
||||
snmp_asn1_dec_raw(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u8_t *buf, u16_t *buf_len, u16_t buf_max_len)
|
||||
{
|
||||
if (len > buf_max_len) {
|
||||
/* not enough dst space */
|
||||
@@ -746,4 +603,102 @@ snmp_asn1_dec_raw(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u8_t *buf, u1
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
#if LWIP_HAVE_INT64
|
||||
/**
|
||||
* Returns octet count for an u64_t.
|
||||
*
|
||||
* @param value value to be encoded
|
||||
* @param octets_needed points to the return value
|
||||
*
|
||||
* @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
|
||||
* as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
|
||||
* of 0xFFFFFFFFFFFFFFFF is preceded with 0x00 and the length is 9 octets!!
|
||||
*/
|
||||
void
|
||||
snmp_asn1_enc_u64t_cnt(u64_t value, u16_t *octets_needed)
|
||||
{
|
||||
/* check if high u32 is 0 */
|
||||
if ((value >> 32) == 0) {
|
||||
/* only low u32 is important */
|
||||
snmp_asn1_enc_u32t_cnt((u32_t)value, octets_needed);
|
||||
} else {
|
||||
/* low u32 does not matter for length determination */
|
||||
snmp_asn1_enc_u32t_cnt((u32_t)(value >> 32), octets_needed);
|
||||
*octets_needed = *octets_needed + 4; /* add the 4 bytes of low u32 */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes large positive integer (counter64) into 2x u32_t.
|
||||
*
|
||||
* @param pbuf_stream points to a pbuf stream
|
||||
* @param len length of the coded integer field
|
||||
* @param value return 64 bit integer
|
||||
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
|
||||
*
|
||||
* @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
|
||||
* as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
|
||||
* of 0xFFFFFFFFFFFFFFFF is preceded with 0x00 and the length is 9 octets!!
|
||||
*/
|
||||
err_t
|
||||
snmp_asn1_dec_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u64_t *value)
|
||||
{
|
||||
u8_t data;
|
||||
|
||||
if ((len > 0) && (len <= 9)) {
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
|
||||
|
||||
/* expecting sign bit to be zero, only unsigned please! */
|
||||
if (((len == 9) && (data == 0x00)) || ((len < 9) && ((data & 0x80) == 0))) {
|
||||
*value = data;
|
||||
len--;
|
||||
|
||||
while (len > 0) {
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
|
||||
*value <<= 8;
|
||||
*value |= data;
|
||||
len--;
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes u64_t (counter64) into a pbuf chained ASN1 msg.
|
||||
*
|
||||
* @param pbuf_stream points to a pbuf stream
|
||||
* @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt())
|
||||
* @param value is the value to be encoded
|
||||
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
|
||||
*
|
||||
* @see snmp_asn1_enc_u64t_cnt()
|
||||
*/
|
||||
err_t
|
||||
snmp_asn1_enc_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t octets_needed, u64_t value)
|
||||
{
|
||||
if (octets_needed > 9) {
|
||||
return ERR_ARG;
|
||||
}
|
||||
if (octets_needed == 9) {
|
||||
/* not enough bits in 'value' add leading 0x00 */
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, 0x00));
|
||||
octets_needed--;
|
||||
}
|
||||
|
||||
while (octets_needed > 1) {
|
||||
octets_needed--;
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(value >> (octets_needed << 3))));
|
||||
}
|
||||
|
||||
/* always write at least one octet (also in case of value == 0) */
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(value)));
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LWIP_SNMP */
|
||||
|
||||
@@ -57,19 +57,21 @@ extern "C" {
|
||||
#define SNMP_ASN1_DATATYPE_MASK 0x1F
|
||||
#define SNMP_ASN1_DATATYPE_EXTENDED 0x1F /* DataType indicating that datatype is encoded in following bytes */
|
||||
|
||||
/* context specific (SNMP) tags (from SNMP spec. RFC1157) */
|
||||
/* context specific (SNMP) tags (from SNMP spec. RFC1157 and RFC1905) */
|
||||
#define SNMP_ASN1_CONTEXT_PDU_GET_REQ 0
|
||||
#define SNMP_ASN1_CONTEXT_PDU_GET_NEXT_REQ 1
|
||||
#define SNMP_ASN1_CONTEXT_PDU_GET_RESP 2
|
||||
#define SNMP_ASN1_CONTEXT_PDU_SET_REQ 3
|
||||
#define SNMP_ASN1_CONTEXT_PDU_TRAP 4
|
||||
#define SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ 5
|
||||
#define SNMP_ASN1_CONTEXT_PDU_INFORM_REQ 6
|
||||
#define SNMP_ASN1_CONTEXT_PDU_V2_TRAP 7
|
||||
#define SNMP_ASN1_CONTEXT_PDU_REPORT 8
|
||||
|
||||
#define SNMP_ASN1_CONTEXT_VARBIND_NO_SUCH_OBJECT 0
|
||||
#define SNMP_ASN1_CONTEXT_VARBIND_END_OF_MIB_VIEW 2
|
||||
|
||||
struct snmp_asn1_tlv
|
||||
{
|
||||
struct snmp_asn1_tlv {
|
||||
u8_t type; /* only U8 because extended types are not specified by SNMP */
|
||||
u8_t type_len; /* encoded length of 'type' field (normally 1) */
|
||||
u8_t length_len; /* indicates how many bytes are required to encode the 'value_len' field */
|
||||
@@ -79,25 +81,28 @@ struct snmp_asn1_tlv
|
||||
#define SNMP_ASN1_TLV_LENGTH(tlv) ((tlv).type_len + (tlv).length_len + (tlv).value_len)
|
||||
#define SNMP_ASN1_SET_TLV_PARAMS(tlv, type_, length_len_, value_len_) do { (tlv).type = (type_); (tlv).type_len = 0; (tlv).length_len = (length_len_); (tlv).value_len = (value_len_); } while (0);
|
||||
|
||||
err_t snmp_asn1_dec_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv);
|
||||
err_t snmp_asn1_dec_tlv(struct snmp_pbuf_stream *pbuf_stream, struct snmp_asn1_tlv *tlv);
|
||||
err_t snmp_asn1_dec_u32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value);
|
||||
err_t snmp_asn1_dec_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value);
|
||||
err_t snmp_asn1_dec_s32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, s32_t *value);
|
||||
err_t snmp_asn1_dec_oid(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t* oid, u8_t* oid_len, u8_t oid_max_len);
|
||||
err_t snmp_asn1_dec_raw(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u8_t *buf, u16_t* buf_len, u16_t buf_max_len);
|
||||
err_t snmp_asn1_dec_oid(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *oid, u8_t *oid_len, u8_t oid_max_len);
|
||||
err_t snmp_asn1_dec_raw(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u8_t *buf, u16_t *buf_len, u16_t buf_max_len);
|
||||
|
||||
err_t snmp_ans1_enc_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv);
|
||||
err_t snmp_ans1_enc_tlv(struct snmp_pbuf_stream *pbuf_stream, struct snmp_asn1_tlv *tlv);
|
||||
|
||||
void snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed);
|
||||
void snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed);
|
||||
void snmp_asn1_enc_u64t_cnt(const u32_t *value, u16_t *octets_needed);
|
||||
void snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed);
|
||||
void snmp_asn1_enc_oid_cnt(const u32_t *oid, u16_t oid_len, u16_t *octets_needed);
|
||||
err_t snmp_asn1_enc_oid(struct snmp_pbuf_stream* pbuf_stream, const u32_t *oid, u16_t oid_len);
|
||||
err_t snmp_asn1_enc_s32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, s32_t value);
|
||||
err_t snmp_asn1_enc_u32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, u32_t value);
|
||||
err_t snmp_asn1_enc_u64t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, const u32_t* value);
|
||||
err_t snmp_asn1_enc_raw(struct snmp_pbuf_stream* pbuf_stream, const u8_t *raw, u16_t raw_len);
|
||||
err_t snmp_asn1_enc_oid(struct snmp_pbuf_stream *pbuf_stream, const u32_t *oid, u16_t oid_len);
|
||||
err_t snmp_asn1_enc_s32t(struct snmp_pbuf_stream *pbuf_stream, u16_t octets_needed, s32_t value);
|
||||
err_t snmp_asn1_enc_u32t(struct snmp_pbuf_stream *pbuf_stream, u16_t octets_needed, u32_t value);
|
||||
err_t snmp_asn1_enc_raw(struct snmp_pbuf_stream *pbuf_stream, const u8_t *raw, u16_t raw_len);
|
||||
|
||||
#if LWIP_HAVE_INT64
|
||||
err_t snmp_asn1_dec_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u64_t *value);
|
||||
void snmp_asn1_enc_u64t_cnt(u64_t value, u16_t *octets_needed);
|
||||
err_t snmp_asn1_enc_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t octets_needed, u64_t value);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -34,24 +34,24 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup snmp SNMPv2c agent
|
||||
* @defgroup snmp SNMPv2c/v3 agent
|
||||
* @ingroup apps
|
||||
* SNMPv2c compatible agent\n
|
||||
* SNMPv2c and SNMPv3 compatible agent\n
|
||||
* There is also a MIB compiler and a MIB viewer in lwIP contrib repository
|
||||
* (lwip-contrib/apps/LwipMibCompiler).\n
|
||||
* The agent implements the most important MIB2 MIBs including IPv6 support
|
||||
* (interfaces, UDP, TCP, SNMP, ICMP, SYSTEM). IP MIB is an older version
|
||||
* whithout IPv6 statistics (TODO).\n
|
||||
* without IPv6 statistics (TODO).\n
|
||||
* Rewritten by Martin Hentschel <info@cl-soft.de> and
|
||||
* Dirk Ziegelmeier <dziegel@gmx.de>\n
|
||||
* Work on SNMPv3 has started, but is not finished.\n
|
||||
*
|
||||
* 0 Agent Capabilities
|
||||
* ====================
|
||||
*
|
||||
*
|
||||
* Features:
|
||||
* ---------
|
||||
* - SNMPv2c support.
|
||||
* - SNMPv3 support (a port to ARM mbedtls is provided, LWIP_SNMP_V3_MBEDTLS option).
|
||||
* - Low RAM usage - no memory pools, stack only.
|
||||
* - MIB2 implementation is separated from SNMP stack.
|
||||
* - Support for multiple MIBs (snmp_set_mibs() call) - e.g. for private MIB.
|
||||
@@ -66,7 +66,7 @@
|
||||
* - Simplified thread sync support for MIBs - useful when MIBs
|
||||
* need to access variables shared with other threads where no locking is
|
||||
* possible. Used in MIB2 to access lwIP stats from lwIP thread.
|
||||
*
|
||||
*
|
||||
* MIB compiler (code generator):
|
||||
* ------------------------------
|
||||
* - Provided in lwIP contrib repository.
|
||||
@@ -78,92 +78,100 @@
|
||||
* - MIB parser, C file generation framework and LWIP code generation are cleanly
|
||||
* separated, which means the code may be useful as a base for code generation
|
||||
* of other SNMP agents.
|
||||
*
|
||||
*
|
||||
* Notes:
|
||||
* ------
|
||||
* - Stack and MIB compiler were used to implement a Profinet device.
|
||||
* Compiled/implemented MIBs: LLDP-MIB, LLDP-EXT-DOT3-MIB, LLDP-EXT-PNO-MIB.
|
||||
*
|
||||
*
|
||||
* SNMPv1 per RFC1157 and SNMPv2c per RFC 3416
|
||||
* -------------------------------------------
|
||||
* Note the S in SNMP stands for "Simple". Note that "Simple" is
|
||||
* relative. SNMP is simple compared to the complex ISO network
|
||||
* management protocols CMIP (Common Management Information Protocol)
|
||||
* and CMOT (CMip Over Tcp).
|
||||
*
|
||||
*
|
||||
* SNMPv3
|
||||
* ------
|
||||
* When SNMPv3 is used, several functions from snmpv3.h must be implemented
|
||||
* by the user. This is mainly user management and persistence handling.
|
||||
* The sample provided in lwip-contrib is insecure, don't use it in production
|
||||
* systems, especially the missing persistence for engine boots variable
|
||||
* simplifies replay attacks.
|
||||
*
|
||||
* MIB II
|
||||
* ------
|
||||
* The standard lwIP stack management information base.
|
||||
* This is a required MIB, so this is always enabled.
|
||||
* The groups EGP, CMOT and transmission are disabled by default.
|
||||
*
|
||||
*
|
||||
* Most mib-2 objects are not writable except:
|
||||
* sysName, sysLocation, sysContact, snmpEnableAuthenTraps.
|
||||
* Writing to or changing the ARP and IP address and route
|
||||
* tables is not possible.
|
||||
*
|
||||
*
|
||||
* Note lwIP has a very limited notion of IP routing. It currently
|
||||
* doen't have a route table and doesn't have a notion of the U,G,H flags.
|
||||
* Instead lwIP uses the interface list with only one default interface
|
||||
* acting as a single gateway interface (G) for the default route.
|
||||
*
|
||||
*
|
||||
* The agent returns a "virtual table" with the default route 0.0.0.0
|
||||
* for the default interface and network routes (no H) for each
|
||||
* network interface in the netif_list.
|
||||
* All routes are considered to be up (U).
|
||||
*
|
||||
*
|
||||
* Loading additional MIBs
|
||||
* -----------------------
|
||||
* MIBs can only be added in compile-time, not in run-time.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* 1 Building the Agent
|
||||
* ====================
|
||||
* First of all you'll need to add the following define
|
||||
* to your local lwipopts.h:
|
||||
* \#define LWIP_SNMP 1
|
||||
*
|
||||
*
|
||||
* and add the source files your makefile.
|
||||
*
|
||||
*
|
||||
* Note you'll might need to adapt you network driver to update
|
||||
* the mib2 variables for your interface.
|
||||
*
|
||||
*
|
||||
* 2 Running the Agent
|
||||
* ===================
|
||||
* The following function calls must be made in your program to
|
||||
* actually get the SNMP agent running.
|
||||
*
|
||||
*
|
||||
* Before starting the agent you should supply pointers
|
||||
* for sysContact, sysLocation, and snmpEnableAuthenTraps.
|
||||
* You can do this by calling
|
||||
*
|
||||
*
|
||||
* - snmp_mib2_set_syscontact()
|
||||
* - snmp_mib2_set_syslocation()
|
||||
* - snmp_set_auth_traps_enabled()
|
||||
*
|
||||
* You can register a callback which is called on successful write access:
|
||||
*
|
||||
* You can register a callback which is called on successful write access:
|
||||
* snmp_set_write_callback().
|
||||
*
|
||||
*
|
||||
* Additionally you may want to set
|
||||
*
|
||||
*
|
||||
* - snmp_mib2_set_sysdescr()
|
||||
* - snmp_set_device_enterprise_oid()
|
||||
* - snmp_mib2_set_sysname()
|
||||
*
|
||||
*
|
||||
* Also before starting the agent you need to setup
|
||||
* one or more trap destinations using these calls:
|
||||
*
|
||||
*
|
||||
* - snmp_trap_dst_enable()
|
||||
* - snmp_trap_dst_ip_set()
|
||||
*
|
||||
*
|
||||
* If you need more than MIB2, set the MIBs you want to use
|
||||
* by snmp_set_mibs().
|
||||
*
|
||||
*
|
||||
* Finally, enable the agent by calling snmp_init()
|
||||
*
|
||||
* @defgroup snmp_core Core
|
||||
* @ingroup snmp
|
||||
*
|
||||
*
|
||||
* @defgroup snmp_traps Traps
|
||||
* @ingroup snmp
|
||||
*/
|
||||
@@ -180,31 +188,39 @@
|
||||
|
||||
|
||||
#if (LWIP_SNMP && (SNMP_TRAP_DESTINATIONS<=0))
|
||||
#error "If you want to use SNMP, you have to define SNMP_TRAP_DESTINATIONS>=1 in your lwipopts.h"
|
||||
#error "If you want to use SNMP, you have to define SNMP_TRAP_DESTINATIONS>=1 in your lwipopts.h"
|
||||
#endif
|
||||
#if (!LWIP_UDP && LWIP_SNMP)
|
||||
#error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h"
|
||||
#error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h"
|
||||
#endif
|
||||
#if SNMP_MAX_OBJ_ID_LEN > 255
|
||||
#error "SNMP_MAX_OBJ_ID_LEN must fit into an u8_t"
|
||||
#endif
|
||||
|
||||
struct snmp_statistics snmp_stats;
|
||||
static const struct snmp_obj_id snmp_device_enterprise_oid_default = {SNMP_DEVICE_ENTERPRISE_OID_LEN, SNMP_DEVICE_ENTERPRISE_OID};
|
||||
static const struct snmp_obj_id* snmp_device_enterprise_oid = &snmp_device_enterprise_oid_default;
|
||||
static const struct snmp_obj_id *snmp_device_enterprise_oid = &snmp_device_enterprise_oid_default;
|
||||
|
||||
const u32_t snmp_zero_dot_zero_values[] = { 0, 0 };
|
||||
const struct snmp_obj_id_const_ref snmp_zero_dot_zero = { LWIP_ARRAYSIZE(snmp_zero_dot_zero_values), snmp_zero_dot_zero_values };
|
||||
|
||||
|
||||
#if SNMP_LWIP_MIB2
|
||||
#if SNMP_LWIP_MIB2 && LWIP_SNMP_V3
|
||||
#include "lwip/apps/snmp_mib2.h"
|
||||
static const struct snmp_mib* const default_mibs[] = { &mib2 };
|
||||
static u8_t snmp_num_mibs = 1;
|
||||
#include "lwip/apps/snmp_snmpv2_framework.h"
|
||||
#include "lwip/apps/snmp_snmpv2_usm.h"
|
||||
static const struct snmp_mib *const default_mibs[] = { &mib2, &snmpframeworkmib, &snmpusmmib };
|
||||
static u8_t snmp_num_mibs = LWIP_ARRAYSIZE(default_mibs);
|
||||
#elif SNMP_LWIP_MIB2
|
||||
#include "lwip/apps/snmp_mib2.h"
|
||||
static const struct snmp_mib *const default_mibs[] = { &mib2 };
|
||||
static u8_t snmp_num_mibs = LWIP_ARRAYSIZE(default_mibs);
|
||||
#else
|
||||
static const struct snmp_mib* const default_mibs[] = { NULL };
|
||||
static const struct snmp_mib *const default_mibs[] = { NULL };
|
||||
static u8_t snmp_num_mibs = 0;
|
||||
#endif
|
||||
|
||||
/* List of known mibs */
|
||||
static struct snmp_mib const * const *snmp_mibs = default_mibs;
|
||||
static struct snmp_mib const *const *snmp_mibs = default_mibs;
|
||||
|
||||
/**
|
||||
* @ingroup snmp_core
|
||||
@@ -219,6 +235,7 @@ static struct snmp_mib const * const *snmp_mibs = default_mibs;
|
||||
void
|
||||
snmp_set_mibs(const struct snmp_mib **mibs, u8_t num_mibs)
|
||||
{
|
||||
LWIP_ASSERT_CORE_LOCKED();
|
||||
LWIP_ASSERT("mibs pointer must be != NULL", (mibs != NULL));
|
||||
LWIP_ASSERT("num_mibs pointer must be != 0", (num_mibs != 0));
|
||||
snmp_mibs = mibs;
|
||||
@@ -232,15 +249,16 @@ snmp_set_mibs(const struct snmp_mib **mibs, u8_t num_mibs)
|
||||
* The 'device enterprise oid' shall point to an OID located under 'private-enterprises' branch (1.3.6.1.4.1.XXX). If a vendor
|
||||
* wants to provide a custom object there, he has to get its own enterprise oid from IANA (http://www.iana.org). It
|
||||
* is not allowed to use LWIP enterprise ID!
|
||||
* In order to identify a specific device it is recommended to create a dedicated OID for each device type under its own
|
||||
* In order to identify a specific device it is recommended to create a dedicated OID for each device type under its own
|
||||
* enterprise oid.
|
||||
* e.g.
|
||||
* device a > 1.3.6.1.4.1.XXX(ent-oid).1(devices).1(device a)
|
||||
* device b > 1.3.6.1.4.1.XXX(ent-oid).1(devices).2(device b)
|
||||
* for more details see description of 'sysObjectID' field in RFC1213-MIB
|
||||
*/
|
||||
void snmp_set_device_enterprise_oid(const struct snmp_obj_id* device_enterprise_oid)
|
||||
void snmp_set_device_enterprise_oid(const struct snmp_obj_id *device_enterprise_oid)
|
||||
{
|
||||
LWIP_ASSERT_CORE_LOCKED();
|
||||
if (device_enterprise_oid == NULL) {
|
||||
snmp_device_enterprise_oid = &snmp_device_enterprise_oid_default;
|
||||
} else {
|
||||
@@ -250,10 +268,11 @@ void snmp_set_device_enterprise_oid(const struct snmp_obj_id* device_enterprise_
|
||||
|
||||
/**
|
||||
* @ingroup snmp_core
|
||||
* Get 'device enterprise oid'
|
||||
* Get 'device enterprise oid'
|
||||
*/
|
||||
const struct snmp_obj_id* snmp_get_device_enterprise_oid(void)
|
||||
const struct snmp_obj_id *snmp_get_device_enterprise_oid(void)
|
||||
{
|
||||
LWIP_ASSERT_CORE_LOCKED();
|
||||
return snmp_device_enterprise_oid;
|
||||
}
|
||||
|
||||
@@ -496,16 +515,16 @@ snmp_oid_to_ip(const u32_t *oid, u8_t oid_len, ip_addr_t *ip)
|
||||
u8_t
|
||||
snmp_oid_to_ip_port(const u32_t *oid, u8_t oid_len, ip_addr_t *ip, u16_t *port)
|
||||
{
|
||||
u8_t idx = 0;
|
||||
u8_t idx;
|
||||
|
||||
/* InetAddressType + InetAddress */
|
||||
idx += snmp_oid_to_ip(&oid[idx], oid_len-idx, ip);
|
||||
idx = snmp_oid_to_ip(&oid[0], oid_len, ip);
|
||||
if (idx == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* InetPortNumber */
|
||||
if (oid_len < (idx+1)) {
|
||||
if (oid_len < (idx + 1)) {
|
||||
return 0;
|
||||
}
|
||||
if (oid[idx] > 0xffff) {
|
||||
@@ -521,14 +540,14 @@ snmp_oid_to_ip_port(const u32_t *oid, u8_t oid_len, ip_addr_t *ip, u16_t *port)
|
||||
|
||||
/**
|
||||
* Assign an OID to struct snmp_obj_id
|
||||
* @param target Assignment target
|
||||
* @param target Assignment target
|
||||
* @param oid OID
|
||||
* @param oid_len OID length
|
||||
*/
|
||||
void
|
||||
snmp_oid_assign(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len)
|
||||
snmp_oid_assign(struct snmp_obj_id *target, const u32_t *oid, u8_t oid_len)
|
||||
{
|
||||
LWIP_ASSERT("oid_len <= LWIP_SNMP_OBJ_ID_LEN", oid_len <= SNMP_MAX_OBJ_ID_LEN);
|
||||
LWIP_ASSERT("oid_len <= SNMP_MAX_OBJ_ID_LEN", oid_len <= SNMP_MAX_OBJ_ID_LEN);
|
||||
|
||||
target->len = oid_len;
|
||||
|
||||
@@ -544,14 +563,14 @@ snmp_oid_assign(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len)
|
||||
* @param oid_len OID length
|
||||
*/
|
||||
void
|
||||
snmp_oid_prefix(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len)
|
||||
snmp_oid_prefix(struct snmp_obj_id *target, const u32_t *oid, u8_t oid_len)
|
||||
{
|
||||
LWIP_ASSERT("target->len + oid_len <= LWIP_SNMP_OBJ_ID_LEN", (target->len + oid_len) <= SNMP_MAX_OBJ_ID_LEN);
|
||||
LWIP_ASSERT("target->len + oid_len <= SNMP_MAX_OBJ_ID_LEN", (target->len + oid_len) <= SNMP_MAX_OBJ_ID_LEN);
|
||||
|
||||
if (oid_len > 0) {
|
||||
/* move existing OID to make room at the beginning for OID to insert */
|
||||
int i;
|
||||
for (i = target->len-1; i>=0; i--) {
|
||||
for (i = target->len - 1; i >= 0; i--) {
|
||||
target->id[i + oid_len] = target->id[i];
|
||||
}
|
||||
|
||||
@@ -569,7 +588,7 @@ snmp_oid_prefix(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len)
|
||||
* @param oid2_len OID 2 length
|
||||
*/
|
||||
void
|
||||
snmp_oid_combine(struct snmp_obj_id* target, const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len)
|
||||
snmp_oid_combine(struct snmp_obj_id *target, const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len)
|
||||
{
|
||||
snmp_oid_assign(target, oid1, oid1_len);
|
||||
snmp_oid_append(target, oid2, oid2_len);
|
||||
@@ -582,13 +601,13 @@ snmp_oid_combine(struct snmp_obj_id* target, const u32_t *oid1, u8_t oid1_len, c
|
||||
* @param oid_len OID length
|
||||
*/
|
||||
void
|
||||
snmp_oid_append(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len)
|
||||
snmp_oid_append(struct snmp_obj_id *target, const u32_t *oid, u8_t oid_len)
|
||||
{
|
||||
LWIP_ASSERT("offset + oid_len <= LWIP_SNMP_OBJ_ID_LEN", (target->len + oid_len) <= SNMP_MAX_OBJ_ID_LEN);
|
||||
LWIP_ASSERT("offset + oid_len <= SNMP_MAX_OBJ_ID_LEN", (target->len + oid_len) <= SNMP_MAX_OBJ_ID_LEN);
|
||||
|
||||
if (oid_len > 0) {
|
||||
MEMCPY(&target->id[target->len], oid, oid_len * sizeof(u32_t));
|
||||
target->len += oid_len;
|
||||
target->len = (u8_t)(target->len + oid_len);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -644,7 +663,7 @@ snmp_oid_compare(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_
|
||||
u8_t
|
||||
snmp_oid_equal(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len)
|
||||
{
|
||||
return (snmp_oid_compare(oid1, oid1_len, oid2, oid2_len) == 0)? 1 : 0;
|
||||
return (snmp_oid_compare(oid1, oid1_len, oid2, oid2_len) == 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -655,32 +674,18 @@ snmp_oid_equal(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_le
|
||||
u8_t
|
||||
netif_to_num(const struct netif *netif)
|
||||
{
|
||||
u8_t result = 0;
|
||||
struct netif *netif_iterator = netif_list;
|
||||
|
||||
while (netif_iterator != NULL) {
|
||||
result++;
|
||||
|
||||
if (netif_iterator == netif) {
|
||||
return result;
|
||||
}
|
||||
|
||||
netif_iterator = netif_iterator->next;
|
||||
}
|
||||
|
||||
LWIP_ASSERT("netif not found in netif_list", 0);
|
||||
return 0;
|
||||
return netif_get_index(netif);
|
||||
}
|
||||
|
||||
static const struct snmp_mib*
|
||||
static const struct snmp_mib *
|
||||
snmp_get_mib_from_oid(const u32_t *oid, u8_t oid_len)
|
||||
{
|
||||
const u32_t* list_oid;
|
||||
const u32_t* searched_oid;
|
||||
const u32_t *list_oid;
|
||||
const u32_t *searched_oid;
|
||||
u8_t i, l;
|
||||
|
||||
u8_t max_match_len = 0;
|
||||
const struct snmp_mib* matched_mib = NULL;
|
||||
const struct snmp_mib *matched_mib = NULL;
|
||||
|
||||
LWIP_ASSERT("'oid' param must not be NULL!", (oid != NULL));
|
||||
|
||||
@@ -717,11 +722,11 @@ snmp_get_mib_from_oid(const u32_t *oid, u8_t oid_len)
|
||||
return matched_mib;
|
||||
}
|
||||
|
||||
static const struct snmp_mib*
|
||||
static const struct snmp_mib *
|
||||
snmp_get_next_mib(const u32_t *oid, u8_t oid_len)
|
||||
{
|
||||
u8_t i;
|
||||
const struct snmp_mib* next_mib = NULL;
|
||||
const struct snmp_mib *next_mib = NULL;
|
||||
|
||||
LWIP_ASSERT("'oid' param must not be NULL!", (oid != NULL));
|
||||
|
||||
@@ -745,10 +750,10 @@ snmp_get_next_mib(const u32_t *oid, u8_t oid_len)
|
||||
return next_mib;
|
||||
}
|
||||
|
||||
static const struct snmp_mib*
|
||||
static const struct snmp_mib *
|
||||
snmp_get_mib_between(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len)
|
||||
{
|
||||
const struct snmp_mib* next_mib = snmp_get_next_mib(oid1, oid1_len);
|
||||
const struct snmp_mib *next_mib = snmp_get_next_mib(oid1, oid1_len);
|
||||
|
||||
LWIP_ASSERT("'oid2' param must not be NULL!", (oid2 != NULL));
|
||||
LWIP_ASSERT("'oid2_len' param must be greater than 0!", (oid2_len > 0));
|
||||
@@ -763,7 +768,7 @@ snmp_get_mib_between(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t o
|
||||
}
|
||||
|
||||
u8_t
|
||||
snmp_get_node_instance_from_oid(const u32_t *oid, u8_t oid_len, struct snmp_node_instance* node_instance)
|
||||
snmp_get_node_instance_from_oid(const u32_t *oid, u8_t oid_len, struct snmp_node_instance *node_instance)
|
||||
{
|
||||
u8_t result = SNMP_ERR_NOSUCHOBJECT;
|
||||
const struct snmp_mib *mib;
|
||||
@@ -776,15 +781,15 @@ snmp_get_node_instance_from_oid(const u32_t *oid, u8_t oid_len, struct snmp_node
|
||||
mn = snmp_mib_tree_resolve_exact(mib, oid, oid_len, &oid_instance_len);
|
||||
if ((mn != NULL) && (mn->node_type != SNMP_NODE_TREE)) {
|
||||
/* get instance */
|
||||
const struct snmp_leaf_node* leaf_node = (const struct snmp_leaf_node*)(const void*)mn;
|
||||
const struct snmp_leaf_node *leaf_node = (const struct snmp_leaf_node *)(const void *)mn;
|
||||
|
||||
node_instance->node = mn;
|
||||
snmp_oid_assign(&node_instance->instance_oid, oid + (oid_len - oid_instance_len), oid_instance_len);
|
||||
|
||||
result = leaf_node->get_instance(
|
||||
oid,
|
||||
oid_len - oid_instance_len,
|
||||
node_instance);
|
||||
oid,
|
||||
oid_len - oid_instance_len,
|
||||
node_instance);
|
||||
|
||||
#ifdef LWIP_DEBUG
|
||||
if (result == SNMP_ERR_NOERROR) {
|
||||
@@ -803,11 +808,11 @@ snmp_get_node_instance_from_oid(const u32_t *oid, u8_t oid_len, struct snmp_node
|
||||
}
|
||||
|
||||
u8_t
|
||||
snmp_get_next_node_instance_from_oid(const u32_t *oid, u8_t oid_len, snmp_validate_node_instance_method validate_node_instance_method, void* validate_node_instance_arg, struct snmp_obj_id* node_oid, struct snmp_node_instance* node_instance)
|
||||
snmp_get_next_node_instance_from_oid(const u32_t *oid, u8_t oid_len, snmp_validate_node_instance_method validate_node_instance_method, void *validate_node_instance_arg, struct snmp_obj_id *node_oid, struct snmp_node_instance *node_instance)
|
||||
{
|
||||
const struct snmp_mib *mib;
|
||||
const struct snmp_node *mn = NULL;
|
||||
const u32_t* start_oid = NULL;
|
||||
const u32_t *start_oid = NULL;
|
||||
u8_t start_oid_len = 0;
|
||||
|
||||
/* resolve target MIB from passed OID */
|
||||
@@ -843,7 +848,7 @@ snmp_get_next_node_instance_from_oid(const u32_t *oid, u8_t oid_len, snmp_valida
|
||||
/* validate the node; if the node has no further instance or the returned instance is invalid, search for the next in MIB and validate again */
|
||||
node_instance->node = mn;
|
||||
while (mn != NULL) {
|
||||
u8_t result;
|
||||
u8_t result;
|
||||
|
||||
/* clear fields which may have values from previous loops */
|
||||
node_instance->asn1_type = 0;
|
||||
@@ -855,10 +860,10 @@ snmp_get_next_node_instance_from_oid(const u32_t *oid, u8_t oid_len, snmp_valida
|
||||
node_instance->reference.ptr = NULL;
|
||||
node_instance->reference_len = 0;
|
||||
|
||||
result = ((const struct snmp_leaf_node*)(const void*)mn)->get_next_instance(
|
||||
node_oid->id,
|
||||
node_oid->len,
|
||||
node_instance);
|
||||
result = ((const struct snmp_leaf_node *)(const void *)mn)->get_next_instance(
|
||||
node_oid->id,
|
||||
node_oid->len,
|
||||
node_instance);
|
||||
|
||||
if (result == SNMP_ERR_NOERROR) {
|
||||
#ifdef LWIP_DEBUG
|
||||
@@ -906,7 +911,7 @@ snmp_get_next_node_instance_from_oid(const u32_t *oid, u8_t oid_len, snmp_valida
|
||||
/*
|
||||
we found a suitable next node,
|
||||
now we have to check if a inner MIB is located between the searched OID and the resulting OID.
|
||||
this is possible because MIB's may be located anywhere in the global tree, that means also in
|
||||
this is possible because MIB's may be located anywhere in the global tree, that means also in
|
||||
the subtree of another MIB (e.g. if searched OID is .2 and resulting OID is .4, then another
|
||||
MIB having .3 as root node may exist)
|
||||
*/
|
||||
@@ -975,17 +980,17 @@ snmp_get_next_node_instance_from_oid(const u32_t *oid, u8_t oid_len, snmp_valida
|
||||
*
|
||||
*/
|
||||
const struct snmp_node *
|
||||
snmp_mib_tree_resolve_exact(const struct snmp_mib *mib, const u32_t *oid, u8_t oid_len, u8_t* oid_instance_len)
|
||||
snmp_mib_tree_resolve_exact(const struct snmp_mib *mib, const u32_t *oid, u8_t oid_len, u8_t *oid_instance_len)
|
||||
{
|
||||
const struct snmp_node* const* node = &mib->root_node;
|
||||
const struct snmp_node *const *node = &mib->root_node;
|
||||
u8_t oid_offset = mib->base_oid_len;
|
||||
|
||||
while ((oid_offset < oid_len) && ((*node)->node_type == SNMP_NODE_TREE)) {
|
||||
/* search for matching sub node */
|
||||
u32_t subnode_oid = *(oid + oid_offset);
|
||||
|
||||
u32_t i = (*(const struct snmp_tree_node* const*)node)->subnode_count;
|
||||
node = (*(const struct snmp_tree_node* const*)node)->subnodes;
|
||||
u32_t i = (*(const struct snmp_tree_node * const *)node)->subnode_count;
|
||||
node = (*(const struct snmp_tree_node * const *)node)->subnodes;
|
||||
while ((i > 0) && ((*node)->oid != subnode_oid)) {
|
||||
node++;
|
||||
i--;
|
||||
@@ -1008,12 +1013,12 @@ snmp_mib_tree_resolve_exact(const struct snmp_mib *mib, const u32_t *oid, u8_t o
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct snmp_node*
|
||||
snmp_mib_tree_resolve_next(const struct snmp_mib *mib, const u32_t *oid, u8_t oid_len, struct snmp_obj_id* oidret)
|
||||
const struct snmp_node *
|
||||
snmp_mib_tree_resolve_next(const struct snmp_mib *mib, const u32_t *oid, u8_t oid_len, struct snmp_obj_id *oidret)
|
||||
{
|
||||
u8_t oid_offset = mib->base_oid_len;
|
||||
const struct snmp_node* const* node;
|
||||
const struct snmp_tree_node* node_stack[SNMP_MAX_OBJ_ID_LEN];
|
||||
const struct snmp_node *const *node;
|
||||
const struct snmp_tree_node *node_stack[SNMP_MAX_OBJ_ID_LEN];
|
||||
s32_t nsi = 0; /* NodeStackIndex */
|
||||
u32_t subnode_oid;
|
||||
|
||||
@@ -1023,7 +1028,7 @@ snmp_mib_tree_resolve_next(const struct snmp_mib *mib, const u32_t *oid, u8_t oi
|
||||
}
|
||||
|
||||
/* first build node stack related to passed oid (as far as possible), then go backwards to determine the next node */
|
||||
node_stack[nsi] = (const struct snmp_tree_node*)(const void*)mib->root_node;
|
||||
node_stack[nsi] = (const struct snmp_tree_node *)(const void *)mib->root_node;
|
||||
while (oid_offset < oid_len) {
|
||||
/* search for matching sub node */
|
||||
u32_t i = node_stack[nsi]->subnode_count;
|
||||
@@ -1041,7 +1046,7 @@ snmp_mib_tree_resolve_next(const struct snmp_mib *mib, const u32_t *oid, u8_t oi
|
||||
break;
|
||||
}
|
||||
nsi++;
|
||||
node_stack[nsi] = (const struct snmp_tree_node*)(const void*)(*node);
|
||||
node_stack[nsi] = (const struct snmp_tree_node *)(const void *)(*node);
|
||||
|
||||
oid_offset++;
|
||||
}
|
||||
@@ -1055,7 +1060,7 @@ snmp_mib_tree_resolve_next(const struct snmp_mib *mib, const u32_t *oid, u8_t oi
|
||||
}
|
||||
|
||||
while (nsi >= 0) {
|
||||
const struct snmp_node* subnode = NULL;
|
||||
const struct snmp_node *subnode = NULL;
|
||||
|
||||
/* find next node on current level */
|
||||
s32_t i = node_stack[nsi]->subnode_count;
|
||||
@@ -1080,7 +1085,7 @@ snmp_mib_tree_resolve_next(const struct snmp_mib *mib, const u32_t *oid, u8_t oi
|
||||
if (subnode->node_type == SNMP_NODE_TREE) {
|
||||
/* next is a tree node, go into it and start searching */
|
||||
nsi++;
|
||||
node_stack[nsi] = (const struct snmp_tree_node*)(const void*)subnode;
|
||||
node_stack[nsi] = (const struct snmp_tree_node *)(const void *)subnode;
|
||||
subnode_oid = 0;
|
||||
} else {
|
||||
/* we found a leaf node -> fill oidret and return it */
|
||||
@@ -1106,8 +1111,8 @@ snmp_mib_tree_resolve_next(const struct snmp_mib *mib, const u32_t *oid, u8_t oi
|
||||
/** initialize struct next_oid_state using this function before passing it to next_oid_check */
|
||||
void
|
||||
snmp_next_oid_init(struct snmp_next_oid_state *state,
|
||||
const u32_t *start_oid, u8_t start_oid_len,
|
||||
u32_t *next_oid_buf, u8_t next_oid_max_len)
|
||||
const u32_t *start_oid, u8_t start_oid_len,
|
||||
u32_t *next_oid_buf, u8_t next_oid_max_len)
|
||||
{
|
||||
state->start_oid = start_oid;
|
||||
state->start_oid_len = start_oid_len;
|
||||
@@ -1121,7 +1126,7 @@ snmp_next_oid_init(struct snmp_next_oid_state *state,
|
||||
this methid is intended if the complete OID is not yet known but it is very expensive to build it up,
|
||||
so it is possible to test the starting part before building up the complete oid and pass it to snmp_next_oid_check()*/
|
||||
u8_t
|
||||
snmp_next_oid_precheck(struct snmp_next_oid_state *state, const u32_t *oid, const u8_t oid_len)
|
||||
snmp_next_oid_precheck(struct snmp_next_oid_state *state, const u32_t *oid, u8_t oid_len)
|
||||
{
|
||||
if (state->status != SNMP_NEXT_OID_STATUS_BUF_TO_SMALL) {
|
||||
u8_t start_oid_len = (oid_len < state->start_oid_len) ? oid_len : state->start_oid_len;
|
||||
@@ -1130,7 +1135,7 @@ snmp_next_oid_precheck(struct snmp_next_oid_state *state, const u32_t *oid, cons
|
||||
if (snmp_oid_compare(oid, oid_len, state->start_oid, start_oid_len) >= 0) {
|
||||
/* check if new oid is located closer to start oid than current closest oid */
|
||||
if ((state->status == SNMP_NEXT_OID_STATUS_NO_MATCH) ||
|
||||
(snmp_oid_compare(oid, oid_len, state->next_oid, state->next_oid_len) < 0)) {
|
||||
(snmp_oid_compare(oid, oid_len, state->next_oid, state->next_oid_len) < 0)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -1141,7 +1146,7 @@ snmp_next_oid_precheck(struct snmp_next_oid_state *state, const u32_t *oid, cons
|
||||
|
||||
/** checks the passed OID if it is a candidate to be the next one (get_next); returns !=0 if passed oid is currently closest, otherwise 0 */
|
||||
u8_t
|
||||
snmp_next_oid_check(struct snmp_next_oid_state *state, const u32_t *oid, const u8_t oid_len, void* reference)
|
||||
snmp_next_oid_check(struct snmp_next_oid_state *state, const u32_t *oid, u8_t oid_len, void *reference)
|
||||
{
|
||||
/* do not overwrite a fail result */
|
||||
if (state->status != SNMP_NEXT_OID_STATUS_BUF_TO_SMALL) {
|
||||
@@ -1149,7 +1154,7 @@ snmp_next_oid_check(struct snmp_next_oid_state *state, const u32_t *oid, const u
|
||||
if (snmp_oid_compare(oid, oid_len, state->start_oid, state->start_oid_len) > 0) {
|
||||
/* check if new oid is located closer to start oid than current closest oid */
|
||||
if ((state->status == SNMP_NEXT_OID_STATUS_NO_MATCH) ||
|
||||
(snmp_oid_compare(oid, oid_len, state->next_oid, state->next_oid_len) < 0)) {
|
||||
(snmp_oid_compare(oid, oid_len, state->next_oid, state->next_oid_len) < 0)) {
|
||||
if (oid_len <= state->next_oid_max_len) {
|
||||
MEMCPY(state->next_oid, oid, oid_len * sizeof(u32_t));
|
||||
state->next_oid_len = oid_len;
|
||||
@@ -1185,7 +1190,7 @@ snmp_oid_in_range(const u32_t *oid_in, u8_t oid_len, const struct snmp_oid_range
|
||||
}
|
||||
|
||||
snmp_err_t
|
||||
snmp_set_test_ok(struct snmp_node_instance* instance, u16_t value_len, void* value)
|
||||
snmp_set_test_ok(struct snmp_node_instance *instance, u16_t value_len, void *value)
|
||||
{
|
||||
LWIP_UNUSED_ARG(instance);
|
||||
LWIP_UNUSED_ARG(value_len);
|
||||
@@ -1228,8 +1233,7 @@ snmp_decode_bits(const u8_t *buf, u32_t buf_len, u32_t *bit_value)
|
||||
}
|
||||
bits_processed++;
|
||||
b <<= 1;
|
||||
}
|
||||
while ((bits_processed & 0x07) != 0); /* &0x07 -> % 8 */
|
||||
} while ((bits_processed & 0x07) != 0); /* &0x07 -> % 8 */
|
||||
} else {
|
||||
bits_processed += 8;
|
||||
}
|
||||
|
||||
@@ -55,17 +55,24 @@ extern "C" {
|
||||
*/
|
||||
#define SNMP_ERR_TOOBIG 1
|
||||
#define SNMP_ERR_AUTHORIZATIONERROR 16
|
||||
|
||||
#define SNMP_ERR_UNKNOWN_ENGINEID 30
|
||||
#define SNMP_ERR_UNKNOWN_SECURITYNAME 31
|
||||
#define SNMP_ERR_UNSUPPORTED_SECLEVEL 32
|
||||
#define SNMP_ERR_NOTINTIMEWINDOW 33
|
||||
#define SNMP_ERR_DECRYIPTION_ERROR 34
|
||||
|
||||
#define SNMP_ERR_NOSUCHOBJECT SNMP_VARBIND_EXCEPTION_OFFSET + SNMP_ASN1_CONTEXT_VARBIND_NO_SUCH_OBJECT
|
||||
#define SNMP_ERR_ENDOFMIBVIEW SNMP_VARBIND_EXCEPTION_OFFSET + SNMP_ASN1_CONTEXT_VARBIND_END_OF_MIB_VIEW
|
||||
|
||||
|
||||
const struct snmp_node* snmp_mib_tree_resolve_exact(const struct snmp_mib *mib, const u32_t *oid, u8_t oid_len, u8_t* oid_instance_len);
|
||||
const struct snmp_node* snmp_mib_tree_resolve_next(const struct snmp_mib *mib, const u32_t *oid, u8_t oid_len, struct snmp_obj_id* oidret);
|
||||
const struct snmp_node *snmp_mib_tree_resolve_exact(const struct snmp_mib *mib, const u32_t *oid, u8_t oid_len, u8_t *oid_instance_len);
|
||||
const struct snmp_node *snmp_mib_tree_resolve_next(const struct snmp_mib *mib, const u32_t *oid, u8_t oid_len, struct snmp_obj_id *oidret);
|
||||
|
||||
typedef u8_t (*snmp_validate_node_instance_method)(struct snmp_node_instance*, void*);
|
||||
typedef u8_t (*snmp_validate_node_instance_method)(struct snmp_node_instance *, void *);
|
||||
|
||||
u8_t snmp_get_node_instance_from_oid(const u32_t *oid, u8_t oid_len, struct snmp_node_instance* node_instance);
|
||||
u8_t snmp_get_next_node_instance_from_oid(const u32_t *oid, u8_t oid_len, snmp_validate_node_instance_method validate_node_instance_method, void* validate_node_instance_arg, struct snmp_obj_id* node_oid, struct snmp_node_instance* node_instance);
|
||||
u8_t snmp_get_node_instance_from_oid(const u32_t *oid, u8_t oid_len, struct snmp_node_instance *node_instance);
|
||||
u8_t snmp_get_next_node_instance_from_oid(const u32_t *oid, u8_t oid_len, snmp_validate_node_instance_method validate_node_instance_method, void *validate_node_instance_arg, struct snmp_obj_id *node_oid, struct snmp_node_instance *node_instance);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
#include "lwip/tcpip.h"
|
||||
#include "lwip/priv/tcpip_priv.h"
|
||||
void
|
||||
snmp_mib2_lwip_synchronizer(snmp_threadsync_called_fn fn, void* arg)
|
||||
snmp_mib2_lwip_synchronizer(snmp_threadsync_called_fn fn, void *arg)
|
||||
{
|
||||
#if LWIP_TCPIP_CORE_LOCKING
|
||||
LOCK_TCPIP_CORE();
|
||||
@@ -87,7 +87,7 @@ extern const struct snmp_scalar_array_node snmp_mib2_system_node;
|
||||
extern const struct snmp_tree_node snmp_mib2_at_root;
|
||||
extern const struct snmp_tree_node snmp_mib2_ip_root;
|
||||
|
||||
static const struct snmp_node* const mib2_nodes[] = {
|
||||
static const struct snmp_node *const mib2_nodes[] = {
|
||||
&snmp_mib2_system_node.node.node,
|
||||
&snmp_mib2_interface_root.node,
|
||||
#if LWIP_ARP && LWIP_IPV4
|
||||
@@ -110,7 +110,7 @@ static const struct snmp_node* const mib2_nodes[] = {
|
||||
|
||||
static const struct snmp_tree_node mib2_root = SNMP_CREATE_TREE_NODE(1, mib2_nodes);
|
||||
|
||||
static const u32_t mib2_base_oid_arr[] = { 1,3,6,1,2,1 };
|
||||
static const u32_t mib2_base_oid_arr[] = { 1, 3, 6, 1, 2, 1 };
|
||||
const struct snmp_mib mib2 = SNMP_MIB_CREATE(mib2_base_oid_arr, &mib2_root.node);
|
||||
|
||||
#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 */
|
||||
|
||||
@@ -58,90 +58,90 @@
|
||||
static s16_t
|
||||
icmp_get_value(const struct snmp_scalar_array_node_def *node, void *value)
|
||||
{
|
||||
u32_t *uint_ptr = (u32_t*)value;
|
||||
u32_t *uint_ptr = (u32_t *)value;
|
||||
|
||||
switch (node->oid) {
|
||||
case 1: /* icmpInMsgs */
|
||||
*uint_ptr = STATS_GET(mib2.icmpinmsgs);
|
||||
return sizeof(*uint_ptr);
|
||||
case 2: /* icmpInErrors */
|
||||
*uint_ptr = STATS_GET(mib2.icmpinerrors);
|
||||
return sizeof(*uint_ptr);
|
||||
case 3: /* icmpInDestUnreachs */
|
||||
*uint_ptr = STATS_GET(mib2.icmpindestunreachs);
|
||||
return sizeof(*uint_ptr);
|
||||
case 4: /* icmpInTimeExcds */
|
||||
*uint_ptr = STATS_GET(mib2.icmpintimeexcds);
|
||||
return sizeof(*uint_ptr);
|
||||
case 5: /* icmpInParmProbs */
|
||||
*uint_ptr = STATS_GET(mib2.icmpinparmprobs);
|
||||
return sizeof(*uint_ptr);
|
||||
case 6: /* icmpInSrcQuenchs */
|
||||
*uint_ptr = STATS_GET(mib2.icmpinsrcquenchs);
|
||||
return sizeof(*uint_ptr);
|
||||
case 7: /* icmpInRedirects */
|
||||
*uint_ptr = STATS_GET(mib2.icmpinredirects);
|
||||
return sizeof(*uint_ptr);
|
||||
case 8: /* icmpInEchos */
|
||||
*uint_ptr = STATS_GET(mib2.icmpinechos);
|
||||
return sizeof(*uint_ptr);
|
||||
case 9: /* icmpInEchoReps */
|
||||
*uint_ptr = STATS_GET(mib2.icmpinechoreps);
|
||||
return sizeof(*uint_ptr);
|
||||
case 10: /* icmpInTimestamps */
|
||||
*uint_ptr = STATS_GET(mib2.icmpintimestamps);
|
||||
return sizeof(*uint_ptr);
|
||||
case 11: /* icmpInTimestampReps */
|
||||
*uint_ptr = STATS_GET(mib2.icmpintimestampreps);
|
||||
return sizeof(*uint_ptr);
|
||||
case 12: /* icmpInAddrMasks */
|
||||
*uint_ptr = STATS_GET(mib2.icmpinaddrmasks);
|
||||
return sizeof(*uint_ptr);
|
||||
case 13: /* icmpInAddrMaskReps */
|
||||
*uint_ptr = STATS_GET(mib2.icmpinaddrmaskreps);
|
||||
return sizeof(*uint_ptr);
|
||||
case 14: /* icmpOutMsgs */
|
||||
*uint_ptr = STATS_GET(mib2.icmpoutmsgs);
|
||||
return sizeof(*uint_ptr);
|
||||
case 15: /* icmpOutErrors */
|
||||
*uint_ptr = STATS_GET(mib2.icmpouterrors);
|
||||
return sizeof(*uint_ptr);
|
||||
case 16: /* icmpOutDestUnreachs */
|
||||
*uint_ptr = STATS_GET(mib2.icmpoutdestunreachs);
|
||||
return sizeof(*uint_ptr);
|
||||
case 17: /* icmpOutTimeExcds */
|
||||
*uint_ptr = STATS_GET(mib2.icmpouttimeexcds);
|
||||
return sizeof(*uint_ptr);
|
||||
case 18: /* icmpOutParmProbs: not supported -> always 0 */
|
||||
*uint_ptr = 0;
|
||||
return sizeof(*uint_ptr);
|
||||
case 19: /* icmpOutSrcQuenchs: not supported -> always 0 */
|
||||
*uint_ptr = 0;
|
||||
return sizeof(*uint_ptr);
|
||||
case 20: /* icmpOutRedirects: not supported -> always 0 */
|
||||
*uint_ptr = 0;
|
||||
return sizeof(*uint_ptr);
|
||||
case 21: /* icmpOutEchos */
|
||||
*uint_ptr = STATS_GET(mib2.icmpoutechos);
|
||||
return sizeof(*uint_ptr);
|
||||
case 22: /* icmpOutEchoReps */
|
||||
*uint_ptr = STATS_GET(mib2.icmpoutechoreps);
|
||||
return sizeof(*uint_ptr);
|
||||
case 23: /* icmpOutTimestamps: not supported -> always 0 */
|
||||
*uint_ptr = 0;
|
||||
return sizeof(*uint_ptr);
|
||||
case 24: /* icmpOutTimestampReps: not supported -> always 0 */
|
||||
*uint_ptr = 0;
|
||||
return sizeof(*uint_ptr);
|
||||
case 25: /* icmpOutAddrMasks: not supported -> always 0 */
|
||||
*uint_ptr = 0;
|
||||
return sizeof(*uint_ptr);
|
||||
case 26: /* icmpOutAddrMaskReps: not supported -> always 0 */
|
||||
*uint_ptr = 0;
|
||||
return sizeof(*uint_ptr);
|
||||
default:
|
||||
LWIP_DEBUGF(SNMP_MIB_DEBUG,("icmp_get_value(): unknown id: %"S32_F"\n", node->oid));
|
||||
break;
|
||||
case 1: /* icmpInMsgs */
|
||||
*uint_ptr = STATS_GET(mib2.icmpinmsgs);
|
||||
return sizeof(*uint_ptr);
|
||||
case 2: /* icmpInErrors */
|
||||
*uint_ptr = STATS_GET(mib2.icmpinerrors);
|
||||
return sizeof(*uint_ptr);
|
||||
case 3: /* icmpInDestUnreachs */
|
||||
*uint_ptr = STATS_GET(mib2.icmpindestunreachs);
|
||||
return sizeof(*uint_ptr);
|
||||
case 4: /* icmpInTimeExcds */
|
||||
*uint_ptr = STATS_GET(mib2.icmpintimeexcds);
|
||||
return sizeof(*uint_ptr);
|
||||
case 5: /* icmpInParmProbs */
|
||||
*uint_ptr = STATS_GET(mib2.icmpinparmprobs);
|
||||
return sizeof(*uint_ptr);
|
||||
case 6: /* icmpInSrcQuenchs */
|
||||
*uint_ptr = STATS_GET(mib2.icmpinsrcquenchs);
|
||||
return sizeof(*uint_ptr);
|
||||
case 7: /* icmpInRedirects */
|
||||
*uint_ptr = STATS_GET(mib2.icmpinredirects);
|
||||
return sizeof(*uint_ptr);
|
||||
case 8: /* icmpInEchos */
|
||||
*uint_ptr = STATS_GET(mib2.icmpinechos);
|
||||
return sizeof(*uint_ptr);
|
||||
case 9: /* icmpInEchoReps */
|
||||
*uint_ptr = STATS_GET(mib2.icmpinechoreps);
|
||||
return sizeof(*uint_ptr);
|
||||
case 10: /* icmpInTimestamps */
|
||||
*uint_ptr = STATS_GET(mib2.icmpintimestamps);
|
||||
return sizeof(*uint_ptr);
|
||||
case 11: /* icmpInTimestampReps */
|
||||
*uint_ptr = STATS_GET(mib2.icmpintimestampreps);
|
||||
return sizeof(*uint_ptr);
|
||||
case 12: /* icmpInAddrMasks */
|
||||
*uint_ptr = STATS_GET(mib2.icmpinaddrmasks);
|
||||
return sizeof(*uint_ptr);
|
||||
case 13: /* icmpInAddrMaskReps */
|
||||
*uint_ptr = STATS_GET(mib2.icmpinaddrmaskreps);
|
||||
return sizeof(*uint_ptr);
|
||||
case 14: /* icmpOutMsgs */
|
||||
*uint_ptr = STATS_GET(mib2.icmpoutmsgs);
|
||||
return sizeof(*uint_ptr);
|
||||
case 15: /* icmpOutErrors */
|
||||
*uint_ptr = STATS_GET(mib2.icmpouterrors);
|
||||
return sizeof(*uint_ptr);
|
||||
case 16: /* icmpOutDestUnreachs */
|
||||
*uint_ptr = STATS_GET(mib2.icmpoutdestunreachs);
|
||||
return sizeof(*uint_ptr);
|
||||
case 17: /* icmpOutTimeExcds */
|
||||
*uint_ptr = STATS_GET(mib2.icmpouttimeexcds);
|
||||
return sizeof(*uint_ptr);
|
||||
case 18: /* icmpOutParmProbs: not supported -> always 0 */
|
||||
*uint_ptr = 0;
|
||||
return sizeof(*uint_ptr);
|
||||
case 19: /* icmpOutSrcQuenchs: not supported -> always 0 */
|
||||
*uint_ptr = 0;
|
||||
return sizeof(*uint_ptr);
|
||||
case 20: /* icmpOutRedirects: not supported -> always 0 */
|
||||
*uint_ptr = 0;
|
||||
return sizeof(*uint_ptr);
|
||||
case 21: /* icmpOutEchos */
|
||||
*uint_ptr = STATS_GET(mib2.icmpoutechos);
|
||||
return sizeof(*uint_ptr);
|
||||
case 22: /* icmpOutEchoReps */
|
||||
*uint_ptr = STATS_GET(mib2.icmpoutechoreps);
|
||||
return sizeof(*uint_ptr);
|
||||
case 23: /* icmpOutTimestamps: not supported -> always 0 */
|
||||
*uint_ptr = 0;
|
||||
return sizeof(*uint_ptr);
|
||||
case 24: /* icmpOutTimestampReps: not supported -> always 0 */
|
||||
*uint_ptr = 0;
|
||||
return sizeof(*uint_ptr);
|
||||
case 25: /* icmpOutAddrMasks: not supported -> always 0 */
|
||||
*uint_ptr = 0;
|
||||
return sizeof(*uint_ptr);
|
||||
case 26: /* icmpOutAddrMaskReps: not supported -> always 0 */
|
||||
*uint_ptr = 0;
|
||||
return sizeof(*uint_ptr);
|
||||
default:
|
||||
LWIP_DEBUGF(SNMP_MIB_DEBUG, ("icmp_get_value(): unknown id: %"S32_F"\n", node->oid));
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -59,16 +59,15 @@
|
||||
/* --- interfaces .1.3.6.1.2.1.2 ----------------------------------------------------- */
|
||||
|
||||
static s16_t
|
||||
interfaces_get_value(struct snmp_node_instance* instance, void* value)
|
||||
interfaces_get_value(struct snmp_node_instance *instance, void *value)
|
||||
{
|
||||
if (instance->node->oid == 1) {
|
||||
s32_t *sint_ptr = (s32_t*)value;
|
||||
s32_t *sint_ptr = (s32_t *)value;
|
||||
s32_t num_netifs = 0;
|
||||
|
||||
struct netif *netif = netif_list;
|
||||
while (netif != NULL) {
|
||||
struct netif *netif;
|
||||
NETIF_FOREACH(netif) {
|
||||
num_netifs++;
|
||||
netif = netif->next;
|
||||
}
|
||||
|
||||
*sint_ptr = num_netifs;
|
||||
@@ -93,7 +92,7 @@ static const u8_t iftable_ifAdminStatus_lowerLayerDown = 7;
|
||||
static const u8_t iftable_ifAdminStatus_down = 2;
|
||||
|
||||
static snmp_err_t
|
||||
interfaces_Table_get_cell_instance(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, struct snmp_node_instance* cell_instance)
|
||||
interfaces_Table_get_cell_instance(const u32_t *column, const u32_t *row_oid, u8_t row_oid_len, struct snmp_node_instance *cell_instance)
|
||||
{
|
||||
u32_t ifIndex;
|
||||
struct netif *netif;
|
||||
@@ -109,14 +108,12 @@ interfaces_Table_get_cell_instance(const u32_t* column, const u32_t* row_oid, u8
|
||||
ifIndex = row_oid[0];
|
||||
|
||||
/* find netif with index */
|
||||
netif = netif_list;
|
||||
while (netif != NULL) {
|
||||
NETIF_FOREACH(netif) {
|
||||
if (netif_to_num(netif) == ifIndex) {
|
||||
/* store netif pointer for subsequent operations (get/test/set) */
|
||||
cell_instance->reference.ptr = netif;
|
||||
return SNMP_ERR_NOERROR;
|
||||
}
|
||||
netif = netif->next;
|
||||
}
|
||||
|
||||
/* not found */
|
||||
@@ -124,7 +121,7 @@ interfaces_Table_get_cell_instance(const u32_t* column, const u32_t* row_oid, u8
|
||||
}
|
||||
|
||||
static snmp_err_t
|
||||
interfaces_Table_get_next_cell_instance(const u32_t* column, struct snmp_obj_id* row_oid, struct snmp_node_instance* cell_instance)
|
||||
interfaces_Table_get_next_cell_instance(const u32_t *column, struct snmp_obj_id *row_oid, struct snmp_node_instance *cell_instance)
|
||||
{
|
||||
struct netif *netif;
|
||||
struct snmp_next_oid_state state;
|
||||
@@ -136,15 +133,12 @@ interfaces_Table_get_next_cell_instance(const u32_t* column, struct snmp_obj_id*
|
||||
snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(interfaces_Table_oid_ranges));
|
||||
|
||||
/* iterate over all possible OIDs to find the next one */
|
||||
netif = netif_list;
|
||||
while (netif != NULL) {
|
||||
NETIF_FOREACH(netif) {
|
||||
u32_t test_oid[LWIP_ARRAYSIZE(interfaces_Table_oid_ranges)];
|
||||
test_oid[0] = netif_to_num(netif);
|
||||
|
||||
/* check generated OID: is it a candidate for the next one? */
|
||||
snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(interfaces_Table_oid_ranges), netif);
|
||||
|
||||
netif = netif->next;
|
||||
}
|
||||
|
||||
/* did we find a next one? */
|
||||
@@ -160,118 +154,117 @@ interfaces_Table_get_next_cell_instance(const u32_t* column, struct snmp_obj_id*
|
||||
}
|
||||
|
||||
static s16_t
|
||||
interfaces_Table_get_value(struct snmp_node_instance* instance, void* value)
|
||||
interfaces_Table_get_value(struct snmp_node_instance *instance, void *value)
|
||||
{
|
||||
struct netif *netif = (struct netif*)instance->reference.ptr;
|
||||
u32_t* value_u32 = (u32_t*)value;
|
||||
s32_t* value_s32 = (s32_t*)value;
|
||||
struct netif *netif = (struct netif *)instance->reference.ptr;
|
||||
u32_t *value_u32 = (u32_t *)value;
|
||||
s32_t *value_s32 = (s32_t *)value;
|
||||
u16_t value_len;
|
||||
|
||||
switch (SNMP_TABLE_GET_COLUMN_FROM_OID(instance->instance_oid.id))
|
||||
{
|
||||
case 1: /* ifIndex */
|
||||
*value_s32 = netif_to_num(netif);
|
||||
value_len = sizeof(*value_s32);
|
||||
break;
|
||||
case 2: /* ifDescr */
|
||||
value_len = sizeof(netif->name);
|
||||
MEMCPY(value, netif->name, value_len);
|
||||
break;
|
||||
case 3: /* ifType */
|
||||
*value_s32 = netif->link_type;
|
||||
value_len = sizeof(*value_s32);
|
||||
break;
|
||||
case 4: /* ifMtu */
|
||||
*value_s32 = netif->mtu;
|
||||
value_len = sizeof(*value_s32);
|
||||
break;
|
||||
case 5: /* ifSpeed */
|
||||
*value_u32 = netif->link_speed;
|
||||
value_len = sizeof(*value_u32);
|
||||
break;
|
||||
case 6: /* ifPhysAddress */
|
||||
value_len = sizeof(netif->hwaddr);
|
||||
MEMCPY(value, &netif->hwaddr, value_len);
|
||||
break;
|
||||
case 7: /* ifAdminStatus */
|
||||
if (netif_is_up(netif)) {
|
||||
*value_s32 = iftable_ifOperStatus_up;
|
||||
} else {
|
||||
*value_s32 = iftable_ifOperStatus_down;
|
||||
}
|
||||
value_len = sizeof(*value_s32);
|
||||
break;
|
||||
case 8: /* ifOperStatus */
|
||||
if (netif_is_up(netif)) {
|
||||
if (netif_is_link_up(netif)) {
|
||||
*value_s32 = iftable_ifAdminStatus_up;
|
||||
switch (SNMP_TABLE_GET_COLUMN_FROM_OID(instance->instance_oid.id)) {
|
||||
case 1: /* ifIndex */
|
||||
*value_s32 = netif_to_num(netif);
|
||||
value_len = sizeof(*value_s32);
|
||||
break;
|
||||
case 2: /* ifDescr */
|
||||
value_len = sizeof(netif->name);
|
||||
MEMCPY(value, netif->name, value_len);
|
||||
break;
|
||||
case 3: /* ifType */
|
||||
*value_s32 = netif->link_type;
|
||||
value_len = sizeof(*value_s32);
|
||||
break;
|
||||
case 4: /* ifMtu */
|
||||
*value_s32 = netif->mtu;
|
||||
value_len = sizeof(*value_s32);
|
||||
break;
|
||||
case 5: /* ifSpeed */
|
||||
*value_u32 = netif->link_speed;
|
||||
value_len = sizeof(*value_u32);
|
||||
break;
|
||||
case 6: /* ifPhysAddress */
|
||||
value_len = sizeof(netif->hwaddr);
|
||||
MEMCPY(value, &netif->hwaddr, value_len);
|
||||
break;
|
||||
case 7: /* ifAdminStatus */
|
||||
if (netif_is_up(netif)) {
|
||||
*value_s32 = iftable_ifOperStatus_up;
|
||||
} else {
|
||||
*value_s32 = iftable_ifAdminStatus_lowerLayerDown;
|
||||
*value_s32 = iftable_ifOperStatus_down;
|
||||
}
|
||||
} else {
|
||||
*value_s32 = iftable_ifAdminStatus_down;
|
||||
}
|
||||
value_len = sizeof(*value_s32);
|
||||
break;
|
||||
case 9: /* ifLastChange */
|
||||
*value_u32 = netif->ts;
|
||||
value_len = sizeof(*value_u32);
|
||||
break;
|
||||
case 10: /* ifInOctets */
|
||||
*value_u32 = netif->mib2_counters.ifinoctets;
|
||||
value_len = sizeof(*value_u32);
|
||||
break;
|
||||
case 11: /* ifInUcastPkts */
|
||||
*value_u32 = netif->mib2_counters.ifinucastpkts;
|
||||
value_len = sizeof(*value_u32);
|
||||
break;
|
||||
case 12: /* ifInNUcastPkts */
|
||||
*value_u32 = netif->mib2_counters.ifinnucastpkts;
|
||||
value_len = sizeof(*value_u32);
|
||||
break;
|
||||
case 13: /* ifInDiscards */
|
||||
*value_u32 = netif->mib2_counters.ifindiscards;
|
||||
value_len = sizeof(*value_u32);
|
||||
break;
|
||||
case 14: /* ifInErrors */
|
||||
*value_u32 = netif->mib2_counters.ifinerrors;
|
||||
value_len = sizeof(*value_u32);
|
||||
break;
|
||||
case 15: /* ifInUnkownProtos */
|
||||
*value_u32 = netif->mib2_counters.ifinunknownprotos;
|
||||
value_len = sizeof(*value_u32);
|
||||
break;
|
||||
case 16: /* ifOutOctets */
|
||||
*value_u32 = netif->mib2_counters.ifoutoctets;
|
||||
value_len = sizeof(*value_u32);
|
||||
break;
|
||||
case 17: /* ifOutUcastPkts */
|
||||
*value_u32 = netif->mib2_counters.ifoutucastpkts;
|
||||
value_len = sizeof(*value_u32);
|
||||
break;
|
||||
case 18: /* ifOutNUcastPkts */
|
||||
*value_u32 = netif->mib2_counters.ifoutnucastpkts;
|
||||
value_len = sizeof(*value_u32);
|
||||
break;
|
||||
case 19: /* ifOutDiscarts */
|
||||
*value_u32 = netif->mib2_counters.ifoutdiscards;
|
||||
value_len = sizeof(*value_u32);
|
||||
break;
|
||||
case 20: /* ifOutErrors */
|
||||
*value_u32 = netif->mib2_counters.ifouterrors;
|
||||
value_len = sizeof(*value_u32);
|
||||
break;
|
||||
case 21: /* ifOutQLen */
|
||||
*value_u32 = iftable_ifOutQLen;
|
||||
value_len = sizeof(*value_u32);
|
||||
break;
|
||||
/** @note returning zeroDotZero (0.0) no media specific MIB support */
|
||||
case 22: /* ifSpecific */
|
||||
value_len = snmp_zero_dot_zero.len * sizeof(u32_t);
|
||||
MEMCPY(value, snmp_zero_dot_zero.id, value_len);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
value_len = sizeof(*value_s32);
|
||||
break;
|
||||
case 8: /* ifOperStatus */
|
||||
if (netif_is_up(netif)) {
|
||||
if (netif_is_link_up(netif)) {
|
||||
*value_s32 = iftable_ifAdminStatus_up;
|
||||
} else {
|
||||
*value_s32 = iftable_ifAdminStatus_lowerLayerDown;
|
||||
}
|
||||
} else {
|
||||
*value_s32 = iftable_ifAdminStatus_down;
|
||||
}
|
||||
value_len = sizeof(*value_s32);
|
||||
break;
|
||||
case 9: /* ifLastChange */
|
||||
*value_u32 = netif->ts;
|
||||
value_len = sizeof(*value_u32);
|
||||
break;
|
||||
case 10: /* ifInOctets */
|
||||
*value_u32 = netif->mib2_counters.ifinoctets;
|
||||
value_len = sizeof(*value_u32);
|
||||
break;
|
||||
case 11: /* ifInUcastPkts */
|
||||
*value_u32 = netif->mib2_counters.ifinucastpkts;
|
||||
value_len = sizeof(*value_u32);
|
||||
break;
|
||||
case 12: /* ifInNUcastPkts */
|
||||
*value_u32 = netif->mib2_counters.ifinnucastpkts;
|
||||
value_len = sizeof(*value_u32);
|
||||
break;
|
||||
case 13: /* ifInDiscards */
|
||||
*value_u32 = netif->mib2_counters.ifindiscards;
|
||||
value_len = sizeof(*value_u32);
|
||||
break;
|
||||
case 14: /* ifInErrors */
|
||||
*value_u32 = netif->mib2_counters.ifinerrors;
|
||||
value_len = sizeof(*value_u32);
|
||||
break;
|
||||
case 15: /* ifInUnkownProtos */
|
||||
*value_u32 = netif->mib2_counters.ifinunknownprotos;
|
||||
value_len = sizeof(*value_u32);
|
||||
break;
|
||||
case 16: /* ifOutOctets */
|
||||
*value_u32 = netif->mib2_counters.ifoutoctets;
|
||||
value_len = sizeof(*value_u32);
|
||||
break;
|
||||
case 17: /* ifOutUcastPkts */
|
||||
*value_u32 = netif->mib2_counters.ifoutucastpkts;
|
||||
value_len = sizeof(*value_u32);
|
||||
break;
|
||||
case 18: /* ifOutNUcastPkts */
|
||||
*value_u32 = netif->mib2_counters.ifoutnucastpkts;
|
||||
value_len = sizeof(*value_u32);
|
||||
break;
|
||||
case 19: /* ifOutDiscarts */
|
||||
*value_u32 = netif->mib2_counters.ifoutdiscards;
|
||||
value_len = sizeof(*value_u32);
|
||||
break;
|
||||
case 20: /* ifOutErrors */
|
||||
*value_u32 = netif->mib2_counters.ifouterrors;
|
||||
value_len = sizeof(*value_u32);
|
||||
break;
|
||||
case 21: /* ifOutQLen */
|
||||
*value_u32 = iftable_ifOutQLen;
|
||||
value_len = sizeof(*value_u32);
|
||||
break;
|
||||
/** @note returning zeroDotZero (0.0) no media specific MIB support */
|
||||
case 22: /* ifSpecific */
|
||||
value_len = snmp_zero_dot_zero.len * sizeof(u32_t);
|
||||
MEMCPY(value, snmp_zero_dot_zero.id, value_len);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return value_len;
|
||||
@@ -280,9 +273,9 @@ interfaces_Table_get_value(struct snmp_node_instance* instance, void* value)
|
||||
#if !SNMP_SAFE_REQUESTS
|
||||
|
||||
static snmp_err_t
|
||||
interfaces_Table_set_test(struct snmp_node_instance* instance, u16_t len, void *value)
|
||||
interfaces_Table_set_test(struct snmp_node_instance *instance, u16_t len, void *value)
|
||||
{
|
||||
s32_t *sint_ptr = (s32_t*)value;
|
||||
s32_t *sint_ptr = (s32_t *)value;
|
||||
|
||||
/* stack should never call this method for another column,
|
||||
because all other columns are set to readonly */
|
||||
@@ -297,10 +290,10 @@ interfaces_Table_set_test(struct snmp_node_instance* instance, u16_t len, void *
|
||||
}
|
||||
|
||||
static snmp_err_t
|
||||
interfaces_Table_set_value(struct snmp_node_instance* instance, u16_t len, void *value)
|
||||
interfaces_Table_set_value(struct snmp_node_instance *instance, u16_t len, void *value)
|
||||
{
|
||||
struct netif *netif = (struct netif*)instance->reference.ptr;
|
||||
s32_t *sint_ptr = (s32_t*)value;
|
||||
struct netif *netif = (struct netif *)instance->reference.ptr;
|
||||
s32_t *sint_ptr = (s32_t *)value;
|
||||
|
||||
/* stack should never call this method for another column,
|
||||
because all other columns are set to readonly */
|
||||
@@ -351,21 +344,21 @@ static const struct snmp_table_col_def interfaces_Table_columns[] = {
|
||||
|
||||
#if !SNMP_SAFE_REQUESTS
|
||||
static const struct snmp_table_node interfaces_Table = SNMP_TABLE_CREATE(
|
||||
2, interfaces_Table_columns,
|
||||
interfaces_Table_get_cell_instance, interfaces_Table_get_next_cell_instance,
|
||||
interfaces_Table_get_value, interfaces_Table_set_test, interfaces_Table_set_value);
|
||||
2, interfaces_Table_columns,
|
||||
interfaces_Table_get_cell_instance, interfaces_Table_get_next_cell_instance,
|
||||
interfaces_Table_get_value, interfaces_Table_set_test, interfaces_Table_set_value);
|
||||
#else
|
||||
static const struct snmp_table_node interfaces_Table = SNMP_TABLE_CREATE(
|
||||
2, interfaces_Table_columns,
|
||||
interfaces_Table_get_cell_instance, interfaces_Table_get_next_cell_instance,
|
||||
interfaces_Table_get_value, NULL, NULL);
|
||||
2, interfaces_Table_columns,
|
||||
interfaces_Table_get_cell_instance, interfaces_Table_get_next_cell_instance,
|
||||
interfaces_Table_get_value, NULL, NULL);
|
||||
#endif
|
||||
|
||||
/* the following nodes access variables in LWIP stack from SNMP worker thread and must therefore be synced to LWIP (TCPIP) thread */
|
||||
CREATE_LWIP_SYNC_NODE(1, interfaces_Number)
|
||||
CREATE_LWIP_SYNC_NODE(2, interfaces_Table)
|
||||
|
||||
static const struct snmp_node* const interface_nodes[] = {
|
||||
static const struct snmp_node *const interface_nodes[] = {
|
||||
&SYNC_NODE_NAME(interfaces_Number).node.node,
|
||||
&SYNC_NODE_NAME(interfaces_Table).node.node
|
||||
};
|
||||
|
||||
@@ -59,85 +59,85 @@
|
||||
/* --- ip .1.3.6.1.2.1.4 ----------------------------------------------------- */
|
||||
|
||||
static s16_t
|
||||
ip_get_value(struct snmp_node_instance* instance, void* value)
|
||||
ip_get_value(struct snmp_node_instance *instance, void *value)
|
||||
{
|
||||
s32_t* sint_ptr = (s32_t*)value;
|
||||
u32_t* uint_ptr = (u32_t*)value;
|
||||
s32_t *sint_ptr = (s32_t *)value;
|
||||
u32_t *uint_ptr = (u32_t *)value;
|
||||
|
||||
switch (instance->node->oid) {
|
||||
case 1: /* ipForwarding */
|
||||
case 1: /* ipForwarding */
|
||||
#if IP_FORWARD
|
||||
/* forwarding */
|
||||
*sint_ptr = 1;
|
||||
/* forwarding */
|
||||
*sint_ptr = 1;
|
||||
#else
|
||||
/* not-forwarding */
|
||||
*sint_ptr = 2;
|
||||
/* not-forwarding */
|
||||
*sint_ptr = 2;
|
||||
#endif
|
||||
return sizeof(*sint_ptr);
|
||||
case 2: /* ipDefaultTTL */
|
||||
*sint_ptr = IP_DEFAULT_TTL;
|
||||
return sizeof(*sint_ptr);
|
||||
case 3: /* ipInReceives */
|
||||
*uint_ptr = STATS_GET(mib2.ipinreceives);
|
||||
return sizeof(*uint_ptr);
|
||||
case 4: /* ipInHdrErrors */
|
||||
*uint_ptr = STATS_GET(mib2.ipinhdrerrors);
|
||||
return sizeof(*uint_ptr);
|
||||
case 5: /* ipInAddrErrors */
|
||||
*uint_ptr = STATS_GET(mib2.ipinaddrerrors);
|
||||
return sizeof(*uint_ptr);
|
||||
case 6: /* ipForwDatagrams */
|
||||
*uint_ptr = STATS_GET(mib2.ipforwdatagrams);
|
||||
return sizeof(*uint_ptr);
|
||||
case 7: /* ipInUnknownProtos */
|
||||
*uint_ptr = STATS_GET(mib2.ipinunknownprotos);
|
||||
return sizeof(*uint_ptr);
|
||||
case 8: /* ipInDiscards */
|
||||
*uint_ptr = STATS_GET(mib2.ipindiscards);
|
||||
return sizeof(*uint_ptr);
|
||||
case 9: /* ipInDelivers */
|
||||
*uint_ptr = STATS_GET(mib2.ipindelivers);
|
||||
return sizeof(*uint_ptr);
|
||||
case 10: /* ipOutRequests */
|
||||
*uint_ptr = STATS_GET(mib2.ipoutrequests);
|
||||
return sizeof(*uint_ptr);
|
||||
case 11: /* ipOutDiscards */
|
||||
*uint_ptr = STATS_GET(mib2.ipoutdiscards);
|
||||
return sizeof(*uint_ptr);
|
||||
case 12: /* ipOutNoRoutes */
|
||||
*uint_ptr = STATS_GET(mib2.ipoutnoroutes);
|
||||
return sizeof(*uint_ptr);
|
||||
case 13: /* ipReasmTimeout */
|
||||
return sizeof(*sint_ptr);
|
||||
case 2: /* ipDefaultTTL */
|
||||
*sint_ptr = IP_DEFAULT_TTL;
|
||||
return sizeof(*sint_ptr);
|
||||
case 3: /* ipInReceives */
|
||||
*uint_ptr = STATS_GET(mib2.ipinreceives);
|
||||
return sizeof(*uint_ptr);
|
||||
case 4: /* ipInHdrErrors */
|
||||
*uint_ptr = STATS_GET(mib2.ipinhdrerrors);
|
||||
return sizeof(*uint_ptr);
|
||||
case 5: /* ipInAddrErrors */
|
||||
*uint_ptr = STATS_GET(mib2.ipinaddrerrors);
|
||||
return sizeof(*uint_ptr);
|
||||
case 6: /* ipForwDatagrams */
|
||||
*uint_ptr = STATS_GET(mib2.ipforwdatagrams);
|
||||
return sizeof(*uint_ptr);
|
||||
case 7: /* ipInUnknownProtos */
|
||||
*uint_ptr = STATS_GET(mib2.ipinunknownprotos);
|
||||
return sizeof(*uint_ptr);
|
||||
case 8: /* ipInDiscards */
|
||||
*uint_ptr = STATS_GET(mib2.ipindiscards);
|
||||
return sizeof(*uint_ptr);
|
||||
case 9: /* ipInDelivers */
|
||||
*uint_ptr = STATS_GET(mib2.ipindelivers);
|
||||
return sizeof(*uint_ptr);
|
||||
case 10: /* ipOutRequests */
|
||||
*uint_ptr = STATS_GET(mib2.ipoutrequests);
|
||||
return sizeof(*uint_ptr);
|
||||
case 11: /* ipOutDiscards */
|
||||
*uint_ptr = STATS_GET(mib2.ipoutdiscards);
|
||||
return sizeof(*uint_ptr);
|
||||
case 12: /* ipOutNoRoutes */
|
||||
*uint_ptr = STATS_GET(mib2.ipoutnoroutes);
|
||||
return sizeof(*uint_ptr);
|
||||
case 13: /* ipReasmTimeout */
|
||||
#if IP_REASSEMBLY
|
||||
*sint_ptr = IP_REASS_MAXAGE;
|
||||
*sint_ptr = IP_REASS_MAXAGE;
|
||||
#else
|
||||
*sint_ptr = 0;
|
||||
*sint_ptr = 0;
|
||||
#endif
|
||||
return sizeof(*sint_ptr);
|
||||
case 14: /* ipReasmReqds */
|
||||
*uint_ptr = STATS_GET(mib2.ipreasmreqds);
|
||||
return sizeof(*uint_ptr);
|
||||
case 15: /* ipReasmOKs */
|
||||
*uint_ptr = STATS_GET(mib2.ipreasmoks);
|
||||
return sizeof(*uint_ptr);
|
||||
case 16: /* ipReasmFails */
|
||||
*uint_ptr = STATS_GET(mib2.ipreasmfails);
|
||||
return sizeof(*uint_ptr);
|
||||
case 17: /* ipFragOKs */
|
||||
*uint_ptr = STATS_GET(mib2.ipfragoks);
|
||||
return sizeof(*uint_ptr);
|
||||
case 18: /* ipFragFails */
|
||||
*uint_ptr = STATS_GET(mib2.ipfragfails);
|
||||
return sizeof(*uint_ptr);
|
||||
case 19: /* ipFragCreates */
|
||||
*uint_ptr = STATS_GET(mib2.ipfragcreates);
|
||||
return sizeof(*uint_ptr);
|
||||
case 23: /* ipRoutingDiscards: not supported -> always 0 */
|
||||
*uint_ptr = 0;
|
||||
return sizeof(*uint_ptr);
|
||||
default:
|
||||
LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_get_value(): unknown id: %"S32_F"\n", instance->node->oid));
|
||||
break;
|
||||
return sizeof(*sint_ptr);
|
||||
case 14: /* ipReasmReqds */
|
||||
*uint_ptr = STATS_GET(mib2.ipreasmreqds);
|
||||
return sizeof(*uint_ptr);
|
||||
case 15: /* ipReasmOKs */
|
||||
*uint_ptr = STATS_GET(mib2.ipreasmoks);
|
||||
return sizeof(*uint_ptr);
|
||||
case 16: /* ipReasmFails */
|
||||
*uint_ptr = STATS_GET(mib2.ipreasmfails);
|
||||
return sizeof(*uint_ptr);
|
||||
case 17: /* ipFragOKs */
|
||||
*uint_ptr = STATS_GET(mib2.ipfragoks);
|
||||
return sizeof(*uint_ptr);
|
||||
case 18: /* ipFragFails */
|
||||
*uint_ptr = STATS_GET(mib2.ipfragfails);
|
||||
return sizeof(*uint_ptr);
|
||||
case 19: /* ipFragCreates */
|
||||
*uint_ptr = STATS_GET(mib2.ipfragcreates);
|
||||
return sizeof(*uint_ptr);
|
||||
case 23: /* ipRoutingDiscards: not supported -> always 0 */
|
||||
*uint_ptr = 0;
|
||||
return sizeof(*uint_ptr);
|
||||
default:
|
||||
LWIP_DEBUGF(SNMP_MIB_DEBUG, ("ip_get_value(): unknown id: %"S32_F"\n", instance->node->oid));
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -154,40 +154,40 @@ ip_get_value(struct snmp_node_instance* instance, void* value)
|
||||
* otherwise return badvalue.
|
||||
*/
|
||||
static snmp_err_t
|
||||
ip_set_test(struct snmp_node_instance* instance, u16_t len, void *value)
|
||||
ip_set_test(struct snmp_node_instance *instance, u16_t len, void *value)
|
||||
{
|
||||
snmp_err_t ret = SNMP_ERR_WRONGVALUE;
|
||||
s32_t *sint_ptr = (s32_t*)value;
|
||||
s32_t *sint_ptr = (s32_t *)value;
|
||||
|
||||
LWIP_UNUSED_ARG(len);
|
||||
switch (instance->node->oid) {
|
||||
case 1: /* ipForwarding */
|
||||
case 1: /* ipForwarding */
|
||||
#if IP_FORWARD
|
||||
/* forwarding */
|
||||
if (*sint_ptr == 1)
|
||||
/* forwarding */
|
||||
if (*sint_ptr == 1)
|
||||
#else
|
||||
/* not-forwarding */
|
||||
if (*sint_ptr == 2)
|
||||
/* not-forwarding */
|
||||
if (*sint_ptr == 2)
|
||||
#endif
|
||||
{
|
||||
ret = SNMP_ERR_NOERROR;
|
||||
}
|
||||
break;
|
||||
case 2: /* ipDefaultTTL */
|
||||
if (*sint_ptr == IP_DEFAULT_TTL) {
|
||||
ret = SNMP_ERR_NOERROR;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_set_test(): unknown id: %"S32_F"\n", instance->node->oid));
|
||||
break;
|
||||
{
|
||||
ret = SNMP_ERR_NOERROR;
|
||||
}
|
||||
break;
|
||||
case 2: /* ipDefaultTTL */
|
||||
if (*sint_ptr == IP_DEFAULT_TTL) {
|
||||
ret = SNMP_ERR_NOERROR;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LWIP_DEBUGF(SNMP_MIB_DEBUG, ("ip_set_test(): unknown id: %"S32_F"\n", instance->node->oid));
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static snmp_err_t
|
||||
ip_set_value(struct snmp_node_instance* instance, u16_t len, void *value)
|
||||
ip_set_value(struct snmp_node_instance *instance, u16_t len, void *value)
|
||||
{
|
||||
LWIP_UNUSED_ARG(instance);
|
||||
LWIP_UNUSED_ARG(len);
|
||||
@@ -207,48 +207,48 @@ static const struct snmp_oid_range ip_AddrTable_oid_ranges[] = {
|
||||
};
|
||||
|
||||
static snmp_err_t
|
||||
ip_AddrTable_get_cell_value_core(struct netif *netif, const u32_t* column, union snmp_variant_value* value, u32_t* value_len)
|
||||
ip_AddrTable_get_cell_value_core(struct netif *netif, const u32_t *column, union snmp_variant_value *value, u32_t *value_len)
|
||||
{
|
||||
LWIP_UNUSED_ARG(value_len);
|
||||
|
||||
switch (*column) {
|
||||
case 1: /* ipAdEntAddr */
|
||||
value->u32 = netif_ip4_addr(netif)->addr;
|
||||
break;
|
||||
case 2: /* ipAdEntIfIndex */
|
||||
value->u32 = netif_to_num(netif);
|
||||
break;
|
||||
case 3: /* ipAdEntNetMask */
|
||||
value->u32 = netif_ip4_netmask(netif)->addr;
|
||||
break;
|
||||
case 4: /* ipAdEntBcastAddr */
|
||||
/* lwIP oddity, there's no broadcast
|
||||
address in the netif we can rely on */
|
||||
value->u32 = IPADDR_BROADCAST & 1;
|
||||
break;
|
||||
case 5: /* ipAdEntReasmMaxSize */
|
||||
case 1: /* ipAdEntAddr */
|
||||
value->u32 = netif_ip4_addr(netif)->addr;
|
||||
break;
|
||||
case 2: /* ipAdEntIfIndex */
|
||||
value->u32 = netif_to_num(netif);
|
||||
break;
|
||||
case 3: /* ipAdEntNetMask */
|
||||
value->u32 = netif_ip4_netmask(netif)->addr;
|
||||
break;
|
||||
case 4: /* ipAdEntBcastAddr */
|
||||
/* lwIP oddity, there's no broadcast
|
||||
address in the netif we can rely on */
|
||||
value->u32 = IPADDR_BROADCAST & 1;
|
||||
break;
|
||||
case 5: /* ipAdEntReasmMaxSize */
|
||||
#if IP_REASSEMBLY
|
||||
/* @todo The theoretical maximum is IP_REASS_MAX_PBUFS * size of the pbufs,
|
||||
* but only if receiving one fragmented packet at a time.
|
||||
* The current solution is to calculate for 2 simultaneous packets...
|
||||
*/
|
||||
value->u32 = (IP_HLEN + ((IP_REASS_MAX_PBUFS/2) *
|
||||
(PBUF_POOL_BUFSIZE - PBUF_LINK_ENCAPSULATION_HLEN - PBUF_LINK_HLEN - IP_HLEN)));
|
||||
/* @todo The theoretical maximum is IP_REASS_MAX_PBUFS * size of the pbufs,
|
||||
* but only if receiving one fragmented packet at a time.
|
||||
* The current solution is to calculate for 2 simultaneous packets...
|
||||
*/
|
||||
value->u32 = (IP_HLEN + ((IP_REASS_MAX_PBUFS / 2) *
|
||||
(PBUF_POOL_BUFSIZE - PBUF_LINK_ENCAPSULATION_HLEN - PBUF_LINK_HLEN - IP_HLEN)));
|
||||
#else
|
||||
/** @todo returning MTU would be a bad thing and
|
||||
returning a wild guess like '576' isn't good either */
|
||||
value->u32 = 0;
|
||||
/** @todo returning MTU would be a bad thing and
|
||||
returning a wild guess like '576' isn't good either */
|
||||
value->u32 = 0;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
break;
|
||||
default:
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
return SNMP_ERR_NOERROR;
|
||||
}
|
||||
|
||||
static snmp_err_t
|
||||
ip_AddrTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len)
|
||||
ip_AddrTable_get_cell_value(const u32_t *column, const u32_t *row_oid, u8_t row_oid_len, union snmp_variant_value *value, u32_t *value_len)
|
||||
{
|
||||
ip4_addr_t ip;
|
||||
struct netif *netif;
|
||||
@@ -262,14 +262,11 @@ ip_AddrTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_
|
||||
snmp_oid_to_ip4(&row_oid[0], &ip); /* we know it succeeds because of oid_in_range check above */
|
||||
|
||||
/* find netif with requested ip */
|
||||
netif = netif_list;
|
||||
while (netif != NULL) {
|
||||
NETIF_FOREACH(netif) {
|
||||
if (ip4_addr_cmp(&ip, netif_ip4_addr(netif))) {
|
||||
/* fill in object properties */
|
||||
return ip_AddrTable_get_cell_value_core(netif, column, value, value_len);
|
||||
}
|
||||
|
||||
netif = netif->next;
|
||||
}
|
||||
|
||||
/* not found */
|
||||
@@ -277,7 +274,7 @@ ip_AddrTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_
|
||||
}
|
||||
|
||||
static snmp_err_t
|
||||
ip_AddrTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
|
||||
ip_AddrTable_get_next_cell_instance_and_value(const u32_t *column, struct snmp_obj_id *row_oid, union snmp_variant_value *value, u32_t *value_len)
|
||||
{
|
||||
struct netif *netif;
|
||||
struct snmp_next_oid_state state;
|
||||
@@ -287,22 +284,19 @@ ip_AddrTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_o
|
||||
snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges));
|
||||
|
||||
/* iterate over all possible OIDs to find the next one */
|
||||
netif = netif_list;
|
||||
while (netif != NULL) {
|
||||
NETIF_FOREACH(netif) {
|
||||
u32_t test_oid[LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges)];
|
||||
snmp_ip4_to_oid(netif_ip4_addr(netif), &test_oid[0]);
|
||||
|
||||
/* check generated OID: is it a candidate for the next one? */
|
||||
snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges), netif);
|
||||
|
||||
netif = netif->next;
|
||||
}
|
||||
|
||||
/* did we find a next one? */
|
||||
if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
|
||||
snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
|
||||
/* fill in object properties */
|
||||
return ip_AddrTable_get_cell_value_core((struct netif*)state.reference, column, value, value_len);
|
||||
return ip_AddrTable_get_cell_value_core((struct netif *)state.reference, column, value, value_len);
|
||||
}
|
||||
|
||||
/* not found */
|
||||
@@ -320,86 +314,86 @@ static const struct snmp_oid_range ip_RouteTable_oid_ranges[] = {
|
||||
};
|
||||
|
||||
static snmp_err_t
|
||||
ip_RouteTable_get_cell_value_core(struct netif *netif, u8_t default_route, const u32_t* column, union snmp_variant_value* value, u32_t* value_len)
|
||||
ip_RouteTable_get_cell_value_core(struct netif *netif, u8_t default_route, const u32_t *column, union snmp_variant_value *value, u32_t *value_len)
|
||||
{
|
||||
switch (*column) {
|
||||
case 1: /* ipRouteDest */
|
||||
if (default_route) {
|
||||
/* default rte has 0.0.0.0 dest */
|
||||
value->u32 = IP4_ADDR_ANY4->addr;
|
||||
} else {
|
||||
/* netifs have netaddress dest */
|
||||
ip4_addr_t tmp;
|
||||
ip4_addr_get_network(&tmp, netif_ip4_addr(netif), netif_ip4_netmask(netif));
|
||||
value->u32 = tmp.addr;
|
||||
}
|
||||
break;
|
||||
case 2: /* ipRouteIfIndex */
|
||||
value->u32 = netif_to_num(netif);
|
||||
break;
|
||||
case 3: /* ipRouteMetric1 */
|
||||
if (default_route) {
|
||||
value->s32 = 1; /* default */
|
||||
} else {
|
||||
value->s32 = 0; /* normal */
|
||||
}
|
||||
break;
|
||||
case 4: /* ipRouteMetric2 */
|
||||
case 5: /* ipRouteMetric3 */
|
||||
case 6: /* ipRouteMetric4 */
|
||||
value->s32 = -1; /* none */
|
||||
break;
|
||||
case 7: /* ipRouteNextHop */
|
||||
if (default_route) {
|
||||
/* default rte: gateway */
|
||||
value->u32 = netif_ip4_gw(netif)->addr;
|
||||
} else {
|
||||
/* other rtes: netif ip_addr */
|
||||
value->u32 = netif_ip4_addr(netif)->addr;
|
||||
}
|
||||
break;
|
||||
case 8: /* ipRouteType */
|
||||
if (default_route) {
|
||||
/* default rte is indirect */
|
||||
value->u32 = 4; /* indirect */
|
||||
} else {
|
||||
/* other rtes are direct */
|
||||
value->u32 = 3; /* direct */
|
||||
}
|
||||
break;
|
||||
case 9: /* ipRouteProto */
|
||||
/* locally defined routes */
|
||||
value->u32 = 2; /* local */
|
||||
break;
|
||||
case 10: /* ipRouteAge */
|
||||
/* @todo (sysuptime - timestamp last change) / 100 */
|
||||
value->u32 = 0;
|
||||
break;
|
||||
case 11: /* ipRouteMask */
|
||||
if (default_route) {
|
||||
/* default rte use 0.0.0.0 mask */
|
||||
value->u32 = IP4_ADDR_ANY4->addr;
|
||||
} else {
|
||||
/* other rtes use netmask */
|
||||
value->u32 = netif_ip4_netmask(netif)->addr;
|
||||
}
|
||||
break;
|
||||
case 12: /* ipRouteMetric5 */
|
||||
value->s32 = -1; /* none */
|
||||
break;
|
||||
case 13: /* ipRouteInfo */
|
||||
value->const_ptr = snmp_zero_dot_zero.id;
|
||||
*value_len = snmp_zero_dot_zero.len * sizeof(u32_t);
|
||||
break;
|
||||
default:
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
case 1: /* ipRouteDest */
|
||||
if (default_route) {
|
||||
/* default rte has 0.0.0.0 dest */
|
||||
value->u32 = IP4_ADDR_ANY4->addr;
|
||||
} else {
|
||||
/* netifs have netaddress dest */
|
||||
ip4_addr_t tmp;
|
||||
ip4_addr_get_network(&tmp, netif_ip4_addr(netif), netif_ip4_netmask(netif));
|
||||
value->u32 = tmp.addr;
|
||||
}
|
||||
break;
|
||||
case 2: /* ipRouteIfIndex */
|
||||
value->u32 = netif_to_num(netif);
|
||||
break;
|
||||
case 3: /* ipRouteMetric1 */
|
||||
if (default_route) {
|
||||
value->s32 = 1; /* default */
|
||||
} else {
|
||||
value->s32 = 0; /* normal */
|
||||
}
|
||||
break;
|
||||
case 4: /* ipRouteMetric2 */
|
||||
case 5: /* ipRouteMetric3 */
|
||||
case 6: /* ipRouteMetric4 */
|
||||
value->s32 = -1; /* none */
|
||||
break;
|
||||
case 7: /* ipRouteNextHop */
|
||||
if (default_route) {
|
||||
/* default rte: gateway */
|
||||
value->u32 = netif_ip4_gw(netif)->addr;
|
||||
} else {
|
||||
/* other rtes: netif ip_addr */
|
||||
value->u32 = netif_ip4_addr(netif)->addr;
|
||||
}
|
||||
break;
|
||||
case 8: /* ipRouteType */
|
||||
if (default_route) {
|
||||
/* default rte is indirect */
|
||||
value->u32 = 4; /* indirect */
|
||||
} else {
|
||||
/* other rtes are direct */
|
||||
value->u32 = 3; /* direct */
|
||||
}
|
||||
break;
|
||||
case 9: /* ipRouteProto */
|
||||
/* locally defined routes */
|
||||
value->u32 = 2; /* local */
|
||||
break;
|
||||
case 10: /* ipRouteAge */
|
||||
/* @todo (sysuptime - timestamp last change) / 100 */
|
||||
value->u32 = 0;
|
||||
break;
|
||||
case 11: /* ipRouteMask */
|
||||
if (default_route) {
|
||||
/* default rte use 0.0.0.0 mask */
|
||||
value->u32 = IP4_ADDR_ANY4->addr;
|
||||
} else {
|
||||
/* other rtes use netmask */
|
||||
value->u32 = netif_ip4_netmask(netif)->addr;
|
||||
}
|
||||
break;
|
||||
case 12: /* ipRouteMetric5 */
|
||||
value->s32 = -1; /* none */
|
||||
break;
|
||||
case 13: /* ipRouteInfo */
|
||||
value->const_ptr = snmp_zero_dot_zero.id;
|
||||
*value_len = snmp_zero_dot_zero.len * sizeof(u32_t);
|
||||
break;
|
||||
default:
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
return SNMP_ERR_NOERROR;
|
||||
}
|
||||
|
||||
static snmp_err_t
|
||||
ip_RouteTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len)
|
||||
ip_RouteTable_get_cell_value(const u32_t *column, const u32_t *row_oid, u8_t row_oid_len, union snmp_variant_value *value, u32_t *value_len)
|
||||
{
|
||||
ip4_addr_t test_ip;
|
||||
struct netif *netif;
|
||||
@@ -419,8 +413,7 @@ ip_RouteTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row
|
||||
}
|
||||
|
||||
/* find netif with requested route */
|
||||
netif = netif_list;
|
||||
while (netif != NULL) {
|
||||
NETIF_FOREACH(netif) {
|
||||
ip4_addr_t dst;
|
||||
ip4_addr_get_network(&dst, netif_ip4_addr(netif), netif_ip4_netmask(netif));
|
||||
|
||||
@@ -428,8 +421,6 @@ ip_RouteTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row
|
||||
/* fill in object properties */
|
||||
return ip_RouteTable_get_cell_value_core(netif, 0, column, value, value_len);
|
||||
}
|
||||
|
||||
netif = netif->next;
|
||||
}
|
||||
|
||||
/* not found */
|
||||
@@ -437,7 +428,7 @@ ip_RouteTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row
|
||||
}
|
||||
|
||||
static snmp_err_t
|
||||
ip_RouteTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
|
||||
ip_RouteTable_get_next_cell_instance_and_value(const u32_t *column, struct snmp_obj_id *row_oid, union snmp_variant_value *value, u32_t *value_len)
|
||||
{
|
||||
struct netif *netif;
|
||||
struct snmp_next_oid_state state;
|
||||
@@ -454,8 +445,7 @@ ip_RouteTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_
|
||||
}
|
||||
|
||||
/* iterate over all possible OIDs to find the next one */
|
||||
netif = netif_list;
|
||||
while (netif != NULL) {
|
||||
NETIF_FOREACH(netif) {
|
||||
ip4_addr_t dst;
|
||||
ip4_addr_get_network(&dst, netif_ip4_addr(netif), netif_ip4_netmask(netif));
|
||||
|
||||
@@ -464,8 +454,6 @@ ip_RouteTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_
|
||||
snmp_ip4_to_oid(&dst, &test_oid[0]);
|
||||
snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges), netif);
|
||||
}
|
||||
|
||||
netif = netif->next;
|
||||
}
|
||||
|
||||
/* did we find a next one? */
|
||||
@@ -474,7 +462,7 @@ ip_RouteTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_
|
||||
snmp_oid_to_ip4(&result_temp[0], &dst);
|
||||
snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
|
||||
/* fill in object properties */
|
||||
return ip_RouteTable_get_cell_value_core((struct netif*)state.reference, ip4_addr_isany_val(dst), column, value, value_len);
|
||||
return ip_RouteTable_get_cell_value_core((struct netif *)state.reference, ip4_addr_isany_val(dst), column, value, value_len);
|
||||
} else {
|
||||
/* not found */
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
@@ -494,7 +482,7 @@ static const struct snmp_oid_range ip_NetToMediaTable_oid_ranges[] = {
|
||||
};
|
||||
|
||||
static snmp_err_t
|
||||
ip_NetToMediaTable_get_cell_value_core(u8_t arp_table_index, const u32_t* column, union snmp_variant_value* value, u32_t* value_len)
|
||||
ip_NetToMediaTable_get_cell_value_core(size_t arp_table_index, const u32_t *column, union snmp_variant_value *value, u32_t *value_len)
|
||||
{
|
||||
ip4_addr_t *ip;
|
||||
struct netif *netif;
|
||||
@@ -504,32 +492,32 @@ ip_NetToMediaTable_get_cell_value_core(u8_t arp_table_index, const u32_t* column
|
||||
|
||||
/* value */
|
||||
switch (*column) {
|
||||
case 1: /* atIfIndex / ipNetToMediaIfIndex */
|
||||
value->u32 = netif_to_num(netif);
|
||||
break;
|
||||
case 2: /* atPhysAddress / ipNetToMediaPhysAddress */
|
||||
value->ptr = ethaddr;
|
||||
*value_len = sizeof(*ethaddr);
|
||||
break;
|
||||
case 3: /* atNetAddress / ipNetToMediaNetAddress */
|
||||
value->u32 = ip->addr;
|
||||
break;
|
||||
case 4: /* ipNetToMediaType */
|
||||
value->u32 = 3; /* dynamic*/
|
||||
break;
|
||||
default:
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
case 1: /* atIfIndex / ipNetToMediaIfIndex */
|
||||
value->u32 = netif_to_num(netif);
|
||||
break;
|
||||
case 2: /* atPhysAddress / ipNetToMediaPhysAddress */
|
||||
value->ptr = ethaddr;
|
||||
*value_len = sizeof(*ethaddr);
|
||||
break;
|
||||
case 3: /* atNetAddress / ipNetToMediaNetAddress */
|
||||
value->u32 = ip->addr;
|
||||
break;
|
||||
case 4: /* ipNetToMediaType */
|
||||
value->u32 = 3; /* dynamic*/
|
||||
break;
|
||||
default:
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
return SNMP_ERR_NOERROR;
|
||||
}
|
||||
|
||||
static snmp_err_t
|
||||
ip_NetToMediaTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len)
|
||||
ip_NetToMediaTable_get_cell_value(const u32_t *column, const u32_t *row_oid, u8_t row_oid_len, union snmp_variant_value *value, u32_t *value_len)
|
||||
{
|
||||
ip4_addr_t ip_in;
|
||||
u8_t netif_index;
|
||||
u8_t i;
|
||||
size_t i;
|
||||
|
||||
/* check if incoming OID length and if values are in plausible range */
|
||||
if (!snmp_oid_in_range(row_oid, row_oid_len, ip_NetToMediaTable_oid_ranges, LWIP_ARRAYSIZE(ip_NetToMediaTable_oid_ranges))) {
|
||||
@@ -541,7 +529,7 @@ ip_NetToMediaTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_
|
||||
snmp_oid_to_ip4(&row_oid[1], &ip_in); /* we know it succeeds because of oid_in_range check above */
|
||||
|
||||
/* find requested entry */
|
||||
for (i=0; i<ARP_TABLE_SIZE; i++) {
|
||||
for (i = 0; i < ARP_TABLE_SIZE; i++) {
|
||||
ip4_addr_t *ip;
|
||||
struct netif *netif;
|
||||
struct eth_addr *ethaddr;
|
||||
@@ -559,9 +547,9 @@ ip_NetToMediaTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_
|
||||
}
|
||||
|
||||
static snmp_err_t
|
||||
ip_NetToMediaTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
|
||||
ip_NetToMediaTable_get_next_cell_instance_and_value(const u32_t *column, struct snmp_obj_id *row_oid, union snmp_variant_value *value, u32_t *value_len)
|
||||
{
|
||||
u8_t i;
|
||||
size_t i;
|
||||
struct snmp_next_oid_state state;
|
||||
u32_t result_temp[LWIP_ARRAYSIZE(ip_NetToMediaTable_oid_ranges)];
|
||||
|
||||
@@ -569,7 +557,7 @@ ip_NetToMediaTable_get_next_cell_instance_and_value(const u32_t* column, struct
|
||||
snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(ip_NetToMediaTable_oid_ranges));
|
||||
|
||||
/* iterate over all possible OIDs to find the next one */
|
||||
for (i=0; i<ARP_TABLE_SIZE; i++) {
|
||||
for (i = 0; i < ARP_TABLE_SIZE; i++) {
|
||||
ip4_addr_t *ip;
|
||||
struct netif *netif;
|
||||
struct eth_addr *ethaddr;
|
||||
@@ -581,7 +569,7 @@ ip_NetToMediaTable_get_next_cell_instance_and_value(const u32_t* column, struct
|
||||
snmp_ip4_to_oid(ip, &test_oid[1]);
|
||||
|
||||
/* check generated OID: is it a candidate for the next one? */
|
||||
snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(ip_NetToMediaTable_oid_ranges), (void*)(size_t)i);
|
||||
snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(ip_NetToMediaTable_oid_ranges), LWIP_PTR_NUMERIC_CAST(void *, i));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -589,7 +577,7 @@ ip_NetToMediaTable_get_next_cell_instance_and_value(const u32_t* column, struct
|
||||
if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
|
||||
snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
|
||||
/* fill in object properties */
|
||||
return ip_NetToMediaTable_get_cell_value_core((u8_t)(size_t)state.reference, column, value, value_len);
|
||||
return ip_NetToMediaTable_get_cell_value_core(LWIP_PTR_NUMERIC_CAST(size_t, state.reference), column, value, value_len);
|
||||
}
|
||||
|
||||
/* not found */
|
||||
@@ -687,7 +675,7 @@ CREATE_LWIP_SYNC_NODE(22, ip_NetToMediaTable)
|
||||
#endif /* LWIP_ARP */
|
||||
CREATE_LWIP_SYNC_NODE(23, ip_RoutingDiscards)
|
||||
|
||||
static const struct snmp_node* const ip_nodes[] = {
|
||||
static const struct snmp_node *const ip_nodes[] = {
|
||||
&SYNC_NODE_NAME(ip_Forwarding).node.node,
|
||||
&SYNC_NODE_NAME(ip_DefaultTTL).node.node,
|
||||
&SYNC_NODE_NAME(ip_InReceives).node.node,
|
||||
@@ -733,7 +721,7 @@ static const struct snmp_table_simple_node at_Table = SNMP_TABLE_CREATE_SIMPLE(1
|
||||
/* the following nodes access variables in LWIP stack from SNMP worker thread and must therefore be synced to LWIP (TCPIP) thread */
|
||||
CREATE_LWIP_SYNC_NODE(1, at_Table)
|
||||
|
||||
static const struct snmp_node* const at_nodes[] = {
|
||||
static const struct snmp_node *const at_nodes[] = {
|
||||
&SYNC_NODE_NAME(at_Table).node.node
|
||||
};
|
||||
|
||||
|
||||
@@ -48,105 +48,105 @@
|
||||
static s16_t
|
||||
snmp_get_value(const struct snmp_scalar_array_node_def *node, void *value)
|
||||
{
|
||||
u32_t *uint_ptr = (u32_t*)value;
|
||||
u32_t *uint_ptr = (u32_t *)value;
|
||||
switch (node->oid) {
|
||||
case 1: /* snmpInPkts */
|
||||
*uint_ptr = snmp_stats.inpkts;
|
||||
break;
|
||||
case 2: /* snmpOutPkts */
|
||||
*uint_ptr = snmp_stats.outpkts;
|
||||
break;
|
||||
case 3: /* snmpInBadVersions */
|
||||
*uint_ptr = snmp_stats.inbadversions;
|
||||
break;
|
||||
case 4: /* snmpInBadCommunityNames */
|
||||
*uint_ptr = snmp_stats.inbadcommunitynames;
|
||||
break;
|
||||
case 5: /* snmpInBadCommunityUses */
|
||||
*uint_ptr = snmp_stats.inbadcommunityuses;
|
||||
break;
|
||||
case 6: /* snmpInASNParseErrs */
|
||||
*uint_ptr = snmp_stats.inasnparseerrs;
|
||||
break;
|
||||
case 8: /* snmpInTooBigs */
|
||||
*uint_ptr = snmp_stats.intoobigs;
|
||||
break;
|
||||
case 9: /* snmpInNoSuchNames */
|
||||
*uint_ptr = snmp_stats.innosuchnames;
|
||||
break;
|
||||
case 10: /* snmpInBadValues */
|
||||
*uint_ptr = snmp_stats.inbadvalues;
|
||||
break;
|
||||
case 11: /* snmpInReadOnlys */
|
||||
*uint_ptr = snmp_stats.inreadonlys;
|
||||
break;
|
||||
case 12: /* snmpInGenErrs */
|
||||
*uint_ptr = snmp_stats.ingenerrs;
|
||||
break;
|
||||
case 13: /* snmpInTotalReqVars */
|
||||
*uint_ptr = snmp_stats.intotalreqvars;
|
||||
break;
|
||||
case 14: /* snmpInTotalSetVars */
|
||||
*uint_ptr = snmp_stats.intotalsetvars;
|
||||
break;
|
||||
case 15: /* snmpInGetRequests */
|
||||
*uint_ptr = snmp_stats.ingetrequests;
|
||||
break;
|
||||
case 16: /* snmpInGetNexts */
|
||||
*uint_ptr = snmp_stats.ingetnexts;
|
||||
break;
|
||||
case 17: /* snmpInSetRequests */
|
||||
*uint_ptr = snmp_stats.insetrequests;
|
||||
break;
|
||||
case 18: /* snmpInGetResponses */
|
||||
*uint_ptr = snmp_stats.ingetresponses;
|
||||
break;
|
||||
case 19: /* snmpInTraps */
|
||||
*uint_ptr = snmp_stats.intraps;
|
||||
break;
|
||||
case 20: /* snmpOutTooBigs */
|
||||
*uint_ptr = snmp_stats.outtoobigs;
|
||||
break;
|
||||
case 21: /* snmpOutNoSuchNames */
|
||||
*uint_ptr = snmp_stats.outnosuchnames;
|
||||
break;
|
||||
case 22: /* snmpOutBadValues */
|
||||
*uint_ptr = snmp_stats.outbadvalues;
|
||||
break;
|
||||
case 24: /* snmpOutGenErrs */
|
||||
*uint_ptr = snmp_stats.outgenerrs;
|
||||
break;
|
||||
case 25: /* snmpOutGetRequests */
|
||||
*uint_ptr = snmp_stats.outgetrequests;
|
||||
break;
|
||||
case 26: /* snmpOutGetNexts */
|
||||
*uint_ptr = snmp_stats.outgetnexts;
|
||||
break;
|
||||
case 27: /* snmpOutSetRequests */
|
||||
*uint_ptr = snmp_stats.outsetrequests;
|
||||
break;
|
||||
case 28: /* snmpOutGetResponses */
|
||||
*uint_ptr = snmp_stats.outgetresponses;
|
||||
break;
|
||||
case 29: /* snmpOutTraps */
|
||||
*uint_ptr = snmp_stats.outtraps;
|
||||
break;
|
||||
case 30: /* snmpEnableAuthenTraps */
|
||||
if (snmp_get_auth_traps_enabled() == SNMP_AUTH_TRAPS_DISABLED) {
|
||||
*uint_ptr = MIB2_AUTH_TRAPS_DISABLED;
|
||||
} else {
|
||||
*uint_ptr = MIB2_AUTH_TRAPS_ENABLED;
|
||||
}
|
||||
break;
|
||||
case 31: /* snmpSilentDrops */
|
||||
*uint_ptr = 0; /* not supported */
|
||||
break;
|
||||
case 32: /* snmpProxyDrops */
|
||||
*uint_ptr = 0; /* not supported */
|
||||
break;
|
||||
default:
|
||||
LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_get_value(): unknown id: %"S32_F"\n", node->oid));
|
||||
return 0;
|
||||
case 1: /* snmpInPkts */
|
||||
*uint_ptr = snmp_stats.inpkts;
|
||||
break;
|
||||
case 2: /* snmpOutPkts */
|
||||
*uint_ptr = snmp_stats.outpkts;
|
||||
break;
|
||||
case 3: /* snmpInBadVersions */
|
||||
*uint_ptr = snmp_stats.inbadversions;
|
||||
break;
|
||||
case 4: /* snmpInBadCommunityNames */
|
||||
*uint_ptr = snmp_stats.inbadcommunitynames;
|
||||
break;
|
||||
case 5: /* snmpInBadCommunityUses */
|
||||
*uint_ptr = snmp_stats.inbadcommunityuses;
|
||||
break;
|
||||
case 6: /* snmpInASNParseErrs */
|
||||
*uint_ptr = snmp_stats.inasnparseerrs;
|
||||
break;
|
||||
case 8: /* snmpInTooBigs */
|
||||
*uint_ptr = snmp_stats.intoobigs;
|
||||
break;
|
||||
case 9: /* snmpInNoSuchNames */
|
||||
*uint_ptr = snmp_stats.innosuchnames;
|
||||
break;
|
||||
case 10: /* snmpInBadValues */
|
||||
*uint_ptr = snmp_stats.inbadvalues;
|
||||
break;
|
||||
case 11: /* snmpInReadOnlys */
|
||||
*uint_ptr = snmp_stats.inreadonlys;
|
||||
break;
|
||||
case 12: /* snmpInGenErrs */
|
||||
*uint_ptr = snmp_stats.ingenerrs;
|
||||
break;
|
||||
case 13: /* snmpInTotalReqVars */
|
||||
*uint_ptr = snmp_stats.intotalreqvars;
|
||||
break;
|
||||
case 14: /* snmpInTotalSetVars */
|
||||
*uint_ptr = snmp_stats.intotalsetvars;
|
||||
break;
|
||||
case 15: /* snmpInGetRequests */
|
||||
*uint_ptr = snmp_stats.ingetrequests;
|
||||
break;
|
||||
case 16: /* snmpInGetNexts */
|
||||
*uint_ptr = snmp_stats.ingetnexts;
|
||||
break;
|
||||
case 17: /* snmpInSetRequests */
|
||||
*uint_ptr = snmp_stats.insetrequests;
|
||||
break;
|
||||
case 18: /* snmpInGetResponses */
|
||||
*uint_ptr = snmp_stats.ingetresponses;
|
||||
break;
|
||||
case 19: /* snmpInTraps */
|
||||
*uint_ptr = snmp_stats.intraps;
|
||||
break;
|
||||
case 20: /* snmpOutTooBigs */
|
||||
*uint_ptr = snmp_stats.outtoobigs;
|
||||
break;
|
||||
case 21: /* snmpOutNoSuchNames */
|
||||
*uint_ptr = snmp_stats.outnosuchnames;
|
||||
break;
|
||||
case 22: /* snmpOutBadValues */
|
||||
*uint_ptr = snmp_stats.outbadvalues;
|
||||
break;
|
||||
case 24: /* snmpOutGenErrs */
|
||||
*uint_ptr = snmp_stats.outgenerrs;
|
||||
break;
|
||||
case 25: /* snmpOutGetRequests */
|
||||
*uint_ptr = snmp_stats.outgetrequests;
|
||||
break;
|
||||
case 26: /* snmpOutGetNexts */
|
||||
*uint_ptr = snmp_stats.outgetnexts;
|
||||
break;
|
||||
case 27: /* snmpOutSetRequests */
|
||||
*uint_ptr = snmp_stats.outsetrequests;
|
||||
break;
|
||||
case 28: /* snmpOutGetResponses */
|
||||
*uint_ptr = snmp_stats.outgetresponses;
|
||||
break;
|
||||
case 29: /* snmpOutTraps */
|
||||
*uint_ptr = snmp_stats.outtraps;
|
||||
break;
|
||||
case 30: /* snmpEnableAuthenTraps */
|
||||
if (snmp_get_auth_traps_enabled() == SNMP_AUTH_TRAPS_DISABLED) {
|
||||
*uint_ptr = MIB2_AUTH_TRAPS_DISABLED;
|
||||
} else {
|
||||
*uint_ptr = MIB2_AUTH_TRAPS_ENABLED;
|
||||
}
|
||||
break;
|
||||
case 31: /* snmpSilentDrops */
|
||||
*uint_ptr = 0; /* not supported */
|
||||
break;
|
||||
case 32: /* snmpProxyDrops */
|
||||
*uint_ptr = 0; /* not supported */
|
||||
break;
|
||||
default:
|
||||
LWIP_DEBUGF(SNMP_MIB_DEBUG, ("snmp_get_value(): unknown id: %"S32_F"\n", node->oid));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return sizeof(*uint_ptr);
|
||||
@@ -160,7 +160,7 @@ snmp_set_test(const struct snmp_scalar_array_node_def *node, u16_t len, void *va
|
||||
|
||||
if (node->oid == 30) {
|
||||
/* snmpEnableAuthenTraps */
|
||||
s32_t *sint_ptr = (s32_t*)value;
|
||||
s32_t *sint_ptr = (s32_t *)value;
|
||||
|
||||
/* we should have writable non-volatile mem here */
|
||||
if ((*sint_ptr == MIB2_AUTH_TRAPS_DISABLED) || (*sint_ptr == MIB2_AUTH_TRAPS_ENABLED)) {
|
||||
@@ -177,7 +177,7 @@ snmp_set_value(const struct snmp_scalar_array_node_def *node, u16_t len, void *v
|
||||
|
||||
if (node->oid == 30) {
|
||||
/* snmpEnableAuthenTraps */
|
||||
s32_t *sint_ptr = (s32_t*)value;
|
||||
s32_t *sint_ptr = (s32_t *)value;
|
||||
if (*sint_ptr == MIB2_AUTH_TRAPS_DISABLED) {
|
||||
snmp_set_auth_traps_enabled(SNMP_AUTH_TRAPS_DISABLED);
|
||||
} else {
|
||||
|
||||
@@ -58,31 +58,31 @@
|
||||
|
||||
/** mib-2.system.sysDescr */
|
||||
static const u8_t sysdescr_default[] = SNMP_LWIP_MIB2_SYSDESC;
|
||||
static const u8_t* sysdescr = sysdescr_default;
|
||||
static const u16_t* sysdescr_len = NULL; /* use strlen for determining len */
|
||||
static const u8_t *sysdescr = sysdescr_default;
|
||||
static const u16_t *sysdescr_len = NULL; /* use strlen for determining len */
|
||||
|
||||
/** mib-2.system.sysContact */
|
||||
static const u8_t syscontact_default[] = SNMP_LWIP_MIB2_SYSCONTACT;
|
||||
static const u8_t* syscontact = syscontact_default;
|
||||
static const u16_t* syscontact_len = NULL; /* use strlen for determining len */
|
||||
static u8_t* syscontact_wr = NULL; /* if writable, points to the same buffer as syscontact (required for correct constness) */
|
||||
static u16_t* syscontact_wr_len = NULL; /* if writable, points to the same buffer as syscontact_len (required for correct constness) */
|
||||
static const u8_t *syscontact = syscontact_default;
|
||||
static const u16_t *syscontact_len = NULL; /* use strlen for determining len */
|
||||
static u8_t *syscontact_wr = NULL; /* if writable, points to the same buffer as syscontact (required for correct constness) */
|
||||
static u16_t *syscontact_wr_len = NULL; /* if writable, points to the same buffer as syscontact_len (required for correct constness) */
|
||||
static u16_t syscontact_bufsize = 0; /* 0=not writable */
|
||||
|
||||
/** mib-2.system.sysName */
|
||||
static const u8_t sysname_default[] = SNMP_LWIP_MIB2_SYSNAME;
|
||||
static const u8_t* sysname = sysname_default;
|
||||
static const u16_t* sysname_len = NULL; /* use strlen for determining len */
|
||||
static u8_t* sysname_wr = NULL; /* if writable, points to the same buffer as sysname (required for correct constness) */
|
||||
static u16_t* sysname_wr_len = NULL; /* if writable, points to the same buffer as sysname_len (required for correct constness) */
|
||||
static const u8_t *sysname = sysname_default;
|
||||
static const u16_t *sysname_len = NULL; /* use strlen for determining len */
|
||||
static u8_t *sysname_wr = NULL; /* if writable, points to the same buffer as sysname (required for correct constness) */
|
||||
static u16_t *sysname_wr_len = NULL; /* if writable, points to the same buffer as sysname_len (required for correct constness) */
|
||||
static u16_t sysname_bufsize = 0; /* 0=not writable */
|
||||
|
||||
/** mib-2.system.sysLocation */
|
||||
static const u8_t syslocation_default[] = SNMP_LWIP_MIB2_SYSLOCATION;
|
||||
static const u8_t* syslocation = syslocation_default;
|
||||
static const u16_t* syslocation_len = NULL; /* use strlen for determining len */
|
||||
static u8_t* syslocation_wr = NULL; /* if writable, points to the same buffer as syslocation (required for correct constness) */
|
||||
static u16_t* syslocation_wr_len = NULL; /* if writable, points to the same buffer as syslocation_len (required for correct constness) */
|
||||
static const u8_t *syslocation = syslocation_default;
|
||||
static const u16_t *syslocation_len = NULL; /* use strlen for determining len */
|
||||
static u8_t *syslocation_wr = NULL; /* if writable, points to the same buffer as syslocation (required for correct constness) */
|
||||
static u16_t *syslocation_wr_len = NULL; /* if writable, points to the same buffer as syslocation_len (required for correct constness) */
|
||||
static u16_t syslocation_bufsize = 0; /* 0=not writable */
|
||||
|
||||
/**
|
||||
@@ -229,48 +229,47 @@ snmp_mib2_set_syslocation_readonly(const u8_t *ocstr, const u16_t *ocstrlen)
|
||||
static s16_t
|
||||
system_get_value(const struct snmp_scalar_array_node_def *node, void *value)
|
||||
{
|
||||
const u8_t* var = NULL;
|
||||
const s16_t* var_len;
|
||||
const u8_t *var = NULL;
|
||||
const s16_t *var_len;
|
||||
u16_t result;
|
||||
|
||||
switch (node->oid) {
|
||||
case 1: /* sysDescr */
|
||||
var = sysdescr;
|
||||
var_len = (const s16_t*)sysdescr_len;
|
||||
break;
|
||||
case 2: /* sysObjectID */
|
||||
{
|
||||
const struct snmp_obj_id* dev_enterprise_oid = snmp_get_device_enterprise_oid();
|
||||
case 1: /* sysDescr */
|
||||
var = sysdescr;
|
||||
var_len = (const s16_t *)sysdescr_len;
|
||||
break;
|
||||
case 2: { /* sysObjectID */
|
||||
const struct snmp_obj_id *dev_enterprise_oid = snmp_get_device_enterprise_oid();
|
||||
MEMCPY(value, dev_enterprise_oid->id, dev_enterprise_oid->len * sizeof(u32_t));
|
||||
return dev_enterprise_oid->len * sizeof(u32_t);
|
||||
}
|
||||
case 3: /* sysUpTime */
|
||||
MIB2_COPY_SYSUPTIME_TO((u32_t*)value);
|
||||
return sizeof(u32_t);
|
||||
case 4: /* sysContact */
|
||||
var = syscontact;
|
||||
var_len = (const s16_t*)syscontact_len;
|
||||
break;
|
||||
case 5: /* sysName */
|
||||
var = sysname;
|
||||
var_len = (const s16_t*)sysname_len;
|
||||
break;
|
||||
case 6: /* sysLocation */
|
||||
var = syslocation;
|
||||
var_len = (const s16_t*)syslocation_len;
|
||||
break;
|
||||
case 7: /* sysServices */
|
||||
*(s32_t*)value = SNMP_SYSSERVICES;
|
||||
return sizeof(s32_t);
|
||||
default:
|
||||
LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_get_value(): unknown id: %"S32_F"\n", node->oid));
|
||||
return 0;
|
||||
case 3: /* sysUpTime */
|
||||
MIB2_COPY_SYSUPTIME_TO((u32_t *)value);
|
||||
return sizeof(u32_t);
|
||||
case 4: /* sysContact */
|
||||
var = syscontact;
|
||||
var_len = (const s16_t *)syscontact_len;
|
||||
break;
|
||||
case 5: /* sysName */
|
||||
var = sysname;
|
||||
var_len = (const s16_t *)sysname_len;
|
||||
break;
|
||||
case 6: /* sysLocation */
|
||||
var = syslocation;
|
||||
var_len = (const s16_t *)syslocation_len;
|
||||
break;
|
||||
case 7: /* sysServices */
|
||||
*(s32_t *)value = SNMP_SYSSERVICES;
|
||||
return sizeof(s32_t);
|
||||
default:
|
||||
LWIP_DEBUGF(SNMP_MIB_DEBUG, ("system_get_value(): unknown id: %"S32_F"\n", node->oid));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* handle string values (OID 1,4,5 and 6) */
|
||||
LWIP_ASSERT("", (value != NULL));
|
||||
if (var_len == NULL) {
|
||||
result = (s16_t)strlen((const char*)var);
|
||||
result = (s16_t)strlen((const char *)var);
|
||||
} else {
|
||||
result = *var_len;
|
||||
}
|
||||
@@ -282,27 +281,27 @@ static snmp_err_t
|
||||
system_set_test(const struct snmp_scalar_array_node_def *node, u16_t len, void *value)
|
||||
{
|
||||
snmp_err_t ret = SNMP_ERR_WRONGVALUE;
|
||||
const u16_t* var_bufsize = NULL;
|
||||
const u16_t* var_wr_len;
|
||||
const u16_t *var_bufsize = NULL;
|
||||
const u16_t *var_wr_len;
|
||||
|
||||
LWIP_UNUSED_ARG(value);
|
||||
|
||||
switch (node->oid) {
|
||||
case 4: /* sysContact */
|
||||
var_bufsize = &syscontact_bufsize;
|
||||
var_wr_len = syscontact_wr_len;
|
||||
break;
|
||||
case 5: /* sysName */
|
||||
var_bufsize = &sysname_bufsize;
|
||||
var_wr_len = sysname_wr_len;
|
||||
break;
|
||||
case 6: /* sysLocation */
|
||||
var_bufsize = &syslocation_bufsize;
|
||||
var_wr_len = syslocation_wr_len;
|
||||
break;
|
||||
default:
|
||||
LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_set_test(): unknown id: %"S32_F"\n", node->oid));
|
||||
return ret;
|
||||
case 4: /* sysContact */
|
||||
var_bufsize = &syscontact_bufsize;
|
||||
var_wr_len = syscontact_wr_len;
|
||||
break;
|
||||
case 5: /* sysName */
|
||||
var_bufsize = &sysname_bufsize;
|
||||
var_wr_len = sysname_wr_len;
|
||||
break;
|
||||
case 6: /* sysLocation */
|
||||
var_bufsize = &syslocation_bufsize;
|
||||
var_wr_len = syslocation_wr_len;
|
||||
break;
|
||||
default:
|
||||
LWIP_DEBUGF(SNMP_MIB_DEBUG, ("system_set_test(): unknown id: %"S32_F"\n", node->oid));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* check if value is writable at all */
|
||||
@@ -327,31 +326,31 @@ system_set_test(const struct snmp_scalar_array_node_def *node, u16_t len, void *
|
||||
static snmp_err_t
|
||||
system_set_value(const struct snmp_scalar_array_node_def *node, u16_t len, void *value)
|
||||
{
|
||||
u8_t* var_wr = NULL;
|
||||
u16_t* var_wr_len;
|
||||
u8_t *var_wr = NULL;
|
||||
u16_t *var_wr_len;
|
||||
|
||||
switch (node->oid) {
|
||||
case 4: /* sysContact */
|
||||
var_wr = syscontact_wr;
|
||||
var_wr_len = syscontact_wr_len;
|
||||
break;
|
||||
case 5: /* sysName */
|
||||
var_wr = sysname_wr;
|
||||
var_wr_len = sysname_wr_len;
|
||||
break;
|
||||
case 6: /* sysLocation */
|
||||
var_wr = syslocation_wr;
|
||||
var_wr_len = syslocation_wr_len;
|
||||
break;
|
||||
default:
|
||||
LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_set_value(): unknown id: %"S32_F"\n", node->oid));
|
||||
return SNMP_ERR_GENERROR;
|
||||
case 4: /* sysContact */
|
||||
var_wr = syscontact_wr;
|
||||
var_wr_len = syscontact_wr_len;
|
||||
break;
|
||||
case 5: /* sysName */
|
||||
var_wr = sysname_wr;
|
||||
var_wr_len = sysname_wr_len;
|
||||
break;
|
||||
case 6: /* sysLocation */
|
||||
var_wr = syslocation_wr;
|
||||
var_wr_len = syslocation_wr_len;
|
||||
break;
|
||||
default:
|
||||
LWIP_DEBUGF(SNMP_MIB_DEBUG, ("system_set_value(): unknown id: %"S32_F"\n", node->oid));
|
||||
return SNMP_ERR_GENERROR;
|
||||
}
|
||||
|
||||
/* no need to check size of target buffer, this was already done in set_test method */
|
||||
LWIP_ASSERT("", var_wr != NULL);
|
||||
MEMCPY(var_wr, value, len);
|
||||
|
||||
|
||||
if (var_wr_len == NULL) {
|
||||
/* add terminating 0 */
|
||||
var_wr[len] = 0;
|
||||
|
||||
@@ -59,42 +59,41 @@
|
||||
/* --- tcp .1.3.6.1.2.1.6 ----------------------------------------------------- */
|
||||
|
||||
static s16_t
|
||||
tcp_get_value(struct snmp_node_instance* instance, void* value)
|
||||
tcp_get_value(struct snmp_node_instance *instance, void *value)
|
||||
{
|
||||
u32_t *uint_ptr = (u32_t*)value;
|
||||
s32_t *sint_ptr = (s32_t*)value;
|
||||
u32_t *uint_ptr = (u32_t *)value;
|
||||
s32_t *sint_ptr = (s32_t *)value;
|
||||
|
||||
switch (instance->node->oid) {
|
||||
case 1: /* tcpRtoAlgorithm, vanj(4) */
|
||||
*sint_ptr = 4;
|
||||
return sizeof(*sint_ptr);
|
||||
case 2: /* tcpRtoMin */
|
||||
/* @todo not the actual value, a guess,
|
||||
needs to be calculated */
|
||||
*sint_ptr = 1000;
|
||||
return sizeof(*sint_ptr);
|
||||
case 3: /* tcpRtoMax */
|
||||
/* @todo not the actual value, a guess,
|
||||
needs to be calculated */
|
||||
*sint_ptr = 60000;
|
||||
return sizeof(*sint_ptr);
|
||||
case 4: /* tcpMaxConn */
|
||||
*sint_ptr = MEMP_NUM_TCP_PCB;
|
||||
return sizeof(*sint_ptr);
|
||||
case 5: /* tcpActiveOpens */
|
||||
*uint_ptr = STATS_GET(mib2.tcpactiveopens);
|
||||
return sizeof(*uint_ptr);
|
||||
case 6: /* tcpPassiveOpens */
|
||||
*uint_ptr = STATS_GET(mib2.tcppassiveopens);
|
||||
return sizeof(*uint_ptr);
|
||||
case 7: /* tcpAttemptFails */
|
||||
*uint_ptr = STATS_GET(mib2.tcpattemptfails);
|
||||
return sizeof(*uint_ptr);
|
||||
case 8: /* tcpEstabResets */
|
||||
*uint_ptr = STATS_GET(mib2.tcpestabresets);
|
||||
return sizeof(*uint_ptr);
|
||||
case 9: /* tcpCurrEstab */
|
||||
{
|
||||
case 1: /* tcpRtoAlgorithm, vanj(4) */
|
||||
*sint_ptr = 4;
|
||||
return sizeof(*sint_ptr);
|
||||
case 2: /* tcpRtoMin */
|
||||
/* @todo not the actual value, a guess,
|
||||
needs to be calculated */
|
||||
*sint_ptr = 1000;
|
||||
return sizeof(*sint_ptr);
|
||||
case 3: /* tcpRtoMax */
|
||||
/* @todo not the actual value, a guess,
|
||||
needs to be calculated */
|
||||
*sint_ptr = 60000;
|
||||
return sizeof(*sint_ptr);
|
||||
case 4: /* tcpMaxConn */
|
||||
*sint_ptr = MEMP_NUM_TCP_PCB;
|
||||
return sizeof(*sint_ptr);
|
||||
case 5: /* tcpActiveOpens */
|
||||
*uint_ptr = STATS_GET(mib2.tcpactiveopens);
|
||||
return sizeof(*uint_ptr);
|
||||
case 6: /* tcpPassiveOpens */
|
||||
*uint_ptr = STATS_GET(mib2.tcppassiveopens);
|
||||
return sizeof(*uint_ptr);
|
||||
case 7: /* tcpAttemptFails */
|
||||
*uint_ptr = STATS_GET(mib2.tcpattemptfails);
|
||||
return sizeof(*uint_ptr);
|
||||
case 8: /* tcpEstabResets */
|
||||
*uint_ptr = STATS_GET(mib2.tcpestabresets);
|
||||
return sizeof(*uint_ptr);
|
||||
case 9: { /* tcpCurrEstab */
|
||||
u16_t tcpcurrestab = 0;
|
||||
struct tcp_pcb *pcb = tcp_active_pcbs;
|
||||
while (pcb != NULL) {
|
||||
@@ -107,30 +106,38 @@ tcp_get_value(struct snmp_node_instance* instance, void* value)
|
||||
*uint_ptr = tcpcurrestab;
|
||||
}
|
||||
return sizeof(*uint_ptr);
|
||||
case 10: /* tcpInSegs */
|
||||
*uint_ptr = STATS_GET(mib2.tcpinsegs);
|
||||
return sizeof(*uint_ptr);
|
||||
case 11: /* tcpOutSegs */
|
||||
*uint_ptr = STATS_GET(mib2.tcpoutsegs);
|
||||
return sizeof(*uint_ptr);
|
||||
case 12: /* tcpRetransSegs */
|
||||
*uint_ptr = STATS_GET(mib2.tcpretranssegs);
|
||||
return sizeof(*uint_ptr);
|
||||
case 14: /* tcpInErrs */
|
||||
*uint_ptr = STATS_GET(mib2.tcpinerrs);
|
||||
return sizeof(*uint_ptr);
|
||||
case 15: /* tcpOutRsts */
|
||||
*uint_ptr = STATS_GET(mib2.tcpoutrsts);
|
||||
return sizeof(*uint_ptr);
|
||||
case 17: /* tcpHCInSegs */
|
||||
memset(value, 0, 2*sizeof(u32_t)); /* not supported */
|
||||
return 2*sizeof(u32_t);
|
||||
case 18: /* tcpHCOutSegs */
|
||||
memset(value, 0, 2*sizeof(u32_t)); /* not supported */
|
||||
return 2*sizeof(u32_t);
|
||||
default:
|
||||
LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcp_get_value(): unknown id: %"S32_F"\n", instance->node->oid));
|
||||
break;
|
||||
case 10: /* tcpInSegs */
|
||||
*uint_ptr = STATS_GET(mib2.tcpinsegs);
|
||||
return sizeof(*uint_ptr);
|
||||
case 11: /* tcpOutSegs */
|
||||
*uint_ptr = STATS_GET(mib2.tcpoutsegs);
|
||||
return sizeof(*uint_ptr);
|
||||
case 12: /* tcpRetransSegs */
|
||||
*uint_ptr = STATS_GET(mib2.tcpretranssegs);
|
||||
return sizeof(*uint_ptr);
|
||||
case 14: /* tcpInErrs */
|
||||
*uint_ptr = STATS_GET(mib2.tcpinerrs);
|
||||
return sizeof(*uint_ptr);
|
||||
case 15: /* tcpOutRsts */
|
||||
*uint_ptr = STATS_GET(mib2.tcpoutrsts);
|
||||
return sizeof(*uint_ptr);
|
||||
#if LWIP_HAVE_INT64
|
||||
case 17: { /* tcpHCInSegs */
|
||||
/* use the 32 bit counter for now... */
|
||||
u64_t val64 = STATS_GET(mib2.tcpinsegs);
|
||||
*((u64_t *)value) = val64;
|
||||
}
|
||||
return sizeof(u64_t);
|
||||
case 18: { /* tcpHCOutSegs */
|
||||
/* use the 32 bit counter for now... */
|
||||
u64_t val64 = STATS_GET(mib2.tcpoutsegs);
|
||||
*((u64_t *)value) = val64;
|
||||
}
|
||||
return sizeof(u64_t);
|
||||
#endif
|
||||
default:
|
||||
LWIP_DEBUGF(SNMP_MIB_DEBUG, ("tcp_get_value(): unknown id: %"S32_F"\n", instance->node->oid));
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -155,45 +162,45 @@ static const struct snmp_oid_range tcp_ConnTable_oid_ranges[] = {
|
||||
};
|
||||
|
||||
static snmp_err_t
|
||||
tcp_ConnTable_get_cell_value_core(struct tcp_pcb *pcb, const u32_t* column, union snmp_variant_value* value, u32_t* value_len)
|
||||
tcp_ConnTable_get_cell_value_core(struct tcp_pcb *pcb, const u32_t *column, union snmp_variant_value *value, u32_t *value_len)
|
||||
{
|
||||
LWIP_UNUSED_ARG(value_len);
|
||||
|
||||
/* value */
|
||||
switch (*column) {
|
||||
case 1: /* tcpConnState */
|
||||
value->u32 = pcb->state + 1;
|
||||
break;
|
||||
case 2: /* tcpConnLocalAddress */
|
||||
value->u32 = ip_2_ip4(&pcb->local_ip)->addr;
|
||||
break;
|
||||
case 3: /* tcpConnLocalPort */
|
||||
value->u32 = pcb->local_port;
|
||||
break;
|
||||
case 4: /* tcpConnRemAddress */
|
||||
if (pcb->state == LISTEN) {
|
||||
value->u32 = IP4_ADDR_ANY4->addr;
|
||||
} else {
|
||||
value->u32 = ip_2_ip4(&pcb->remote_ip)->addr;
|
||||
}
|
||||
break;
|
||||
case 5: /* tcpConnRemPort */
|
||||
if (pcb->state == LISTEN) {
|
||||
value->u32 = 0;
|
||||
} else {
|
||||
value->u32 = pcb->remote_port;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LWIP_ASSERT("invalid id", 0);
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
case 1: /* tcpConnState */
|
||||
value->u32 = pcb->state + 1;
|
||||
break;
|
||||
case 2: /* tcpConnLocalAddress */
|
||||
value->u32 = ip_2_ip4(&pcb->local_ip)->addr;
|
||||
break;
|
||||
case 3: /* tcpConnLocalPort */
|
||||
value->u32 = pcb->local_port;
|
||||
break;
|
||||
case 4: /* tcpConnRemAddress */
|
||||
if (pcb->state == LISTEN) {
|
||||
value->u32 = IP4_ADDR_ANY4->addr;
|
||||
} else {
|
||||
value->u32 = ip_2_ip4(&pcb->remote_ip)->addr;
|
||||
}
|
||||
break;
|
||||
case 5: /* tcpConnRemPort */
|
||||
if (pcb->state == LISTEN) {
|
||||
value->u32 = 0;
|
||||
} else {
|
||||
value->u32 = pcb->remote_port;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LWIP_ASSERT("invalid id", 0);
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
return SNMP_ERR_NOERROR;
|
||||
}
|
||||
|
||||
static snmp_err_t
|
||||
tcp_ConnTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len)
|
||||
tcp_ConnTable_get_cell_value(const u32_t *column, const u32_t *row_oid, u8_t row_oid_len, union snmp_variant_value *value, u32_t *value_len)
|
||||
{
|
||||
u8_t i;
|
||||
ip4_addr_t local_ip;
|
||||
@@ -220,7 +227,7 @@ tcp_ConnTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row
|
||||
while (pcb != NULL) {
|
||||
/* do local IP and local port match? */
|
||||
if (IP_IS_V4_VAL(pcb->local_ip) &&
|
||||
ip4_addr_cmp(&local_ip, ip_2_ip4(&pcb->local_ip)) && (local_port == pcb->local_port)) {
|
||||
ip4_addr_cmp(&local_ip, ip_2_ip4(&pcb->local_ip)) && (local_port == pcb->local_port)) {
|
||||
|
||||
/* PCBs in state LISTEN are not connected and have no remote_ip or remote_port */
|
||||
if (pcb->state == LISTEN) {
|
||||
@@ -230,7 +237,7 @@ tcp_ConnTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row
|
||||
}
|
||||
} else {
|
||||
if (IP_IS_V4_VAL(pcb->remote_ip) &&
|
||||
ip4_addr_cmp(&remote_ip, ip_2_ip4(&pcb->remote_ip)) && (remote_port == pcb->remote_port)) {
|
||||
ip4_addr_cmp(&remote_ip, ip_2_ip4(&pcb->remote_ip)) && (remote_port == pcb->remote_port)) {
|
||||
/* fill in object properties */
|
||||
return tcp_ConnTable_get_cell_value_core(pcb, column, value, value_len);
|
||||
}
|
||||
@@ -246,7 +253,7 @@ tcp_ConnTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row
|
||||
}
|
||||
|
||||
static snmp_err_t
|
||||
tcp_ConnTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
|
||||
tcp_ConnTable_get_next_cell_instance_and_value(const u32_t *column, struct snmp_obj_id *row_oid, union snmp_variant_value *value, u32_t *value_len)
|
||||
{
|
||||
u8_t i;
|
||||
struct tcp_pcb *pcb;
|
||||
@@ -290,7 +297,7 @@ tcp_ConnTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_
|
||||
if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
|
||||
snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
|
||||
/* fill in object properties */
|
||||
return tcp_ConnTable_get_cell_value_core((struct tcp_pcb*)state.reference, column, value, value_len);
|
||||
return tcp_ConnTable_get_cell_value_core((struct tcp_pcb *)state.reference, column, value, value_len);
|
||||
}
|
||||
|
||||
/* not found */
|
||||
@@ -302,43 +309,43 @@ tcp_ConnTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_
|
||||
/* --- tcpConnectionTable --- */
|
||||
|
||||
static snmp_err_t
|
||||
tcp_ConnectionTable_get_cell_value_core(const u32_t* column, struct tcp_pcb *pcb, union snmp_variant_value* value)
|
||||
tcp_ConnectionTable_get_cell_value_core(const u32_t *column, struct tcp_pcb *pcb, union snmp_variant_value *value)
|
||||
{
|
||||
/* all items except tcpConnectionState and tcpConnectionProcess are declared as not-accessible */
|
||||
switch (*column) {
|
||||
case 7: /* tcpConnectionState */
|
||||
value->u32 = pcb->state + 1;
|
||||
break;
|
||||
case 8: /* tcpConnectionProcess */
|
||||
value->u32 = 0; /* not supported */
|
||||
break;
|
||||
default:
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
case 7: /* tcpConnectionState */
|
||||
value->u32 = pcb->state + 1;
|
||||
break;
|
||||
case 8: /* tcpConnectionProcess */
|
||||
value->u32 = 0; /* not supported */
|
||||
break;
|
||||
default:
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
return SNMP_ERR_NOERROR;
|
||||
}
|
||||
|
||||
static snmp_err_t
|
||||
tcp_ConnectionTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len)
|
||||
tcp_ConnectionTable_get_cell_value(const u32_t *column, const u32_t *row_oid, u8_t row_oid_len, union snmp_variant_value *value, u32_t *value_len)
|
||||
{
|
||||
ip_addr_t local_ip, remote_ip;
|
||||
u16_t local_port, remote_port;
|
||||
struct tcp_pcb *pcb;
|
||||
u8_t idx = 0;
|
||||
u8_t i;
|
||||
struct tcp_pcb ** const tcp_pcb_nonlisten_lists[] = {&tcp_bound_pcbs, &tcp_active_pcbs, &tcp_tw_pcbs};
|
||||
struct tcp_pcb **const tcp_pcb_nonlisten_lists[] = {&tcp_bound_pcbs, &tcp_active_pcbs, &tcp_tw_pcbs};
|
||||
|
||||
LWIP_UNUSED_ARG(value_len);
|
||||
|
||||
/* tcpConnectionLocalAddressType + tcpConnectionLocalAddress + tcpConnectionLocalPort */
|
||||
idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len-idx, &local_ip, &local_port);
|
||||
idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len - idx, &local_ip, &local_port);
|
||||
if (idx == 0) {
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
/* tcpConnectionRemAddressType + tcpConnectionRemAddress + tcpConnectionRemPort */
|
||||
idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len-idx, &remote_ip, &remote_port);
|
||||
idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len - idx, &remote_ip, &remote_port);
|
||||
if (idx == 0) {
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
@@ -349,9 +356,9 @@ tcp_ConnectionTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8
|
||||
|
||||
while (pcb != NULL) {
|
||||
if (ip_addr_cmp(&local_ip, &pcb->local_ip) &&
|
||||
(local_port == pcb->local_port) &&
|
||||
ip_addr_cmp(&remote_ip, &pcb->remote_ip) &&
|
||||
(remote_port == pcb->remote_port)) {
|
||||
(local_port == pcb->local_port) &&
|
||||
ip_addr_cmp(&remote_ip, &pcb->remote_ip) &&
|
||||
(remote_port == pcb->remote_port)) {
|
||||
/* fill in object properties */
|
||||
return tcp_ConnectionTable_get_cell_value_core(column, pcb, value);
|
||||
}
|
||||
@@ -364,7 +371,7 @@ tcp_ConnectionTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8
|
||||
}
|
||||
|
||||
static snmp_err_t
|
||||
tcp_ConnectionTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
|
||||
tcp_ConnectionTable_get_next_cell_instance_and_value(const u32_t *column, struct snmp_obj_id *row_oid, union snmp_variant_value *value, u32_t *value_len)
|
||||
{
|
||||
struct tcp_pcb *pcb;
|
||||
struct snmp_next_oid_state state;
|
||||
@@ -372,7 +379,7 @@ tcp_ConnectionTable_get_next_cell_instance_and_value(const u32_t* column, struct
|
||||
* 1x tcpConnectionRemAddressType + 1x OID len + 16x tcpConnectionRemAddress + 1x tcpConnectionRemPort */
|
||||
u32_t result_temp[38];
|
||||
u8_t i;
|
||||
struct tcp_pcb ** const tcp_pcb_nonlisten_lists[] = {&tcp_bound_pcbs, &tcp_active_pcbs, &tcp_tw_pcbs};
|
||||
struct tcp_pcb **const tcp_pcb_nonlisten_lists[] = {&tcp_bound_pcbs, &tcp_active_pcbs, &tcp_tw_pcbs};
|
||||
|
||||
LWIP_UNUSED_ARG(value_len);
|
||||
|
||||
@@ -404,7 +411,7 @@ tcp_ConnectionTable_get_next_cell_instance_and_value(const u32_t* column, struct
|
||||
if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
|
||||
snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
|
||||
/* fill in object properties */
|
||||
return tcp_ConnectionTable_get_cell_value_core(column, (struct tcp_pcb*)state.reference, value);
|
||||
return tcp_ConnectionTable_get_cell_value_core(column, (struct tcp_pcb *)state.reference, value);
|
||||
} else {
|
||||
/* not found */
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
@@ -414,22 +421,22 @@ tcp_ConnectionTable_get_next_cell_instance_and_value(const u32_t* column, struct
|
||||
/* --- tcpListenerTable --- */
|
||||
|
||||
static snmp_err_t
|
||||
tcp_ListenerTable_get_cell_value_core(const u32_t* column, union snmp_variant_value* value)
|
||||
tcp_ListenerTable_get_cell_value_core(const u32_t *column, union snmp_variant_value *value)
|
||||
{
|
||||
/* all items except tcpListenerProcess are declared as not-accessible */
|
||||
switch (*column) {
|
||||
case 4: /* tcpListenerProcess */
|
||||
value->u32 = 0; /* not supported */
|
||||
break;
|
||||
default:
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
case 4: /* tcpListenerProcess */
|
||||
value->u32 = 0; /* not supported */
|
||||
break;
|
||||
default:
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
return SNMP_ERR_NOERROR;
|
||||
}
|
||||
|
||||
static snmp_err_t
|
||||
tcp_ListenerTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len)
|
||||
tcp_ListenerTable_get_cell_value(const u32_t *column, const u32_t *row_oid, u8_t row_oid_len, union snmp_variant_value *value, u32_t *value_len)
|
||||
{
|
||||
ip_addr_t local_ip;
|
||||
u16_t local_port;
|
||||
@@ -439,7 +446,7 @@ tcp_ListenerTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t
|
||||
LWIP_UNUSED_ARG(value_len);
|
||||
|
||||
/* tcpListenerLocalAddressType + tcpListenerLocalAddress + tcpListenerLocalPort */
|
||||
idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len-idx, &local_ip, &local_port);
|
||||
idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len - idx, &local_ip, &local_port);
|
||||
if (idx == 0) {
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
@@ -448,7 +455,7 @@ tcp_ListenerTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t
|
||||
pcb = tcp_listen_pcbs.listen_pcbs;
|
||||
while (pcb != NULL) {
|
||||
if (ip_addr_cmp(&local_ip, &pcb->local_ip) &&
|
||||
(local_port == pcb->local_port)) {
|
||||
(local_port == pcb->local_port)) {
|
||||
/* fill in object properties */
|
||||
return tcp_ListenerTable_get_cell_value_core(column, value);
|
||||
}
|
||||
@@ -460,7 +467,7 @@ tcp_ListenerTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t
|
||||
}
|
||||
|
||||
static snmp_err_t
|
||||
tcp_ListenerTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
|
||||
tcp_ListenerTable_get_next_cell_instance_and_value(const u32_t *column, struct snmp_obj_id *row_oid, union snmp_variant_value *value, u32_t *value_len)
|
||||
{
|
||||
struct tcp_pcb_listen *pcb;
|
||||
struct snmp_next_oid_state state;
|
||||
@@ -512,8 +519,10 @@ static const struct snmp_scalar_node tcp_OutSegs = SNMP_SCALAR_CREATE_NODE
|
||||
static const struct snmp_scalar_node tcp_RetransSegs = SNMP_SCALAR_CREATE_NODE_READONLY(12, SNMP_ASN1_TYPE_COUNTER, tcp_get_value);
|
||||
static const struct snmp_scalar_node tcp_InErrs = SNMP_SCALAR_CREATE_NODE_READONLY(14, SNMP_ASN1_TYPE_COUNTER, tcp_get_value);
|
||||
static const struct snmp_scalar_node tcp_OutRsts = SNMP_SCALAR_CREATE_NODE_READONLY(15, SNMP_ASN1_TYPE_COUNTER, tcp_get_value);
|
||||
#if LWIP_HAVE_INT64
|
||||
static const struct snmp_scalar_node tcp_HCInSegs = SNMP_SCALAR_CREATE_NODE_READONLY(17, SNMP_ASN1_TYPE_COUNTER64, tcp_get_value);
|
||||
static const struct snmp_scalar_node tcp_HCOutSegs = SNMP_SCALAR_CREATE_NODE_READONLY(18, SNMP_ASN1_TYPE_COUNTER64, tcp_get_value);
|
||||
#endif
|
||||
|
||||
#if LWIP_IPV4
|
||||
static const struct snmp_table_simple_col_def tcp_ConnTable_columns[] = {
|
||||
@@ -561,12 +570,14 @@ CREATE_LWIP_SYNC_NODE(13, tcp_ConnTable)
|
||||
#endif /* LWIP_IPV4 */
|
||||
CREATE_LWIP_SYNC_NODE(14, tcp_InErrs)
|
||||
CREATE_LWIP_SYNC_NODE(15, tcp_OutRsts)
|
||||
#if LWIP_HAVE_INT64
|
||||
CREATE_LWIP_SYNC_NODE(17, tcp_HCInSegs)
|
||||
CREATE_LWIP_SYNC_NODE(18, tcp_HCOutSegs)
|
||||
#endif
|
||||
CREATE_LWIP_SYNC_NODE(19, tcp_ConnectionTable)
|
||||
CREATE_LWIP_SYNC_NODE(20, tcp_ListenerTable)
|
||||
|
||||
static const struct snmp_node* const tcp_nodes[] = {
|
||||
static const struct snmp_node *const tcp_nodes[] = {
|
||||
&SYNC_NODE_NAME(tcp_RtoAlgorithm).node.node,
|
||||
&SYNC_NODE_NAME(tcp_RtoMin).node.node,
|
||||
&SYNC_NODE_NAME(tcp_RtoMax).node.node,
|
||||
@@ -585,8 +596,10 @@ static const struct snmp_node* const tcp_nodes[] = {
|
||||
&SYNC_NODE_NAME(tcp_InErrs).node.node,
|
||||
&SYNC_NODE_NAME(tcp_OutRsts).node.node,
|
||||
&SYNC_NODE_NAME(tcp_HCInSegs).node.node,
|
||||
#if LWIP_HAVE_INT64
|
||||
&SYNC_NODE_NAME(tcp_HCOutSegs).node.node,
|
||||
&SYNC_NODE_NAME(tcp_ConnectionTable).node.node,
|
||||
#endif
|
||||
&SYNC_NODE_NAME(tcp_ListenerTable).node.node
|
||||
};
|
||||
|
||||
|
||||
@@ -58,32 +58,40 @@
|
||||
/* --- udp .1.3.6.1.2.1.7 ----------------------------------------------------- */
|
||||
|
||||
static s16_t
|
||||
udp_get_value(struct snmp_node_instance* instance, void* value)
|
||||
udp_get_value(struct snmp_node_instance *instance, void *value)
|
||||
{
|
||||
u32_t *uint_ptr = (u32_t*)value;
|
||||
u32_t *uint_ptr = (u32_t *)value;
|
||||
|
||||
switch (instance->node->oid) {
|
||||
case 1: /* udpInDatagrams */
|
||||
*uint_ptr = STATS_GET(mib2.udpindatagrams);
|
||||
return sizeof(*uint_ptr);
|
||||
case 2: /* udpNoPorts */
|
||||
*uint_ptr = STATS_GET(mib2.udpnoports);
|
||||
return sizeof(*uint_ptr);
|
||||
case 3: /* udpInErrors */
|
||||
*uint_ptr = STATS_GET(mib2.udpinerrors);
|
||||
return sizeof(*uint_ptr);
|
||||
case 4: /* udpOutDatagrams */
|
||||
*uint_ptr = STATS_GET(mib2.udpoutdatagrams);
|
||||
return sizeof(*uint_ptr);
|
||||
case 8: /* udpHCInDatagrams */
|
||||
memset(value, 0, 2*sizeof(u32_t)); /* not supported */
|
||||
return 2*sizeof(u32_t);
|
||||
case 9: /* udpHCOutDatagrams */
|
||||
memset(value, 0, 2*sizeof(u32_t)); /* not supported */
|
||||
return 2*sizeof(u32_t);
|
||||
default:
|
||||
LWIP_DEBUGF(SNMP_MIB_DEBUG,("udp_get_value(): unknown id: %"S32_F"\n", instance->node->oid));
|
||||
break;
|
||||
case 1: /* udpInDatagrams */
|
||||
*uint_ptr = STATS_GET(mib2.udpindatagrams);
|
||||
return sizeof(*uint_ptr);
|
||||
case 2: /* udpNoPorts */
|
||||
*uint_ptr = STATS_GET(mib2.udpnoports);
|
||||
return sizeof(*uint_ptr);
|
||||
case 3: /* udpInErrors */
|
||||
*uint_ptr = STATS_GET(mib2.udpinerrors);
|
||||
return sizeof(*uint_ptr);
|
||||
case 4: /* udpOutDatagrams */
|
||||
*uint_ptr = STATS_GET(mib2.udpoutdatagrams);
|
||||
return sizeof(*uint_ptr);
|
||||
#if LWIP_HAVE_INT64
|
||||
case 8: { /* udpHCInDatagrams */
|
||||
/* use the 32 bit counter for now... */
|
||||
u64_t val64 = STATS_GET(mib2.udpindatagrams);
|
||||
*((u64_t *)value) = val64;
|
||||
}
|
||||
return sizeof(u64_t);
|
||||
case 9: { /* udpHCOutDatagrams */
|
||||
/* use the 32 bit counter for now... */
|
||||
u64_t val64 = STATS_GET(mib2.udpoutdatagrams);
|
||||
*((u64_t *)value) = val64;
|
||||
}
|
||||
return sizeof(u64_t);
|
||||
#endif
|
||||
default:
|
||||
LWIP_DEBUGF(SNMP_MIB_DEBUG, ("udp_get_value(): unknown id: %"S32_F"\n", instance->node->oid));
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -92,22 +100,22 @@ udp_get_value(struct snmp_node_instance* instance, void* value)
|
||||
/* --- udpEndpointTable --- */
|
||||
|
||||
static snmp_err_t
|
||||
udp_endpointTable_get_cell_value_core(const u32_t* column, union snmp_variant_value* value)
|
||||
udp_endpointTable_get_cell_value_core(const u32_t *column, union snmp_variant_value *value)
|
||||
{
|
||||
/* all items except udpEndpointProcess are declared as not-accessible */
|
||||
switch (*column) {
|
||||
case 8: /* udpEndpointProcess */
|
||||
value->u32 = 0; /* not supported */
|
||||
break;
|
||||
default:
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
case 8: /* udpEndpointProcess */
|
||||
value->u32 = 0; /* not supported */
|
||||
break;
|
||||
default:
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
return SNMP_ERR_NOERROR;
|
||||
}
|
||||
|
||||
static snmp_err_t
|
||||
udp_endpointTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len)
|
||||
udp_endpointTable_get_cell_value(const u32_t *column, const u32_t *row_oid, u8_t row_oid_len, union snmp_variant_value *value, u32_t *value_len)
|
||||
{
|
||||
ip_addr_t local_ip, remote_ip;
|
||||
u16_t local_port, remote_port;
|
||||
@@ -117,32 +125,32 @@ udp_endpointTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t
|
||||
LWIP_UNUSED_ARG(value_len);
|
||||
|
||||
/* udpEndpointLocalAddressType + udpEndpointLocalAddress + udpEndpointLocalPort */
|
||||
idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len-idx, &local_ip, &local_port);
|
||||
idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len - idx, &local_ip, &local_port);
|
||||
if (idx == 0) {
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
/* udpEndpointRemoteAddressType + udpEndpointRemoteAddress + udpEndpointRemotePort */
|
||||
idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len-idx, &remote_ip, &remote_port);
|
||||
idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len - idx, &remote_ip, &remote_port);
|
||||
if (idx == 0) {
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
/* udpEndpointInstance */
|
||||
if (row_oid_len < (idx+1)) {
|
||||
if (row_oid_len < (idx + 1)) {
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
if (row_oid[idx] != 0) {
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
|
||||
/* find udp_pcb with requested ip and port*/
|
||||
pcb = udp_pcbs;
|
||||
while (pcb != NULL) {
|
||||
if (ip_addr_cmp(&local_ip, &pcb->local_ip) &&
|
||||
(local_port == pcb->local_port) &&
|
||||
ip_addr_cmp(&remote_ip, &pcb->remote_ip) &&
|
||||
(remote_port == pcb->remote_port)) {
|
||||
(local_port == pcb->local_port) &&
|
||||
ip_addr_cmp(&remote_ip, &pcb->remote_ip) &&
|
||||
(remote_port == pcb->remote_port)) {
|
||||
/* fill in object properties */
|
||||
return udp_endpointTable_get_cell_value_core(column, value);
|
||||
}
|
||||
@@ -153,8 +161,8 @@ udp_endpointTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
static snmp_err_t
|
||||
udp_endpointTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
|
||||
static snmp_err_t
|
||||
udp_endpointTable_get_next_cell_instance_and_value(const u32_t *column, struct snmp_obj_id *row_oid, union snmp_variant_value *value, u32_t *value_len)
|
||||
{
|
||||
struct udp_pcb *pcb;
|
||||
struct snmp_next_oid_state state;
|
||||
@@ -181,12 +189,12 @@ udp_endpointTable_get_next_cell_instance_and_value(const u32_t* column, struct s
|
||||
/* udpEndpointRemoteAddressType + udpEndpointRemoteAddress + udpEndpointRemotePort */
|
||||
idx += snmp_ip_port_to_oid(&pcb->remote_ip, pcb->remote_port, &test_oid[idx]);
|
||||
|
||||
test_oid[idx] = 0; /* udpEndpointInstance */
|
||||
test_oid[idx] = 0; /* udpEndpointInstance */
|
||||
idx++;
|
||||
|
||||
|
||||
/* check generated OID: is it a candidate for the next one? */
|
||||
snmp_next_oid_check(&state, test_oid, idx, NULL);
|
||||
|
||||
|
||||
pcb = pcb->next;
|
||||
}
|
||||
|
||||
@@ -214,29 +222,29 @@ static const struct snmp_oid_range udp_Table_oid_ranges[] = {
|
||||
{ 1, 0xffff } /* Port */
|
||||
};
|
||||
|
||||
static snmp_err_t
|
||||
udp_Table_get_cell_value_core(struct udp_pcb *pcb, const u32_t* column, union snmp_variant_value* value, u32_t* value_len)
|
||||
static snmp_err_t
|
||||
udp_Table_get_cell_value_core(struct udp_pcb *pcb, const u32_t *column, union snmp_variant_value *value, u32_t *value_len)
|
||||
{
|
||||
LWIP_UNUSED_ARG(value_len);
|
||||
|
||||
switch (*column) {
|
||||
case 1: /* udpLocalAddress */
|
||||
/* set reference to PCB local IP and return a generic node that copies IP4 addresses */
|
||||
value->u32 = ip_2_ip4(&pcb->local_ip)->addr;
|
||||
break;
|
||||
case 2: /* udpLocalPort */
|
||||
/* set reference to PCB local port and return a generic node that copies u16_t values */
|
||||
value->u32 = pcb->local_port;
|
||||
break;
|
||||
default:
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
case 1: /* udpLocalAddress */
|
||||
/* set reference to PCB local IP and return a generic node that copies IP4 addresses */
|
||||
value->u32 = ip_2_ip4(&pcb->local_ip)->addr;
|
||||
break;
|
||||
case 2: /* udpLocalPort */
|
||||
/* set reference to PCB local port and return a generic node that copies u16_t values */
|
||||
value->u32 = pcb->local_port;
|
||||
break;
|
||||
default:
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
return SNMP_ERR_NOERROR;
|
||||
}
|
||||
|
||||
static snmp_err_t
|
||||
udp_Table_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len)
|
||||
static snmp_err_t
|
||||
udp_Table_get_cell_value(const u32_t *column, const u32_t *row_oid, u8_t row_oid_len, union snmp_variant_value *value, u32_t *value_len)
|
||||
{
|
||||
ip4_addr_t ip;
|
||||
u16_t port;
|
||||
@@ -267,8 +275,8 @@ udp_Table_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
static snmp_err_t
|
||||
udp_Table_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
|
||||
static snmp_err_t
|
||||
udp_Table_get_next_cell_instance_and_value(const u32_t *column, struct snmp_obj_id *row_oid, union snmp_variant_value *value, u32_t *value_len)
|
||||
{
|
||||
struct udp_pcb *pcb;
|
||||
struct snmp_next_oid_state state;
|
||||
@@ -289,7 +297,7 @@ udp_Table_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_
|
||||
/* check generated OID: is it a candidate for the next one? */
|
||||
snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(udp_Table_oid_ranges), pcb);
|
||||
}
|
||||
|
||||
|
||||
pcb = pcb->next;
|
||||
}
|
||||
|
||||
@@ -297,7 +305,7 @@ udp_Table_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_
|
||||
if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
|
||||
snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
|
||||
/* fill in object properties */
|
||||
return udp_Table_get_cell_value_core((struct udp_pcb*)state.reference, column, value, value_len);
|
||||
return udp_Table_get_cell_value_core((struct udp_pcb *)state.reference, column, value, value_len);
|
||||
} else {
|
||||
/* not found */
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
@@ -310,8 +318,10 @@ static const struct snmp_scalar_node udp_inDatagrams = SNMP_SCALAR_CREATE_NOD
|
||||
static const struct snmp_scalar_node udp_noPorts = SNMP_SCALAR_CREATE_NODE_READONLY(2, SNMP_ASN1_TYPE_COUNTER, udp_get_value);
|
||||
static const struct snmp_scalar_node udp_inErrors = SNMP_SCALAR_CREATE_NODE_READONLY(3, SNMP_ASN1_TYPE_COUNTER, udp_get_value);
|
||||
static const struct snmp_scalar_node udp_outDatagrams = SNMP_SCALAR_CREATE_NODE_READONLY(4, SNMP_ASN1_TYPE_COUNTER, udp_get_value);
|
||||
#if LWIP_HAVE_INT64
|
||||
static const struct snmp_scalar_node udp_HCInDatagrams = SNMP_SCALAR_CREATE_NODE_READONLY(8, SNMP_ASN1_TYPE_COUNTER64, udp_get_value);
|
||||
static const struct snmp_scalar_node udp_HCOutDatagrams = SNMP_SCALAR_CREATE_NODE_READONLY(9, SNMP_ASN1_TYPE_COUNTER64, udp_get_value);
|
||||
#endif
|
||||
|
||||
#if LWIP_IPV4
|
||||
static const struct snmp_table_simple_col_def udp_Table_columns[] = {
|
||||
@@ -322,13 +332,13 @@ static const struct snmp_table_simple_node udp_Table = SNMP_TABLE_CREATE_SIMPLE(
|
||||
#endif /* LWIP_IPV4 */
|
||||
|
||||
static const struct snmp_table_simple_col_def udp_endpointTable_columns[] = {
|
||||
/* all items except udpEndpointProcess are declared as not-accessible */
|
||||
/* all items except udpEndpointProcess are declared as not-accessible */
|
||||
{ 8, SNMP_ASN1_TYPE_UNSIGNED32, SNMP_VARIANT_VALUE_TYPE_U32 } /* udpEndpointProcess */
|
||||
};
|
||||
|
||||
static const struct snmp_table_simple_node udp_endpointTable = SNMP_TABLE_CREATE_SIMPLE(7, udp_endpointTable_columns, udp_endpointTable_get_cell_value, udp_endpointTable_get_next_cell_instance_and_value);
|
||||
|
||||
/* the following nodes access variables in LWIP stack from SNMP worker thread and must therefore be synced to LWIP (TCPIP) thread */
|
||||
/* the following nodes access variables in LWIP stack from SNMP worker thread and must therefore be synced to LWIP (TCPIP) thread */
|
||||
CREATE_LWIP_SYNC_NODE(1, udp_inDatagrams)
|
||||
CREATE_LWIP_SYNC_NODE(2, udp_noPorts)
|
||||
CREATE_LWIP_SYNC_NODE(3, udp_inErrors)
|
||||
@@ -337,10 +347,12 @@ CREATE_LWIP_SYNC_NODE(4, udp_outDatagrams)
|
||||
CREATE_LWIP_SYNC_NODE(5, udp_Table)
|
||||
#endif /* LWIP_IPV4 */
|
||||
CREATE_LWIP_SYNC_NODE(7, udp_endpointTable)
|
||||
#if LWIP_HAVE_INT64
|
||||
CREATE_LWIP_SYNC_NODE(8, udp_HCInDatagrams)
|
||||
CREATE_LWIP_SYNC_NODE(9, udp_HCOutDatagrams)
|
||||
#endif
|
||||
|
||||
static const struct snmp_node* const udp_nodes[] = {
|
||||
static const struct snmp_node *const udp_nodes[] = {
|
||||
&SYNC_NODE_NAME(udp_inDatagrams).node.node,
|
||||
&SYNC_NODE_NAME(udp_noPorts).node.node,
|
||||
&SYNC_NODE_NAME(udp_inErrors).node.node,
|
||||
@@ -348,9 +360,12 @@ static const struct snmp_node* const udp_nodes[] = {
|
||||
#if LWIP_IPV4
|
||||
&SYNC_NODE_NAME(udp_Table).node.node,
|
||||
#endif /* LWIP_IPV4 */
|
||||
&SYNC_NODE_NAME(udp_endpointTable).node.node,
|
||||
&SYNC_NODE_NAME(udp_endpointTable).node.node
|
||||
#if LWIP_HAVE_INT64
|
||||
,
|
||||
&SYNC_NODE_NAME(udp_HCInDatagrams).node.node,
|
||||
&SYNC_NODE_NAME(udp_HCOutDatagrams).node.node
|
||||
#endif
|
||||
};
|
||||
|
||||
const struct snmp_tree_node snmp_mib2_udp_root = SNMP_CREATE_TREE_NODE(7, udp_nodes);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -57,24 +57,12 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* The listen port of the SNMP agent. Clients have to make their requests to
|
||||
this port. Most standard clients won't work if you change this! */
|
||||
#ifndef SNMP_IN_PORT
|
||||
#define SNMP_IN_PORT 161
|
||||
#endif
|
||||
/* The remote port the SNMP agent sends traps to. Most standard trap sinks won't
|
||||
work if you change this! */
|
||||
#ifndef SNMP_TRAP_PORT
|
||||
#define SNMP_TRAP_PORT 162
|
||||
#endif
|
||||
|
||||
/* version defines used in PDU */
|
||||
#define SNMP_VERSION_1 0
|
||||
#define SNMP_VERSION_2c 1
|
||||
#define SNMP_VERSION_3 3
|
||||
|
||||
struct snmp_varbind_enumerator
|
||||
{
|
||||
struct snmp_varbind_enumerator {
|
||||
struct snmp_pbuf_stream pbuf_stream;
|
||||
u16_t varbind_count;
|
||||
};
|
||||
@@ -86,11 +74,10 @@ typedef enum {
|
||||
SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH = 3
|
||||
} snmp_vb_enumerator_err_t;
|
||||
|
||||
void snmp_vb_enumerator_init(struct snmp_varbind_enumerator* enumerator, struct pbuf* p, u16_t offset, u16_t length);
|
||||
snmp_vb_enumerator_err_t snmp_vb_enumerator_get_next(struct snmp_varbind_enumerator* enumerator, struct snmp_varbind* varbind);
|
||||
void snmp_vb_enumerator_init(struct snmp_varbind_enumerator *enumerator, struct pbuf *p, u16_t offset, u16_t length);
|
||||
snmp_vb_enumerator_err_t snmp_vb_enumerator_get_next(struct snmp_varbind_enumerator *enumerator, struct snmp_varbind *varbind);
|
||||
|
||||
struct snmp_request
|
||||
{
|
||||
struct snmp_request {
|
||||
/* Communication handle */
|
||||
void *handle;
|
||||
/* source IP address */
|
||||
@@ -115,7 +102,10 @@ struct snmp_request
|
||||
s32_t non_repeaters;
|
||||
/* max-repetitions (getBulkRequest (SNMPv2c)) */
|
||||
s32_t max_repetitions;
|
||||
|
||||
|
||||
/* Usually response-pdu (2). When snmpv3 errors are detected report-pdu(8) */
|
||||
u8_t request_out_type;
|
||||
|
||||
#if LWIP_SNMP_V3
|
||||
s32_t msg_id;
|
||||
s32_t msg_max_size;
|
||||
@@ -128,7 +118,9 @@ struct snmp_request
|
||||
u8_t msg_user_name[SNMP_V3_MAX_USER_LENGTH];
|
||||
u8_t msg_user_name_len;
|
||||
u8_t msg_authentication_parameters[SNMP_V3_MAX_AUTH_PARAM_LENGTH];
|
||||
u8_t msg_authentication_parameters_len;
|
||||
u8_t msg_privacy_parameters[SNMP_V3_MAX_PRIV_PARAM_LENGTH];
|
||||
u8_t msg_privacy_parameters_len;
|
||||
u8_t context_engine_id[SNMP_V3_MAX_ENGINE_ID_LENGTH];
|
||||
u8_t context_engine_id_len;
|
||||
u8_t context_name[SNMP_V3_MAX_ENGINE_ID_LENGTH];
|
||||
@@ -162,8 +154,7 @@ struct snmp_request
|
||||
};
|
||||
|
||||
/** A helper struct keeping length information about varbinds */
|
||||
struct snmp_varbind_len
|
||||
{
|
||||
struct snmp_varbind_len {
|
||||
u8_t vb_len_len;
|
||||
u16_t vb_value_len;
|
||||
u8_t oid_len_len;
|
||||
@@ -177,13 +168,13 @@ extern const char *snmp_community;
|
||||
/** Agent community string for write access */
|
||||
extern const char *snmp_community_write;
|
||||
/** handle for sending traps */
|
||||
extern void* snmp_traps_handle;
|
||||
extern void *snmp_traps_handle;
|
||||
|
||||
void snmp_receive(void *handle, struct pbuf *p, const ip_addr_t *source_ip, u16_t port);
|
||||
err_t snmp_sendto(void *handle, struct pbuf *p, const ip_addr_t *dst, u16_t port);
|
||||
u8_t snmp_get_local_ip_for_dst(void* handle, const ip_addr_t *dst, ip_addr_t *result);
|
||||
u8_t snmp_get_local_ip_for_dst(void *handle, const ip_addr_t *dst, ip_addr_t *result);
|
||||
err_t snmp_varbind_length(struct snmp_varbind *varbind, struct snmp_varbind_len *len);
|
||||
err_t snmp_append_outbound_varbind(struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind* varbind);
|
||||
err_t snmp_append_outbound_varbind(struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind *varbind);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -36,11 +36,13 @@
|
||||
|
||||
#if LWIP_SNMP && SNMP_USE_NETCONN
|
||||
|
||||
#include <string.h>
|
||||
#include "lwip/api.h"
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "snmp_msg.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/prot/iana.h"
|
||||
|
||||
/** SNMP netconn API worker thread */
|
||||
static void
|
||||
@@ -50,17 +52,17 @@ snmp_netconn_thread(void *arg)
|
||||
struct netbuf *buf;
|
||||
err_t err;
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
|
||||
|
||||
/* Bind to SNMP port with default IP address */
|
||||
#if LWIP_IPV6
|
||||
#if LWIP_IPV6
|
||||
conn = netconn_new(NETCONN_UDP_IPV6);
|
||||
netconn_bind(conn, IP6_ADDR_ANY, SNMP_IN_PORT);
|
||||
netconn_bind(conn, IP6_ADDR_ANY, LWIP_IANA_PORT_SNMP);
|
||||
#else /* LWIP_IPV6 */
|
||||
conn = netconn_new(NETCONN_UDP);
|
||||
netconn_bind(conn, IP4_ADDR_ANY, SNMP_IN_PORT);
|
||||
netconn_bind(conn, IP4_ADDR_ANY, LWIP_IANA_PORT_SNMP);
|
||||
#endif /* LWIP_IPV6 */
|
||||
LWIP_ERROR("snmp_netconn: invalid conn", (conn != NULL), return;);
|
||||
|
||||
|
||||
snmp_traps_handle = conn;
|
||||
|
||||
do {
|
||||
@@ -73,28 +75,28 @@ snmp_netconn_thread(void *arg)
|
||||
if (buf != NULL) {
|
||||
netbuf_delete(buf);
|
||||
}
|
||||
} while(1);
|
||||
} while (1);
|
||||
}
|
||||
|
||||
err_t
|
||||
err_t
|
||||
snmp_sendto(void *handle, struct pbuf *p, const ip_addr_t *dst, u16_t port)
|
||||
{
|
||||
err_t result;
|
||||
struct netbuf buf;
|
||||
|
||||
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
buf.p = p;
|
||||
result = netconn_sendto((struct netconn*)handle, &buf, dst, port);
|
||||
|
||||
result = netconn_sendto((struct netconn *)handle, &buf, dst, port);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
u8_t
|
||||
snmp_get_local_ip_for_dst(void* handle, const ip_addr_t *dst, ip_addr_t *result)
|
||||
snmp_get_local_ip_for_dst(void *handle, const ip_addr_t *dst, ip_addr_t *result)
|
||||
{
|
||||
struct netconn* conn = (struct netconn*)handle;
|
||||
struct netconn *conn = (struct netconn *)handle;
|
||||
struct netif *dst_if;
|
||||
const ip_addr_t* dst_ip;
|
||||
const ip_addr_t *dst_ip;
|
||||
|
||||
LWIP_UNUSED_ARG(conn); /* unused in case of IPV4 only configuration */
|
||||
|
||||
@@ -114,6 +116,7 @@ snmp_get_local_ip_for_dst(void* handle, const ip_addr_t *dst, ip_addr_t *result)
|
||||
void
|
||||
snmp_init(void)
|
||||
{
|
||||
LWIP_ASSERT_CORE_LOCKED();
|
||||
sys_thread_new("snmp_netconn", snmp_netconn_thread, NULL, SNMP_STACK_SIZE, SNMP_THREAD_PRIO);
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
#include <string.h>
|
||||
|
||||
err_t
|
||||
snmp_pbuf_stream_init(struct snmp_pbuf_stream* pbuf_stream, struct pbuf* p, u16_t offset, u16_t length)
|
||||
snmp_pbuf_stream_init(struct snmp_pbuf_stream *pbuf_stream, struct pbuf *p, u16_t offset, u16_t length)
|
||||
{
|
||||
pbuf_stream->offset = offset;
|
||||
pbuf_stream->length = length;
|
||||
@@ -54,7 +54,7 @@ snmp_pbuf_stream_init(struct snmp_pbuf_stream* pbuf_stream, struct pbuf* p, u16_
|
||||
}
|
||||
|
||||
err_t
|
||||
snmp_pbuf_stream_read(struct snmp_pbuf_stream* pbuf_stream, u8_t* data)
|
||||
snmp_pbuf_stream_read(struct snmp_pbuf_stream *pbuf_stream, u8_t *data)
|
||||
{
|
||||
if (pbuf_stream->length == 0) {
|
||||
return ERR_BUF;
|
||||
@@ -71,13 +71,13 @@ snmp_pbuf_stream_read(struct snmp_pbuf_stream* pbuf_stream, u8_t* data)
|
||||
}
|
||||
|
||||
err_t
|
||||
snmp_pbuf_stream_write(struct snmp_pbuf_stream* pbuf_stream, u8_t data)
|
||||
snmp_pbuf_stream_write(struct snmp_pbuf_stream *pbuf_stream, u8_t data)
|
||||
{
|
||||
return snmp_pbuf_stream_writebuf(pbuf_stream, &data, 1);
|
||||
}
|
||||
|
||||
err_t
|
||||
snmp_pbuf_stream_writebuf(struct snmp_pbuf_stream* pbuf_stream, const void* buf, u16_t buf_len)
|
||||
snmp_pbuf_stream_writebuf(struct snmp_pbuf_stream *pbuf_stream, const void *buf, u16_t buf_len)
|
||||
{
|
||||
if (pbuf_stream->length < buf_len) {
|
||||
return ERR_BUF;
|
||||
@@ -94,7 +94,7 @@ snmp_pbuf_stream_writebuf(struct snmp_pbuf_stream* pbuf_stream, const void* buf,
|
||||
}
|
||||
|
||||
err_t
|
||||
snmp_pbuf_stream_writeto(struct snmp_pbuf_stream* pbuf_stream, struct snmp_pbuf_stream* target_pbuf_stream, u16_t len)
|
||||
snmp_pbuf_stream_writeto(struct snmp_pbuf_stream *pbuf_stream, struct snmp_pbuf_stream *target_pbuf_stream, u16_t len)
|
||||
{
|
||||
|
||||
if ((pbuf_stream == NULL) || (target_pbuf_stream == NULL)) {
|
||||
@@ -112,14 +112,14 @@ snmp_pbuf_stream_writeto(struct snmp_pbuf_stream* pbuf_stream, struct snmp_pbuf_
|
||||
u16_t chunk_len;
|
||||
err_t err;
|
||||
u16_t target_offset;
|
||||
struct pbuf* pbuf = pbuf_skip(pbuf_stream->pbuf, pbuf_stream->offset, &target_offset);
|
||||
struct pbuf *pbuf = pbuf_skip(pbuf_stream->pbuf, pbuf_stream->offset, &target_offset);
|
||||
|
||||
if ((pbuf == NULL) || (pbuf->len == 0)) {
|
||||
return ERR_BUF;
|
||||
}
|
||||
|
||||
chunk_len = LWIP_MIN(len, pbuf->len);
|
||||
err = snmp_pbuf_stream_writebuf(target_pbuf_stream, &((u8_t*)pbuf->payload)[target_offset], chunk_len);
|
||||
err = snmp_pbuf_stream_writebuf(target_pbuf_stream, &((u8_t *)pbuf->payload)[target_offset], chunk_len);
|
||||
if (err != ERR_OK) {
|
||||
return err;
|
||||
}
|
||||
@@ -133,7 +133,7 @@ snmp_pbuf_stream_writeto(struct snmp_pbuf_stream* pbuf_stream, struct snmp_pbuf_
|
||||
}
|
||||
|
||||
err_t
|
||||
snmp_pbuf_stream_seek(struct snmp_pbuf_stream* pbuf_stream, s32_t offset)
|
||||
snmp_pbuf_stream_seek(struct snmp_pbuf_stream *pbuf_stream, s32_t offset)
|
||||
{
|
||||
if ((offset < 0) || (offset > pbuf_stream->length)) {
|
||||
/* we cannot seek backwards or forward behind stream end */
|
||||
@@ -147,7 +147,7 @@ snmp_pbuf_stream_seek(struct snmp_pbuf_stream* pbuf_stream, s32_t offset)
|
||||
}
|
||||
|
||||
err_t
|
||||
snmp_pbuf_stream_seek_abs(struct snmp_pbuf_stream* pbuf_stream, u32_t offset)
|
||||
snmp_pbuf_stream_seek_abs(struct snmp_pbuf_stream *pbuf_stream, u32_t offset)
|
||||
{
|
||||
s32_t rel_offset = offset - pbuf_stream->offset;
|
||||
return snmp_pbuf_stream_seek(pbuf_stream, rel_offset);
|
||||
|
||||
@@ -49,20 +49,19 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct snmp_pbuf_stream
|
||||
{
|
||||
struct pbuf* pbuf;
|
||||
struct snmp_pbuf_stream {
|
||||
struct pbuf *pbuf;
|
||||
u16_t offset;
|
||||
u16_t length;
|
||||
};
|
||||
|
||||
err_t snmp_pbuf_stream_init(struct snmp_pbuf_stream* pbuf_stream, struct pbuf* p, u16_t offset, u16_t length);
|
||||
err_t snmp_pbuf_stream_read(struct snmp_pbuf_stream* pbuf_stream, u8_t* data);
|
||||
err_t snmp_pbuf_stream_write(struct snmp_pbuf_stream* pbuf_stream, u8_t data);
|
||||
err_t snmp_pbuf_stream_writebuf(struct snmp_pbuf_stream* pbuf_stream, const void* buf, u16_t buf_len);
|
||||
err_t snmp_pbuf_stream_writeto(struct snmp_pbuf_stream* pbuf_stream, struct snmp_pbuf_stream* target_pbuf_stream, u16_t len);
|
||||
err_t snmp_pbuf_stream_seek(struct snmp_pbuf_stream* pbuf_stream, s32_t offset);
|
||||
err_t snmp_pbuf_stream_seek_abs(struct snmp_pbuf_stream* pbuf_stream, u32_t offset);
|
||||
err_t snmp_pbuf_stream_init(struct snmp_pbuf_stream *pbuf_stream, struct pbuf *p, u16_t offset, u16_t length);
|
||||
err_t snmp_pbuf_stream_read(struct snmp_pbuf_stream *pbuf_stream, u8_t *data);
|
||||
err_t snmp_pbuf_stream_write(struct snmp_pbuf_stream *pbuf_stream, u8_t data);
|
||||
err_t snmp_pbuf_stream_writebuf(struct snmp_pbuf_stream *pbuf_stream, const void *buf, u16_t buf_len);
|
||||
err_t snmp_pbuf_stream_writeto(struct snmp_pbuf_stream *pbuf_stream, struct snmp_pbuf_stream *target_pbuf_stream, u16_t len);
|
||||
err_t snmp_pbuf_stream_seek(struct snmp_pbuf_stream *pbuf_stream, s32_t offset);
|
||||
err_t snmp_pbuf_stream_seek_abs(struct snmp_pbuf_stream *pbuf_stream, u32_t offset);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/prot/iana.h"
|
||||
#include "snmp_msg.h"
|
||||
|
||||
/* lwIP UDP receive callback function */
|
||||
@@ -52,18 +53,18 @@ snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr,
|
||||
pbuf_free(p);
|
||||
}
|
||||
|
||||
err_t
|
||||
err_t
|
||||
snmp_sendto(void *handle, struct pbuf *p, const ip_addr_t *dst, u16_t port)
|
||||
{
|
||||
return udp_sendto((struct udp_pcb*)handle, p, dst, port);
|
||||
return udp_sendto((struct udp_pcb *)handle, p, dst, port);
|
||||
}
|
||||
|
||||
u8_t
|
||||
snmp_get_local_ip_for_dst(void* handle, const ip_addr_t *dst, ip_addr_t *result)
|
||||
snmp_get_local_ip_for_dst(void *handle, const ip_addr_t *dst, ip_addr_t *result)
|
||||
{
|
||||
struct udp_pcb* udp_pcb = (struct udp_pcb*)handle;
|
||||
struct udp_pcb *udp_pcb = (struct udp_pcb *)handle;
|
||||
struct netif *dst_if;
|
||||
const ip_addr_t* dst_ip;
|
||||
const ip_addr_t *dst_ip;
|
||||
|
||||
LWIP_UNUSED_ARG(udp_pcb); /* unused in case of IPV4 only configuration */
|
||||
|
||||
@@ -86,14 +87,16 @@ void
|
||||
snmp_init(void)
|
||||
{
|
||||
err_t err;
|
||||
|
||||
|
||||
struct udp_pcb *snmp_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
|
||||
LWIP_ERROR("snmp_raw: no PCB", (snmp_pcb != NULL), return;);
|
||||
|
||||
LWIP_ASSERT_CORE_LOCKED();
|
||||
|
||||
snmp_traps_handle = snmp_pcb;
|
||||
|
||||
udp_recv(snmp_pcb, snmp_recv, (void *)SNMP_IN_PORT);
|
||||
err = udp_bind(snmp_pcb, IP_ANY_TYPE, SNMP_IN_PORT);
|
||||
udp_recv(snmp_pcb, snmp_recv, NULL);
|
||||
err = udp_bind(snmp_pcb, IP_ANY_TYPE, LWIP_IANA_PORT_SNMP);
|
||||
LWIP_ERROR("snmp_raw: Unable to bind PCB", (err == ERR_OK), return;);
|
||||
}
|
||||
|
||||
|
||||
@@ -42,14 +42,14 @@
|
||||
#include "lwip/apps/snmp_scalar.h"
|
||||
#include "lwip/apps/snmp_core.h"
|
||||
|
||||
static s16_t snmp_scalar_array_get_value(struct snmp_node_instance* instance, void* value);
|
||||
static snmp_err_t snmp_scalar_array_set_test(struct snmp_node_instance* instance, u16_t value_len, void* value);
|
||||
static snmp_err_t snmp_scalar_array_set_value(struct snmp_node_instance* instance, u16_t value_len, void* value);
|
||||
static s16_t snmp_scalar_array_get_value(struct snmp_node_instance *instance, void *value);
|
||||
static snmp_err_t snmp_scalar_array_set_test(struct snmp_node_instance *instance, u16_t value_len, void *value);
|
||||
static snmp_err_t snmp_scalar_array_set_value(struct snmp_node_instance *instance, u16_t value_len, void *value);
|
||||
|
||||
snmp_err_t
|
||||
snmp_scalar_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
|
||||
snmp_err_t
|
||||
snmp_scalar_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance *instance)
|
||||
{
|
||||
const struct snmp_scalar_node* scalar_node = (const struct snmp_scalar_node*)(const void*)instance->node;
|
||||
const struct snmp_scalar_node *scalar_node = (const struct snmp_scalar_node *)(const void *)instance->node;
|
||||
|
||||
LWIP_UNUSED_ARG(root_oid);
|
||||
LWIP_UNUSED_ARG(root_oid_len);
|
||||
@@ -67,8 +67,8 @@ snmp_scalar_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_n
|
||||
return SNMP_ERR_NOERROR;
|
||||
}
|
||||
|
||||
snmp_err_t
|
||||
snmp_scalar_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
|
||||
snmp_err_t
|
||||
snmp_scalar_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance *instance)
|
||||
{
|
||||
/* because our only instance is .0 we can only return a next instance if no instance oid is passed */
|
||||
if (instance->instance_oid.len == 0) {
|
||||
@@ -83,14 +83,14 @@ snmp_scalar_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct s
|
||||
|
||||
|
||||
snmp_err_t
|
||||
snmp_scalar_array_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
|
||||
snmp_scalar_array_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance *instance)
|
||||
{
|
||||
LWIP_UNUSED_ARG(root_oid);
|
||||
LWIP_UNUSED_ARG(root_oid_len);
|
||||
|
||||
if ((instance->instance_oid.len == 2) && (instance->instance_oid.id[1] == 0)) {
|
||||
const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)(const void*)instance->node;
|
||||
const struct snmp_scalar_array_node_def* array_node_def = array_node->array_nodes;
|
||||
const struct snmp_scalar_array_node *array_node = (const struct snmp_scalar_array_node *)(const void *)instance->node;
|
||||
const struct snmp_scalar_array_node_def *array_node_def = array_node->array_nodes;
|
||||
u32_t i = 0;
|
||||
|
||||
while (i < array_node->array_node_count) {
|
||||
@@ -118,11 +118,11 @@ snmp_scalar_array_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct
|
||||
}
|
||||
|
||||
snmp_err_t
|
||||
snmp_scalar_array_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
|
||||
snmp_scalar_array_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance *instance)
|
||||
{
|
||||
const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)(const void*)instance->node;
|
||||
const struct snmp_scalar_array_node_def* array_node_def = array_node->array_nodes;
|
||||
const struct snmp_scalar_array_node_def* result = NULL;
|
||||
const struct snmp_scalar_array_node *array_node = (const struct snmp_scalar_array_node *)(const void *)instance->node;
|
||||
const struct snmp_scalar_array_node_def *array_node_def = array_node->array_nodes;
|
||||
const struct snmp_scalar_array_node_def *result = NULL;
|
||||
|
||||
LWIP_UNUSED_ARG(root_oid);
|
||||
LWIP_UNUSED_ARG(root_oid_len);
|
||||
@@ -130,7 +130,7 @@ snmp_scalar_array_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, st
|
||||
if ((instance->instance_oid.len == 0) && (array_node->array_node_count > 0)) {
|
||||
/* return node with lowest OID */
|
||||
u16_t i = 0;
|
||||
|
||||
|
||||
result = array_node_def;
|
||||
array_node_def++;
|
||||
|
||||
@@ -142,7 +142,7 @@ snmp_scalar_array_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, st
|
||||
}
|
||||
} else if (instance->instance_oid.len >= 1) {
|
||||
if (instance->instance_oid.len == 1) {
|
||||
/* if we have the requested OID we return its instance, otherwise we search for the next available */
|
||||
/* if we have the requested OID we return its instance, otherwise we search for the next available */
|
||||
u16_t i = 0;
|
||||
while (i < array_node->array_node_count) {
|
||||
if (array_node_def->oid == instance->instance_oid.id[0]) {
|
||||
@@ -179,7 +179,7 @@ snmp_scalar_array_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, st
|
||||
instance->instance_oid.len = 2;
|
||||
instance->instance_oid.id[0] = result->oid;
|
||||
instance->instance_oid.id[1] = 0;
|
||||
|
||||
|
||||
instance->access = result->access;
|
||||
instance->asn1_type = result->asn1_type;
|
||||
instance->get_value = snmp_scalar_array_get_value;
|
||||
@@ -191,30 +191,42 @@ snmp_scalar_array_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, st
|
||||
}
|
||||
|
||||
static s16_t
|
||||
snmp_scalar_array_get_value(struct snmp_node_instance* instance, void* value)
|
||||
snmp_scalar_array_get_value(struct snmp_node_instance *instance, void *value)
|
||||
{
|
||||
const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)(const void*)instance->node;
|
||||
const struct snmp_scalar_array_node_def* array_node_def = (const struct snmp_scalar_array_node_def*)instance->reference.const_ptr;
|
||||
s16_t result = -1;
|
||||
const struct snmp_scalar_array_node *array_node = (const struct snmp_scalar_array_node *)(const void *)instance->node;
|
||||
const struct snmp_scalar_array_node_def *array_node_def = (const struct snmp_scalar_array_node_def *)instance->reference.const_ptr;
|
||||
|
||||
return array_node->get_value(array_node_def, value);
|
||||
if (array_node->get_value != NULL) {
|
||||
result = array_node->get_value(array_node_def, value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static snmp_err_t
|
||||
snmp_scalar_array_set_test(struct snmp_node_instance* instance, u16_t value_len, void* value)
|
||||
snmp_scalar_array_set_test(struct snmp_node_instance *instance, u16_t value_len, void *value)
|
||||
{
|
||||
const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)(const void*)instance->node;
|
||||
const struct snmp_scalar_array_node_def* array_node_def = (const struct snmp_scalar_array_node_def*)instance->reference.const_ptr;
|
||||
snmp_err_t result = SNMP_ERR_NOTWRITABLE;
|
||||
const struct snmp_scalar_array_node *array_node = (const struct snmp_scalar_array_node *)(const void *)instance->node;
|
||||
const struct snmp_scalar_array_node_def *array_node_def = (const struct snmp_scalar_array_node_def *)instance->reference.const_ptr;
|
||||
|
||||
return array_node->set_test(array_node_def, value_len, value);
|
||||
if (array_node->set_test != NULL) {
|
||||
result = array_node->set_test(array_node_def, value_len, value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static snmp_err_t
|
||||
snmp_scalar_array_set_value(struct snmp_node_instance* instance, u16_t value_len, void* value)
|
||||
snmp_scalar_array_set_value(struct snmp_node_instance *instance, u16_t value_len, void *value)
|
||||
{
|
||||
const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)(const void*)instance->node;
|
||||
const struct snmp_scalar_array_node_def* array_node_def = (const struct snmp_scalar_array_node_def*)instance->reference.const_ptr;
|
||||
snmp_err_t result = SNMP_ERR_NOTWRITABLE;
|
||||
const struct snmp_scalar_array_node *array_node = (const struct snmp_scalar_array_node *)(const void *)instance->node;
|
||||
const struct snmp_scalar_array_node_def *array_node_def = (const struct snmp_scalar_array_node_def *)instance->reference.const_ptr;
|
||||
|
||||
return array_node->set_value(array_node_def, value_len, value);
|
||||
if (array_node->set_value != NULL) {
|
||||
result = array_node->set_value(array_node_def, value_len, value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* LWIP_SNMP */
|
||||
|
||||
90
src/apps/snmp/snmp_snmpv2_framework.c
Normal file
90
src/apps/snmp/snmp_snmpv2_framework.c
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
Generated by LwipMibCompiler
|
||||
*/
|
||||
|
||||
#include "lwip/apps/snmp_opts.h"
|
||||
|
||||
#if LWIP_SNMP && LWIP_SNMP_V3 /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/apps/snmp_snmpv2_framework.h"
|
||||
#include "lwip/apps/snmp.h"
|
||||
#include "lwip/apps/snmp_core.h"
|
||||
#include "lwip/apps/snmp_scalar.h"
|
||||
#include "lwip/apps/snmp_table.h"
|
||||
#include "lwip/apps/snmpv3.h"
|
||||
#include "snmpv3_priv.h"
|
||||
|
||||
#include "lwip/sys.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
const struct snmp_obj_id usmNoAuthProtocol = { 10, { 1, 3, 6, 1, 6, 3, 10, 1, 1, 1 } };
|
||||
const struct snmp_obj_id usmHMACMD5AuthProtocol = { 10, { 1, 3, 6, 1, 6, 3, 10, 1, 1, 2 } };
|
||||
const struct snmp_obj_id usmHMACSHAAuthProtocol = { 10, { 1, 3, 6, 1, 6, 3, 10, 1, 1, 3 } };
|
||||
/* .4 sha-224
|
||||
* .5 sha-256
|
||||
* .6 sha-384
|
||||
* .7 sha-512
|
||||
*/
|
||||
|
||||
const struct snmp_obj_id usmNoPrivProtocol = { 10, { 1, 3, 6, 1, 6, 3, 10, 1, 2, 1 } };
|
||||
const struct snmp_obj_id usmDESPrivProtocol = { 10, { 1, 3, 6, 1, 6, 3, 10, 1, 2, 2 } };
|
||||
/* .3 3des-ede */
|
||||
const struct snmp_obj_id usmAESPrivProtocol = { 10, { 1, 3, 6, 1, 6, 3, 10, 1, 2, 4 } };
|
||||
/* .5 unknown
|
||||
* .6 unknown
|
||||
* .7 unknown
|
||||
*/
|
||||
|
||||
/* TODO: where should this value come from? */
|
||||
#define SNMP_FRAMEWORKMIB_SNMPENGINEMAXMESSAGESIZE 1500
|
||||
|
||||
/* --- snmpFrameworkMIBObjects 1.3.6.1.6.3.10.2 ----------------------------------------------------- */
|
||||
static s16_t snmpengine_scalars_get_value(const struct snmp_scalar_array_node_def *node, void *value)
|
||||
{
|
||||
const char *engineid;
|
||||
u8_t engineid_len;
|
||||
|
||||
switch (node->oid) {
|
||||
case 1: /* snmpEngineID */
|
||||
snmpv3_get_engine_id(&engineid, &engineid_len);
|
||||
MEMCPY(value, engineid, engineid_len);
|
||||
return engineid_len;
|
||||
case 2: /* snmpEngineBoots */
|
||||
*(s32_t *)value = snmpv3_get_engine_boots_internal();
|
||||
return sizeof(s32_t);
|
||||
case 3: /* snmpEngineTime */
|
||||
*(s32_t *)value = snmpv3_get_engine_time_internal();
|
||||
return sizeof(s32_t);
|
||||
case 4: /* snmpEngineMaxMessageSize */
|
||||
*(s32_t *)value = SNMP_FRAMEWORKMIB_SNMPENGINEMAXMESSAGESIZE;
|
||||
return sizeof(s32_t);
|
||||
default:
|
||||
LWIP_DEBUGF(SNMP_MIB_DEBUG, ("snmpengine_scalars_get_value(): unknown id: %"S32_F"\n", node->oid));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct snmp_scalar_array_node_def snmpengine_scalars_nodes[] = {
|
||||
{1, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpEngineID */
|
||||
{2, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpEngineBoots */
|
||||
{3, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpEngineTime */
|
||||
{4, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpEngineMaxMessageSize */
|
||||
};
|
||||
static const struct snmp_scalar_array_node snmpengine_scalars = SNMP_SCALAR_CREATE_ARRAY_NODE(1, snmpengine_scalars_nodes, snmpengine_scalars_get_value, NULL, NULL);
|
||||
|
||||
static const struct snmp_node *const snmpframeworkmibobjects_subnodes[] = {
|
||||
&snmpengine_scalars.node.node
|
||||
};
|
||||
static const struct snmp_tree_node snmpframeworkmibobjects_treenode = SNMP_CREATE_TREE_NODE(2, snmpframeworkmibobjects_subnodes);
|
||||
|
||||
/* --- snmpFrameworkMIB ----------------------------------------------------- */
|
||||
static const struct snmp_node *const snmpframeworkmib_subnodes[] = {
|
||||
&snmpframeworkmibobjects_treenode.node
|
||||
};
|
||||
static const struct snmp_tree_node snmpframeworkmib_root = SNMP_CREATE_TREE_NODE(10, snmpframeworkmib_subnodes);
|
||||
static const u32_t snmpframeworkmib_base_oid[] = {1, 3, 6, 1, 6, 3, 10};
|
||||
const struct snmp_mib snmpframeworkmib = {snmpframeworkmib_base_oid, LWIP_ARRAYSIZE(snmpframeworkmib_base_oid), &snmpframeworkmib_root.node};
|
||||
|
||||
/* --- snmpFrameworkMIB ----------------------------------------------------- */
|
||||
#endif /* LWIP_SNMP */
|
||||
410
src/apps/snmp/snmp_snmpv2_usm.c
Normal file
410
src/apps/snmp/snmp_snmpv2_usm.c
Normal file
@@ -0,0 +1,410 @@
|
||||
/*
|
||||
Generated by LwipMibCompiler
|
||||
*/
|
||||
|
||||
#include "lwip/apps/snmp_opts.h"
|
||||
#if LWIP_SNMP && LWIP_SNMP_V3
|
||||
|
||||
#include "lwip/apps/snmp_snmpv2_usm.h"
|
||||
#include "lwip/apps/snmp.h"
|
||||
#include "lwip/apps/snmp_core.h"
|
||||
#include "lwip/apps/snmp_scalar.h"
|
||||
#include "lwip/apps/snmp_table.h"
|
||||
#include "lwip/apps/snmpv3.h"
|
||||
#include "snmpv3_priv.h"
|
||||
|
||||
#include "lwip/apps/snmp_snmpv2_framework.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* --- usmUser 1.3.6.1.6.3.15.1.2 ----------------------------------------------------- */
|
||||
|
||||
static const struct snmp_oid_range usmUserTable_oid_ranges[] = {
|
||||
{ 0, 0xff }, { 0, 0xff }, { 0, 0xff }, { 0, 0xff },
|
||||
{ 0, 0xff }, { 0, 0xff }, { 0, 0xff }, { 0, 0xff },
|
||||
{ 0, 0xff }, { 0, 0xff }, { 0, 0xff }, { 0, 0xff },
|
||||
{ 0, 0xff }, { 0, 0xff }, { 0, 0xff }, { 0, 0xff },
|
||||
{ 0, 0xff }, { 0, 0xff }, { 0, 0xff }, { 0, 0xff },
|
||||
{ 0, 0xff }, { 0, 0xff }, { 0, 0xff }, { 0, 0xff },
|
||||
{ 0, 0xff }, { 0, 0xff }, { 0, 0xff }, { 0, 0xff },
|
||||
{ 0, 0xff }, { 0, 0xff }, { 0, 0xff }, { 0, 0xff }
|
||||
};
|
||||
|
||||
static void snmp_engineid_to_oid(const char *engineid, u32_t *oid, u32_t len)
|
||||
{
|
||||
u8_t i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
oid[i] = engineid[i];
|
||||
}
|
||||
}
|
||||
|
||||
static void snmp_oid_to_name(char *name, const u32_t *oid, size_t len)
|
||||
{
|
||||
u8_t i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
name[i] = (char)oid[i];
|
||||
}
|
||||
}
|
||||
|
||||
static void snmp_name_to_oid(const char *name, u32_t *oid, size_t len)
|
||||
{
|
||||
u8_t i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
oid[i] = name[i];
|
||||
}
|
||||
}
|
||||
|
||||
static const struct snmp_obj_id *snmp_auth_algo_to_oid(snmpv3_auth_algo_t algo)
|
||||
{
|
||||
if (algo == SNMP_V3_AUTH_ALGO_MD5) {
|
||||
return &usmHMACMD5AuthProtocol;
|
||||
} else if (algo == SNMP_V3_AUTH_ALGO_SHA) {
|
||||
return &usmHMACMD5AuthProtocol;
|
||||
}
|
||||
|
||||
return &usmNoAuthProtocol;
|
||||
}
|
||||
|
||||
static const struct snmp_obj_id *snmp_priv_algo_to_oid(snmpv3_priv_algo_t algo)
|
||||
{
|
||||
if (algo == SNMP_V3_PRIV_ALGO_DES) {
|
||||
return &usmDESPrivProtocol;
|
||||
} else if (algo == SNMP_V3_PRIV_ALGO_AES) {
|
||||
return &usmAESPrivProtocol;
|
||||
}
|
||||
|
||||
return &usmNoPrivProtocol;
|
||||
}
|
||||
|
||||
char username[32];
|
||||
|
||||
static snmp_err_t usmusertable_get_instance(const u32_t *column, const u32_t *row_oid, u8_t row_oid_len, struct snmp_node_instance *cell_instance)
|
||||
{
|
||||
const char *engineid;
|
||||
u8_t eid_len;
|
||||
|
||||
u32_t engineid_oid[SNMP_V3_MAX_ENGINE_ID_LENGTH];
|
||||
|
||||
u8_t name_len;
|
||||
u8_t engineid_len;
|
||||
|
||||
u8_t name_start;
|
||||
u8_t engineid_start;
|
||||
|
||||
LWIP_UNUSED_ARG(column);
|
||||
|
||||
snmpv3_get_engine_id(&engineid, &eid_len);
|
||||
|
||||
engineid_len = (u8_t)row_oid[0];
|
||||
engineid_start = 1;
|
||||
|
||||
if (engineid_len != eid_len) {
|
||||
/* EngineID length does not match! */
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
if (engineid_len > row_oid_len) {
|
||||
/* row OID doesn't contain enough data according to engineid_len.*/
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
/* check if incoming OID length and if values are in plausible range */
|
||||
if (!snmp_oid_in_range(&row_oid[engineid_start], engineid_len, usmUserTable_oid_ranges, engineid_len)) {
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
snmp_engineid_to_oid(engineid, engineid_oid, engineid_len);
|
||||
|
||||
/* Verify EngineID */
|
||||
if (snmp_oid_equal(&row_oid[engineid_start], engineid_len, engineid_oid, engineid_len)) {
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
name_len = (u8_t)row_oid[engineid_start + engineid_len];
|
||||
name_start = engineid_start + engineid_len + 1;
|
||||
|
||||
if (name_len > SNMP_V3_MAX_USER_LENGTH) {
|
||||
/* specified name is too long */
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
if (1 + engineid_len + 1 + name_len != row_oid_len) {
|
||||
/* Length of EngineID and name does not match row oid length. (+2 for length fields)*/
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
/* check if incoming OID length and if values are in plausible range */
|
||||
if (!snmp_oid_in_range(&row_oid[name_start], name_len, usmUserTable_oid_ranges, name_len)) {
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
/* Verify if user exists */
|
||||
memset(username, 0, sizeof(username));
|
||||
snmp_oid_to_name(username, &row_oid[name_start], name_len);
|
||||
if (snmpv3_get_user(username, NULL, NULL, NULL, NULL) != ERR_OK) {
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
/* Save name in reference pointer to make it easier to handle later on */
|
||||
cell_instance->reference.ptr = username;
|
||||
cell_instance->reference_len = name_len;
|
||||
|
||||
/* user was found */
|
||||
return SNMP_ERR_NOERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* valid oid options
|
||||
* <oid>
|
||||
* <oid>.<EngineID length>
|
||||
* <oid>.<EngineID length>.<partial EngineID>
|
||||
* <oid>.<EngineID length>.<EngineID>
|
||||
* <oid>.<EngineID length>.<EngineID>.<UserName length>
|
||||
* <oid>.<EngineID length>.<EngineID>.<UserName length>.<partial UserName>
|
||||
* <oid>.<EngineID length>.<EngineID>.<UserName length>.<UserName>
|
||||
*
|
||||
*/
|
||||
static snmp_err_t usmusertable_get_next_instance(const u32_t *column, struct snmp_obj_id *row_oid, struct snmp_node_instance *cell_instance)
|
||||
{
|
||||
const char *engineid;
|
||||
u8_t eid_len;
|
||||
|
||||
u32_t engineid_oid[SNMP_V3_MAX_ENGINE_ID_LENGTH];
|
||||
|
||||
u8_t name_len;
|
||||
u8_t engineid_len;
|
||||
|
||||
u8_t name_start;
|
||||
u8_t engineid_start = 1;
|
||||
u8_t i;
|
||||
|
||||
struct snmp_next_oid_state state;
|
||||
|
||||
u32_t result_temp[LWIP_ARRAYSIZE(usmUserTable_oid_ranges)];
|
||||
|
||||
LWIP_UNUSED_ARG(column);
|
||||
|
||||
snmpv3_get_engine_id(&engineid, &eid_len);
|
||||
|
||||
/* If EngineID might be given */
|
||||
if (row_oid->len > 0) {
|
||||
engineid_len = (u8_t)row_oid->id[0];
|
||||
engineid_start = 1;
|
||||
|
||||
if (engineid_len != eid_len) {
|
||||
/* EngineID length does not match! */
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
if (engineid_len > row_oid->len) {
|
||||
/* Verify partial EngineID */
|
||||
snmp_engineid_to_oid(engineid, engineid_oid, row_oid->len - 1);
|
||||
if (!snmp_oid_equal(&row_oid->id[engineid_start], row_oid->len - 1, engineid_oid, row_oid->len - 1)) {
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
} else {
|
||||
/* Verify complete EngineID */
|
||||
snmp_engineid_to_oid(engineid, engineid_oid, engineid_len);
|
||||
if (!snmp_oid_equal(&row_oid->id[engineid_start], engineid_len, engineid_oid, engineid_len)) {
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
/* At this point, the given EngineID (partially) matches the local EngineID.*/
|
||||
|
||||
/* If name might also be given */
|
||||
if (row_oid->len > engineid_start + engineid_len) {
|
||||
name_len = (u8_t)row_oid->id[engineid_start + engineid_len];
|
||||
name_start = engineid_start + engineid_len + 1;
|
||||
|
||||
if (name_len > SNMP_V3_MAX_USER_LENGTH) {
|
||||
/* specified name is too long, max length is 32 according to mib file.*/
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
if (row_oid->len < engineid_len + name_len + 2) {
|
||||
/* Partial name given according to oid.*/
|
||||
u8_t tmplen = row_oid->len - engineid_len - 2;
|
||||
if (!snmp_oid_in_range(&row_oid->id[name_start], tmplen, usmUserTable_oid_ranges, tmplen)) {
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
} else {
|
||||
/* Full name given according to oid. Also test for too much data.*/
|
||||
u8_t tmplen = row_oid->len - engineid_len - 2;
|
||||
if (!snmp_oid_in_range(&row_oid->id[name_start], name_len, usmUserTable_oid_ranges, tmplen)) {
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
/* At this point the EngineID and (partial) UserName match the local EngineID and UserName.*/
|
||||
}
|
||||
}
|
||||
|
||||
/* init struct to search next oid */
|
||||
snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(usmUserTable_oid_ranges));
|
||||
|
||||
for (i = 0; i < snmpv3_get_amount_of_users(); i++) {
|
||||
u32_t test_oid[LWIP_ARRAYSIZE(usmUserTable_oid_ranges)];
|
||||
|
||||
test_oid[0] = eid_len;
|
||||
snmp_engineid_to_oid(engineid, &test_oid[1], eid_len);
|
||||
|
||||
snmpv3_get_username(username, i);
|
||||
|
||||
test_oid[1 + eid_len] = strlen(username);
|
||||
snmp_name_to_oid(username, &test_oid[2 + eid_len], strlen(username));
|
||||
|
||||
/* check generated OID: is it a candidate for the next one? */
|
||||
snmp_next_oid_check(&state, test_oid, (u8_t)(1 + eid_len + 1 + strlen(username)), LWIP_PTR_NUMERIC_CAST(void *, i));
|
||||
}
|
||||
|
||||
/* did we find a next one? */
|
||||
if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
|
||||
snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
|
||||
/* store username for subsequent operations (get/test/set) */
|
||||
memset(username, 0, sizeof(username));
|
||||
snmpv3_get_username(username, LWIP_PTR_NUMERIC_CAST(u8_t, state.reference));
|
||||
cell_instance->reference.ptr = username;
|
||||
cell_instance->reference_len = strlen(username);
|
||||
return SNMP_ERR_NOERROR;
|
||||
}
|
||||
|
||||
/* not found */
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
static s16_t usmusertable_get_value(struct snmp_node_instance *cell_instance, void *value)
|
||||
{
|
||||
snmpv3_user_storagetype_t storage_type;
|
||||
|
||||
switch (SNMP_TABLE_GET_COLUMN_FROM_OID(cell_instance->instance_oid.id)) {
|
||||
case 3: /* usmUserSecurityName */
|
||||
MEMCPY(value, cell_instance->reference.ptr, cell_instance->reference_len);
|
||||
return (s16_t)cell_instance->reference_len;
|
||||
case 4: /* usmUserCloneFrom */
|
||||
MEMCPY(value, snmp_zero_dot_zero.id, snmp_zero_dot_zero.len * sizeof(u32_t));
|
||||
return snmp_zero_dot_zero.len * sizeof(u32_t);
|
||||
case 5: { /* usmUserAuthProtocol */
|
||||
const struct snmp_obj_id *auth_algo;
|
||||
snmpv3_auth_algo_t auth_algo_val;
|
||||
snmpv3_get_user((const char *)cell_instance->reference.ptr, &auth_algo_val, NULL, NULL, NULL);
|
||||
auth_algo = snmp_auth_algo_to_oid(auth_algo_val);
|
||||
MEMCPY(value, auth_algo->id, auth_algo->len * sizeof(u32_t));
|
||||
return auth_algo->len * sizeof(u32_t);
|
||||
}
|
||||
case 6: /* usmUserAuthKeyChange */
|
||||
return 0;
|
||||
case 7: /* usmUserOwnAuthKeyChange */
|
||||
return 0;
|
||||
case 8: { /* usmUserPrivProtocol */
|
||||
const struct snmp_obj_id *priv_algo;
|
||||
snmpv3_priv_algo_t priv_algo_val;
|
||||
snmpv3_get_user((const char *)cell_instance->reference.ptr, NULL, NULL, &priv_algo_val, NULL);
|
||||
priv_algo = snmp_priv_algo_to_oid(priv_algo_val);
|
||||
MEMCPY(value, priv_algo->id, priv_algo->len * sizeof(u32_t));
|
||||
return priv_algo->len * sizeof(u32_t);
|
||||
}
|
||||
case 9: /* usmUserPrivKeyChange */
|
||||
return 0;
|
||||
case 10: /* usmUserOwnPrivKeyChange */
|
||||
return 0;
|
||||
case 11: /* usmUserPublic */
|
||||
/* TODO: Implement usmUserPublic */
|
||||
return 0;
|
||||
case 12: /* usmUserStorageType */
|
||||
snmpv3_get_user_storagetype((const char *)cell_instance->reference.ptr, &storage_type);
|
||||
*(s32_t *)value = storage_type;
|
||||
return sizeof(s32_t);
|
||||
case 13: /* usmUserStatus */
|
||||
*(s32_t *)value = 1; /* active */
|
||||
return sizeof(s32_t);
|
||||
default:
|
||||
LWIP_DEBUGF(SNMP_MIB_DEBUG, ("usmusertable_get_value(): unknown id: %"S32_F"\n", SNMP_TABLE_GET_COLUMN_FROM_OID(cell_instance->instance_oid.id)));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* --- usmMIBObjects 1.3.6.1.6.3.15.1 ----------------------------------------------------- */
|
||||
static s16_t usmstats_scalars_get_value(const struct snmp_scalar_array_node_def *node, void *value)
|
||||
{
|
||||
u32_t *uint_ptr = (u32_t *)value;
|
||||
switch (node->oid) {
|
||||
case 1: /* usmStatsUnsupportedSecLevels */
|
||||
*uint_ptr = snmp_stats.unsupportedseclevels;
|
||||
break;
|
||||
case 2: /* usmStatsNotInTimeWindows */
|
||||
*uint_ptr = snmp_stats.notintimewindows;
|
||||
break;
|
||||
case 3: /* usmStatsUnknownUserNames */
|
||||
*uint_ptr = snmp_stats.unknownusernames;
|
||||
break;
|
||||
case 4: /* usmStatsUnknownEngineIDs */
|
||||
*uint_ptr = snmp_stats.unknownengineids;
|
||||
break;
|
||||
case 5: /* usmStatsWrongDigests */
|
||||
*uint_ptr = snmp_stats.wrongdigests;
|
||||
break;
|
||||
case 6: /* usmStatsDecryptionErrors */
|
||||
*uint_ptr = snmp_stats.decryptionerrors;
|
||||
break;
|
||||
default:
|
||||
LWIP_DEBUGF(SNMP_MIB_DEBUG, ("usmstats_scalars_get_value(): unknown id: %"S32_F"\n", node->oid));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return sizeof(*uint_ptr);
|
||||
}
|
||||
|
||||
/* --- snmpUsmMIB ----------------------------------------------------- */
|
||||
|
||||
/* --- usmUser 1.3.6.1.6.3.15.1.2 ----------------------------------------------------- */
|
||||
|
||||
static const struct snmp_table_col_def usmusertable_columns[] = {
|
||||
{3, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY}, /* usmUserSecurityName */
|
||||
{4, SNMP_ASN1_TYPE_OBJECT_ID, SNMP_NODE_INSTANCE_READ_ONLY}, /* usmUserCloneFrom */
|
||||
{5, SNMP_ASN1_TYPE_OBJECT_ID, SNMP_NODE_INSTANCE_READ_ONLY}, /* usmUserAuthProtocol */
|
||||
{6, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY}, /* usmUserAuthKeyChange */
|
||||
{7, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY}, /* usmUserOwnAuthKeyChange */
|
||||
{8, SNMP_ASN1_TYPE_OBJECT_ID, SNMP_NODE_INSTANCE_READ_ONLY}, /* usmUserPrivProtocol */
|
||||
{9, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY}, /* usmUserPrivKeyChange */
|
||||
{10, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY}, /* usmUserOwnPrivKeyChange */
|
||||
{11, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY}, /* usmUserPublic */
|
||||
{12, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY}, /* usmUserStorageType */
|
||||
{13, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY}, /* usmUserStatus */
|
||||
};
|
||||
static const struct snmp_table_node usmusertable = SNMP_TABLE_CREATE(2, usmusertable_columns, usmusertable_get_instance, usmusertable_get_next_instance, usmusertable_get_value, NULL, NULL);
|
||||
|
||||
static const struct snmp_node *const usmuser_subnodes[] = {
|
||||
&usmusertable.node.node
|
||||
};
|
||||
static const struct snmp_tree_node usmuser_treenode = SNMP_CREATE_TREE_NODE(2, usmuser_subnodes);
|
||||
|
||||
/* --- usmMIBObjects 1.3.6.1.6.3.15.1 ----------------------------------------------------- */
|
||||
static const struct snmp_scalar_array_node_def usmstats_scalars_nodes[] = {
|
||||
{1, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* usmStatsUnsupportedSecLevels */
|
||||
{2, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* usmStatsNotInTimeWindows */
|
||||
{3, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* usmStatsUnknownUserNames */
|
||||
{4, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* usmStatsUnknownEngineIDs */
|
||||
{5, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* usmStatsWrongDigests */
|
||||
{6, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* usmStatsDecryptionErrors */
|
||||
};
|
||||
static const struct snmp_scalar_array_node usmstats_scalars = SNMP_SCALAR_CREATE_ARRAY_NODE(1, usmstats_scalars_nodes, usmstats_scalars_get_value, NULL, NULL);
|
||||
|
||||
static const struct snmp_node *const usmmibobjects_subnodes[] = {
|
||||
&usmstats_scalars.node.node,
|
||||
&usmuser_treenode.node
|
||||
};
|
||||
static const struct snmp_tree_node usmmibobjects_treenode = SNMP_CREATE_TREE_NODE(1, usmmibobjects_subnodes);
|
||||
|
||||
/* --- snmpUsmMIB ----------------------------------------------------- */
|
||||
static const struct snmp_node *const snmpusmmib_subnodes[] = {
|
||||
&usmmibobjects_treenode.node
|
||||
};
|
||||
static const struct snmp_tree_node snmpusmmib_root = SNMP_CREATE_TREE_NODE(15, snmpusmmib_subnodes);
|
||||
static const u32_t snmpusmmib_base_oid[] = {1, 3, 6, 1, 6, 3, 15};
|
||||
const struct snmp_mib snmpusmmib = {snmpusmmib_base_oid, LWIP_ARRAYSIZE(snmpusmmib_base_oid), &snmpusmmib_root.node};
|
||||
|
||||
#endif /* LWIP_SNMP */
|
||||
@@ -43,10 +43,10 @@
|
||||
#include "lwip/apps/snmp_table.h"
|
||||
#include <string.h>
|
||||
|
||||
snmp_err_t snmp_table_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
|
||||
snmp_err_t snmp_table_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance *instance)
|
||||
{
|
||||
snmp_err_t ret = SNMP_ERR_NOSUCHINSTANCE;
|
||||
const struct snmp_table_node* table_node = (const struct snmp_table_node*)(const void*)instance->node;
|
||||
const struct snmp_table_node *table_node = (const struct snmp_table_node *)(const void *)instance->node;
|
||||
|
||||
LWIP_UNUSED_ARG(root_oid);
|
||||
LWIP_UNUSED_ARG(root_oid_len);
|
||||
@@ -55,13 +55,13 @@ snmp_err_t snmp_table_get_instance(const u32_t *root_oid, u8_t root_oid_len, str
|
||||
/* fixed row entry always has oid 1 */
|
||||
if ((instance->instance_oid.len >= 3) && (instance->instance_oid.id[0] == 1)) {
|
||||
/* search column */
|
||||
const struct snmp_table_col_def* col_def = table_node->columns;
|
||||
const struct snmp_table_col_def *col_def = table_node->columns;
|
||||
u16_t i = table_node->column_count;
|
||||
while (i > 0) {
|
||||
if (col_def->index == instance->instance_oid.id[1]) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
col_def++;
|
||||
i--;
|
||||
}
|
||||
@@ -75,20 +75,20 @@ snmp_err_t snmp_table_get_instance(const u32_t *root_oid, u8_t root_oid_len, str
|
||||
instance->set_value = table_node->set_value;
|
||||
|
||||
ret = table_node->get_cell_instance(
|
||||
&(instance->instance_oid.id[1]),
|
||||
&(instance->instance_oid.id[2]),
|
||||
instance->instance_oid.len-2,
|
||||
instance);
|
||||
&(instance->instance_oid.id[1]),
|
||||
&(instance->instance_oid.id[2]),
|
||||
instance->instance_oid.len - 2,
|
||||
instance);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
snmp_err_t snmp_table_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
|
||||
snmp_err_t snmp_table_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance *instance)
|
||||
{
|
||||
const struct snmp_table_node* table_node = (const struct snmp_table_node*)(const void*)instance->node;
|
||||
const struct snmp_table_col_def* col_def;
|
||||
const struct snmp_table_node *table_node = (const struct snmp_table_node *)(const void *)instance->node;
|
||||
const struct snmp_table_col_def *col_def;
|
||||
struct snmp_obj_id row_oid;
|
||||
u32_t column = 0;
|
||||
snmp_err_t result;
|
||||
@@ -116,7 +116,7 @@ snmp_err_t snmp_table_get_next_instance(const u32_t *root_oid, u8_t root_oid_len
|
||||
/* resolve column and value */
|
||||
do {
|
||||
u16_t i;
|
||||
const struct snmp_table_col_def* next_col_def = NULL;
|
||||
const struct snmp_table_col_def *next_col_def = NULL;
|
||||
col_def = table_node->columns;
|
||||
|
||||
for (i = 0; i < table_node->column_count; i++) {
|
||||
@@ -138,9 +138,9 @@ snmp_err_t snmp_table_get_next_instance(const u32_t *root_oid, u8_t root_oid_len
|
||||
instance->access = next_col_def->access;
|
||||
|
||||
result = table_node->get_next_cell_instance(
|
||||
&next_col_def->index,
|
||||
&row_oid,
|
||||
instance);
|
||||
&next_col_def->index,
|
||||
&row_oid,
|
||||
instance);
|
||||
|
||||
if (result == SNMP_ERR_NOERROR) {
|
||||
col_def = next_col_def;
|
||||
@@ -161,10 +161,10 @@ snmp_err_t snmp_table_get_next_instance(const u32_t *root_oid, u8_t root_oid_len
|
||||
}
|
||||
|
||||
|
||||
snmp_err_t snmp_table_simple_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
|
||||
snmp_err_t snmp_table_simple_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance *instance)
|
||||
{
|
||||
snmp_err_t ret = SNMP_ERR_NOSUCHINSTANCE;
|
||||
const struct snmp_table_simple_node* table_node = (const struct snmp_table_simple_node*)(const void*)instance->node;
|
||||
const struct snmp_table_simple_node *table_node = (const struct snmp_table_simple_node *)(const void *)instance->node;
|
||||
|
||||
LWIP_UNUSED_ARG(root_oid);
|
||||
LWIP_UNUSED_ARG(root_oid_len);
|
||||
@@ -173,15 +173,15 @@ snmp_err_t snmp_table_simple_get_instance(const u32_t *root_oid, u8_t root_oid_l
|
||||
/* fixed row entry always has oid 1 */
|
||||
if ((instance->instance_oid.len >= 3) && (instance->instance_oid.id[0] == 1)) {
|
||||
ret = table_node->get_cell_value(
|
||||
&(instance->instance_oid.id[1]),
|
||||
&(instance->instance_oid.id[2]),
|
||||
instance->instance_oid.len-2,
|
||||
&instance->reference,
|
||||
&instance->reference_len);
|
||||
&(instance->instance_oid.id[1]),
|
||||
&(instance->instance_oid.id[2]),
|
||||
instance->instance_oid.len - 2,
|
||||
&instance->reference,
|
||||
&instance->reference_len);
|
||||
|
||||
if (ret == SNMP_ERR_NOERROR) {
|
||||
/* search column */
|
||||
const struct snmp_table_simple_col_def* col_def = table_node->columns;
|
||||
const struct snmp_table_simple_col_def *col_def = table_node->columns;
|
||||
u32_t i = table_node->column_count;
|
||||
while (i > 0) {
|
||||
if (col_def->index == instance->instance_oid.id[1]) {
|
||||
@@ -212,22 +212,22 @@ snmp_err_t snmp_table_simple_get_instance(const u32_t *root_oid, u8_t root_oid_l
|
||||
default:
|
||||
LWIP_DEBUGF(SNMP_DEBUG, ("snmp_table_simple_get_instance(): unknown column data_type: %d\n", col_def->data_type));
|
||||
return SNMP_ERR_GENERROR;
|
||||
}
|
||||
}
|
||||
|
||||
ret = SNMP_ERR_NOERROR;
|
||||
} else {
|
||||
ret = SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
snmp_err_t snmp_table_simple_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
|
||||
snmp_err_t snmp_table_simple_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance *instance)
|
||||
{
|
||||
const struct snmp_table_simple_node* table_node = (const struct snmp_table_simple_node*)(const void*)instance->node;
|
||||
const struct snmp_table_simple_col_def* col_def;
|
||||
const struct snmp_table_simple_node *table_node = (const struct snmp_table_simple_node *)(const void *)instance->node;
|
||||
const struct snmp_table_simple_col_def *col_def;
|
||||
struct snmp_obj_id row_oid;
|
||||
u32_t column = 0;
|
||||
snmp_err_t result;
|
||||
@@ -251,7 +251,7 @@ snmp_err_t snmp_table_simple_get_next_instance(const u32_t *root_oid, u8_t root_
|
||||
/* resolve column and value */
|
||||
do {
|
||||
u32_t i;
|
||||
const struct snmp_table_simple_col_def* next_col_def = NULL;
|
||||
const struct snmp_table_simple_col_def *next_col_def = NULL;
|
||||
col_def = table_node->columns;
|
||||
|
||||
for (i = 0; i < table_node->column_count; i++) {
|
||||
@@ -271,10 +271,10 @@ snmp_err_t snmp_table_simple_get_next_instance(const u32_t *root_oid, u8_t root_
|
||||
}
|
||||
|
||||
result = table_node->get_next_cell_instance_and_value(
|
||||
&next_col_def->index,
|
||||
&row_oid,
|
||||
&instance->reference,
|
||||
&instance->reference_len);
|
||||
&next_col_def->index,
|
||||
&row_oid,
|
||||
&instance->reference,
|
||||
&instance->reference_len);
|
||||
|
||||
if (result == SNMP_ERR_NOERROR) {
|
||||
col_def = next_col_def;
|
||||
@@ -283,8 +283,7 @@ snmp_err_t snmp_table_simple_get_next_instance(const u32_t *root_oid, u8_t root_
|
||||
|
||||
row_oid.len = 0; /* reset row_oid because we switch to next column and start with the first entry there */
|
||||
column = next_col_def->index + 1;
|
||||
}
|
||||
while (1);
|
||||
} while (1);
|
||||
|
||||
instance->asn1_type = col_def->asn1_type;
|
||||
instance->access = SNMP_NODE_INSTANCE_READ_ONLY;
|
||||
@@ -318,23 +317,23 @@ snmp_err_t snmp_table_simple_get_next_instance(const u32_t *root_oid, u8_t root_
|
||||
|
||||
|
||||
s16_t
|
||||
snmp_table_extract_value_from_s32ref(struct snmp_node_instance* instance, void* value)
|
||||
snmp_table_extract_value_from_s32ref(struct snmp_node_instance *instance, void *value)
|
||||
{
|
||||
s32_t *dst = (s32_t*)value;
|
||||
s32_t *dst = (s32_t *)value;
|
||||
*dst = instance->reference.s32;
|
||||
return sizeof(*dst);
|
||||
}
|
||||
|
||||
s16_t
|
||||
snmp_table_extract_value_from_u32ref(struct snmp_node_instance* instance, void* value)
|
||||
snmp_table_extract_value_from_u32ref(struct snmp_node_instance *instance, void *value)
|
||||
{
|
||||
u32_t *dst = (u32_t*)value;
|
||||
u32_t *dst = (u32_t *)value;
|
||||
*dst = instance->reference.u32;
|
||||
return sizeof(*dst);
|
||||
}
|
||||
|
||||
s16_t
|
||||
snmp_table_extract_value_from_refconstptr(struct snmp_node_instance* instance, void* value)
|
||||
snmp_table_extract_value_from_refconstptr(struct snmp_node_instance *instance, void *value)
|
||||
{
|
||||
MEMCPY(value, instance->reference.const_ptr, instance->reference_len);
|
||||
return (u16_t)instance->reference_len;
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
#include "lwip/apps/snmp_core.h"
|
||||
#include "lwip/sys.h"
|
||||
#include <string.h>
|
||||
|
||||
|
||||
static void
|
||||
call_synced_function(struct threadsync_data *call_data, snmp_threadsync_called_fn fn)
|
||||
{
|
||||
@@ -53,17 +53,21 @@ call_synced_function(struct threadsync_data *call_data, snmp_threadsync_called_f
|
||||
static void
|
||||
threadsync_get_value_synced(void *ctx)
|
||||
{
|
||||
struct threadsync_data *call_data = (struct threadsync_data*)ctx;
|
||||
struct threadsync_data *call_data = (struct threadsync_data *)ctx;
|
||||
|
||||
call_data->retval.s16 = call_data->proxy_instance.get_value(&call_data->proxy_instance, call_data->arg1.value);
|
||||
if (call_data->proxy_instance.get_value != NULL) {
|
||||
call_data->retval.s16 = call_data->proxy_instance.get_value(&call_data->proxy_instance, call_data->arg1.value);
|
||||
} else {
|
||||
call_data->retval.s16 = -1;
|
||||
}
|
||||
|
||||
sys_sem_signal(&call_data->threadsync_node->instance->sem);
|
||||
}
|
||||
|
||||
static s16_t
|
||||
threadsync_get_value(struct snmp_node_instance* instance, void* value)
|
||||
threadsync_get_value(struct snmp_node_instance *instance, void *value)
|
||||
{
|
||||
struct threadsync_data *call_data = (struct threadsync_data*)instance->reference.ptr;
|
||||
struct threadsync_data *call_data = (struct threadsync_data *)instance->reference.ptr;
|
||||
|
||||
call_data->arg1.value = value;
|
||||
call_synced_function(call_data, threadsync_get_value_synced);
|
||||
@@ -74,17 +78,21 @@ threadsync_get_value(struct snmp_node_instance* instance, void* value)
|
||||
static void
|
||||
threadsync_set_test_synced(void *ctx)
|
||||
{
|
||||
struct threadsync_data *call_data = (struct threadsync_data*)ctx;
|
||||
struct threadsync_data *call_data = (struct threadsync_data *)ctx;
|
||||
|
||||
call_data->retval.err = call_data->proxy_instance.set_test(&call_data->proxy_instance, call_data->arg2.len, call_data->arg1.value);
|
||||
if (call_data->proxy_instance.set_test != NULL) {
|
||||
call_data->retval.err = call_data->proxy_instance.set_test(&call_data->proxy_instance, call_data->arg2.len, call_data->arg1.value);
|
||||
} else {
|
||||
call_data->retval.err = SNMP_ERR_NOTWRITABLE;
|
||||
}
|
||||
|
||||
sys_sem_signal(&call_data->threadsync_node->instance->sem);
|
||||
}
|
||||
|
||||
static snmp_err_t
|
||||
threadsync_set_test(struct snmp_node_instance* instance, u16_t len, void *value)
|
||||
threadsync_set_test(struct snmp_node_instance *instance, u16_t len, void *value)
|
||||
{
|
||||
struct threadsync_data *call_data = (struct threadsync_data*)instance->reference.ptr;
|
||||
struct threadsync_data *call_data = (struct threadsync_data *)instance->reference.ptr;
|
||||
|
||||
call_data->arg1.value = value;
|
||||
call_data->arg2.len = len;
|
||||
@@ -96,30 +104,34 @@ threadsync_set_test(struct snmp_node_instance* instance, u16_t len, void *value)
|
||||
static void
|
||||
threadsync_set_value_synced(void *ctx)
|
||||
{
|
||||
struct threadsync_data *call_data = (struct threadsync_data*)ctx;
|
||||
struct threadsync_data *call_data = (struct threadsync_data *)ctx;
|
||||
|
||||
call_data->retval.err = call_data->proxy_instance.set_value(&call_data->proxy_instance, call_data->arg2.len, call_data->arg1.value);
|
||||
if (call_data->proxy_instance.set_value != NULL) {
|
||||
call_data->retval.err = call_data->proxy_instance.set_value(&call_data->proxy_instance, call_data->arg2.len, call_data->arg1.value);
|
||||
} else {
|
||||
call_data->retval.err = SNMP_ERR_NOTWRITABLE;
|
||||
}
|
||||
|
||||
sys_sem_signal(&call_data->threadsync_node->instance->sem);
|
||||
}
|
||||
|
||||
static snmp_err_t
|
||||
threadsync_set_value(struct snmp_node_instance* instance, u16_t len, void *value)
|
||||
threadsync_set_value(struct snmp_node_instance *instance, u16_t len, void *value)
|
||||
{
|
||||
struct threadsync_data *call_data = (struct threadsync_data*)instance->reference.ptr;
|
||||
struct threadsync_data *call_data = (struct threadsync_data *)instance->reference.ptr;
|
||||
|
||||
call_data->arg1.value = value;
|
||||
call_data->arg2.len = len;
|
||||
call_synced_function(call_data, threadsync_set_value_synced);
|
||||
|
||||
|
||||
return call_data->retval.err;
|
||||
}
|
||||
|
||||
static void
|
||||
threadsync_release_instance_synced(void* ctx)
|
||||
threadsync_release_instance_synced(void *ctx)
|
||||
{
|
||||
struct threadsync_data *call_data = (struct threadsync_data*)ctx;
|
||||
|
||||
struct threadsync_data *call_data = (struct threadsync_data *)ctx;
|
||||
|
||||
call_data->proxy_instance.release_instance(&call_data->proxy_instance);
|
||||
|
||||
sys_sem_signal(&call_data->threadsync_node->instance->sem);
|
||||
@@ -128,18 +140,18 @@ threadsync_release_instance_synced(void* ctx)
|
||||
static void
|
||||
threadsync_release_instance(struct snmp_node_instance *instance)
|
||||
{
|
||||
struct threadsync_data *call_data = (struct threadsync_data*)instance->reference.ptr;
|
||||
|
||||
struct threadsync_data *call_data = (struct threadsync_data *)instance->reference.ptr;
|
||||
|
||||
if (call_data->proxy_instance.release_instance != NULL) {
|
||||
call_synced_function(call_data, threadsync_release_instance_synced);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
get_instance_synced(void* ctx)
|
||||
get_instance_synced(void *ctx)
|
||||
{
|
||||
struct threadsync_data *call_data = (struct threadsync_data*)ctx;
|
||||
const struct snmp_leaf_node *leaf = (const struct snmp_leaf_node*)(const void*)call_data->proxy_instance.node;
|
||||
struct threadsync_data *call_data = (struct threadsync_data *)ctx;
|
||||
const struct snmp_leaf_node *leaf = (const struct snmp_leaf_node *)(const void *)call_data->proxy_instance.node;
|
||||
|
||||
call_data->retval.err = leaf->get_instance(call_data->arg1.root_oid, call_data->arg2.root_oid_len, &call_data->proxy_instance);
|
||||
|
||||
@@ -147,10 +159,10 @@ get_instance_synced(void* ctx)
|
||||
}
|
||||
|
||||
static void
|
||||
get_next_instance_synced(void* ctx)
|
||||
get_next_instance_synced(void *ctx)
|
||||
{
|
||||
struct threadsync_data *call_data = (struct threadsync_data*)ctx;
|
||||
const struct snmp_leaf_node *leaf = (const struct snmp_leaf_node*)(const void*)call_data->proxy_instance.node;
|
||||
struct threadsync_data *call_data = (struct threadsync_data *)ctx;
|
||||
const struct snmp_leaf_node *leaf = (const struct snmp_leaf_node *)(const void *)call_data->proxy_instance.node;
|
||||
|
||||
call_data->retval.err = leaf->get_next_instance(call_data->arg1.root_oid, call_data->arg2.root_oid_len, &call_data->proxy_instance);
|
||||
|
||||
@@ -158,9 +170,9 @@ get_next_instance_synced(void* ctx)
|
||||
}
|
||||
|
||||
static snmp_err_t
|
||||
do_sync(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance, snmp_threadsync_called_fn fn)
|
||||
do_sync(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance *instance, snmp_threadsync_called_fn fn)
|
||||
{
|
||||
const struct snmp_threadsync_node *threadsync_node = (const struct snmp_threadsync_node*)(const void*)instance->node;
|
||||
const struct snmp_threadsync_node *threadsync_node = (const struct snmp_threadsync_node *)(const void *)instance->node;
|
||||
struct threadsync_data *call_data = &threadsync_node->instance->data;
|
||||
|
||||
if (threadsync_node->node.node.oid != threadsync_node->target->node.oid) {
|
||||
@@ -184,9 +196,9 @@ do_sync(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* ins
|
||||
instance->access = call_data->proxy_instance.access;
|
||||
instance->asn1_type = call_data->proxy_instance.asn1_type;
|
||||
instance->release_instance = threadsync_release_instance;
|
||||
instance->get_value = (call_data->proxy_instance.get_value != NULL)? threadsync_get_value : NULL;
|
||||
instance->set_value = (call_data->proxy_instance.set_value != NULL)? threadsync_set_value : NULL;
|
||||
instance->set_test = (call_data->proxy_instance.set_test != NULL)? threadsync_set_test : NULL;
|
||||
instance->get_value = (call_data->proxy_instance.get_value != NULL) ? threadsync_get_value : NULL;
|
||||
instance->set_value = (call_data->proxy_instance.set_value != NULL) ? threadsync_set_value : NULL;
|
||||
instance->set_test = (call_data->proxy_instance.set_test != NULL) ? threadsync_set_test : NULL;
|
||||
snmp_oid_assign(&instance->instance_oid, call_data->proxy_instance.instance_oid.id, call_data->proxy_instance.instance_oid.len);
|
||||
}
|
||||
|
||||
@@ -194,13 +206,13 @@ do_sync(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* ins
|
||||
}
|
||||
|
||||
snmp_err_t
|
||||
snmp_threadsync_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
|
||||
snmp_threadsync_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance *instance)
|
||||
{
|
||||
return do_sync(root_oid, root_oid_len, instance, get_instance_synced);
|
||||
}
|
||||
|
||||
snmp_err_t
|
||||
snmp_threadsync_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
|
||||
snmp_threadsync_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance *instance)
|
||||
{
|
||||
return do_sync(root_oid, root_oid_len, instance, get_next_instance_synced);
|
||||
}
|
||||
@@ -211,6 +223,7 @@ void snmp_threadsync_init(struct snmp_threadsync_instance *instance, snmp_thread
|
||||
err_t err = sys_mutex_new(&instance->sem_usage_mutex);
|
||||
LWIP_ASSERT("Failed to set up mutex", err == ERR_OK);
|
||||
err = sys_sem_new(&instance->sem, 0);
|
||||
LWIP_UNUSED_ARG(err); /* in case of LWIP_NOASSERT */
|
||||
LWIP_ASSERT("Failed to set up semaphore", err == ERR_OK);
|
||||
instance->sync_fn = sync_fn;
|
||||
}
|
||||
|
||||
@@ -46,12 +46,12 @@
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/apps/snmp.h"
|
||||
#include "lwip/apps/snmp_core.h"
|
||||
#include "lwip/prot/iana.h"
|
||||
#include "snmp_msg.h"
|
||||
#include "snmp_asn1.h"
|
||||
#include "snmp_core_priv.h"
|
||||
|
||||
struct snmp_msg_trap
|
||||
{
|
||||
struct snmp_msg_trap {
|
||||
/* source enterprise ID (sysObjectID) */
|
||||
const struct snmp_obj_id *enterprise;
|
||||
/* source IP address, raw network order format */
|
||||
@@ -78,16 +78,21 @@ struct snmp_msg_trap
|
||||
|
||||
static u16_t snmp_trap_varbind_sum(struct snmp_msg_trap *trap, struct snmp_varbind *varbinds);
|
||||
static u16_t snmp_trap_header_sum(struct snmp_msg_trap *trap, u16_t vb_len);
|
||||
static void snmp_trap_header_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream);
|
||||
static void snmp_trap_varbind_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind *varbinds);
|
||||
static err_t snmp_trap_header_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream);
|
||||
static err_t snmp_trap_varbind_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind *varbinds);
|
||||
|
||||
#define BUILD_EXEC(code) \
|
||||
if ((code) != ERR_OK) { \
|
||||
LWIP_DEBUGF(SNMP_DEBUG, ("SNMP error during creation of outbound trap frame!")); \
|
||||
return ERR_ARG; \
|
||||
}
|
||||
|
||||
/** Agent community string for sending traps */
|
||||
extern const char *snmp_community_trap;
|
||||
|
||||
void* snmp_traps_handle;
|
||||
void *snmp_traps_handle;
|
||||
|
||||
struct snmp_trap_dst
|
||||
{
|
||||
struct snmp_trap_dst {
|
||||
/* destination IP address in network order */
|
||||
ip_addr_t dip;
|
||||
/* set to 0 when disabled, >0 when enabled */
|
||||
@@ -106,6 +111,7 @@ static u8_t snmp_auth_traps_enabled = 0;
|
||||
void
|
||||
snmp_trap_dst_enable(u8_t dst_idx, u8_t enable)
|
||||
{
|
||||
LWIP_ASSERT_CORE_LOCKED();
|
||||
if (dst_idx < SNMP_TRAP_DESTINATIONS) {
|
||||
trap_dst[dst_idx].enable = enable;
|
||||
}
|
||||
@@ -120,6 +126,7 @@ snmp_trap_dst_enable(u8_t dst_idx, u8_t enable)
|
||||
void
|
||||
snmp_trap_dst_ip_set(u8_t dst_idx, const ip_addr_t *dst)
|
||||
{
|
||||
LWIP_ASSERT_CORE_LOCKED();
|
||||
if (dst_idx < SNMP_TRAP_DESTINATIONS) {
|
||||
ip_addr_set(&trap_dst[dst_idx].dip, dst);
|
||||
}
|
||||
@@ -163,7 +170,7 @@ snmp_get_auth_traps_enabled(void)
|
||||
* (sysObjectID) for specific traps.
|
||||
*/
|
||||
err_t
|
||||
snmp_send_trap(const struct snmp_obj_id* eoid, s32_t generic_trap, s32_t specific_trap, struct snmp_varbind *varbinds)
|
||||
snmp_send_trap(const struct snmp_obj_id *eoid, s32_t generic_trap, s32_t specific_trap, struct snmp_varbind *varbinds)
|
||||
{
|
||||
struct snmp_msg_trap trap_msg;
|
||||
struct snmp_trap_dst *td;
|
||||
@@ -171,6 +178,8 @@ snmp_send_trap(const struct snmp_obj_id* eoid, s32_t generic_trap, s32_t specifi
|
||||
u16_t i, tot_len;
|
||||
err_t err = ERR_OK;
|
||||
|
||||
LWIP_ASSERT_CORE_LOCKED();
|
||||
|
||||
trap_msg.snmp_version = 0;
|
||||
|
||||
for (i = 0, td = &trap_dst[0]; i < SNMP_TRAP_DESTINATIONS; i++, td++) {
|
||||
@@ -202,7 +211,7 @@ snmp_send_trap(const struct snmp_obj_id* eoid, s32_t generic_trap, s32_t specifi
|
||||
struct snmp_pbuf_stream pbuf_stream;
|
||||
snmp_pbuf_stream_init(&pbuf_stream, p, 0, tot_len);
|
||||
|
||||
/* pass 1, encode packet ino the pbuf(s) */
|
||||
/* pass 1, encode packet into the pbuf(s) */
|
||||
snmp_trap_header_enc(&trap_msg, &pbuf_stream);
|
||||
snmp_trap_varbind_enc(&trap_msg, &pbuf_stream, varbinds);
|
||||
|
||||
@@ -210,7 +219,7 @@ snmp_send_trap(const struct snmp_obj_id* eoid, s32_t generic_trap, s32_t specifi
|
||||
snmp_stats.outpkts++;
|
||||
|
||||
/** send to the TRAP destination */
|
||||
snmp_sendto(snmp_traps_handle, p, &td->dip, SNMP_TRAP_PORT);
|
||||
snmp_sendto(snmp_traps_handle, p, &td->dip, LWIP_IANA_PORT_SNMP_TRAP);
|
||||
pbuf_free(p);
|
||||
} else {
|
||||
err = ERR_MEM;
|
||||
@@ -228,7 +237,7 @@ snmp_send_trap(const struct snmp_obj_id* eoid, s32_t generic_trap, s32_t specifi
|
||||
* @ingroup snmp_traps
|
||||
* Send generic SNMP trap
|
||||
*/
|
||||
err_t
|
||||
err_t
|
||||
snmp_send_trap_generic(s32_t generic_trap)
|
||||
{
|
||||
static const struct snmp_obj_id oid = { 7, { 1, 3, 6, 1, 2, 1, 11 } };
|
||||
@@ -257,7 +266,7 @@ snmp_coldstart_trap(void)
|
||||
|
||||
/**
|
||||
* @ingroup snmp_traps
|
||||
* Send authentication failure trap (used internally by agent)
|
||||
* Send authentication failure trap (used internally by agent)
|
||||
*/
|
||||
void
|
||||
snmp_authfail_trap(void)
|
||||
@@ -357,7 +366,7 @@ snmp_trap_header_sum(struct snmp_msg_trap *trap, u16_t vb_len)
|
||||
return tot_len;
|
||||
}
|
||||
|
||||
static void
|
||||
static err_t
|
||||
snmp_trap_varbind_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind *varbinds)
|
||||
{
|
||||
struct snmp_asn1_tlv tlv;
|
||||
@@ -366,80 +375,84 @@ snmp_trap_varbind_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_
|
||||
varbind = varbinds;
|
||||
|
||||
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 0, trap->vbseqlen);
|
||||
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
|
||||
BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
|
||||
|
||||
while (varbind != NULL) {
|
||||
snmp_append_outbound_varbind(pbuf_stream, varbind);
|
||||
BUILD_EXEC( snmp_append_outbound_varbind(pbuf_stream, varbind) );
|
||||
|
||||
varbind = varbind->next;
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes trap header from head to tail.
|
||||
*/
|
||||
static void
|
||||
static err_t
|
||||
snmp_trap_header_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream)
|
||||
{
|
||||
struct snmp_asn1_tlv tlv;
|
||||
|
||||
/* 'Message' sequence */
|
||||
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 0, trap->seqlen);
|
||||
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
|
||||
BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
|
||||
|
||||
/* version */
|
||||
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
|
||||
snmp_asn1_enc_s32t_cnt(trap->snmp_version, &tlv.value_len);
|
||||
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
|
||||
snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->snmp_version);
|
||||
BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
|
||||
BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->snmp_version) );
|
||||
|
||||
/* community */
|
||||
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, trap->comlen);
|
||||
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
|
||||
snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)snmp_community_trap, trap->comlen);
|
||||
BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
|
||||
BUILD_EXEC( snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)snmp_community_trap, trap->comlen) );
|
||||
|
||||
/* 'PDU' sequence */
|
||||
SNMP_ASN1_SET_TLV_PARAMS(tlv, (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_TRAP), 0, trap->pdulen);
|
||||
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
|
||||
BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
|
||||
|
||||
/* object ID */
|
||||
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OBJECT_ID, 0, 0);
|
||||
snmp_asn1_enc_oid_cnt(trap->enterprise->id, trap->enterprise->len, &tlv.value_len);
|
||||
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
|
||||
snmp_asn1_enc_oid(pbuf_stream, trap->enterprise->id, trap->enterprise->len);
|
||||
BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
|
||||
BUILD_EXEC( snmp_asn1_enc_oid(pbuf_stream, trap->enterprise->id, trap->enterprise->len) );
|
||||
|
||||
/* IP addr */
|
||||
if (IP_IS_V6_VAL(trap->sip)) {
|
||||
#if LWIP_IPV6
|
||||
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_IPADDR, 0, sizeof(ip_2_ip6(&trap->sip)->addr));
|
||||
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
|
||||
snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)&ip_2_ip6(&trap->sip)->addr, sizeof(ip_2_ip6(&trap->sip)->addr));
|
||||
BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
|
||||
BUILD_EXEC( snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)&ip_2_ip6(&trap->sip)->addr, sizeof(ip_2_ip6(&trap->sip)->addr)) );
|
||||
#endif
|
||||
} else {
|
||||
#if LWIP_IPV4
|
||||
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_IPADDR, 0, sizeof(ip_2_ip4(&trap->sip)->addr));
|
||||
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
|
||||
snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)&ip_2_ip4(&trap->sip)->addr, sizeof(ip_2_ip4(&trap->sip)->addr));
|
||||
BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
|
||||
BUILD_EXEC( snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)&ip_2_ip4(&trap->sip)->addr, sizeof(ip_2_ip4(&trap->sip)->addr)) );
|
||||
#endif
|
||||
}
|
||||
|
||||
/* trap length */
|
||||
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
|
||||
snmp_asn1_enc_s32t_cnt(trap->gen_trap, &tlv.value_len);
|
||||
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
|
||||
snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->gen_trap);
|
||||
BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
|
||||
BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->gen_trap) );
|
||||
|
||||
/* specific trap */
|
||||
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
|
||||
snmp_asn1_enc_s32t_cnt(trap->spc_trap, &tlv.value_len);
|
||||
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
|
||||
snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->spc_trap);
|
||||
BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
|
||||
BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->spc_trap) );
|
||||
|
||||
/* timestamp */
|
||||
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_TIMETICKS, 0, 0);
|
||||
snmp_asn1_enc_s32t_cnt(trap->ts, &tlv.value_len);
|
||||
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
|
||||
snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->ts);
|
||||
BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
|
||||
BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->ts) );
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
#endif /* LWIP_SNMP */
|
||||
|
||||
@@ -58,7 +58,7 @@ snmpv3_engine_id_changed(void)
|
||||
* (re-)initialized itself since snmpEngineID
|
||||
* was last configured.
|
||||
*/
|
||||
u32_t
|
||||
s32_t
|
||||
snmpv3_get_engine_boots_internal(void)
|
||||
{
|
||||
if (snmpv3_get_engine_boots() == 0 ||
|
||||
@@ -75,7 +75,7 @@ snmpv3_get_engine_boots_internal(void)
|
||||
* Once the timer reaches 2147483647 it gets reset to zero and the
|
||||
* engine boot ups get incremented.
|
||||
*/
|
||||
u32_t
|
||||
s32_t
|
||||
snmpv3_get_engine_time_internal(void)
|
||||
{
|
||||
if (snmpv3_get_engine_time() >= SNMP_MAX_TIME_BOOT) {
|
||||
@@ -101,7 +101,7 @@ snmpv3_get_engine_time_internal(void)
|
||||
* @todo: This is a potential thread safety issue.
|
||||
*/
|
||||
err_t
|
||||
snmpv3_build_priv_param(u8_t* priv_param)
|
||||
snmpv3_build_priv_param(u8_t *priv_param)
|
||||
{
|
||||
#ifdef LWIP_RAND /* Based on RFC3826 */
|
||||
static u8_t init;
|
||||
@@ -124,7 +124,7 @@ snmpv3_build_priv_param(u8_t* priv_param)
|
||||
}
|
||||
#else /* Based on RFC3414 */
|
||||
static u32_t ctr;
|
||||
u32_t boots = LWIP_SNMPV3_GET_ENGINE_BOOTS();
|
||||
u32_t boots = snmpv3_get_engine_boots_internal();
|
||||
SMEMCPY(&priv_param[0], &boots, 4);
|
||||
SMEMCPY(&priv_param[4], &ctr, 4);
|
||||
ctr++;
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
/**
|
||||
* @file
|
||||
* Dummy SNMPv3 functions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2016 Elias Oenal.
|
||||
* 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. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
||||
*
|
||||
* Author: Elias Oenal <lwip@eliasoenal.com>
|
||||
* Dirk Ziegelmeier <dirk@ziegelmeier.net>
|
||||
*/
|
||||
|
||||
#include "lwip/apps/snmpv3.h"
|
||||
#include "snmpv3_priv.h"
|
||||
#include <string.h>
|
||||
#include "lwip/err.h"
|
||||
|
||||
#if LWIP_SNMP && LWIP_SNMP_V3
|
||||
|
||||
/**
|
||||
* @param username is a pointer to a string.
|
||||
* @param auth_algo is a pointer to u8_t. The implementation has to set this if user was found.
|
||||
* @param auth_key is a pointer to a pointer to a string. Implementation has to set this if user was found.
|
||||
* @param priv_algo is a pointer to u8_t. The implementation has to set this if user was found.
|
||||
* @param priv_key is a pointer to a pointer to a string. Implementation has to set this if user was found.
|
||||
*/
|
||||
err_t
|
||||
snmpv3_get_user(const char* username, u8_t *auth_algo, u8_t *auth_key, u8_t *priv_algo, u8_t *priv_key)
|
||||
{
|
||||
const char* engine_id;
|
||||
u8_t engine_id_len;
|
||||
|
||||
if(strlen(username) == 0) {
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
if(memcmp(username, "lwip", 4) != 0) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
snmpv3_get_engine_id(&engine_id, &engine_id_len);
|
||||
|
||||
if(auth_key != NULL) {
|
||||
snmpv3_password_to_key_sha((const u8_t*)"maplesyrup", 10,
|
||||
(const u8_t*)engine_id, engine_id_len,
|
||||
auth_key);
|
||||
*auth_algo = SNMP_V3_AUTH_ALGO_SHA;
|
||||
}
|
||||
if(priv_key != NULL) {
|
||||
snmpv3_password_to_key_sha((const u8_t*)"maplesyrup", 10,
|
||||
(const u8_t*)engine_id, engine_id_len,
|
||||
priv_key);
|
||||
*priv_algo = SNMP_V3_PRIV_ALGO_DES;
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get engine ID from persistence
|
||||
* @param id
|
||||
* @param len
|
||||
*/
|
||||
void
|
||||
snmpv3_get_engine_id(const char **id, u8_t *len)
|
||||
{
|
||||
*id = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02";
|
||||
*len = 12;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store engine ID in persistence
|
||||
* @param id
|
||||
* @param len
|
||||
*/
|
||||
err_t
|
||||
snmpv3_set_engine_id(const char *id, u8_t len)
|
||||
{
|
||||
LWIP_UNUSED_ARG(id);
|
||||
LWIP_UNUSED_ARG(len);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get engine boots from persistence. Must be increased on each boot.
|
||||
* @return
|
||||
*/
|
||||
u32_t
|
||||
snmpv3_get_engine_boots(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store engine boots in persistence
|
||||
* @param boots
|
||||
*/
|
||||
void
|
||||
snmpv3_set_engine_boots(u32_t boots)
|
||||
{
|
||||
LWIP_UNUSED_ARG(boots);
|
||||
}
|
||||
|
||||
/**
|
||||
* RFC3414 2.2.2.
|
||||
* Once the timer reaches 2147483647 it gets reset to zero and the
|
||||
* engine boot ups get incremented.
|
||||
*/
|
||||
u32_t
|
||||
snmpv3_get_engine_time(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset current engine time to 0
|
||||
*/
|
||||
void
|
||||
snmpv3_reset_engine_time(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* LWIP_SNMP && LWIP_SNMP_V3 */
|
||||
@@ -49,8 +49,8 @@
|
||||
#include "mbedtls/sha1.h"
|
||||
|
||||
err_t
|
||||
snmpv3_auth(struct snmp_pbuf_stream* stream, u16_t length,
|
||||
const u8_t* key, u8_t algo, u8_t* hmac_out)
|
||||
snmpv3_auth(struct snmp_pbuf_stream *stream, u16_t length,
|
||||
const u8_t *key, snmpv3_auth_algo_t algo, u8_t *hmac_out)
|
||||
{
|
||||
u32_t i;
|
||||
u8_t key_len;
|
||||
@@ -70,10 +70,10 @@ snmpv3_auth(struct snmp_pbuf_stream* stream, u16_t length,
|
||||
}
|
||||
|
||||
mbedtls_md_init(&ctx);
|
||||
if(mbedtls_md_setup(&ctx, md_info, 1) != 0) {
|
||||
if (mbedtls_md_setup(&ctx, md_info, 1) != 0) {
|
||||
return ERR_ARG;
|
||||
}
|
||||
|
||||
|
||||
if (mbedtls_md_hmac_starts(&ctx, key, key_len) != 0) {
|
||||
goto free_md;
|
||||
}
|
||||
@@ -96,7 +96,7 @@ snmpv3_auth(struct snmp_pbuf_stream* stream, u16_t length,
|
||||
|
||||
mbedtls_md_free(&ctx);
|
||||
return ERR_OK;
|
||||
|
||||
|
||||
free_md:
|
||||
mbedtls_md_free(&ctx);
|
||||
return ERR_ARG;
|
||||
@@ -105,9 +105,9 @@ free_md:
|
||||
#if LWIP_SNMP_V3_CRYPTO
|
||||
|
||||
err_t
|
||||
snmpv3_crypt(struct snmp_pbuf_stream* stream, u16_t length,
|
||||
const u8_t* key, const u8_t* priv_param, const u32_t engine_boots,
|
||||
const u32_t engine_time, u8_t algo, u8_t mode)
|
||||
snmpv3_crypt(struct snmp_pbuf_stream *stream, u16_t length,
|
||||
const u8_t *key, const u8_t *priv_param, const u32_t engine_boots,
|
||||
const u32_t engine_time, snmpv3_priv_algo_t algo, snmpv3_priv_mode_t mode)
|
||||
{
|
||||
size_t i;
|
||||
mbedtls_cipher_context_t ctx;
|
||||
@@ -130,21 +130,21 @@ snmpv3_crypt(struct snmp_pbuf_stream* stream, u16_t length,
|
||||
}
|
||||
|
||||
cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_DES_CBC);
|
||||
if(mbedtls_cipher_setup(&ctx, cipher_info) != 0) {
|
||||
if (mbedtls_cipher_setup(&ctx, cipher_info) != 0) {
|
||||
return ERR_ARG;
|
||||
}
|
||||
if(mbedtls_cipher_set_padding_mode(&ctx, MBEDTLS_PADDING_NONE) != 0) {
|
||||
if (mbedtls_cipher_set_padding_mode(&ctx, MBEDTLS_PADDING_NONE) != 0) {
|
||||
return ERR_ARG;
|
||||
}
|
||||
if(mbedtls_cipher_setkey(&ctx, key, 8*8, (mode == SNMP_V3_PRIV_MODE_ENCRYPT)? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT) != 0) {
|
||||
if (mbedtls_cipher_setkey(&ctx, key, 8 * 8, (mode == SNMP_V3_PRIV_MODE_ENCRYPT) ? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT) != 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Prepare IV */
|
||||
/* Prepare IV */
|
||||
for (i = 0; i < LWIP_ARRAYSIZE(iv_local); i++) {
|
||||
iv_local[i] = priv_param[i] ^ key[i + 8];
|
||||
}
|
||||
if(mbedtls_cipher_set_iv(&ctx, iv_local, LWIP_ARRAYSIZE(iv_local)) != 0) {
|
||||
if (mbedtls_cipher_set_iv(&ctx, iv_local, LWIP_ARRAYSIZE(iv_local)) != 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -152,31 +152,38 @@ snmpv3_crypt(struct snmp_pbuf_stream* stream, u16_t length,
|
||||
size_t j;
|
||||
u8_t in_bytes[8];
|
||||
out_len = LWIP_ARRAYSIZE(out_bytes) ;
|
||||
|
||||
|
||||
for (j = 0; j < LWIP_ARRAYSIZE(in_bytes); j++) {
|
||||
snmp_pbuf_stream_read(&read_stream, &in_bytes[j]);
|
||||
if (snmp_pbuf_stream_read(&read_stream, &in_bytes[j]) != ERR_OK) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if(mbedtls_cipher_update(&ctx, in_bytes, LWIP_ARRAYSIZE(in_bytes), out_bytes, &out_len) != 0) {
|
||||
if (mbedtls_cipher_update(&ctx, in_bytes, LWIP_ARRAYSIZE(in_bytes), out_bytes, &out_len) != 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
snmp_pbuf_stream_writebuf(&write_stream, out_bytes, out_len);
|
||||
if (snmp_pbuf_stream_writebuf(&write_stream, out_bytes, (u16_t)out_len) != ERR_OK) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
out_len = LWIP_ARRAYSIZE(out_bytes);
|
||||
if(mbedtls_cipher_finish(&ctx, out_bytes, &out_len) != 0) {
|
||||
if (mbedtls_cipher_finish(&ctx, out_bytes, &out_len) != 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (snmp_pbuf_stream_writebuf(&write_stream, out_bytes, (u16_t)out_len) != ERR_OK) {
|
||||
goto error;
|
||||
}
|
||||
snmp_pbuf_stream_writebuf(&write_stream, out_bytes, out_len);
|
||||
} else if (algo == SNMP_V3_PRIV_ALGO_AES) {
|
||||
u8_t iv_local[16];
|
||||
|
||||
cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_CFB128);
|
||||
if(mbedtls_cipher_setup(&ctx, cipher_info) != 0) {
|
||||
if (mbedtls_cipher_setup(&ctx, cipher_info) != 0) {
|
||||
return ERR_ARG;
|
||||
}
|
||||
if(mbedtls_cipher_setkey(&ctx, key, 16*8, (mode == SNMP_V3_PRIV_MODE_ENCRYPT)? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT) != 0) {
|
||||
if (mbedtls_cipher_setkey(&ctx, key, 16 * 8, (mode == SNMP_V3_PRIV_MODE_ENCRYPT) ? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT) != 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -193,7 +200,7 @@ snmpv3_crypt(struct snmp_pbuf_stream* stream, u16_t length,
|
||||
iv_local[4 + 2] = (engine_time >> 8) & 0xFF;
|
||||
iv_local[4 + 3] = (engine_time >> 0) & 0xFF;
|
||||
SMEMCPY(iv_local + 8, priv_param, 8);
|
||||
if(mbedtls_cipher_set_iv(&ctx, iv_local, LWIP_ARRAYSIZE(iv_local)) != 0) {
|
||||
if (mbedtls_cipher_set_iv(&ctx, iv_local, LWIP_ARRAYSIZE(iv_local)) != 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -201,12 +208,16 @@ snmpv3_crypt(struct snmp_pbuf_stream* stream, u16_t length,
|
||||
u8_t in_byte;
|
||||
u8_t out_byte;
|
||||
size_t out_len = sizeof(out_byte);
|
||||
|
||||
snmp_pbuf_stream_read(&read_stream, &in_byte);
|
||||
if(mbedtls_cipher_update(&ctx, &in_byte, sizeof(in_byte), &out_byte, &out_len) != 0) {
|
||||
|
||||
if (snmp_pbuf_stream_read(&read_stream, &in_byte) != ERR_OK) {
|
||||
goto error;
|
||||
}
|
||||
if (mbedtls_cipher_update(&ctx, &in_byte, sizeof(in_byte), &out_byte, &out_len) != 0) {
|
||||
goto error;
|
||||
}
|
||||
if (snmp_pbuf_stream_write(&write_stream, out_byte) != ERR_OK) {
|
||||
goto error;
|
||||
}
|
||||
snmp_pbuf_stream_write(&write_stream, out_byte);
|
||||
}
|
||||
} else {
|
||||
return ERR_ARG;
|
||||
@@ -223,13 +234,13 @@ error:
|
||||
#endif /* LWIP_SNMP_V3_CRYPTO */
|
||||
|
||||
/* A.2.1. Password to Key Sample Code for MD5 */
|
||||
void
|
||||
void
|
||||
snmpv3_password_to_key_md5(
|
||||
const u8_t *password, /* IN */
|
||||
u8_t passwordlen, /* IN */
|
||||
const u8_t *engineID, /* IN - pointer to snmpEngineID */
|
||||
u8_t engineLength,/* IN - length of snmpEngineID */
|
||||
u8_t *key) /* OUT - pointer to caller 16-octet buffer */
|
||||
const u8_t *password, /* IN */
|
||||
size_t passwordlen, /* IN */
|
||||
const u8_t *engineID, /* IN - pointer to snmpEngineID */
|
||||
u8_t engineLength,/* IN - length of snmpEngineID */
|
||||
u8_t *key) /* OUT - pointer to caller 16-octet buffer */
|
||||
{
|
||||
mbedtls_md5_context MD;
|
||||
u8_t *cp, password_buf[64];
|
||||
@@ -276,13 +287,13 @@ snmpv3_password_to_key_md5(
|
||||
}
|
||||
|
||||
/* A.2.2. Password to Key Sample Code for SHA */
|
||||
void
|
||||
void
|
||||
snmpv3_password_to_key_sha(
|
||||
const u8_t *password, /* IN */
|
||||
u8_t passwordlen, /* IN */
|
||||
const u8_t *engineID, /* IN - pointer to snmpEngineID */
|
||||
u8_t engineLength,/* IN - length of snmpEngineID */
|
||||
u8_t *key) /* OUT - pointer to caller 20-octet buffer */
|
||||
const u8_t *password, /* IN */
|
||||
size_t passwordlen, /* IN */
|
||||
const u8_t *engineID, /* IN - pointer to snmpEngineID */
|
||||
u8_t engineLength,/* IN - length of snmpEngineID */
|
||||
u8_t *key) /* OUT - pointer to caller 20-octet buffer */
|
||||
{
|
||||
mbedtls_sha1_context SH;
|
||||
u8_t *cp, password_buf[72];
|
||||
@@ -323,7 +334,7 @@ snmpv3_password_to_key_sha(
|
||||
mbedtls_sha1_starts(&SH);
|
||||
mbedtls_sha1_update(&SH, password_buf, 40 + engineLength);
|
||||
mbedtls_sha1_finish(&SH, key);
|
||||
|
||||
|
||||
mbedtls_sha1_free(&SH);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
|
||||
#if LWIP_SNMP && LWIP_SNMP_V3
|
||||
|
||||
#include "lwip/apps/snmpv3.h"
|
||||
#include "snmp_pbuf_stream.h"
|
||||
|
||||
/* According to RFC 3411 */
|
||||
@@ -48,18 +49,20 @@
|
||||
#define SNMP_V3_MAX_AUTH_PARAM_LENGTH 12
|
||||
#define SNMP_V3_MAX_PRIV_PARAM_LENGTH 8
|
||||
|
||||
#define SNMP_V3_AUTH_FLAG 0x01
|
||||
#define SNMP_V3_PRIV_FLAG 0x02
|
||||
|
||||
#define SNMP_V3_MD5_LEN 16
|
||||
#define SNMP_V3_SHA_LEN 20
|
||||
|
||||
u32_t snmpv3_get_engine_boots_internal(void);
|
||||
u32_t snmpv3_get_engine_time_internal(void);
|
||||
err_t snmpv3_auth(struct snmp_pbuf_stream* stream, u16_t length, const u8_t* key, u8_t algo, u8_t* hmac_out);
|
||||
err_t snmpv3_crypt(struct snmp_pbuf_stream* stream, u16_t length, const u8_t* key,
|
||||
const u8_t* priv_param, const u32_t engine_boots, const u32_t engine_time, u8_t algo, u8_t mode);
|
||||
err_t snmpv3_build_priv_param(u8_t* priv_param);
|
||||
typedef enum {
|
||||
SNMP_V3_PRIV_MODE_DECRYPT = 0,
|
||||
SNMP_V3_PRIV_MODE_ENCRYPT = 1
|
||||
} snmpv3_priv_mode_t;
|
||||
|
||||
s32_t snmpv3_get_engine_boots_internal(void);
|
||||
err_t snmpv3_auth(struct snmp_pbuf_stream *stream, u16_t length, const u8_t *key, snmpv3_auth_algo_t algo, u8_t *hmac_out);
|
||||
err_t snmpv3_crypt(struct snmp_pbuf_stream *stream, u16_t length, const u8_t *key,
|
||||
const u8_t *priv_param, const u32_t engine_boots, const u32_t engine_time, snmpv3_priv_algo_t algo, snmpv3_priv_mode_t mode);
|
||||
err_t snmpv3_build_priv_param(u8_t *priv_param);
|
||||
void snmpv3_enginetime_timer(void *arg);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -42,11 +42,10 @@
|
||||
* This is simple "SNTP" client for the lwIP raw API.
|
||||
* It is a minimal implementation of SNTPv4 as specified in RFC 4330.
|
||||
*
|
||||
* For a list of some public NTP servers, see this link :
|
||||
* For a list of some public NTP servers, see this link:
|
||||
* http://support.ntp.org/bin/view/Servers/NTPPoolServers
|
||||
*
|
||||
* @todo:
|
||||
* - set/change servers at runtime
|
||||
* - complete SNTP_CHECK_RESPONSE checks 3 and 4
|
||||
*/
|
||||
|
||||
@@ -72,21 +71,12 @@
|
||||
#define SNTP_SUPPORT_MULTIPLE_SERVERS 0
|
||||
#endif /* NTP_MAX_SERVERS > 1 */
|
||||
|
||||
#if (SNTP_UPDATE_DELAY < 15000) && !defined(SNTP_SUPPRESS_DELAY_CHECK)
|
||||
#ifndef SNTP_SUPPRESS_DELAY_CHECK
|
||||
#if SNTP_UPDATE_DELAY < 15000
|
||||
#error "SNTPv4 RFC 4330 enforces a minimum update time of 15 seconds (define SNTP_SUPPRESS_DELAY_CHECK to disable this error)!"
|
||||
#endif
|
||||
|
||||
/* Configure behaviour depending on microsecond or second precision */
|
||||
#ifdef SNTP_SET_SYSTEM_TIME_US
|
||||
#define SNTP_CALC_TIME_US 1
|
||||
#define SNTP_RECEIVE_TIME_SIZE 2
|
||||
#else
|
||||
#define SNTP_SET_SYSTEM_TIME_US(sec, us)
|
||||
#define SNTP_CALC_TIME_US 0
|
||||
#define SNTP_RECEIVE_TIME_SIZE 1
|
||||
#endif
|
||||
|
||||
|
||||
/* the various debug levels for this file */
|
||||
#define SNTP_DEBUG_TRACE (SNTP_DEBUG | LWIP_DBG_TRACE)
|
||||
#define SNTP_DEBUG_STATE (SNTP_DEBUG | LWIP_DBG_STATE)
|
||||
@@ -101,10 +91,10 @@
|
||||
|
||||
#define SNTP_OFFSET_LI_VN_MODE 0
|
||||
#define SNTP_LI_MASK 0xC0
|
||||
#define SNTP_LI_NO_WARNING 0x00
|
||||
#define SNTP_LI_LAST_MINUTE_61_SEC 0x01
|
||||
#define SNTP_LI_LAST_MINUTE_59_SEC 0x02
|
||||
#define SNTP_LI_ALARM_CONDITION 0x03 /* (clock not synchronized) */
|
||||
#define SNTP_LI_NO_WARNING (0x00 << 6)
|
||||
#define SNTP_LI_LAST_MINUTE_61_SEC (0x01 << 6)
|
||||
#define SNTP_LI_LAST_MINUTE_59_SEC (0x02 << 6)
|
||||
#define SNTP_LI_ALARM_CONDITION (0x03 << 6) /* (clock not synchronized) */
|
||||
|
||||
#define SNTP_VERSION_MASK 0x38
|
||||
#define SNTP_VERSION (4/* NTP Version 4*/<<3)
|
||||
@@ -121,18 +111,89 @@
|
||||
#define SNTP_OFFSET_RECEIVE_TIME 32
|
||||
#define SNTP_OFFSET_TRANSMIT_TIME 40
|
||||
|
||||
/* number of seconds between 1900 and 1970 (MSB=1)*/
|
||||
#define DIFF_SEC_1900_1970 (2208988800UL)
|
||||
/* number of seconds between 1970 and Feb 7, 2036 (6:28:16 UTC) (MSB=0) */
|
||||
#define DIFF_SEC_1970_2036 (2085978496UL)
|
||||
/* Number of seconds between 1970 and Feb 7, 2036 06:28:16 UTC (epoch 1) */
|
||||
#define DIFF_SEC_1970_2036 ((u32_t)2085978496L)
|
||||
|
||||
/** Convert NTP timestamp fraction to microseconds.
|
||||
*/
|
||||
#ifndef SNTP_FRAC_TO_US
|
||||
# if LWIP_HAVE_INT64
|
||||
# define SNTP_FRAC_TO_US(f) ((u32_t)(((u64_t)(f) * 1000000UL) >> 32))
|
||||
# else
|
||||
# define SNTP_FRAC_TO_US(f) ((u32_t)(f) / 4295)
|
||||
# endif
|
||||
#endif /* !SNTP_FRAC_TO_US */
|
||||
|
||||
/* Configure behaviour depending on native, microsecond or second precision.
|
||||
* Treat NTP timestamps as signed two's-complement integers. This way,
|
||||
* timestamps that have the MSB set simply become negative offsets from
|
||||
* the epoch (Feb 7, 2036 06:28:16 UTC). Representable dates range from
|
||||
* 1968 to 2104.
|
||||
*/
|
||||
#ifndef SNTP_SET_SYSTEM_TIME_NTP
|
||||
# ifdef SNTP_SET_SYSTEM_TIME_US
|
||||
# define SNTP_SET_SYSTEM_TIME_NTP(s, f) \
|
||||
SNTP_SET_SYSTEM_TIME_US((u32_t)((s) + DIFF_SEC_1970_2036), SNTP_FRAC_TO_US(f))
|
||||
# else
|
||||
# define SNTP_SET_SYSTEM_TIME_NTP(s, f) \
|
||||
SNTP_SET_SYSTEM_TIME((u32_t)((s) + DIFF_SEC_1970_2036))
|
||||
# endif
|
||||
#endif /* !SNTP_SET_SYSTEM_TIME_NTP */
|
||||
|
||||
/* Get the system time either natively as NTP timestamp or convert from
|
||||
* Unix time in seconds and microseconds. Take care to avoid overflow if the
|
||||
* microsecond value is at the maximum of 999999. Also add 0.5 us fudge to
|
||||
* avoid special values like 0, and to mask round-off errors that would
|
||||
* otherwise break round-trip conversion identity.
|
||||
*/
|
||||
#ifndef SNTP_GET_SYSTEM_TIME_NTP
|
||||
# define SNTP_GET_SYSTEM_TIME_NTP(s, f) do { \
|
||||
u32_t sec_, usec_; \
|
||||
SNTP_GET_SYSTEM_TIME(sec_, usec_); \
|
||||
(s) = (s32_t)(sec_ - DIFF_SEC_1970_2036); \
|
||||
(f) = usec_ * 4295 - ((usec_ * 2143) >> 16) + 2147; \
|
||||
} while (0)
|
||||
#endif /* !SNTP_GET_SYSTEM_TIME_NTP */
|
||||
|
||||
/* Start offset of the timestamps to extract from the SNTP packet */
|
||||
#define SNTP_OFFSET_TIMESTAMPS \
|
||||
(SNTP_OFFSET_TRANSMIT_TIME + 8 - sizeof(struct sntp_timestamps))
|
||||
|
||||
/* Round-trip delay arithmetic helpers */
|
||||
#if SNTP_COMP_ROUNDTRIP
|
||||
# if !LWIP_HAVE_INT64
|
||||
# error "SNTP round-trip delay compensation requires 64-bit arithmetic"
|
||||
# endif
|
||||
# define SNTP_SEC_FRAC_TO_S64(s, f) \
|
||||
((s64_t)(((u64_t)(s) << 32) | (u32_t)(f)))
|
||||
# define SNTP_TIMESTAMP_TO_S64(t) \
|
||||
SNTP_SEC_FRAC_TO_S64(lwip_ntohl((t).sec), lwip_ntohl((t).frac))
|
||||
#endif /* SNTP_COMP_ROUNDTRIP */
|
||||
|
||||
/**
|
||||
* 64-bit NTP timestamp, in network byte order.
|
||||
*/
|
||||
struct sntp_time {
|
||||
u32_t sec;
|
||||
u32_t frac;
|
||||
};
|
||||
|
||||
/**
|
||||
* Timestamps to be extracted from the NTP header.
|
||||
*/
|
||||
struct sntp_timestamps {
|
||||
#if SNTP_COMP_ROUNDTRIP || SNTP_CHECK_RESPONSE >= 2
|
||||
struct sntp_time orig;
|
||||
struct sntp_time recv;
|
||||
#endif
|
||||
struct sntp_time xmit;
|
||||
};
|
||||
|
||||
/**
|
||||
* SNTP packet format (without optional fields)
|
||||
* Timestamps are coded as 64 bits:
|
||||
* - 32 bits seconds since Jan 01, 1970, 00:00
|
||||
* - 32 bits seconds fraction (0-padded)
|
||||
* For future use, if the MSB in the seconds part is set, seconds are based
|
||||
* on Feb 07, 2036, 06:28:16.
|
||||
* - signed 32 bits seconds since Feb 07, 2036, 06:28:16 UTC (epoch 1)
|
||||
* - unsigned 32 bits seconds fraction (2^32 = 1 second)
|
||||
*/
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
@@ -163,19 +224,23 @@ static void sntp_request(void *arg);
|
||||
static u8_t sntp_opmode;
|
||||
|
||||
/** The UDP pcb used by the SNTP client */
|
||||
static struct udp_pcb* sntp_pcb;
|
||||
static struct udp_pcb *sntp_pcb;
|
||||
/** Names/Addresses of servers */
|
||||
struct sntp_server {
|
||||
#if SNTP_SERVER_DNS
|
||||
char* name;
|
||||
const char *name;
|
||||
#endif /* SNTP_SERVER_DNS */
|
||||
ip_addr_t addr;
|
||||
#if SNTP_MONITOR_SERVER_REACHABILITY
|
||||
/** Reachability shift register as described in RFC 5905 */
|
||||
u8_t reachability;
|
||||
#endif /* SNTP_MONITOR_SERVER_REACHABILITY */
|
||||
};
|
||||
static struct sntp_server sntp_servers[SNTP_MAX_SERVERS];
|
||||
|
||||
#if SNTP_GET_SERVERS_FROM_DHCP
|
||||
#if SNTP_GET_SERVERS_FROM_DHCP || SNTP_GET_SERVERS_FROM_DHCPV6
|
||||
static u8_t sntp_set_servers_from_dhcp;
|
||||
#endif /* SNTP_GET_SERVERS_FROM_DHCP */
|
||||
#endif /* SNTP_GET_SERVERS_FROM_DHCP || SNTP_GET_SERVERS_FROM_DHCPV6 */
|
||||
#if SNTP_SUPPORT_MULTIPLE_SERVERS
|
||||
/** The currently used server (initialized to 0) */
|
||||
static u8_t sntp_current_server;
|
||||
@@ -199,38 +264,69 @@ static ip_addr_t sntp_last_server_address;
|
||||
|
||||
#if SNTP_CHECK_RESPONSE >= 2
|
||||
/** Saves the last timestamp sent (which is sent back by the server)
|
||||
* to compare against in response */
|
||||
static u32_t sntp_last_timestamp_sent[2];
|
||||
* to compare against in response. Stored in network byte order. */
|
||||
static struct sntp_time sntp_last_timestamp_sent;
|
||||
#endif /* SNTP_CHECK_RESPONSE >= 2 */
|
||||
|
||||
#if defined(LWIP_DEBUG) && !defined(sntp_format_time)
|
||||
/* Debug print helper. */
|
||||
static const char *
|
||||
sntp_format_time(s32_t sec)
|
||||
{
|
||||
time_t ut;
|
||||
ut = (u32_t)((u32_t)sec + DIFF_SEC_1970_2036);
|
||||
return ctime(&ut);
|
||||
}
|
||||
#endif /* LWIP_DEBUG && !sntp_format_time */
|
||||
|
||||
/**
|
||||
* SNTP processing of received timestamp
|
||||
*/
|
||||
static void
|
||||
sntp_process(u32_t *receive_timestamp)
|
||||
sntp_process(const struct sntp_timestamps *timestamps)
|
||||
{
|
||||
/* convert SNTP time (1900-based) to unix GMT time (1970-based)
|
||||
* if MSB is 0, SNTP time is 2036-based!
|
||||
*/
|
||||
u32_t rx_secs = lwip_ntohl(receive_timestamp[0]);
|
||||
int is_1900_based = ((rx_secs & 0x80000000) != 0);
|
||||
u32_t t = is_1900_based ? (rx_secs - DIFF_SEC_1900_1970) : (rx_secs + DIFF_SEC_1970_2036);
|
||||
time_t tim = t;
|
||||
s32_t sec;
|
||||
u32_t frac;
|
||||
|
||||
#if SNTP_CALC_TIME_US
|
||||
u32_t us = lwip_ntohl(receive_timestamp[1]) / 4295;
|
||||
SNTP_SET_SYSTEM_TIME_US(t, us);
|
||||
/* display local time from GMT time */
|
||||
LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s, %"U32_F" us", ctime(&tim), us));
|
||||
sec = (s32_t)lwip_ntohl(timestamps->xmit.sec);
|
||||
frac = lwip_ntohl(timestamps->xmit.frac);
|
||||
|
||||
#else /* SNTP_CALC_TIME_US */
|
||||
#if SNTP_COMP_ROUNDTRIP
|
||||
# if SNTP_CHECK_RESPONSE >= 2
|
||||
if (timestamps->recv.sec != 0 || timestamps->recv.frac != 0)
|
||||
# endif
|
||||
{
|
||||
s32_t dest_sec;
|
||||
u32_t dest_frac;
|
||||
u32_t step_sec;
|
||||
|
||||
/* change system time and/or the update the RTC clock */
|
||||
SNTP_SET_SYSTEM_TIME(t);
|
||||
/* display local time from GMT time */
|
||||
LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s", ctime(&tim)));
|
||||
#endif /* SNTP_CALC_TIME_US */
|
||||
LWIP_UNUSED_ARG(tim);
|
||||
/* Get the destination time stamp, i.e. the current system time */
|
||||
SNTP_GET_SYSTEM_TIME_NTP(dest_sec, dest_frac);
|
||||
|
||||
step_sec = (dest_sec < sec) ? ((u32_t)sec - (u32_t)dest_sec)
|
||||
: ((u32_t)dest_sec - (u32_t)sec);
|
||||
/* In order to avoid overflows, skip the compensation if the clock step
|
||||
* is larger than about 34 years. */
|
||||
if ((step_sec >> 30) == 0) {
|
||||
s64_t t1, t2, t3, t4;
|
||||
|
||||
t4 = SNTP_SEC_FRAC_TO_S64(dest_sec, dest_frac);
|
||||
t3 = SNTP_SEC_FRAC_TO_S64(sec, frac);
|
||||
t1 = SNTP_TIMESTAMP_TO_S64(timestamps->orig);
|
||||
t2 = SNTP_TIMESTAMP_TO_S64(timestamps->recv);
|
||||
/* Clock offset calculation according to RFC 4330 */
|
||||
t4 += ((t2 - t1) + (t3 - t4)) / 2;
|
||||
|
||||
sec = (s32_t)((u64_t)t4 >> 32);
|
||||
frac = (u32_t)((u64_t)t4);
|
||||
}
|
||||
}
|
||||
#endif /* SNTP_COMP_ROUNDTRIP */
|
||||
|
||||
SNTP_SET_SYSTEM_TIME_NTP(sec, frac);
|
||||
LWIP_UNUSED_ARG(frac); /* might be unused if only seconds are set */
|
||||
LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s, %" U32_F " us\n",
|
||||
sntp_format_time(sec), SNTP_FRAC_TO_US(frac)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -242,18 +338,23 @@ sntp_initialize_request(struct sntp_msg *req)
|
||||
memset(req, 0, SNTP_MSG_LEN);
|
||||
req->li_vn_mode = SNTP_LI_NO_WARNING | SNTP_VERSION | SNTP_MODE_CLIENT;
|
||||
|
||||
#if SNTP_CHECK_RESPONSE >= 2
|
||||
#if SNTP_CHECK_RESPONSE >= 2 || SNTP_COMP_ROUNDTRIP
|
||||
{
|
||||
u32_t sntp_time_sec, sntp_time_us;
|
||||
/* fill in transmit timestamp and save it in 'sntp_last_timestamp_sent' */
|
||||
SNTP_GET_SYSTEM_TIME(sntp_time_sec, sntp_time_us);
|
||||
sntp_last_timestamp_sent[0] = lwip_htonl(sntp_time_sec + DIFF_SEC_1900_1970);
|
||||
req->transmit_timestamp[0] = sntp_last_timestamp_sent[0];
|
||||
/* we send/save us instead of fraction to be faster... */
|
||||
sntp_last_timestamp_sent[1] = lwip_htonl(sntp_time_us);
|
||||
req->transmit_timestamp[1] = sntp_last_timestamp_sent[1];
|
||||
s32_t secs;
|
||||
u32_t sec, frac;
|
||||
/* Get the transmit timestamp */
|
||||
SNTP_GET_SYSTEM_TIME_NTP(secs, frac);
|
||||
sec = lwip_htonl((u32_t)secs);
|
||||
frac = lwip_htonl(frac);
|
||||
|
||||
# if SNTP_CHECK_RESPONSE >= 2
|
||||
sntp_last_timestamp_sent.sec = sec;
|
||||
sntp_last_timestamp_sent.frac = frac;
|
||||
# endif
|
||||
req->transmit_timestamp[0] = sec;
|
||||
req->transmit_timestamp[1] = frac;
|
||||
}
|
||||
#endif /* SNTP_CHECK_RESPONSE >= 2 */
|
||||
#endif /* SNTP_CHECK_RESPONSE >= 2 || SNTP_COMP_ROUNDTRIP */
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -262,14 +363,15 @@ sntp_initialize_request(struct sntp_msg *req)
|
||||
* @param arg is unused (only necessary to conform to sys_timeout)
|
||||
*/
|
||||
static void
|
||||
sntp_retry(void* arg)
|
||||
sntp_retry(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
|
||||
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_retry: Next request will be sent in %"U32_F" ms\n",
|
||||
sntp_retry_timeout));
|
||||
sntp_retry_timeout));
|
||||
|
||||
/* set up a timer to send a retry and increase the retry delay */
|
||||
sys_untimeout(sntp_request, NULL);
|
||||
sys_timeout(sntp_retry_timeout, sntp_request, NULL);
|
||||
|
||||
#if SNTP_RETRY_TIMEOUT_EXP
|
||||
@@ -281,6 +383,8 @@ sntp_retry(void* arg)
|
||||
if ((new_retry_timeout <= SNTP_RETRY_TIMEOUT_MAX) &&
|
||||
(new_retry_timeout > sntp_retry_timeout)) {
|
||||
sntp_retry_timeout = new_retry_timeout;
|
||||
} else {
|
||||
sntp_retry_timeout = SNTP_RETRY_TIMEOUT_MAX;
|
||||
}
|
||||
}
|
||||
#endif /* SNTP_RETRY_TIMEOUT_EXP */
|
||||
@@ -296,7 +400,7 @@ sntp_retry(void* arg)
|
||||
* @param arg is unused (only necessary to conform to sys_timeout)
|
||||
*/
|
||||
static void
|
||||
sntp_try_next_server(void* arg)
|
||||
sntp_try_next_server(void *arg)
|
||||
{
|
||||
u8_t old_server, i;
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
@@ -311,9 +415,9 @@ sntp_try_next_server(void* arg)
|
||||
#if SNTP_SERVER_DNS
|
||||
|| (sntp_servers[sntp_current_server].name != NULL)
|
||||
#endif
|
||||
) {
|
||||
) {
|
||||
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_try_next_server: Sending request to server %"U16_F"\n",
|
||||
(u16_t)sntp_current_server));
|
||||
(u16_t)sntp_current_server));
|
||||
/* new server: reset retry timeout */
|
||||
SNTP_RESET_RETRY_TIMEOUT();
|
||||
/* instantly send a request to the next server */
|
||||
@@ -332,25 +436,21 @@ sntp_try_next_server(void* arg)
|
||||
|
||||
/** UDP recv callback for the sntp pcb */
|
||||
static void
|
||||
sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
|
||||
sntp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
|
||||
{
|
||||
struct sntp_timestamps timestamps;
|
||||
u8_t mode;
|
||||
u8_t stratum;
|
||||
u32_t receive_timestamp[SNTP_RECEIVE_TIME_SIZE];
|
||||
err_t err;
|
||||
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_UNUSED_ARG(pcb);
|
||||
|
||||
/* packet received: stop retry timeout */
|
||||
sys_untimeout(sntp_try_next_server, NULL);
|
||||
sys_untimeout(sntp_request, NULL);
|
||||
|
||||
err = ERR_ARG;
|
||||
#if SNTP_CHECK_RESPONSE >= 1
|
||||
/* check server address and port */
|
||||
if (((sntp_opmode != SNTP_OPMODE_POLL) || ip_addr_cmp(addr, &sntp_last_server_address)) &&
|
||||
(port == SNTP_PORT))
|
||||
(port == SNTP_PORT))
|
||||
#else /* SNTP_CHECK_RESPONSE >= 1 */
|
||||
LWIP_UNUSED_ARG(addr);
|
||||
LWIP_UNUSED_ARG(port);
|
||||
@@ -358,32 +458,30 @@ sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, const ip_addr_t *addr,
|
||||
{
|
||||
/* process the response */
|
||||
if (p->tot_len == SNTP_MSG_LEN) {
|
||||
pbuf_copy_partial(p, &mode, 1, SNTP_OFFSET_LI_VN_MODE);
|
||||
mode &= SNTP_MODE_MASK;
|
||||
mode = pbuf_get_at(p, SNTP_OFFSET_LI_VN_MODE) & SNTP_MODE_MASK;
|
||||
/* if this is a SNTP response... */
|
||||
if (((sntp_opmode == SNTP_OPMODE_POLL) && (mode == SNTP_MODE_SERVER)) ||
|
||||
if (((sntp_opmode == SNTP_OPMODE_POLL) && (mode == SNTP_MODE_SERVER)) ||
|
||||
((sntp_opmode == SNTP_OPMODE_LISTENONLY) && (mode == SNTP_MODE_BROADCAST))) {
|
||||
pbuf_copy_partial(p, &stratum, 1, SNTP_OFFSET_STRATUM);
|
||||
stratum = pbuf_get_at(p, SNTP_OFFSET_STRATUM);
|
||||
|
||||
if (stratum == SNTP_STRATUM_KOD) {
|
||||
/* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */
|
||||
err = SNTP_ERR_KOD;
|
||||
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Received Kiss-of-Death\n"));
|
||||
} else {
|
||||
pbuf_copy_partial(p, ×tamps, sizeof(timestamps), SNTP_OFFSET_TIMESTAMPS);
|
||||
#if SNTP_CHECK_RESPONSE >= 2
|
||||
/* check originate_timetamp against sntp_last_timestamp_sent */
|
||||
u32_t originate_timestamp[2];
|
||||
pbuf_copy_partial(p, &originate_timestamp, 8, SNTP_OFFSET_ORIGINATE_TIME);
|
||||
if ((originate_timestamp[0] != sntp_last_timestamp_sent[0]) ||
|
||||
(originate_timestamp[1] != sntp_last_timestamp_sent[1]))
|
||||
{
|
||||
LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid originate timestamp in response\n"));
|
||||
if (timestamps.orig.sec != sntp_last_timestamp_sent.sec ||
|
||||
timestamps.orig.frac != sntp_last_timestamp_sent.frac) {
|
||||
LWIP_DEBUGF(SNTP_DEBUG_WARN,
|
||||
("sntp_recv: Invalid originate timestamp in response\n"));
|
||||
} else
|
||||
#endif /* SNTP_CHECK_RESPONSE >= 2 */
|
||||
/* @todo: add code for SNTP_CHECK_RESPONSE >= 3 and >= 4 here */
|
||||
/* @todo: add code for SNTP_CHECK_RESPONSE >= 3 and >= 4 here */
|
||||
{
|
||||
/* correct answer */
|
||||
err = ERR_OK;
|
||||
pbuf_copy_partial(p, &receive_timestamp, SNTP_RECEIVE_TIME_SIZE * 4, SNTP_OFFSET_TRANSMIT_TIME);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -401,30 +499,39 @@ sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, const ip_addr_t *addr,
|
||||
err = ERR_TIMEOUT;
|
||||
}
|
||||
#endif /* SNTP_CHECK_RESPONSE >= 1 */
|
||||
pbuf_free(p);
|
||||
if (err == ERR_OK) {
|
||||
sntp_process(receive_timestamp);
|
||||
|
||||
pbuf_free(p);
|
||||
|
||||
if (err == ERR_OK) {
|
||||
/* correct packet received: process it it */
|
||||
sntp_process(×tamps);
|
||||
|
||||
#if SNTP_MONITOR_SERVER_REACHABILITY
|
||||
/* indicate that server responded */
|
||||
sntp_servers[sntp_current_server].reachability |= 1;
|
||||
#endif /* SNTP_MONITOR_SERVER_REACHABILITY */
|
||||
/* Set up timeout for next request (only if poll response was received)*/
|
||||
if (sntp_opmode == SNTP_OPMODE_POLL) {
|
||||
u32_t sntp_update_delay;
|
||||
sys_untimeout(sntp_try_next_server, NULL);
|
||||
sys_untimeout(sntp_request, NULL);
|
||||
|
||||
/* Correct response, reset retry timeout */
|
||||
SNTP_RESET_RETRY_TIMEOUT();
|
||||
|
||||
sys_timeout((u32_t)SNTP_UPDATE_DELAY, sntp_request, NULL);
|
||||
sntp_update_delay = (u32_t)SNTP_UPDATE_DELAY;
|
||||
sys_timeout(sntp_update_delay, sntp_request, NULL);
|
||||
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Scheduled next time request: %"U32_F" ms\n",
|
||||
(u32_t)SNTP_UPDATE_DELAY));
|
||||
sntp_update_delay));
|
||||
}
|
||||
} else if (err != ERR_TIMEOUT) {
|
||||
/* Errors are only processed in case of an explicit poll response */
|
||||
} else if (err == SNTP_ERR_KOD) {
|
||||
/* KOD errors are only processed in case of an explicit poll response */
|
||||
if (sntp_opmode == SNTP_OPMODE_POLL) {
|
||||
if (err == SNTP_ERR_KOD) {
|
||||
/* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */
|
||||
sntp_try_next_server(NULL);
|
||||
} else {
|
||||
/* another error, try the same server again */
|
||||
sntp_retry(NULL);
|
||||
}
|
||||
/* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */
|
||||
sntp_try_next_server(NULL);
|
||||
}
|
||||
} else {
|
||||
/* ignore any broken packet, poll mode: retry after timeout to avoid flooding */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -435,7 +542,10 @@ sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, const ip_addr_t *addr,
|
||||
static void
|
||||
sntp_send_request(const ip_addr_t *server_addr)
|
||||
{
|
||||
struct pbuf* p;
|
||||
struct pbuf *p;
|
||||
|
||||
LWIP_ASSERT("server_addr != NULL", server_addr != NULL);
|
||||
|
||||
p = pbuf_alloc(PBUF_TRANSPORT, SNTP_MSG_LEN, PBUF_RAM);
|
||||
if (p != NULL) {
|
||||
struct sntp_msg *sntpmsg = (struct sntp_msg *)p->payload;
|
||||
@@ -446,16 +556,22 @@ sntp_send_request(const ip_addr_t *server_addr)
|
||||
udp_sendto(sntp_pcb, p, server_addr, SNTP_PORT);
|
||||
/* free the pbuf after sending it */
|
||||
pbuf_free(p);
|
||||
#if SNTP_MONITOR_SERVER_REACHABILITY
|
||||
/* indicate new packet has been sent */
|
||||
sntp_servers[sntp_current_server].reachability <<= 1;
|
||||
#endif /* SNTP_MONITOR_SERVER_REACHABILITY */
|
||||
/* set up receive timeout: try next server or retry on timeout */
|
||||
sys_untimeout(sntp_try_next_server, NULL);
|
||||
sys_timeout((u32_t)SNTP_RECV_TIMEOUT, sntp_try_next_server, NULL);
|
||||
#if SNTP_CHECK_RESPONSE >= 1
|
||||
/* save server address to verify it in sntp_recv */
|
||||
ip_addr_set(&sntp_last_server_address, server_addr);
|
||||
ip_addr_copy(sntp_last_server_address, *server_addr);
|
||||
#endif /* SNTP_CHECK_RESPONSE >= 1 */
|
||||
} else {
|
||||
LWIP_DEBUGF(SNTP_DEBUG_SERIOUS, ("sntp_send_request: Out of memory, trying again in %"U32_F" ms\n",
|
||||
(u32_t)SNTP_RETRY_TIMEOUT));
|
||||
(u32_t)SNTP_RETRY_TIMEOUT));
|
||||
/* out of memory: set up a timer to send a retry */
|
||||
sys_untimeout(sntp_request, NULL);
|
||||
sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_request, NULL);
|
||||
}
|
||||
}
|
||||
@@ -465,7 +581,7 @@ sntp_send_request(const ip_addr_t *server_addr)
|
||||
* DNS found callback when using DNS names as server address.
|
||||
*/
|
||||
static void
|
||||
sntp_dns_found(const char* hostname, const ip_addr_t *ipaddr, void *arg)
|
||||
sntp_dns_found(const char *hostname, const ip_addr_t *ipaddr, void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(hostname);
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
@@ -473,6 +589,7 @@ sntp_dns_found(const char* hostname, const ip_addr_t *ipaddr, void *arg)
|
||||
if (ipaddr != NULL) {
|
||||
/* Address resolved, send request */
|
||||
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_dns_found: Server address resolved, sending request\n"));
|
||||
sntp_servers[sntp_current_server].addr = *ipaddr;
|
||||
sntp_send_request(ipaddr);
|
||||
} else {
|
||||
/* DNS resolving failed -> try another server */
|
||||
@@ -501,7 +618,7 @@ sntp_request(void *arg)
|
||||
/* always resolve the name and rely on dns-internal caching & timeout */
|
||||
ip_addr_set_zero(&sntp_servers[sntp_current_server].addr);
|
||||
err = dns_gethostbyname(sntp_servers[sntp_current_server].name, &sntp_server_address,
|
||||
sntp_dns_found, NULL);
|
||||
sntp_dns_found, NULL);
|
||||
if (err == ERR_INPROGRESS) {
|
||||
/* DNS request sent, wait for sntp_dns_found being called */
|
||||
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_request: Waiting for server address to be resolved.\n"));
|
||||
@@ -518,11 +635,12 @@ sntp_request(void *arg)
|
||||
|
||||
if (err == ERR_OK) {
|
||||
LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_request: current server address is %s\n",
|
||||
ipaddr_ntoa(&sntp_server_address)));
|
||||
ipaddr_ntoa(&sntp_server_address)));
|
||||
sntp_send_request(&sntp_server_address);
|
||||
} else {
|
||||
/* address conversion failed, try another server */
|
||||
LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_request: Invalid server address, trying next server.\n"));
|
||||
sys_untimeout(sntp_try_next_server, NULL);
|
||||
sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_try_next_server, NULL);
|
||||
}
|
||||
}
|
||||
@@ -535,6 +653,9 @@ sntp_request(void *arg)
|
||||
void
|
||||
sntp_init(void)
|
||||
{
|
||||
/* LWIP_ASSERT_CORE_LOCKED(); is checked by udp_new() */
|
||||
LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_init: SNTP initialised\n"));
|
||||
|
||||
#ifdef SNTP_SERVER_ADDRESS
|
||||
#if SNTP_SERVER_DNS
|
||||
sntp_setservername(0, SNTP_SERVER_ADDRESS);
|
||||
@@ -571,8 +692,16 @@ sntp_init(void)
|
||||
void
|
||||
sntp_stop(void)
|
||||
{
|
||||
LWIP_ASSERT_CORE_LOCKED();
|
||||
if (sntp_pcb != NULL) {
|
||||
#if SNTP_MONITOR_SERVER_REACHABILITY
|
||||
u8_t i;
|
||||
for (i = 0; i < SNTP_MAX_SERVERS; i++) {
|
||||
sntp_servers[i].reachability = 0;
|
||||
}
|
||||
#endif /* SNTP_MONITOR_SERVER_REACHABILITY */
|
||||
sys_untimeout(sntp_request, NULL);
|
||||
sys_untimeout(sntp_try_next_server, NULL);
|
||||
udp_remove(sntp_pcb);
|
||||
sntp_pcb = NULL;
|
||||
}
|
||||
@@ -584,7 +713,7 @@ sntp_stop(void)
|
||||
*/
|
||||
u8_t sntp_enabled(void)
|
||||
{
|
||||
return (sntp_pcb != NULL)? 1 : 0;
|
||||
return (sntp_pcb != NULL) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -595,6 +724,7 @@ u8_t sntp_enabled(void)
|
||||
void
|
||||
sntp_setoperatingmode(u8_t operating_mode)
|
||||
{
|
||||
LWIP_ASSERT_CORE_LOCKED();
|
||||
LWIP_ASSERT("Invalid operating mode", operating_mode <= SNTP_OPMODE_LISTENONLY);
|
||||
LWIP_ASSERT("Operating mode must not be set while SNTP client is running", sntp_pcb == NULL);
|
||||
sntp_opmode = operating_mode;
|
||||
@@ -610,7 +740,24 @@ sntp_getoperatingmode(void)
|
||||
return sntp_opmode;
|
||||
}
|
||||
|
||||
#if SNTP_GET_SERVERS_FROM_DHCP
|
||||
#if SNTP_MONITOR_SERVER_REACHABILITY
|
||||
/**
|
||||
* @ingroup sntp
|
||||
* Gets the server reachability shift register as described in RFC 5905.
|
||||
*
|
||||
* @param idx the index of the NTP server
|
||||
*/
|
||||
u8_t
|
||||
sntp_getreachability(u8_t idx)
|
||||
{
|
||||
if (idx < SNTP_MAX_SERVERS) {
|
||||
return sntp_servers[idx].reachability;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* SNTP_MONITOR_SERVER_REACHABILITY */
|
||||
|
||||
#if SNTP_GET_SERVERS_FROM_DHCP || SNTP_GET_SERVERS_FROM_DHCPV6
|
||||
/**
|
||||
* Config SNTP server handling by IP address, name, or DHCP; clear table
|
||||
* @param set_servers_from_dhcp enable or disable getting server addresses from dhcp
|
||||
@@ -619,11 +766,12 @@ void
|
||||
sntp_servermode_dhcp(int set_servers_from_dhcp)
|
||||
{
|
||||
u8_t new_mode = set_servers_from_dhcp ? 1 : 0;
|
||||
LWIP_ASSERT_CORE_LOCKED();
|
||||
if (sntp_set_servers_from_dhcp != new_mode) {
|
||||
sntp_set_servers_from_dhcp = new_mode;
|
||||
}
|
||||
}
|
||||
#endif /* SNTP_GET_SERVERS_FROM_DHCP */
|
||||
#endif /* SNTP_GET_SERVERS_FROM_DHCP || SNTP_GET_SERVERS_FROM_DHCPV6 */
|
||||
|
||||
/**
|
||||
* @ingroup sntp
|
||||
@@ -635,6 +783,7 @@ sntp_servermode_dhcp(int set_servers_from_dhcp)
|
||||
void
|
||||
sntp_setserver(u8_t idx, const ip_addr_t *server)
|
||||
{
|
||||
LWIP_ASSERT_CORE_LOCKED();
|
||||
if (idx < SNTP_MAX_SERVERS) {
|
||||
if (server != NULL) {
|
||||
sntp_servers[idx].addr = (*server);
|
||||
@@ -651,15 +800,15 @@ sntp_setserver(u8_t idx, const ip_addr_t *server)
|
||||
/**
|
||||
* Initialize one of the NTP servers by IP address, required by DHCP
|
||||
*
|
||||
* @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS
|
||||
* @param dnsserver IP address of the NTP server to set
|
||||
* @param num the index of the NTP server to set must be < SNTP_MAX_SERVERS
|
||||
* @param server IP address of the NTP server to set
|
||||
*/
|
||||
void
|
||||
dhcp_set_ntp_servers(u8_t num, const ip4_addr_t *server)
|
||||
{
|
||||
LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp: %s %u.%u.%u.%u as NTP server #%u via DHCP\n",
|
||||
(sntp_set_servers_from_dhcp ? "Got" : "Rejected"),
|
||||
ip4_addr1(server), ip4_addr2(server), ip4_addr3(server), ip4_addr4(server), num));
|
||||
(sntp_set_servers_from_dhcp ? "Got" : "Rejected"),
|
||||
ip4_addr1(server), ip4_addr2(server), ip4_addr3(server), ip4_addr4(server), num));
|
||||
if (sntp_set_servers_from_dhcp && num) {
|
||||
u8_t i;
|
||||
for (i = 0; (i < num) && (i < SNTP_MAX_SERVERS); i++) {
|
||||
@@ -674,6 +823,33 @@ dhcp_set_ntp_servers(u8_t num, const ip4_addr_t *server)
|
||||
}
|
||||
#endif /* LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP */
|
||||
|
||||
#if LWIP_IPV6_DHCP6 && SNTP_GET_SERVERS_FROM_DHCPV6
|
||||
/**
|
||||
* Initialize one of the NTP servers by IP address, required by DHCPV6
|
||||
*
|
||||
* @param num the number of NTP server addresses to set must be < SNTP_MAX_SERVERS
|
||||
* @param server array of IP address of the NTP servers to set
|
||||
*/
|
||||
void
|
||||
dhcp6_set_ntp_servers(u8_t num_ntp_servers, ip_addr_t* ntp_server_addrs)
|
||||
{
|
||||
LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp: %s %u NTP server(s) via DHCPv6\n",
|
||||
(sntp_set_servers_from_dhcp ? "Got" : "Rejected"),
|
||||
num_ntp_servers));
|
||||
if (sntp_set_servers_from_dhcp && num_ntp_servers) {
|
||||
u8_t i;
|
||||
for (i = 0; (i < num_ntp_servers) && (i < SNTP_MAX_SERVERS); i++) {
|
||||
LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp: NTP server %u: %s\n",
|
||||
i, ipaddr_ntoa(&ntp_server_addrs[i])));
|
||||
sntp_setserver(i, &ntp_server_addrs[i]);
|
||||
}
|
||||
for (i = num_ntp_servers; i < SNTP_MAX_SERVERS; i++) {
|
||||
sntp_setserver(i, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* LWIP_DHCPv6 && SNTP_GET_SERVERS_FROM_DHCPV6 */
|
||||
|
||||
/**
|
||||
* @ingroup sntp
|
||||
* Obtain one of the currently configured by IP address (or DHCP) NTP servers
|
||||
@@ -682,25 +858,26 @@ dhcp_set_ntp_servers(u8_t num, const ip4_addr_t *server)
|
||||
* @return IP address of the indexed NTP server or "ip_addr_any" if the NTP
|
||||
* server has not been configured by address (or at all).
|
||||
*/
|
||||
const ip_addr_t*
|
||||
const ip_addr_t *
|
||||
sntp_getserver(u8_t idx)
|
||||
{
|
||||
if (idx < SNTP_MAX_SERVERS) {
|
||||
return &sntp_servers[idx].addr;
|
||||
}
|
||||
return IP4_ADDR_ANY;
|
||||
return IP_ADDR_ANY;
|
||||
}
|
||||
|
||||
#if SNTP_SERVER_DNS
|
||||
/**
|
||||
* Initialize one of the NTP servers by name
|
||||
*
|
||||
* @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS
|
||||
* @param dnsserver DNS name of the NTP server to set, to be resolved at contact time
|
||||
* @param idx the index of the NTP server to set must be < SNTP_MAX_SERVERS
|
||||
* @param server DNS name of the NTP server to set, to be resolved at contact time
|
||||
*/
|
||||
void
|
||||
sntp_setservername(u8_t idx, char *server)
|
||||
sntp_setservername(u8_t idx, const char *server)
|
||||
{
|
||||
LWIP_ASSERT_CORE_LOCKED();
|
||||
if (idx < SNTP_MAX_SERVERS) {
|
||||
sntp_servers[idx].name = server;
|
||||
}
|
||||
@@ -709,11 +886,11 @@ sntp_setservername(u8_t idx, char *server)
|
||||
/**
|
||||
* Obtain one of the currently configured by name NTP servers.
|
||||
*
|
||||
* @param numdns the index of the NTP server
|
||||
* @param idx the index of the NTP server
|
||||
* @return IP address of the indexed NTP server or NULL if the NTP
|
||||
* server has not been configured by name (or at all)
|
||||
*/
|
||||
char *
|
||||
const char *
|
||||
sntp_getservername(u8_t idx)
|
||||
{
|
||||
if (idx < SNTP_MAX_SERVERS) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/****************************************************************//**
|
||||
/**
|
||||
*
|
||||
* @file tftp_server.c
|
||||
*
|
||||
@@ -10,9 +10,9 @@
|
||||
* Copyright (c) Deltatee Enterprises Ltd. 2013
|
||||
* All rights reserved.
|
||||
*
|
||||
********************************************************************/
|
||||
*/
|
||||
|
||||
/*
|
||||
/*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification,are permitted provided that the following conditions are met:
|
||||
*
|
||||
@@ -92,7 +92,7 @@ struct tftp_state {
|
||||
|
||||
static struct tftp_state tftp_state;
|
||||
|
||||
static void tftp_tmr(void* arg);
|
||||
static void tftp_tmr(void *arg);
|
||||
|
||||
static void
|
||||
close_handle(void)
|
||||
@@ -100,13 +100,13 @@ close_handle(void)
|
||||
tftp_state.port = 0;
|
||||
ip_addr_set_any(0, &tftp_state.addr);
|
||||
|
||||
if(tftp_state.last_data != NULL) {
|
||||
if (tftp_state.last_data != NULL) {
|
||||
pbuf_free(tftp_state.last_data);
|
||||
tftp_state.last_data = NULL;
|
||||
}
|
||||
|
||||
sys_untimeout(tftp_tmr, NULL);
|
||||
|
||||
|
||||
if (tftp_state.handle) {
|
||||
tftp_state.ctx->close(tftp_state.handle);
|
||||
tftp_state.handle = NULL;
|
||||
@@ -118,15 +118,15 @@ static void
|
||||
send_error(const ip_addr_t *addr, u16_t port, enum tftp_error code, const char *str)
|
||||
{
|
||||
int str_length = strlen(str);
|
||||
struct pbuf* p;
|
||||
u16_t* payload;
|
||||
|
||||
struct pbuf *p;
|
||||
u16_t *payload;
|
||||
|
||||
p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(TFTP_HEADER_LENGTH + str_length + 1), PBUF_RAM);
|
||||
if(p == NULL) {
|
||||
if (p == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
payload = (u16_t*) p->payload;
|
||||
payload = (u16_t *) p->payload;
|
||||
payload[0] = PP_HTONS(TFTP_ERROR);
|
||||
payload[1] = lwip_htons(code);
|
||||
MEMCPY(&payload[2], str, str_length + 1);
|
||||
@@ -138,15 +138,15 @@ send_error(const ip_addr_t *addr, u16_t port, enum tftp_error code, const char *
|
||||
static void
|
||||
send_ack(u16_t blknum)
|
||||
{
|
||||
struct pbuf* p;
|
||||
u16_t* payload;
|
||||
|
||||
struct pbuf *p;
|
||||
u16_t *payload;
|
||||
|
||||
p = pbuf_alloc(PBUF_TRANSPORT, TFTP_HEADER_LENGTH, PBUF_RAM);
|
||||
if(p == NULL) {
|
||||
if (p == NULL) {
|
||||
return;
|
||||
}
|
||||
payload = (u16_t*) p->payload;
|
||||
|
||||
payload = (u16_t *) p->payload;
|
||||
|
||||
payload[0] = PP_HTONS(TFTP_ACK);
|
||||
payload[1] = lwip_htons(blknum);
|
||||
udp_sendto(tftp_state.upcb, p, &tftp_state.addr, tftp_state.port);
|
||||
@@ -157,15 +157,15 @@ static void
|
||||
resend_data(void)
|
||||
{
|
||||
struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, tftp_state.last_data->len, PBUF_RAM);
|
||||
if(p == NULL) {
|
||||
if (p == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(pbuf_copy(p, tftp_state.last_data) != ERR_OK) {
|
||||
if (pbuf_copy(p, tftp_state.last_data) != ERR_OK) {
|
||||
pbuf_free(p);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
udp_sendto(tftp_state.upcb, p, &tftp_state.addr, tftp_state.port);
|
||||
pbuf_free(p);
|
||||
}
|
||||
@@ -176,12 +176,12 @@ send_data(void)
|
||||
u16_t *payload;
|
||||
int ret;
|
||||
|
||||
if(tftp_state.last_data != NULL) {
|
||||
if (tftp_state.last_data != NULL) {
|
||||
pbuf_free(tftp_state.last_data);
|
||||
}
|
||||
|
||||
|
||||
tftp_state.last_data = pbuf_alloc(PBUF_TRANSPORT, TFTP_HEADER_LENGTH + TFTP_MAX_PAYLOAD_SIZE, PBUF_RAM);
|
||||
if(tftp_state.last_data == NULL) {
|
||||
if (tftp_state.last_data == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16
|
||||
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_UNUSED_ARG(upcb);
|
||||
|
||||
|
||||
if (((tftp_state.port != 0) && (port != tftp_state.port)) ||
|
||||
(!ip_addr_isany_val(tftp_state.addr) && !ip_addr_cmp(&tftp_state.addr, addr))) {
|
||||
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Only one connection at a time is supported");
|
||||
@@ -223,37 +223,36 @@ recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16
|
||||
|
||||
switch (opcode) {
|
||||
case PP_HTONS(TFTP_RRQ): /* fall through */
|
||||
case PP_HTONS(TFTP_WRQ):
|
||||
{
|
||||
case PP_HTONS(TFTP_WRQ): {
|
||||
const char tftp_null = 0;
|
||||
char filename[TFTP_MAX_FILENAME_LEN];
|
||||
char mode[TFTP_MAX_MODE_LEN];
|
||||
char filename[TFTP_MAX_FILENAME_LEN + 1];
|
||||
char mode[TFTP_MAX_MODE_LEN + 1];
|
||||
u16_t filename_end_offset;
|
||||
u16_t mode_end_offset;
|
||||
|
||||
if(tftp_state.handle != NULL) {
|
||||
if (tftp_state.handle != NULL) {
|
||||
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Only one connection at a time is supported");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
sys_timeout(TFTP_TIMER_MSECS, tftp_tmr, NULL);
|
||||
|
||||
/* find \0 in pbuf -> end of filename string */
|
||||
filename_end_offset = pbuf_memfind(p, &tftp_null, sizeof(tftp_null), 2);
|
||||
if((u16_t)(filename_end_offset-2) > sizeof(filename)) {
|
||||
if ((u16_t)(filename_end_offset - 1) > sizeof(filename)) {
|
||||
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Filename too long/not NULL terminated");
|
||||
break;
|
||||
}
|
||||
pbuf_copy_partial(p, filename, filename_end_offset-2, 2);
|
||||
pbuf_copy_partial(p, filename, filename_end_offset - 1, 2);
|
||||
|
||||
/* find \0 in pbuf -> end of mode string */
|
||||
mode_end_offset = pbuf_memfind(p, &tftp_null, sizeof(tftp_null), filename_end_offset+1);
|
||||
if((u16_t)(mode_end_offset-filename_end_offset) > sizeof(mode)) {
|
||||
mode_end_offset = pbuf_memfind(p, &tftp_null, sizeof(tftp_null), filename_end_offset + 1);
|
||||
if ((u16_t)(mode_end_offset - filename_end_offset) > sizeof(mode)) {
|
||||
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Mode too long/not NULL terminated");
|
||||
break;
|
||||
}
|
||||
pbuf_copy_partial(p, mode, mode_end_offset-filename_end_offset, filename_end_offset+1);
|
||||
|
||||
pbuf_copy_partial(p, mode, mode_end_offset - filename_end_offset, filename_end_offset + 1);
|
||||
|
||||
tftp_state.handle = tftp_state.ctx->open(filename, mode, opcode == PP_HTONS(TFTP_WRQ));
|
||||
tftp_state.blknum = 1;
|
||||
|
||||
@@ -279,12 +278,11 @@ recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PP_HTONS(TFTP_DATA):
|
||||
{
|
||||
|
||||
case PP_HTONS(TFTP_DATA): {
|
||||
int ret;
|
||||
u16_t blknum;
|
||||
|
||||
|
||||
if (tftp_state.handle == NULL) {
|
||||
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "No connection");
|
||||
break;
|
||||
@@ -296,24 +294,32 @@ recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16
|
||||
}
|
||||
|
||||
blknum = lwip_ntohs(sbuf[1]);
|
||||
pbuf_header(p, -TFTP_HEADER_LENGTH);
|
||||
if (blknum == tftp_state.blknum) {
|
||||
pbuf_remove_header(p, TFTP_HEADER_LENGTH);
|
||||
|
||||
ret = tftp_state.ctx->write(tftp_state.handle, p);
|
||||
if (ret < 0) {
|
||||
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "error writing file");
|
||||
close_handle();
|
||||
} else {
|
||||
ret = tftp_state.ctx->write(tftp_state.handle, p);
|
||||
if (ret < 0) {
|
||||
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "error writing file");
|
||||
close_handle();
|
||||
} else {
|
||||
send_ack(blknum);
|
||||
}
|
||||
|
||||
if (p->tot_len < TFTP_MAX_PAYLOAD_SIZE) {
|
||||
close_handle();
|
||||
} else {
|
||||
tftp_state.blknum++;
|
||||
}
|
||||
} else if ((u16_t)(blknum + 1) == tftp_state.blknum) {
|
||||
/* retransmit of previous block, ack again (casting to u16_t to care for overflow) */
|
||||
send_ack(blknum);
|
||||
}
|
||||
|
||||
if (p->tot_len < TFTP_MAX_PAYLOAD_SIZE) {
|
||||
close_handle();
|
||||
} else {
|
||||
send_error(addr, port, TFTP_ERROR_UNKNOWN_TRFR_ID, "Wrong block number");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PP_HTONS(TFTP_ACK):
|
||||
{
|
||||
case PP_HTONS(TFTP_ACK): {
|
||||
u16_t blknum;
|
||||
int lastpkt;
|
||||
|
||||
@@ -348,7 +354,7 @@ recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
send_error(addr, port, TFTP_ERROR_ILLEGAL_OPERATION, "Unknown operation");
|
||||
break;
|
||||
@@ -358,10 +364,10 @@ recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16
|
||||
}
|
||||
|
||||
static void
|
||||
tftp_tmr(void* arg)
|
||||
tftp_tmr(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
|
||||
|
||||
tftp_state.timer++;
|
||||
|
||||
if (tftp_state.handle == NULL) {
|
||||
@@ -386,11 +392,12 @@ tftp_tmr(void* arg)
|
||||
* Initialize TFTP server.
|
||||
* @param ctx TFTP callback struct
|
||||
*/
|
||||
err_t
|
||||
err_t
|
||||
tftp_init(const struct tftp_context *ctx)
|
||||
{
|
||||
err_t ret;
|
||||
|
||||
/* LWIP_ASSERT_CORE_LOCKED(); is checked by udp_new() */
|
||||
struct udp_pcb *pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
|
||||
if (pcb == NULL) {
|
||||
return ERR_MEM;
|
||||
@@ -414,4 +421,15 @@ tftp_init(const struct tftp_context *ctx)
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/** @ingroup tftp
|
||||
* Deinitialize ("turn off") TFTP server.
|
||||
*/
|
||||
void tftp_cleanup(void)
|
||||
{
|
||||
LWIP_ASSERT("Cleanup called on non-initialized TFTP", tftp_state.upcb != NULL);
|
||||
udp_remove(tftp_state.upcb);
|
||||
close_handle();
|
||||
memset(&tftp_state, 0, sizeof(tftp_state));
|
||||
}
|
||||
|
||||
#endif /* LWIP_UDP */
|
||||
|
||||
717
src/core/altcp.c
Normal file
717
src/core/altcp.c
Normal file
@@ -0,0 +1,717 @@
|
||||
/**
|
||||
* @file
|
||||
* @defgroup altcp Application layered TCP Functions
|
||||
* @ingroup altcp_api
|
||||
*
|
||||
* This file contains the common functions for altcp to work.
|
||||
* For more details see @ref altcp_api.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup altcp_api Application layered TCP Introduction
|
||||
* @ingroup callbackstyle_api
|
||||
*
|
||||
* Overview
|
||||
* --------
|
||||
* altcp (application layered TCP connection API; to be used from TCPIP thread)
|
||||
* is an abstraction layer that prevents applications linking hard against the
|
||||
* @ref tcp.h functions while providing the same functionality. It is used to
|
||||
* e.g. add SSL/TLS (see LWIP_ALTCP_TLS) or proxy-connect support to an application
|
||||
* written for the tcp callback API without that application knowing the
|
||||
* protocol details.
|
||||
*
|
||||
* * This interface mimics the tcp callback API to the application while preventing
|
||||
* direct linking (much like virtual functions).
|
||||
* * This way, an application can make use of other application layer protocols
|
||||
* on top of TCP without knowing the details (e.g. TLS, proxy connection).
|
||||
* * This is achieved by simply including "lwip/altcp.h" instead of "lwip/tcp.h",
|
||||
* replacing "struct tcp_pcb" with "struct altcp_pcb" and prefixing all functions
|
||||
* with "altcp_" instead of "tcp_".
|
||||
*
|
||||
* With altcp support disabled (LWIP_ALTCP==0), applications written against the
|
||||
* altcp API can still be compiled but are directly linked against the tcp.h
|
||||
* callback API and then cannot use layered protocols. To minimize code changes
|
||||
* in this case, the use of altcp_allocators is strongly suggested.
|
||||
*
|
||||
* Usage
|
||||
* -----
|
||||
* To make use of this API from an existing tcp raw API application:
|
||||
* * Include "lwip/altcp.h" instead of "lwip/tcp.h"
|
||||
* * Replace "struct tcp_pcb" with "struct altcp_pcb"
|
||||
* * Prefix all called tcp API functions with "altcp_" instead of "tcp_" to link
|
||||
* against the altcp functions
|
||||
* * @ref altcp_new (and @ref altcp_new_ip_type/@ref altcp_new_ip6) take
|
||||
* an @ref altcp_allocator_t as an argument, whereas the original tcp API
|
||||
* functions take no arguments.
|
||||
* * An @ref altcp_allocator_t allocator is an object that holds a pointer to an
|
||||
* allocator object and a corresponding state (e.g. for TLS, the corresponding
|
||||
* state may hold certificates or keys). This way, the application does not
|
||||
* even need to know if it uses TLS or pure TCP, this is handled at runtime
|
||||
* by passing a specific allocator.
|
||||
* * An application can alternatively bind hard to the altcp_tls API by calling
|
||||
* @ref altcp_tls_new or @ref altcp_tls_wrap.
|
||||
* * The TLS layer is not directly implemented by lwIP, but a port to mbedTLS is
|
||||
* provided.
|
||||
* * Another altcp layer is proxy-connect to use TLS behind a HTTP proxy (see
|
||||
* @ref altcp_proxyconnect.h)
|
||||
*
|
||||
* altcp_allocator_t
|
||||
* -----------------
|
||||
* An altcp allocator is created by the application by combining an allocator
|
||||
* callback function and a corresponding state, e.g.:\code{.c}
|
||||
* static const unsigned char cert[] = {0x2D, ... (see mbedTLS doc for how to create this)};
|
||||
* struct altcp_tls_config * conf = altcp_tls_create_config_client(cert, sizeof(cert));
|
||||
* altcp_allocator_t tls_allocator = {
|
||||
* altcp_tls_alloc, conf
|
||||
* };
|
||||
* \endcode
|
||||
*
|
||||
*
|
||||
* struct altcp_tls_config
|
||||
* -----------------------
|
||||
* The struct altcp_tls_config holds state that is needed to create new TLS client
|
||||
* or server connections (e.g. certificates and private keys).
|
||||
*
|
||||
* It is not defined by lwIP itself but by the TLS port (e.g. altcp_tls to mbedTLS
|
||||
* adaption). However, the parameters used to create it are defined in @ref
|
||||
* altcp_tls.h (see @ref altcp_tls_create_config_server_privkey_cert for servers
|
||||
* and @ref altcp_tls_create_config_client/@ref altcp_tls_create_config_client_2wayauth
|
||||
* for clients).
|
||||
*
|
||||
* For mbedTLS, ensure that certificates can be parsed by 'mbedtls_x509_crt_parse()' and
|
||||
* private keys can be parsed by 'mbedtls_pk_parse_key()'.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Simon Goldschmidt
|
||||
* 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. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Simon Goldschmidt <goldsimon@gmx.de>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/altcp.h"
|
||||
#include "lwip/priv/altcp_priv.h"
|
||||
#include "lwip/altcp_tcp.h"
|
||||
#include "lwip/tcp.h"
|
||||
#include "lwip/mem.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
extern const struct altcp_functions altcp_tcp_functions;
|
||||
|
||||
/**
|
||||
* For altcp layer implementations only: allocate a new struct altcp_pcb from the pool
|
||||
* and zero the memory
|
||||
*/
|
||||
struct altcp_pcb *
|
||||
altcp_alloc(void)
|
||||
{
|
||||
struct altcp_pcb *ret = (struct altcp_pcb *)memp_malloc(MEMP_ALTCP_PCB);
|
||||
if (ret != NULL) {
|
||||
memset(ret, 0, sizeof(struct altcp_pcb));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* For altcp layer implementations only: return a struct altcp_pcb to the pool
|
||||
*/
|
||||
void
|
||||
altcp_free(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn) {
|
||||
if (conn->fns && conn->fns->dealloc) {
|
||||
conn->fns->dealloc(conn);
|
||||
}
|
||||
memp_free(MEMP_ALTCP_PCB, conn);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup altcp
|
||||
* altcp_new_ip6: @ref altcp_new for IPv6
|
||||
*/
|
||||
struct altcp_pcb *
|
||||
altcp_new_ip6(altcp_allocator_t *allocator)
|
||||
{
|
||||
return altcp_new_ip_type(allocator, IPADDR_TYPE_V6);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup altcp
|
||||
* altcp_new: @ref altcp_new for IPv4
|
||||
*/
|
||||
struct altcp_pcb *
|
||||
altcp_new(altcp_allocator_t *allocator)
|
||||
{
|
||||
return altcp_new_ip_type(allocator, IPADDR_TYPE_V4);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup altcp
|
||||
* altcp_new_ip_type: called by applications to allocate a new pcb with the help of an
|
||||
* allocator function.
|
||||
*
|
||||
* @param allocator allocator function and argument
|
||||
* @param ip_type IP version of the pcb (@ref lwip_ip_addr_type)
|
||||
* @return a new altcp_pcb or NULL on error
|
||||
*/
|
||||
struct altcp_pcb *
|
||||
altcp_new_ip_type(altcp_allocator_t *allocator, u8_t ip_type)
|
||||
{
|
||||
struct altcp_pcb *conn;
|
||||
if (allocator == NULL) {
|
||||
/* no allocator given, create a simple TCP connection */
|
||||
return altcp_tcp_new_ip_type(ip_type);
|
||||
}
|
||||
if (allocator->alloc == NULL) {
|
||||
/* illegal allocator */
|
||||
return NULL;
|
||||
}
|
||||
conn = allocator->alloc(allocator->arg, ip_type);
|
||||
if (conn == NULL) {
|
||||
/* allocation failed */
|
||||
return NULL;
|
||||
}
|
||||
return conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup altcp
|
||||
* @see tcp_arg()
|
||||
*/
|
||||
void
|
||||
altcp_arg(struct altcp_pcb *conn, void *arg)
|
||||
{
|
||||
if (conn) {
|
||||
conn->arg = arg;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup altcp
|
||||
* @see tcp_accept()
|
||||
*/
|
||||
void
|
||||
altcp_accept(struct altcp_pcb *conn, altcp_accept_fn accept)
|
||||
{
|
||||
if (conn != NULL) {
|
||||
conn->accept = accept;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup altcp
|
||||
* @see tcp_recv()
|
||||
*/
|
||||
void
|
||||
altcp_recv(struct altcp_pcb *conn, altcp_recv_fn recv)
|
||||
{
|
||||
if (conn) {
|
||||
conn->recv = recv;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup altcp
|
||||
* @see tcp_sent()
|
||||
*/
|
||||
void
|
||||
altcp_sent(struct altcp_pcb *conn, altcp_sent_fn sent)
|
||||
{
|
||||
if (conn) {
|
||||
conn->sent = sent;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup altcp
|
||||
* @see tcp_poll()
|
||||
*/
|
||||
void
|
||||
altcp_poll(struct altcp_pcb *conn, altcp_poll_fn poll, u8_t interval)
|
||||
{
|
||||
if (conn) {
|
||||
conn->poll = poll;
|
||||
conn->pollinterval = interval;
|
||||
if (conn->fns && conn->fns->set_poll) {
|
||||
conn->fns->set_poll(conn, interval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup altcp
|
||||
* @see tcp_err()
|
||||
*/
|
||||
void
|
||||
altcp_err(struct altcp_pcb *conn, altcp_err_fn err)
|
||||
{
|
||||
if (conn) {
|
||||
conn->err = err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Generic functions calling the "virtual" ones */
|
||||
|
||||
/**
|
||||
* @ingroup altcp
|
||||
* @see tcp_recved()
|
||||
*/
|
||||
void
|
||||
altcp_recved(struct altcp_pcb *conn, u16_t len)
|
||||
{
|
||||
if (conn && conn->fns && conn->fns->recved) {
|
||||
conn->fns->recved(conn, len);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup altcp
|
||||
* @see tcp_bind()
|
||||
*/
|
||||
err_t
|
||||
altcp_bind(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port)
|
||||
{
|
||||
if (conn && conn->fns && conn->fns->bind) {
|
||||
return conn->fns->bind(conn, ipaddr, port);
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup altcp
|
||||
* @see tcp_connect()
|
||||
*/
|
||||
err_t
|
||||
altcp_connect(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port, altcp_connected_fn connected)
|
||||
{
|
||||
if (conn && conn->fns && conn->fns->connect) {
|
||||
return conn->fns->connect(conn, ipaddr, port, connected);
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup altcp
|
||||
* @see tcp_listen_with_backlog_and_err()
|
||||
*/
|
||||
struct altcp_pcb *
|
||||
altcp_listen_with_backlog_and_err(struct altcp_pcb *conn, u8_t backlog, err_t *err)
|
||||
{
|
||||
if (conn && conn->fns && conn->fns->listen) {
|
||||
return conn->fns->listen(conn, backlog, err);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup altcp
|
||||
* @see tcp_abort()
|
||||
*/
|
||||
void
|
||||
altcp_abort(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn && conn->fns && conn->fns->abort) {
|
||||
conn->fns->abort(conn);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup altcp
|
||||
* @see tcp_close()
|
||||
*/
|
||||
err_t
|
||||
altcp_close(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn && conn->fns && conn->fns->close) {
|
||||
return conn->fns->close(conn);
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup altcp
|
||||
* @see tcp_shutdown()
|
||||
*/
|
||||
err_t
|
||||
altcp_shutdown(struct altcp_pcb *conn, int shut_rx, int shut_tx)
|
||||
{
|
||||
if (conn && conn->fns && conn->fns->shutdown) {
|
||||
return conn->fns->shutdown(conn, shut_rx, shut_tx);
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup altcp
|
||||
* @see tcp_write()
|
||||
*/
|
||||
err_t
|
||||
altcp_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags)
|
||||
{
|
||||
if (conn && conn->fns && conn->fns->write) {
|
||||
return conn->fns->write(conn, dataptr, len, apiflags);
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup altcp
|
||||
* @see tcp_output()
|
||||
*/
|
||||
err_t
|
||||
altcp_output(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn && conn->fns && conn->fns->output) {
|
||||
return conn->fns->output(conn);
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup altcp
|
||||
* @see tcp_mss()
|
||||
*/
|
||||
u16_t
|
||||
altcp_mss(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn && conn->fns && conn->fns->mss) {
|
||||
return conn->fns->mss(conn);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup altcp
|
||||
* @see tcp_sndbuf()
|
||||
*/
|
||||
u16_t
|
||||
altcp_sndbuf(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn && conn->fns && conn->fns->sndbuf) {
|
||||
return conn->fns->sndbuf(conn);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup altcp
|
||||
* @see tcp_sndqueuelen()
|
||||
*/
|
||||
u16_t
|
||||
altcp_sndqueuelen(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn && conn->fns && conn->fns->sndqueuelen) {
|
||||
return conn->fns->sndqueuelen(conn);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
altcp_nagle_disable(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn && conn->fns && conn->fns->nagle_disable) {
|
||||
conn->fns->nagle_disable(conn);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
altcp_nagle_enable(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn && conn->fns && conn->fns->nagle_enable) {
|
||||
conn->fns->nagle_enable(conn);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
altcp_nagle_disabled(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn && conn->fns && conn->fns->nagle_disabled) {
|
||||
return conn->fns->nagle_disabled(conn);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup altcp
|
||||
* @see tcp_setprio()
|
||||
*/
|
||||
void
|
||||
altcp_setprio(struct altcp_pcb *conn, u8_t prio)
|
||||
{
|
||||
if (conn && conn->fns && conn->fns->setprio) {
|
||||
conn->fns->setprio(conn, prio);
|
||||
}
|
||||
}
|
||||
|
||||
err_t
|
||||
altcp_get_tcp_addrinfo(struct altcp_pcb *conn, int local, ip_addr_t *addr, u16_t *port)
|
||||
{
|
||||
if (conn && conn->fns && conn->fns->addrinfo) {
|
||||
return conn->fns->addrinfo(conn, local, addr, port);
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
ip_addr_t *
|
||||
altcp_get_ip(struct altcp_pcb *conn, int local)
|
||||
{
|
||||
if (conn && conn->fns && conn->fns->getip) {
|
||||
return conn->fns->getip(conn, local);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u16_t
|
||||
altcp_get_port(struct altcp_pcb *conn, int local)
|
||||
{
|
||||
if (conn && conn->fns && conn->fns->getport) {
|
||||
return conn->fns->getport(conn, local);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if LWIP_TCP_KEEPALIVE
|
||||
void
|
||||
altcp_keepalive_disable(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn && conn->fns && conn->fns->keepalive_disable) {
|
||||
conn->fns->keepalive_disable(conn);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
altcp_keepalive_enable(struct altcp_pcb *conn, u32_t idle, u32_t intvl, u32_t count)
|
||||
{
|
||||
if (conn && conn->fns && conn->fns->keepalive_enable) {
|
||||
conn->fns->keepalive_enable(conn, idle, intvl, count);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef LWIP_DEBUG
|
||||
enum tcp_state
|
||||
altcp_dbg_get_tcp_state(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn && conn->fns && conn->fns->dbg_get_tcp_state) {
|
||||
return conn->fns->dbg_get_tcp_state(conn);
|
||||
}
|
||||
return CLOSED;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Default implementations for the "virtual" functions */
|
||||
|
||||
void
|
||||
altcp_default_set_poll(struct altcp_pcb *conn, u8_t interval)
|
||||
{
|
||||
if (conn && conn->inner_conn) {
|
||||
altcp_poll(conn->inner_conn, conn->poll, interval);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
altcp_default_recved(struct altcp_pcb *conn, u16_t len)
|
||||
{
|
||||
if (conn && conn->inner_conn) {
|
||||
altcp_recved(conn->inner_conn, len);
|
||||
}
|
||||
}
|
||||
|
||||
err_t
|
||||
altcp_default_bind(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port)
|
||||
{
|
||||
if (conn && conn->inner_conn) {
|
||||
return altcp_bind(conn->inner_conn, ipaddr, port);
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
err_t
|
||||
altcp_default_shutdown(struct altcp_pcb *conn, int shut_rx, int shut_tx)
|
||||
{
|
||||
if (conn) {
|
||||
if (shut_rx && shut_tx && conn->fns && conn->fns->close) {
|
||||
/* default shutdown for both sides is close */
|
||||
return conn->fns->close(conn);
|
||||
}
|
||||
if (conn->inner_conn) {
|
||||
return altcp_shutdown(conn->inner_conn, shut_rx, shut_tx);
|
||||
}
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
err_t
|
||||
altcp_default_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags)
|
||||
{
|
||||
if (conn && conn->inner_conn) {
|
||||
return altcp_write(conn->inner_conn, dataptr, len, apiflags);
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
err_t
|
||||
altcp_default_output(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn && conn->inner_conn) {
|
||||
return altcp_output(conn->inner_conn);
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
u16_t
|
||||
altcp_default_mss(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn && conn->inner_conn) {
|
||||
return altcp_mss(conn->inner_conn);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u16_t
|
||||
altcp_default_sndbuf(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn && conn->inner_conn) {
|
||||
return altcp_sndbuf(conn->inner_conn);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u16_t
|
||||
altcp_default_sndqueuelen(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn && conn->inner_conn) {
|
||||
return altcp_sndqueuelen(conn->inner_conn);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
altcp_default_nagle_disable(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn && conn->inner_conn) {
|
||||
altcp_nagle_disable(conn->inner_conn);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
altcp_default_nagle_enable(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn && conn->inner_conn) {
|
||||
altcp_nagle_enable(conn->inner_conn);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
altcp_default_nagle_disabled(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn && conn->inner_conn) {
|
||||
return altcp_nagle_disabled(conn->inner_conn);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
altcp_default_setprio(struct altcp_pcb *conn, u8_t prio)
|
||||
{
|
||||
if (conn && conn->inner_conn) {
|
||||
altcp_setprio(conn->inner_conn, prio);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
altcp_default_dealloc(struct altcp_pcb *conn)
|
||||
{
|
||||
LWIP_UNUSED_ARG(conn);
|
||||
/* nothing to do */
|
||||
}
|
||||
|
||||
err_t
|
||||
altcp_default_get_tcp_addrinfo(struct altcp_pcb *conn, int local, ip_addr_t *addr, u16_t *port)
|
||||
{
|
||||
if (conn && conn->inner_conn) {
|
||||
return altcp_get_tcp_addrinfo(conn->inner_conn, local, addr, port);
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
ip_addr_t *
|
||||
altcp_default_get_ip(struct altcp_pcb *conn, int local)
|
||||
{
|
||||
if (conn && conn->inner_conn) {
|
||||
return altcp_get_ip(conn->inner_conn, local);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u16_t
|
||||
altcp_default_get_port(struct altcp_pcb *conn, int local)
|
||||
{
|
||||
if (conn && conn->inner_conn) {
|
||||
return altcp_get_port(conn->inner_conn, local);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if LWIP_TCP_KEEPALIVE
|
||||
void
|
||||
altcp_default_keepalive_disable(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn && conn->inner_conn) {
|
||||
altcp_keepalive_disable(conn->inner_conn);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
altcp_default_keepalive_enable(struct altcp_pcb *conn, u32_t idle, u32_t intvl, u32_t count)
|
||||
{
|
||||
if (conn && conn->inner_conn) {
|
||||
altcp_keepalive_enable(conn->inner_conn, idle, intvl, count);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef LWIP_DEBUG
|
||||
enum tcp_state
|
||||
altcp_default_dbg_get_tcp_state(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn && conn->inner_conn) {
|
||||
return altcp_dbg_get_tcp_state(conn->inner_conn);
|
||||
}
|
||||
return CLOSED;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* LWIP_ALTCP */
|
||||
87
src/core/altcp_alloc.c
Normal file
87
src/core/altcp_alloc.c
Normal file
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* @file
|
||||
* Application layered TCP connection API (to be used from TCPIP thread)\n
|
||||
* This interface mimics the tcp callback API to the application while preventing
|
||||
* direct linking (much like virtual functions).
|
||||
* This way, an application can make use of other application layer protocols
|
||||
* on top of TCP without knowing the details (e.g. TLS, proxy connection).
|
||||
*
|
||||
* This file contains allocation implementation that combine several layers.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Simon Goldschmidt
|
||||
* 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. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Simon Goldschmidt <goldsimon@gmx.de>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/altcp.h"
|
||||
#include "lwip/altcp_tcp.h"
|
||||
#include "lwip/altcp_tls.h"
|
||||
#include "lwip/priv/altcp_priv.h"
|
||||
#include "lwip/mem.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if LWIP_ALTCP_TLS
|
||||
|
||||
/** This standard allocator function creates an altcp pcb for
|
||||
* TLS over TCP */
|
||||
struct altcp_pcb *
|
||||
altcp_tls_new(struct altcp_tls_config *config, u8_t ip_type)
|
||||
{
|
||||
struct altcp_pcb *inner_conn, *ret;
|
||||
LWIP_UNUSED_ARG(ip_type);
|
||||
|
||||
inner_conn = altcp_tcp_new_ip_type(ip_type);
|
||||
if (inner_conn == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ret = altcp_tls_wrap(config, inner_conn);
|
||||
if (ret == NULL) {
|
||||
altcp_close(inner_conn);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** This standard allocator function creates an altcp pcb for
|
||||
* TLS over TCP */
|
||||
struct altcp_pcb *
|
||||
altcp_tls_alloc(void *arg, u8_t ip_type)
|
||||
{
|
||||
return altcp_tls_new((struct altcp_tls_config *)arg, ip_type);
|
||||
}
|
||||
|
||||
#endif /* LWIP_ALTCP_TLS */
|
||||
|
||||
#endif /* LWIP_ALTCP */
|
||||
577
src/core/altcp_tcp.c
Normal file
577
src/core/altcp_tcp.c
Normal file
@@ -0,0 +1,577 @@
|
||||
/**
|
||||
* @file
|
||||
* Application layered TCP connection API (to be used from TCPIP thread)\n
|
||||
* This interface mimics the tcp callback API to the application while preventing
|
||||
* direct linking (much like virtual functions).
|
||||
* This way, an application can make use of other application layer protocols
|
||||
* on top of TCP without knowing the details (e.g. TLS, proxy connection).
|
||||
*
|
||||
* This file contains the base implementation calling into tcp.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Simon Goldschmidt
|
||||
* 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. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Simon Goldschmidt <goldsimon@gmx.de>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/altcp.h"
|
||||
#include "lwip/altcp_tcp.h"
|
||||
#include "lwip/priv/altcp_priv.h"
|
||||
#include "lwip/tcp.h"
|
||||
#include "lwip/priv/tcp_priv.h"
|
||||
#include "lwip/mem.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define ALTCP_TCP_ASSERT_CONN(conn) do { \
|
||||
LWIP_ASSERT("conn->inner_conn == NULL", (conn)->inner_conn == NULL); \
|
||||
LWIP_UNUSED_ARG(conn); /* for LWIP_NOASSERT */ } while(0)
|
||||
#define ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb) do { \
|
||||
LWIP_ASSERT("pcb mismatch", (conn)->state == tpcb); \
|
||||
LWIP_UNUSED_ARG(tpcb); /* for LWIP_NOASSERT */ \
|
||||
ALTCP_TCP_ASSERT_CONN(conn); } while(0)
|
||||
|
||||
|
||||
/* Variable prototype, the actual declaration is at the end of this file
|
||||
since it contains pointers to static functions declared here */
|
||||
extern const struct altcp_functions altcp_tcp_functions;
|
||||
|
||||
static void altcp_tcp_setup(struct altcp_pcb *conn, struct tcp_pcb *tpcb);
|
||||
|
||||
/* callback functions for TCP */
|
||||
static err_t
|
||||
altcp_tcp_accept(void *arg, struct tcp_pcb *new_tpcb, err_t err)
|
||||
{
|
||||
struct altcp_pcb *listen_conn = (struct altcp_pcb *)arg;
|
||||
if (listen_conn && listen_conn->accept) {
|
||||
/* create a new altcp_conn to pass to the next 'accept' callback */
|
||||
struct altcp_pcb *new_conn = altcp_alloc();
|
||||
if (new_conn == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
altcp_tcp_setup(new_conn, new_tpcb);
|
||||
return listen_conn->accept(listen_conn->arg, new_conn, err);
|
||||
}
|
||||
return ERR_ARG;
|
||||
}
|
||||
|
||||
static err_t
|
||||
altcp_tcp_connected(void *arg, struct tcp_pcb *tpcb, err_t err)
|
||||
{
|
||||
struct altcp_pcb *conn = (struct altcp_pcb *)arg;
|
||||
if (conn) {
|
||||
ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb);
|
||||
if (conn->connected) {
|
||||
return conn->connected(conn->arg, conn, err);
|
||||
}
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static err_t
|
||||
altcp_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
|
||||
{
|
||||
struct altcp_pcb *conn = (struct altcp_pcb *)arg;
|
||||
if (conn) {
|
||||
ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb);
|
||||
if (conn->recv) {
|
||||
return conn->recv(conn->arg, conn, p, err);
|
||||
}
|
||||
}
|
||||
if (p != NULL) {
|
||||
/* prevent memory leaks */
|
||||
pbuf_free(p);
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static err_t
|
||||
altcp_tcp_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
|
||||
{
|
||||
struct altcp_pcb *conn = (struct altcp_pcb *)arg;
|
||||
if (conn) {
|
||||
ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb);
|
||||
if (conn->sent) {
|
||||
return conn->sent(conn->arg, conn, len);
|
||||
}
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static err_t
|
||||
altcp_tcp_poll(void *arg, struct tcp_pcb *tpcb)
|
||||
{
|
||||
struct altcp_pcb *conn = (struct altcp_pcb *)arg;
|
||||
if (conn) {
|
||||
ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb);
|
||||
if (conn->poll) {
|
||||
return conn->poll(conn->arg, conn);
|
||||
}
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
altcp_tcp_err(void *arg, err_t err)
|
||||
{
|
||||
struct altcp_pcb *conn = (struct altcp_pcb *)arg;
|
||||
if (conn) {
|
||||
conn->state = NULL; /* already freed */
|
||||
if (conn->err) {
|
||||
conn->err(conn->arg, err);
|
||||
}
|
||||
altcp_free(conn);
|
||||
}
|
||||
}
|
||||
|
||||
/* setup functions */
|
||||
|
||||
static void
|
||||
altcp_tcp_remove_callbacks(struct tcp_pcb *tpcb)
|
||||
{
|
||||
tcp_arg(tpcb, NULL);
|
||||
if (tpcb->state != LISTEN) {
|
||||
tcp_recv(tpcb, NULL);
|
||||
tcp_sent(tpcb, NULL);
|
||||
tcp_err(tpcb, NULL);
|
||||
tcp_poll(tpcb, NULL, tpcb->pollinterval);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
altcp_tcp_setup_callbacks(struct altcp_pcb *conn, struct tcp_pcb *tpcb)
|
||||
{
|
||||
tcp_arg(tpcb, conn);
|
||||
/* this might be called for LISTN when close fails... */
|
||||
if (tpcb->state != LISTEN) {
|
||||
tcp_recv(tpcb, altcp_tcp_recv);
|
||||
tcp_sent(tpcb, altcp_tcp_sent);
|
||||
tcp_err(tpcb, altcp_tcp_err);
|
||||
/* tcp_poll is set when interval is set by application */
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
altcp_tcp_setup(struct altcp_pcb *conn, struct tcp_pcb *tpcb)
|
||||
{
|
||||
altcp_tcp_setup_callbacks(conn, tpcb);
|
||||
conn->state = tpcb;
|
||||
conn->fns = &altcp_tcp_functions;
|
||||
}
|
||||
|
||||
struct altcp_pcb *
|
||||
altcp_tcp_new_ip_type(u8_t ip_type)
|
||||
{
|
||||
/* Allocate the tcp pcb first to invoke the priority handling code
|
||||
if we're out of pcbs */
|
||||
struct tcp_pcb *tpcb = tcp_new_ip_type(ip_type);
|
||||
if (tpcb != NULL) {
|
||||
struct altcp_pcb *ret = altcp_alloc();
|
||||
if (ret != NULL) {
|
||||
altcp_tcp_setup(ret, tpcb);
|
||||
return ret;
|
||||
} else {
|
||||
/* altcp_pcb allocation failed -> free the tcp_pcb too */
|
||||
tcp_close(tpcb);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** altcp_tcp allocator function fitting to @ref altcp_allocator_t / @ref altcp_new.
|
||||
*
|
||||
* arg pointer is not used for TCP.
|
||||
*/
|
||||
struct altcp_pcb *
|
||||
altcp_tcp_alloc(void *arg, u8_t ip_type)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
return altcp_tcp_new_ip_type(ip_type);
|
||||
}
|
||||
|
||||
struct altcp_pcb *
|
||||
altcp_tcp_wrap(struct tcp_pcb *tpcb)
|
||||
{
|
||||
if (tpcb != NULL) {
|
||||
struct altcp_pcb *ret = altcp_alloc();
|
||||
if (ret != NULL) {
|
||||
altcp_tcp_setup(ret, tpcb);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* "virtual" functions calling into tcp */
|
||||
static void
|
||||
altcp_tcp_set_poll(struct altcp_pcb *conn, u8_t interval)
|
||||
{
|
||||
if (conn != NULL) {
|
||||
struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
|
||||
ALTCP_TCP_ASSERT_CONN(conn);
|
||||
tcp_poll(pcb, altcp_tcp_poll, interval);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
altcp_tcp_recved(struct altcp_pcb *conn, u16_t len)
|
||||
{
|
||||
if (conn != NULL) {
|
||||
struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
|
||||
ALTCP_TCP_ASSERT_CONN(conn);
|
||||
tcp_recved(pcb, len);
|
||||
}
|
||||
}
|
||||
|
||||
static err_t
|
||||
altcp_tcp_bind(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port)
|
||||
{
|
||||
struct tcp_pcb *pcb;
|
||||
if (conn == NULL) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
ALTCP_TCP_ASSERT_CONN(conn);
|
||||
pcb = (struct tcp_pcb *)conn->state;
|
||||
return tcp_bind(pcb, ipaddr, port);
|
||||
}
|
||||
|
||||
static err_t
|
||||
altcp_tcp_connect(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port, altcp_connected_fn connected)
|
||||
{
|
||||
struct tcp_pcb *pcb;
|
||||
if (conn == NULL) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
ALTCP_TCP_ASSERT_CONN(conn);
|
||||
conn->connected = connected;
|
||||
pcb = (struct tcp_pcb *)conn->state;
|
||||
return tcp_connect(pcb, ipaddr, port, altcp_tcp_connected);
|
||||
}
|
||||
|
||||
static struct altcp_pcb *
|
||||
altcp_tcp_listen(struct altcp_pcb *conn, u8_t backlog, err_t *err)
|
||||
{
|
||||
struct tcp_pcb *pcb;
|
||||
struct tcp_pcb *lpcb;
|
||||
if (conn == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ALTCP_TCP_ASSERT_CONN(conn);
|
||||
pcb = (struct tcp_pcb *)conn->state;
|
||||
lpcb = tcp_listen_with_backlog_and_err(pcb, backlog, err);
|
||||
if (lpcb != NULL) {
|
||||
conn->state = lpcb;
|
||||
tcp_accept(lpcb, altcp_tcp_accept);
|
||||
return conn;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
altcp_tcp_abort(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn != NULL) {
|
||||
struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
|
||||
ALTCP_TCP_ASSERT_CONN(conn);
|
||||
if (pcb) {
|
||||
tcp_abort(pcb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static err_t
|
||||
altcp_tcp_close(struct altcp_pcb *conn)
|
||||
{
|
||||
struct tcp_pcb *pcb;
|
||||
if (conn == NULL) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
ALTCP_TCP_ASSERT_CONN(conn);
|
||||
pcb = (struct tcp_pcb *)conn->state;
|
||||
if (pcb) {
|
||||
err_t err;
|
||||
tcp_poll_fn oldpoll = pcb->poll;
|
||||
altcp_tcp_remove_callbacks(pcb);
|
||||
err = tcp_close(pcb);
|
||||
if (err != ERR_OK) {
|
||||
/* not closed, set up all callbacks again */
|
||||
altcp_tcp_setup_callbacks(conn, pcb);
|
||||
/* poll callback is not included in the above */
|
||||
tcp_poll(pcb, oldpoll, pcb->pollinterval);
|
||||
return err;
|
||||
}
|
||||
conn->state = NULL; /* unsafe to reference pcb after tcp_close(). */
|
||||
}
|
||||
altcp_free(conn);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static err_t
|
||||
altcp_tcp_shutdown(struct altcp_pcb *conn, int shut_rx, int shut_tx)
|
||||
{
|
||||
struct tcp_pcb *pcb;
|
||||
if (conn == NULL) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
ALTCP_TCP_ASSERT_CONN(conn);
|
||||
pcb = (struct tcp_pcb *)conn->state;
|
||||
return tcp_shutdown(pcb, shut_rx, shut_tx);
|
||||
}
|
||||
|
||||
static err_t
|
||||
altcp_tcp_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags)
|
||||
{
|
||||
struct tcp_pcb *pcb;
|
||||
if (conn == NULL) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
ALTCP_TCP_ASSERT_CONN(conn);
|
||||
pcb = (struct tcp_pcb *)conn->state;
|
||||
return tcp_write(pcb, dataptr, len, apiflags);
|
||||
}
|
||||
|
||||
static err_t
|
||||
altcp_tcp_output(struct altcp_pcb *conn)
|
||||
{
|
||||
struct tcp_pcb *pcb;
|
||||
if (conn == NULL) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
ALTCP_TCP_ASSERT_CONN(conn);
|
||||
pcb = (struct tcp_pcb *)conn->state;
|
||||
return tcp_output(pcb);
|
||||
}
|
||||
|
||||
static u16_t
|
||||
altcp_tcp_mss(struct altcp_pcb *conn)
|
||||
{
|
||||
struct tcp_pcb *pcb;
|
||||
if (conn == NULL) {
|
||||
return 0;
|
||||
}
|
||||
ALTCP_TCP_ASSERT_CONN(conn);
|
||||
pcb = (struct tcp_pcb *)conn->state;
|
||||
return tcp_mss(pcb);
|
||||
}
|
||||
|
||||
static u16_t
|
||||
altcp_tcp_sndbuf(struct altcp_pcb *conn)
|
||||
{
|
||||
struct tcp_pcb *pcb;
|
||||
if (conn == NULL) {
|
||||
return 0;
|
||||
}
|
||||
ALTCP_TCP_ASSERT_CONN(conn);
|
||||
pcb = (struct tcp_pcb *)conn->state;
|
||||
return tcp_sndbuf(pcb);
|
||||
}
|
||||
|
||||
static u16_t
|
||||
altcp_tcp_sndqueuelen(struct altcp_pcb *conn)
|
||||
{
|
||||
struct tcp_pcb *pcb;
|
||||
if (conn == NULL) {
|
||||
return 0;
|
||||
}
|
||||
ALTCP_TCP_ASSERT_CONN(conn);
|
||||
pcb = (struct tcp_pcb *)conn->state;
|
||||
return tcp_sndqueuelen(pcb);
|
||||
}
|
||||
|
||||
static void
|
||||
altcp_tcp_nagle_disable(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn && conn->state) {
|
||||
struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
|
||||
ALTCP_TCP_ASSERT_CONN(conn);
|
||||
tcp_nagle_disable(pcb);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
altcp_tcp_nagle_enable(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn && conn->state) {
|
||||
struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
|
||||
ALTCP_TCP_ASSERT_CONN(conn);
|
||||
tcp_nagle_enable(pcb);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
altcp_tcp_nagle_disabled(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn && conn->state) {
|
||||
struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
|
||||
ALTCP_TCP_ASSERT_CONN(conn);
|
||||
return tcp_nagle_disabled(pcb);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
altcp_tcp_setprio(struct altcp_pcb *conn, u8_t prio)
|
||||
{
|
||||
if (conn != NULL) {
|
||||
struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
|
||||
ALTCP_TCP_ASSERT_CONN(conn);
|
||||
tcp_setprio(pcb, prio);
|
||||
}
|
||||
}
|
||||
|
||||
#if LWIP_TCP_KEEPALIVE
|
||||
static void
|
||||
altcp_tcp_keepalive_disable(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn && conn->state) {
|
||||
struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
|
||||
ALTCP_TCP_ASSERT_CONN(conn);
|
||||
ip_reset_option(pcb, SOF_KEEPALIVE);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
altcp_tcp_keepalive_enable(struct altcp_pcb *conn, u32_t idle, u32_t intvl, u32_t cnt)
|
||||
{
|
||||
if (conn && conn->state) {
|
||||
struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
|
||||
ALTCP_TCP_ASSERT_CONN(conn);
|
||||
ip_set_option(pcb, SOF_KEEPALIVE);
|
||||
pcb->keep_idle = idle ? idle : TCP_KEEPIDLE_DEFAULT;
|
||||
pcb->keep_intvl = intvl ? intvl : TCP_KEEPINTVL_DEFAULT;
|
||||
pcb->keep_cnt = cnt ? cnt : TCP_KEEPCNT_DEFAULT;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
altcp_tcp_dealloc(struct altcp_pcb *conn)
|
||||
{
|
||||
LWIP_UNUSED_ARG(conn);
|
||||
ALTCP_TCP_ASSERT_CONN(conn);
|
||||
/* no private state to clean up */
|
||||
}
|
||||
|
||||
static err_t
|
||||
altcp_tcp_get_tcp_addrinfo(struct altcp_pcb *conn, int local, ip_addr_t *addr, u16_t *port)
|
||||
{
|
||||
if (conn) {
|
||||
struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
|
||||
ALTCP_TCP_ASSERT_CONN(conn);
|
||||
return tcp_tcp_get_tcp_addrinfo(pcb, local, addr, port);
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
static ip_addr_t *
|
||||
altcp_tcp_get_ip(struct altcp_pcb *conn, int local)
|
||||
{
|
||||
if (conn) {
|
||||
struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
|
||||
ALTCP_TCP_ASSERT_CONN(conn);
|
||||
if (pcb) {
|
||||
if (local) {
|
||||
return &pcb->local_ip;
|
||||
} else {
|
||||
return &pcb->remote_ip;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static u16_t
|
||||
altcp_tcp_get_port(struct altcp_pcb *conn, int local)
|
||||
{
|
||||
if (conn) {
|
||||
struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
|
||||
ALTCP_TCP_ASSERT_CONN(conn);
|
||||
if (pcb) {
|
||||
if (local) {
|
||||
return pcb->local_port;
|
||||
} else {
|
||||
return pcb->remote_port;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef LWIP_DEBUG
|
||||
static enum tcp_state
|
||||
altcp_tcp_dbg_get_tcp_state(struct altcp_pcb *conn)
|
||||
{
|
||||
if (conn) {
|
||||
struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
|
||||
ALTCP_TCP_ASSERT_CONN(conn);
|
||||
if (pcb) {
|
||||
return pcb->state;
|
||||
}
|
||||
}
|
||||
return CLOSED;
|
||||
}
|
||||
#endif
|
||||
const struct altcp_functions altcp_tcp_functions = {
|
||||
altcp_tcp_set_poll,
|
||||
altcp_tcp_recved,
|
||||
altcp_tcp_bind,
|
||||
altcp_tcp_connect,
|
||||
altcp_tcp_listen,
|
||||
altcp_tcp_abort,
|
||||
altcp_tcp_close,
|
||||
altcp_tcp_shutdown,
|
||||
altcp_tcp_write,
|
||||
altcp_tcp_output,
|
||||
altcp_tcp_mss,
|
||||
altcp_tcp_sndbuf,
|
||||
altcp_tcp_sndqueuelen,
|
||||
altcp_tcp_nagle_disable,
|
||||
altcp_tcp_nagle_enable,
|
||||
altcp_tcp_nagle_disabled,
|
||||
altcp_tcp_setprio,
|
||||
altcp_tcp_dealloc,
|
||||
altcp_tcp_get_tcp_addrinfo,
|
||||
altcp_tcp_get_ip,
|
||||
altcp_tcp_get_port
|
||||
#if LWIP_TCP_KEEPALIVE
|
||||
, altcp_tcp_keepalive_disable
|
||||
, altcp_tcp_keepalive_enable
|
||||
#endif
|
||||
#ifdef LWIP_DEBUG
|
||||
, altcp_tcp_dbg_get_tcp_state
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* LWIP_ALTCP */
|
||||
@@ -11,7 +11,7 @@
|
||||
* \#define lwip_htonl(x) your_htonl
|
||||
*
|
||||
* Note lwip_ntohs() and lwip_ntohl() are merely references to the htonx counterparts.
|
||||
*
|
||||
*
|
||||
* If you \#define them to htons() and htonl(), you should
|
||||
* \#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS to prevent lwIP from
|
||||
* defining htonx/ntohx compatibility macros.
|
||||
@@ -20,6 +20,10 @@
|
||||
* @ingroup sys_layer
|
||||
* lwIP provides default implementations for non-standard functions.
|
||||
* These can be mapped to OS functions to reduce code footprint if desired.
|
||||
* All defines related to this section must not be placed in lwipopts.h,
|
||||
* but in arch/cc.h!
|
||||
* These options cannot be \#defined in lwipopts.h since they are not options
|
||||
* of lwIP itself, but options of the lwIP port to your system.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -71,7 +75,7 @@
|
||||
u16_t
|
||||
lwip_htons(u16_t n)
|
||||
{
|
||||
return (u16_t)PP_HTONS(n);
|
||||
return PP_HTONS(n);
|
||||
}
|
||||
#endif /* lwip_htons */
|
||||
|
||||
@@ -85,7 +89,7 @@ lwip_htons(u16_t n)
|
||||
u32_t
|
||||
lwip_htonl(u32_t n)
|
||||
{
|
||||
return (u32_t)PP_HTONL(n);
|
||||
return PP_HTONL(n);
|
||||
}
|
||||
#endif /* lwip_htonl */
|
||||
|
||||
@@ -97,17 +101,17 @@ lwip_htonl(u32_t n)
|
||||
* lwIP default implementation for strnstr() non-standard function.
|
||||
* This can be \#defined to strnstr() depending on your platform port.
|
||||
*/
|
||||
char*
|
||||
lwip_strnstr(const char* buffer, const char* token, size_t n)
|
||||
char *
|
||||
lwip_strnstr(const char *buffer, const char *token, size_t n)
|
||||
{
|
||||
const char* p;
|
||||
int tokenlen = (int)strlen(token);
|
||||
const char *p;
|
||||
size_t tokenlen = strlen(token);
|
||||
if (tokenlen == 0) {
|
||||
return (char *)(size_t)buffer;
|
||||
return LWIP_CONST_CAST(char *, buffer);
|
||||
}
|
||||
for (p = buffer; *p && (p + tokenlen <= buffer + n); p++) {
|
||||
if ((*p == *token) && (strncmp(p, token, tokenlen) == 0)) {
|
||||
return (char *)(size_t)p;
|
||||
return LWIP_CONST_CAST(char *, p);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
@@ -121,7 +125,7 @@ lwip_strnstr(const char* buffer, const char* token, size_t n)
|
||||
* This can be \#defined to stricmp() depending on your platform port.
|
||||
*/
|
||||
int
|
||||
lwip_stricmp(const char* str1, const char* str2)
|
||||
lwip_stricmp(const char *str1, const char *str2)
|
||||
{
|
||||
char c1, c2;
|
||||
|
||||
@@ -156,7 +160,7 @@ lwip_stricmp(const char* str1, const char* str2)
|
||||
* This can be \#defined to strnicmp() depending on your platform port.
|
||||
*/
|
||||
int
|
||||
lwip_strnicmp(const char* str1, const char* str2, size_t len)
|
||||
lwip_strnicmp(const char *str1, const char *str2, size_t len)
|
||||
{
|
||||
char c1, c2;
|
||||
|
||||
@@ -179,7 +183,8 @@ lwip_strnicmp(const char* str1, const char* str2, size_t len)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
} while (len-- && c1 != 0);
|
||||
len--;
|
||||
} while ((len != 0) && (c1 != 0));
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -191,28 +196,45 @@ lwip_strnicmp(const char* str1, const char* str2, size_t len)
|
||||
* This can be \#defined to itoa() or snprintf(result, bufsize, "%d", number) depending on your platform port.
|
||||
*/
|
||||
void
|
||||
lwip_itoa(char* result, size_t bufsize, int number)
|
||||
lwip_itoa(char *result, size_t bufsize, int number)
|
||||
{
|
||||
const int base = 10;
|
||||
char* ptr = result, *ptr1 = result, tmp_char;
|
||||
int tmp_value;
|
||||
LWIP_UNUSED_ARG(bufsize);
|
||||
char *res = result;
|
||||
char *tmp = result + bufsize - 1;
|
||||
int n = (number >= 0) ? number : -number;
|
||||
|
||||
do {
|
||||
tmp_value = number;
|
||||
number /= base;
|
||||
*ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"[35 + (tmp_value - number * base)];
|
||||
} while(number);
|
||||
/* handle invalid bufsize */
|
||||
if (bufsize < 2) {
|
||||
if (bufsize == 1) {
|
||||
*result = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Apply negative sign */
|
||||
if (tmp_value < 0) {
|
||||
*ptr++ = '-';
|
||||
/* First, add sign */
|
||||
if (number < 0) {
|
||||
*res++ = '-';
|
||||
}
|
||||
*ptr-- = '\0';
|
||||
while(ptr1 < ptr) {
|
||||
tmp_char = *ptr;
|
||||
*ptr--= *ptr1;
|
||||
*ptr1++ = tmp_char;
|
||||
/* Then create the string from the end and stop if buffer full,
|
||||
and ensure output string is zero terminated */
|
||||
*tmp = 0;
|
||||
while ((n != 0) && (tmp > res)) {
|
||||
char val = (char)('0' + (n % 10));
|
||||
tmp--;
|
||||
*tmp = val;
|
||||
n = n / 10;
|
||||
}
|
||||
if (n) {
|
||||
/* buffer is too small */
|
||||
*result = 0;
|
||||
return;
|
||||
}
|
||||
if (*tmp == 0) {
|
||||
/* Nothing added? */
|
||||
*res++ = '0';
|
||||
*res++ = 0;
|
||||
return;
|
||||
}
|
||||
/* move from temporary buffer to output buffer (sign is not moved) */
|
||||
memmove(res, tmp, (size_t)((result + bufsize) - tmp));
|
||||
}
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user