Compare commits
4208 Commits
STABLE-1_4
...
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 | ||
|
|
d5dd5241e7 | ||
|
|
c4eb52dcff | ||
|
|
1e6c4ac017 | ||
|
|
b978d17ca0 | ||
|
|
dde55c6c0e | ||
|
|
5d22679c67 | ||
|
|
132dafa3fc | ||
|
|
54d76ffd6d | ||
|
|
b6f32caaad | ||
|
|
1c9e603299 | ||
|
|
1a7ba24d13 | ||
|
|
d4384cfac4 | ||
|
|
a82ec4499f | ||
|
|
7d8989e3ea | ||
|
|
5079e4552c | ||
|
|
e040132d92 | ||
|
|
760281207e | ||
|
|
20fde0be6c | ||
|
|
67895e7bdd | ||
|
|
801f26ee0c | ||
|
|
4dffe521a3 | ||
|
|
f5f8ab5acf | ||
|
|
e3a9f01fe4 | ||
|
|
37d5691b19 | ||
|
|
725feb0d4a | ||
|
|
6edde498e3 | ||
|
|
d5bfec2e52 | ||
|
|
576f49ee2b | ||
|
|
697be5c2c3 | ||
|
|
c9cfbe27c1 | ||
|
|
0a343948d9 | ||
|
|
ed239c4e71 | ||
|
|
695c81762c | ||
|
|
f6e27940bd | ||
|
|
9cd555c51a | ||
|
|
4e74ae4bc9 | ||
|
|
5477aa5a42 | ||
|
|
70ccea9207 | ||
|
|
69be49fdc3 | ||
|
|
740182de3c | ||
|
|
ad3530ee10 | ||
|
|
86a92543de | ||
|
|
2afc2a52d5 | ||
|
|
a1c0a0185b | ||
|
|
05419912e0 | ||
|
|
13fb616bb2 | ||
|
|
0c06073819 | ||
|
|
50e09ccd2c | ||
|
|
fa211096c2 | ||
|
|
87172d6d35 | ||
|
|
60a507f88b | ||
|
|
0d7805a86a | ||
|
|
9ba9dee2aa | ||
|
|
95754ba95a | ||
|
|
bef7873042 | ||
|
|
ec236da972 | ||
|
|
ee27daffc4 | ||
|
|
cdc97d2779 | ||
|
|
d9c6badc55 | ||
|
|
30251b1404 | ||
|
|
d1ed89b2e4 | ||
|
|
81549578bf | ||
|
|
f8683499a6 | ||
|
|
1e5efee7cb | ||
|
|
b040544628 | ||
|
|
eb77c839fc | ||
|
|
5e15125b3d | ||
|
|
8f8f56914b | ||
|
|
b33070e0cf | ||
|
|
8c52afb6ca | ||
|
|
df5a79966d | ||
|
|
d7f8d33506 | ||
|
|
db9c866fff | ||
|
|
149701b347 | ||
|
|
682b82aad8 | ||
|
|
65796cd827 | ||
|
|
40846260b5 | ||
|
|
af04864094 | ||
|
|
5ddd2aef4b | ||
|
|
17e6c9dd02 | ||
|
|
0e7f48d81c | ||
|
|
461b3531c7 | ||
|
|
4144d54642 | ||
|
|
837b7b3f98 | ||
|
|
1f68b32485 | ||
|
|
f8d19e28de | ||
|
|
f3cec74bd6 | ||
|
|
87e815030c | ||
|
|
78498981e2 | ||
|
|
633696c153 | ||
|
|
0e2354e658 | ||
|
|
5d811d799c | ||
|
|
6abcd00f71 | ||
|
|
97b774ceb9 | ||
|
|
2f085aa441 | ||
|
|
354e385453 | ||
|
|
c7c6b7ce93 | ||
|
|
c25de8f317 | ||
|
|
c9bae5ea9b | ||
|
|
dbd847b70c | ||
|
|
19e2780656 | ||
|
|
eb3a08308d | ||
|
|
470dae613e | ||
|
|
22907c7b27 | ||
|
|
623f9ce046 | ||
|
|
4d4710dadf | ||
|
|
2facd2d64d | ||
|
|
ee4cd45c98 | ||
|
|
58c8e0f8ca | ||
|
|
8dbd1abdc4 | ||
|
|
ef0dc65515 | ||
|
|
8cd43a3dd9 | ||
|
|
4a73bcbc65 | ||
|
|
f38705c38c | ||
|
|
b7c2553b46 | ||
|
|
f8a95aa27f | ||
|
|
d66442ba91 | ||
|
|
aeae4e91db | ||
|
|
34682facd1 | ||
|
|
ac6b64cf66 | ||
|
|
b944ceb89d | ||
|
|
ab8a1a0430 | ||
|
|
4325aca0f7 | ||
|
|
23147b0e21 | ||
|
|
9078f31544 | ||
|
|
a08ed9148d | ||
|
|
8d45162a59 | ||
|
|
f5135b05d9 | ||
|
|
2137f49d32 | ||
|
|
aef3d2cb87 | ||
|
|
840d1e60fa | ||
|
|
198fa5dbfa | ||
|
|
ef827e85b8 | ||
|
|
e545262d98 | ||
|
|
fb62e9350f | ||
|
|
db6aa82a10 | ||
|
|
c9dff6b5aa | ||
|
|
4b45baee10 | ||
|
|
05a6d82fa1 | ||
|
|
0d510dd66d | ||
|
|
537bd836c9 | ||
|
|
57468b8a30 | ||
|
|
452f5d6296 | ||
|
|
2980a12373 | ||
|
|
89aa4e7d79 | ||
|
|
3e23eb764b | ||
|
|
aeb3834219 | ||
|
|
475d49440c | ||
|
|
a2ca85a260 | ||
|
|
4c390ad39c | ||
|
|
a1db05c11e | ||
|
|
bf5866b27d | ||
|
|
298ec340e5 | ||
|
|
1ba0e17157 | ||
|
|
43ddf6eee6 | ||
|
|
8426dfa14d | ||
|
|
6fc7f84497 | ||
|
|
831b7fc7d3 | ||
|
|
d9b0236525 | ||
|
|
e78bc41116 | ||
|
|
c719c466b3 | ||
|
|
31778193da | ||
|
|
6caa7b9927 | ||
|
|
979bee386c | ||
|
|
d2f52e19d5 | ||
|
|
56dc574bed | ||
|
|
e4c74109cd | ||
|
|
fd5b34ae43 | ||
|
|
306171c93b | ||
|
|
d99d91dae9 | ||
|
|
fc54556d80 | ||
|
|
0d5eea288c | ||
|
|
4456c7d230 | ||
|
|
f170dde1c6 | ||
|
|
bae4d6398c | ||
|
|
18136c047b | ||
|
|
d9eaf6f310 | ||
|
|
42c193821c | ||
|
|
1c5c96a50a | ||
|
|
40f2bed5c4 | ||
|
|
21c99b6ebb | ||
|
|
a032ccafe7 | ||
|
|
4f4d16260f | ||
|
|
6b1e1af3d1 | ||
|
|
b3bae1b44c | ||
|
|
730080f20e | ||
|
|
a189941da6 | ||
|
|
f93a6e3310 | ||
|
|
5e36815867 | ||
|
|
01d8e5013f | ||
|
|
6688033bc4 | ||
|
|
ed566cceaa | ||
|
|
55d05092ef | ||
|
|
0e9ef19cfb | ||
|
|
fefb782bfe | ||
|
|
12609c951c | ||
|
|
64f79e7ffc | ||
|
|
ebd1bf8a49 | ||
|
|
4a7dafc6a6 | ||
|
|
1e6f33d44b | ||
|
|
96c3c48ba7 | ||
|
|
14fb48cd7a | ||
|
|
9725a496b5 | ||
|
|
967516aa40 | ||
|
|
e844159f0a | ||
|
|
11386a26d9 | ||
|
|
8eb9db18a2 | ||
|
|
43d6812b3e | ||
|
|
7c0d952379 | ||
|
|
c4e3be814f | ||
|
|
ad357a4c89 | ||
|
|
2d503f4433 | ||
|
|
5df88220c4 | ||
|
|
458211c2af | ||
|
|
84e139f20c | ||
|
|
81c68f529b | ||
|
|
f299b4b7cf | ||
|
|
8d68400387 | ||
|
|
d89fa2dcbc | ||
|
|
16293125a6 | ||
|
|
e24fde05db | ||
|
|
ef31afb921 | ||
|
|
a8c8e08984 | ||
|
|
97fae7e41b | ||
|
|
7f60cb3889 | ||
|
|
ebf7959880 | ||
|
|
0c7a59b5db | ||
|
|
c9ad58308a | ||
|
|
a262a2f252 | ||
|
|
fa6a2d48cc | ||
|
|
c62bfd8146 | ||
|
|
1db9631e7d | ||
|
|
c8c804140d | ||
|
|
ee815e4e7a | ||
|
|
c28fb298b7 | ||
|
|
93b286e508 | ||
|
|
2a90f33757 | ||
|
|
efb7b3d5f8 | ||
|
|
02d51e3ac5 | ||
|
|
fec657bb38 | ||
|
|
858287fc3a | ||
|
|
af6b707e9a | ||
|
|
ab72ed8517 | ||
|
|
482a4d2ce9 | ||
|
|
c61c8f3766 | ||
|
|
af48bec63c | ||
|
|
39ac8e2c57 | ||
|
|
52449e12c0 | ||
|
|
2335c1a73c | ||
|
|
ebe0e6f98d | ||
|
|
4d85def20a | ||
|
|
b472648e40 | ||
|
|
a2894ede1c | ||
|
|
306113c8c3 | ||
|
|
4919932c49 | ||
|
|
4af297fc20 | ||
|
|
4e1f8effaf | ||
|
|
5493220c93 | ||
|
|
ce6ea0df15 | ||
|
|
6dcb2b2415 | ||
|
|
36b9caed23 | ||
|
|
13251526fa | ||
|
|
b34baff546 | ||
|
|
6f62fe5998 | ||
|
|
dc7340bbd5 | ||
|
|
d95ab511d0 | ||
|
|
bf3e8e6a48 | ||
|
|
3194c9c4cf | ||
|
|
18fcc1d504 | ||
|
|
5c0944e01a | ||
|
|
5a09fd3e35 | ||
|
|
0005b7c2d0 | ||
|
|
6ba03d543f | ||
|
|
61dae47a71 | ||
|
|
85ab39985a | ||
|
|
e5284ec616 | ||
|
|
4b41ef551e | ||
|
|
a2fd68098e | ||
|
|
1631307bb3 | ||
|
|
10332773ff | ||
|
|
fa568f7750 | ||
|
|
282b8a2b6c | ||
|
|
b1dfd00f92 | ||
|
|
eba6ae0122 | ||
|
|
219438fb24 | ||
|
|
e4c01a064e | ||
|
|
08378b7d4b | ||
|
|
fc66fb830c | ||
|
|
fa8797b86d | ||
|
|
953dd5b628 | ||
|
|
455a41822e | ||
|
|
1ea1026961 | ||
|
|
09c22e13fe | ||
|
|
7c02a85424 | ||
|
|
d15ebc6a4c | ||
|
|
f185104ac6 | ||
|
|
5811948b0a | ||
|
|
dd0779c204 | ||
|
|
898e69118a | ||
|
|
f55c0e7864 | ||
|
|
3ca4eb5cd8 | ||
|
|
6af213787a | ||
|
|
0a7db8a9a5 | ||
|
|
0673fcdb44 | ||
|
|
980a919c9a | ||
|
|
8d07629b71 | ||
|
|
cf66233873 | ||
|
|
b94c8ee76f | ||
|
|
73131b1677 | ||
|
|
87855b0e0e | ||
|
|
2acfa0ebe7 | ||
|
|
a20cdc597a | ||
|
|
70ee63ef3d | ||
|
|
c2a5480ac7 | ||
|
|
01561b26ef | ||
|
|
9b47b6393b | ||
|
|
e8d8c5dcc9 | ||
|
|
bae67915ab | ||
|
|
5f774270b6 | ||
|
|
02221cf5dc | ||
|
|
6383ef88b4 | ||
|
|
dd110309e5 | ||
|
|
4c06a737a4 | ||
|
|
da83946e75 | ||
|
|
3d379c97ec | ||
|
|
018294d287 | ||
|
|
247d2e97a0 | ||
|
|
92f385aaed | ||
|
|
2f7e6d0661 | ||
|
|
e4d75a75ea | ||
|
|
501cfbe02b | ||
|
|
a7979d7d24 | ||
|
|
52d6d696ae | ||
|
|
e76b8b2551 | ||
|
|
d00609257b | ||
|
|
6cc7f38c99 | ||
|
|
2c2d11fa4d | ||
|
|
4cb7e31d2d | ||
|
|
0c7d015ec4 | ||
|
|
4b67c582f6 | ||
|
|
5f9c944da4 | ||
|
|
b7da649944 | ||
|
|
90fba8773f | ||
|
|
3f0dae29e9 | ||
|
|
9fb9033815 | ||
|
|
8c620d9206 | ||
|
|
b4efa33b7c | ||
|
|
71dc8f8f53 | ||
|
|
161ee4f4b2 | ||
|
|
eac1005c9c | ||
|
|
b0284a6927 | ||
|
|
bdaec1691e | ||
|
|
5bcaefddd4 | ||
|
|
f7e12d835c | ||
|
|
93ad162aa6 | ||
|
|
f322e782f8 | ||
|
|
23cf45d252 | ||
|
|
56102c1b1c | ||
|
|
53dc94d570 | ||
|
|
a326b057b3 | ||
|
|
1bb2539f74 | ||
|
|
b14032c531 | ||
|
|
70927892e1 | ||
|
|
0e6f2049ad | ||
|
|
b2b1ec14f5 | ||
|
|
a39c040571 | ||
|
|
fb7998699d | ||
|
|
d89378e3f8 | ||
|
|
63fdb3bb62 | ||
|
|
31f941e172 | ||
|
|
8ece46d5d2 | ||
|
|
0cb1d1144d | ||
|
|
aece68639a | ||
|
|
eb3261d6e0 | ||
|
|
9305bf2ace | ||
|
|
0b5c393361 | ||
|
|
6c7eef7ac0 | ||
|
|
ef5c1b6590 | ||
|
|
fc7aa7a247 | ||
|
|
ccc830c99c | ||
|
|
af97f9b239 | ||
|
|
6618189342 | ||
|
|
6b524367a3 | ||
|
|
1993b0257c | ||
|
|
6bce7509f7 | ||
|
|
7e4d934f7a | ||
|
|
4a7d07a2e0 | ||
|
|
765181a97c | ||
|
|
7b770dd9b6 | ||
|
|
7f43fcab71 | ||
|
|
c7e20150f0 | ||
|
|
c6831648e2 | ||
|
|
8a9de94b1f | ||
|
|
8140c77d7d | ||
|
|
67d674a59c | ||
|
|
dc0859b8d1 | ||
|
|
9c10daba93 | ||
|
|
0fea2bc02e | ||
|
|
ce19c59bb2 | ||
|
|
8643782e5d | ||
|
|
bd79f6c055 | ||
|
|
40bc80b551 | ||
|
|
e030118750 | ||
|
|
59295be4ef | ||
|
|
10acd8303d | ||
|
|
73ee4cbbf7 | ||
|
|
f6468510c6 | ||
|
|
a62e4452a2 | ||
|
|
168ad22761 | ||
|
|
fb75f48751 | ||
|
|
ca71eea56f | ||
|
|
00598b0b46 | ||
|
|
4f5ff37c5d | ||
|
|
80be1a6bf8 | ||
|
|
d75ece2505 | ||
|
|
28dd0813ab | ||
|
|
194d624077 | ||
|
|
de9054cb7a | ||
|
|
413eeef5fa | ||
|
|
6e6ce4fb78 | ||
|
|
f98c3dd4b5 | ||
|
|
806298583b | ||
|
|
764343ebc7 | ||
|
|
523b11e664 | ||
|
|
d43c092f17 | ||
|
|
9cc3fb2e63 | ||
|
|
802a4f2a14 | ||
|
|
3ad2ad2329 | ||
|
|
299a19e135 | ||
|
|
e8ffac852e | ||
|
|
98d58ffd59 | ||
|
|
97b8e88e69 | ||
|
|
24a339a609 | ||
|
|
86e419425b | ||
|
|
d0a79ff085 | ||
|
|
dff46e3816 | ||
|
|
b06f14c11f | ||
|
|
579fffd2ec | ||
|
|
5d4c1432c2 | ||
|
|
6adeb706a6 | ||
|
|
c641ae3d3d | ||
|
|
72208cddfa | ||
|
|
7037b340c1 | ||
|
|
06c7404461 | ||
|
|
6c0d78caaa | ||
|
|
4ec3d29168 | ||
|
|
09636c5b92 | ||
|
|
cb99ca099e | ||
|
|
2f950a7dcc | ||
|
|
a324c7a8e4 | ||
|
|
4ea1d62d45 | ||
|
|
421dab87e8 | ||
|
|
01e5d6d819 | ||
|
|
18c332ae51 | ||
|
|
9a355502e1 | ||
|
|
52da49cd81 | ||
|
|
288fc8ede3 | ||
|
|
6293a835e9 | ||
|
|
6af4215f27 | ||
|
|
2df636fe77 | ||
|
|
e302b1bbd2 | ||
|
|
c483520081 | ||
|
|
959042aa88 | ||
|
|
a463119597 | ||
|
|
e0918d706e | ||
|
|
b939e9536d | ||
|
|
e9b0003085 | ||
|
|
087ecab891 | ||
|
|
212eacd9d6 | ||
|
|
dcd52510ce | ||
|
|
98e92f6550 | ||
|
|
b91e47b518 | ||
|
|
811b237bd7 | ||
|
|
7e3de89646 | ||
|
|
4b136d631a | ||
|
|
5a1b9bf808 | ||
|
|
14ca418ac0 | ||
|
|
cb5f7859fd | ||
|
|
2fdea8b79b | ||
|
|
2e26fc9224 | ||
|
|
fd83f4fb22 | ||
|
|
d362e167c0 | ||
|
|
a12c149093 | ||
|
|
afa2a96085 | ||
|
|
9d0546839c | ||
|
|
28aaf2caf4 | ||
|
|
40e9eae791 | ||
|
|
f0dbba6406 | ||
|
|
a99fe1fa32 | ||
|
|
e7069d6e82 | ||
|
|
b97c4d96e2 | ||
|
|
f21aede031 | ||
|
|
c1c3d0e1ba | ||
|
|
50b5b4c4dd | ||
|
|
b9b36084a5 | ||
|
|
f226e107a6 | ||
|
|
d4f824398c | ||
|
|
b438a0d6fd | ||
|
|
7c368b7f36 | ||
|
|
06782c699c | ||
|
|
42dfa71f97 | ||
|
|
d3e55185c6 | ||
|
|
e6bc591a1e | ||
|
|
d31d2ee882 | ||
|
|
91b5d8ad1e | ||
|
|
aecbefc728 | ||
|
|
ecbe45bf43 | ||
|
|
a0e8c2dd8f | ||
|
|
500e748888 | ||
|
|
4047702928 | ||
|
|
5d356c96f5 | ||
|
|
39545d2c6d | ||
|
|
e40175ef05 | ||
|
|
2d7a6a5d94 | ||
|
|
c164869f6d | ||
|
|
236bc19422 | ||
|
|
ddac5b1895 | ||
|
|
9a70715371 | ||
|
|
96296947fc | ||
|
|
8b9886bfe2 | ||
|
|
9015c28406 | ||
|
|
b77fcef1a5 | ||
|
|
6fb074874b | ||
|
|
3d684cda23 | ||
|
|
71ca26b212 | ||
|
|
4a5422cd11 | ||
|
|
38c0255fa2 | ||
|
|
102f5882d5 | ||
|
|
19e2b15c41 | ||
|
|
a929f418e7 | ||
|
|
0116c3cd76 | ||
|
|
2c1bd363e6 | ||
|
|
efd3fb8f4e | ||
|
|
94e502fc8a | ||
|
|
224d5a9f33 | ||
|
|
d133999e1d | ||
|
|
98c741976b | ||
|
|
502f08cb92 | ||
|
|
1af40e7de2 | ||
|
|
75c5829a57 | ||
|
|
8dc77ef558 | ||
|
|
cfe5182380 | ||
|
|
2040f4f0b1 | ||
|
|
7b4bd3343b | ||
|
|
1d108b400f | ||
|
|
42d50eba4e | ||
|
|
7df5496e7b | ||
|
|
c751802fad | ||
|
|
6d95a34971 | ||
|
|
61e067b98a | ||
|
|
fda778f6b6 | ||
|
|
d98e25a783 | ||
|
|
4e241fbf14 | ||
|
|
b9a2ee8aaa | ||
|
|
25652254a5 | ||
|
|
5e7b343d52 | ||
|
|
606b6990ff | ||
|
|
270378387c | ||
|
|
9ddde3ef4a | ||
|
|
5a056cc861 | ||
|
|
5d9f59daa4 | ||
|
|
076f1ee89e | ||
|
|
010b0e2972 | ||
|
|
952da88b84 | ||
|
|
9be133777b | ||
|
|
6be7e221a5 | ||
|
|
a364427ae5 | ||
|
|
451277e7f0 | ||
|
|
51f3cdfd5a | ||
|
|
344de0e119 | ||
|
|
bfd3baa20e | ||
|
|
631c458c55 | ||
|
|
6c8c3fd48c | ||
|
|
90a656ed78 | ||
|
|
f4bf0dff85 | ||
|
|
59af802fb6 | ||
|
|
ebd103775d | ||
|
|
bd177ff38f | ||
|
|
ac21a5f370 | ||
|
|
ac0af0d7c7 | ||
|
|
8e7b8a32f9 | ||
|
|
ab989c3551 | ||
|
|
8c0f620d83 | ||
|
|
7e9377a9c7 | ||
|
|
9f69bf82df | ||
|
|
c6949d88d9 | ||
|
|
45c6279bb0 | ||
|
|
b9389c6eaf | ||
|
|
b08f73be44 | ||
|
|
33fc20cca2 | ||
|
|
5df4f70a96 | ||
|
|
9f3aff0cdf | ||
|
|
3417a02b25 | ||
|
|
1dcd5d31d7 | ||
|
|
73b8026cb9 | ||
|
|
fc2701ae03 | ||
|
|
4a6c444a17 | ||
|
|
05961a27cf | ||
|
|
93665a7659 | ||
|
|
49badf39a1 | ||
|
|
2e05856f90 | ||
|
|
30e6f908ee | ||
|
|
e653ac9db7 | ||
|
|
21354af674 | ||
|
|
c981b726f8 | ||
|
|
21e6e1c824 | ||
|
|
b07031479c | ||
|
|
475be665ff | ||
|
|
3d38af5174 | ||
|
|
b28a80375b | ||
|
|
a5d4a27ae1 | ||
|
|
afd9ee9147 | ||
|
|
afd1bb938e | ||
|
|
025d5591eb | ||
|
|
7d77a52ea5 | ||
|
|
2b5250dd9d | ||
|
|
8ce49499ae | ||
|
|
5a123a3405 | ||
|
|
0d0b935d3d | ||
|
|
2be86fbc3e | ||
|
|
bb908366a5 | ||
|
|
73d8f14ebd | ||
|
|
ffa340a68c | ||
|
|
b8b83c2994 | ||
|
|
4d1a2e6699 | ||
|
|
15fbfb7363 | ||
|
|
54f7cae12c | ||
|
|
76d25befb4 | ||
|
|
749f7fae1a | ||
|
|
61d07f88f0 | ||
|
|
8ac1b4825a | ||
|
|
87354abf0f | ||
|
|
0b6370b9b8 | ||
|
|
92f5da8412 | ||
|
|
309e072238 | ||
|
|
ab2c65549d | ||
|
|
ca1b8288de | ||
|
|
8c7f513f4d | ||
|
|
16c70dd60e | ||
|
|
03e9c88488 | ||
|
|
0731eda0b3 | ||
|
|
083c6123d6 | ||
|
|
12a4cae404 | ||
|
|
3a26e8b6cc | ||
|
|
28652d4d51 | ||
|
|
b67427bd3b | ||
|
|
3a7c998f91 | ||
|
|
141aeaab3d | ||
|
|
c8b65f6c1d | ||
|
|
d70d9bf866 | ||
|
|
4bd57882b0 | ||
|
|
52fdc6bb3e | ||
|
|
d0c3baf340 | ||
|
|
6f43057662 | ||
|
|
d8784a77b7 | ||
|
|
27f03798b9 | ||
|
|
5b0a47ca87 | ||
|
|
9b0a0841e9 | ||
|
|
0b4bc5ea31 | ||
|
|
cab341976e | ||
|
|
52a3bf5d43 | ||
|
|
63c2dc926e | ||
|
|
cc477361ad | ||
|
|
377885581f | ||
|
|
7321420d8c | ||
|
|
9466d64a9a | ||
|
|
d929a4b17e | ||
|
|
945607e094 | ||
|
|
7721b20179 | ||
|
|
c6b742812d | ||
|
|
85d5fbdc7f | ||
|
|
449fc98a55 | ||
|
|
7e7f2f31ff | ||
|
|
a1fc91afa8 | ||
|
|
c39ef75cb3 | ||
|
|
7bda462031 | ||
|
|
f97bf85fd6 | ||
|
|
a9c7ead6b7 | ||
|
|
dd80759bb9 | ||
|
|
a1c78ea7bf | ||
|
|
5794ac2340 | ||
|
|
44e1a2d8e2 | ||
|
|
3a62a45bcd | ||
|
|
149bb36805 | ||
|
|
93ccba9bcb | ||
|
|
b24e5cd1c8 | ||
|
|
7fbb5fc82a | ||
|
|
464a8c9794 | ||
|
|
7aea739f87 | ||
|
|
852d5b9c80 | ||
|
|
b4d7238eb8 | ||
|
|
ee87d28252 | ||
|
|
6ffe12cede | ||
|
|
d6adc1f6cb | ||
|
|
5f8b5cbb20 | ||
|
|
7b9cb98bbb | ||
|
|
222eb25eb5 | ||
|
|
dbfdb13166 | ||
|
|
d38cdccbcd | ||
|
|
2575c7fb5f | ||
|
|
ea174560b1 | ||
|
|
bc51dddcaf | ||
|
|
f09dec5fb7 | ||
|
|
8e8571da6a | ||
|
|
0d576aa521 | ||
|
|
0e1b401abe | ||
|
|
bf7fc41e0f | ||
|
|
90bc1da434 | ||
|
|
dc98e31e4d | ||
|
|
1d7996dc47 | ||
|
|
2b3db52c70 | ||
|
|
b65a22b32a | ||
|
|
b849e52c17 | ||
|
|
588b11185a | ||
|
|
dfc963880a | ||
|
|
00975769a0 | ||
|
|
f7a3d6cca5 | ||
|
|
8f71795844 | ||
|
|
8106413644 | ||
|
|
5e472badf1 | ||
|
|
2a2f92f7c2 | ||
|
|
f3b7bca3cf | ||
|
|
9fbf5a4004 | ||
|
|
5d637360cc | ||
|
|
7d8f0c781f | ||
|
|
a212210c35 | ||
|
|
ba40925335 | ||
|
|
eab92ccb03 | ||
|
|
fc17d02451 | ||
|
|
37d514c949 | ||
|
|
a4297ef0fd | ||
|
|
c65eca58c9 | ||
|
|
18bb74e5c5 | ||
|
|
af1978fa4e | ||
|
|
5cf802eda0 | ||
|
|
80cc988f2f | ||
|
|
076795562e | ||
|
|
f5fef6eebc | ||
|
|
375ec36246 | ||
|
|
b00a17059a | ||
|
|
bcab7fef84 | ||
|
|
d2bb569ee4 | ||
|
|
52b426a343 | ||
|
|
f4fbc90217 | ||
|
|
e0ab8c581d | ||
|
|
094cdf1c7b | ||
|
|
814577fcc6 | ||
|
|
15925b66c6 | ||
|
|
925b280fd2 | ||
|
|
6b405eccd0 | ||
|
|
15326cdbad | ||
|
|
bd0b51c9ef | ||
|
|
9a4c66006e | ||
|
|
1c52780b62 | ||
|
|
bee5515e9a | ||
|
|
0a7f404d09 | ||
|
|
1dea649cff | ||
|
|
7396d8818b | ||
|
|
2d80af1dcb | ||
|
|
b5cd90a342 | ||
|
|
5358380c5f | ||
|
|
eead3a7038 | ||
|
|
ce370ec48f | ||
|
|
24ebf6bd6f | ||
|
|
b0d4386744 | ||
|
|
0c673b6a44 | ||
|
|
e89b48d23f | ||
|
|
f9ce31f98b | ||
|
|
bd131e5e4b | ||
|
|
f3132c5290 | ||
|
|
babb247e2a | ||
|
|
cc4f94f415 | ||
|
|
9885d5d9f5 | ||
|
|
8e5663a32f | ||
|
|
4bbfc3857a | ||
|
|
5404ce3c0a | ||
|
|
2289673a30 | ||
|
|
6aed6e659f | ||
|
|
42c92f80f1 | ||
|
|
fa16ee8dcb | ||
|
|
70f3e5ed05 | ||
|
|
2dc8f59bf4 | ||
|
|
d5778bad2f | ||
|
|
81c8121551 | ||
|
|
97b7555119 | ||
|
|
a5214abd04 | ||
|
|
bf8bcfafe2 | ||
|
|
8cb64698aa | ||
|
|
163d7f9791 | ||
|
|
a649a3eb50 | ||
|
|
2a8398dfb8 | ||
|
|
fd891081c4 | ||
|
|
953b7bdd59 | ||
|
|
1dde3d6e56 | ||
|
|
ec49b68b38 | ||
|
|
68590c2b27 | ||
|
|
ac4b089b18 | ||
|
|
005c196ed8 | ||
|
|
3b5803ec9a | ||
|
|
fd4a109ffa | ||
|
|
481d350bf3 | ||
|
|
d121ea84d0 | ||
|
|
a5ac41c203 | ||
|
|
e4457335b8 | ||
|
|
680f8f31ab | ||
|
|
6650eb4cd2 | ||
|
|
799fe7a5ba | ||
|
|
9a4d7b9956 | ||
|
|
fe8d2ba72f | ||
|
|
e90591bb78 | ||
|
|
e2a3565971 | ||
|
|
aeab047ede | ||
|
|
777e667f08 | ||
|
|
fa6f068fd1 | ||
|
|
439ae629e0 | ||
|
|
17fad79f71 | ||
|
|
d8531a2407 | ||
|
|
c805843e64 | ||
|
|
880f1008d6 | ||
|
|
be9cd800b0 | ||
|
|
0106cf7ae0 | ||
|
|
50303eea23 | ||
|
|
339e82d7aa | ||
|
|
5a25652c21 | ||
|
|
8f675c37fc | ||
|
|
5809b01388 | ||
|
|
f104d68569 | ||
|
|
10edba936b | ||
|
|
bbb5e99f25 | ||
|
|
ea94549cb2 | ||
|
|
9a97a80efc | ||
|
|
e4cac595c2 | ||
|
|
cf3d7def33 | ||
|
|
24bc77a935 | ||
|
|
9dd1c81d41 | ||
|
|
cddd3b552a | ||
|
|
5aa5563622 | ||
|
|
09b850cc6f | ||
|
|
273d609bac | ||
|
|
288b4564e4 | ||
|
|
78a36df901 | ||
|
|
1c1587eef6 | ||
|
|
11b810721a | ||
|
|
e5eba61cf0 | ||
|
|
54a2c13b2e | ||
|
|
b2410e428a | ||
|
|
208f24a20c | ||
|
|
8cd33a5e41 | ||
|
|
905a434179 | ||
|
|
222155d7e2 | ||
|
|
28549e35fe | ||
|
|
8f6cfa8769 | ||
|
|
f411a34af5 | ||
|
|
1de8d432d4 | ||
|
|
515a4cad73 | ||
|
|
4beacc4ca0 | ||
|
|
9c7231ee75 | ||
|
|
e31902dc4c | ||
|
|
53853a25b0 | ||
|
|
858bce7b4e | ||
|
|
77d355560f | ||
|
|
733758a909 | ||
|
|
90df2111b7 | ||
|
|
31732631fc | ||
|
|
c4d78e6422 | ||
|
|
52463fa25b | ||
|
|
96373f6959 | ||
|
|
0a67c06b51 | ||
|
|
babce70c95 | ||
|
|
4cf509989f | ||
|
|
6185bf6f61 | ||
|
|
2c31beb6e7 | ||
|
|
9f3270afaf | ||
|
|
fe2cfe2dba | ||
|
|
1ee574944c | ||
|
|
80375e68dd | ||
|
|
289d1dd7f3 | ||
|
|
f2c7e9c939 | ||
|
|
dc36dbac27 | ||
|
|
d9534325cf | ||
|
|
c221361874 | ||
|
|
70ebeda7ed | ||
|
|
11faa8149e | ||
|
|
70487a43d4 | ||
|
|
a93ae2558f | ||
|
|
c2ba9129ad | ||
|
|
c2a74b767b | ||
|
|
123c8dbd6a | ||
|
|
40ff62fa60 | ||
|
|
84397ef013 | ||
|
|
a2b7cec17b | ||
|
|
e80e7a10d4 | ||
|
|
8c4d1909f4 | ||
|
|
bb8ecd7e08 | ||
|
|
a7e1c730b2 | ||
|
|
6f1fc6c403 | ||
|
|
9f3aab6a62 | ||
|
|
44256740bd | ||
|
|
156ad0dbf5 | ||
|
|
5056d375f2 | ||
|
|
b68e801975 | ||
|
|
987f0e3016 | ||
|
|
713deba83f | ||
|
|
b9d0d80946 | ||
|
|
84cd489d24 | ||
|
|
708beb4874 | ||
|
|
4e8574bd23 | ||
|
|
fbdfba2509 | ||
|
|
e033866651 | ||
|
|
76094b8c7e | ||
|
|
e336f877c2 | ||
|
|
7f699b36ff | ||
|
|
e041b9a51c | ||
|
|
0a222a2ff7 | ||
|
|
031de097db | ||
|
|
d4361fc7d7 | ||
|
|
44617bfa9b | ||
|
|
6352106aaa | ||
|
|
7412a0e74e | ||
|
|
19d17adcfb | ||
|
|
e1e7a704e1 | ||
|
|
19dd6c391f | ||
|
|
c5cab4e719 | ||
|
|
b48f6d1405 | ||
|
|
c466f8824f | ||
|
|
2b16cd93bf | ||
|
|
0c39165701 | ||
|
|
9d1234d83a | ||
|
|
dfaa979b99 | ||
|
|
611966de63 | ||
|
|
4341df4094 | ||
|
|
83f8ec1397 | ||
|
|
fdd98879bf | ||
|
|
406f707d9a | ||
|
|
5e34b8736a | ||
|
|
7b946fa9b1 | ||
|
|
0178d1d2ee | ||
|
|
0c06f09d6d | ||
|
|
a82c6122d5 | ||
|
|
2e56f2d780 | ||
|
|
2562d637cd | ||
|
|
f69b1841e0 | ||
|
|
a3bccae173 | ||
|
|
a21144b834 | ||
|
|
7f92660598 | ||
|
|
3b60c855e1 | ||
|
|
a709041b8b | ||
|
|
8bb27ba8c4 | ||
|
|
bd4c4b5959 | ||
|
|
fb6d0f9006 | ||
|
|
6e863ecb50 | ||
|
|
764bf251cd | ||
|
|
91586bc6f6 | ||
|
|
f971fb921e | ||
|
|
c730e45f0c | ||
|
|
5c27429958 | ||
|
|
8010d6706e | ||
|
|
9c6708513a | ||
|
|
21b9b5e741 | ||
|
|
3f49b85680 | ||
|
|
65bb7a623c | ||
|
|
4293c1e138 | ||
|
|
b8e94ec066 | ||
|
|
e15872982e | ||
|
|
e4f7ddacb3 | ||
|
|
c69dede728 | ||
|
|
39370db55d | ||
|
|
73bb986737 | ||
|
|
98b9d31f24 | ||
|
|
ecf9d25ed0 | ||
|
|
668d461104 | ||
|
|
29553ba7a1 | ||
|
|
cacbd596c9 | ||
|
|
6203737093 | ||
|
|
5f642eb3e3 | ||
|
|
92a241a29e | ||
|
|
c838e1ed5b | ||
|
|
d38db89626 | ||
|
|
3f0b1e2cdc | ||
|
|
f518c6578c | ||
|
|
2dec8f449a | ||
|
|
1ef913cd36 | ||
|
|
affc6d61ca | ||
|
|
f278b27119 | ||
|
|
37bb0b89f0 | ||
|
|
02bddd251a | ||
|
|
c12fa7b4c4 | ||
|
|
b32751a693 | ||
|
|
fc1db87318 | ||
|
|
365f3fb651 | ||
|
|
a7ee681515 | ||
|
|
b02bcde8e0 | ||
|
|
bef5ccda0b | ||
|
|
a2cd2ae5a8 | ||
|
|
698e20a990 | ||
|
|
b6ad76fe1a | ||
|
|
22957a8082 | ||
|
|
8dfd5e82cb | ||
|
|
65efeec4e9 | ||
|
|
15bb334e81 | ||
|
|
77f906376e | ||
|
|
9b22f167f1 | ||
|
|
b401f42520 | ||
|
|
2949449e25 | ||
|
|
2b971400fa | ||
|
|
22df34fc70 | ||
|
|
490581a0eb | ||
|
|
0737cfb84e | ||
|
|
58895c3cf6 | ||
|
|
7fb832aa4e | ||
|
|
673c6505ae | ||
|
|
1fef434f01 | ||
|
|
495fc61a34 | ||
|
|
f80d0dab08 | ||
|
|
fb1ac8d766 | ||
|
|
bc47bd28ab | ||
|
|
5cf4771397 | ||
|
|
8891b277c6 | ||
|
|
e4abd4234d | ||
|
|
fe33fd6d86 | ||
|
|
bf75ace695 | ||
|
|
5b1b430403 | ||
|
|
424bd7e38c | ||
|
|
180ed573a5 | ||
|
|
a9b6b5b704 | ||
|
|
064d171332 | ||
|
|
30445712a5 | ||
|
|
91b6d45178 | ||
|
|
3312983b27 | ||
|
|
fecd1bde83 | ||
|
|
0176e03e36 | ||
|
|
8c35429ba3 | ||
|
|
9957cd4a2a | ||
|
|
ae7eeda88a | ||
|
|
3f4d75c8d6 | ||
|
|
1bcd361456 | ||
|
|
7962b21c00 | ||
|
|
59002d5081 | ||
|
|
ce883d2041 | ||
|
|
96847c1199 | ||
|
|
df1f12778f | ||
|
|
dff234112b | ||
|
|
e18e08ff08 | ||
|
|
f3ed562983 | ||
|
|
969fb4c981 | ||
|
|
82fcc307ef | ||
|
|
1fdab5ac0e | ||
|
|
389831218e | ||
|
|
7b5ef3ae58 | ||
|
|
9d28549f32 | ||
|
|
6cdea62638 | ||
|
|
3dd0977635 | ||
|
|
ba71ac78d9 | ||
|
|
373714c02f | ||
|
|
927b72abd2 | ||
|
|
f89e859415 | ||
|
|
dae73e21b8 | ||
|
|
f950bf4362 | ||
|
|
0621e8d1b1 | ||
|
|
5a185a0fbd | ||
|
|
45fd622491 | ||
|
|
5e7a74e2e7 | ||
|
|
94625a8fa8 | ||
|
|
dbe703cfb0 | ||
|
|
bc30899168 | ||
|
|
ce98bc9437 | ||
|
|
d39f929675 | ||
|
|
b589864144 | ||
|
|
9e0202b38f | ||
|
|
ba41685353 | ||
|
|
bb91bd2279 | ||
|
|
8b2c73de4e | ||
|
|
715d8d3881 | ||
|
|
5ad743e182 | ||
|
|
b0917d987a | ||
|
|
99d2e5233d | ||
|
|
e11e12f01d | ||
|
|
c71723101a | ||
|
|
262a641396 | ||
|
|
4d2f4ce78c | ||
|
|
51ce505d7d | ||
|
|
f85737bf29 | ||
|
|
ed4130bd2f | ||
|
|
0fbdd5e56e | ||
|
|
cc4d09423a | ||
|
|
db76671d4d | ||
|
|
05e6f06b62 | ||
|
|
f36adac8ab | ||
|
|
121268d320 | ||
|
|
e6b6543c33 | ||
|
|
e00e4a6c13 | ||
|
|
e588dfdbce | ||
|
|
2f40d19193 | ||
|
|
7a485b1a71 | ||
|
|
abc74464a0 | ||
|
|
9882dd5eff | ||
|
|
bb92a059b6 | ||
|
|
47a579f54f | ||
|
|
6746f1d13c | ||
|
|
74939c20c4 | ||
|
|
b9b31a5e72 | ||
|
|
8eab90418a | ||
|
|
83cddd8941 | ||
|
|
e8c0ba2a47 | ||
|
|
cb6adc643b | ||
|
|
0454950564 | ||
|
|
4f9bcc5ecc | ||
|
|
39e32ea7c1 | ||
|
|
2f3dcf7a16 | ||
|
|
6f0dceee09 | ||
|
|
9614c60cf6 | ||
|
|
cca758d332 | ||
|
|
52a4ca99a8 | ||
|
|
72b3f3f612 | ||
|
|
f62022cdf3 | ||
|
|
726af89168 | ||
|
|
c1c1754171 | ||
|
|
68a1ec2eb1 | ||
|
|
b85b554db1 | ||
|
|
dc04118469 | ||
|
|
7276f49f54 | ||
|
|
4704c9a0ad | ||
|
|
c15b357889 | ||
|
|
46204a9f86 | ||
|
|
5b07569eb9 | ||
|
|
b55412a0c4 | ||
|
|
81d3337681 | ||
|
|
41ee45d9f7 | ||
|
|
79e7201854 | ||
|
|
ddf899ad1e | ||
|
|
7702ed66a0 | ||
|
|
b8d7a2b8e6 | ||
|
|
8a0fb03e21 | ||
|
|
1e4f312352 | ||
|
|
77270adb96 | ||
|
|
42170e4e57 | ||
|
|
318ba1decd | ||
|
|
1fbbf0e837 | ||
|
|
6795590603 | ||
|
|
196120fabd | ||
|
|
dd3725a452 | ||
|
|
c8cd67c989 | ||
|
|
aea87a9a2f | ||
|
|
aa0e41c389 | ||
|
|
c4a1cad81b | ||
|
|
0f3fbb267b | ||
|
|
a17b3fc838 | ||
|
|
dd8feb49aa | ||
|
|
b572028e95 | ||
|
|
a01a1b4556 | ||
|
|
3121b34d17 | ||
|
|
36305e5bd8 | ||
|
|
541e3b6eb4 | ||
|
|
a24f4421d6 | ||
|
|
e8399416ae | ||
|
|
d0fa8acf86 | ||
|
|
ced7bef274 | ||
|
|
311644f39b | ||
|
|
91e40e668c | ||
|
|
987f6237c4 | ||
|
|
b9a8310f4b | ||
|
|
ddba4b90c3 | ||
|
|
98f98048bc | ||
|
|
367ac04ed8 | ||
|
|
43b18b20cc | ||
|
|
06d8dba4a0 | ||
|
|
b79c3aadd2 | ||
|
|
46985bf750 | ||
|
|
36b3878a45 | ||
|
|
bc8120c864 | ||
|
|
8b6d9d8216 | ||
|
|
413bf85dde | ||
|
|
97ef85c9aa | ||
|
|
f649172580 | ||
|
|
aad76acb68 | ||
|
|
5eb1c411a5 | ||
|
|
0d6001a196 | ||
|
|
0ab21da820 | ||
|
|
204bd29e52 | ||
|
|
fd8b37dc14 | ||
|
|
94550682d7 | ||
|
|
7754f96549 | ||
|
|
ee2d01ed88 | ||
|
|
e97f9fca22 | ||
|
|
177c06b1f1 | ||
|
|
cc348dcca2 | ||
|
|
8622af77c1 | ||
|
|
3b21f469ca | ||
|
|
82033d5029 | ||
|
|
da5ccbf7d1 | ||
|
|
a22a92b481 | ||
|
|
5bd262f9e9 | ||
|
|
2b93ef1d75 | ||
|
|
05abfc8ded | ||
|
|
de8e810792 | ||
|
|
cb28380f47 | ||
|
|
d104335501 | ||
|
|
7263cc675b | ||
|
|
d850efdd08 | ||
|
|
a6bd0944db | ||
|
|
7df2dd67bd | ||
|
|
5be95aa377 | ||
|
|
c2f978bd1e | ||
|
|
21815a1427 | ||
|
|
877fcb35f4 | ||
|
|
c2f7e166a0 | ||
|
|
e171b4e3f0 | ||
|
|
2a6f31a84e | ||
|
|
bc4473b275 | ||
|
|
43c38a5aeb | ||
|
|
6e5ff1dbe8 | ||
|
|
4edade8079 | ||
|
|
9352988c44 | ||
|
|
e5e0a21fc6 | ||
|
|
fb456e00ac | ||
|
|
851e03966d | ||
|
|
38e3299675 | ||
|
|
dbdeca3032 | ||
|
|
a78e4c6cf3 | ||
|
|
76e785dd5e | ||
|
|
767d0d9046 | ||
|
|
145efb1a33 | ||
|
|
22d2af2a29 | ||
|
|
13801ebd74 | ||
|
|
614fa7b853 | ||
|
|
4b815eece9 | ||
|
|
11f350e63f | ||
|
|
4dc3c7a6a0 | ||
|
|
d106053e4c | ||
|
|
5315751dc9 | ||
|
|
e448a9a4a9 | ||
|
|
5b0d9338fd | ||
|
|
409d7a99f9 | ||
|
|
f77e581468 | ||
|
|
d3217718a9 | ||
|
|
7e76480db4 | ||
|
|
7856141fc4 | ||
|
|
232cf8c28b | ||
|
|
b51805b87e | ||
|
|
392ef77bc5 | ||
|
|
de83c3e9e0 | ||
|
|
050d233e10 | ||
|
|
8c1f834a4a | ||
|
|
cbeb5ab960 | ||
|
|
33a51a1bdc | ||
|
|
73660f779b | ||
|
|
2c79332de7 | ||
|
|
2aec025e16 | ||
|
|
24f486261a | ||
|
|
f0c4944e2c | ||
|
|
cf15872b8d | ||
|
|
78e1b9b7c1 | ||
|
|
967a8d0678 | ||
|
|
fa44cef27b | ||
|
|
29ba3df717 | ||
|
|
aacc222b7d | ||
|
|
341f0bf9e3 | ||
|
|
091c6a3bda | ||
|
|
fd53cad208 | ||
|
|
1b6d6d0dc0 | ||
|
|
40c671b1a5 | ||
|
|
0a8b1c199d | ||
|
|
3a3c823ddb | ||
|
|
900f3c9a09 | ||
|
|
8fe2f747f4 | ||
|
|
adaeff5540 | ||
|
|
d0f91c00cb | ||
|
|
e20a071977 | ||
|
|
737a6921c3 | ||
|
|
44af6978db | ||
|
|
acbdf63a48 | ||
|
|
e59beeb625 | ||
|
|
f01dc8cc34 | ||
|
|
89f0e45b50 | ||
|
|
3f83556128 | ||
|
|
1cdafabc7c | ||
|
|
f9965b4967 | ||
|
|
0de0942f9c | ||
|
|
00a46f104a | ||
|
|
009755ba01 | ||
|
|
53a96f69ef | ||
|
|
e60bc69515 | ||
|
|
fbadb8354f | ||
|
|
02dee05c16 | ||
|
|
b16316ae37 | ||
|
|
f5077dc982 | ||
|
|
634c438b50 | ||
|
|
f468c492b9 | ||
|
|
5410838793 | ||
|
|
91c2618f21 | ||
|
|
beabd3c6b7 | ||
|
|
a81c7bf04b | ||
|
|
a6c3bb4c6d | ||
|
|
902d190a11 | ||
|
|
0142f113a3 | ||
|
|
fe195a86cd | ||
|
|
11845cedd6 | ||
|
|
5e43e2d333 | ||
|
|
15cc47334e | ||
|
|
5989c1883e | ||
|
|
632de523de | ||
|
|
2db7513590 | ||
|
|
ced24f9215 | ||
|
|
b302cad46d | ||
|
|
33838b8c1c | ||
|
|
42fb74ce22 | ||
|
|
74670ec07f | ||
|
|
3450a78992 | ||
|
|
f4ef6180b8 | ||
|
|
f0c25aaa60 | ||
|
|
0f63c1ef8f | ||
|
|
b27966860e | ||
|
|
51566d43bd | ||
|
|
71d085bd13 | ||
|
|
ffb10e7aac | ||
|
|
a5503df32b | ||
|
|
c8db96705f | ||
|
|
f94efab6c3 | ||
|
|
4c0af0f79e | ||
|
|
fc7e327d19 | ||
|
|
045f44c7f9 | ||
|
|
867d13b007 | ||
|
|
40991b93a2 | ||
|
|
949d76b328 | ||
|
|
210a2ccfdf | ||
|
|
3862aad2f7 | ||
|
|
2a005c2f11 | ||
|
|
ab46ac9bd8 | ||
|
|
c51ed84fd8 | ||
|
|
74054ea907 | ||
|
|
f79bc03360 | ||
|
|
b553df860c | ||
|
|
f753a728dd | ||
|
|
3f2e8ebcdf | ||
|
|
a1fe83c070 | ||
|
|
879c94b01e | ||
|
|
da40445d75 | ||
|
|
6235e1ae57 | ||
|
|
3618432107 | ||
|
|
f1cba8a0ea | ||
|
|
489760d2e3 | ||
|
|
caf9fc5687 | ||
|
|
dc93c2afec | ||
|
|
9164c4f309 | ||
|
|
e241f880e8 | ||
|
|
662f1355de | ||
|
|
c865211c2f | ||
|
|
6324068d34 | ||
|
|
e77e18f8c4 | ||
|
|
69c337b31d | ||
|
|
bc99f75b53 | ||
|
|
421582d747 | ||
|
|
ab1606a0f6 | ||
|
|
bcfaeca373 | ||
|
|
5f0e261f2d | ||
|
|
0e1aec4348 | ||
|
|
c1c65777b6 | ||
|
|
89d666155d | ||
|
|
4d6d65ee33 | ||
|
|
dcdb360a19 | ||
|
|
8a73990f51 | ||
|
|
efe229a54b | ||
|
|
d6fdf7d4b1 | ||
|
|
cf180b651b | ||
|
|
2e649e1843 | ||
|
|
1985579148 | ||
|
|
d31dbc6798 | ||
|
|
ffd45a2261 | ||
|
|
135631d29d | ||
|
|
ce7e31cd04 | ||
|
|
4ff1eb1890 | ||
|
|
7c47c917b5 | ||
|
|
7285459375 | ||
|
|
52b7ebd4e7 | ||
|
|
ea6f624b58 | ||
|
|
3cf3b78192 | ||
|
|
cdc2d034de | ||
|
|
cd8a17d644 | ||
|
|
57e3e7f150 | ||
|
|
c759639603 | ||
|
|
a6c101aeb8 | ||
|
|
7ea8a754c1 | ||
|
|
d5667343cb | ||
|
|
0bfe435c4f | ||
|
|
cd39843c75 | ||
|
|
f9ae65acd8 | ||
|
|
cfd930cae7 | ||
|
|
0b7e3610ac | ||
|
|
10946e7669 | ||
|
|
2dcd8c2729 | ||
|
|
dcde1c2a8f | ||
|
|
0810384555 | ||
|
|
434fb1e0da | ||
|
|
435a0b98ac | ||
|
|
05eda236cc | ||
|
|
c998faeeab | ||
|
|
f967933e8b | ||
|
|
8862a1ac8f | ||
|
|
ad56a115be | ||
|
|
c8ed013600 | ||
|
|
c49fc8db72 | ||
|
|
93fa268db1 | ||
|
|
521c92764d | ||
|
|
71d121fab2 | ||
|
|
86970a01d7 | ||
|
|
210496f0ca | ||
|
|
2eb0386c2a | ||
|
|
440c99100b | ||
|
|
33d5e646e5 | ||
|
|
c00a62d37f | ||
|
|
17486408b4 | ||
|
|
c17594c1d0 | ||
|
|
4463239d6e | ||
|
|
45d82c8d99 | ||
|
|
3e302e8683 | ||
|
|
d6620f0f3a | ||
|
|
f7a5b71dba | ||
|
|
a4d14fc987 | ||
|
|
c8587e1242 | ||
|
|
4e62a88870 | ||
|
|
32f6e7e231 | ||
|
|
94f7bcef67 | ||
|
|
36e90a1bd5 | ||
|
|
9fbe900949 | ||
|
|
73f1511ac2 | ||
|
|
5937932370 | ||
|
|
794c93b540 | ||
|
|
b92ac33022 | ||
|
|
90bbcbf994 | ||
|
|
151995f88c | ||
|
|
611b3c4c2c | ||
|
|
2a6104ab17 | ||
|
|
1dcd4cc220 | ||
|
|
7174578ac3 | ||
|
|
10d09049bb | ||
|
|
98c6a4e86e | ||
|
|
3bd52891c5 | ||
|
|
ee752ab1ce | ||
|
|
9eb900c448 | ||
|
|
0e919d25e9 | ||
|
|
4ed34d2c6f | ||
|
|
c893b44da2 | ||
|
|
d06a736f41 | ||
|
|
b135a0aa49 | ||
|
|
c73daef2a1 | ||
|
|
bc08c1d2b7 | ||
|
|
8451feaa7a | ||
|
|
e30823769c | ||
|
|
12e3b52f4d | ||
|
|
5812b22662 | ||
|
|
f139b14a3c | ||
|
|
291f1382c5 | ||
|
|
e0fe83740a | ||
|
|
9012ec5310 | ||
|
|
c37ecb1552 | ||
|
|
59d8e76081 | ||
|
|
5097ac05bf | ||
|
|
a9c154691b | ||
|
|
d628a9bc78 | ||
|
|
2fb1859732 | ||
|
|
5f5d16c698 | ||
|
|
f666e772a2 | ||
|
|
8974b12af5 | ||
|
|
f96d5c9633 | ||
|
|
50336aaedd | ||
|
|
6a04357547 | ||
|
|
0da64f430e | ||
|
|
e27ab3a24f | ||
|
|
121de4ef47 | ||
|
|
77f7d99048 | ||
|
|
4b035b9902 | ||
|
|
9778b1411c | ||
|
|
636ff411f1 | ||
|
|
02598d1e91 | ||
|
|
31aea3c996 | ||
|
|
a60f2588d6 | ||
|
|
d518f5f307 | ||
|
|
d5cbacba50 | ||
|
|
ab0f3da650 | ||
|
|
52de24b95b | ||
|
|
70b60bbe16 | ||
|
|
aff890bce8 | ||
|
|
905f1609b3 | ||
|
|
c978b25f7f | ||
|
|
2b526756f0 | ||
|
|
8a436d5103 | ||
|
|
1dd050aaca | ||
|
|
99bcce7892 | ||
|
|
0e2ea94f5e | ||
|
|
9cd7abdd6e | ||
|
|
dbacfe0a1d | ||
|
|
d50494f274 | ||
|
|
4b5e867a69 | ||
|
|
969306f0f1 | ||
|
|
af722a2978 | ||
|
|
7fce9346dc | ||
|
|
b23a6172ed | ||
|
|
ea58a8103c | ||
|
|
7857c22277 | ||
|
|
b3c7e948be | ||
|
|
c966a538fb | ||
|
|
3027a7d7e2 | ||
|
|
dd22176935 | ||
|
|
dbf9d0f094 | ||
|
|
b3218d45f3 | ||
|
|
3ca5184998 | ||
|
|
007ab69777 | ||
|
|
12d374d4b7 | ||
|
|
0ddd7de1ba | ||
|
|
f385193a89 | ||
|
|
ff078920bc | ||
|
|
b62f443be5 | ||
|
|
553c4203ab | ||
|
|
df16a7c4f3 | ||
|
|
896535fe87 | ||
|
|
89434f6a2f | ||
|
|
4e520cdd30 | ||
|
|
72dcdb7655 | ||
|
|
db5510b866 | ||
|
|
61e0efa0c7 | ||
|
|
12514c09b2 | ||
|
|
90a0590de1 | ||
|
|
b09c891290 | ||
|
|
d28bb04a9c | ||
|
|
9de1c71ff7 | ||
|
|
3ce6dd166c | ||
|
|
684bef066f | ||
|
|
52f2221be9 | ||
|
|
1bee131d52 | ||
|
|
2731976a95 | ||
|
|
f7d5e81130 | ||
|
|
371bc91d73 | ||
|
|
89771de6d0 | ||
|
|
71b213df63 | ||
|
|
7f3913ff58 | ||
|
|
d884034c9f | ||
|
|
bec199c4a2 | ||
|
|
3686110ed2 | ||
|
|
708e421ec3 | ||
|
|
5ae7ee5276 | ||
|
|
65493b421a | ||
|
|
301511a840 | ||
|
|
e86a0a4325 | ||
|
|
8d05279599 | ||
|
|
587e0e3e0c | ||
|
|
2315f32ca0 | ||
|
|
5a71509353 | ||
|
|
a310bc19a7 | ||
|
|
0647533f8c | ||
|
|
99dd78964a | ||
|
|
0d1606ff23 | ||
|
|
a6a92d42f9 | ||
|
|
2aabe16163 | ||
|
|
5984c996a8 | ||
|
|
c8d126f6ef | ||
|
|
9004554da3 | ||
|
|
4eb9efdd33 | ||
|
|
83740d81f2 | ||
|
|
c8581e4cd9 | ||
|
|
612e33c499 | ||
|
|
3e8ac30940 | ||
|
|
4bcddd72e6 | ||
|
|
00bb70a62d | ||
|
|
b4990b5bb4 | ||
|
|
65095253a9 | ||
|
|
c87efb77bc | ||
|
|
03159254ce | ||
|
|
ec5cf8593e | ||
|
|
9f065c0ea5 | ||
|
|
df3f05e824 | ||
|
|
9a10afbbc6 | ||
|
|
8d916b8573 | ||
|
|
653657ae43 | ||
|
|
b0b7240022 | ||
|
|
1e82003bf9 | ||
|
|
4be7fccad3 | ||
|
|
b040ace4c2 | ||
|
|
ab572ce5b9 | ||
|
|
ded77f59cd | ||
|
|
a1c5415f8f | ||
|
|
00e8988b52 | ||
|
|
5680808fb6 | ||
|
|
814bcc04ad | ||
|
|
a8cbff08ef | ||
|
|
ee8a05c3c7 | ||
|
|
46d7f6f95d | ||
|
|
30c89310a6 | ||
|
|
d6e1b86147 | ||
|
|
a8e973f5d7 | ||
|
|
c4d1354c54 | ||
|
|
dc2e700057 | ||
|
|
bfe0c3a8e0 | ||
|
|
a387270b76 | ||
|
|
59b659b027 | ||
|
|
973472c51e | ||
|
|
9052511c86 | ||
|
|
f57d4818a4 | ||
|
|
c5973dd411 | ||
|
|
e5f38bf391 | ||
|
|
6b4db944dd | ||
|
|
0a761d238a | ||
|
|
c8f026c382 | ||
|
|
2c70c12814 | ||
|
|
b31f6eb45f | ||
|
|
d387c1c83a | ||
|
|
7a1a2b9aa6 | ||
|
|
444da3ecec | ||
|
|
1918914598 | ||
|
|
29f3f2e1d8 | ||
|
|
759d11ce1a | ||
|
|
729e24da78 | ||
|
|
ec362536f5 | ||
|
|
b92fe3eecb | ||
|
|
985de035bc | ||
|
|
2e40ceaaa4 | ||
|
|
02a797f9f9 | ||
|
|
b938154f6b | ||
|
|
e312ebcb57 | ||
|
|
02cf50063e | ||
|
|
f511bec26c | ||
|
|
9f93c16bbf | ||
|
|
892e75ca92 | ||
|
|
5e73068e09 | ||
|
|
b71d9ce3f6 | ||
|
|
730529353d | ||
|
|
101f57d5e0 | ||
|
|
2cfc9e286e | ||
|
|
998ed99288 | ||
|
|
9048a7f021 | ||
|
|
1c91bb5a20 | ||
|
|
b957a81ea5 | ||
|
|
19fdeae4ba | ||
|
|
50ecd2c12c | ||
|
|
07f9212799 | ||
|
|
8a8cba75a2 | ||
|
|
1ae3808e13 | ||
|
|
ee2936ffbf | ||
|
|
5b29f1cdec | ||
|
|
bce29ac353 | ||
|
|
f7584fa883 | ||
|
|
18074ff98f | ||
|
|
4ad60b477c | ||
|
|
69469496e2 | ||
|
|
baaa2592a6 | ||
|
|
ecb8aa6fc1 | ||
|
|
34210901bf | ||
|
|
7132893863 | ||
|
|
cfe04d4453 | ||
|
|
f98f2890f3 | ||
|
|
d93c21349f | ||
|
|
9358dbbd99 | ||
|
|
2b9d304816 | ||
|
|
e6465a6f44 | ||
|
|
4aa9244b92 | ||
|
|
1ac4d1b793 | ||
|
|
ea205f2fcd | ||
|
|
9c15ffbb74 | ||
|
|
09b4485870 | ||
|
|
19282d6d6c | ||
|
|
ee85aaccd2 | ||
|
|
0afc34f6fc | ||
|
|
45bfccfddc | ||
|
|
f8501478f6 | ||
|
|
a5582e0960 | ||
|
|
b4fe72c4a2 | ||
|
|
48f7678771 | ||
|
|
808098413c | ||
|
|
74fd2dc9ad | ||
|
|
443b2551c7 | ||
|
|
7b681bc94a | ||
|
|
bd29f7168c | ||
|
|
c8c0dc2f53 | ||
|
|
17c6be6a9b | ||
|
|
318e752fd6 | ||
|
|
3dcfd7ba41 | ||
|
|
604a92dc3d | ||
|
|
b146ae96a7 | ||
|
|
0963e91c34 | ||
|
|
5d13b5a2fb | ||
|
|
90db821036 | ||
|
|
99d1fdd270 | ||
|
|
10ab72855d | ||
|
|
0d18516af8 | ||
|
|
e22c815444 | ||
|
|
e579e98469 | ||
|
|
723eaa1f40 | ||
|
|
4ebeeaf1e0 | ||
|
|
2c9ceea3cf | ||
|
|
c289872ab7 | ||
|
|
9469bdc93e | ||
|
|
9b4564d7f3 | ||
|
|
b5b5844119 | ||
|
|
6ef7563f53 | ||
|
|
e3e3200f95 | ||
|
|
7a0f814043 | ||
|
|
80b62df0a9 | ||
|
|
81d4e201bb | ||
|
|
8155b8cfb3 | ||
|
|
276e35ecfb | ||
|
|
7d8657287e | ||
|
|
f7905582db | ||
|
|
f12e6837be | ||
|
|
3870031c6e | ||
|
|
060a1fc727 | ||
|
|
28783abbe2 | ||
|
|
974a853f40 | ||
|
|
7ff9825f55 | ||
|
|
04b4971d8c | ||
|
|
6c3f6cfd89 | ||
|
|
ee833ea594 | ||
|
|
338feef70e | ||
|
|
ec68aaf43b | ||
|
|
24df78bcbc | ||
|
|
e926a93568 | ||
|
|
28476e3b7b | ||
|
|
05aa0ad114 | ||
|
|
5ceaed291f | ||
|
|
48934414b2 | ||
|
|
c1804810d8 | ||
|
|
69ee35c909 | ||
|
|
5d2e93e5f0 | ||
|
|
1cbd2121e2 | ||
|
|
c0d9e3231b | ||
|
|
2775fb5a45 | ||
|
|
6ca8bc4037 | ||
|
|
5dd6b1effc | ||
|
|
369e9fbf08 | ||
|
|
e39d012312 | ||
|
|
7d077a2260 | ||
|
|
b30faa577d | ||
|
|
91356d2d03 | ||
|
|
61f0231ce0 | ||
|
|
482a18e6de | ||
|
|
382ddac1a1 | ||
|
|
2b3e020152 | ||
|
|
01391f0234 | ||
|
|
32c6f96000 | ||
|
|
a883fe7b8e | ||
|
|
5d74d97fe1 | ||
|
|
db4844e3f0 | ||
|
|
7ca4fd817e | ||
|
|
8e13bcd43d | ||
|
|
cacdbb5262 | ||
|
|
35729f0870 | ||
|
|
0ff98eb2f5 | ||
|
|
dbe33783c9 | ||
|
|
f38352f1af | ||
|
|
1bf2e313f6 | ||
|
|
ca26fd17a7 | ||
|
|
4085a3fad4 | ||
|
|
36f470383b | ||
|
|
52dc9ef418 | ||
|
|
bada7e0f92 | ||
|
|
ec93b03d8d | ||
|
|
a5e748de84 | ||
|
|
2809405164 | ||
|
|
79ecf2edb7 | ||
|
|
c2ebf5544b | ||
|
|
d6fbe2a5ad | ||
|
|
b89e10c3e6 | ||
|
|
5a6c64cc28 | ||
|
|
aecbce283d | ||
|
|
60f920df0e | ||
|
|
da19974e81 | ||
|
|
ab9feb2e35 | ||
|
|
b8d798158b | ||
|
|
82d7c78b0c | ||
|
|
0074b7becb | ||
|
|
33237419c1 | ||
|
|
aa6f6bc3aa | ||
|
|
f1e023af85 | ||
|
|
f71a590375 | ||
|
|
9f48488d87 | ||
|
|
085c1594de | ||
|
|
56c6301089 | ||
|
|
e303f30d10 | ||
|
|
4b9883a573 | ||
|
|
9fb46e1206 | ||
|
|
8216303524 | ||
|
|
6c7357bbf9 | ||
|
|
13add693db | ||
|
|
a491aa0f6a | ||
|
|
e8f49f1b95 | ||
|
|
0a8c53575c | ||
|
|
3c40d93f36 | ||
|
|
4335e99f2e | ||
|
|
1fd4b851f5 | ||
|
|
142cc8fe2a | ||
|
|
5c37c63cef | ||
|
|
39caf630a9 | ||
|
|
b0502d1f3b | ||
|
|
7c9b545b30 | ||
|
|
678dcc2ca5 | ||
|
|
54d4d9a881 | ||
|
|
a5e06ed5b7 | ||
|
|
63038e0305 | ||
|
|
7cea4d7df6 | ||
|
|
936066aa03 | ||
|
|
e7f3224091 | ||
|
|
974f6982a1 | ||
|
|
7fe7e1e984 | ||
|
|
9148ab79f3 | ||
|
|
1204f15bfa | ||
|
|
f1c7e73bef | ||
|
|
c18abd4fbe | ||
|
|
c3ac875055 | ||
|
|
dbd125c714 | ||
|
|
695e001984 | ||
|
|
33b42872e5 | ||
|
|
8bb7602145 | ||
|
|
d9e2edd1df | ||
|
|
f9d80d5bd2 | ||
|
|
406874b6c2 | ||
|
|
e4ddd6cb6d | ||
|
|
a7745e9a86 | ||
|
|
3fd7bc8058 | ||
|
|
25e398a8f0 | ||
|
|
c31b03327f | ||
|
|
f6d56e2937 | ||
|
|
ca7769e041 | ||
|
|
c0aef7dd6b | ||
|
|
4283ecf774 | ||
|
|
88a57dc98d | ||
|
|
035ecef8a5 | ||
|
|
4c3b6814dc | ||
|
|
3f016fcc5a | ||
|
|
be75c483d0 | ||
|
|
08dd32d32d | ||
|
|
b49584457a | ||
|
|
40d25adb88 | ||
|
|
a38e5a44ec | ||
|
|
3fceef0936 | ||
|
|
c065427ebe | ||
|
|
c82f04f54c | ||
|
|
d9d0c52770 | ||
|
|
c60635855d | ||
|
|
2666d6df90 | ||
|
|
8558fa0bcf | ||
|
|
f36d6b7ef5 | ||
|
|
e9908048ec | ||
|
|
dceed2ea5c | ||
|
|
7b63878926 | ||
|
|
01ecd3517e | ||
|
|
fbdea8dc71 | ||
|
|
58d0e8b28f | ||
|
|
07fbe82305 | ||
|
|
05a967564a | ||
|
|
75ef1278e6 | ||
|
|
fc158ad5c0 | ||
|
|
4d69d0eda5 | ||
|
|
d7ba4bbb9b | ||
|
|
2225b8add7 | ||
|
|
9572db262c | ||
|
|
515e4b9187 | ||
|
|
c1dc1a20d6 | ||
|
|
a58083b11e | ||
|
|
0f24fba28a | ||
|
|
4d774e275d | ||
|
|
a2d6a50dff | ||
|
|
08b56e8180 | ||
|
|
7a77917df6 | ||
|
|
e432014a88 | ||
|
|
a89db9872d | ||
|
|
6dcc85dcf4 | ||
|
|
a375ea4ee2 | ||
|
|
d74464e091 | ||
|
|
e2c2afbbe0 | ||
|
|
cffe54d094 | ||
|
|
2f02120fee | ||
|
|
c0b534e531 | ||
|
|
5eaef50a77 | ||
|
|
a80c4d147c | ||
|
|
ad66b2bf13 | ||
|
|
ef6ec9de01 | ||
|
|
751deac9d1 | ||
|
|
406da499ff | ||
|
|
a6b48d5273 | ||
|
|
6272b5c58c | ||
|
|
8c9b99458d | ||
|
|
3273c68b63 | ||
|
|
a44e2190d6 | ||
|
|
2dab478c3f | ||
|
|
a32afb28c0 | ||
|
|
d2a89b424b | ||
|
|
9502cd7047 | ||
|
|
cd02450095 | ||
|
|
03a3412e62 | ||
|
|
33086e6db0 | ||
|
|
d7a951996b | ||
|
|
38bfe50508 | ||
|
|
a70567e74f | ||
|
|
db472c73c1 | ||
|
|
29824f9baa | ||
|
|
32b1a9fc8a | ||
|
|
018719d9d3 | ||
|
|
8ae472821f | ||
|
|
26911ff21c | ||
|
|
5070cc07be | ||
|
|
1e65eb4936 | ||
|
|
13e40f754c | ||
|
|
87cfd930e4 | ||
|
|
8b63a89267 | ||
|
|
94eff945b4 | ||
|
|
039737ffc2 | ||
|
|
08370c7230 | ||
|
|
2f9b28c0fc | ||
|
|
4e1320d480 | ||
|
|
e6202cfa97 | ||
|
|
a15b28a24e | ||
|
|
9975dbeded | ||
|
|
2cf5eec62f | ||
|
|
51012d07cc | ||
|
|
252abbeb8d | ||
|
|
357b28f675 | ||
|
|
bf37afd7c7 | ||
|
|
f311045320 | ||
|
|
381a7b110a | ||
|
|
75f2c56558 | ||
|
|
91333c5d2f | ||
|
|
ee2ba4e52f | ||
|
|
ae300c98a4 | ||
|
|
748b70311e | ||
|
|
8d0664186a | ||
|
|
2fb5a71efd | ||
|
|
4fda366b67 | ||
|
|
2ceae6014e | ||
|
|
cf3162cff1 | ||
|
|
2350d941a5 | ||
|
|
25f9f55878 | ||
|
|
07540f3386 | ||
|
|
fe63f36656 | ||
|
|
434daf87c2 | ||
|
|
c681e5e082 | ||
|
|
549f97b54a | ||
|
|
f47a93b0c1 | ||
|
|
3fe5a99dab | ||
|
|
097bc4c622 | ||
|
|
252126cf76 | ||
|
|
8609d1e790 | ||
|
|
9809f1ff66 | ||
|
|
796098e4c9 | ||
|
|
eb6bcdb3ee | ||
|
|
a1555e0615 | ||
|
|
44b527415f | ||
|
|
ed294c5945 | ||
|
|
bd3ade31fa | ||
|
|
d03d2e6d3d | ||
|
|
58ffa8d526 | ||
|
|
bfe8c15a29 | ||
|
|
2fa7e003b1 | ||
|
|
ba948669cd | ||
|
|
666e84eef2 | ||
|
|
69b15c889d | ||
|
|
ff3bf6d7f5 | ||
|
|
b844129649 | ||
|
|
86059bd5dd | ||
|
|
9927d991ef | ||
|
|
6849b7d555 | ||
|
|
1efd1ee6ac | ||
|
|
d12600fba0 | ||
|
|
769b2a3e30 | ||
|
|
d237ec7e78 | ||
|
|
de1375201f | ||
|
|
13ba8810c7 | ||
|
|
bdfbac2aa6 | ||
|
|
6bd0bd2ed1 | ||
|
|
211a889528 | ||
|
|
3bb29bf63a | ||
|
|
78d52ad2de | ||
|
|
4fe648415f | ||
|
|
6751ac4970 | ||
|
|
6764957d06 | ||
|
|
c719ba7bf3 | ||
|
|
31d7293b17 | ||
|
|
defef2222a | ||
|
|
63459f65fb | ||
|
|
c68e1ceb64 | ||
|
|
07e72d2ac8 | ||
|
|
7f97e354b4 | ||
|
|
e5a554f0b5 | ||
|
|
9e4aa79278 | ||
|
|
a0298728df | ||
|
|
0eb83f6ee6 | ||
|
|
e81f092520 | ||
|
|
7fb874ad28 | ||
|
|
a4a41b9023 | ||
|
|
99aea7eb6f | ||
|
|
b4ac36337f | ||
|
|
7072bc3203 | ||
|
|
7e9f000d0b | ||
|
|
af56eebc6a | ||
|
|
387c778496 | ||
|
|
fbbde125d9 | ||
|
|
dbaefd6126 | ||
|
|
a1c87f7c49 | ||
|
|
045ee53468 | ||
|
|
b84ab718b0 | ||
|
|
6144deb6b6 | ||
|
|
19864a4a08 | ||
|
|
7920b6e163 | ||
|
|
4928166593 | ||
|
|
ad5f520c68 | ||
|
|
150b4fb4f6 | ||
|
|
4f8198b298 | ||
|
|
076f177100 | ||
|
|
3b939480a4 | ||
|
|
773a2767c7 | ||
|
|
e9b29184d0 | ||
|
|
0d02b8d1f6 | ||
|
|
98c0fcc659 | ||
|
|
1ddebcc862 | ||
|
|
1adb900561 | ||
|
|
c5c1012ddd | ||
|
|
519f81771a | ||
|
|
c762c06b17 | ||
|
|
8bab543531 | ||
|
|
bab8c82a35 | ||
|
|
b82bca7c99 | ||
|
|
556a2126b5 | ||
|
|
a070751061 | ||
|
|
847845027f | ||
|
|
c69914367d | ||
|
|
48d364e269 | ||
|
|
c58c27ed8b | ||
|
|
97b8abf16c | ||
|
|
59567b43b0 | ||
|
|
e067e84d69 | ||
|
|
35c670513f | ||
|
|
8ec92b6fe7 | ||
|
|
5552f082e8 | ||
|
|
3c122117fc | ||
|
|
a467d21eba | ||
|
|
bc724ea206 | ||
|
|
4ea5c1d973 | ||
|
|
c65883a727 | ||
|
|
a4f6146667 | ||
|
|
936c6c0d5c | ||
|
|
91af8878e1 | ||
|
|
d2b2ae09e6 | ||
|
|
94c35184a9 | ||
|
|
9e021cd1a8 | ||
|
|
78565026ac | ||
|
|
de6be743c6 | ||
|
|
f534e80c71 | ||
|
|
0797ab6bc6 | ||
|
|
b4df26a75d | ||
|
|
d92c462466 | ||
|
|
f31b905847 | ||
|
|
572e457e77 | ||
|
|
be9b23a082 | ||
|
|
c9e7531251 | ||
|
|
90faecd86e | ||
|
|
6c12e5bfbe | ||
|
|
2e069429c2 | ||
|
|
e65202f825 | ||
|
|
11a3057e8e | ||
|
|
ba0c619844 | ||
|
|
a83fb30836 | ||
|
|
dc092653f4 | ||
|
|
25c6278000 | ||
|
|
5033e0e752 | ||
|
|
295eeef9b6 | ||
|
|
f63b87e28b | ||
|
|
1f780e86d5 | ||
|
|
408a56ffaf | ||
|
|
a84f5d52ff | ||
|
|
fb6eed0087 | ||
|
|
dc242a01b4 | ||
|
|
074d3dd2b1 | ||
|
|
807afbc879 | ||
|
|
8f1eeb1025 | ||
|
|
dd288f70ec | ||
|
|
6a11134a18 | ||
|
|
9b60b55f03 | ||
|
|
77aa06df64 | ||
|
|
9b7860d6ec | ||
|
|
bda73b1bc9 | ||
|
|
8576ee0981 | ||
|
|
8093b55e86 | ||
|
|
b6db4a0e2e | ||
|
|
cd7894dfc9 | ||
|
|
c36d73f42a | ||
|
|
9871c4ff06 | ||
|
|
e330983408 | ||
|
|
4bbf443ba2 | ||
|
|
0234c62c3e | ||
|
|
0bdc27186d | ||
|
|
c51c55b782 | ||
|
|
26250f1953 | ||
|
|
7ecfe6304a | ||
|
|
b7be03801c | ||
|
|
b21cb8a396 | ||
|
|
eadd56a376 | ||
|
|
2aa9a66c57 | ||
|
|
8e9c07df39 | ||
|
|
1d392f0e76 | ||
|
|
08cbc1b22b | ||
|
|
f744d7a789 | ||
|
|
ff2a737094 | ||
|
|
111a1cef52 | ||
|
|
a44b56dc61 | ||
|
|
1b586b69bc | ||
|
|
4a7f2ffc5e | ||
|
|
503162ec54 | ||
|
|
22fad86453 | ||
|
|
8641b8a36e | ||
|
|
be2d3b5886 | ||
|
|
3120487243 | ||
|
|
4404ef0281 | ||
|
|
0c68fc409e | ||
|
|
ea7bf19057 | ||
|
|
99bf9775d9 | ||
|
|
0e2d5f9d0e | ||
|
|
3065b9f968 | ||
|
|
cce5fbc7b1 | ||
|
|
82a4d4ec65 | ||
|
|
708147625f | ||
|
|
93559a54e9 | ||
|
|
f10ddea305 | ||
|
|
4a8ff6d824 | ||
|
|
4b7e3af77c | ||
|
|
19238a910c | ||
|
|
2deb13df43 | ||
|
|
1ece33e79a | ||
|
|
844f5e5af1 | ||
|
|
51bfac71b0 | ||
|
|
81a0fd782f | ||
|
|
3a30e5bf78 | ||
|
|
a87096cdc9 | ||
|
|
527d99fd39 | ||
|
|
6e2722a6d3 | ||
|
|
8694deaabb | ||
|
|
a226099b04 | ||
|
|
336ba8f419 | ||
|
|
5abdc99f3e | ||
|
|
f7ef9887d7 | ||
|
|
fed76f29d0 | ||
|
|
a3cfbfc6ba | ||
|
|
444646b65e | ||
|
|
8bd508a73d | ||
|
|
1cceb4e0ad | ||
|
|
c2d2034ae8 | ||
|
|
f94ed922e5 | ||
|
|
7a57d28db4 | ||
|
|
ce5121e659 | ||
|
|
a7d7158b05 | ||
|
|
6b8c78bacc | ||
|
|
2da930ba4c | ||
|
|
772cac7946 | ||
|
|
42f672d85d | ||
|
|
945f2912a7 | ||
|
|
1ccf516c5e | ||
|
|
fb396b8fac | ||
|
|
6db3026d47 | ||
|
|
becc306300 | ||
|
|
4e7ce11684 | ||
|
|
6589cf9d8e | ||
|
|
552589f098 | ||
|
|
2ec79c03a0 | ||
|
|
21653f0f91 | ||
|
|
b922eaa754 | ||
|
|
d27da93c33 | ||
|
|
2e6fa7f8a3 | ||
|
|
302184938a | ||
|
|
e5355cc45f | ||
|
|
2fe778507a | ||
|
|
4077422ae2 | ||
|
|
a9ac45c5f0 | ||
|
|
7ef99ee6f3 | ||
|
|
e44aada634 | ||
|
|
ac0a864e14 | ||
|
|
3c3331d5ed | ||
|
|
6f21f48937 | ||
|
|
2e227f868b | ||
|
|
7d7513c71c | ||
|
|
d95f1e9913 | ||
|
|
1013b49ab7 | ||
|
|
dc0e15a74e | ||
|
|
d6e5ca722f | ||
|
|
cd3ba00479 | ||
|
|
c549dba725 | ||
|
|
ca1ad99bea | ||
|
|
2c7bd7e591 | ||
|
|
bea45b3c30 | ||
|
|
093c7b4386 | ||
|
|
8332a5aa53 | ||
|
|
eb020656d2 | ||
|
|
31456a6dfe | ||
|
|
03fda0f803 | ||
|
|
c09f03f6e8 | ||
|
|
3bad9ff50a | ||
|
|
0663421d01 | ||
|
|
10175caa38 | ||
|
|
103ad75c50 | ||
|
|
2f5f86d6fc | ||
|
|
89d2c2917f | ||
|
|
05817aa3b9 | ||
|
|
5464ed6661 | ||
|
|
05c84a147d | ||
|
|
9c35403b98 | ||
|
|
b5b075eb04 | ||
|
|
e1261c9620 | ||
|
|
5531bca078 | ||
|
|
28b9dd50ff | ||
|
|
44c2a0a7fc | ||
|
|
d143acfc76 | ||
|
|
b4d59fd52d | ||
|
|
2ee2a1b730 | ||
|
|
86ebc8e46c | ||
|
|
29c5ee6b19 | ||
|
|
323aebf1f5 | ||
|
|
a5dd1ccfaa | ||
|
|
4dd297cef2 | ||
|
|
7f9fea18ae | ||
|
|
adb8b881b4 | ||
|
|
d3d1b69c7a | ||
|
|
922d3716ff | ||
|
|
4158222e86 | ||
|
|
6727c43441 | ||
|
|
55c1ec2925 | ||
|
|
0f1c18e675 | ||
|
|
0de1293ff5 | ||
|
|
89ab390719 | ||
|
|
88ef3ffa50 | ||
|
|
668d5d9d92 | ||
|
|
6c908ac727 | ||
|
|
2c4bd7162f | ||
|
|
cf18e0776d | ||
|
|
8b866beaeb | ||
|
|
ee5fca7a2b | ||
|
|
fc074937f5 | ||
|
|
a17ea13453 | ||
|
|
8bb4ea85b8 | ||
|
|
26e8372c75 | ||
|
|
4704efa32a | ||
|
|
339925e835 | ||
|
|
28360a7f26 | ||
|
|
49bb62d221 | ||
|
|
04f121b88f | ||
|
|
6ce5c8eb78 | ||
|
|
7736cdae1c | ||
|
|
05aa1f1ae4 | ||
|
|
42827cdea2 | ||
|
|
b88dad4034 | ||
|
|
d0645273df | ||
|
|
dea27e105d | ||
|
|
0bfad4392a | ||
|
|
4c1b507c07 | ||
|
|
0289055948 | ||
|
|
83a48dafea | ||
|
|
a7a20a9de4 | ||
|
|
82b67b01ff | ||
|
|
b896203dcf | ||
|
|
795d5807b5 | ||
|
|
7d43f4a1f4 | ||
|
|
c268c5e07c | ||
|
|
517659640e | ||
|
|
a9672e1a21 | ||
|
|
4570f71f21 | ||
|
|
ca2fd867b8 | ||
|
|
624da03bad | ||
|
|
a820f32ec9 | ||
|
|
f5dc6e80c0 | ||
|
|
de70b710af | ||
|
|
bf10a27db8 | ||
|
|
aa2656cb9e | ||
|
|
adf2b2bf03 | ||
|
|
6773326d96 | ||
|
|
1d7efce0dc | ||
|
|
1a1deb5d58 | ||
|
|
bcba806ef0 | ||
|
|
00648c27eb | ||
|
|
4885b39121 | ||
|
|
0f3e70b679 | ||
|
|
372a0f9eea | ||
|
|
2a44bad2e7 | ||
|
|
33e8472473 | ||
|
|
8834a8b216 | ||
|
|
db794c2d32 | ||
|
|
a1d80c29de | ||
|
|
bea796ebc0 | ||
|
|
d4978210f0 | ||
|
|
ef59e952d8 | ||
|
|
54d5ee5562 | ||
|
|
eb75ae05c6 | ||
|
|
b56a1501d2 | ||
|
|
fe9c716fbe | ||
|
|
bc308c21fc | ||
|
|
3e41f36ef5 | ||
|
|
8d2131884c | ||
|
|
289566afe8 | ||
|
|
944adc56ee | ||
|
|
6e81f722ad | ||
|
|
bfa28f4c30 | ||
|
|
3dcd33b08f | ||
|
|
3ac81e9d7c | ||
|
|
1704d21356 | ||
|
|
d690775ca1 | ||
|
|
fb07a28c99 | ||
|
|
1dff9aea62 | ||
|
|
e5d54f5344 | ||
|
|
a558c01589 | ||
|
|
7043983acc | ||
|
|
dd245c63d7 | ||
|
|
84d8760561 | ||
|
|
e1225cec5f | ||
|
|
5db6bb02d6 | ||
|
|
679d3fd5b3 | ||
|
|
c622985fda | ||
|
|
d910786034 | ||
|
|
8dbf572ea5 | ||
|
|
f8af1a7443 | ||
|
|
d95bcab053 | ||
|
|
2b4c10e705 | ||
|
|
ac4c802089 | ||
|
|
c6e4b8f829 | ||
|
|
52d41d19d3 | ||
|
|
0e7df4b193 | ||
|
|
2c9b3b35d1 | ||
|
|
773dcae2f9 | ||
|
|
22e7b674ed | ||
|
|
8c95422204 | ||
|
|
34531a8160 | ||
|
|
5c199483cd | ||
|
|
c52189557e | ||
|
|
bcabe63971 | ||
|
|
193ccaa3b4 | ||
|
|
c6605766e7 | ||
|
|
4fca628d36 | ||
|
|
7f81c62bf0 | ||
|
|
fc7da615fb | ||
|
|
86766f4e20 | ||
|
|
8cb0b7d043 | ||
|
|
b6cdeeef8e | ||
|
|
ac2175fa7d | ||
|
|
5816bab6a2 | ||
|
|
d0d650aa67 | ||
|
|
6d5ec9c998 | ||
|
|
fe08467e45 | ||
|
|
26e03b81fe | ||
|
|
f6582fd229 | ||
|
|
5e87126c38 | ||
|
|
c279692cfe | ||
|
|
7d0dab9d7d | ||
|
|
16555ad12e | ||
|
|
9a95c2ff08 | ||
|
|
1d6347c9b0 | ||
|
|
13075460ea | ||
|
|
4c3dfb92b7 | ||
|
|
fc2efaeb8c | ||
|
|
b15e60243b | ||
|
|
f2de3215c3 | ||
|
|
efbad07643 | ||
|
|
69d61eda01 | ||
|
|
e9255d3714 | ||
|
|
c8647c0396 | ||
|
|
8114627d6a | ||
|
|
5048a30fc7 | ||
|
|
ce6fb83ef4 | ||
|
|
85f8a59d7f | ||
|
|
dd8729063c | ||
|
|
14c766e750 | ||
|
|
3a11a8a01d | ||
|
|
988815579a | ||
|
|
d1fa13ed52 | ||
|
|
08b497faea | ||
|
|
96d332e234 | ||
|
|
440f31a4d3 | ||
|
|
cb91705e03 | ||
|
|
d12e742373 | ||
|
|
7aa7c0f481 | ||
|
|
b3ffa16315 | ||
|
|
09d1f55bce | ||
|
|
21333d0f18 | ||
|
|
edcc859b58 | ||
|
|
2ce17a724a | ||
|
|
0fb07ba328 | ||
|
|
78f0307246 | ||
|
|
c5203ab5ea | ||
|
|
3d1a306518 | ||
|
|
2750d61e92 | ||
|
|
43ac5ad70d | ||
|
|
309e936ad9 | ||
|
|
d00fa906cf | ||
|
|
01839b9c14 | ||
|
|
1f396946e5 | ||
|
|
2f58ef781c | ||
|
|
8b9f70ac08 | ||
|
|
e039d4103f | ||
|
|
0333e81616 | ||
|
|
cf1be4ae2d | ||
|
|
dc34636598 | ||
|
|
c74d881d3d | ||
|
|
ab51f3bec0 | ||
|
|
b4c4fae3f5 | ||
|
|
ce98df59f1 | ||
|
|
f29bdd21a7 | ||
|
|
9d31401d47 | ||
|
|
5c68bbe16f | ||
|
|
07c610e068 | ||
|
|
998f109fc8 | ||
|
|
cfb70bccc1 | ||
|
|
7524f9006e | ||
|
|
bcfe3dacc6 | ||
|
|
6c56151d27 | ||
|
|
98274d2145 | ||
|
|
1d125f55ba | ||
|
|
918470affc | ||
|
|
797f26e45b | ||
|
|
e145c1d31c | ||
|
|
bb5d0c5c4a | ||
|
|
0aea1b608a | ||
|
|
a2aa43a426 | ||
|
|
8d5514603e | ||
|
|
b9a2feff5e | ||
|
|
f13615d97a | ||
|
|
d6227aece6 | ||
|
|
6058389974 | ||
|
|
dccad08508 | ||
|
|
112158b056 | ||
|
|
5be300736e | ||
|
|
1b98a64e90 | ||
|
|
4849eb4c54 | ||
|
|
5e8ee7e006 | ||
|
|
e27d34d118 | ||
|
|
a0bf8d5740 | ||
|
|
17a5ba08e4 | ||
|
|
d0877153bf | ||
|
|
55011e5308 | ||
|
|
2697b3c7da | ||
|
|
b9c17dd1f0 | ||
|
|
aea17bfae2 | ||
|
|
0a5755145c | ||
|
|
249e19769b | ||
|
|
f64808c385 | ||
|
|
2e69b54a4f | ||
|
|
cd5d1ceadf | ||
|
|
c55f6b40ec | ||
|
|
bf4ec9be22 | ||
|
|
ed0626afeb | ||
|
|
b5305d5a8c | ||
|
|
17efa04ea6 | ||
|
|
b3f5c8f6b2 | ||
|
|
4507083148 | ||
|
|
f4c0018d7a | ||
|
|
c9e1d6cca8 | ||
|
|
242dc34115 | ||
|
|
41c785d77a | ||
|
|
a745528b40 | ||
|
|
7465be91d0 | ||
|
|
d79c5baa1b | ||
|
|
46af0d38fa | ||
|
|
6323e09a0a | ||
|
|
d94bdb75c8 | ||
|
|
cc3b4dff20 | ||
|
|
78ac382fdf | ||
|
|
860072aaaf | ||
|
|
2694a409c6 | ||
|
|
206b1f4631 | ||
|
|
ef9891e8ff | ||
|
|
bd69890ccd | ||
|
|
fc280c7cd6 | ||
|
|
435ac2a650 | ||
|
|
fb0ad2f9ea | ||
|
|
7385449f33 | ||
|
|
1f4b814d0b | ||
|
|
a93d9c4310 | ||
|
|
1813d11b9d | ||
|
|
09ac68c196 | ||
|
|
c2fd905e32 | ||
|
|
cc84f28d1b | ||
|
|
2bd498524d | ||
|
|
4b934945f3 | ||
|
|
b666ab0673 | ||
|
|
6a4c30fe5d | ||
|
|
4002aef594 | ||
|
|
ba28d36e67 | ||
|
|
4444db2990 | ||
|
|
d0026793bf | ||
|
|
93b5cd5ddd | ||
|
|
12c2d7e4cf | ||
|
|
4eb5acd9e2 | ||
|
|
0f56d838ec | ||
|
|
12a948dacb | ||
|
|
137953605e | ||
|
|
629fad6f5f | ||
|
|
2911c84a69 | ||
|
|
89a1420609 | ||
|
|
e584557afe | ||
|
|
2ed5413e24 | ||
|
|
91532b2d5c | ||
|
|
732cac1c0e | ||
|
|
5b04860b8b | ||
|
|
5a674f419d | ||
|
|
d30246dc05 | ||
|
|
af5a913019 | ||
|
|
604e69c7ae | ||
|
|
d765c9de37 | ||
|
|
98b6e2bcce | ||
|
|
d80be7961c | ||
|
|
2aec3a9789 | ||
|
|
ccd7dbe0e4 | ||
|
|
92fcfd7a6f | ||
|
|
1b2b054139 | ||
|
|
853d1eac96 | ||
|
|
2ef29d6839 | ||
|
|
6865806b55 | ||
|
|
9546e65617 | ||
|
|
5852993243 | ||
|
|
90a03a77ad | ||
|
|
4bfbe7ebeb | ||
|
|
f3c1686a40 | ||
|
|
33a587d97e | ||
|
|
a444ec5111 | ||
|
|
5ead1bf5c8 |
10
.gitattributes
vendored
Normal file
10
.gitattributes
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
# These files are text and should be normalized
|
||||
*.txt text
|
||||
*.c text
|
||||
*.h text
|
||||
|
||||
# For git archive
|
||||
.gitignore export-ignore
|
||||
.gitattributes export-ignore
|
||||
.travis.yml export-ignore
|
||||
.vscode export-ignore
|
||||
19
.gitignore
vendored
Normal file
19
.gitignore
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
*.o
|
||||
*.a
|
||||
/doc/doxygen/output/html
|
||||
/src/apps/snmp/LwipMibCompiler/CCodeGeneration/bin/
|
||||
/src/apps/snmp/LwipMibCompiler/CCodeGeneration/obj/
|
||||
/src/apps/snmp/LwipMibCompiler/LwipMibCompiler/bin/
|
||||
/src/apps/snmp/LwipMibCompiler/LwipMibCompiler/obj/
|
||||
/src/apps/snmp/LwipMibCompiler/MibViewer/bin/
|
||||
/src/apps/snmp/LwipMibCompiler/MibViewer/obj/
|
||||
/src/apps/snmp/LwipMibCompiler/LwipSnmpCodeGeneration/bin/
|
||||
/src/apps/snmp/LwipMibCompiler/LwipSnmpCodeGeneration/obj/
|
||||
/src/apps/snmp/LwipMibCompiler/SharpSnmpLib/bin/
|
||||
/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
|
||||
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
|
||||
1
FILES
1
FILES
@@ -1,4 +1,5 @@
|
||||
src/ - The source code for the lwIP TCP/IP stack.
|
||||
doc/ - The documentation for lwIP.
|
||||
test/ - Some code to test whether the sources do what they should.
|
||||
|
||||
See also the FILES file in each subdirectory.
|
||||
|
||||
83
README
83
README
@@ -1,37 +1,56 @@
|
||||
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
|
||||
|
||||
* IP (Internet Protocol) including packet forwarding over multiple network
|
||||
interfaces
|
||||
* IP (Internet Protocol, IPv4 and IPv6) including packet forwarding over
|
||||
multiple network interfaces
|
||||
* ICMP (Internet Control Message Protocol) for network maintenance and debugging
|
||||
* IGMP (Internet Group Management Protocol) for multicast traffic management
|
||||
* MLD (Multicast listener discovery for IPv6). Aims to be compliant with
|
||||
RFC 2710. No support for MLDv2
|
||||
* 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
|
||||
* Specialized raw/native API for enhanced performance
|
||||
fast recovery/fast retransmit and sending SACKs
|
||||
* raw/native API for enhanced performance
|
||||
* Optional Berkeley-like socket API
|
||||
* DNS (Domain names resolver)
|
||||
* SNMP (Simple Network Management Protocol)
|
||||
* DHCP (Dynamic Host Configuration Protocol)
|
||||
* AUTOIP (for IPv4, conform with RFC 3927)
|
||||
* PPP (Point-to-Point Protocol)
|
||||
* ARP (Address Resolution Protocol) for Ethernet
|
||||
* 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 (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
|
||||
|
||||
lwIP is freely available under a BSD license.
|
||||
|
||||
|
||||
DEVELOPMENT
|
||||
|
||||
lwIP has grown into an excellent TCP/IP stack for embedded devices,
|
||||
@@ -40,38 +59,34 @@ and additions to the stack to further increase its usefulness.
|
||||
|
||||
Development of lwIP is hosted on Savannah, a central point for
|
||||
software development, maintenance and distribution. Everyone can
|
||||
help improve lwIP by use of Savannah's interface, CVS and the
|
||||
help improve lwIP by use of Savannah's interface, Git and the
|
||||
mailing list. A core team of developers will commit changes to the
|
||||
CVS source tree.
|
||||
Git source tree.
|
||||
|
||||
The lwIP TCP/IP stack is maintained in the 'lwip' CVS module and
|
||||
contributions (such as platform ports) are in the 'contrib' module.
|
||||
The lwIP TCP/IP stack is maintained in the 'lwip' Git module and
|
||||
contributions (such as platform ports) are in the 'contrib' Git module.
|
||||
|
||||
See doc/savannah.txt for details on CVS server access for users and
|
||||
See doc/savannah.txt for details on Git server access for users and
|
||||
developers.
|
||||
|
||||
Last night's CVS tar ball can be downloaded from:
|
||||
http://savannah.gnu.org/cvs.backups/lwip.tar.gz [CHANGED - NEEDS FIXING]
|
||||
|
||||
The current CVS trees are web-browsable:
|
||||
http://savannah.nongnu.org/cgi-bin/viewcvs/lwip/lwip/
|
||||
http://savannah.nongnu.org/cgi-bin/viewcvs/lwip/contrib/
|
||||
The current Git trees are web-browsable:
|
||||
http://git.savannah.gnu.org/cgit/lwip.git
|
||||
http://git.savannah.gnu.org/cgit/lwip/lwip-contrib.git
|
||||
|
||||
Submit patches and bugs via the lwIP project page:
|
||||
http://savannah.nongnu.org/projects/lwip/
|
||||
|
||||
Continuous integration builds (GCC, clang):
|
||||
https://travis-ci.org/yarrick/lwip-merged
|
||||
|
||||
|
||||
DOCUMENTATION
|
||||
|
||||
The original out-dated homepage of lwIP and Adam Dunkels' papers on
|
||||
lwIP are at the official lwIP home page:
|
||||
http://www.sics.se/~adam/lwip/
|
||||
|
||||
Self documentation of the source code is regularly extracted from the
|
||||
current CVS sources and is available from this web page:
|
||||
Self documentation of the source code is regularly extracted from the current
|
||||
Git sources and is available from this web page:
|
||||
http://www.nongnu.org/lwip/
|
||||
|
||||
There is now a constantly growin wiki about lwIP at
|
||||
There is now a constantly growing wiki about lwIP at
|
||||
http://lwip.wikia.com/wiki/LwIP_Wiki
|
||||
|
||||
Also, there are mailing lists you can subscribe at
|
||||
@@ -80,10 +95,12 @@ plus searchable archives:
|
||||
http://lists.nongnu.org/archive/html/lwip-users/
|
||||
http://lists.nongnu.org/archive/html/lwip-devel/
|
||||
|
||||
lwIP was originally written by Adam Dunkels:
|
||||
http://dunkels.com/adam/
|
||||
|
||||
Reading Adam's papers, the files in docs/, browsing the source code
|
||||
documentation and browsing the mailing list archives is a good way to
|
||||
become familiar with the design of lwIP.
|
||||
|
||||
Adam Dunkels <adam@sics.se>
|
||||
Leon Woestenberg <leon.woestenberg@gmx.net>
|
||||
|
||||
|
||||
136
UPGRADING
136
UPGRADING
@@ -4,10 +4,144 @@ application written for an older version of lwIP to correctly work
|
||||
with newer versions.
|
||||
|
||||
|
||||
(CVS HEAD)
|
||||
(git master)
|
||||
|
||||
* [Enter new changes just after this line - do not remove this line]
|
||||
|
||||
(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)
|
||||
|
||||
++ Application changes:
|
||||
|
||||
* Changed netif "up" flag handling to be an administrative flag (as opposed to the previous meaning of
|
||||
"ip4-address-valid", a netif will now not be used for transmission if not up) -> even a DHCP netif
|
||||
has to be set "up" before starting the DHCP client
|
||||
* Added IPv6 support (dual-stack or IPv4/IPv6 only)
|
||||
* Changed ip_addr_t to be a union in dual-stack mode (use ip4_addr_t where referring to IPv4 only).
|
||||
* Major rewrite of SNMP (added MIB parser that creates code stubs for custom MIBs);
|
||||
supports SNMPv2c (experimental v3 support)
|
||||
* Moved some core applications from contrib repository to src/apps (and include/lwip/apps)
|
||||
|
||||
+++ Raw API:
|
||||
* Changed TCP listen backlog: removed tcp_accepted(), added the function pair tcp_backlog_delayed()/
|
||||
tcp_backlog_accepted() to explicitly delay backlog handling on a connection pcb
|
||||
|
||||
+++ Socket API:
|
||||
* Added an implementation for posix sendmsg()
|
||||
* Added LWIP_FIONREAD_LINUXMODE that makes ioctl/FIONREAD return the size of the next pending datagram
|
||||
|
||||
++ Port changes
|
||||
|
||||
+++ new files:
|
||||
* MANY new and moved files!
|
||||
* Added src/Filelists.mk for use in Makefile projects
|
||||
* Continued moving stack-internal parts from abc.h to abc_priv.h in sub-folder "priv"
|
||||
to let abc.h only contain the actual application programmer's API
|
||||
|
||||
+++ sys layer:
|
||||
* Made LWIP_TCPIP_CORE_LOCKING==1 the default as it usually performs better than
|
||||
the traditional message passing (although with LWIP_COMPAT_MUTEX you are still
|
||||
open to priority inversion, so this is not recommended any more)
|
||||
* Added LWIP_NETCONN_SEM_PER_THREAD to use one "op_completed" semaphore per thread
|
||||
instead of using one per netconn (these semaphores are used even with core locking
|
||||
enabled as some longer lasting functions like big writes still need to delay)
|
||||
* Added generalized abstraction for itoa(), strnicmp(), stricmp() and strnstr()
|
||||
in def.h (to be overridden in cc.h) instead of config
|
||||
options for netbiosns, httpd, dns, etc. ...
|
||||
* New abstraction for hton* and ntoh* functions in def.h.
|
||||
To override them, use the following in cc.h:
|
||||
#define lwip_htons(x) <your_htons>
|
||||
#define lwip_htonl(x) <your_htonl>
|
||||
|
||||
+++ new options:
|
||||
* TODO
|
||||
|
||||
+++ new pools:
|
||||
* Added LWIP_MEMPOOL_* (declare/init/alloc/free) to declare private memp pools
|
||||
that share memp.c code but do not have to be made global via lwippools.h
|
||||
* Added pools for IPv6, MPU_COMPATIBLE, dns-api, netif-api, etc.
|
||||
* added hook LWIP_HOOK_MEMP_AVAILABLE() to get informed when a memp pool was empty and an item
|
||||
is now available
|
||||
|
||||
* Signature of LWIP_HOOK_VLAN_SET macro was changed
|
||||
|
||||
* LWIP_DECLARE_MEMORY_ALIGNED() may be used to declare aligned memory buffers (mem/memp)
|
||||
or to move buffers to dedicated memory using compiler attributes
|
||||
|
||||
* Standard C headers are used to define sized types and printf formatters
|
||||
(disable by setting LWIP_NO_STDINT_H=1 or LWIP_NO_INTTYPES_H=1 if your compiler
|
||||
does not support these)
|
||||
|
||||
|
||||
++ Major bugfixes/improvements
|
||||
|
||||
* Added IPv6 support (dual-stack or IPv4/IPv6 only)
|
||||
* Major rewrite of PPP (incl. keep-up with apache pppd)
|
||||
see doc/ppp.txt for an upgrading how-to
|
||||
* Major rewrite of SNMP (incl. MIB parser)
|
||||
* Fixed timing issues that might have lead to losing a DHCP lease
|
||||
* Made rx processing path more robust against crafted errors
|
||||
* TCP window scaling support
|
||||
* modification of api modules to support FreeRTOS-MPU (don't pass stack-pointers to other threads)
|
||||
* made DNS client more robust
|
||||
* support PBUF_REF for RX packets
|
||||
* LWIP_NETCONN_FULLDUPLEX allows netconn/sockets to be used for reading/writing from separate
|
||||
threads each (needs LWIP_NETCONN_SEM_PER_THREAD)
|
||||
* Moved and reordered stats (mainly memp/mib2)
|
||||
|
||||
(1.4.0)
|
||||
|
||||
++ Application changes:
|
||||
|
||||
* Replaced struct ip_addr by typedef ip_addr_t (struct ip_addr is kept for
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
doxygen/ - Configuration files and scripts to create the lwIP doxygen source
|
||||
documentation (found at http://www.nongnu.org/lwip/)
|
||||
|
||||
savannah.txt - How to obtain the current development source code.
|
||||
contrib.txt - How to contribute to lwIP as a developer.
|
||||
rawapi.txt - The documentation for the core API of lwIP.
|
||||
Also provides an overview about the other APIs and multithreading.
|
||||
snmp_agent.txt - The documentation for the lwIP SNMP agent.
|
||||
sys_arch.txt - The documentation for a system abstraction layer of lwIP.
|
||||
ppp.txt - Documentation of the PPP interface for lwIP.
|
||||
|
||||
122
doc/NO_SYS_SampleCode.c
Normal file
122
doc/NO_SYS_SampleCode.c
Normal file
@@ -0,0 +1,122 @@
|
||||
void
|
||||
eth_mac_irq()
|
||||
{
|
||||
/* Service MAC IRQ here */
|
||||
|
||||
/* Allocate pbuf from pool (avoid using heap in interrupts) */
|
||||
struct pbuf* p = pbuf_alloc(PBUF_RAW, eth_data_count, PBUF_POOL);
|
||||
|
||||
if(p != NULL) {
|
||||
/* Copy ethernet frame into pbuf */
|
||||
pbuf_take(p, eth_data, eth_data_count);
|
||||
|
||||
/* Put in a queue which is processed in main loop */
|
||||
if(!queue_try_put(&queue, p)) {
|
||||
/* queue is full -> packet loss */
|
||||
pbuf_free(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static err_t
|
||||
netif_output(struct netif *netif, struct pbuf *p)
|
||||
{
|
||||
LINK_STATS_INC(link.xmit);
|
||||
|
||||
/* Update SNMP stats (only if you use SNMP) */
|
||||
MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->tot_len);
|
||||
int unicast = ((p->payload[0] & 0x01) == 0);
|
||||
if (unicast) {
|
||||
MIB2_STATS_NETIF_INC(netif, ifoutucastpkts);
|
||||
} else {
|
||||
MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts);
|
||||
}
|
||||
|
||||
lock_interrupts();
|
||||
pbuf_copy_partial(p, mac_send_buffer, p->tot_len, 0);
|
||||
/* Start MAC transmit here */
|
||||
unlock_interrupts();
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
netif->linkoutput = netif_output;
|
||||
netif->output = etharp_output;
|
||||
netif->output_ip6 = ethip6_output;
|
||||
netif->mtu = ETHERNET_MTU;
|
||||
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, ETH_HWADDR_LEN);
|
||||
netif->hwaddr_len = ETH_HWADDR_LEN;
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
void
|
||||
main(void)
|
||||
{
|
||||
struct netif netif;
|
||||
|
||||
lwip_init();
|
||||
|
||||
netif_add(&netif, IP4_ADDR_ANY, IP4_ADDR_ANY, IP4_ADDR_ANY, NULL, netif_init, netif_input);
|
||||
netif.name[0] = 'e';
|
||||
netif.name[1] = '0';
|
||||
netif_create_ip6_linklocal_address(&netif, 1);
|
||||
netif.ip6_autoconfig_enabled = 1;
|
||||
netif_set_status_callback(&netif, netif_status_callback);
|
||||
netif_set_default(&netif);
|
||||
netif_set_up(&netif);
|
||||
|
||||
/* Start DHCP and HTTPD */
|
||||
dhcp_start(&netif );
|
||||
httpd_init();
|
||||
|
||||
while(1) {
|
||||
/* Check link state, e.g. via MDIO communication with PHY */
|
||||
if(link_state_changed()) {
|
||||
if(link_is_up()) {
|
||||
netif_set_link_up(&netif);
|
||||
} else {
|
||||
netif_set_link_down(&netif);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for received frames, feed them to lwIP */
|
||||
lock_interrupts();
|
||||
struct pbuf* p = queue_try_get(&queue);
|
||||
unlock_interrupts();
|
||||
|
||||
if(p != NULL) {
|
||||
LINK_STATS_INC(link.recv);
|
||||
|
||||
/* Update SNMP stats (only if you use SNMP) */
|
||||
MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len);
|
||||
int unicast = ((p->payload[0] & 0x01) == 0);
|
||||
if (unicast) {
|
||||
MIB2_STATS_NETIF_INC(netif, ifinucastpkts);
|
||||
} else {
|
||||
MIB2_STATS_NETIF_INC(netif, ifinnucastpkts);
|
||||
}
|
||||
|
||||
if(netif.input(p, &netif) != ERR_OK) {
|
||||
pbuf_free(p);
|
||||
}
|
||||
}
|
||||
|
||||
/* Cyclic lwIP timers check */
|
||||
sys_check_timeouts();
|
||||
|
||||
/* your application goes here */
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -34,30 +34,25 @@ features of Savannah help us not lose users' input.
|
||||
2.3 Bug reports and patches:
|
||||
|
||||
1. Make sure you are reporting bugs or send patches against the latest
|
||||
sources. (From the latest release and/or the current CVS sources.)
|
||||
sources. (From the latest release and/or the current Git sources.)
|
||||
2. If you think you found a bug make sure it's not already filed in the
|
||||
bugtracker at Savannah.
|
||||
3. If you have a fix put the patch on Savannah. If it is a patch that affects
|
||||
both core and arch specific stuff please separate them so that the core can
|
||||
be applied separately while leaving the other patch 'open'. The prefered way
|
||||
be applied separately while leaving the other patch 'open'. The preferred way
|
||||
is to NOT touch archs you can't test and let maintainers take care of them.
|
||||
This is a good way to see if they are used at all - the same goes for unix
|
||||
netifs except tapif.
|
||||
4. Do not file a bug and post a fix to it to the patch area. Either a bug report
|
||||
or a patch will be enough.
|
||||
If you correct an existing bug then attach the patch to the bug rather than creating a new entry in the patch area.
|
||||
5. Trivial patches (compiler warning, indentation and spelling fixes or anything obvious which takes a line or two)
|
||||
can go to the lwip-users list. This is still the fastest way of interaction and the list is not so crowded
|
||||
as to allow for loss of fixes. Putting bugs on Savannah and subsequently closing them is too much an overhead
|
||||
for reporting a compiler warning fix.
|
||||
6. Patches should be specific to a single change or to related changes.Do not mix bugfixes with spelling and other
|
||||
trivial fixes unless the bugfix is trivial too.Do not reorganize code and rename identifiers in the same patch you
|
||||
change behaviour if not necessary.A patch is easier to read and understand if it's to the point and short than
|
||||
5. Patches should be specific to a single change or to related changes. Do not mix bugfixes with spelling and other
|
||||
trivial fixes unless the bugfix is trivial too. Do not reorganize code and rename identifiers in the same patch you
|
||||
change behaviour if not necessary. A patch is easier to read and understand if it's to the point and short than
|
||||
if it's not to the point and long :) so the chances for it to be applied are greater.
|
||||
|
||||
2.4 Platform porters:
|
||||
|
||||
1. If you have ported lwIP to a platform (an OS, a uC/processor or a combination of these) and
|
||||
you think it could benefit others[1] you might want discuss this on the mailing list. You
|
||||
can also ask for CVS access to submit and maintain your port in the contrib CVS module.
|
||||
|
||||
can also ask for Git access to submit and maintain your port in the contrib Git module.
|
||||
|
||||
1
doc/doxygen/generate.bat
Normal file
1
doc/doxygen/generate.bat
Normal file
@@ -0,0 +1 @@
|
||||
doxygen lwip.Doxyfile
|
||||
3
doc/doxygen/generate.sh
Executable file
3
doc/doxygen/generate.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
doxygen lwip.Doxyfile
|
||||
2531
doc/doxygen/lwip.Doxyfile
Normal file
2531
doc/doxygen/lwip.Doxyfile
Normal file
File diff suppressed because it is too large
Load Diff
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
412
doc/doxygen/main_page.h
Normal file
412
doc/doxygen/main_page.h
Normal file
@@ -0,0 +1,412 @@
|
||||
/**
|
||||
* @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 "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 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
|
||||
*/
|
||||
|
||||
/**
|
||||
* @mainpage Overview
|
||||
* @verbinclude "README"
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page upgrading Upgrading
|
||||
* @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"
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page pitfalls Common pitfalls
|
||||
*
|
||||
* Multiple Execution Contexts in lwIP code
|
||||
* ========================================
|
||||
*
|
||||
* The most common source of lwIP problems is to have multiple execution contexts
|
||||
* inside the lwIP code.
|
||||
*
|
||||
* 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
|
||||
* -------------
|
||||
* In mainloop mode, only @ref callbackstyle_api can be used.
|
||||
* The user has two possibilities to ensure there is only one
|
||||
* exection context at a time in lwIP:
|
||||
*
|
||||
* 1) Deliver RX ethernet packets directly in interrupt context to lwIP
|
||||
* by calling netif->input directly in interrupt. This implies all lwIP
|
||||
* callback functions are called in IRQ context, which may cause further
|
||||
* problems in application code: IRQ is blocked for a long time, multiple
|
||||
* execution contexts in application code etc. When the application wants
|
||||
* to call lwIP, it only needs to disable interrupts during the call.
|
||||
* If timers are involved, even more locking code is needed to lock out
|
||||
* timer IRQ and ethernet IRQ from each other, assuming these may be nested.
|
||||
*
|
||||
* 2) Run lwIP in a mainloop. There is example code here: @ref lwip_nosys.
|
||||
* lwIP is _ONLY_ called from mainloop callstacks here. The ethernet IRQ
|
||||
* has to put received telegrams into a queue which is polled in the
|
||||
* mainloop. Ensure lwIP is _NEVER_ called from an interrupt, e.g.
|
||||
* some SPI IRQ wants to forward data to udp_send() or tcp_write()!
|
||||
*
|
||||
* OS Mode
|
||||
* -------
|
||||
* In OS mode, @ref callbackstyle_api AND @ref sequential_api can be used.
|
||||
* @ref sequential_api are designed to be called from threads other than
|
||||
* the TCPIP thread, so there is nothing to consider here.
|
||||
* But @ref callbackstyle_api functions must _ONLY_ be called from
|
||||
* TCPIP thread. It is a common error to call these from other threads
|
||||
* or from IRQ contexts. Ethernet RX needs to deliver incoming packets
|
||||
* in the correct way by sending a message to TCPIP thread, this is
|
||||
* implemented in tcpip_input().
|
||||
* Again, ensure lwIP is _NEVER_ called from an interrupt, e.g.
|
||||
* some SPI IRQ wants to forward data to udp_send() or tcp_write()!
|
||||
*
|
||||
* 1) tcpip_callback() can be used get called back from TCPIP thread,
|
||||
* it is safe to call any @ref callbackstyle_api from there.
|
||||
*
|
||||
* 2) Use @ref LWIP_TCPIP_CORE_LOCKING. All @ref callbackstyle_api
|
||||
* functions can be called when lwIP core lock is aquired, see
|
||||
* @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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page bugs Reporting bugs
|
||||
* Please report bugs in the lwIP bug tracker at savannah.\n
|
||||
* BEFORE submitting, please check if the bug has already been reported!\n
|
||||
* 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
|
||||
* Use this mode if you do not run an OS on your system. \#define NO_SYS to 1.
|
||||
* Feed incoming packets to netif->input(pbuf, netif) function from mainloop,
|
||||
* *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, @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
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup lwip_os OS mode (TCPIP thread)
|
||||
* @ingroup lwip
|
||||
* Use this mode if you run an OS on your system. It is recommended to
|
||||
* use an RTOS that correctly handles priority inversion and
|
||||
* to use @ref LWIP_TCPIP_CORE_LOCKING.\n
|
||||
* Porting: implement all functions in @ref sys_layer.\n
|
||||
* You can use @ref callbackstyle_api together with @ref tcpip_callback,
|
||||
* and all @ref sequential_api.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*/
|
||||
10
doc/doxygen/output/index.html
Normal file
10
doc/doxygen/output/index.html
Normal file
@@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Redirection</title>
|
||||
<meta http-equiv="refresh" content="0; url=html/index.html" />
|
||||
</head>
|
||||
<body>
|
||||
<a href="html/index.html">index.html</a>
|
||||
</body>
|
||||
</html>
|
||||
112
doc/mdns.txt
Normal file
112
doc/mdns.txt
Normal file
@@ -0,0 +1,112 @@
|
||||
Multicast DNS for lwIP
|
||||
|
||||
Author: Erik Ekman
|
||||
|
||||
|
||||
Note! The MDNS responder does not have all features required by the standards.
|
||||
See notes in src/apps/mdns/mdns.c for what is left. It is however usable in normal
|
||||
cases - but watch out if many devices on the same network try to use the same
|
||||
host/service instance names.
|
||||
|
||||
|
||||
How to enable:
|
||||
==============
|
||||
|
||||
MDNS support does not depend on DNS.
|
||||
MDNS supports using IPv4 only, v6 only, or v4+v6.
|
||||
|
||||
To enable MDNS responder, set
|
||||
LWIP_MDNS_RESPONDER = 1
|
||||
in lwipopts.h and add src/apps/mdns/mdns.c to your list of files to build.
|
||||
|
||||
The max number of services supported per netif is defined by MDNS_MAX_SERVICES,
|
||||
default is 1.
|
||||
|
||||
Increase MEMP_NUM_UDP_PCB by 1. MDNS needs one PCB.
|
||||
Increase LWIP_NUM_NETIF_CLIENT_DATA by 1 (MDNS needs one entry on netif).
|
||||
|
||||
MDNS with IPv4 requires LWIP_IGMP = 1, and preferably LWIP_AUTOIP = 1.
|
||||
MDNS with IPv6 requires LWIP_IPV6_MLD = 1, and that a link-local address is
|
||||
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 (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.
|
||||
|
||||
|
||||
How to use:
|
||||
===========
|
||||
|
||||
Call mdns_resp_init() during system initialization.
|
||||
This opens UDP sockets on port 5353 for IPv4 and IPv6.
|
||||
|
||||
|
||||
To start responding on a netif, run
|
||||
mdns_resp_add_netif(struct netif *netif, char *hostname, u32_t dns_ttl)
|
||||
|
||||
The hostname will be copied. If this returns successfully, the netif will join
|
||||
the multicast groups and any MDNS/legacy DNS requests sent unicast or multicast
|
||||
to port 5353 will be handled:
|
||||
- <hostname>.local type A, AAAA or ANY returns relevant IP addresses
|
||||
- Reverse lookups (PTR in-addr.arpa, ip6.arpa) of netif addresses
|
||||
returns <hostname>.local
|
||||
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.
|
||||
|
||||
Call mdns_resp_announce() 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)
|
||||
|
||||
|
||||
Adding services:
|
||||
================
|
||||
|
||||
The netif first needs to be registered. Then run
|
||||
mdns_resp_add_service(struct netif *netif, char *name, char *service,
|
||||
u16_t proto, u16_t port, u32_t dns_ttl,
|
||||
service_get_txt_fn_t txt_fn, void *txt_userdata);
|
||||
|
||||
The name and service pointers will be copied. Name refers to the name of the
|
||||
service instance, and service is the type of service, like _http
|
||||
proto can be DNSSD_PROTO_UDP or DNSSD_PROTO_TCP which represent _udp and _tcp.
|
||||
If this call returns successfully, the following queries will be answered:
|
||||
- _services._dns-sd._udp.local type PTR returns <service>.<proto>.local
|
||||
- <service>.<proto>.local type PTR returns <name>.<service>.<proto>.local
|
||||
- <name>.<service>.<proto>.local type SRV returns hostname and port of service
|
||||
- <name>.<service>.<proto>.local type TXT builds text strings by calling txt_fn
|
||||
with the supplied userdata. The callback adds strings to the reply by calling
|
||||
mdns_resp_add_service_txtitem(struct mdns_service *service, char *txt,
|
||||
int txt_len). Example callback method:
|
||||
|
||||
static void srv_txt(struct mdns_service *service, void *txt_userdata)
|
||||
{
|
||||
res = mdns_resp_add_service_txtitem(service, "path=/", 6);
|
||||
LWIP_ERROR("mdns add service txt failed\n", (res == ERR_OK), return);
|
||||
}
|
||||
|
||||
Since a hostname struct is used for TXT storage each single item can be max
|
||||
63 bytes long, and the total max length (including length bytes for each
|
||||
item) is 255 bytes.
|
||||
|
||||
If your device runs a webserver on port 80, an example call might be:
|
||||
|
||||
mdns_resp_add_service(netif, "myweb", "_http"
|
||||
DNSSD_PROTO_TCP, 80, 3600, srv_txt, NULL);
|
||||
|
||||
which will publish myweb._http._tcp.local for any hosts looking for web servers,
|
||||
and point them to <hostname>.local:80
|
||||
|
||||
Relevant information will be sent as additional records to reduce number of
|
||||
requests required from a client.
|
||||
|
||||
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)
|
||||
529
doc/ppp.txt
Normal file
529
doc/ppp.txt
Normal file
@@ -0,0 +1,529 @@
|
||||
PPP interface for lwIP
|
||||
|
||||
Author: Sylvain Rochet
|
||||
|
||||
Table of Contents:
|
||||
|
||||
1 - Supported PPP protocols and features
|
||||
2 - Raw API PPP example for all protocols
|
||||
3 - PPPoS input path (raw API, IRQ safe API, TCPIP API)
|
||||
4 - Thread safe PPP API (PPPAPI)
|
||||
5 - Notify phase callback (PPP_NOTIFY_PHASE)
|
||||
6 - Upgrading from lwIP <= 1.4.x to lwIP >= 2.0.x
|
||||
|
||||
|
||||
|
||||
1 Supported PPP protocols and features
|
||||
======================================
|
||||
|
||||
Supported Low level protocols:
|
||||
* PPP over serial using HDLC-like framing, such as wired dialup modems
|
||||
or mobile telecommunications GPRS/EDGE/UMTS/HSPA+/LTE modems
|
||||
* PPP over Ethernet, such as xDSL modems
|
||||
* PPP over L2TP (Layer 2 Tunneling Protocol) LAC (L2TP Access Concentrator),
|
||||
IP tunnel over UDP, such as VPN access
|
||||
|
||||
Supported auth protocols:
|
||||
* PAP, Password Authentication Protocol
|
||||
* CHAP, Challenge-Handshake Authentication Protocol, also known as CHAP-MD5
|
||||
* MSCHAPv1, Microsoft version of CHAP, version 1
|
||||
* MSCHAPv2, Microsoft version of CHAP, version 2
|
||||
* EAP, Extensible Authentication Protocol
|
||||
|
||||
Supported address protocols:
|
||||
* IPCP, IP Control Protocol, IPv4 addresses negotiation
|
||||
* IP6CP, IPv6 Control Protocol, IPv6 link-local addresses negotiation
|
||||
|
||||
Supported encryption protocols:
|
||||
* MPPE, Microsoft Point-to-Point Encryption
|
||||
|
||||
Supported compression or miscellaneous protocols, for serial links only:
|
||||
* PFC, Protocol Field Compression
|
||||
* ACFC, Address-and-Control-Field-Compression
|
||||
* ACCM, Asynchronous-Control-Character-Map
|
||||
* VJ, Van Jacobson TCP/IP Header Compression
|
||||
|
||||
|
||||
|
||||
2 Raw API PPP example for all protocols
|
||||
=======================================
|
||||
|
||||
As usual, raw API for lwIP means the lightweight API which *MUST* only be used
|
||||
for NO_SYS=1 systems or called inside lwIP core thread for NO_SYS=0 systems.
|
||||
|
||||
/*
|
||||
* Globals
|
||||
* =======
|
||||
*/
|
||||
|
||||
/* The PPP control block */
|
||||
ppp_pcb *ppp;
|
||||
|
||||
/* The PPP IP interface */
|
||||
struct netif ppp_netif;
|
||||
|
||||
|
||||
/*
|
||||
* PPP status callback
|
||||
* ===================
|
||||
*
|
||||
* PPP status callback is called on PPP status change (up, down, …) from lwIP
|
||||
* core thread
|
||||
*/
|
||||
|
||||
/* PPP status callback example */
|
||||
static void status_cb(ppp_pcb *pcb, int err_code, void *ctx) {
|
||||
struct netif *pppif = ppp_netif(pcb);
|
||||
LWIP_UNUSED_ARG(ctx);
|
||||
|
||||
switch(err_code) {
|
||||
case PPPERR_NONE: {
|
||||
#if LWIP_DNS
|
||||
const ip_addr_t *ns;
|
||||
#endif /* LWIP_DNS */
|
||||
printf("status_cb: Connected\n");
|
||||
#if PPP_IPV4_SUPPORT
|
||||
printf(" our_ipaddr = %s\n", ipaddr_ntoa(&pppif->ip_addr));
|
||||
printf(" his_ipaddr = %s\n", ipaddr_ntoa(&pppif->gw));
|
||||
printf(" netmask = %s\n", ipaddr_ntoa(&pppif->netmask));
|
||||
#if LWIP_DNS
|
||||
ns = dns_getserver(0);
|
||||
printf(" dns1 = %s\n", ipaddr_ntoa(ns));
|
||||
ns = dns_getserver(1);
|
||||
printf(" dns2 = %s\n", ipaddr_ntoa(ns));
|
||||
#endif /* LWIP_DNS */
|
||||
#endif /* PPP_IPV4_SUPPORT */
|
||||
#if PPP_IPV6_SUPPORT
|
||||
printf(" our6_ipaddr = %s\n", ip6addr_ntoa(netif_ip6_addr(pppif, 0)));
|
||||
#endif /* PPP_IPV6_SUPPORT */
|
||||
break;
|
||||
}
|
||||
case PPPERR_PARAM: {
|
||||
printf("status_cb: Invalid parameter\n");
|
||||
break;
|
||||
}
|
||||
case PPPERR_OPEN: {
|
||||
printf("status_cb: Unable to open PPP session\n");
|
||||
break;
|
||||
}
|
||||
case PPPERR_DEVICE: {
|
||||
printf("status_cb: Invalid I/O device for PPP\n");
|
||||
break;
|
||||
}
|
||||
case PPPERR_ALLOC: {
|
||||
printf("status_cb: Unable to allocate resources\n");
|
||||
break;
|
||||
}
|
||||
case PPPERR_USER: {
|
||||
printf("status_cb: User interrupt\n");
|
||||
break;
|
||||
}
|
||||
case PPPERR_CONNECT: {
|
||||
printf("status_cb: Connection lost\n");
|
||||
break;
|
||||
}
|
||||
case PPPERR_AUTHFAIL: {
|
||||
printf("status_cb: Failed authentication challenge\n");
|
||||
break;
|
||||
}
|
||||
case PPPERR_PROTOCOL: {
|
||||
printf("status_cb: Failed to meet protocol\n");
|
||||
break;
|
||||
}
|
||||
case PPPERR_PEERDEAD: {
|
||||
printf("status_cb: Connection timeout\n");
|
||||
break;
|
||||
}
|
||||
case PPPERR_IDLETIMEOUT: {
|
||||
printf("status_cb: Idle Timeout\n");
|
||||
break;
|
||||
}
|
||||
case PPPERR_CONNECTTIME: {
|
||||
printf("status_cb: Max connect time reached\n");
|
||||
break;
|
||||
}
|
||||
case PPPERR_LOOPBACK: {
|
||||
printf("status_cb: Loopback detected\n");
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
printf("status_cb: Unknown error code %d\n", err_code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This should be in the switch case, this is put outside of the switch
|
||||
* case for example readability.
|
||||
*/
|
||||
|
||||
if (err_code == PPPERR_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* ppp_close() was previously called, don't reconnect */
|
||||
if (err_code == PPPERR_USER) {
|
||||
/* ppp_free(); -- can be called here */
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to reconnect in 30 seconds, if you need a modem chatscript you have
|
||||
* to do a much better signaling here ;-)
|
||||
*/
|
||||
ppp_connect(pcb, 30);
|
||||
/* OR ppp_listen(pcb); */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Creating a new PPPoS session
|
||||
* ============================
|
||||
*
|
||||
* In lwIP, PPPoS is not PPPoSONET, in lwIP PPPoS is PPPoSerial.
|
||||
*/
|
||||
|
||||
#include "netif/ppp/pppos.h"
|
||||
|
||||
/*
|
||||
* PPPoS serial output callback
|
||||
*
|
||||
* ppp_pcb, PPP control block
|
||||
* data, buffer to write to serial port
|
||||
* len, length of the data buffer
|
||||
* ctx, optional user-provided callback context pointer
|
||||
*
|
||||
* Return value: len if write succeed
|
||||
*/
|
||||
static u32_t output_cb(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx) {
|
||||
return uart_write(UART, data, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new PPPoS interface
|
||||
*
|
||||
* ppp_netif, netif to use for this PPP link, i.e. PPP IP interface
|
||||
* output_cb, PPPoS serial output callback
|
||||
* status_cb, PPP status callback, called on PPP status change (up, down, …)
|
||||
* ctx_cb, optional user-provided callback context pointer
|
||||
*/
|
||||
ppp = pppos_create(&ppp_netif,
|
||||
output_cb, status_cb, ctx_cb);
|
||||
|
||||
|
||||
/*
|
||||
* Creating a new PPPoE session
|
||||
* ============================
|
||||
*/
|
||||
|
||||
#include "netif/ppp/pppoe.h"
|
||||
|
||||
/*
|
||||
* Create a new PPPoE interface
|
||||
*
|
||||
* ppp_netif, netif to use for this PPP link, i.e. PPP IP interface
|
||||
* ethif, already existing and setup Ethernet interface to use
|
||||
* service_name, PPPoE service name discriminator (not supported yet)
|
||||
* concentrator_name, PPPoE concentrator name discriminator (not supported yet)
|
||||
* status_cb, PPP status callback, called on PPP status change (up, down, …)
|
||||
* ctx_cb, optional user-provided callback context pointer
|
||||
*/
|
||||
ppp = pppoe_create(&ppp_netif,
|
||||
ðif,
|
||||
service_name, concentrator_name,
|
||||
status_cb, ctx_cb);
|
||||
|
||||
|
||||
/*
|
||||
* Creating a new PPPoL2TP session
|
||||
* ===============================
|
||||
*/
|
||||
|
||||
#include "netif/ppp/pppol2tp.h"
|
||||
|
||||
/*
|
||||
* Create a new PPPoL2TP interface
|
||||
*
|
||||
* ppp_netif, netif to use for this PPP link, i.e. PPP IP interface
|
||||
* netif, optional already existing and setup output netif, necessary if you
|
||||
* want to set this interface as default route to settle the chicken
|
||||
* and egg problem with VPN links
|
||||
* ipaddr, IP to connect to
|
||||
* port, UDP port to connect to (usually 1701)
|
||||
* secret, L2TP secret to use
|
||||
* secret_len, size in bytes of the L2TP secret
|
||||
* status_cb, PPP status callback, called on PPP status change (up, down, …)
|
||||
* ctx_cb, optional user-provided callback context pointer
|
||||
*/
|
||||
ppp = pppol2tp_create(&ppp_netif,
|
||||
struct netif *netif, ip_addr_t *ipaddr, u16_t port,
|
||||
u8_t *secret, u8_t secret_len,
|
||||
ppp_link_status_cb_fn link_status_cb, void *ctx_cb);
|
||||
|
||||
|
||||
/*
|
||||
* Initiate PPP client connection
|
||||
* ==============================
|
||||
*/
|
||||
|
||||
/* Set this interface as default route */
|
||||
ppp_set_default(ppp);
|
||||
|
||||
/*
|
||||
* Basic PPP client configuration. Can only be set if PPP session is in the
|
||||
* dead state (i.e. disconnected). We don't need to provide thread-safe
|
||||
* equivalents through PPPAPI because those helpers are only changing
|
||||
* structure members while session is inactive for lwIP core. Configuration
|
||||
* only need to be done once.
|
||||
*/
|
||||
|
||||
/* Ask the peer for up to 2 DNS server addresses. */
|
||||
ppp_set_usepeerdns(ppp, 1);
|
||||
|
||||
/* Auth configuration, this is pretty self-explanatory */
|
||||
ppp_set_auth(ppp, PPPAUTHTYPE_ANY, "login", "password");
|
||||
|
||||
/*
|
||||
* Initiate PPP negotiation, without waiting (holdoff=0), can only be called
|
||||
* if PPP session is in the dead state (i.e. disconnected).
|
||||
*/
|
||||
u16_t holdoff = 0;
|
||||
ppp_connect(ppp, holdoff);
|
||||
|
||||
|
||||
/*
|
||||
* Initiate PPP server listener
|
||||
* ============================
|
||||
*/
|
||||
|
||||
/*
|
||||
* Basic PPP server configuration. Can only be set if PPP session is in the
|
||||
* dead state (i.e. disconnected). We don't need to provide thread-safe
|
||||
* equivalents through PPPAPI because those helpers are only changing
|
||||
* structure members while session is inactive for lwIP core. Configuration
|
||||
* only need to be done once.
|
||||
*/
|
||||
ip4_addr_t addr;
|
||||
|
||||
/* Set our address */
|
||||
IP4_ADDR(&addr, 192,168,0,1);
|
||||
ppp_set_ipcp_ouraddr(ppp, &addr);
|
||||
|
||||
/* Set peer(his) address */
|
||||
IP4_ADDR(&addr, 192,168,0,2);
|
||||
ppp_set_ipcp_hisaddr(ppp, &addr);
|
||||
|
||||
/* Set primary DNS server */
|
||||
IP4_ADDR(&addr, 192,168,10,20);
|
||||
ppp_set_ipcp_dnsaddr(ppp, 0, &addr);
|
||||
|
||||
/* Set secondary DNS server */
|
||||
IP4_ADDR(&addr, 192,168,10,21);
|
||||
ppp_set_ipcp_dnsaddr(ppp, 1, &addr);
|
||||
|
||||
/* Auth configuration, this is pretty self-explanatory */
|
||||
ppp_set_auth(ppp, PPPAUTHTYPE_ANY, "login", "password");
|
||||
|
||||
/* Require peer to authenticate */
|
||||
ppp_set_auth_required(ppp, 1);
|
||||
|
||||
/*
|
||||
* Only for PPPoS, the PPP session should be up and waiting for input.
|
||||
*
|
||||
* Note: for PPPoS, ppp_connect() and ppp_listen() are actually the same thing.
|
||||
* The listen call is meant for future support of PPPoE and PPPoL2TP server
|
||||
* mode, where we will need to negotiate the incoming PPPoE session or L2TP
|
||||
* session before initiating PPP itself. We need this call because there is
|
||||
* two passive modes for PPPoS, ppp_set_passive and ppp_set_silent.
|
||||
*/
|
||||
ppp_set_silent(pppos, 1);
|
||||
|
||||
/*
|
||||
* Initiate PPP listener (i.e. wait for an incoming connection), can only
|
||||
* be called if PPP session is in the dead state (i.e. disconnected).
|
||||
*/
|
||||
ppp_listen(ppp);
|
||||
|
||||
|
||||
/*
|
||||
* Closing PPP connection
|
||||
* ======================
|
||||
*/
|
||||
|
||||
/*
|
||||
* Initiate the end of the PPP session, without carrier lost signal
|
||||
* (nocarrier=0), meaning a clean shutdown of PPP protocols.
|
||||
* You can call this function at anytime.
|
||||
*/
|
||||
u8_t nocarrier = 0;
|
||||
ppp_close(ppp, nocarrier);
|
||||
/*
|
||||
* Then you must wait your status_cb() to be called, it may takes from a few
|
||||
* seconds to several tens of seconds depending on the current PPP state.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Freeing a PPP connection
|
||||
* ========================
|
||||
*/
|
||||
|
||||
/*
|
||||
* Free the PPP control block, can only be called if PPP session is in the
|
||||
* dead state (i.e. disconnected). You need to call ppp_close() before.
|
||||
*/
|
||||
ppp_free(ppp);
|
||||
|
||||
|
||||
|
||||
3 PPPoS input path (raw API, IRQ safe API, TCPIP API)
|
||||
=====================================================
|
||||
|
||||
Received data on serial port should be sent to lwIP using the pppos_input()
|
||||
function or the pppos_input_tcpip() function.
|
||||
|
||||
If NO_SYS is 1 and if PPP_INPROC_IRQ_SAFE is 0 (the default), pppos_input()
|
||||
is not IRQ safe and then *MUST* only be called inside your main loop.
|
||||
|
||||
Whatever the NO_SYS value, if PPP_INPROC_IRQ_SAFE is 1, pppos_input() is IRQ
|
||||
safe and can be safely called from an interrupt context, using that is going
|
||||
to reduce your need of buffer if pppos_input() is called byte after byte in
|
||||
your rx serial interrupt.
|
||||
|
||||
if NO_SYS is 0, the thread safe way outside an interrupt context is to use
|
||||
the pppos_input_tcpip() function to pass input data to the lwIP core thread
|
||||
using the TCPIP API. This is thread safe in all cases but you should avoid
|
||||
passing data byte after byte because it uses heavy locking (mailbox) and it
|
||||
allocates pbuf, better fill them !
|
||||
|
||||
if NO_SYS is 0 and if PPP_INPROC_IRQ_SAFE is 1, you may also use pppos_input()
|
||||
from an RX thread, however pppos_input() is not thread safe by itself. You can
|
||||
do that *BUT* you should NEVER call pppos_connect(), pppos_listen() and
|
||||
ppp_free() if pppos_input() can still be running, doing this is NOT thread safe
|
||||
at all. Using PPP_INPROC_IRQ_SAFE from an RX thread is discouraged unless you
|
||||
really know what you are doing, your move ;-)
|
||||
|
||||
|
||||
/*
|
||||
* Fonction to call for received data
|
||||
*
|
||||
* ppp, PPP control block
|
||||
* buffer, input buffer
|
||||
* buffer_len, buffer length in bytes
|
||||
*/
|
||||
void pppos_input(ppp, buffer, buffer_len);
|
||||
|
||||
or
|
||||
|
||||
void pppos_input_tcpip(ppp, buffer, buffer_len);
|
||||
|
||||
|
||||
|
||||
4 Thread safe PPP API (PPPAPI)
|
||||
==============================
|
||||
|
||||
There is a thread safe API for all corresponding ppp_* functions, you have to
|
||||
enable LWIP_PPP_API in your lwipopts.h file, then see
|
||||
include/netif/ppp/pppapi.h, this is actually pretty obvious.
|
||||
|
||||
|
||||
|
||||
5 Notify phase callback (PPP_NOTIFY_PHASE)
|
||||
==========================================
|
||||
|
||||
Notify phase callback, enabled using the PPP_NOTIFY_PHASE config option, let
|
||||
you configure a callback that is called on each PPP internal state change.
|
||||
This is different from the status callback which only warns you about
|
||||
up(running) and down(dead) events.
|
||||
|
||||
Notify phase callback can be used, for example, to set a LED pattern depending
|
||||
on the current phase of the PPP session. Here is a callback example which
|
||||
tries to mimic what we usually see on xDSL modems while they are negotiating
|
||||
the link, which should be self-explanatory:
|
||||
|
||||
static void ppp_notify_phase_cb(ppp_pcb *pcb, u8_t phase, void *ctx) {
|
||||
switch (phase) {
|
||||
|
||||
/* Session is down (either permanently or briefly) */
|
||||
case PPP_PHASE_DEAD:
|
||||
led_set(PPP_LED, LED_OFF);
|
||||
break;
|
||||
|
||||
/* We are between two sessions */
|
||||
case PPP_PHASE_HOLDOFF:
|
||||
led_set(PPP_LED, LED_SLOW_BLINK);
|
||||
break;
|
||||
|
||||
/* Session just started */
|
||||
case PPP_PHASE_INITIALIZE:
|
||||
led_set(PPP_LED, LED_FAST_BLINK);
|
||||
break;
|
||||
|
||||
/* Session is running */
|
||||
case PPP_PHASE_RUNNING:
|
||||
led_set(PPP_LED, LED_ON);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
6 Upgrading from lwIP <= 1.4.x to lwIP >= 2.0.x
|
||||
===============================================
|
||||
|
||||
PPP API was fully reworked between 1.4.x and 2.0.x releases. However porting
|
||||
from previous lwIP version is pretty easy:
|
||||
|
||||
* Previous PPP API used an integer to identify PPP sessions, we are now
|
||||
using ppp_pcb* control block, therefore all functions changed from "int ppp"
|
||||
to "ppp_pcb *ppp"
|
||||
|
||||
* struct netif was moved outside the PPP structure, you have to provide a netif
|
||||
for PPP interface in pppoX_create() functions
|
||||
|
||||
* PPP session are not started automatically after you created them anymore,
|
||||
you have to call ppp_connect(), this way you can configure the session before
|
||||
starting it.
|
||||
|
||||
* Previous PPP API used CamelCase, we are now using snake_case.
|
||||
|
||||
* Previous PPP API mixed PPPoS and PPPoE calls, this isn't the case anymore,
|
||||
PPPoS functions are now prefixed pppos_ and PPPoE functions are now prefixed
|
||||
pppoe_, common functions are now prefixed ppp_.
|
||||
|
||||
* New PPPERR_ error codes added, check you have all of them in your status
|
||||
callback function
|
||||
|
||||
* Only the following include files should now be used in user application:
|
||||
#include "netif/ppp/pppapi.h"
|
||||
#include "netif/ppp/pppos.h"
|
||||
#include "netif/ppp/pppoe.h"
|
||||
#include "netif/ppp/pppol2tp.h"
|
||||
|
||||
Functions from ppp.h can be used, but you don't need to include this header
|
||||
file as it is already included by above header files.
|
||||
|
||||
* PPP_INPROC_OWNTHREAD was broken by design and was removed, you have to create
|
||||
your own serial rx thread
|
||||
|
||||
* PPP_INPROC_MULTITHREADED option was misnamed and confusing and was renamed
|
||||
PPP_INPROC_IRQ_SAFE, please read the "PPPoS input path" documentation above
|
||||
because you might have been fooled by that
|
||||
|
||||
* If you used tcpip_callback_with_block() on ppp_ functions you may wish to use
|
||||
the PPPAPI API instead.
|
||||
|
||||
* ppp_sighup and ppp_close functions were merged using an optional argument
|
||||
"nocarrier" on ppp_close.
|
||||
|
||||
* DNS servers are now only remotely asked if LWIP_DNS is set and if
|
||||
ppp_set_usepeerdns() is set to true, they are now automatically registered
|
||||
using the dns_setserver() function so you don't need to do that in the PPP
|
||||
callback anymore.
|
||||
|
||||
* PPPoS does not use the SIO API anymore, as such it now requires a serial
|
||||
output callback in place of sio_write
|
||||
|
||||
* PPP_MAXIDLEFLAG is now in ms instead of jiffies
|
||||
505
doc/rawapi.txt
505
doc/rawapi.txt
@@ -1,505 +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 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.
|
||||
|
||||
** Threading
|
||||
|
||||
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"). The raw API may only be used from
|
||||
this thread! 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
|
||||
- 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.
|
||||
|
||||
Only since 1.3.0, 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.
|
||||
|
||||
Both 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.
|
||||
|
||||
--- Callbacks
|
||||
|
||||
Program execution is driven by callbacks. 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, struct ip_addr *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_accepted(struct tcp_pcb *pcb)
|
||||
|
||||
Inform lwIP that an incoming connection has been accepted. This would
|
||||
usually be called from the accept callback. This allows lwIP to perform
|
||||
housekeeping tasks, such as allowing further incoming connections to be
|
||||
queued in the listen backlog.
|
||||
|
||||
- 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, struct ip_addr *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, void *dataptr, u16_t len,
|
||||
u8_t copy)
|
||||
|
||||
Enqueues the data pointed to by the argument dataptr. The length of
|
||||
the data is passed as the len parameter. The copy argument is either
|
||||
0 or 1 and indicates whether the new memory should be allocated for
|
||||
the data to be copied into. If the argument is 0, no new memory
|
||||
should be allocated and the data should only be referenced by
|
||||
pointer.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
--- Lower layer TCP interface
|
||||
|
||||
TCP provides a simple interface to the lower layers of the
|
||||
system. During system initialization, the function tcp_init() has
|
||||
to be called before any other TCP function is called. When the system
|
||||
is running, the two timer functions tcp_fasttmr() and tcp_slowtmr()
|
||||
must be called with regular intervals. The tcp_fasttmr() should be
|
||||
called every TCP_FAST_INTERVAL milliseconds (defined in tcp.h) and
|
||||
tcp_slowtmr() should be called every TCP_SLOW_INTERVAL milliseconds.
|
||||
|
||||
|
||||
--- 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, struct ip_addr *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, struct ip_addr *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,
|
||||
struct ip_addr *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 the build configuration (lwipopts.h)
|
||||
and 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:
|
||||
|
||||
- stats_init()
|
||||
|
||||
Clears the structure where runtime statistics are gathered.
|
||||
|
||||
- sys_init()
|
||||
|
||||
Not of much use since we set the NO_SYS 1 option in lwipopts.h,
|
||||
to be called for easy configuration changes.
|
||||
|
||||
- mem_init()
|
||||
|
||||
Initializes the dynamic memory heap defined by MEM_SIZE.
|
||||
|
||||
- memp_init()
|
||||
|
||||
Initializes the memory pools defined by MEMP_NUM_x.
|
||||
|
||||
- pbuf_init()
|
||||
|
||||
Initializes the pbuf memory pool defined by PBUF_POOL_SIZE.
|
||||
|
||||
- etharp_init()
|
||||
|
||||
Initializes the ARP table and queue.
|
||||
Note: you must call etharp_tmr at a ARP_TMR_INTERVAL (5 seconds) regular interval
|
||||
after this initialization.
|
||||
|
||||
- ip_init()
|
||||
|
||||
Doesn't do much, it should be called to handle future changes.
|
||||
|
||||
- udp_init()
|
||||
|
||||
Clears the UDP PCB list.
|
||||
|
||||
- tcp_init()
|
||||
|
||||
Clears the TCP PCB list and clears some internal TCP timers.
|
||||
Note: you must call tcp_fasttmr() and tcp_slowtmr() at the
|
||||
predefined regular intervals after this initialization.
|
||||
|
||||
- netif_add(struct netif *netif, struct ip_addr *ipaddr,
|
||||
struct ip_addr *netmask, struct ip_addr *gw,
|
||||
void *state, err_t (* init)(struct netif *netif),
|
||||
err_t (* input)(struct pbuf *p, 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 it's 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_up(struct netif *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.
|
||||
Note: you must call dhcp_fine_tmr() and dhcp_coarse_tmr() at
|
||||
the predefined regular intervals after starting the client.
|
||||
|
||||
You can peek in the netif->dhcp struct for the actual DHCP status.
|
||||
|
||||
|
||||
--- 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_PLATFORM_BYTESWAP 1
|
||||
#define LWIP_PLATFORM_HTONS(x) <your_htons>
|
||||
#define LWIP_PLATFORM_HTONL(x) <your_htonl>
|
||||
|
||||
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!
|
||||
133
doc/savannah.txt
133
doc/savannah.txt
@@ -2,134 +2,119 @@ Daily Use Guide for using Savannah for lwIP
|
||||
|
||||
Table of Contents:
|
||||
|
||||
1 - Obtaining lwIP from the CVS repository
|
||||
2 - Committers/developers CVS access using SSH (to be written)
|
||||
3 - Merging from DEVEL branch to main trunk (stable branch)
|
||||
1 - Obtaining lwIP from the Git repository
|
||||
2 - Committers/developers Git access using SSH
|
||||
3 - Merging a development branch to master branch
|
||||
4 - How to release lwIP
|
||||
|
||||
|
||||
|
||||
1 Obtaining lwIP from the CVS repository
|
||||
1 Obtaining lwIP from the Git repository
|
||||
----------------------------------------
|
||||
|
||||
To perform an anonymous CVS checkout of the main trunk (this is where
|
||||
To perform an anonymous Git clone of the master branch (this is where
|
||||
bug fixes and incremental enhancements occur), do this:
|
||||
git clone git://git.savannah.nongnu.org/lwip.git
|
||||
|
||||
cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout lwip
|
||||
|
||||
Or, obtain a stable branch (updated with bug fixes only) as follows:
|
||||
cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \
|
||||
-r STABLE-0_7 -d lwip-0.7 lwip
|
||||
git clone --branch DEVEL-1_4_1 git://git.savannah.nongnu.org/lwip.git
|
||||
|
||||
Or, obtain a specific (fixed) release as follows:
|
||||
cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \
|
||||
-r STABLE-0_7_0 -d lwip-0.7.0 lwip
|
||||
git clone --branch STABLE-1_4_1 git://git.savannah.nongnu.org/lwip.git
|
||||
|
||||
3 Committers/developers CVS access using SSH
|
||||
|
||||
2 Committers/developers Git access using SSH
|
||||
--------------------------------------------
|
||||
|
||||
The Savannah server uses SSH (Secure Shell) protocol 2 authentication and encryption.
|
||||
As such, CVS commits to the server occur through a SSH tunnel for project members.
|
||||
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:
|
||||
|
||||
ssh -v your_login@cvs.sv.gnu.org
|
||||
ssh -v your_login@git.sv.gnu.org
|
||||
|
||||
If it tells you:
|
||||
Linux vcs.savannah.gnu.org 2.6.32-5-xen-686 #1 SMP Wed Jun 17 17:10:03 UTC 2015 i686
|
||||
|
||||
Authenticating with public key "your_key_name"...
|
||||
Server refused to allocate pty
|
||||
Interactive shell login is not possible for security reasons.
|
||||
VCS commands are allowed.
|
||||
Last login: Tue May 15 23:10:12 2012 from 82.245.102.129
|
||||
You tried to execute:
|
||||
Sorry, you are not allowed to execute that command.
|
||||
Shared connection to git.sv.gnu.org closed.
|
||||
|
||||
then you could login; Savannah refuses to give you a shell - which is OK, as we
|
||||
are allowed to use SSH for CVS only. Now, you should be able to do this:
|
||||
are allowed to use SSH for Git only. Now, you should be able to do this:
|
||||
git clone your_login@git.sv.gnu.org:/srv/git/lwip.git
|
||||
|
||||
export CVS_RSH=ssh
|
||||
cvs -z3 -d:ext:your_login@cvs.sv.gnu.org:/sources/lwip co lwip
|
||||
|
||||
after which you can edit your local files with bug fixes or new features and
|
||||
commit them. Make sure you know what you are doing when using CVS to make
|
||||
After which you can edit your local files with bug fixes or new features and
|
||||
commit them. Make sure you know what you are doing when using Git to make
|
||||
changes on the repository. If in doubt, ask on the lwip-members mailing list.
|
||||
|
||||
(If SSH asks about authenticity of the host, you can check the key
|
||||
fingerprint against http://savannah.nongnu.org/cvs/?group=lwip)
|
||||
fingerprint against https://savannah.nongnu.org/git/?group=lwip
|
||||
|
||||
|
||||
3 Merging from DEVEL branch to main trunk (stable)
|
||||
--------------------------------------------------
|
||||
3 - Merging a development branch to master branch
|
||||
-------------------------------------------------
|
||||
|
||||
Merging is a delicate process in CVS and requires the
|
||||
following disciplined steps in order to prevent conflicts
|
||||
in the future. Conflicts can be hard to solve!
|
||||
Merging is a straightforward process in Git. How to merge all changes in a
|
||||
development branch since our last merge from main:
|
||||
|
||||
Merging from branch A to branch B requires that the A branch
|
||||
has a tag indicating the previous merger. This tag is called
|
||||
'merged_from_A_to_B'. After merging, the tag is moved in the
|
||||
A branch to remember this merger for future merge actions.
|
||||
Checkout the master branch:
|
||||
git checkout master
|
||||
|
||||
IMPORTANT: AFTER COMMITTING A SUCCESFUL MERGE IN THE
|
||||
REPOSITORY, THE TAG MUST BE SET ON THE SOURCE BRANCH OF THE
|
||||
MERGE ACTION (REPLACING EXISTING TAGS WITH THE SAME NAME).
|
||||
Merge the development branch to master:
|
||||
git merge your-development-branch
|
||||
|
||||
Merge all changes in DEVEL since our last merge to main:
|
||||
Resolve any conflict.
|
||||
|
||||
In the working copy of the main trunk:
|
||||
cvs update -P -jmerged_from_DEVEL_to_main -jDEVEL
|
||||
Commit the merge result.
|
||||
git commit -a
|
||||
|
||||
(This will apply the changes between 'merged_from_DEVEL_to_main'
|
||||
and 'DEVEL' to your work set of files)
|
||||
Push your commits:
|
||||
git push
|
||||
|
||||
We can now commit the merge result.
|
||||
cvs commit -R -m "Merged from DEVEL to main."
|
||||
|
||||
If this worked out OK, we now move the tag in the DEVEL branch
|
||||
to this merge point, so we can use this point for future merges:
|
||||
|
||||
cvs rtag -F -r DEVEL merged_from_DEVEL_to_main lwip
|
||||
|
||||
4 How to release lwIP
|
||||
---------------------
|
||||
|
||||
First, checkout a clean copy of the branch to be released. Tag this set with
|
||||
tag name "STABLE-0_6_3". (I use release number 0.6.3 throughout this example).
|
||||
First, tag the release using Git: (I use release number 1.4.1 throughout
|
||||
this example).
|
||||
git tag -a STABLE-1_4_1
|
||||
|
||||
Login CVS using pserver authentication, then export a clean copy of the
|
||||
tagged tree. Export is similar to a checkout, except that the CVS metadata
|
||||
is not created locally.
|
||||
Share the tag reference by pushing it to remote:
|
||||
git push origin STABLE-1_4_1
|
||||
|
||||
export CVS_RSH=ssh
|
||||
cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \
|
||||
-r STABLE-0_6_3 -d lwip-0.6.3 lwip
|
||||
Prepare the release:
|
||||
cp -r lwip lwip-1.4.1
|
||||
rm -rf lwip-1.4.1/.git lwip-1.4.1/.gitattributes
|
||||
|
||||
Archive this directory using tar, gzip'd, bzip2'd and zip'd.
|
||||
|
||||
tar czvf lwip-0.6.3.tar.gz lwip-0.6.3
|
||||
tar cjvf lwip-0.6.3.tar.bz2 lwip-0.6.3
|
||||
zip -r lwip-0.6.3.zip lwip-0.6.3
|
||||
Archive the current directory using tar, gzip'd, bzip2'd and zip'd.
|
||||
tar czvf lwip-1.4.1.tar.gz lwip-1.4.1
|
||||
tar cjvf lwip-1.4.1.tar.bz2 lwip-1.4.1
|
||||
zip -r lwip-1.4.1.zip lwip-1.4.1
|
||||
|
||||
Now, sign the archives with a detached GPG binary signature as follows:
|
||||
|
||||
gpg -b lwip-0.6.3.tar.gz
|
||||
gpg -b lwip-0.6.3.tar.bz2
|
||||
gpg -b lwip-0.6.3.zip
|
||||
gpg -b lwip-1.4.1.tar.gz
|
||||
gpg -b lwip-1.4.1.tar.bz2
|
||||
gpg -b lwip-1.4.1.zip
|
||||
|
||||
Upload these files using anonymous FTP:
|
||||
ncftp ftp://savannah.gnu.org/incoming/savannah/lwip
|
||||
|
||||
ncftp>mput *0.6.3.*
|
||||
ncftp ftp://savannah.gnu.org/incoming/savannah/lwip
|
||||
ncftp> mput *1.4.1.*
|
||||
|
||||
Additionally, you may post a news item on Savannah, like this:
|
||||
|
||||
A new 0.6.3 release is now available here:
|
||||
http://savannah.nongnu.org/files/?group=lwip&highlight=0.6.3
|
||||
A new 1.4.1 release is now available here:
|
||||
http://savannah.nongnu.org/files/?group=lwip&highlight=1.4.1
|
||||
|
||||
You will have to submit this via the user News interface, then approve
|
||||
this via the Administrator News interface.
|
||||
this via the Administrator News interface.
|
||||
|
||||
@@ -1,181 +0,0 @@
|
||||
SNMPv1 agent for lwIP
|
||||
|
||||
Author: Christiaan Simons
|
||||
|
||||
This is a brief introduction how to use and configure the SNMP agent.
|
||||
Note the agent uses the raw-API UDP interface so you may also want to
|
||||
read rawapi.txt to gain a better understanding of the SNMP message handling.
|
||||
|
||||
0 Agent Capabilities
|
||||
====================
|
||||
|
||||
SNMPv1 per RFC1157
|
||||
This is an old(er) standard but is still widely supported.
|
||||
For SNMPv2c and v3 have a greater complexity and need many
|
||||
more lines of code. IMHO this breaks the idea of "lightweight IP".
|
||||
|
||||
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).
|
||||
|
||||
MIB II per RFC1213
|
||||
The standard lwIP stack management information base.
|
||||
This is a required MIB, so this is always enabled.
|
||||
When builing lwIP without TCP, the mib-2.tcp group is omitted.
|
||||
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.
|
||||
There is no MIB compiler thus additional MIBs must be hand coded.
|
||||
|
||||
Large SNMP message support
|
||||
The packet decoding and encoding routines are designed
|
||||
to use pbuf-chains. Larger payloads than the minimum
|
||||
SNMP requirement of 484 octets are supported if the
|
||||
PBUF_POOL_SIZE and IP_REASS_BUFSIZE are set to match your
|
||||
local requirement.
|
||||
|
||||
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 in lwip/src/core/snmp
|
||||
and some snmp headers in lwip/src/include/lwip to 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
|
||||
to non-volatile memory for sysContact, sysLocation,
|
||||
and snmpEnableAuthenTraps. You can do this by calling
|
||||
|
||||
snmp_set_syscontact()
|
||||
snmp_set_syslocation()
|
||||
snmp_set_snmpenableauthentraps()
|
||||
|
||||
Additionally you may want to set
|
||||
|
||||
snmp_set_sysdescr()
|
||||
snmp_set_sysobjid() (if you have a private MIB)
|
||||
snmp_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();
|
||||
|
||||
In the lwIP initialisation sequence call snmp_init() just after
|
||||
the call to udp_init().
|
||||
|
||||
Exactly every 10 msec the SNMP uptime timestamp must be updated with
|
||||
snmp_inc_sysuptime(). You should call this from a timer interrupt
|
||||
or a timer signal handler depending on your runtime environment.
|
||||
|
||||
An alternative way to update the SNMP uptime timestamp is to do a call like
|
||||
snmp_add_sysuptime(100) each 1000ms (which is bigger "step", but call to
|
||||
a lower frequency). Another one is to not call snmp_inc_sysuptime() or
|
||||
snmp_add_sysuptime(), and to define the SNMP_GET_SYSUPTIME(sysuptime) macro.
|
||||
This one is undefined by default in mib2.c. SNMP_GET_SYSUPTIME is called inside
|
||||
snmp_get_sysuptime(u32_t *value), and enable to change "sysuptime" value only
|
||||
when it's queried (any function which need "sysuptime" have to call
|
||||
snmp_get_sysuptime).
|
||||
|
||||
|
||||
3 Private MIBs
|
||||
==============
|
||||
|
||||
If want to extend the agent with your own private MIB you'll need to
|
||||
add the following define to your local lwipopts.h:
|
||||
|
||||
#define SNMP_PRIVATE_MIB 1
|
||||
|
||||
You must provide the private_mib.h and associated files yourself.
|
||||
Note we don't have a "MIB compiler" that generates C source from a MIB,
|
||||
so you're required to do some serious coding if you enable this!
|
||||
|
||||
Note the lwIP enterprise ID (26381) is assigned to the lwIP project,
|
||||
ALL OBJECT IDENTIFIERS LIVING UNDER THIS ID ARE ASSIGNED BY THE lwIP
|
||||
MAINTAINERS!
|
||||
|
||||
If you need to create your own private MIB you'll need
|
||||
to apply for your own enterprise ID with IANA: http://www.iana.org/numbers.html
|
||||
|
||||
You can set it by passing a struct snmp_obj_id to the agent
|
||||
using snmp_set_sysobjid(&my_object_id), just before snmp_init().
|
||||
|
||||
Note the object identifiers for thes MIB-2 and your private MIB
|
||||
tree must be kept in sorted ascending (lexicographical) order.
|
||||
This to ensure correct getnext operation.
|
||||
|
||||
An example for a private MIB is part of the "minimal Unix" project:
|
||||
contrib/ports/unix/proj/minimal/lwip_prvmib.c
|
||||
|
||||
The next chapter gives a more detailed description of the
|
||||
MIB-2 tree and the optional private MIB.
|
||||
|
||||
4 The Gory Details
|
||||
==================
|
||||
|
||||
4.0 Object identifiers and the MIB tree.
|
||||
|
||||
We have three distinct parts for all object identifiers:
|
||||
|
||||
The prefix
|
||||
.iso.org.dod.internet
|
||||
|
||||
the middle part
|
||||
.mgmt.mib-2.ip.ipNetToMediaTable.ipNetToMediaEntry.ipNetToMediaPhysAddress
|
||||
|
||||
and the index part
|
||||
.1.192.168.0.1
|
||||
|
||||
Objects located above the .internet hierarchy aren't supported.
|
||||
Currently only the .mgmt sub-tree is available and
|
||||
when the SNMP_PRIVATE_MIB is enabled the .private tree
|
||||
becomes available too.
|
||||
|
||||
Object identifiers from incoming requests are checked
|
||||
for a matching prefix, middle part and index part
|
||||
or are expanded(*) for GetNext requests with short
|
||||
or inexisting names in the request.
|
||||
(* we call this "expansion" but this also
|
||||
resembles the "auto-completion" operation)
|
||||
|
||||
The middle part is usually located in ROM (const)
|
||||
to preserve precious RAM on small microcontrollers.
|
||||
However RAM location is possible for a dynamically
|
||||
changing private tree.
|
||||
|
||||
The index part is handled by functions which in
|
||||
turn use dynamically allocated index trees from RAM.
|
||||
These trees are updated by e.g. the etharp code
|
||||
when new entries are made or removed form the ARP cache.
|
||||
|
||||
/** @todo more gory details */
|
||||
216
doc/sys_arch.txt
216
doc/sys_arch.txt
@@ -1,216 +0,0 @@
|
||||
sys_arch interface for lwIP 0.6++
|
||||
|
||||
Author: Adam Dunkels
|
||||
|
||||
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 and mailboxes 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. Previous versions of lwIP required the sys_arch to
|
||||
implement timer scheduling as well but as of lwIP 0.5 this is
|
||||
implemented in a higher layer.
|
||||
|
||||
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 are used for message passing and can be implemented
|
||||
either as a queue which allows multiple messages to be posted to a
|
||||
mailbox, or as a rendez-vous point where only one message can be
|
||||
posted at a time. lwIP works with both kinds, but the former type will
|
||||
be more efficient. 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". lwIP does not place any restrictions on how
|
||||
sys_sem_t or sys_mbox_t are represented internally.
|
||||
|
||||
The following functions must be implemented by the sys_arch:
|
||||
|
||||
- void sys_init(void)
|
||||
|
||||
Is called to initialize the sys_arch layer.
|
||||
|
||||
- sys_sem_t sys_sem_new(u8_t count)
|
||||
|
||||
Creates and returns a new semaphore. The "count" argument specifies
|
||||
the initial state of the semaphore.
|
||||
|
||||
- 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.
|
||||
|
||||
- sys_mbox_t sys_mbox_new(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.
|
||||
|
||||
- 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.
|
||||
|
||||
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.
|
||||
|
||||
- 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.
|
||||
|
||||
Note:
|
||||
|
||||
Be carefull 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"
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
@@ -29,40 +29,8 @@
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
#ifndef __LWIP_INET_H__
|
||||
#define __LWIP_INET_H__
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#if defined(__IAR_SYSTEMS_ICC__)|| defined (__GNUC__)
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
|
||||
u16_t inet_chksum(void *data, u16_t len);
|
||||
u16_t inet_chksum_pbuf(struct pbuf *p);
|
||||
u16_t inet_chksum_pseudo(struct pbuf *p,
|
||||
struct ip_addr *src, struct ip_addr *dest,
|
||||
u8_t proto, u32_t proto_len);
|
||||
|
||||
u32_t inet_addr(const char *cp);
|
||||
s8_t inet_aton(const char *cp, struct in_addr *addr);
|
||||
|
||||
#ifndef _MACHINE_ENDIAN_H_
|
||||
#ifndef _NETINET_IN_H
|
||||
#ifndef _LINUX_BYTEORDER_GENERIC_H
|
||||
u16_t htons(u16_t n);
|
||||
u16_t ntohs(u16_t n);
|
||||
u32_t htonl(u32_t n);
|
||||
u32_t ntohl(u32_t n);
|
||||
#endif /* _LINUX_BYTEORDER_GENERIC_H */
|
||||
#endif /* _NETINET_IN_H */
|
||||
#endif /* _MACHINE_ENDIAN_H_ */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LWIP_INET_H__ */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
@@ -29,72 +29,67 @@
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
#ifndef __LWIP_ICMP_H__
|
||||
#define __LWIP_ICMP_H__
|
||||
#ifndef __CC_H__
|
||||
#define __CC_H__
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "cpu.h"
|
||||
|
||||
#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
|
||||
typedef int sys_prot_t;
|
||||
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/netif.h"
|
||||
#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
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ICMP6_DUR 1
|
||||
#define ICMP6_TE 3
|
||||
#define ICMP6_ECHO 128 /* echo */
|
||||
#define ICMP6_ER 129 /* echo reply */
|
||||
|
||||
|
||||
enum icmp_dur_type {
|
||||
ICMP_DUR_NET = 0, /* net unreachable */
|
||||
ICMP_DUR_HOST = 1, /* host unreachable */
|
||||
ICMP_DUR_PROTO = 2, /* protocol unreachable */
|
||||
ICMP_DUR_PORT = 3, /* port unreachable */
|
||||
ICMP_DUR_FRAG = 4, /* fragmentation needed and DF set */
|
||||
ICMP_DUR_SR = 5 /* source route failed */
|
||||
};
|
||||
|
||||
enum icmp_te_type {
|
||||
ICMP_TE_TTL = 0, /* time to live exceeded in transit */
|
||||
ICMP_TE_FRAG = 1 /* fragment reassembly time exceeded */
|
||||
};
|
||||
|
||||
void icmp_input(struct pbuf *p, struct netif *inp);
|
||||
|
||||
void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t);
|
||||
void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t);
|
||||
|
||||
struct icmp_echo_hdr {
|
||||
u8_t type;
|
||||
u8_t icode;
|
||||
u16_t chksum;
|
||||
u16_t id;
|
||||
u16_t seqno;
|
||||
};
|
||||
|
||||
struct icmp_dur_hdr {
|
||||
u8_t type;
|
||||
u8_t icode;
|
||||
u16_t chksum;
|
||||
u32_t unused;
|
||||
};
|
||||
|
||||
struct icmp_te_hdr {
|
||||
u8_t type;
|
||||
u8_t icode;
|
||||
u16_t chksum;
|
||||
u32_t unused;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LWIP_ICMP */
|
||||
|
||||
#endif /* __LWIP_ICMP_H__ */
|
||||
#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__ */
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
api/ - The code for the high-level wrapper API. Not needed if
|
||||
you use the lowel-level call-back/raw API.
|
||||
|
||||
apps/ - Higher layer applications that are specifically programmed
|
||||
with the lwIP low-level raw API.
|
||||
|
||||
core/ - The core of the TPC/IP stack; protocol implementations,
|
||||
memory and buffer management, and the low-level raw API.
|
||||
|
||||
include/ - lwIP include files.
|
||||
|
||||
netif/ - Generic network interface device drivers are kept here,
|
||||
as well as the ARP module.
|
||||
netif/ - Generic network interface device drivers are kept here.
|
||||
|
||||
For more information on the various subdirectories, check the FILES
|
||||
file in each directory.
|
||||
|
||||
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})
|
||||
205
src/Filelists.mk
Normal file
205
src/Filelists.mk
Normal file
@@ -0,0 +1,205 @@
|
||||
#
|
||||
# Copyright (c) 2001, 2002 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>
|
||||
#
|
||||
|
||||
# COREFILES, CORE4FILES: The minimum set of files needed for lwIP.
|
||||
COREFILES=$(LWIPDIR)/core/init.c \
|
||||
$(LWIPDIR)/core/def.c \
|
||||
$(LWIPDIR)/core/dns.c \
|
||||
$(LWIPDIR)/core/inet_chksum.c \
|
||||
$(LWIPDIR)/core/ip.c \
|
||||
$(LWIPDIR)/core/mem.c \
|
||||
$(LWIPDIR)/core/memp.c \
|
||||
$(LWIPDIR)/core/netif.c \
|
||||
$(LWIPDIR)/core/pbuf.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 \
|
||||
$(LWIPDIR)/core/timeouts.c \
|
||||
$(LWIPDIR)/core/udp.c
|
||||
|
||||
CORE4FILES=$(LWIPDIR)/core/ipv4/autoip.c \
|
||||
$(LWIPDIR)/core/ipv4/dhcp.c \
|
||||
$(LWIPDIR)/core/ipv4/etharp.c \
|
||||
$(LWIPDIR)/core/ipv4/icmp.c \
|
||||
$(LWIPDIR)/core/ipv4/igmp.c \
|
||||
$(LWIPDIR)/core/ipv4/ip4_frag.c \
|
||||
$(LWIPDIR)/core/ipv4/ip4.c \
|
||||
$(LWIPDIR)/core/ipv4/ip4_addr.c
|
||||
|
||||
CORE6FILES=$(LWIPDIR)/core/ipv6/dhcp6.c \
|
||||
$(LWIPDIR)/core/ipv6/ethip6.c \
|
||||
$(LWIPDIR)/core/ipv6/icmp6.c \
|
||||
$(LWIPDIR)/core/ipv6/inet6.c \
|
||||
$(LWIPDIR)/core/ipv6/ip6.c \
|
||||
$(LWIPDIR)/core/ipv6/ip6_addr.c \
|
||||
$(LWIPDIR)/core/ipv6/ip6_frag.c \
|
||||
$(LWIPDIR)/core/ipv6/mld6.c \
|
||||
$(LWIPDIR)/core/ipv6/nd6.c
|
||||
|
||||
# APIFILES: The files which implement the sequential and socket APIs.
|
||||
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 \
|
||||
$(LWIPDIR)/api/sockets.c \
|
||||
$(LWIPDIR)/api/tcpip.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_common.c \
|
||||
$(LWIPDIR)/netif/lowpan6.c \
|
||||
$(LWIPDIR)/netif/lowpan6_ble.c \
|
||||
$(LWIPDIR)/netif/zepif.c
|
||||
|
||||
# PPPFILES: PPP
|
||||
PPPFILES=$(LWIPDIR)/netif/ppp/auth.c \
|
||||
$(LWIPDIR)/netif/ppp/ccp.c \
|
||||
$(LWIPDIR)/netif/ppp/chap-md5.c \
|
||||
$(LWIPDIR)/netif/ppp/chap_ms.c \
|
||||
$(LWIPDIR)/netif/ppp/chap-new.c \
|
||||
$(LWIPDIR)/netif/ppp/demand.c \
|
||||
$(LWIPDIR)/netif/ppp/eap.c \
|
||||
$(LWIPDIR)/netif/ppp/ecp.c \
|
||||
$(LWIPDIR)/netif/ppp/eui64.c \
|
||||
$(LWIPDIR)/netif/ppp/fsm.c \
|
||||
$(LWIPDIR)/netif/ppp/ipcp.c \
|
||||
$(LWIPDIR)/netif/ppp/ipv6cp.c \
|
||||
$(LWIPDIR)/netif/ppp/lcp.c \
|
||||
$(LWIPDIR)/netif/ppp/magic.c \
|
||||
$(LWIPDIR)/netif/ppp/mppe.c \
|
||||
$(LWIPDIR)/netif/ppp/multilink.c \
|
||||
$(LWIPDIR)/netif/ppp/ppp.c \
|
||||
$(LWIPDIR)/netif/ppp/pppapi.c \
|
||||
$(LWIPDIR)/netif/ppp/pppcrypt.c \
|
||||
$(LWIPDIR)/netif/ppp/pppoe.c \
|
||||
$(LWIPDIR)/netif/ppp/pppol2tp.c \
|
||||
$(LWIPDIR)/netif/ppp/pppos.c \
|
||||
$(LWIPDIR)/netif/ppp/upap.c \
|
||||
$(LWIPDIR)/netif/ppp/utils.c \
|
||||
$(LWIPDIR)/netif/ppp/vj.c \
|
||||
$(LWIPDIR)/netif/ppp/polarssl/arc4.c \
|
||||
$(LWIPDIR)/netif/ppp/polarssl/des.c \
|
||||
$(LWIPDIR)/netif/ppp/polarssl/md4.c \
|
||||
$(LWIPDIR)/netif/ppp/polarssl/md5.c \
|
||||
$(LWIPDIR)/netif/ppp/polarssl/sha1.c
|
||||
|
||||
# LWIPNOAPPSFILES: All LWIP files without apps
|
||||
LWIPNOAPPSFILES=$(COREFILES) \
|
||||
$(CORE4FILES) \
|
||||
$(CORE6FILES) \
|
||||
$(APIFILES) \
|
||||
$(NETIFFILES) \
|
||||
$(PPPFILES) \
|
||||
$(SIXLOWPAN)
|
||||
|
||||
# SNMPFILES: SNMPv2c agent
|
||||
SNMPFILES=$(LWIPDIR)/apps/snmp/snmp_asn1.c \
|
||||
$(LWIPDIR)/apps/snmp/snmp_core.c \
|
||||
$(LWIPDIR)/apps/snmp/snmp_mib2.c \
|
||||
$(LWIPDIR)/apps/snmp/snmp_mib2_icmp.c \
|
||||
$(LWIPDIR)/apps/snmp/snmp_mib2_interfaces.c \
|
||||
$(LWIPDIR)/apps/snmp/snmp_mib2_ip.c \
|
||||
$(LWIPDIR)/apps/snmp/snmp_mib2_snmp.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 \
|
||||
$(LWIPDIR)/apps/snmp/snmp_pbuf_stream.c \
|
||||
$(LWIPDIR)/apps/snmp/snmp_raw.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
|
||||
|
||||
# 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
|
||||
|
||||
# MDNSFILES: MDNS responder
|
||||
MDNSFILES=$(LWIPDIR)/apps/mdns/mdns.c
|
||||
|
||||
# NETBIOSNSFILES: NetBIOS name server
|
||||
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) \
|
||||
$(HTTPFILES) \
|
||||
$(LWIPERFFILES) \
|
||||
$(SMTPFILES) \
|
||||
$(SNTPFILES) \
|
||||
$(MDNSFILES) \
|
||||
$(NETBIOSNSFILES) \
|
||||
$(TFTPFILES) \
|
||||
$(MQTTFILES) \
|
||||
$(MBEDTLS_FILES)
|
||||
1101
src/api/api_lib.c
1101
src/api/api_lib.c
File diff suppressed because it is too large
Load Diff
1741
src/api/api_msg.c
1741
src/api/api_msg.c
File diff suppressed because it is too large
Load Diff
102
src/api/err.c
102
src/api/err.c
@@ -6,9 +6,9 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2004 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,
|
||||
@@ -17,46 +17,84 @@
|
||||
* 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>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/sys.h"
|
||||
|
||||
#include "lwip/errno.h"
|
||||
|
||||
#if !NO_SYS
|
||||
/** Table to quickly map an lwIP error (err_t) to a socket error
|
||||
* by using -err as an index */
|
||||
static const int err_to_errno_table[] = {
|
||||
0, /* ERR_OK 0 No error, everything OK. */
|
||||
ENOMEM, /* ERR_MEM -1 Out of memory error. */
|
||||
ENOBUFS, /* ERR_BUF -2 Buffer error. */
|
||||
EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */
|
||||
EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */
|
||||
EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */
|
||||
EINVAL, /* ERR_VAL -6 Illegal value. */
|
||||
EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */
|
||||
EADDRINUSE, /* ERR_USE -8 Address in use. */
|
||||
EALREADY, /* ERR_ALREADY -9 Already connecting. */
|
||||
EISCONN, /* ERR_ISCONN -10 Conn already established.*/
|
||||
ENOTCONN, /* ERR_CONN -11 Not connected. */
|
||||
-1, /* ERR_IF -12 Low-level netif error */
|
||||
ECONNABORTED, /* ERR_ABRT -13 Connection aborted. */
|
||||
ECONNRESET, /* ERR_RST -14 Connection reset. */
|
||||
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 connected.", /* ERR_ISCONN -9 */
|
||||
"Connection aborted.", /* ERR_ABRT -10 */
|
||||
"Connection reset.", /* ERR_RST -11 */
|
||||
"Connection closed.", /* ERR_CLSD -12 */
|
||||
"Not connected.", /* ERR_CONN -13 */
|
||||
"Illegal argument.", /* ERR_ARG -14 */
|
||||
"Low-level netif error.", /* ERR_IF -15 */
|
||||
"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 */
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -68,8 +106,10 @@ static const char *err_strerr[] = {
|
||||
const char *
|
||||
lwip_strerr(err_t err)
|
||||
{
|
||||
if ((err > 0) || (-err >= (err_t)LWIP_ARRAYSIZE(err_strerr))) {
|
||||
return "Unknown error.";
|
||||
}
|
||||
return err_strerr[-err];
|
||||
|
||||
}
|
||||
|
||||
#endif /* LWIP_DEBUG */
|
||||
|
||||
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 */
|
||||
@@ -2,13 +2,19 @@
|
||||
* @file
|
||||
* Network buffer management
|
||||
*
|
||||
* @defgroup netbuf Network buffers
|
||||
* @ingroup netconn
|
||||
* Network buffer descriptor for @ref netconn. Based on @ref pbuf internally
|
||||
* to avoid copying data around.\n
|
||||
* Buffers must not be shared accross multiple threads, all functions except
|
||||
* netbuf_new() and netbuf_delete() are not thread-safe.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2004 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,
|
||||
@@ -17,21 +23,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>
|
||||
*
|
||||
*/
|
||||
@@ -46,6 +52,7 @@
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* @ingroup netbuf
|
||||
* Create (allocate) and initialize a new netbuf.
|
||||
* The netbuf doesn't yet contain a packet buffer!
|
||||
*
|
||||
@@ -59,26 +66,13 @@ netbuf *netbuf_new(void)
|
||||
|
||||
buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
|
||||
if (buf != NULL) {
|
||||
buf->p = NULL;
|
||||
buf->ptr = NULL;
|
||||
ip_addr_set_any(&buf->addr);
|
||||
buf->port = 0;
|
||||
#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY
|
||||
#if LWIP_CHECKSUM_ON_COPY
|
||||
buf->flags = 0;
|
||||
#endif /* LWIP_CHECKSUM_ON_COPY */
|
||||
buf->toport_chksum = 0;
|
||||
#if LWIP_NETBUF_RECVINFO
|
||||
ip_addr_set_any(&buf->toaddr);
|
||||
#endif /* LWIP_NETBUF_RECVINFO */
|
||||
#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */
|
||||
return buf;
|
||||
} else {
|
||||
return NULL;
|
||||
memset(buf, 0, sizeof(struct netbuf));
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup netbuf
|
||||
* Deallocate a netbuf allocated by netbuf_new().
|
||||
*
|
||||
* @param buf pointer to a netbuf allocated by netbuf_new()
|
||||
@@ -96,6 +90,7 @@ netbuf_delete(struct netbuf *buf)
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup netbuf
|
||||
* Allocate memory for a packet buffer for a given netbuf.
|
||||
*
|
||||
* @param buf the netbuf for which to allocate a packet buffer
|
||||
@@ -114,15 +109,16 @@ 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup netbuf
|
||||
* Free the packet buffer included in a netbuf
|
||||
*
|
||||
* @param buf pointer to the netbuf which contains the packet buffer to free
|
||||
@@ -135,9 +131,14 @@ 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 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup netbuf
|
||||
* Let a netbuf reference existing (non-volatile) data.
|
||||
*
|
||||
* @param buf netbuf which should reference the data
|
||||
@@ -158,13 +159,14 @@ netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size)
|
||||
buf->ptr = NULL;
|
||||
return ERR_MEM;
|
||||
}
|
||||
buf->p->payload = (void*)dataptr;
|
||||
((struct pbuf_rom *)buf->p)->payload = dataptr;
|
||||
buf->p->len = buf->p->tot_len = size;
|
||||
buf->ptr = buf->p;
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup netbuf
|
||||
* Chain one netbuf to another (@see pbuf_chain)
|
||||
*
|
||||
* @param head the first netbuf
|
||||
@@ -173,7 +175,7 @@ netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size)
|
||||
void
|
||||
netbuf_chain(struct netbuf *head, struct netbuf *tail)
|
||||
{
|
||||
LWIP_ERROR("netbuf_ref: invalid head", (head != NULL), return;);
|
||||
LWIP_ERROR("netbuf_chain: invalid head", (head != NULL), return;);
|
||||
LWIP_ERROR("netbuf_chain: invalid tail", (tail != NULL), return;);
|
||||
pbuf_cat(head->p, tail->p);
|
||||
head->ptr = head->p;
|
||||
@@ -181,12 +183,13 @@ netbuf_chain(struct netbuf *head, struct netbuf *tail)
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup netbuf
|
||||
* Get the data pointer and length of the data inside a netbuf.
|
||||
*
|
||||
* @param buf netbuf to get the data from
|
||||
* @param dataptr pointer to a void pointer where to store the data pointer
|
||||
* @param len pointer to an u16_t where the length of the data is stored
|
||||
* @return ERR_OK if the information was retreived,
|
||||
* @return ERR_OK if the information was retrieved,
|
||||
* ERR_BUF on error.
|
||||
*/
|
||||
err_t
|
||||
@@ -205,6 +208,7 @@ netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len)
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup netbuf
|
||||
* Move the current data pointer of a packet buffer contained in a netbuf
|
||||
* to the next part.
|
||||
* The packet buffer itself is not modified.
|
||||
@@ -217,7 +221,7 @@ netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len)
|
||||
s8_t
|
||||
netbuf_next(struct netbuf *buf)
|
||||
{
|
||||
LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return -1;);
|
||||
LWIP_ERROR("netbuf_next: invalid buf", (buf != NULL), return -1;);
|
||||
if (buf->ptr->next == NULL) {
|
||||
return -1;
|
||||
}
|
||||
@@ -229,6 +233,7 @@ netbuf_next(struct netbuf *buf)
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup netbuf
|
||||
* Move the current data pointer of a packet buffer contained in a netbuf
|
||||
* to the beginning of the packet.
|
||||
* The packet buffer itself is not modified.
|
||||
@@ -238,7 +243,7 @@ netbuf_next(struct netbuf *buf)
|
||||
void
|
||||
netbuf_first(struct netbuf *buf)
|
||||
{
|
||||
LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;);
|
||||
LWIP_ERROR("netbuf_first: invalid buf", (buf != NULL), return;);
|
||||
buf->ptr = buf->p;
|
||||
}
|
||||
|
||||
|
||||
203
src/api/netdb.c
203
src/api/netdb.c
@@ -2,10 +2,12 @@
|
||||
* @file
|
||||
* API functions for name resolving
|
||||
*
|
||||
* @defgroup netdbapi NETDB API
|
||||
* @ingroup socket
|
||||
*/
|
||||
|
||||
/*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* 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,
|
||||
@@ -14,21 +16,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: Simon Goldschmidt
|
||||
*
|
||||
*/
|
||||
@@ -44,12 +46,12 @@
|
||||
#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 {
|
||||
ip_addr_t *addrs;
|
||||
ip_addr_t *addr_list[2];
|
||||
ip_addr_t addr;
|
||||
char *aliases;
|
||||
};
|
||||
@@ -81,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;
|
||||
@@ -92,6 +94,7 @@ lwip_gethostbyname(const char *name)
|
||||
HOSTENT_STORAGE char *s_aliases;
|
||||
HOSTENT_STORAGE ip_addr_t s_hostent_addr;
|
||||
HOSTENT_STORAGE ip_addr_t *s_phostent_addr[2];
|
||||
HOSTENT_STORAGE char s_hostname[DNS_MAX_NAME_LENGTH + 1];
|
||||
|
||||
/* query host IP address */
|
||||
err = netconn_gethostbyname(name, &addr);
|
||||
@@ -105,31 +108,27 @@ lwip_gethostbyname(const char *name)
|
||||
s_hostent_addr = addr;
|
||||
s_phostent_addr[0] = &s_hostent_addr;
|
||||
s_phostent_addr[1] = NULL;
|
||||
s_hostent.h_name = (char*)name;
|
||||
strncpy(s_hostname, name, DNS_MAX_NAME_LENGTH);
|
||||
s_hostname[DNS_MAX_NAME_LENGTH] = 0;
|
||||
s_hostent.h_name = s_hostname;
|
||||
s_aliases = NULL;
|
||||
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", s_hostent.h_aliases));
|
||||
if (s_hostent.h_aliases != NULL) {
|
||||
u8_t idx;
|
||||
for ( idx=0; s_hostent.h_aliases[idx]; idx++) {
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == %p\n", idx, s_hostent.h_aliases[idx]));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == %s\n", idx, s_hostent.h_aliases[idx]));
|
||||
}
|
||||
}
|
||||
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", 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, ip_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;
|
||||
@@ -180,27 +179,27 @@ lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
|
||||
}
|
||||
/* first thing to do: set *result to nothing */
|
||||
*result = NULL;
|
||||
if ((name == NULL) || (ret == NULL) || (buf == 0)) {
|
||||
if ((name == NULL) || (ret == NULL) || (buf == NULL)) {
|
||||
/* not all arguments given */
|
||||
*h_errnop = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
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));
|
||||
err = netconn_gethostbyname(name, &h->addr);
|
||||
if (err != ERR_OK) {
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));
|
||||
*h_errnop = ENSRNOTFOUND;
|
||||
*h_errnop = HOST_NOT_FOUND;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -209,13 +208,14 @@ lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
|
||||
hostname[namelen] = 0;
|
||||
|
||||
/* fill hostent */
|
||||
h->addrs = &(h->addr);
|
||||
h->addr_list[0] = &h->addr;
|
||||
h->addr_list[1] = NULL;
|
||||
h->aliases = NULL;
|
||||
ret->h_name = (char*)hostname;
|
||||
ret->h_aliases = &(h->aliases);
|
||||
ret->h_name = hostname;
|
||||
ret->h_aliases = &h->aliases;
|
||||
ret->h_addrtype = AF_INET;
|
||||
ret->h_length = sizeof(ip_addr_t);
|
||||
ret->h_addr_list = (char**)&(h->addrs);
|
||||
ret->h_addr_list = (char **)&h->addr_list;
|
||||
|
||||
/* set result != NULL */
|
||||
*result = ret;
|
||||
@@ -257,22 +257,25 @@ lwip_freeaddrinfo(struct addrinfo *ai)
|
||||
*
|
||||
* @param nodename descriptive name or address string of the host
|
||||
* (may be NULL -> local address)
|
||||
* @param servname port number as string of NULL
|
||||
* @param servname port number as string of NULL
|
||||
* @param hints structure containing input values that set socktype and protocol
|
||||
* @param res pointer to a pointer where to store the result (set to NULL on failure)
|
||||
* @return 0 on success, non-zero on failure
|
||||
*
|
||||
* @todo: implement AI_V4MAPPED, AI_ADDRCONFIG
|
||||
*/
|
||||
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;
|
||||
struct addrinfo *ai;
|
||||
struct sockaddr_in *sa = NULL;
|
||||
struct sockaddr_storage *sa = NULL;
|
||||
int port_nr = 0;
|
||||
size_t total_size;
|
||||
size_t namelen = 0;
|
||||
int ai_family;
|
||||
|
||||
if (res == NULL) {
|
||||
return EAI_FAIL;
|
||||
@@ -282,49 +285,116 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
|
||||
return EAI_NONAME;
|
||||
}
|
||||
|
||||
if (hints != NULL) {
|
||||
ai_family = hints->ai_family;
|
||||
if ((ai_family != AF_UNSPEC)
|
||||
#if LWIP_IPV4
|
||||
&& (ai_family != AF_INET)
|
||||
#endif /* LWIP_IPV4 */
|
||||
#if LWIP_IPV6
|
||||
&& (ai_family != AF_INET6)
|
||||
#endif /* LWIP_IPV6 */
|
||||
) {
|
||||
return EAI_FAMILY;
|
||||
}
|
||||
} else {
|
||||
ai_family = AF_UNSPEC;
|
||||
}
|
||||
|
||||
if (servname != NULL) {
|
||||
/* service name specified: convert to port number
|
||||
* @todo?: currently, only ASCII integers (port numbers) are supported! */
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
|
||||
if (nodename != NULL) {
|
||||
/* service location specified, try to resolve */
|
||||
err = netconn_gethostbyname(nodename, &addr);
|
||||
if (err != ERR_OK) {
|
||||
return EAI_FAIL;
|
||||
if ((hints != NULL) && (hints->ai_flags & AI_NUMERICHOST)) {
|
||||
/* no DNS lookup, just parse for an address string */
|
||||
if (!ipaddr_aton(nodename, &addr)) {
|
||||
return EAI_NONAME;
|
||||
}
|
||||
#if LWIP_IPV4 && LWIP_IPV6
|
||||
if ((IP_IS_V6_VAL(addr) && ai_family == AF_INET) ||
|
||||
(IP_IS_V4_VAL(addr) && ai_family == AF_INET6)) {
|
||||
return EAI_NONAME;
|
||||
}
|
||||
#endif /* LWIP_IPV4 && LWIP_IPV6 */
|
||||
} else {
|
||||
#if LWIP_IPV4 && LWIP_IPV6
|
||||
/* AF_UNSPEC: prefer IPv4 */
|
||||
u8_t type = NETCONN_DNS_IPV4_IPV6;
|
||||
if (ai_family == AF_INET) {
|
||||
type = NETCONN_DNS_IPV4;
|
||||
} else if (ai_family == AF_INET6) {
|
||||
type = NETCONN_DNS_IPV6;
|
||||
}
|
||||
#endif /* LWIP_IPV4 && LWIP_IPV6 */
|
||||
err = netconn_gethostbyname_addrtype(nodename, &addr, type);
|
||||
if (err != ERR_OK) {
|
||||
return EAI_FAIL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* service location specified, use loopback address */
|
||||
ip_addr_set_loopback(&addr);
|
||||
if ((hints != NULL) && (hints->ai_flags & AI_PASSIVE)) {
|
||||
ip_addr_set_any_val(ai_family == AF_INET6, addr);
|
||||
} else {
|
||||
ip_addr_set_loopback_val(ai_family == AF_INET6, addr);
|
||||
}
|
||||
}
|
||||
|
||||
total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_in);
|
||||
total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_storage);
|
||||
if (nodename != NULL) {
|
||||
namelen = strlen(nodename);
|
||||
LWIP_ASSERT("namelen is too long", (namelen + 1) <= (mem_size_t)-1);
|
||||
if (namelen > DNS_MAX_NAME_LENGTH) {
|
||||
/* invalid name length */
|
||||
return EAI_FAIL;
|
||||
}
|
||||
LWIP_ASSERT("namelen is too long", total_size + namelen + 1 > total_size);
|
||||
total_size += namelen + 1;
|
||||
}
|
||||
/* 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) {
|
||||
goto memerr;
|
||||
return EAI_MEMORY;
|
||||
}
|
||||
memset(ai, 0, total_size);
|
||||
sa = (struct sockaddr_in*)((u8_t*)ai + sizeof(struct addrinfo));
|
||||
/* set up sockaddr */
|
||||
inet_addr_from_ipaddr(&sa->sin_addr, &addr);
|
||||
sa->sin_family = AF_INET;
|
||||
sa->sin_len = sizeof(struct sockaddr_in);
|
||||
sa->sin_port = htons((u16_t)port_nr);
|
||||
/* cast through void* to get rid of alignment warnings */
|
||||
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;
|
||||
/* 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;
|
||||
/* set up sockaddr */
|
||||
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);
|
||||
ai->ai_family = AF_INET;
|
||||
#endif /* LWIP_IPV4 */
|
||||
}
|
||||
|
||||
/* set up addrinfo */
|
||||
ai->ai_family = AF_INET;
|
||||
if (hints != NULL) {
|
||||
/* copy socktype & protocol from hints if specified */
|
||||
ai->ai_socktype = hints->ai_socktype;
|
||||
@@ -332,21 +402,16 @@ 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_in));
|
||||
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_in);
|
||||
ai->ai_addr = (struct sockaddr*)sa;
|
||||
ai->ai_addrlen = sizeof(struct sockaddr_storage);
|
||||
ai->ai_addr = (struct sockaddr *)sa;
|
||||
|
||||
*res = ai;
|
||||
|
||||
return 0;
|
||||
memerr:
|
||||
if (ai != NULL) {
|
||||
memp_free(MEMP_NETDB, ai);
|
||||
}
|
||||
return EAI_MEMORY;
|
||||
}
|
||||
|
||||
#endif /* LWIP_DNS && LWIP_SOCKET */
|
||||
|
||||
@@ -2,10 +2,17 @@
|
||||
* @file
|
||||
* Network Interface Sequential API module
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
|
||||
/*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* 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,
|
||||
@@ -14,81 +21,198 @@
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#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/tcpip.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)
|
||||
#define NETIFAPI_VAR_FREE(name) API_VAR_FREE(MEMP_NETIFAPI_MSG, name)
|
||||
|
||||
/**
|
||||
* Call netif_add() inside the tcpip_thread context.
|
||||
*/
|
||||
void
|
||||
do_netifapi_netif_add(struct netifapi_msg_msg *msg)
|
||||
static err_t
|
||||
netifapi_do_netif_add(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_add( msg->netif,
|
||||
msg->msg.add.ipaddr,
|
||||
msg->msg.add.netmask,
|
||||
msg->msg.add.gw,
|
||||
#if LWIP_IPV4
|
||||
API_EXPR_REF(msg->msg.add.ipaddr),
|
||||
API_EXPR_REF(msg->msg.add.netmask),
|
||||
API_EXPR_REF(msg->msg.add.gw),
|
||||
#endif /* LWIP_IPV4 */
|
||||
msg->msg.add.state,
|
||||
msg->msg.add.init,
|
||||
msg->msg.add.input)) {
|
||||
msg->err = ERR_IF;
|
||||
return ERR_IF;
|
||||
} else {
|
||||
msg->err = ERR_OK;
|
||||
return ERR_OK;
|
||||
}
|
||||
TCPIP_NETIFAPI_ACK(msg);
|
||||
}
|
||||
|
||||
#if LWIP_IPV4
|
||||
/**
|
||||
* Call netif_set_addr() inside the tcpip_thread context.
|
||||
*/
|
||||
void
|
||||
do_netifapi_netif_set_addr(struct netifapi_msg_msg *msg)
|
||||
static err_t
|
||||
netifapi_do_netif_set_addr(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;
|
||||
|
||||
netif_set_addr( msg->netif,
|
||||
msg->msg.add.ipaddr,
|
||||
msg->msg.add.netmask,
|
||||
msg->msg.add.gw);
|
||||
msg->err = ERR_OK;
|
||||
TCPIP_NETIFAPI_ACK(msg);
|
||||
API_EXPR_REF(msg->msg.add.ipaddr),
|
||||
API_EXPR_REF(msg->msg.add.netmask),
|
||||
API_EXPR_REF(msg->msg.add.gw));
|
||||
return ERR_OK;
|
||||
}
|
||||
#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.
|
||||
*/
|
||||
void
|
||||
do_netifapi_netif_common(struct netifapi_msg_msg *msg)
|
||||
static err_t
|
||||
netifapi_do_netif_common(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 (msg->msg.common.errtfunc != NULL) {
|
||||
msg->err = msg->msg.common.errtfunc(msg->netif);
|
||||
return msg->msg.common.errtfunc(msg->netif);
|
||||
} else {
|
||||
msg->err = ERR_OK;
|
||||
msg->msg.common.voidfunc(msg->netif);
|
||||
return ERR_OK;
|
||||
}
|
||||
TCPIP_NETIFAPI_ACK(msg);
|
||||
}
|
||||
|
||||
#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
|
||||
* tcpip_thread context.
|
||||
*
|
||||
@@ -96,27 +220,44 @@ do_netifapi_netif_common(struct netifapi_msg_msg *msg)
|
||||
*/
|
||||
err_t
|
||||
netifapi_netif_add(struct netif *netif,
|
||||
ip_addr_t *ipaddr,
|
||||
ip_addr_t *netmask,
|
||||
ip_addr_t *gw,
|
||||
void *state,
|
||||
netif_init_fn init,
|
||||
netif_input_fn input)
|
||||
#if LWIP_IPV4
|
||||
const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw,
|
||||
#endif /* LWIP_IPV4 */
|
||||
void *state, netif_init_fn init, netif_input_fn input)
|
||||
{
|
||||
struct netifapi_msg msg;
|
||||
msg.function = do_netifapi_netif_add;
|
||||
msg.msg.netif = netif;
|
||||
msg.msg.msg.add.ipaddr = ipaddr;
|
||||
msg.msg.msg.add.netmask = netmask;
|
||||
msg.msg.msg.add.gw = gw;
|
||||
msg.msg.msg.add.state = state;
|
||||
msg.msg.msg.add.init = init;
|
||||
msg.msg.msg.add.input = input;
|
||||
TCPIP_NETIFAPI(&msg);
|
||||
return msg.msg.err;
|
||||
err_t err;
|
||||
NETIFAPI_VAR_DECLARE(msg);
|
||||
NETIFAPI_VAR_ALLOC(msg);
|
||||
|
||||
#if LWIP_IPV4
|
||||
if (ipaddr == NULL) {
|
||||
ipaddr = IP4_ADDR_ANY4;
|
||||
}
|
||||
if (netmask == NULL) {
|
||||
netmask = IP4_ADDR_ANY4;
|
||||
}
|
||||
if (gw == NULL) {
|
||||
gw = IP4_ADDR_ANY4;
|
||||
}
|
||||
#endif /* LWIP_IPV4 */
|
||||
|
||||
NETIFAPI_VAR_REF(msg).netif = netif;
|
||||
#if LWIP_IPV4
|
||||
NETIFAPI_VAR_REF(msg).msg.add.ipaddr = NETIFAPI_VAR_REF(ipaddr);
|
||||
NETIFAPI_VAR_REF(msg).msg.add.netmask = NETIFAPI_VAR_REF(netmask);
|
||||
NETIFAPI_VAR_REF(msg).msg.add.gw = NETIFAPI_VAR_REF(gw);
|
||||
#endif /* LWIP_IPV4 */
|
||||
NETIFAPI_VAR_REF(msg).msg.add.state = state;
|
||||
NETIFAPI_VAR_REF(msg).msg.add.init = init;
|
||||
NETIFAPI_VAR_REF(msg).msg.add.input = input;
|
||||
err = tcpip_api_call(netifapi_do_netif_add, &API_VAR_REF(msg).call);
|
||||
NETIFAPI_VAR_FREE(msg);
|
||||
return err;
|
||||
}
|
||||
|
||||
#if LWIP_IPV4
|
||||
/**
|
||||
* @ingroup netifapi_netif
|
||||
* Call netif_set_addr() in a thread-safe way by running that function inside the
|
||||
* tcpip_thread context.
|
||||
*
|
||||
@@ -124,19 +265,33 @@ netifapi_netif_add(struct netif *netif,
|
||||
*/
|
||||
err_t
|
||||
netifapi_netif_set_addr(struct netif *netif,
|
||||
ip_addr_t *ipaddr,
|
||||
ip_addr_t *netmask,
|
||||
ip_addr_t *gw)
|
||||
const ip4_addr_t *ipaddr,
|
||||
const ip4_addr_t *netmask,
|
||||
const ip4_addr_t *gw)
|
||||
{
|
||||
struct netifapi_msg msg;
|
||||
msg.function = do_netifapi_netif_set_addr;
|
||||
msg.msg.netif = netif;
|
||||
msg.msg.msg.add.ipaddr = ipaddr;
|
||||
msg.msg.msg.add.netmask = netmask;
|
||||
msg.msg.msg.add.gw = gw;
|
||||
TCPIP_NETIFAPI(&msg);
|
||||
return msg.msg.err;
|
||||
err_t err;
|
||||
NETIFAPI_VAR_DECLARE(msg);
|
||||
NETIFAPI_VAR_ALLOC(msg);
|
||||
|
||||
if (ipaddr == NULL) {
|
||||
ipaddr = IP4_ADDR_ANY4;
|
||||
}
|
||||
if (netmask == NULL) {
|
||||
netmask = IP4_ADDR_ANY4;
|
||||
}
|
||||
if (gw == NULL) {
|
||||
gw = IP4_ADDR_ANY4;
|
||||
}
|
||||
|
||||
NETIFAPI_VAR_REF(msg).netif = netif;
|
||||
NETIFAPI_VAR_REF(msg).msg.add.ipaddr = NETIFAPI_VAR_REF(ipaddr);
|
||||
NETIFAPI_VAR_REF(msg).msg.add.netmask = NETIFAPI_VAR_REF(netmask);
|
||||
NETIFAPI_VAR_REF(msg).msg.add.gw = NETIFAPI_VAR_REF(gw);
|
||||
err = tcpip_api_call(netifapi_do_netif_set_addr, &API_VAR_REF(msg).call);
|
||||
NETIFAPI_VAR_FREE(msg);
|
||||
return err;
|
||||
}
|
||||
#endif /* LWIP_IPV4 */
|
||||
|
||||
/**
|
||||
* call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) in a thread-safe
|
||||
@@ -146,15 +301,80 @@ 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)
|
||||
{
|
||||
struct netifapi_msg msg;
|
||||
msg.function = do_netifapi_netif_common;
|
||||
msg.msg.netif = netif;
|
||||
msg.msg.msg.common.voidfunc = voidfunc;
|
||||
msg.msg.msg.common.errtfunc = errtfunc;
|
||||
TCPIP_NETIFAPI(&msg);
|
||||
return msg.msg.err;
|
||||
err_t err;
|
||||
NETIFAPI_VAR_DECLARE(msg);
|
||||
NETIFAPI_VAR_ALLOC(msg);
|
||||
|
||||
NETIFAPI_VAR_REF(msg).netif = netif;
|
||||
NETIFAPI_VAR_REF(msg).msg.common.voidfunc = voidfunc;
|
||||
NETIFAPI_VAR_REF(msg).msg.common.errtfunc = errtfunc;
|
||||
err = tcpip_api_call(netifapi_do_netif_common, &API_VAR_REF(msg).call);
|
||||
NETIFAPI_VAR_FREE(msg);
|
||||
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 */
|
||||
|
||||
4810
src/api/sockets.c
4810
src/api/sockets.c
File diff suppressed because it is too large
Load Diff
622
src/api/tcpip.c
622
src/api/tcpip.c
@@ -40,25 +40,80 @@
|
||||
|
||||
#if !NO_SYS /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/priv/tcpip_priv.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/memp.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/tcpip.h"
|
||||
#include "lwip/init.h"
|
||||
#include "netif/etharp.h"
|
||||
#include "netif/ppp_oe.h"
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#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)
|
||||
#define TCPIP_MSG_VAR_FREE(name) API_VAR_FREE(MEMP_TCPIP_MSG_API, name)
|
||||
|
||||
/* 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 */
|
||||
|
||||
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)
|
||||
#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
|
||||
@@ -76,54 +131,56 @@ 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 */
|
||||
sys_timeouts_mbox_fetch(&mbox, (void **)&msg);
|
||||
LOCK_TCPIP_CORE();
|
||||
switch (msg->type) {
|
||||
#if LWIP_NETCONN
|
||||
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;
|
||||
}
|
||||
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));
|
||||
msg->msg.apimsg->function(&(msg->msg.apimsg->msg));
|
||||
msg->msg.api_msg.function(msg->msg.api_msg.msg);
|
||||
break;
|
||||
#endif /* LWIP_NETCONN */
|
||||
case TCPIP_MSG_API_CALL:
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API CALL message %p\n", (void *)msg));
|
||||
msg->msg.api_call.arg->err = msg->msg.api_call.function(msg->msg.api_call.arg);
|
||||
sys_sem_signal(msg->msg.api_call.sem);
|
||||
break;
|
||||
#endif /* !LWIP_TCPIP_CORE_LOCKING */
|
||||
|
||||
#if !LWIP_TCPIP_CORE_LOCKING_INPUT
|
||||
case TCPIP_MSG_INPKT:
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg));
|
||||
#if LWIP_ETHERNET
|
||||
if (msg->msg.inp.netif->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {
|
||||
ethernet_input(msg->msg.inp.p, msg->msg.inp.netif);
|
||||
} else
|
||||
#endif /* LWIP_ETHERNET */
|
||||
{
|
||||
ip_input(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 */
|
||||
#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */
|
||||
|
||||
#if LWIP_NETIF_API
|
||||
case TCPIP_MSG_NETIFAPI:
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: Netif API message %p\n", (void *)msg));
|
||||
msg->msg.netifapimsg->function(&(msg->msg.netifapimsg->msg));
|
||||
break;
|
||||
#endif /* LWIP_NETIF_API */
|
||||
|
||||
case TCPIP_MSG_CALLBACK:
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
|
||||
msg->msg.cb.function(msg->msg.cb.ctx);
|
||||
memp_free(MEMP_TCPIP_MSG_API, msg);
|
||||
break;
|
||||
|
||||
#if LWIP_TCPIP_TIMEOUT
|
||||
#if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS
|
||||
case TCPIP_MSG_TIMEOUT:
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg));
|
||||
sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);
|
||||
@@ -134,19 +191,91 @@ tcpip_thread(void *arg)
|
||||
sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg);
|
||||
memp_free(MEMP_TCPIP_MSG_API, msg);
|
||||
break;
|
||||
#endif /* LWIP_TCPIP_TIMEOUT */
|
||||
#endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */
|
||||
|
||||
case TCPIP_MSG_CALLBACK:
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
|
||||
msg->msg.cb.function(msg->msg.cb.ctx);
|
||||
memp_free(MEMP_TCPIP_MSG_API, msg);
|
||||
break;
|
||||
|
||||
case TCPIP_MSG_CALLBACK_STATIC:
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK_STATIC %p\n", (void *)msg));
|
||||
msg->msg.cb.function(msg->msg.cb.ctx);
|
||||
break;
|
||||
|
||||
default:
|
||||
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
|
||||
*
|
||||
* @param p the received packet
|
||||
* @param inp the network interface on which the packet was received
|
||||
* @param input_fn input function to call
|
||||
*/
|
||||
err_t
|
||||
tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn)
|
||||
{
|
||||
#if LWIP_TCPIP_CORE_LOCKING_INPUT
|
||||
err_t ret;
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_inpkt: PACKET %p/%p\n", (void *)p, (void *)inp));
|
||||
LOCK_TCPIP_CORE();
|
||||
ret = input_fn(p, inp);
|
||||
UNLOCK_TCPIP_CORE();
|
||||
return ret;
|
||||
#else /* LWIP_TCPIP_CORE_LOCKING_INPUT */
|
||||
struct tcpip_msg *msg;
|
||||
|
||||
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
|
||||
|
||||
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT);
|
||||
if (msg == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
msg->type = TCPIP_MSG_INPKT;
|
||||
msg->msg.inp.p = p;
|
||||
msg->msg.inp.netif = inp;
|
||||
msg->msg.inp.input_fn = input_fn;
|
||||
if (sys_mbox_trypost(&tcpip_mbox, msg) != ERR_OK) {
|
||||
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
|
||||
return ERR_MEM;
|
||||
}
|
||||
return ERR_OK;
|
||||
#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup lwip_os
|
||||
* Pass a received packet to tcpip_thread for input processing with
|
||||
* ethernet_input or ip_input. Don't call directly, pass to netif_add()
|
||||
* and call netif->input().
|
||||
*
|
||||
* @param p the received packet, p->payload pointing to the Ethernet header or
|
||||
* to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or
|
||||
* NETIF_FLAG_ETHERNET flags)
|
||||
@@ -155,85 +284,93 @@ tcpip_thread(void *arg)
|
||||
err_t
|
||||
tcpip_input(struct pbuf *p, struct netif *inp)
|
||||
{
|
||||
#if LWIP_TCPIP_CORE_LOCKING_INPUT
|
||||
err_t ret;
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_input: PACKET %p/%p\n", (void *)p, (void *)inp));
|
||||
LOCK_TCPIP_CORE();
|
||||
#if LWIP_ETHERNET
|
||||
if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {
|
||||
ret = ethernet_input(p, inp);
|
||||
return tcpip_inpkt(p, inp, ethernet_input);
|
||||
} else
|
||||
#endif /* LWIP_ETHERNET */
|
||||
{
|
||||
ret = ip_input(p, inp);
|
||||
}
|
||||
UNLOCK_TCPIP_CORE();
|
||||
return ret;
|
||||
#else /* LWIP_TCPIP_CORE_LOCKING_INPUT */
|
||||
struct tcpip_msg *msg;
|
||||
|
||||
if (sys_mbox_valid(&mbox)) {
|
||||
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT);
|
||||
if (msg == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
msg->type = TCPIP_MSG_INPKT;
|
||||
msg->msg.inp.p = p;
|
||||
msg->msg.inp.netif = inp;
|
||||
if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
|
||||
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
|
||||
return ERR_MEM;
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
return ERR_VAL;
|
||||
#endif /* LWIP_TCPIP_CORE_LOCKING_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 f the function to call
|
||||
* @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;
|
||||
|
||||
if (sys_mbox_valid(&mbox)) {
|
||||
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
|
||||
if (msg == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
return ERR_OK;
|
||||
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
|
||||
if (msg == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
return ERR_VAL;
|
||||
|
||||
msg->type = TCPIP_MSG_CALLBACK;
|
||||
msg->msg.cb.function = function;
|
||||
msg->msg.cb.ctx = ctx;
|
||||
|
||||
sys_mbox_post(&tcpip_mbox, msg);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
#if LWIP_TCPIP_TIMEOUT
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
#if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS
|
||||
/**
|
||||
* call sys_timeout in tcpip_thread
|
||||
*
|
||||
* @param msec time in milliseconds for timeout
|
||||
* @param msecs time in milliseconds for timeout
|
||||
* @param h function to be called on timeout
|
||||
* @param arg argument to pass to timeout function h
|
||||
* @return ERR_MEM on memory error, ERR_OK otherwise
|
||||
@@ -243,26 +380,24 @@ tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
|
||||
{
|
||||
struct tcpip_msg *msg;
|
||||
|
||||
if (sys_mbox_valid(&mbox)) {
|
||||
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
|
||||
if (msg == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
|
||||
|
||||
msg->type = TCPIP_MSG_TIMEOUT;
|
||||
msg->msg.tmo.msecs = msecs;
|
||||
msg->msg.tmo.h = h;
|
||||
msg->msg.tmo.arg = arg;
|
||||
sys_mbox_post(&mbox, msg);
|
||||
return ERR_OK;
|
||||
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
|
||||
if (msg == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
return ERR_VAL;
|
||||
|
||||
msg->type = TCPIP_MSG_TIMEOUT;
|
||||
msg->msg.tmo.msecs = msecs;
|
||||
msg->msg.tmo.h = h;
|
||||
msg->msg.tmo.arg = arg;
|
||||
sys_mbox_post(&tcpip_mbox, msg);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* call sys_untimeout in tcpip_thread
|
||||
*
|
||||
* @param msec time in milliseconds for timeout
|
||||
* @param h function to be called on timeout
|
||||
* @param arg argument to pass to timeout function h
|
||||
* @return ERR_MEM on memory error, ERR_OK otherwise
|
||||
@@ -272,127 +407,197 @@ tcpip_untimeout(sys_timeout_handler h, void *arg)
|
||||
{
|
||||
struct tcpip_msg *msg;
|
||||
|
||||
if (sys_mbox_valid(&mbox)) {
|
||||
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
|
||||
if (msg == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
|
||||
|
||||
msg->type = TCPIP_MSG_UNTIMEOUT;
|
||||
msg->msg.tmo.h = h;
|
||||
msg->msg.tmo.arg = arg;
|
||||
sys_mbox_post(&mbox, msg);
|
||||
return ERR_OK;
|
||||
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
|
||||
if (msg == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
#endif /* LWIP_TCPIP_TIMEOUT */
|
||||
|
||||
#if LWIP_NETCONN
|
||||
msg->type = TCPIP_MSG_UNTIMEOUT;
|
||||
msg->msg.tmo.h = h;
|
||||
msg->msg.tmo.arg = arg;
|
||||
sys_mbox_post(&tcpip_mbox, msg);
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */
|
||||
|
||||
|
||||
/**
|
||||
* Call the lower part of a netconn_* function
|
||||
* This function is then running in the thread context
|
||||
* of tcpip_thread and has exclusive access to lwIP core code.
|
||||
* Sends a message to TCPIP thread to call a function. Caller thread blocks on
|
||||
* on a provided semaphore, which ist NOT automatically signalled by TCPIP thread,
|
||||
* this has to be done by the user.
|
||||
* It is recommended to use LWIP_TCPIP_CORE_LOCKING since this is the way
|
||||
* with least runtime overhead.
|
||||
*
|
||||
* @param apimsg a struct containing the function to call and its parameters
|
||||
* @param fn function to be called from TCPIP thread
|
||||
* @param apimsg argument to API function
|
||||
* @param sem semaphore to wait on
|
||||
* @return ERR_OK if the function was called, another err_t if not
|
||||
*/
|
||||
err_t
|
||||
tcpip_apimsg(struct api_msg *apimsg)
|
||||
tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t *sem)
|
||||
{
|
||||
struct tcpip_msg msg;
|
||||
#ifdef LWIP_DEBUG
|
||||
/* catch functions that don't set err */
|
||||
apimsg->msg.err = ERR_VAL;
|
||||
#endif
|
||||
|
||||
if (sys_mbox_valid(&mbox)) {
|
||||
msg.type = TCPIP_MSG_API;
|
||||
msg.msg.apimsg = apimsg;
|
||||
sys_mbox_post(&mbox, &msg);
|
||||
sys_arch_sem_wait(&apimsg->msg.conn->op_completed, 0);
|
||||
return apimsg->msg.err;
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
#if LWIP_TCPIP_CORE_LOCKING
|
||||
/**
|
||||
* Call the lower part of a netconn_* function
|
||||
* This function has exclusive access to lwIP core code by locking it
|
||||
* before the function is called.
|
||||
*
|
||||
* @param apimsg a struct containing the function to call and its parameters
|
||||
* @return ERR_OK (only for compatibility fo tcpip_apimsg())
|
||||
*/
|
||||
err_t
|
||||
tcpip_apimsg_lock(struct api_msg *apimsg)
|
||||
{
|
||||
#ifdef LWIP_DEBUG
|
||||
/* catch functions that don't set err */
|
||||
apimsg->msg.err = ERR_VAL;
|
||||
#endif
|
||||
|
||||
LWIP_UNUSED_ARG(sem);
|
||||
LOCK_TCPIP_CORE();
|
||||
apimsg->function(&(apimsg->msg));
|
||||
fn(apimsg);
|
||||
UNLOCK_TCPIP_CORE();
|
||||
return apimsg->msg.err;
|
||||
return ERR_OK;
|
||||
#else /* LWIP_TCPIP_CORE_LOCKING */
|
||||
TCPIP_MSG_VAR_DECLARE(msg);
|
||||
|
||||
}
|
||||
LWIP_ASSERT("semaphore not initialized", sys_sem_valid(sem));
|
||||
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(&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 */
|
||||
#endif /* LWIP_NETCONN */
|
||||
|
||||
#if LWIP_NETIF_API
|
||||
#if !LWIP_TCPIP_CORE_LOCKING
|
||||
/**
|
||||
* Much like tcpip_apimsg, but calls the lower part of a netifapi_*
|
||||
* function.
|
||||
*
|
||||
* @param netifapimsg a struct containing the function to call and its parameters
|
||||
* @return error code given back by the function that was called
|
||||
*/
|
||||
err_t
|
||||
tcpip_netifapi(struct netifapi_msg* netifapimsg)
|
||||
{
|
||||
struct tcpip_msg msg;
|
||||
|
||||
if (sys_mbox_valid(&mbox)) {
|
||||
err_t err = sys_sem_new(&netifapimsg->msg.sem, 0);
|
||||
if (err != ERR_OK) {
|
||||
netifapimsg->msg.err = err;
|
||||
return err;
|
||||
}
|
||||
|
||||
msg.type = TCPIP_MSG_NETIFAPI;
|
||||
msg.msg.netifapimsg = netifapimsg;
|
||||
sys_mbox_post(&mbox, &msg);
|
||||
sys_sem_wait(&netifapimsg->msg.sem);
|
||||
sys_sem_free(&netifapimsg->msg.sem);
|
||||
return netifapimsg->msg.err;
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
#else /* !LWIP_TCPIP_CORE_LOCKING */
|
||||
|
||||
/**
|
||||
* Call the lower part of a netifapi_* function
|
||||
* This function has exclusive access to lwIP core code by locking it
|
||||
* before the function is called.
|
||||
*
|
||||
* @param netifapimsg a struct containing the function to call and its parameters
|
||||
* @return ERR_OK (only for compatibility fo tcpip_netifapi())
|
||||
* 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.
|
||||
* If not, a semaphore is created and destroyed on every call which is usually
|
||||
* an expensive/slow operation.
|
||||
* @param fn Function to call
|
||||
* @param call Call parameters
|
||||
* @return Return value from tcpip_api_call_fn
|
||||
*/
|
||||
err_t
|
||||
tcpip_netifapi_lock(struct netifapi_msg* netifapimsg)
|
||||
tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call)
|
||||
{
|
||||
LOCK_TCPIP_CORE();
|
||||
netifapimsg->function(&(netifapimsg->msg));
|
||||
#if LWIP_TCPIP_CORE_LOCKING
|
||||
err_t err;
|
||||
LOCK_TCPIP_CORE();
|
||||
err = fn(call);
|
||||
UNLOCK_TCPIP_CORE();
|
||||
return netifapimsg->msg.err;
|
||||
return err;
|
||||
#else /* LWIP_TCPIP_CORE_LOCKING */
|
||||
TCPIP_MSG_VAR_DECLARE(msg);
|
||||
|
||||
#if !LWIP_NETCONN_SEM_PER_THREAD
|
||||
err_t err = sys_sem_new(&call->sem, 0);
|
||||
if (err != ERR_OK) {
|
||||
return err;
|
||||
}
|
||||
#endif /* LWIP_NETCONN_SEM_PER_THREAD */
|
||||
|
||||
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;
|
||||
TCPIP_MSG_VAR_REF(msg).msg.api_call.arg = call;
|
||||
TCPIP_MSG_VAR_REF(msg).msg.api_call.function = fn;
|
||||
#if LWIP_NETCONN_SEM_PER_THREAD
|
||||
TCPIP_MSG_VAR_REF(msg).msg.api_call.sem = LWIP_NETCONN_THREAD_SEM_GET();
|
||||
#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(&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);
|
||||
|
||||
#if !LWIP_NETCONN_SEM_PER_THREAD
|
||||
sys_sem_free(&call->sem);
|
||||
#endif /* LWIP_NETCONN_SEM_PER_THREAD */
|
||||
|
||||
return call->err;
|
||||
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
||||
}
|
||||
#endif /* !LWIP_TCPIP_CORE_LOCKING */
|
||||
#endif /* LWIP_NETIF_API */
|
||||
|
||||
/**
|
||||
* @ingroup lwip_os
|
||||
* Allocate a structure for a static callback message and initialize it.
|
||||
* 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_callbackmsg_trycallback().
|
||||
*
|
||||
* @see tcpip_callbackmsg_trycallback()
|
||||
* @see tcpip_callbackmsg_delete()
|
||||
*/
|
||||
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);
|
||||
if (msg == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
msg->type = TCPIP_MSG_CALLBACK_STATIC;
|
||||
msg->msg.cb.function = function;
|
||||
msg->msg.cb.ctx = ctx;
|
||||
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)
|
||||
{
|
||||
memp_free(MEMP_TCPIP_MSG_API, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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_callbackmsg_trycallback(struct tcpip_callback_msg *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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup lwip_os
|
||||
* Initialize this module:
|
||||
* - initialize all sub modules
|
||||
* - start the tcpip_thread
|
||||
@@ -407,16 +612,19 @@ 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
|
||||
if(sys_mutex_new(&lock_tcpip_core) != ERR_OK) {
|
||||
if (sys_mutex_new(&lock_tcpip_core) != ERR_OK) {
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -441,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -454,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 */
|
||||
174
src/apps/http/fs.c
Normal file
174
src/apps/http/fs.c
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lwip/apps/httpd_opts.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/apps/fs.h"
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#include HTTPD_FSDATA_FILE
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
#if LWIP_HTTPD_CUSTOM_FILES
|
||||
int fs_open_custom(struct fs_file *file, const char *name);
|
||||
void fs_close_custom(struct fs_file *file);
|
||||
#if LWIP_HTTPD_FS_ASYNC_READ
|
||||
u8_t fs_canread_custom(struct fs_file *file);
|
||||
u8_t fs_wait_read_custom(struct fs_file *file, fs_wait_cb callback_fn, void *callback_arg);
|
||||
int fs_read_async_custom(struct fs_file *file, char *buffer, int count, fs_wait_cb callback_fn, void *callback_arg);
|
||||
#else /* LWIP_HTTPD_FS_ASYNC_READ */
|
||||
int fs_read_custom(struct fs_file *file, char *buffer, int count);
|
||||
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
|
||||
#endif /* LWIP_HTTPD_CUSTOM_FILES */
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
err_t
|
||||
fs_open(struct fs_file *file, const char *name)
|
||||
{
|
||||
const struct fsdata_file *f;
|
||||
|
||||
if ((file == NULL) || (name == NULL)) {
|
||||
return ERR_ARG;
|
||||
}
|
||||
|
||||
#if LWIP_HTTPD_CUSTOM_FILES
|
||||
if (fs_open_custom(file, name)) {
|
||||
file->is_custom_file = 1;
|
||||
return ERR_OK;
|
||||
}
|
||||
file->is_custom_file = 0;
|
||||
#endif /* LWIP_HTTPD_CUSTOM_FILES */
|
||||
|
||||
for (f = FS_ROOT; f != NULL; f = f->next) {
|
||||
if (!strcmp(name, (const char *)f->name)) {
|
||||
file->data = (const char *)f->data;
|
||||
file->len = f->len;
|
||||
file->index = f->len;
|
||||
file->pextension = NULL;
|
||||
file->flags = f->flags;
|
||||
#if HTTPD_PRECALCULATED_CHECKSUM
|
||||
file->chksum_count = f->chksum_count;
|
||||
file->chksum = f->chksum;
|
||||
#endif /* HTTPD_PRECALCULATED_CHECKSUM */
|
||||
#if LWIP_HTTPD_FILE_STATE
|
||||
file->state = fs_state_init(file, name);
|
||||
#endif /* #if LWIP_HTTPD_FILE_STATE */
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
/* file not found */
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
fs_close(struct fs_file *file)
|
||||
{
|
||||
#if LWIP_HTTPD_CUSTOM_FILES
|
||||
if (file->is_custom_file) {
|
||||
fs_close_custom(file);
|
||||
}
|
||||
#endif /* LWIP_HTTPD_CUSTOM_FILES */
|
||||
#if LWIP_HTTPD_FILE_STATE
|
||||
fs_state_free(file, file->state);
|
||||
#endif /* #if LWIP_HTTPD_FILE_STATE */
|
||||
LWIP_UNUSED_ARG(file);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
#if LWIP_HTTPD_DYNAMIC_FILE_READ
|
||||
#if LWIP_HTTPD_FS_ASYNC_READ
|
||||
int
|
||||
fs_read_async(struct fs_file *file, char *buffer, int count, fs_wait_cb callback_fn, void *callback_arg)
|
||||
#else /* LWIP_HTTPD_FS_ASYNC_READ */
|
||||
int
|
||||
fs_read(struct fs_file *file, char *buffer, int count)
|
||||
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
|
||||
{
|
||||
int read;
|
||||
if (file->index == file->len) {
|
||||
return FS_READ_EOF;
|
||||
}
|
||||
#if LWIP_HTTPD_FS_ASYNC_READ
|
||||
LWIP_UNUSED_ARG(callback_fn);
|
||||
LWIP_UNUSED_ARG(callback_arg);
|
||||
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
|
||||
#if LWIP_HTTPD_CUSTOM_FILES
|
||||
if (file->is_custom_file) {
|
||||
#if LWIP_HTTPD_FS_ASYNC_READ
|
||||
return fs_read_async_custom(file, buffer, count, callback_fn, callback_arg);
|
||||
#else /* LWIP_HTTPD_FS_ASYNC_READ */
|
||||
return fs_read_custom(file, buffer, count);
|
||||
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
|
||||
}
|
||||
#endif /* LWIP_HTTPD_CUSTOM_FILES */
|
||||
|
||||
read = file->len - file->index;
|
||||
if (read > count) {
|
||||
read = count;
|
||||
}
|
||||
|
||||
MEMCPY(buffer, (file->data + file->index), read);
|
||||
file->index += read;
|
||||
|
||||
return (read);
|
||||
}
|
||||
#endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
#if LWIP_HTTPD_FS_ASYNC_READ
|
||||
int
|
||||
fs_is_file_ready(struct fs_file *file, fs_wait_cb callback_fn, void *callback_arg)
|
||||
{
|
||||
if (file != NULL) {
|
||||
#if LWIP_HTTPD_FS_ASYNC_READ
|
||||
#if LWIP_HTTPD_CUSTOM_FILES
|
||||
if (!fs_canread_custom(file)) {
|
||||
if (fs_wait_read_custom(file, callback_fn, callback_arg)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#else /* LWIP_HTTPD_CUSTOM_FILES */
|
||||
LWIP_UNUSED_ARG(callback_fn);
|
||||
LWIP_UNUSED_ARG(callback_arg);
|
||||
#endif /* LWIP_HTTPD_CUSTOM_FILES */
|
||||
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
int
|
||||
fs_bytes_left(struct fs_file *file)
|
||||
{
|
||||
return file->len - file->index;
|
||||
}
|
||||
21
src/apps/http/fs/404.html
Normal file
21
src/apps/http/fs/404.html
Normal file
@@ -0,0 +1,21 @@
|
||||
<html>
|
||||
<head><title>lwIP - A Lightweight TCP/IP Stack</title></head>
|
||||
<body bgcolor="white" text="black">
|
||||
|
||||
<table width="100%">
|
||||
<tr valign="top"><td width="80">
|
||||
<a href="http://www.sics.se/"><img src="/img/sics.gif"
|
||||
border="0" alt="SICS logo" title="SICS logo"></a>
|
||||
</td><td width="500">
|
||||
<h1>lwIP - A Lightweight TCP/IP Stack</h1>
|
||||
<h2>404 - Page not found</h2>
|
||||
<p>
|
||||
Sorry, the page you are requesting was not found on this
|
||||
server.
|
||||
</p>
|
||||
</td><td>
|
||||
|
||||
</td></tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
BIN
src/apps/http/fs/img/sics.gif
Normal file
BIN
src/apps/http/fs/img/sics.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 724 B |
47
src/apps/http/fs/index.html
Normal file
47
src/apps/http/fs/index.html
Normal file
@@ -0,0 +1,47 @@
|
||||
<html>
|
||||
<head><title>lwIP - A Lightweight TCP/IP Stack</title></head>
|
||||
<body bgcolor="white" text="black">
|
||||
|
||||
<table width="100%">
|
||||
<tr valign="top"><td width="80">
|
||||
<a href="http://www.sics.se/"><img src="/img/sics.gif"
|
||||
border="0" alt="SICS logo" title="SICS logo"></a>
|
||||
</td><td width="500">
|
||||
<h1>lwIP - A Lightweight TCP/IP Stack</h1>
|
||||
<p>
|
||||
The web page you are watching was served by a simple web
|
||||
server running on top of the lightweight TCP/IP stack <a
|
||||
href="http://www.sics.se/~adam/lwip/">lwIP</a>.
|
||||
</p>
|
||||
<p>
|
||||
lwIP is an open source implementation of the TCP/IP
|
||||
protocol suite that was originally written by <a
|
||||
href="http://www.sics.se/~adam/lwip/">Adam Dunkels
|
||||
of the Swedish Institute of Computer Science</a> but now is
|
||||
being actively developed by a team of developers
|
||||
distributed world-wide. Since it's release, lwIP has
|
||||
spurred a lot of interest and has been ported to several
|
||||
platforms and operating systems. lwIP can be used either
|
||||
with or without an underlying OS.
|
||||
</p>
|
||||
<p>
|
||||
The focus of the lwIP TCP/IP implementation is to reduce
|
||||
the RAM 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.
|
||||
</p>
|
||||
<p>
|
||||
More information about lwIP can be found at the lwIP
|
||||
homepage at <a
|
||||
href="http://savannah.nongnu.org/projects/lwip/">http://savannah.nongnu.org/projects/lwip/</a>
|
||||
or at the lwIP wiki at <a
|
||||
href="http://lwip.wikia.com/">http://lwip.wikia.com/</a>.
|
||||
</p>
|
||||
</td><td>
|
||||
|
||||
</td></tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
337
src/apps/http/fsdata.c
Normal file
337
src/apps/http/fsdata.c
Normal file
@@ -0,0 +1,337 @@
|
||||
#include "lwip/apps/fs.h"
|
||||
#include "lwip/def.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;
|
||||
#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,
|
||||
|
||||
/* HTTP header */
|
||||
/* "HTTP/1.0 200 OK
|
||||
" (17 bytes) */
|
||||
0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x30,0x20,0x32,0x30,0x30,0x20,0x4f,0x4b,0x0d,
|
||||
0x0a,
|
||||
/* "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,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,
|
||||
0x6a,0x6a,0x6a,0xbf,0xbf,0xbf,0x93,0x93,0x93,0x0f,0x0f,0x0f,0xb0,0xb0,0xb0,0xa6,
|
||||
0xa6,0xa6,0x80,0x80,0x80,0x76,0x76,0x76,0x1e,0x1e,0x1e,0x9d,0x9d,0x9d,0x2e,0x2e,
|
||||
0x2e,0x49,0x49,0x49,0x54,0x54,0x54,0x8a,0x8a,0x8a,0x60,0x60,0x60,0xc6,0xa6,0x99,
|
||||
0xbd,0xb5,0xb2,0xc2,0xab,0xa1,0xd9,0x41,0x40,0xd5,0x67,0x55,0xc0,0xb0,0xaa,0xd5,
|
||||
0x5e,0x4e,0xd6,0x50,0x45,0xcc,0x93,0x7d,0xc8,0xa1,0x90,0xce,0x8b,0x76,0xd2,0x7b,
|
||||
0x65,0xd1,0x84,0x6d,0xc9,0x99,0x86,0x3a,0x3a,0x3a,0x00,0x00,0x00,0xb8,0xb8,0xb8,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2c,0x00,0x00,
|
||||
0x00,0x00,0x46,0x00,0x22,0x00,0x00,0x06,0xfe,0x40,0x90,0x70,0x48,0x2c,0x1a,0x8f,
|
||||
0xc8,0xa4,0x72,0xc9,0x6c,0x3a,0x9f,0xd0,0xa8,0x74,0x4a,0xad,0x5a,0xaf,0xd8,0xac,
|
||||
0x76,0xa9,0x40,0x04,0xbe,0x83,0xe2,0x60,0x3c,0x50,0x20,0x0d,0x8e,0x6f,0x00,0x31,
|
||||
0x28,0x1c,0x0d,0x07,0xb5,0xc3,0x60,0x75,0x24,0x3e,0xf8,0xfc,0x87,0x11,0x06,0xe9,
|
||||
0x3d,0x46,0x07,0x0b,0x7a,0x7a,0x7c,0x43,0x06,0x1e,0x84,0x78,0x0b,0x07,0x6e,0x51,
|
||||
0x01,0x8a,0x84,0x08,0x7e,0x79,0x80,0x87,0x89,0x91,0x7a,0x93,0x0a,0x04,0x99,0x78,
|
||||
0x96,0x4f,0x03,0x9e,0x79,0x01,0x94,0x9f,0x43,0x9c,0xa3,0xa4,0x05,0x77,0xa3,0xa0,
|
||||
0x4e,0x98,0x79,0x0b,0x1e,0x83,0xa4,0xa6,0x1f,0x96,0x05,0x9d,0xaa,0x78,0x01,0x07,
|
||||
0x84,0x04,0x1e,0x1e,0xbb,0xb8,0x51,0x84,0x0e,0x43,0x05,0x07,0x77,0xa5,0x7f,0x42,
|
||||
0xb1,0xb2,0x01,0x63,0x08,0x0d,0xbb,0x01,0x0c,0x7a,0x0d,0x44,0x0e,0xd8,0xaf,0x4c,
|
||||
0x05,0x7a,0x04,0x47,0x07,0x07,0xb7,0x80,0xa2,0xe1,0x7d,0x44,0x05,0x01,0x04,0x01,
|
||||
0xd0,0xea,0x87,0x93,0x4f,0xe0,0x9a,0x49,0xce,0xd8,0x79,0x04,0x66,0x20,0x15,0x10,
|
||||
0x10,0x11,0x92,0x29,0x80,0xb6,0xc0,0x91,0x15,0x45,0x1e,0x90,0x19,0x71,0x46,0xa8,
|
||||
0x5c,0x04,0x0e,0x00,0x22,0x4e,0xe8,0x40,0x24,0x9f,0x3e,0x04,0x06,0xa7,0x58,0xd4,
|
||||
0x93,0xa0,0x1c,0x91,0x3f,0xe8,0xf0,0x88,0x03,0xb1,0x21,0xa2,0x49,0x00,0x19,0x86,
|
||||
0xfc,0x52,0x44,0xe0,0x01,0x9d,0x29,0x21,0x15,0x25,0x50,0xf7,0x67,0x25,0x1e,0x06,
|
||||
0xfd,0x4e,0x9a,0xb4,0x90,0xac,0x15,0xfa,0xcb,0x52,0x53,0x1e,0x8c,0xf2,0xf8,0x07,
|
||||
0x92,0x2d,0x08,0x3a,0x4d,0x12,0x49,0x95,0x49,0xdb,0x14,0x04,0xc4,0x14,0x85,0x29,
|
||||
0xaa,0xe7,0x01,0x08,0xa4,0x49,0x01,0x14,0x51,0xe0,0x53,0x91,0xd5,0x29,0x06,0x1a,
|
||||
0x64,0x02,0xf4,0xc7,0x81,0x9e,0x05,0x20,0x22,0x64,0xa5,0x30,0xae,0xab,0x9e,0x97,
|
||||
0x53,0xd8,0xb9,0xfd,0x50,0xef,0x93,0x02,0x42,0x74,0x34,0xe8,0x9c,0x20,0x21,0xc9,
|
||||
0x01,0x68,0x78,0xe6,0x55,0x29,0x20,0x56,0x4f,0x4c,0x40,0x51,0x71,0x82,0xc0,0x70,
|
||||
0x21,0x22,0x85,0xbe,0x4b,0x1c,0x44,0x05,0xea,0xa4,0x01,0xbf,0x22,0xb5,0xf0,0x1c,
|
||||
0x06,0x51,0x38,0x8f,0xe0,0x22,0xec,0x18,0xac,0x39,0x22,0xd4,0xd6,0x93,0x44,0x01,
|
||||
0x32,0x82,0xc8,0xfc,0x61,0xb3,0x01,0x45,0x0c,0x2e,0x83,0x30,0xd0,0x0e,0x17,0x24,
|
||||
0x0f,0x70,0x85,0x94,0xee,0x05,0x05,0x53,0x4b,0x32,0x1b,0x3f,0x98,0xd3,0x1d,0x29,
|
||||
0x81,0xb0,0xae,0x1e,0x8c,0x7e,0x68,0xe0,0x60,0x5a,0x54,0x8f,0xb0,0x78,0x69,0x73,
|
||||
0x06,0xa2,0x00,0x6b,0x57,0xca,0x3d,0x11,0x50,0xbd,0x04,0x30,0x4b,0x3a,0xd4,0xab,
|
||||
0x5f,0x1f,0x9b,0x3d,0x13,0x74,0x27,0x88,0x3c,0x25,0xe0,0x17,0xbe,0x7a,0x79,0x45,
|
||||
0x0d,0x0c,0xb0,0x8b,0xda,0x90,0xca,0x80,0x06,0x5d,0x17,0x60,0x1c,0x22,0x4c,0xd8,
|
||||
0x57,0x22,0x06,0x20,0x00,0x98,0x07,0x08,0xe4,0x56,0x80,0x80,0x1c,0xc5,0xb7,0xc5,
|
||||
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;
|
||||
#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,
|
||||
|
||||
/* HTTP header */
|
||||
/* "HTTP/1.0 404 File not found
|
||||
" (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/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,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,
|
||||
0x69,0x74,0x6c,0x65,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,0x69,
|
||||
0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,
|
||||
0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x74,0x69,0x74,0x6c,0x65,0x3e,0x3c,0x2f,
|
||||
0x68,0x65,0x61,0x64,0x3e,0x0d,0x0a,0x3c,0x62,0x6f,0x64,0x79,0x20,0x62,0x67,0x63,
|
||||
0x6f,0x6c,0x6f,0x72,0x3d,0x22,0x77,0x68,0x69,0x74,0x65,0x22,0x20,0x74,0x65,0x78,
|
||||
0x74,0x3d,0x22,0x62,0x6c,0x61,0x63,0x6b,0x22,0x3e,0x0d,0x0a,0x0d,0x0a,0x20,0x20,
|
||||
0x20,0x20,0x3c,0x74,0x61,0x62,0x6c,0x65,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,
|
||||
0x31,0x30,0x30,0x25,0x22,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x74,
|
||||
0x72,0x20,0x76,0x61,0x6c,0x69,0x67,0x6e,0x3d,0x22,0x74,0x6f,0x70,0x22,0x3e,0x3c,
|
||||
0x74,0x64,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,0x38,0x30,0x22,0x3e,0x09,0x20,
|
||||
0x20,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x61,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,
|
||||
0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,
|
||||
0x65,0x2f,0x22,0x3e,0x3c,0x69,0x6d,0x67,0x20,0x73,0x72,0x63,0x3d,0x22,0x2f,0x69,
|
||||
0x6d,0x67,0x2f,0x73,0x69,0x63,0x73,0x2e,0x67,0x69,0x66,0x22,0x0d,0x0a,0x09,0x20,
|
||||
0x20,0x62,0x6f,0x72,0x64,0x65,0x72,0x3d,0x22,0x30,0x22,0x20,0x61,0x6c,0x74,0x3d,
|
||||
0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x20,0x74,0x69,0x74,0x6c,
|
||||
0x65,0x3d,0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x3e,0x3c,0x2f,
|
||||
0x61,0x3e,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x20,0x77,0x69,
|
||||
0x64,0x74,0x68,0x3d,0x22,0x35,0x30,0x30,0x22,0x3e,0x09,0x20,0x20,0x0d,0x0a,0x09,
|
||||
0x20,0x20,0x3c,0x68,0x31,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,
|
||||
0x69,0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,
|
||||
0x50,0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x68,0x31,0x3e,0x0d,0x0a,0x09,0x20,
|
||||
0x20,0x3c,0x68,0x32,0x3e,0x34,0x30,0x34,0x20,0x2d,0x20,0x50,0x61,0x67,0x65,0x20,
|
||||
0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x3c,0x2f,0x68,0x32,0x3e,0x0d,0x0a,
|
||||
0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x53,0x6f,0x72,
|
||||
0x72,0x79,0x2c,0x20,0x74,0x68,0x65,0x20,0x70,0x61,0x67,0x65,0x20,0x79,0x6f,0x75,
|
||||
0x20,0x61,0x72,0x65,0x20,0x72,0x65,0x71,0x75,0x65,0x73,0x74,0x69,0x6e,0x67,0x20,
|
||||
0x77,0x61,0x73,0x20,0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x20,0x6f,0x6e,
|
||||
0x20,0x74,0x68,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x65,0x72,0x76,
|
||||
0x65,0x72,0x2e,0x20,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,
|
||||
0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x26,0x6e,
|
||||
0x62,0x73,0x70,0x3b,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x2f,0x74,0x72,
|
||||
0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x2f,0x74,0x61,0x62,0x6c,0x65,
|
||||
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;
|
||||
#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,
|
||||
|
||||
/* HTTP header */
|
||||
/* "HTTP/1.0 200 OK
|
||||
" (17 bytes) */
|
||||
0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x30,0x20,0x32,0x30,0x30,0x20,0x4f,0x4b,0x0d,
|
||||
0x0a,
|
||||
/* "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,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,
|
||||
0x69,0x74,0x6c,0x65,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,0x69,
|
||||
0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,
|
||||
0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x74,0x69,0x74,0x6c,0x65,0x3e,0x3c,0x2f,
|
||||
0x68,0x65,0x61,0x64,0x3e,0x0d,0x0a,0x3c,0x62,0x6f,0x64,0x79,0x20,0x62,0x67,0x63,
|
||||
0x6f,0x6c,0x6f,0x72,0x3d,0x22,0x77,0x68,0x69,0x74,0x65,0x22,0x20,0x74,0x65,0x78,
|
||||
0x74,0x3d,0x22,0x62,0x6c,0x61,0x63,0x6b,0x22,0x3e,0x0d,0x0a,0x0d,0x0a,0x20,0x20,
|
||||
0x20,0x20,0x3c,0x74,0x61,0x62,0x6c,0x65,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,
|
||||
0x31,0x30,0x30,0x25,0x22,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x74,
|
||||
0x72,0x20,0x76,0x61,0x6c,0x69,0x67,0x6e,0x3d,0x22,0x74,0x6f,0x70,0x22,0x3e,0x3c,
|
||||
0x74,0x64,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,0x38,0x30,0x22,0x3e,0x09,0x20,
|
||||
0x20,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x61,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,
|
||||
0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,
|
||||
0x65,0x2f,0x22,0x3e,0x3c,0x69,0x6d,0x67,0x20,0x73,0x72,0x63,0x3d,0x22,0x2f,0x69,
|
||||
0x6d,0x67,0x2f,0x73,0x69,0x63,0x73,0x2e,0x67,0x69,0x66,0x22,0x0d,0x0a,0x09,0x20,
|
||||
0x20,0x62,0x6f,0x72,0x64,0x65,0x72,0x3d,0x22,0x30,0x22,0x20,0x61,0x6c,0x74,0x3d,
|
||||
0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x20,0x74,0x69,0x74,0x6c,
|
||||
0x65,0x3d,0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x3e,0x3c,0x2f,
|
||||
0x61,0x3e,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x20,0x77,0x69,
|
||||
0x64,0x74,0x68,0x3d,0x22,0x35,0x30,0x30,0x22,0x3e,0x09,0x20,0x20,0x0d,0x0a,0x09,
|
||||
0x20,0x20,0x3c,0x68,0x31,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,
|
||||
0x69,0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,
|
||||
0x50,0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x68,0x31,0x3e,0x0d,0x0a,0x09,0x20,
|
||||
0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x54,0x68,0x65,0x20,0x77,
|
||||
0x65,0x62,0x20,0x70,0x61,0x67,0x65,0x20,0x79,0x6f,0x75,0x20,0x61,0x72,0x65,0x20,
|
||||
0x77,0x61,0x74,0x63,0x68,0x69,0x6e,0x67,0x20,0x77,0x61,0x73,0x20,0x73,0x65,0x72,
|
||||
0x76,0x65,0x64,0x20,0x62,0x79,0x20,0x61,0x20,0x73,0x69,0x6d,0x70,0x6c,0x65,0x20,
|
||||
0x77,0x65,0x62,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x65,0x72,0x76,0x65,0x72,
|
||||
0x20,0x72,0x75,0x6e,0x6e,0x69,0x6e,0x67,0x20,0x6f,0x6e,0x20,0x74,0x6f,0x70,0x20,
|
||||
0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x6c,0x69,0x67,0x68,0x74,0x77,0x65,0x69,0x67,
|
||||
0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,0x20,0x73,0x74,0x61,0x63,0x6b,0x20,
|
||||
0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,
|
||||
0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,
|
||||
0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f,0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x6c,
|
||||
0x77,0x49,0x50,0x3c,0x2f,0x61,0x3e,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,
|
||||
0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,
|
||||
0x6c,0x77,0x49,0x50,0x20,0x69,0x73,0x20,0x61,0x6e,0x20,0x6f,0x70,0x65,0x6e,0x20,
|
||||
0x73,0x6f,0x75,0x72,0x63,0x65,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,
|
||||
0x61,0x74,0x69,0x6f,0x6e,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x54,0x43,0x50,
|
||||
0x2f,0x49,0x50,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x72,0x6f,0x74,0x6f,0x63,
|
||||
0x6f,0x6c,0x20,0x73,0x75,0x69,0x74,0x65,0x20,0x74,0x68,0x61,0x74,0x20,0x77,0x61,
|
||||
0x73,0x20,0x6f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x6c,0x79,0x20,0x77,0x72,0x69,
|
||||
0x74,0x74,0x65,0x6e,0x20,0x62,0x79,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,
|
||||
0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,
|
||||
0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f,
|
||||
0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x41,0x64,0x61,0x6d,0x20,0x44,0x75,0x6e,0x6b,
|
||||
0x65,0x6c,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,
|
||||
0x20,0x53,0x77,0x65,0x64,0x69,0x73,0x68,0x20,0x49,0x6e,0x73,0x74,0x69,0x74,0x75,
|
||||
0x74,0x65,0x20,0x6f,0x66,0x20,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x72,0x20,0x53,
|
||||
0x63,0x69,0x65,0x6e,0x63,0x65,0x3c,0x2f,0x61,0x3e,0x20,0x62,0x75,0x74,0x20,0x6e,
|
||||
0x6f,0x77,0x20,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x62,0x65,0x69,0x6e,
|
||||
0x67,0x20,0x61,0x63,0x74,0x69,0x76,0x65,0x6c,0x79,0x20,0x64,0x65,0x76,0x65,0x6c,
|
||||
0x6f,0x70,0x65,0x64,0x20,0x62,0x79,0x20,0x61,0x20,0x74,0x65,0x61,0x6d,0x20,0x6f,
|
||||
0x66,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x72,0x73,0x0d,0x0a,0x09,0x20,
|
||||
0x20,0x20,0x20,0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x77,
|
||||
0x6f,0x72,0x6c,0x64,0x2d,0x77,0x69,0x64,0x65,0x2e,0x20,0x53,0x69,0x6e,0x63,0x65,
|
||||
0x20,0x69,0x74,0x27,0x73,0x20,0x72,0x65,0x6c,0x65,0x61,0x73,0x65,0x2c,0x20,0x6c,
|
||||
0x77,0x49,0x50,0x20,0x68,0x61,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x70,
|
||||
0x75,0x72,0x72,0x65,0x64,0x20,0x61,0x20,0x6c,0x6f,0x74,0x20,0x6f,0x66,0x20,0x69,
|
||||
0x6e,0x74,0x65,0x72,0x65,0x73,0x74,0x20,0x61,0x6e,0x64,0x20,0x68,0x61,0x73,0x20,
|
||||
0x62,0x65,0x65,0x6e,0x20,0x70,0x6f,0x72,0x74,0x65,0x64,0x20,0x74,0x6f,0x20,0x73,
|
||||
0x65,0x76,0x65,0x72,0x61,0x6c,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x6c,0x61,
|
||||
0x74,0x66,0x6f,0x72,0x6d,0x73,0x20,0x61,0x6e,0x64,0x20,0x6f,0x70,0x65,0x72,0x61,
|
||||
0x74,0x69,0x6e,0x67,0x20,0x73,0x79,0x73,0x74,0x65,0x6d,0x73,0x2e,0x20,0x6c,0x77,
|
||||
0x49,0x50,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x75,0x73,0x65,0x64,0x20,0x65,
|
||||
0x69,0x74,0x68,0x65,0x72,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x77,0x69,0x74,0x68,
|
||||
0x20,0x6f,0x72,0x20,0x77,0x69,0x74,0x68,0x6f,0x75,0x74,0x20,0x61,0x6e,0x20,0x75,
|
||||
0x6e,0x64,0x65,0x72,0x6c,0x79,0x69,0x6e,0x67,0x20,0x4f,0x53,0x2e,0x0d,0x0a,0x09,
|
||||
0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,
|
||||
0x09,0x20,0x20,0x20,0x20,0x54,0x68,0x65,0x20,0x66,0x6f,0x63,0x75,0x73,0x20,0x6f,
|
||||
0x66,0x20,0x74,0x68,0x65,0x20,0x6c,0x77,0x49,0x50,0x20,0x54,0x43,0x50,0x2f,0x49,
|
||||
0x50,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e,
|
||||
0x20,0x69,0x73,0x20,0x74,0x6f,0x20,0x72,0x65,0x64,0x75,0x63,0x65,0x0d,0x0a,0x09,
|
||||
0x20,0x20,0x20,0x20,0x74,0x68,0x65,0x20,0x52,0x41,0x4d,0x20,0x75,0x73,0x61,0x67,
|
||||
0x65,0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x73,0x74,0x69,0x6c,0x6c,0x20,0x68,0x61,
|
||||
0x76,0x69,0x6e,0x67,0x20,0x61,0x20,0x66,0x75,0x6c,0x6c,0x20,0x73,0x63,0x61,0x6c,
|
||||
0x65,0x20,0x54,0x43,0x50,0x2e,0x20,0x54,0x68,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,
|
||||
0x20,0x20,0x6d,0x61,0x6b,0x65,0x73,0x20,0x6c,0x77,0x49,0x50,0x20,0x73,0x75,0x69,
|
||||
0x74,0x61,0x62,0x6c,0x65,0x20,0x66,0x6f,0x72,0x20,0x75,0x73,0x65,0x20,0x69,0x6e,
|
||||
0x20,0x65,0x6d,0x62,0x65,0x64,0x64,0x65,0x64,0x20,0x73,0x79,0x73,0x74,0x65,0x6d,
|
||||
0x73,0x20,0x77,0x69,0x74,0x68,0x20,0x74,0x65,0x6e,0x73,0x0d,0x0a,0x09,0x20,0x20,
|
||||
0x20,0x20,0x6f,0x66,0x20,0x6b,0x69,0x6c,0x6f,0x62,0x79,0x74,0x65,0x73,0x20,0x6f,
|
||||
0x66,0x20,0x66,0x72,0x65,0x65,0x20,0x52,0x41,0x4d,0x20,0x61,0x6e,0x64,0x20,0x72,
|
||||
0x6f,0x6f,0x6d,0x20,0x66,0x6f,0x72,0x20,0x61,0x72,0x6f,0x75,0x6e,0x64,0x20,0x34,
|
||||
0x30,0x20,0x6b,0x69,0x6c,0x6f,0x62,0x79,0x74,0x65,0x73,0x0d,0x0a,0x09,0x20,0x20,
|
||||
0x20,0x20,0x6f,0x66,0x20,0x63,0x6f,0x64,0x65,0x20,0x52,0x4f,0x4d,0x2e,0x0d,0x0a,
|
||||
0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,
|
||||
0x0a,0x09,0x20,0x20,0x20,0x20,0x4d,0x6f,0x72,0x65,0x20,0x69,0x6e,0x66,0x6f,0x72,
|
||||
0x6d,0x61,0x74,0x69,0x6f,0x6e,0x20,0x61,0x62,0x6f,0x75,0x74,0x20,0x6c,0x77,0x49,
|
||||
0x50,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x66,0x6f,0x75,0x6e,0x64,0x20,0x61,
|
||||
0x74,0x20,0x74,0x68,0x65,0x20,0x6c,0x77,0x49,0x50,0x0d,0x0a,0x09,0x20,0x20,0x20,
|
||||
0x20,0x68,0x6f,0x6d,0x65,0x70,0x61,0x67,0x65,0x20,0x61,0x74,0x20,0x3c,0x61,0x0d,
|
||||
0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,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,0x2f,0x22,0x3e,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,0x2f,
|
||||
0x3c,0x2f,0x61,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x72,0x20,0x61,0x74,
|
||||
0x20,0x74,0x68,0x65,0x20,0x6c,0x77,0x49,0x50,0x20,0x77,0x69,0x6b,0x69,0x20,0x61,
|
||||
0x74,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,
|
||||
0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x6c,0x77,0x69,0x70,0x2e,0x77,0x69,0x6b,
|
||||
0x69,0x61,0x2e,0x63,0x6f,0x6d,0x2f,0x22,0x3e,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,
|
||||
0x6c,0x77,0x69,0x70,0x2e,0x77,0x69,0x6b,0x69,0x61,0x2e,0x63,0x6f,0x6d,0x2f,0x3c,
|
||||
0x2f,0x61,0x3e,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,
|
||||
0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x26,0x6e,
|
||||
0x62,0x73,0x70,0x3b,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x2f,0x74,0x72,
|
||||
0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x2f,0x74,0x61,0x62,0x6c,0x65,
|
||||
0x3e,0x0d,0x0a,0x3c,0x2f,0x62,0x6f,0x64,0x79,0x3e,0x0d,0x0a,0x3c,0x2f,0x68,0x74,
|
||||
0x6d,0x6c,0x3e,0x0d,0x0a,0x0d,0x0a,};
|
||||
|
||||
|
||||
|
||||
const struct fsdata_file file__img_sics_gif[] = { {
|
||||
file_NULL,
|
||||
data__img_sics_gif,
|
||||
data__img_sics_gif + 16,
|
||||
sizeof(data__img_sics_gif) - 16,
|
||||
FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT,
|
||||
}};
|
||||
|
||||
const struct fsdata_file file__404_html[] = { {
|
||||
file__img_sics_gif,
|
||||
data__404_html,
|
||||
data__404_html + 12,
|
||||
sizeof(data__404_html) - 12,
|
||||
FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT,
|
||||
}};
|
||||
|
||||
const struct fsdata_file file__index_html[] = { {
|
||||
file__404_html,
|
||||
data__index_html,
|
||||
data__index_html + 12,
|
||||
sizeof(data__index_html) - 12,
|
||||
FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT,
|
||||
}};
|
||||
|
||||
#define FS_ROOT file__index_html
|
||||
#define FS_NUMFILES 3
|
||||
|
||||
41
src/apps/http/fsdata.h
Normal file
41
src/apps/http/fsdata.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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 LWIP_FSDATA_H
|
||||
#define LWIP_FSDATA_H
|
||||
|
||||
#include "lwip/apps/httpd_opts.h"
|
||||
#include "lwip/apps/fs.h"
|
||||
|
||||
/* 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 */
|
||||
2762
src/apps/http/httpd.c
Normal file
2762
src/apps/http/httpd.c
Normal file
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 */
|
||||
97
src/apps/http/makefsdata/makefsdata
Normal file
97
src/apps/http/makefsdata/makefsdata
Normal file
@@ -0,0 +1,97 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
open(OUTPUT, "> fsdata.c");
|
||||
|
||||
chdir("fs");
|
||||
open(FILES, "find . -type f |");
|
||||
|
||||
while($file = <FILES>) {
|
||||
|
||||
# Do not include files in CVS directories nor backup files.
|
||||
if($file =~ /(CVS|~)/) {
|
||||
next;
|
||||
}
|
||||
|
||||
chop($file);
|
||||
|
||||
open(HEADER, "> /tmp/header") || die $!;
|
||||
if($file =~ /404/) {
|
||||
print(HEADER "HTTP/1.0 404 File not found\r\n");
|
||||
} else {
|
||||
print(HEADER "HTTP/1.0 200 OK\r\n");
|
||||
}
|
||||
print(HEADER "Server: lwIP/pre-0.6 (http://www.sics.se/~adam/lwip/)\r\n");
|
||||
if($file =~ /\.html$/) {
|
||||
print(HEADER "Content-type: text/html\r\n");
|
||||
} elsif($file =~ /\.gif$/) {
|
||||
print(HEADER "Content-type: image/gif\r\n");
|
||||
} elsif($file =~ /\.png$/) {
|
||||
print(HEADER "Content-type: image/png\r\n");
|
||||
} elsif($file =~ /\.jpg$/) {
|
||||
print(HEADER "Content-type: image/jpeg\r\n");
|
||||
} elsif($file =~ /\.class$/) {
|
||||
print(HEADER "Content-type: application/octet-stream\r\n");
|
||||
} elsif($file =~ /\.ram$/) {
|
||||
print(HEADER "Content-type: audio/x-pn-realaudio\r\n");
|
||||
} else {
|
||||
print(HEADER "Content-type: text/plain\r\n");
|
||||
}
|
||||
print(HEADER "\r\n");
|
||||
close(HEADER);
|
||||
|
||||
unless($file =~ /\.plain$/ || $file =~ /cgi/) {
|
||||
system("cat /tmp/header $file > /tmp/file");
|
||||
} else {
|
||||
system("cp $file /tmp/file");
|
||||
}
|
||||
|
||||
open(FILE, "/tmp/file");
|
||||
unlink("/tmp/file");
|
||||
unlink("/tmp/header");
|
||||
|
||||
$file =~ s/\.//;
|
||||
$fvar = $file;
|
||||
$fvar =~ s-/-_-g;
|
||||
$fvar =~ s-\.-_-g;
|
||||
print(OUTPUT "static const unsigned char data".$fvar."[] = {\n");
|
||||
print(OUTPUT "\t/* $file */\n\t");
|
||||
for($j = 0; $j < length($file); $j++) {
|
||||
printf(OUTPUT "%#02x, ", unpack("C", substr($file, $j, 1)));
|
||||
}
|
||||
printf(OUTPUT "0,\n");
|
||||
|
||||
|
||||
$i = 0;
|
||||
while(read(FILE, $data, 1)) {
|
||||
if($i == 0) {
|
||||
print(OUTPUT "\t");
|
||||
}
|
||||
printf(OUTPUT "%#02x, ", unpack("C", $data));
|
||||
$i++;
|
||||
if($i == 10) {
|
||||
print(OUTPUT "\n");
|
||||
$i = 0;
|
||||
}
|
||||
}
|
||||
print(OUTPUT "};\n\n");
|
||||
close(FILE);
|
||||
push(@fvars, $fvar);
|
||||
push(@files, $file);
|
||||
}
|
||||
|
||||
for($i = 0; $i < @fvars; $i++) {
|
||||
$file = $files[$i];
|
||||
$fvar = $fvars[$i];
|
||||
|
||||
if($i == 0) {
|
||||
$prevfile = "NULL";
|
||||
} else {
|
||||
$prevfile = "file" . $fvars[$i - 1];
|
||||
}
|
||||
print(OUTPUT "const struct fsdata_file file".$fvar."[] = {{$prevfile, data$fvar, ");
|
||||
print(OUTPUT "data$fvar + ". (length($file) + 1) .", ");
|
||||
print(OUTPUT "sizeof(data$fvar) - ". (length($file) + 1) ."}};\n\n");
|
||||
}
|
||||
|
||||
print(OUTPUT "#define FS_ROOT file$fvars[$i - 1]\n\n");
|
||||
print(OUTPUT "#define FS_NUMFILES $i\n");
|
||||
1251
src/apps/http/makefsdata/makefsdata.c
Normal file
1251
src/apps/http/makefsdata/makefsdata.c
Normal file
File diff suppressed because it is too large
Load Diff
13
src/apps/http/makefsdata/readme.txt
Normal file
13
src/apps/http/makefsdata/readme.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
This directory contains a script ('makefsdata') to create C code suitable for
|
||||
httpd for given html pages (or other files) in a directory.
|
||||
|
||||
There is also a plain C console application doing the same and extended a bit.
|
||||
|
||||
Usage: htmlgen [targetdir] [-s] [-i]s
|
||||
targetdir: relative or absolute path to files to convert
|
||||
switch -s: toggle processing of subdirectories (default is on)
|
||||
switch -e: exclude HTTP header from file (header is created at runtime, default is on)
|
||||
switch -11: include HTTP 1.1 header (1.0 is default)
|
||||
|
||||
if targetdir not specified, makefsdata will attempt to
|
||||
process files in subdirectory 'fs'.
|
||||
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
|
||||
841
src/apps/lwiperf/lwiperf.c
Normal file
841
src/apps/lwiperf/lwiperf.c
Normal file
@@ -0,0 +1,841 @@
|
||||
/**
|
||||
* @file
|
||||
* lwIP iPerf server implementation
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup iperf Iperf server
|
||||
* @ingroup apps
|
||||
*
|
||||
* 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
|
||||
* - 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)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2014 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
|
||||
*/
|
||||
|
||||
#include "lwip/apps/lwiperf.h"
|
||||
|
||||
#include "lwip/tcp.h"
|
||||
#include "lwip/sys.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* 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
|
||||
#define LWIPERF_TCP_MAX_IDLE_SEC 10U
|
||||
#endif
|
||||
#if LWIPERF_TCP_MAX_IDLE_SEC > 255
|
||||
#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
|
||||
#define LWIPERF_ALLOC(type) mem_malloc(sizeof(type))
|
||||
#define LWIPERF_FREE(type, item) mem_free(item)
|
||||
#endif
|
||||
|
||||
/** If this is 1, check that received data has the correct format */
|
||||
#ifndef LWIPERF_CHECK_RX_DATA
|
||||
#define LWIPERF_CHECK_RX_DATA 0
|
||||
#endif
|
||||
|
||||
/** This is the Iperf settings struct sent from the client */
|
||||
typedef struct _lwiperf_settings {
|
||||
#define LWIPERF_FLAGS_ANSWER_TEST 0x80000000
|
||||
#define LWIPERF_FLAGS_ANSWER_NOW 0x00000001
|
||||
u32_t flags;
|
||||
u32_t num_threads; /* unused for now */
|
||||
u32_t remote_port;
|
||||
u32_t buffer_len; /* unused for now */
|
||||
u32_t win_band; /* TCP window / UDP rate: unused for now */
|
||||
u32_t amount; /* pos. value: bytes?; neg. values: time (unit is 10ms: 1/100 second) */
|
||||
} lwiperf_settings_t;
|
||||
|
||||
/** Basic connection handle */
|
||||
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;
|
||||
/* 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;
|
||||
u32_t time_started;
|
||||
lwiperf_report_fn report_fn;
|
||||
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;
|
||||
/** 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',
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
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_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 = iter->next;
|
||||
}
|
||||
/* @debug: ensure this item is listed only once */
|
||||
for (iter = iter->next; iter != NULL; iter = iter->next) {
|
||||
LWIP_ASSERT("duplicate entry", iter != item);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if ((conn != NULL) && (conn->report_fn != NULL)) {
|
||||
u32_t now, duration_ms, bandwidth_kbitpsec;
|
||||
now = sys_now();
|
||||
duration_ms = now - conn->time_started;
|
||||
if (duration_ms == 0) {
|
||||
bandwidth_kbitpsec = 0;
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/** Close an iperf tcp session */
|
||||
static void
|
||||
lwiperf_tcp_close(lwiperf_state_tcp_t *conn, enum lwiperf_report_type report_type)
|
||||
{
|
||||
err_t err;
|
||||
|
||||
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);
|
||||
tcp_sent(conn->conn_pcb, NULL);
|
||||
tcp_recv(conn->conn_pcb, NULL);
|
||||
tcp_err(conn->conn_pcb, NULL);
|
||||
err = tcp_close(conn->conn_pcb);
|
||||
if (err != ERR_OK) {
|
||||
/* don't want to wait for free memory here... */
|
||||
tcp_abort(conn->conn_pcb);
|
||||
}
|
||||
} else {
|
||||
/* no conn pcb, this is the listener pcb */
|
||||
err = tcp_close(conn->server_pcb);
|
||||
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)
|
||||
{
|
||||
int send_more;
|
||||
err_t err;
|
||||
u16_t txlen;
|
||||
u16_t txlen_max;
|
||||
void *txptr;
|
||||
u8_t apiflags;
|
||||
|
||||
LWIP_ASSERT("conn invalid", (conn != NULL) && conn->base.tcp && (conn->base.server == 0));
|
||||
|
||||
do {
|
||||
send_more = 0;
|
||||
if (conn->settings.amount & PP_HTONL(0x80000000)) {
|
||||
/* 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_ms = time * 10;
|
||||
if (diff_ms >= time_ms) {
|
||||
/* time specified by the client is over -> close the connection */
|
||||
lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_CLIENT);
|
||||
return ERR_OK;
|
||||
}
|
||||
} else {
|
||||
/* this session is byte-limited */
|
||||
u32_t amount_bytes = lwip_htonl(conn->settings.amount);
|
||||
/* @todo: this can send up to 1*MSS more than requested... */
|
||||
if (amount_bytes >= conn->bytes_transferred) {
|
||||
/* all requested bytes transferred -> close the connection */
|
||||
lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_CLIENT);
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (conn->bytes_transferred < 24) {
|
||||
/* transmit the settings a first time */
|
||||
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];
|
||||
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 = 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;
|
||||
}
|
||||
apiflags = 0; /* no copying needed */
|
||||
send_more = 1;
|
||||
}
|
||||
txlen = txlen_max;
|
||||
do {
|
||||
err = tcp_write(conn->conn_pcb, txptr, txlen, apiflags);
|
||||
if (err == ERR_MEM) {
|
||||
txlen /= 2;
|
||||
}
|
||||
} while ((err == ERR_MEM) && (txlen >= (TCP_MSS / 2)));
|
||||
|
||||
if (err == ERR_OK) {
|
||||
conn->bytes_transferred += txlen;
|
||||
} else {
|
||||
send_more = 0;
|
||||
}
|
||||
} while (send_more);
|
||||
|
||||
tcp_output(conn->conn_pcb);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/** TCP sent callback, try to send more data */
|
||||
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;
|
||||
/* @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);
|
||||
LWIP_UNUSED_ARG(len);
|
||||
|
||||
conn->poll_count = 0;
|
||||
|
||||
return lwiperf_tcp_client_send_more(conn);
|
||||
}
|
||||
|
||||
/** TCP connected callback (active connection), send data now */
|
||||
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;
|
||||
LWIP_ASSERT("invalid conn", conn->conn_pcb == tpcb);
|
||||
LWIP_UNUSED_ARG(tpcb);
|
||||
if (err != ERR_OK) {
|
||||
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE);
|
||||
return ERR_OK;
|
||||
}
|
||||
conn->poll_count = 0;
|
||||
conn->time_started = sys_now();
|
||||
return lwiperf_tcp_client_send_more(conn);
|
||||
}
|
||||
|
||||
/** Start TCP connection back to the client (either parallel or after the
|
||||
* receive test has finished.
|
||||
*/
|
||||
static err_t
|
||||
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;
|
||||
ip_addr_t remote_addr;
|
||||
|
||||
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_ip_type(IP_GET_TYPE(remote_ip));
|
||||
if (newpcb == NULL) {
|
||||
LWIPERF_FREE(lwiperf_state_tcp_t, client_conn);
|
||||
return ERR_MEM;
|
||||
}
|
||||
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->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;
|
||||
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, *remote_ip);
|
||||
|
||||
err = tcp_connect(newpcb, &remote_addr, remote_port, lwiperf_tcp_client_connected);
|
||||
if (err != ERR_OK) {
|
||||
lwiperf_tcp_close(client_conn, LWIPERF_TCP_ABORTED_LOCAL);
|
||||
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)
|
||||
{
|
||||
u8_t tmp;
|
||||
u16_t tot_len;
|
||||
u32_t packet_idx;
|
||||
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);
|
||||
|
||||
if (err != ERR_OK) {
|
||||
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE);
|
||||
return ERR_OK;
|
||||
}
|
||||
if (p == NULL) {
|
||||
/* connection closed -> test done */
|
||||
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;
|
||||
}
|
||||
tot_len = p->tot_len;
|
||||
|
||||
conn->poll_count = 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_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_OK;
|
||||
}
|
||||
conn->have_settings_buf = 1;
|
||||
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_passive(conn);
|
||||
if (err2 != ERR_OK) {
|
||||
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_TXERROR);
|
||||
pbuf_free(p);
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
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);
|
||||
if (conn->bytes_transferred <= 24) {
|
||||
conn->time_started = sys_now();
|
||||
tcp_recved(tpcb, p->tot_len);
|
||||
pbuf_free(p);
|
||||
return ERR_OK;
|
||||
}
|
||||
conn->next_num = 4; /* 24 bytes received... */
|
||||
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;
|
||||
u16_t i;
|
||||
for (i = 0; i < q->len; i++) {
|
||||
u8_t val = payload[i];
|
||||
u8_t num = val - '0';
|
||||
if (num == conn->next_num) {
|
||||
conn->next_num++;
|
||||
if (conn->next_num == 10) {
|
||||
conn->next_num = 0;
|
||||
}
|
||||
} else {
|
||||
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR);
|
||||
pbuf_free(p);
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
packet_idx += q->len;
|
||||
}
|
||||
LWIP_ASSERT("count mismatch", packet_idx == p->tot_len);
|
||||
conn->bytes_transferred += packet_idx;
|
||||
tcp_recved(tpcb, tot_len);
|
||||
pbuf_free(p);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/** Error callback, iperf tcp session aborted */
|
||||
static void
|
||||
lwiperf_tcp_err(void *arg, err_t err)
|
||||
{
|
||||
lwiperf_state_tcp_t *conn = (lwiperf_state_tcp_t *)arg;
|
||||
LWIP_UNUSED_ARG(err);
|
||||
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE);
|
||||
}
|
||||
|
||||
/** TCP poll callback, try to send more data */
|
||||
static err_t
|
||||
lwiperf_tcp_poll(void *arg, struct tcp_pcb *tpcb)
|
||||
{
|
||||
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) {
|
||||
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL);
|
||||
return ERR_OK; /* lwiperf_tcp_close frees conn */
|
||||
}
|
||||
|
||||
if (!conn->base.server) {
|
||||
lwiperf_tcp_client_send_more(conn);
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/** This is called when a new client connects for an iperf tcp session */
|
||||
static err_t
|
||||
lwiperf_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
|
||||
{
|
||||
lwiperf_state_tcp_t *s, *conn;
|
||||
if ((err != ERR_OK) || (newpcb == NULL) || (arg == NULL)) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
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_master_state = &s->base;
|
||||
conn->conn_pcb = newpcb;
|
||||
conn->time_started = sys_now();
|
||||
conn->report_fn = s->report_fn;
|
||||
conn->report_arg = s->report_arg;
|
||||
|
||||
/* setup the tcp rx connection */
|
||||
tcp_arg(newpcb, conn);
|
||||
tcp_recv(newpcb, lwiperf_tcp_recv);
|
||||
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.
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
return lwiperf_start_tcp_server(IP_ADDR_ANY, LWIPERF_TCP_PORT_DEFAULT,
|
||||
report_fn, report_arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iperf
|
||||
* Start a TCP iperf server on a specific IP address and port and listen for
|
||||
* incoming connections from iperf clients.
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
err_t err;
|
||||
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 ERR_ARG;
|
||||
}
|
||||
|
||||
s = (lwiperf_state_tcp_t *)LWIPERF_ALLOC(lwiperf_state_tcp_t);
|
||||
if (s == 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_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 ERR_MEM;
|
||||
}
|
||||
pcb = NULL;
|
||||
|
||||
tcp_arg(s->server_pcb, s);
|
||||
tcp_accept(s->server_pcb, lwiperf_tcp_accept);
|
||||
|
||||
lwiperf_list_add(&s->base);
|
||||
*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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iperf
|
||||
* Abort an iperf session (handle returned by lwiperf_start_tcp_server*())
|
||||
*/
|
||||
void
|
||||
lwiperf_abort(void *lwiperf_session)
|
||||
{
|
||||
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_master_state == lwiperf_session)) {
|
||||
dealloc = i;
|
||||
i = i->next;
|
||||
if (last != NULL) {
|
||||
last->next = i;
|
||||
}
|
||||
LWIPERF_FREE(lwiperf_state_tcp_t, dealloc); /* @todo: type? */
|
||||
} else {
|
||||
last = i;
|
||||
i = i->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* LWIP_TCP && LWIP_CALLBACK_API */
|
||||
2407
src/apps/mdns/mdns.c
Normal file
2407
src/apps/mdns/mdns.c
Normal file
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
533
src/apps/netbiosns/netbiosns.c
Normal file
533
src/apps/netbiosns/netbiosns.c
Normal file
@@ -0,0 +1,533 @@
|
||||
/**
|
||||
* @file
|
||||
* NetBIOS name service responder
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup netbiosns NETBIOS responder
|
||||
* @ingroup apps
|
||||
*
|
||||
* This is an example implementation of a NetBIOS name server.
|
||||
* It responds to name queries for a configurable name.
|
||||
* Name resolving is not supported.
|
||||
*
|
||||
* Note that the device doesn't broadcast it's own name so can't
|
||||
* detect duplicate names!
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* 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"
|
||||
|
||||
#if LWIP_IPV4 && LWIP_UDP /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/prot/iana.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/** size of a NetBIOS name */
|
||||
#define NETBIOS_NAME_LEN 16
|
||||
|
||||
/** The Time-To-Live for NetBIOS name responds (in seconds)
|
||||
* Default is 300000 seconds (3 days, 11 hours, 20 minutes) */
|
||||
#define NETBIOS_NAME_TTL 300000u
|
||||
|
||||
/** NetBIOS header flags */
|
||||
#define NETB_HFLAG_RESPONSE 0x8000U
|
||||
#define NETB_HFLAG_OPCODE 0x7800U
|
||||
#define NETB_HFLAG_OPCODE_NAME_QUERY 0x0000U
|
||||
#define NETB_HFLAG_AUTHORATIVE 0x0400U
|
||||
#define NETB_HFLAG_TRUNCATED 0x0200U
|
||||
#define NETB_HFLAG_RECURS_DESIRED 0x0100U
|
||||
#define NETB_HFLAG_RECURS_AVAILABLE 0x0080U
|
||||
#define NETB_HFLAG_BROADCAST 0x0010U
|
||||
#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
|
||||
#define NETB_NFLAG_NODETYPE_HNODE 0x6000U
|
||||
#define NETB_NFLAG_NODETYPE_MNODE 0x4000U
|
||||
#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"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct netbios_hdr {
|
||||
PACK_STRUCT_FIELD(u16_t trans_id);
|
||||
PACK_STRUCT_FIELD(u16_t flags);
|
||||
PACK_STRUCT_FIELD(u16_t questions);
|
||||
PACK_STRUCT_FIELD(u16_t answerRRs);
|
||||
PACK_STRUCT_FIELD(u16_t authorityRRs);
|
||||
PACK_STRUCT_FIELD(u16_t additionalRRs);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# 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"
|
||||
#endif
|
||||
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_FIELD(u16_t type);
|
||||
PACK_STRUCT_FIELD(u16_t cls);
|
||||
PACK_STRUCT_FIELD(u32_t ttl);
|
||||
PACK_STRUCT_FIELD(u16_t datalen);
|
||||
PACK_STRUCT_FIELD(u16_t flags);
|
||||
PACK_STRUCT_FLD_S(ip4_addr_p_t addr);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
/** NetBIOS message */
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct netbios_resp {
|
||||
struct netbios_hdr resp_hdr;
|
||||
struct netbios_name_hdr resp_name;
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# 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
|
||||
static char netbiosns_local_name[NETBIOS_NAME_LEN];
|
||||
#define NETBIOS_LOCAL_NAME netbiosns_local_name
|
||||
#endif
|
||||
|
||||
static struct udp_pcb *netbiosns_pcb;
|
||||
|
||||
/** Decode a NetBIOS name (from packet to string) */
|
||||
static int
|
||||
netbiosns_name_decode(const char *name_enc, char *name_dec, int name_dec_len)
|
||||
{
|
||||
const char *pname;
|
||||
char cname;
|
||||
char cnbname;
|
||||
int idx = 0;
|
||||
|
||||
LWIP_UNUSED_ARG(name_dec_len);
|
||||
|
||||
/* Start decoding netbios name. */
|
||||
pname = name_enc;
|
||||
for (;;) {
|
||||
/* 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 (!lwip_isupper(cname)) {
|
||||
/* Not legal. */
|
||||
return -1;
|
||||
}
|
||||
cname -= 'A';
|
||||
cnbname = cname << 4;
|
||||
pname++;
|
||||
|
||||
cname = *pname;
|
||||
if (!lwip_isupper(cname)) {
|
||||
/* Not legal. */
|
||||
return -1;
|
||||
}
|
||||
cname -= 'A';
|
||||
cnbname |= cname;
|
||||
pname++;
|
||||
|
||||
/* Do we have room to store the character? */
|
||||
if (idx < NETBIOS_NAME_LEN) {
|
||||
/* Yes - store the character. */
|
||||
name_dec[idx++] = (cnbname != ' ' ? cnbname : '\0');
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0 /* function currently unused */
|
||||
/** Encode a NetBIOS name (from string to packet) - currently unused because
|
||||
we don't ask for names. */
|
||||
static int
|
||||
netbiosns_name_encode(char *name_enc, char *name_dec, int name_dec_len)
|
||||
{
|
||||
char *pname;
|
||||
char cname;
|
||||
unsigned char ucname;
|
||||
int idx = 0;
|
||||
|
||||
/* Start encoding netbios name. */
|
||||
pname = name_enc;
|
||||
|
||||
for (;;) {
|
||||
/* 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') && (cname < '0' || cname > '9')) {
|
||||
/* Not legal. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Do we have room to store the character? */
|
||||
if (idx >= name_dec_len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Yes - store the character. */
|
||||
ucname = cname;
|
||||
name_dec[idx++] = ('A' + ((ucname >> 4) & 0x0F));
|
||||
name_dec[idx++] = ('A' + ( ucname & 0x0F));
|
||||
pname++;
|
||||
}
|
||||
|
||||
/* Fill with "space" coding */
|
||||
for (; idx < name_dec_len - 1;) {
|
||||
name_dec[idx++] = 'C';
|
||||
name_dec[idx++] = 'A';
|
||||
}
|
||||
|
||||
/* Terminate string */
|
||||
name_dec[idx] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
/** NetBIOS Name service recv callback */
|
||||
static void
|
||||
netbiosns_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
|
||||
/* 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_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))) {
|
||||
/* decode the NetBIOS name */
|
||||
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;
|
||||
|
||||
/* 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_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);
|
||||
|
||||
/* 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 */
|
||||
}
|
||||
}
|
||||
}
|
||||
/* free the pbuf */
|
||||
pbuf_free(p);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
|
||||
netbiosns_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
|
||||
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, LWIP_IANA_PORT_NETBIOS);
|
||||
udp_recv(netbiosns_pcb, netbiosns_recv, netbiosns_pcb);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NETBIOS_LWIP_NAME
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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 /* NETBIOS_LWIP_NAME */
|
||||
|
||||
/**
|
||||
* @ingroup netbiosns
|
||||
* Stop netbios responder
|
||||
*/
|
||||
void
|
||||
netbiosns_stop(void)
|
||||
{
|
||||
LWIP_ASSERT_CORE_LOCKED();
|
||||
if (netbiosns_pcb != NULL) {
|
||||
udp_remove(netbiosns_pcb);
|
||||
netbiosns_pcb = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* LWIP_IPV4 && LWIP_UDP */
|
||||
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
704
src/apps/snmp/snmp_asn1.c
Normal file
704
src/apps/snmp/snmp_asn1.c
Normal file
@@ -0,0 +1,704 @@
|
||||
/**
|
||||
* @file
|
||||
* Abstract Syntax Notation One (ISO 8824, 8825) encoding
|
||||
*
|
||||
* @todo not optimised (yet), favor correctness over speed, favor speed over size
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
|
||||
* 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: Christiaan Simons <christiaan.simons@axon.tv>
|
||||
* Martin Hentschel <info@cl-soft.de>
|
||||
*/
|
||||
|
||||
#include "lwip/apps/snmp_opts.h"
|
||||
|
||||
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "snmp_asn1.h"
|
||||
|
||||
#define PBUF_OP_EXEC(code) \
|
||||
if ((code) != ERR_OK) { \
|
||||
return ERR_BUF; \
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a TLV into a pbuf stream.
|
||||
*
|
||||
* @param pbuf_stream points to a pbuf stream
|
||||
* @param tlv TLV to encode
|
||||
* @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)
|
||||
{
|
||||
u8_t data;
|
||||
u8_t length_bytes_required;
|
||||
|
||||
/* write type */
|
||||
if ((tlv->type & SNMP_ASN1_DATATYPE_MASK) == SNMP_ASN1_DATATYPE_EXTENDED) {
|
||||
/* extended format is not used by SNMP so we do not accept those values */
|
||||
return ERR_ARG;
|
||||
}
|
||||
if (tlv->type_len != 0) {
|
||||
/* any other value as auto is not accepted for type (we always use one byte because extended syntax is prohibited) */
|
||||
return ERR_ARG;
|
||||
}
|
||||
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, tlv->type));
|
||||
tlv->type_len = 1;
|
||||
|
||||
/* write length */
|
||||
if (tlv->value_len <= 127) {
|
||||
length_bytes_required = 1;
|
||||
} else if (tlv->value_len <= 255) {
|
||||
length_bytes_required = 2;
|
||||
} else {
|
||||
length_bytes_required = 3;
|
||||
}
|
||||
|
||||
/* check for forced min length */
|
||||
if (tlv->length_len > 0) {
|
||||
if (tlv->length_len < length_bytes_required) {
|
||||
/* unable to code requested length in requested number of bytes */
|
||||
return ERR_ARG;
|
||||
}
|
||||
|
||||
length_bytes_required = tlv->length_len;
|
||||
} else {
|
||||
tlv->length_len = length_bytes_required;
|
||||
}
|
||||
|
||||
if (length_bytes_required > 1) {
|
||||
/* multi byte representation required */
|
||||
length_bytes_required--;
|
||||
data = 0x80 | length_bytes_required; /* extended length definition, 1 length byte follows */
|
||||
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data));
|
||||
|
||||
while (length_bytes_required > 1) {
|
||||
if (length_bytes_required == 2) {
|
||||
/* append high byte */
|
||||
data = (u8_t)(tlv->value_len >> 8);
|
||||
} else {
|
||||
/* append leading 0x00 */
|
||||
data = 0x00;
|
||||
}
|
||||
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data));
|
||||
length_bytes_required--;
|
||||
}
|
||||
}
|
||||
|
||||
/* append low byte */
|
||||
data = (u8_t)(tlv->value_len & 0xFF);
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data));
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes raw data (octet string, opaque) into a pbuf chained ASN1 msg.
|
||||
*
|
||||
* @param pbuf_stream points to a pbuf stream
|
||||
* @param raw_len raw data length
|
||||
* @param raw points raw data
|
||||
* @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)
|
||||
{
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_writebuf(pbuf_stream, raw, raw_len));
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes u32_t (counter, gauge, timeticks) 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_u32t_cnt()
|
||||
*/
|
||||
err_t
|
||||
snmp_asn1_enc_u32t(struct snmp_pbuf_stream *pbuf_stream, u16_t octets_needed, u32_t value)
|
||||
{
|
||||
if (octets_needed > 5) {
|
||||
return ERR_ARG;
|
||||
}
|
||||
if (octets_needed == 5) {
|
||||
/* 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))));
|
||||
}
|
||||
|
||||
/* (only) one least significant octet */
|
||||
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.
|
||||
*
|
||||
* @param pbuf_stream points to a pbuf stream
|
||||
* @param octets_needed encoding length (from snmp_asn1_enc_s32t_cnt())
|
||||
* @param value is the host order s32_t value to be encoded
|
||||
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
while (octets_needed > 1) {
|
||||
octets_needed--;
|
||||
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(value >> (octets_needed << 3))));
|
||||
}
|
||||
|
||||
/* (only) one least significant octet */
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)value));
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes object identifier into a pbuf chained ASN1 msg.
|
||||
*
|
||||
* @param pbuf_stream points to a pbuf stream
|
||||
* @param oid points to object identifier array
|
||||
* @param oid_len object identifier array length
|
||||
* @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)
|
||||
{
|
||||
if (oid_len > 1) {
|
||||
/* write compressed first two sub id's */
|
||||
u32_t compressed_byte = ((oid[0] * 40) + oid[1]);
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)compressed_byte));
|
||||
oid_len -= 2;
|
||||
oid += 2;
|
||||
} else {
|
||||
/* @bug: allow empty varbinds for symmetry (we must decode them for getnext), allow partial compression?? */
|
||||
/* ident_len <= 1, at least we need zeroDotZero (0.0) (ident_len == 2) */
|
||||
return ERR_ARG;
|
||||
}
|
||||
|
||||
while (oid_len > 0) {
|
||||
u32_t sub_id;
|
||||
u8_t shift, tail;
|
||||
|
||||
oid_len--;
|
||||
sub_id = *oid;
|
||||
tail = 0;
|
||||
shift = 28;
|
||||
while (shift > 0) {
|
||||
u8_t code;
|
||||
|
||||
code = (u8_t)(sub_id >> shift);
|
||||
if ((code != 0) || (tail != 0)) {
|
||||
tail = 1;
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, code | 0x80));
|
||||
}
|
||||
shift -= 7;
|
||||
}
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)sub_id & 0x7F));
|
||||
|
||||
/* proceed to next sub-identifier */
|
||||
oid++;
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns octet count for length.
|
||||
*
|
||||
* @param length parameter length
|
||||
* @param octets_needed points to the return value
|
||||
*/
|
||||
void
|
||||
snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed)
|
||||
{
|
||||
if (length < 0x80U) {
|
||||
*octets_needed = 1;
|
||||
} else if (length < 0x100U) {
|
||||
*octets_needed = 2;
|
||||
} else {
|
||||
*octets_needed = 3;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns octet count for an u32_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_u32t_cnt(u32_t value, u16_t *octets_needed)
|
||||
{
|
||||
if (value < 0x80UL) {
|
||||
*octets_needed = 1;
|
||||
} else if (value < 0x8000UL) {
|
||||
*octets_needed = 2;
|
||||
} else if (value < 0x800000UL) {
|
||||
*octets_needed = 3;
|
||||
} else if (value < 0x80000000UL) {
|
||||
*octets_needed = 4;
|
||||
} else {
|
||||
*octets_needed = 5;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns octet count for an s32_t.
|
||||
*
|
||||
* @param value value to be encoded
|
||||
* @param octets_needed points to the return value
|
||||
*
|
||||
* @note ASN coded integers are _always_ signed.
|
||||
*/
|
||||
void
|
||||
snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed)
|
||||
{
|
||||
if (value < 0) {
|
||||
value = ~value;
|
||||
}
|
||||
if (value < 0x80L) {
|
||||
*octets_needed = 1;
|
||||
} else if (value < 0x8000L) {
|
||||
*octets_needed = 2;
|
||||
} else if (value < 0x800000L) {
|
||||
*octets_needed = 3;
|
||||
} else {
|
||||
*octets_needed = 4;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns octet count for an object identifier.
|
||||
*
|
||||
* @param oid points to object identifier array
|
||||
* @param oid_len object identifier array length
|
||||
* @param octets_needed points to the return value
|
||||
*/
|
||||
void
|
||||
snmp_asn1_enc_oid_cnt(const u32_t *oid, u16_t oid_len, u16_t *octets_needed)
|
||||
{
|
||||
u32_t sub_id;
|
||||
|
||||
*octets_needed = 0;
|
||||
if (oid_len > 1) {
|
||||
/* compressed prefix in one octet */
|
||||
(*octets_needed)++;
|
||||
oid_len -= 2;
|
||||
oid += 2;
|
||||
}
|
||||
while (oid_len > 0) {
|
||||
oid_len--;
|
||||
sub_id = *oid;
|
||||
|
||||
sub_id >>= 7;
|
||||
(*octets_needed)++;
|
||||
while (sub_id > 0) {
|
||||
sub_id >>= 7;
|
||||
(*octets_needed)++;
|
||||
}
|
||||
oid++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a TLV from a pbuf stream.
|
||||
*
|
||||
* @param pbuf_stream points to a pbuf stream
|
||||
* @param tlv returns decoded TLV
|
||||
* @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)
|
||||
{
|
||||
u8_t data;
|
||||
|
||||
/* decode type first */
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
|
||||
tlv->type = data;
|
||||
|
||||
if ((tlv->type & SNMP_ASN1_DATATYPE_MASK) == SNMP_ASN1_DATATYPE_EXTENDED) {
|
||||
/* extended format is not used by SNMP so we do not accept those values */
|
||||
return ERR_VAL;
|
||||
}
|
||||
tlv->type_len = 1;
|
||||
|
||||
/* now, decode length */
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
|
||||
|
||||
if (data < 0x80) { /* short form */
|
||||
tlv->length_len = 1;
|
||||
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;
|
||||
|
||||
while (length_bytes > 0) {
|
||||
/* we only support up to u16.maxvalue-1 (2 bytes) but have to accept leading zero bytes */
|
||||
if (tlv->value_len > 0xFF) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
|
||||
tlv->value_len <<= 8;
|
||||
tlv->value_len |= data;
|
||||
|
||||
/* take care for special value used for indefinite length */
|
||||
if (tlv->value_len == 0xFFFF) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
length_bytes--;
|
||||
}
|
||||
} else { /* data == 0x80 indefinite length form */
|
||||
/* (not allowed for SNMP; RFC 1157, 3.2.2) */
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes positive integer (counter, gauge, timeticks) into 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_u32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value)
|
||||
{
|
||||
u8_t data;
|
||||
|
||||
if ((len > 0) && (len <= 5)) {
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
|
||||
|
||||
/* expecting sign bit to be zero, only unsigned please! */
|
||||
if (((len == 5) && (data == 0x00)) || ((len < 5) && ((data & 0x80) == 0))) {
|
||||
*value = data;
|
||||
len--;
|
||||
|
||||
while (len > 0) {
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
|
||||
len--;
|
||||
|
||||
*value <<= 8;
|
||||
*value |= data;
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes integer into s32_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!
|
||||
*/
|
||||
err_t
|
||||
snmp_asn1_dec_s32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, s32_t *value)
|
||||
{
|
||||
u8_t data;
|
||||
|
||||
if ((len > 0) && (len < 5)) {
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
|
||||
|
||||
if (data & 0x80) {
|
||||
/* negative, start from -1 */
|
||||
*value = -1;
|
||||
*value = (*value << 8) | data;
|
||||
} else {
|
||||
/* positive, start from 0 */
|
||||
*value = data;
|
||||
}
|
||||
len--;
|
||||
/* shift in the remaining value */
|
||||
while (len > 0) {
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
|
||||
*value = (*value << 8) | data;
|
||||
len--;
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes object identifier from incoming message into array of u32_t.
|
||||
*
|
||||
* @param pbuf_stream points to a pbuf stream
|
||||
* @param len length of the coded object identifier
|
||||
* @param oid return decoded object identifier
|
||||
* @param oid_len return decoded object identifier length
|
||||
* @param oid_max_len size of oid buffer
|
||||
* @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)
|
||||
{
|
||||
u32_t *oid_ptr;
|
||||
u8_t data;
|
||||
|
||||
*oid_len = 0;
|
||||
oid_ptr = oid;
|
||||
if (len > 0) {
|
||||
if (oid_max_len < 2) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
|
||||
len--;
|
||||
|
||||
/* first compressed octet */
|
||||
if (data == 0x2B) {
|
||||
/* (most) common case 1.3 (iso.org) */
|
||||
*oid_ptr = 1;
|
||||
oid_ptr++;
|
||||
*oid_ptr = 3;
|
||||
oid_ptr++;
|
||||
} else if (data < 40) {
|
||||
*oid_ptr = 0;
|
||||
oid_ptr++;
|
||||
*oid_ptr = data;
|
||||
oid_ptr++;
|
||||
} else if (data < 80) {
|
||||
*oid_ptr = 1;
|
||||
oid_ptr++;
|
||||
*oid_ptr = data - 40;
|
||||
oid_ptr++;
|
||||
} else {
|
||||
*oid_ptr = 2;
|
||||
oid_ptr++;
|
||||
*oid_ptr = data - 80;
|
||||
oid_ptr++;
|
||||
}
|
||||
*oid_len = 2;
|
||||
} else {
|
||||
/* accepting zero length identifiers e.g. for getnext operation. uncommon but valid */
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
while ((len > 0) && (*oid_len < oid_max_len)) {
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
|
||||
len--;
|
||||
|
||||
if ((data & 0x80) == 0x00) {
|
||||
/* sub-identifier uses single octet */
|
||||
*oid_ptr = data;
|
||||
} else {
|
||||
/* sub-identifier uses multiple octets */
|
||||
u32_t sub_id = (data & ~0x80);
|
||||
while ((len > 0) && ((data & 0x80) != 0)) {
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
|
||||
len--;
|
||||
|
||||
sub_id = (sub_id << 7) + (data & ~0x80);
|
||||
}
|
||||
|
||||
if ((data & 0x80) != 0) {
|
||||
/* "more bytes following" bit still set at end of len */
|
||||
return ERR_VAL;
|
||||
}
|
||||
*oid_ptr = sub_id;
|
||||
}
|
||||
oid_ptr++;
|
||||
(*oid_len)++;
|
||||
}
|
||||
|
||||
if (len > 0) {
|
||||
/* OID to long to fit in our buffer */
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes (copies) raw data (ip-addresses, octet strings, opaque encoding)
|
||||
* from incoming message into array.
|
||||
*
|
||||
* @param pbuf_stream points to a pbuf stream
|
||||
* @param len length of the coded raw data (zero is valid, e.g. empty string!)
|
||||
* @param buf return raw bytes
|
||||
* @param buf_len returns length of the raw return value
|
||||
* @param buf_max_len buffer size
|
||||
* @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)
|
||||
{
|
||||
if (len > buf_max_len) {
|
||||
/* not enough dst space */
|
||||
return ERR_MEM;
|
||||
}
|
||||
*buf_len = len;
|
||||
|
||||
while (len > 0) {
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, buf));
|
||||
buf++;
|
||||
len--;
|
||||
}
|
||||
|
||||
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 */
|
||||
113
src/apps/snmp/snmp_asn1.h
Normal file
113
src/apps/snmp/snmp_asn1.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* @file
|
||||
* Abstract Syntax Notation One (ISO 8824, 8825) codec.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
|
||||
* 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: Christiaan Simons <christiaan.simons@axon.tv>
|
||||
* Martin Hentschel <info@cl-soft.de>
|
||||
* Elias Oenal <lwip@eliasoenal.com>
|
||||
*/
|
||||
|
||||
#ifndef LWIP_HDR_APPS_SNMP_ASN1_H
|
||||
#define LWIP_HDR_APPS_SNMP_ASN1_H
|
||||
|
||||
#include "lwip/apps/snmp_opts.h"
|
||||
|
||||
#if LWIP_SNMP
|
||||
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/apps/snmp_core.h"
|
||||
#include "snmp_pbuf_stream.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SNMP_ASN1_TLV_INDEFINITE_LENGTH 0x80
|
||||
|
||||
#define SNMP_ASN1_CLASS_MASK 0xC0
|
||||
#define SNMP_ASN1_CONTENTTYPE_MASK 0x20
|
||||
#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 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 {
|
||||
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 */
|
||||
u16_t value_len; /* encoded length of the value */
|
||||
};
|
||||
#define SNMP_ASN1_TLV_HDR_LENGTH(tlv) ((tlv).type_len + (tlv).length_len)
|
||||
#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_u32t(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_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_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_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
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LWIP_SNMP */
|
||||
|
||||
#endif /* LWIP_HDR_APPS_SNMP_ASN1_H */
|
||||
1353
src/apps/snmp/snmp_core.c
Normal file
1353
src/apps/snmp/snmp_core.c
Normal file
File diff suppressed because it is too large
Load Diff
83
src/apps/snmp/snmp_core_priv.h
Normal file
83
src/apps/snmp/snmp_core_priv.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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: Martin Hentschel <info@cl-soft.de>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LWIP_HDR_APPS_SNMP_CORE_PRIV_H
|
||||
#define LWIP_HDR_APPS_SNMP_CORE_PRIV_H
|
||||
|
||||
#include "lwip/apps/snmp_opts.h"
|
||||
|
||||
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/apps/snmp_core.h"
|
||||
#include "snmp_asn1.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* (outdated) SNMPv1 error codes
|
||||
* shall not be used by MIBS anymore, nevertheless required from core for properly answering a v1 request
|
||||
*/
|
||||
#define SNMP_ERR_NOSUCHNAME 2
|
||||
#define SNMP_ERR_BADVALUE 3
|
||||
#define SNMP_ERR_READONLY 4
|
||||
/* error codes which are internal and shall not be used by MIBS
|
||||
* shall not be used by MIBS anymore, nevertheless required from core for properly answering a v1 request
|
||||
*/
|
||||
#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);
|
||||
|
||||
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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LWIP_SNMP */
|
||||
|
||||
#endif /* LWIP_HDR_APPS_SNMP_CORE_PRIV_H */
|
||||
116
src/apps/snmp/snmp_mib2.c
Normal file
116
src/apps/snmp/snmp_mib2.c
Normal file
@@ -0,0 +1,116 @@
|
||||
/**
|
||||
* @file
|
||||
* Management Information Base II (RFC1213) objects and functions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
|
||||
* 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: Dirk Ziegelmeier <dziegel@gmx.de>
|
||||
* Christiaan Simons <christiaan.simons@axon.tv>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup snmp_mib2 MIB2
|
||||
* @ingroup snmp
|
||||
*/
|
||||
|
||||
#include "lwip/apps/snmp_opts.h"
|
||||
|
||||
#if LWIP_SNMP && SNMP_LWIP_MIB2 /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#if !LWIP_STATS
|
||||
#error LWIP_SNMP MIB2 needs LWIP_STATS (for MIB2)
|
||||
#endif
|
||||
#if !MIB2_STATS
|
||||
#error LWIP_SNMP MIB2 needs MIB2_STATS (for MIB2)
|
||||
#endif
|
||||
|
||||
#include "lwip/snmp.h"
|
||||
#include "lwip/apps/snmp.h"
|
||||
#include "lwip/apps/snmp_core.h"
|
||||
#include "lwip/apps/snmp_mib2.h"
|
||||
#include "lwip/apps/snmp_scalar.h"
|
||||
|
||||
#if SNMP_USE_NETCONN
|
||||
#include "lwip/tcpip.h"
|
||||
#include "lwip/priv/tcpip_priv.h"
|
||||
void
|
||||
snmp_mib2_lwip_synchronizer(snmp_threadsync_called_fn fn, void *arg)
|
||||
{
|
||||
#if LWIP_TCPIP_CORE_LOCKING
|
||||
LOCK_TCPIP_CORE();
|
||||
fn(arg);
|
||||
UNLOCK_TCPIP_CORE();
|
||||
#else
|
||||
tcpip_callback(fn, arg);
|
||||
#endif
|
||||
}
|
||||
|
||||
struct snmp_threadsync_instance snmp_mib2_lwip_locks;
|
||||
#endif
|
||||
|
||||
/* dot3 and EtherLike MIB not planned. (transmission .1.3.6.1.2.1.10) */
|
||||
/* historical (some say hysterical). (cmot .1.3.6.1.2.1.9) */
|
||||
/* lwIP has no EGP, thus may not implement it. (egp .1.3.6.1.2.1.8) */
|
||||
|
||||
/* --- mib-2 .1.3.6.1.2.1 ----------------------------------------------------- */
|
||||
extern const struct snmp_scalar_array_node snmp_mib2_snmp_root;
|
||||
extern const struct snmp_tree_node snmp_mib2_udp_root;
|
||||
extern const struct snmp_tree_node snmp_mib2_tcp_root;
|
||||
extern const struct snmp_scalar_array_node snmp_mib2_icmp_root;
|
||||
extern const struct snmp_tree_node snmp_mib2_interface_root;
|
||||
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[] = {
|
||||
&snmp_mib2_system_node.node.node,
|
||||
&snmp_mib2_interface_root.node,
|
||||
#if LWIP_ARP && LWIP_IPV4
|
||||
&snmp_mib2_at_root.node,
|
||||
#endif /* LWIP_ARP && LWIP_IPV4 */
|
||||
#if LWIP_IPV4
|
||||
&snmp_mib2_ip_root.node,
|
||||
#endif /* LWIP_IPV4 */
|
||||
#if LWIP_ICMP
|
||||
&snmp_mib2_icmp_root.node.node,
|
||||
#endif /* LWIP_ICMP */
|
||||
#if LWIP_TCP
|
||||
&snmp_mib2_tcp_root.node,
|
||||
#endif /* LWIP_TCP */
|
||||
#if LWIP_UDP
|
||||
&snmp_mib2_udp_root.node,
|
||||
#endif /* LWIP_UDP */
|
||||
&snmp_mib2_snmp_root.node.node
|
||||
};
|
||||
|
||||
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 };
|
||||
const struct snmp_mib mib2 = SNMP_MIB_CREATE(mib2_base_oid_arr, &mib2_root.node);
|
||||
|
||||
#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 */
|
||||
182
src/apps/snmp/snmp_mib2_icmp.c
Normal file
182
src/apps/snmp/snmp_mib2_icmp.c
Normal file
@@ -0,0 +1,182 @@
|
||||
/**
|
||||
* @file
|
||||
* Management Information Base II (RFC1213) ICMP objects and functions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
|
||||
* 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: Dirk Ziegelmeier <dziegel@gmx.de>
|
||||
* Christiaan Simons <christiaan.simons@axon.tv>
|
||||
*/
|
||||
|
||||
#include "lwip/snmp.h"
|
||||
#include "lwip/apps/snmp.h"
|
||||
#include "lwip/apps/snmp_core.h"
|
||||
#include "lwip/apps/snmp_mib2.h"
|
||||
#include "lwip/apps/snmp_table.h"
|
||||
#include "lwip/apps/snmp_scalar.h"
|
||||
#include "lwip/icmp.h"
|
||||
#include "lwip/stats.h"
|
||||
|
||||
#if LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_ICMP
|
||||
|
||||
#if SNMP_USE_NETCONN
|
||||
#define SYNC_NODE_NAME(node_name) node_name ## _synced
|
||||
#define CREATE_LWIP_SYNC_NODE(oid, node_name) \
|
||||
static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks);
|
||||
#else
|
||||
#define SYNC_NODE_NAME(node_name) node_name
|
||||
#define CREATE_LWIP_SYNC_NODE(oid, node_name)
|
||||
#endif
|
||||
|
||||
/* --- icmp .1.3.6.1.2.1.5 ----------------------------------------------------- */
|
||||
|
||||
static s16_t
|
||||
icmp_get_value(const struct snmp_scalar_array_node_def *node, void *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;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const struct snmp_scalar_array_node_def icmp_nodes[] = {
|
||||
{ 1, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
|
||||
{ 2, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
|
||||
{ 3, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
|
||||
{ 4, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
|
||||
{ 5, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
|
||||
{ 6, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
|
||||
{ 7, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
|
||||
{ 8, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
|
||||
{ 9, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
|
||||
{10, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
|
||||
{11, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
|
||||
{12, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
|
||||
{13, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
|
||||
{14, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
|
||||
{15, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
|
||||
{16, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
|
||||
{17, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
|
||||
{18, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
|
||||
{19, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
|
||||
{20, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
|
||||
{21, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
|
||||
{22, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
|
||||
{23, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
|
||||
{24, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
|
||||
{25, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
|
||||
{26, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}
|
||||
};
|
||||
|
||||
const struct snmp_scalar_array_node snmp_mib2_icmp_root = SNMP_SCALAR_CREATE_ARRAY_NODE(5, icmp_nodes, icmp_get_value, NULL, NULL);
|
||||
|
||||
#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_ICMP */
|
||||
368
src/apps/snmp/snmp_mib2_interfaces.c
Normal file
368
src/apps/snmp/snmp_mib2_interfaces.c
Normal file
@@ -0,0 +1,368 @@
|
||||
/**
|
||||
* @file
|
||||
* Management Information Base II (RFC1213) INTERFACES objects and functions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
|
||||
* 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: Dirk Ziegelmeier <dziegel@gmx.de>
|
||||
* Christiaan Simons <christiaan.simons@axon.tv>
|
||||
*/
|
||||
|
||||
#include "lwip/snmp.h"
|
||||
#include "lwip/apps/snmp.h"
|
||||
#include "lwip/apps/snmp_core.h"
|
||||
#include "lwip/apps/snmp_mib2.h"
|
||||
#include "lwip/apps/snmp_table.h"
|
||||
#include "lwip/apps/snmp_scalar.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/stats.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if LWIP_SNMP && SNMP_LWIP_MIB2
|
||||
|
||||
#if SNMP_USE_NETCONN
|
||||
#define SYNC_NODE_NAME(node_name) node_name ## _synced
|
||||
#define CREATE_LWIP_SYNC_NODE(oid, node_name) \
|
||||
static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks);
|
||||
#else
|
||||
#define SYNC_NODE_NAME(node_name) node_name
|
||||
#define CREATE_LWIP_SYNC_NODE(oid, node_name)
|
||||
#endif
|
||||
|
||||
|
||||
/* --- interfaces .1.3.6.1.2.1.2 ----------------------------------------------------- */
|
||||
|
||||
static s16_t
|
||||
interfaces_get_value(struct snmp_node_instance *instance, void *value)
|
||||
{
|
||||
if (instance->node->oid == 1) {
|
||||
s32_t *sint_ptr = (s32_t *)value;
|
||||
s32_t num_netifs = 0;
|
||||
|
||||
struct netif *netif;
|
||||
NETIF_FOREACH(netif) {
|
||||
num_netifs++;
|
||||
}
|
||||
|
||||
*sint_ptr = num_netifs;
|
||||
return sizeof(*sint_ptr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* list of allowed value ranges for incoming OID */
|
||||
static const struct snmp_oid_range interfaces_Table_oid_ranges[] = {
|
||||
{ 1, 0xff } /* netif->num is u8_t */
|
||||
};
|
||||
|
||||
static const u8_t iftable_ifOutQLen = 0;
|
||||
|
||||
static const u8_t iftable_ifOperStatus_up = 1;
|
||||
static const u8_t iftable_ifOperStatus_down = 2;
|
||||
|
||||
static const u8_t iftable_ifAdminStatus_up = 1;
|
||||
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)
|
||||
{
|
||||
u32_t ifIndex;
|
||||
struct netif *netif;
|
||||
|
||||
LWIP_UNUSED_ARG(column);
|
||||
|
||||
/* check if incoming OID length and if values are in plausible range */
|
||||
if (!snmp_oid_in_range(row_oid, row_oid_len, interfaces_Table_oid_ranges, LWIP_ARRAYSIZE(interfaces_Table_oid_ranges))) {
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
/* get netif index from incoming OID */
|
||||
ifIndex = row_oid[0];
|
||||
|
||||
/* find netif with index */
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* not found */
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct netif *netif;
|
||||
struct snmp_next_oid_state state;
|
||||
u32_t result_temp[LWIP_ARRAYSIZE(interfaces_Table_oid_ranges)];
|
||||
|
||||
LWIP_UNUSED_ARG(column);
|
||||
|
||||
/* init struct to search next oid */
|
||||
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_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);
|
||||
}
|
||||
|
||||
/* 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 netif pointer for subsequent operations (get/test/set) */
|
||||
cell_instance->reference.ptr = /* (struct netif*) */state.reference;
|
||||
return SNMP_ERR_NOERROR;
|
||||
}
|
||||
|
||||
/* not found */
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
static s16_t
|
||||
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;
|
||||
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;
|
||||
} 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;
|
||||
}
|
||||
|
||||
#if !SNMP_SAFE_REQUESTS
|
||||
|
||||
static snmp_err_t
|
||||
interfaces_Table_set_test(struct snmp_node_instance *instance, u16_t len, void *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 */
|
||||
LWIP_ASSERT("Invalid column", (SNMP_TABLE_GET_COLUMN_FROM_OID(instance->instance_oid.id) == 7));
|
||||
LWIP_UNUSED_ARG(len);
|
||||
|
||||
if (*sint_ptr == 1 || *sint_ptr == 2) {
|
||||
return SNMP_ERR_NOERROR;
|
||||
}
|
||||
|
||||
return SNMP_ERR_WRONGVALUE;
|
||||
}
|
||||
|
||||
static snmp_err_t
|
||||
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;
|
||||
|
||||
/* stack should never call this method for another column,
|
||||
because all other columns are set to readonly */
|
||||
LWIP_ASSERT("Invalid column", (SNMP_TABLE_GET_COLUMN_FROM_OID(instance->instance_oid.id) == 7));
|
||||
LWIP_UNUSED_ARG(len);
|
||||
|
||||
if (*sint_ptr == 1) {
|
||||
netif_set_up(netif);
|
||||
} else if (*sint_ptr == 2) {
|
||||
netif_set_down(netif);
|
||||
}
|
||||
|
||||
return SNMP_ERR_NOERROR;
|
||||
}
|
||||
|
||||
#endif /* SNMP_SAFE_REQUESTS */
|
||||
|
||||
static const struct snmp_scalar_node interfaces_Number = SNMP_SCALAR_CREATE_NODE_READONLY(1, SNMP_ASN1_TYPE_INTEGER, interfaces_get_value);
|
||||
|
||||
static const struct snmp_table_col_def interfaces_Table_columns[] = {
|
||||
{ 1, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifIndex */
|
||||
{ 2, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifDescr */
|
||||
{ 3, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifType */
|
||||
{ 4, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifMtu */
|
||||
{ 5, SNMP_ASN1_TYPE_GAUGE, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifSpeed */
|
||||
{ 6, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifPhysAddress */
|
||||
#if !SNMP_SAFE_REQUESTS
|
||||
{ 7, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_WRITE }, /* ifAdminStatus */
|
||||
#else
|
||||
{ 7, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifAdminStatus */
|
||||
#endif
|
||||
{ 8, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOperStatus */
|
||||
{ 9, SNMP_ASN1_TYPE_TIMETICKS, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifLastChange */
|
||||
{ 10, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInOctets */
|
||||
{ 11, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInUcastPkts */
|
||||
{ 12, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInNUcastPkts */
|
||||
{ 13, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInDiscarts */
|
||||
{ 14, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInErrors */
|
||||
{ 15, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInUnkownProtos */
|
||||
{ 16, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutOctets */
|
||||
{ 17, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutUcastPkts */
|
||||
{ 18, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutNUcastPkts */
|
||||
{ 19, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutDiscarts */
|
||||
{ 20, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutErrors */
|
||||
{ 21, SNMP_ASN1_TYPE_GAUGE, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutQLen */
|
||||
{ 22, SNMP_ASN1_TYPE_OBJECT_ID, SNMP_NODE_INSTANCE_READ_ONLY } /* ifSpecific */
|
||||
};
|
||||
|
||||
#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);
|
||||
#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);
|
||||
#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[] = {
|
||||
&SYNC_NODE_NAME(interfaces_Number).node.node,
|
||||
&SYNC_NODE_NAME(interfaces_Table).node.node
|
||||
};
|
||||
|
||||
const struct snmp_tree_node snmp_mib2_interface_root = SNMP_CREATE_TREE_NODE(2, interface_nodes);
|
||||
|
||||
#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 */
|
||||
731
src/apps/snmp/snmp_mib2_ip.c
Normal file
731
src/apps/snmp/snmp_mib2_ip.c
Normal file
@@ -0,0 +1,731 @@
|
||||
/**
|
||||
* @file
|
||||
* Management Information Base II (RFC1213) IP objects and functions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
|
||||
* 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: Dirk Ziegelmeier <dziegel@gmx.de>
|
||||
* Christiaan Simons <christiaan.simons@axon.tv>
|
||||
*/
|
||||
|
||||
#include "lwip/snmp.h"
|
||||
#include "lwip/apps/snmp.h"
|
||||
#include "lwip/apps/snmp_core.h"
|
||||
#include "lwip/apps/snmp_mib2.h"
|
||||
#include "lwip/apps/snmp_table.h"
|
||||
#include "lwip/apps/snmp_scalar.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/etharp.h"
|
||||
|
||||
#if LWIP_SNMP && SNMP_LWIP_MIB2
|
||||
|
||||
#if SNMP_USE_NETCONN
|
||||
#define SYNC_NODE_NAME(node_name) node_name ## _synced
|
||||
#define CREATE_LWIP_SYNC_NODE(oid, node_name) \
|
||||
static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks);
|
||||
#else
|
||||
#define SYNC_NODE_NAME(node_name) node_name
|
||||
#define CREATE_LWIP_SYNC_NODE(oid, node_name)
|
||||
#endif
|
||||
|
||||
#if LWIP_IPV4
|
||||
/* --- ip .1.3.6.1.2.1.4 ----------------------------------------------------- */
|
||||
|
||||
static s16_t
|
||||
ip_get_value(struct snmp_node_instance *instance, void *value)
|
||||
{
|
||||
s32_t *sint_ptr = (s32_t *)value;
|
||||
u32_t *uint_ptr = (u32_t *)value;
|
||||
|
||||
switch (instance->node->oid) {
|
||||
case 1: /* ipForwarding */
|
||||
#if IP_FORWARD
|
||||
/* forwarding */
|
||||
*sint_ptr = 1;
|
||||
#else
|
||||
/* 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 */
|
||||
#if IP_REASSEMBLY
|
||||
*sint_ptr = IP_REASS_MAXAGE;
|
||||
#else
|
||||
*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 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test ip object value before setting.
|
||||
*
|
||||
* @param instance node instance
|
||||
* @param len return value space (in bytes)
|
||||
* @param value points to (varbind) space to copy value from.
|
||||
*
|
||||
* @note we allow set if the value matches the hardwired value,
|
||||
* otherwise return badvalue.
|
||||
*/
|
||||
static snmp_err_t
|
||||
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;
|
||||
|
||||
LWIP_UNUSED_ARG(len);
|
||||
switch (instance->node->oid) {
|
||||
case 1: /* ipForwarding */
|
||||
#if IP_FORWARD
|
||||
/* forwarding */
|
||||
if (*sint_ptr == 1)
|
||||
#else
|
||||
/* 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;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static snmp_err_t
|
||||
ip_set_value(struct snmp_node_instance *instance, u16_t len, void *value)
|
||||
{
|
||||
LWIP_UNUSED_ARG(instance);
|
||||
LWIP_UNUSED_ARG(len);
|
||||
LWIP_UNUSED_ARG(value);
|
||||
/* nothing to do here because in set_test we only accept values being the same as our own stored value -> no need to store anything */
|
||||
return SNMP_ERR_NOERROR;
|
||||
}
|
||||
|
||||
/* --- ipAddrTable --- */
|
||||
|
||||
/* list of allowed value ranges for incoming OID */
|
||||
static const struct snmp_oid_range ip_AddrTable_oid_ranges[] = {
|
||||
{ 0, 0xff }, /* IP A */
|
||||
{ 0, 0xff }, /* IP B */
|
||||
{ 0, 0xff }, /* IP C */
|
||||
{ 0, 0xff } /* IP D */
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
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 */
|
||||
#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)));
|
||||
#else
|
||||
/** @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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
ip4_addr_t ip;
|
||||
struct netif *netif;
|
||||
|
||||
/* check if incoming OID length and if values are in plausible range */
|
||||
if (!snmp_oid_in_range(row_oid, row_oid_len, ip_AddrTable_oid_ranges, LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges))) {
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
/* get IP from incoming OID */
|
||||
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_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);
|
||||
}
|
||||
}
|
||||
|
||||
/* not found */
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct netif *netif;
|
||||
struct snmp_next_oid_state state;
|
||||
u32_t result_temp[LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges)];
|
||||
|
||||
/* init struct to search next oid */
|
||||
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_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);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* not found */
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
/* --- ipRouteTable --- */
|
||||
|
||||
/* list of allowed value ranges for incoming OID */
|
||||
static const struct snmp_oid_range ip_RouteTable_oid_ranges[] = {
|
||||
{ 0, 0xff }, /* IP A */
|
||||
{ 0, 0xff }, /* IP B */
|
||||
{ 0, 0xff }, /* IP C */
|
||||
{ 0, 0xff }, /* IP D */
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
ip4_addr_t test_ip;
|
||||
struct netif *netif;
|
||||
|
||||
/* check if incoming OID length and if values are in plausible range */
|
||||
if (!snmp_oid_in_range(row_oid, row_oid_len, ip_RouteTable_oid_ranges, LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges))) {
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
/* get IP and port from incoming OID */
|
||||
snmp_oid_to_ip4(&row_oid[0], &test_ip); /* we know it succeeds because of oid_in_range check above */
|
||||
|
||||
/* default route is on default netif */
|
||||
if (ip4_addr_isany_val(test_ip) && (netif_default != NULL)) {
|
||||
/* fill in object properties */
|
||||
return ip_RouteTable_get_cell_value_core(netif_default, 1, column, value, value_len);
|
||||
}
|
||||
|
||||
/* find netif with requested route */
|
||||
NETIF_FOREACH(netif) {
|
||||
ip4_addr_t dst;
|
||||
ip4_addr_get_network(&dst, netif_ip4_addr(netif), netif_ip4_netmask(netif));
|
||||
|
||||
if (ip4_addr_cmp(&dst, &test_ip)) {
|
||||
/* fill in object properties */
|
||||
return ip_RouteTable_get_cell_value_core(netif, 0, column, value, value_len);
|
||||
}
|
||||
}
|
||||
|
||||
/* not found */
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct netif *netif;
|
||||
struct snmp_next_oid_state state;
|
||||
u32_t result_temp[LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges)];
|
||||
u32_t test_oid[LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges)];
|
||||
|
||||
/* init struct to search next oid */
|
||||
snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges));
|
||||
|
||||
/* check default route */
|
||||
if (netif_default != NULL) {
|
||||
snmp_ip4_to_oid(IP4_ADDR_ANY4, &test_oid[0]);
|
||||
snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges), netif_default);
|
||||
}
|
||||
|
||||
/* iterate over all possible OIDs to find the next one */
|
||||
NETIF_FOREACH(netif) {
|
||||
ip4_addr_t dst;
|
||||
ip4_addr_get_network(&dst, netif_ip4_addr(netif), netif_ip4_netmask(netif));
|
||||
|
||||
/* check generated OID: is it a candidate for the next one? */
|
||||
if (!ip4_addr_isany_val(dst)) {
|
||||
snmp_ip4_to_oid(&dst, &test_oid[0]);
|
||||
snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges), netif);
|
||||
}
|
||||
}
|
||||
|
||||
/* did we find a next one? */
|
||||
if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
|
||||
ip4_addr_t dst;
|
||||
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);
|
||||
} else {
|
||||
/* not found */
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
#if LWIP_ARP && LWIP_IPV4
|
||||
/* --- ipNetToMediaTable --- */
|
||||
|
||||
/* list of allowed value ranges for incoming OID */
|
||||
static const struct snmp_oid_range ip_NetToMediaTable_oid_ranges[] = {
|
||||
{ 1, 0xff }, /* IfIndex */
|
||||
{ 0, 0xff }, /* IP A */
|
||||
{ 0, 0xff }, /* IP B */
|
||||
{ 0, 0xff }, /* IP C */
|
||||
{ 0, 0xff } /* IP D */
|
||||
};
|
||||
|
||||
static snmp_err_t
|
||||
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;
|
||||
struct eth_addr *ethaddr;
|
||||
|
||||
etharp_get_entry(arp_table_index, &ip, &netif, ðaddr);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
ip4_addr_t ip_in;
|
||||
u8_t netif_index;
|
||||
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))) {
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
/* get IP from incoming OID */
|
||||
netif_index = (u8_t)row_oid[0];
|
||||
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++) {
|
||||
ip4_addr_t *ip;
|
||||
struct netif *netif;
|
||||
struct eth_addr *ethaddr;
|
||||
|
||||
if (etharp_get_entry(i, &ip, &netif, ðaddr)) {
|
||||
if ((netif_index == netif_to_num(netif)) && ip4_addr_cmp(&ip_in, ip)) {
|
||||
/* fill in object properties */
|
||||
return ip_NetToMediaTable_get_cell_value_core(i, column, value, value_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* not found */
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
size_t i;
|
||||
struct snmp_next_oid_state state;
|
||||
u32_t result_temp[LWIP_ARRAYSIZE(ip_NetToMediaTable_oid_ranges)];
|
||||
|
||||
/* init struct to search next oid */
|
||||
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++) {
|
||||
ip4_addr_t *ip;
|
||||
struct netif *netif;
|
||||
struct eth_addr *ethaddr;
|
||||
|
||||
if (etharp_get_entry(i, &ip, &netif, ðaddr)) {
|
||||
u32_t test_oid[LWIP_ARRAYSIZE(ip_NetToMediaTable_oid_ranges)];
|
||||
|
||||
test_oid[0] = netif_to_num(netif);
|
||||
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), 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);
|
||||
/* fill in object properties */
|
||||
return ip_NetToMediaTable_get_cell_value_core(LWIP_PTR_NUMERIC_CAST(size_t, state.reference), column, value, value_len);
|
||||
}
|
||||
|
||||
/* not found */
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
#endif /* LWIP_ARP && LWIP_IPV4 */
|
||||
|
||||
static const struct snmp_scalar_node ip_Forwarding = SNMP_SCALAR_CREATE_NODE(1, SNMP_NODE_INSTANCE_READ_WRITE, SNMP_ASN1_TYPE_INTEGER, ip_get_value, ip_set_test, ip_set_value);
|
||||
static const struct snmp_scalar_node ip_DefaultTTL = SNMP_SCALAR_CREATE_NODE(2, SNMP_NODE_INSTANCE_READ_WRITE, SNMP_ASN1_TYPE_INTEGER, ip_get_value, ip_set_test, ip_set_value);
|
||||
static const struct snmp_scalar_node ip_InReceives = SNMP_SCALAR_CREATE_NODE_READONLY(3, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
|
||||
static const struct snmp_scalar_node ip_InHdrErrors = SNMP_SCALAR_CREATE_NODE_READONLY(4, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
|
||||
static const struct snmp_scalar_node ip_InAddrErrors = SNMP_SCALAR_CREATE_NODE_READONLY(5, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
|
||||
static const struct snmp_scalar_node ip_ForwDatagrams = SNMP_SCALAR_CREATE_NODE_READONLY(6, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
|
||||
static const struct snmp_scalar_node ip_InUnknownProtos = SNMP_SCALAR_CREATE_NODE_READONLY(7, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
|
||||
static const struct snmp_scalar_node ip_InDiscards = SNMP_SCALAR_CREATE_NODE_READONLY(8, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
|
||||
static const struct snmp_scalar_node ip_InDelivers = SNMP_SCALAR_CREATE_NODE_READONLY(9, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
|
||||
static const struct snmp_scalar_node ip_OutRequests = SNMP_SCALAR_CREATE_NODE_READONLY(10, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
|
||||
static const struct snmp_scalar_node ip_OutDiscards = SNMP_SCALAR_CREATE_NODE_READONLY(11, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
|
||||
static const struct snmp_scalar_node ip_OutNoRoutes = SNMP_SCALAR_CREATE_NODE_READONLY(12, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
|
||||
static const struct snmp_scalar_node ip_ReasmTimeout = SNMP_SCALAR_CREATE_NODE_READONLY(13, SNMP_ASN1_TYPE_INTEGER, ip_get_value);
|
||||
static const struct snmp_scalar_node ip_ReasmReqds = SNMP_SCALAR_CREATE_NODE_READONLY(14, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
|
||||
static const struct snmp_scalar_node ip_ReasmOKs = SNMP_SCALAR_CREATE_NODE_READONLY(15, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
|
||||
static const struct snmp_scalar_node ip_ReasmFails = SNMP_SCALAR_CREATE_NODE_READONLY(16, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
|
||||
static const struct snmp_scalar_node ip_FragOKs = SNMP_SCALAR_CREATE_NODE_READONLY(17, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
|
||||
static const struct snmp_scalar_node ip_FragFails = SNMP_SCALAR_CREATE_NODE_READONLY(18, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
|
||||
static const struct snmp_scalar_node ip_FragCreates = SNMP_SCALAR_CREATE_NODE_READONLY(19, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
|
||||
static const struct snmp_scalar_node ip_RoutingDiscards = SNMP_SCALAR_CREATE_NODE_READONLY(23, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
|
||||
|
||||
static const struct snmp_table_simple_col_def ip_AddrTable_columns[] = {
|
||||
{ 1, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipAdEntAddr */
|
||||
{ 2, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipAdEntIfIndex */
|
||||
{ 3, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipAdEntNetMask */
|
||||
{ 4, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipAdEntBcastAddr */
|
||||
{ 5, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 } /* ipAdEntReasmMaxSize */
|
||||
};
|
||||
|
||||
static const struct snmp_table_simple_node ip_AddrTable = SNMP_TABLE_CREATE_SIMPLE(20, ip_AddrTable_columns, ip_AddrTable_get_cell_value, ip_AddrTable_get_next_cell_instance_and_value);
|
||||
|
||||
static const struct snmp_table_simple_col_def ip_RouteTable_columns[] = {
|
||||
{ 1, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipRouteDest */
|
||||
{ 2, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipRouteIfIndex */
|
||||
{ 3, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_S32 }, /* ipRouteMetric1 */
|
||||
{ 4, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_S32 }, /* ipRouteMetric2 */
|
||||
{ 5, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_S32 }, /* ipRouteMetric3 */
|
||||
{ 6, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_S32 }, /* ipRouteMetric4 */
|
||||
{ 7, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipRouteNextHop */
|
||||
{ 8, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipRouteType */
|
||||
{ 9, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipRouteProto */
|
||||
{ 10, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipRouteAge */
|
||||
{ 11, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipRouteMask */
|
||||
{ 12, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_S32 }, /* ipRouteMetric5 */
|
||||
{ 13, SNMP_ASN1_TYPE_OBJECT_ID, SNMP_VARIANT_VALUE_TYPE_PTR } /* ipRouteInfo */
|
||||
};
|
||||
|
||||
static const struct snmp_table_simple_node ip_RouteTable = SNMP_TABLE_CREATE_SIMPLE(21, ip_RouteTable_columns, ip_RouteTable_get_cell_value, ip_RouteTable_get_next_cell_instance_and_value);
|
||||
#endif /* LWIP_IPV4 */
|
||||
|
||||
#if LWIP_ARP && LWIP_IPV4
|
||||
static const struct snmp_table_simple_col_def ip_NetToMediaTable_columns[] = {
|
||||
{ 1, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipNetToMediaIfIndex */
|
||||
{ 2, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_VARIANT_VALUE_TYPE_PTR }, /* ipNetToMediaPhysAddress */
|
||||
{ 3, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipNetToMediaNetAddress */
|
||||
{ 4, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 } /* ipNetToMediaType */
|
||||
};
|
||||
|
||||
static const struct snmp_table_simple_node ip_NetToMediaTable = SNMP_TABLE_CREATE_SIMPLE(22, ip_NetToMediaTable_columns, ip_NetToMediaTable_get_cell_value, ip_NetToMediaTable_get_next_cell_instance_and_value);
|
||||
#endif /* LWIP_ARP && LWIP_IPV4 */
|
||||
|
||||
#if LWIP_IPV4
|
||||
/* 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, ip_Forwarding)
|
||||
CREATE_LWIP_SYNC_NODE( 2, ip_DefaultTTL)
|
||||
CREATE_LWIP_SYNC_NODE( 3, ip_InReceives)
|
||||
CREATE_LWIP_SYNC_NODE( 4, ip_InHdrErrors)
|
||||
CREATE_LWIP_SYNC_NODE( 5, ip_InAddrErrors)
|
||||
CREATE_LWIP_SYNC_NODE( 6, ip_ForwDatagrams)
|
||||
CREATE_LWIP_SYNC_NODE( 7, ip_InUnknownProtos)
|
||||
CREATE_LWIP_SYNC_NODE( 8, ip_InDiscards)
|
||||
CREATE_LWIP_SYNC_NODE( 9, ip_InDelivers)
|
||||
CREATE_LWIP_SYNC_NODE(10, ip_OutRequests)
|
||||
CREATE_LWIP_SYNC_NODE(11, ip_OutDiscards)
|
||||
CREATE_LWIP_SYNC_NODE(12, ip_OutNoRoutes)
|
||||
CREATE_LWIP_SYNC_NODE(13, ip_ReasmTimeout)
|
||||
CREATE_LWIP_SYNC_NODE(14, ip_ReasmReqds)
|
||||
CREATE_LWIP_SYNC_NODE(15, ip_ReasmOKs)
|
||||
CREATE_LWIP_SYNC_NODE(15, ip_ReasmFails)
|
||||
CREATE_LWIP_SYNC_NODE(17, ip_FragOKs)
|
||||
CREATE_LWIP_SYNC_NODE(18, ip_FragFails)
|
||||
CREATE_LWIP_SYNC_NODE(19, ip_FragCreates)
|
||||
CREATE_LWIP_SYNC_NODE(20, ip_AddrTable)
|
||||
CREATE_LWIP_SYNC_NODE(21, ip_RouteTable)
|
||||
#if LWIP_ARP
|
||||
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[] = {
|
||||
&SYNC_NODE_NAME(ip_Forwarding).node.node,
|
||||
&SYNC_NODE_NAME(ip_DefaultTTL).node.node,
|
||||
&SYNC_NODE_NAME(ip_InReceives).node.node,
|
||||
&SYNC_NODE_NAME(ip_InHdrErrors).node.node,
|
||||
&SYNC_NODE_NAME(ip_InAddrErrors).node.node,
|
||||
&SYNC_NODE_NAME(ip_ForwDatagrams).node.node,
|
||||
&SYNC_NODE_NAME(ip_InUnknownProtos).node.node,
|
||||
&SYNC_NODE_NAME(ip_InDiscards).node.node,
|
||||
&SYNC_NODE_NAME(ip_InDelivers).node.node,
|
||||
&SYNC_NODE_NAME(ip_OutRequests).node.node,
|
||||
&SYNC_NODE_NAME(ip_OutDiscards).node.node,
|
||||
&SYNC_NODE_NAME(ip_OutNoRoutes).node.node,
|
||||
&SYNC_NODE_NAME(ip_ReasmTimeout).node.node,
|
||||
&SYNC_NODE_NAME(ip_ReasmReqds).node.node,
|
||||
&SYNC_NODE_NAME(ip_ReasmOKs).node.node,
|
||||
&SYNC_NODE_NAME(ip_ReasmFails).node.node,
|
||||
&SYNC_NODE_NAME(ip_FragOKs).node.node,
|
||||
&SYNC_NODE_NAME(ip_FragFails).node.node,
|
||||
&SYNC_NODE_NAME(ip_FragCreates).node.node,
|
||||
&SYNC_NODE_NAME(ip_AddrTable).node.node,
|
||||
&SYNC_NODE_NAME(ip_RouteTable).node.node,
|
||||
#if LWIP_ARP
|
||||
&SYNC_NODE_NAME(ip_NetToMediaTable).node.node,
|
||||
#endif /* LWIP_ARP */
|
||||
&SYNC_NODE_NAME(ip_RoutingDiscards).node.node
|
||||
};
|
||||
|
||||
const struct snmp_tree_node snmp_mib2_ip_root = SNMP_CREATE_TREE_NODE(4, ip_nodes);
|
||||
#endif /* LWIP_IPV4 */
|
||||
|
||||
/* --- at .1.3.6.1.2.1.3 ----------------------------------------------------- */
|
||||
|
||||
#if LWIP_ARP && LWIP_IPV4
|
||||
/* at node table is a subset of ip_nettomedia table (same rows but less columns) */
|
||||
static const struct snmp_table_simple_col_def at_Table_columns[] = {
|
||||
{ 1, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* atIfIndex */
|
||||
{ 2, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_VARIANT_VALUE_TYPE_PTR }, /* atPhysAddress */
|
||||
{ 3, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 } /* atNetAddress */
|
||||
};
|
||||
|
||||
static const struct snmp_table_simple_node at_Table = SNMP_TABLE_CREATE_SIMPLE(1, at_Table_columns, ip_NetToMediaTable_get_cell_value, ip_NetToMediaTable_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 */
|
||||
CREATE_LWIP_SYNC_NODE(1, at_Table)
|
||||
|
||||
static const struct snmp_node *const at_nodes[] = {
|
||||
&SYNC_NODE_NAME(at_Table).node.node
|
||||
};
|
||||
|
||||
const struct snmp_tree_node snmp_mib2_at_root = SNMP_CREATE_TREE_NODE(3, at_nodes);
|
||||
#endif /* LWIP_ARP && LWIP_IPV4 */
|
||||
|
||||
#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 */
|
||||
227
src/apps/snmp/snmp_mib2_snmp.c
Normal file
227
src/apps/snmp/snmp_mib2_snmp.c
Normal file
@@ -0,0 +1,227 @@
|
||||
/**
|
||||
* @file
|
||||
* Management Information Base II (RFC1213) SNMP objects and functions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
|
||||
* 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: Dirk Ziegelmeier <dziegel@gmx.de>
|
||||
* Christiaan Simons <christiaan.simons@axon.tv>
|
||||
*/
|
||||
|
||||
#include "lwip/snmp.h"
|
||||
#include "lwip/apps/snmp.h"
|
||||
#include "lwip/apps/snmp_core.h"
|
||||
#include "lwip/apps/snmp_mib2.h"
|
||||
#include "lwip/apps/snmp_scalar.h"
|
||||
|
||||
#if LWIP_SNMP && SNMP_LWIP_MIB2
|
||||
|
||||
#define MIB2_AUTH_TRAPS_ENABLED 1
|
||||
#define MIB2_AUTH_TRAPS_DISABLED 2
|
||||
|
||||
/* --- snmp .1.3.6.1.2.1.11 ----------------------------------------------------- */
|
||||
static s16_t
|
||||
snmp_get_value(const struct snmp_scalar_array_node_def *node, void *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;
|
||||
}
|
||||
|
||||
return sizeof(*uint_ptr);
|
||||
}
|
||||
|
||||
static snmp_err_t
|
||||
snmp_set_test(const struct snmp_scalar_array_node_def *node, u16_t len, void *value)
|
||||
{
|
||||
snmp_err_t ret = SNMP_ERR_WRONGVALUE;
|
||||
LWIP_UNUSED_ARG(len);
|
||||
|
||||
if (node->oid == 30) {
|
||||
/* snmpEnableAuthenTraps */
|
||||
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)) {
|
||||
ret = SNMP_ERR_NOERROR;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static snmp_err_t
|
||||
snmp_set_value(const struct snmp_scalar_array_node_def *node, u16_t len, void *value)
|
||||
{
|
||||
LWIP_UNUSED_ARG(len);
|
||||
|
||||
if (node->oid == 30) {
|
||||
/* snmpEnableAuthenTraps */
|
||||
s32_t *sint_ptr = (s32_t *)value;
|
||||
if (*sint_ptr == MIB2_AUTH_TRAPS_DISABLED) {
|
||||
snmp_set_auth_traps_enabled(SNMP_AUTH_TRAPS_DISABLED);
|
||||
} else {
|
||||
snmp_set_auth_traps_enabled(SNMP_AUTH_TRAPS_ENABLED);
|
||||
}
|
||||
}
|
||||
|
||||
return SNMP_ERR_NOERROR;
|
||||
}
|
||||
|
||||
/* the following nodes access variables in SNMP stack (snmp_stats) from SNMP worker thread -> OK, no sync needed */
|
||||
static const struct snmp_scalar_array_node_def snmp_nodes[] = {
|
||||
{ 1, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInPkts */
|
||||
{ 2, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutPkts */
|
||||
{ 3, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInBadVersions */
|
||||
{ 4, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInBadCommunityNames */
|
||||
{ 5, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInBadCommunityUses */
|
||||
{ 6, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInASNParseErrs */
|
||||
{ 8, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInTooBigs */
|
||||
{ 9, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInNoSuchNames */
|
||||
{10, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInBadValues */
|
||||
{11, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInReadOnlys */
|
||||
{12, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInGenErrs */
|
||||
{13, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInTotalReqVars */
|
||||
{14, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInTotalSetVars */
|
||||
{15, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInGetRequests */
|
||||
{16, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInGetNexts */
|
||||
{17, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInSetRequests */
|
||||
{18, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInGetResponses */
|
||||
{19, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInTraps */
|
||||
{20, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutTooBigs */
|
||||
{21, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutNoSuchNames */
|
||||
{22, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutBadValues */
|
||||
{24, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutGenErrs */
|
||||
{25, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutGetRequests */
|
||||
{26, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutGetNexts */
|
||||
{27, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutSetRequests */
|
||||
{28, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutGetResponses */
|
||||
{29, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutTraps */
|
||||
{30, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_WRITE}, /* snmpEnableAuthenTraps */
|
||||
{31, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpSilentDrops */
|
||||
{32, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY} /* snmpProxyDrops */
|
||||
};
|
||||
|
||||
const struct snmp_scalar_array_node snmp_mib2_snmp_root = SNMP_SCALAR_CREATE_ARRAY_NODE(11, snmp_nodes, snmp_get_value, snmp_set_test, snmp_set_value);
|
||||
|
||||
#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 */
|
||||
376
src/apps/snmp/snmp_mib2_system.c
Normal file
376
src/apps/snmp/snmp_mib2_system.c
Normal file
@@ -0,0 +1,376 @@
|
||||
/**
|
||||
* @file
|
||||
* Management Information Base II (RFC1213) SYSTEM objects and functions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
|
||||
* 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: Dirk Ziegelmeier <dziegel@gmx.de>
|
||||
* Christiaan Simons <christiaan.simons@axon.tv>
|
||||
*/
|
||||
|
||||
#include "lwip/snmp.h"
|
||||
#include "lwip/apps/snmp.h"
|
||||
#include "lwip/apps/snmp_core.h"
|
||||
#include "lwip/apps/snmp_mib2.h"
|
||||
#include "lwip/apps/snmp_table.h"
|
||||
#include "lwip/apps/snmp_scalar.h"
|
||||
#include "lwip/sys.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if LWIP_SNMP && SNMP_LWIP_MIB2
|
||||
|
||||
#if SNMP_USE_NETCONN
|
||||
#define SYNC_NODE_NAME(node_name) node_name ## _synced
|
||||
#define CREATE_LWIP_SYNC_NODE(oid, node_name) \
|
||||
static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks);
|
||||
#else
|
||||
#define SYNC_NODE_NAME(node_name) node_name
|
||||
#define CREATE_LWIP_SYNC_NODE(oid, node_name)
|
||||
#endif
|
||||
|
||||
/* --- system .1.3.6.1.2.1.1 ----------------------------------------------------- */
|
||||
|
||||
/** 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 */
|
||||
|
||||
/** 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 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 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 u16_t syslocation_bufsize = 0; /* 0=not writable */
|
||||
|
||||
/**
|
||||
* @ingroup snmp_mib2
|
||||
* Initializes sysDescr pointers.
|
||||
*
|
||||
* @param str if non-NULL then copy str pointer
|
||||
* @param len points to string length, excluding zero terminator
|
||||
*/
|
||||
void
|
||||
snmp_mib2_set_sysdescr(const u8_t *str, const u16_t *len)
|
||||
{
|
||||
if (str != NULL) {
|
||||
sysdescr = str;
|
||||
sysdescr_len = len;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup snmp_mib2
|
||||
* Initializes sysContact pointers
|
||||
*
|
||||
* @param ocstr if non-NULL then copy str pointer
|
||||
* @param ocstrlen points to string length, excluding zero terminator.
|
||||
* if set to NULL it is assumed that ocstr is NULL-terminated.
|
||||
* @param bufsize size of the buffer in bytes.
|
||||
* (this is required because the buffer can be overwritten by snmp-set)
|
||||
* if ocstrlen is NULL buffer needs space for terminating 0 byte.
|
||||
* otherwise complete buffer is used for string.
|
||||
* if bufsize is set to 0, the value is regarded as read-only.
|
||||
*/
|
||||
void
|
||||
snmp_mib2_set_syscontact(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize)
|
||||
{
|
||||
if (ocstr != NULL) {
|
||||
syscontact = ocstr;
|
||||
syscontact_wr = ocstr;
|
||||
syscontact_len = ocstrlen;
|
||||
syscontact_wr_len = ocstrlen;
|
||||
syscontact_bufsize = bufsize;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup snmp_mib2
|
||||
* see \ref snmp_mib2_set_syscontact but set pointer to readonly memory
|
||||
*/
|
||||
void
|
||||
snmp_mib2_set_syscontact_readonly(const u8_t *ocstr, const u16_t *ocstrlen)
|
||||
{
|
||||
if (ocstr != NULL) {
|
||||
syscontact = ocstr;
|
||||
syscontact_len = ocstrlen;
|
||||
syscontact_wr = NULL;
|
||||
syscontact_wr_len = NULL;
|
||||
syscontact_bufsize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @ingroup snmp_mib2
|
||||
* Initializes sysName pointers
|
||||
*
|
||||
* @param ocstr if non-NULL then copy str pointer
|
||||
* @param ocstrlen points to string length, excluding zero terminator.
|
||||
* if set to NULL it is assumed that ocstr is NULL-terminated.
|
||||
* @param bufsize size of the buffer in bytes.
|
||||
* (this is required because the buffer can be overwritten by snmp-set)
|
||||
* if ocstrlen is NULL buffer needs space for terminating 0 byte.
|
||||
* otherwise complete buffer is used for string.
|
||||
* if bufsize is set to 0, the value is regarded as read-only.
|
||||
*/
|
||||
void
|
||||
snmp_mib2_set_sysname(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize)
|
||||
{
|
||||
if (ocstr != NULL) {
|
||||
sysname = ocstr;
|
||||
sysname_wr = ocstr;
|
||||
sysname_len = ocstrlen;
|
||||
sysname_wr_len = ocstrlen;
|
||||
sysname_bufsize = bufsize;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup snmp_mib2
|
||||
* see \ref snmp_mib2_set_sysname but set pointer to readonly memory
|
||||
*/
|
||||
void
|
||||
snmp_mib2_set_sysname_readonly(const u8_t *ocstr, const u16_t *ocstrlen)
|
||||
{
|
||||
if (ocstr != NULL) {
|
||||
sysname = ocstr;
|
||||
sysname_len = ocstrlen;
|
||||
sysname_wr = NULL;
|
||||
sysname_wr_len = NULL;
|
||||
sysname_bufsize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup snmp_mib2
|
||||
* Initializes sysLocation pointers
|
||||
*
|
||||
* @param ocstr if non-NULL then copy str pointer
|
||||
* @param ocstrlen points to string length, excluding zero terminator.
|
||||
* if set to NULL it is assumed that ocstr is NULL-terminated.
|
||||
* @param bufsize size of the buffer in bytes.
|
||||
* (this is required because the buffer can be overwritten by snmp-set)
|
||||
* if ocstrlen is NULL buffer needs space for terminating 0 byte.
|
||||
* otherwise complete buffer is used for string.
|
||||
* if bufsize is set to 0, the value is regarded as read-only.
|
||||
*/
|
||||
void
|
||||
snmp_mib2_set_syslocation(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize)
|
||||
{
|
||||
if (ocstr != NULL) {
|
||||
syslocation = ocstr;
|
||||
syslocation_wr = ocstr;
|
||||
syslocation_len = ocstrlen;
|
||||
syslocation_wr_len = ocstrlen;
|
||||
syslocation_bufsize = bufsize;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup snmp_mib2
|
||||
* see \ref snmp_mib2_set_syslocation but set pointer to readonly memory
|
||||
*/
|
||||
void
|
||||
snmp_mib2_set_syslocation_readonly(const u8_t *ocstr, const u16_t *ocstrlen)
|
||||
{
|
||||
if (ocstr != NULL) {
|
||||
syslocation = ocstr;
|
||||
syslocation_len = ocstrlen;
|
||||
syslocation_wr = NULL;
|
||||
syslocation_wr_len = NULL;
|
||||
syslocation_bufsize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
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();
|
||||
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;
|
||||
}
|
||||
|
||||
/* handle string values (OID 1,4,5 and 6) */
|
||||
LWIP_ASSERT("", (value != NULL));
|
||||
if (var_len == NULL) {
|
||||
result = (s16_t)strlen((const char *)var);
|
||||
} else {
|
||||
result = *var_len;
|
||||
}
|
||||
MEMCPY(value, var, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* check if value is writable at all */
|
||||
if (*var_bufsize > 0) {
|
||||
if (var_wr_len == NULL) {
|
||||
/* we have to take the terminating 0 into account */
|
||||
if (len < *var_bufsize) {
|
||||
ret = SNMP_ERR_NOERROR;
|
||||
}
|
||||
} else {
|
||||
if (len <= *var_bufsize) {
|
||||
ret = SNMP_ERR_NOERROR;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = SNMP_ERR_NOTWRITABLE;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
} else {
|
||||
*var_wr_len = len;
|
||||
}
|
||||
|
||||
return SNMP_ERR_NOERROR;
|
||||
}
|
||||
|
||||
static const struct snmp_scalar_array_node_def system_nodes[] = {
|
||||
{1, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY}, /* sysDescr */
|
||||
{2, SNMP_ASN1_TYPE_OBJECT_ID, SNMP_NODE_INSTANCE_READ_ONLY}, /* sysObjectID */
|
||||
{3, SNMP_ASN1_TYPE_TIMETICKS, SNMP_NODE_INSTANCE_READ_ONLY}, /* sysUpTime */
|
||||
{4, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_WRITE}, /* sysContact */
|
||||
{5, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_WRITE}, /* sysName */
|
||||
{6, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_WRITE}, /* sysLocation */
|
||||
{7, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY} /* sysServices */
|
||||
};
|
||||
|
||||
const struct snmp_scalar_array_node snmp_mib2_system_node = SNMP_SCALAR_CREATE_ARRAY_NODE(1, system_nodes, system_get_value, system_set_test, system_set_value);
|
||||
|
||||
#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 */
|
||||
607
src/apps/snmp/snmp_mib2_tcp.c
Normal file
607
src/apps/snmp/snmp_mib2_tcp.c
Normal file
@@ -0,0 +1,607 @@
|
||||
/**
|
||||
* @file
|
||||
* Management Information Base II (RFC1213) TCP objects and functions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
|
||||
* 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: Dirk Ziegelmeier <dziegel@gmx.de>
|
||||
* Christiaan Simons <christiaan.simons@axon.tv>
|
||||
*/
|
||||
|
||||
#include "lwip/snmp.h"
|
||||
#include "lwip/apps/snmp.h"
|
||||
#include "lwip/apps/snmp_core.h"
|
||||
#include "lwip/apps/snmp_mib2.h"
|
||||
#include "lwip/apps/snmp_table.h"
|
||||
#include "lwip/apps/snmp_scalar.h"
|
||||
#include "lwip/tcp.h"
|
||||
#include "lwip/priv/tcp_priv.h"
|
||||
#include "lwip/stats.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_TCP
|
||||
|
||||
#if SNMP_USE_NETCONN
|
||||
#define SYNC_NODE_NAME(node_name) node_name ## _synced
|
||||
#define CREATE_LWIP_SYNC_NODE(oid, node_name) \
|
||||
static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks);
|
||||
#else
|
||||
#define SYNC_NODE_NAME(node_name) node_name
|
||||
#define CREATE_LWIP_SYNC_NODE(oid, node_name)
|
||||
#endif
|
||||
|
||||
/* --- tcp .1.3.6.1.2.1.6 ----------------------------------------------------- */
|
||||
|
||||
static s16_t
|
||||
tcp_get_value(struct snmp_node_instance *instance, void *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 */
|
||||
u16_t tcpcurrestab = 0;
|
||||
struct tcp_pcb *pcb = tcp_active_pcbs;
|
||||
while (pcb != NULL) {
|
||||
if ((pcb->state == ESTABLISHED) ||
|
||||
(pcb->state == CLOSE_WAIT)) {
|
||||
tcpcurrestab++;
|
||||
}
|
||||
pcb = pcb->next;
|
||||
}
|
||||
*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);
|
||||
#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;
|
||||
}
|
||||
|
||||
/* --- tcpConnTable --- */
|
||||
|
||||
#if LWIP_IPV4
|
||||
|
||||
/* list of allowed value ranges for incoming OID */
|
||||
static const struct snmp_oid_range tcp_ConnTable_oid_ranges[] = {
|
||||
{ 0, 0xff }, /* IP A */
|
||||
{ 0, 0xff }, /* IP B */
|
||||
{ 0, 0xff }, /* IP C */
|
||||
{ 0, 0xff }, /* IP D */
|
||||
{ 0, 0xffff }, /* Port */
|
||||
{ 0, 0xff }, /* IP A */
|
||||
{ 0, 0xff }, /* IP B */
|
||||
{ 0, 0xff }, /* IP C */
|
||||
{ 0, 0xff }, /* IP D */
|
||||
{ 0, 0xffff } /* Port */
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
u8_t i;
|
||||
ip4_addr_t local_ip;
|
||||
ip4_addr_t remote_ip;
|
||||
u16_t local_port;
|
||||
u16_t remote_port;
|
||||
struct tcp_pcb *pcb;
|
||||
|
||||
/* check if incoming OID length and if values are in plausible range */
|
||||
if (!snmp_oid_in_range(row_oid, row_oid_len, tcp_ConnTable_oid_ranges, LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges))) {
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
/* get IPs and ports from incoming OID */
|
||||
snmp_oid_to_ip4(&row_oid[0], &local_ip); /* we know it succeeds because of oid_in_range check above */
|
||||
local_port = (u16_t)row_oid[4];
|
||||
snmp_oid_to_ip4(&row_oid[5], &remote_ip); /* we know it succeeds because of oid_in_range check above */
|
||||
remote_port = (u16_t)row_oid[9];
|
||||
|
||||
/* find tcp_pcb with requested ips and ports */
|
||||
for (i = 0; i < LWIP_ARRAYSIZE(tcp_pcb_lists); i++) {
|
||||
pcb = *tcp_pcb_lists[i];
|
||||
|
||||
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)) {
|
||||
|
||||
/* PCBs in state LISTEN are not connected and have no remote_ip or remote_port */
|
||||
if (pcb->state == LISTEN) {
|
||||
if (ip4_addr_cmp(&remote_ip, IP4_ADDR_ANY4) && (remote_port == 0)) {
|
||||
/* fill in object properties */
|
||||
return tcp_ConnTable_get_cell_value_core(pcb, column, value, value_len);
|
||||
}
|
||||
} 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)) {
|
||||
/* fill in object properties */
|
||||
return tcp_ConnTable_get_cell_value_core(pcb, column, value, value_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pcb = pcb->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* not found */
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
u8_t i;
|
||||
struct tcp_pcb *pcb;
|
||||
struct snmp_next_oid_state state;
|
||||
u32_t result_temp[LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges)];
|
||||
|
||||
/* init struct to search next oid */
|
||||
snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges));
|
||||
|
||||
/* iterate over all possible OIDs to find the next one */
|
||||
for (i = 0; i < LWIP_ARRAYSIZE(tcp_pcb_lists); i++) {
|
||||
pcb = *tcp_pcb_lists[i];
|
||||
while (pcb != NULL) {
|
||||
u32_t test_oid[LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges)];
|
||||
|
||||
if (IP_IS_V4_VAL(pcb->local_ip)) {
|
||||
snmp_ip4_to_oid(ip_2_ip4(&pcb->local_ip), &test_oid[0]);
|
||||
test_oid[4] = pcb->local_port;
|
||||
|
||||
/* PCBs in state LISTEN are not connected and have no remote_ip or remote_port */
|
||||
if (pcb->state == LISTEN) {
|
||||
snmp_ip4_to_oid(IP4_ADDR_ANY4, &test_oid[5]);
|
||||
test_oid[9] = 0;
|
||||
} else {
|
||||
if (IP_IS_V6_VAL(pcb->remote_ip)) { /* should never happen */
|
||||
continue;
|
||||
}
|
||||
snmp_ip4_to_oid(ip_2_ip4(&pcb->remote_ip), &test_oid[5]);
|
||||
test_oid[9] = pcb->remote_port;
|
||||
}
|
||||
|
||||
/* check generated OID: is it a candidate for the next one? */
|
||||
snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges), pcb);
|
||||
}
|
||||
|
||||
pcb = pcb->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 tcp_ConnTable_get_cell_value_core((struct tcp_pcb *)state.reference, column, value, value_len);
|
||||
}
|
||||
|
||||
/* not found */
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
#endif /* LWIP_IPV4 */
|
||||
|
||||
/* --- tcpConnectionTable --- */
|
||||
|
||||
static snmp_err_t
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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};
|
||||
|
||||
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);
|
||||
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);
|
||||
if (idx == 0) {
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
/* find tcp_pcb with requested ip and port*/
|
||||
for (i = 0; i < LWIP_ARRAYSIZE(tcp_pcb_nonlisten_lists); i++) {
|
||||
pcb = *tcp_pcb_nonlisten_lists[i];
|
||||
|
||||
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)) {
|
||||
/* fill in object properties */
|
||||
return tcp_ConnectionTable_get_cell_value_core(column, pcb, value);
|
||||
}
|
||||
pcb = pcb->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* not found */
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct tcp_pcb *pcb;
|
||||
struct snmp_next_oid_state state;
|
||||
/* 1x tcpConnectionLocalAddressType + 1x OID len + 16x tcpConnectionLocalAddress + 1x tcpConnectionLocalPort
|
||||
* 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};
|
||||
|
||||
LWIP_UNUSED_ARG(value_len);
|
||||
|
||||
/* init struct to search next oid */
|
||||
snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(result_temp));
|
||||
|
||||
/* iterate over all possible OIDs to find the next one */
|
||||
for (i = 0; i < LWIP_ARRAYSIZE(tcp_pcb_nonlisten_lists); i++) {
|
||||
pcb = *tcp_pcb_nonlisten_lists[i];
|
||||
|
||||
while (pcb != NULL) {
|
||||
u8_t idx = 0;
|
||||
u32_t test_oid[LWIP_ARRAYSIZE(result_temp)];
|
||||
|
||||
/* tcpConnectionLocalAddressType + tcpConnectionLocalAddress + tcpConnectionLocalPort */
|
||||
idx += snmp_ip_port_to_oid(&pcb->local_ip, pcb->local_port, &test_oid[idx]);
|
||||
|
||||
/* tcpConnectionRemAddressType + tcpConnectionRemAddress + tcpConnectionRemPort */
|
||||
idx += snmp_ip_port_to_oid(&pcb->remote_ip, pcb->remote_port, &test_oid[idx]);
|
||||
|
||||
/* check generated OID: is it a candidate for the next one? */
|
||||
snmp_next_oid_check(&state, test_oid, idx, pcb);
|
||||
|
||||
pcb = pcb->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 tcp_ConnectionTable_get_cell_value_core(column, (struct tcp_pcb *)state.reference, value);
|
||||
} else {
|
||||
/* not found */
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
/* --- tcpListenerTable --- */
|
||||
|
||||
static snmp_err_t
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
ip_addr_t local_ip;
|
||||
u16_t local_port;
|
||||
struct tcp_pcb_listen *pcb;
|
||||
u8_t idx = 0;
|
||||
|
||||
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);
|
||||
if (idx == 0) {
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
/* find tcp_pcb with requested ip and port*/
|
||||
pcb = tcp_listen_pcbs.listen_pcbs;
|
||||
while (pcb != NULL) {
|
||||
if (ip_addr_cmp(&local_ip, &pcb->local_ip) &&
|
||||
(local_port == pcb->local_port)) {
|
||||
/* fill in object properties */
|
||||
return tcp_ListenerTable_get_cell_value_core(column, value);
|
||||
}
|
||||
pcb = pcb->next;
|
||||
}
|
||||
|
||||
/* not found */
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct tcp_pcb_listen *pcb;
|
||||
struct snmp_next_oid_state state;
|
||||
/* 1x tcpListenerLocalAddressType + 1x OID len + 16x tcpListenerLocalAddress + 1x tcpListenerLocalPort */
|
||||
u32_t result_temp[19];
|
||||
|
||||
LWIP_UNUSED_ARG(value_len);
|
||||
|
||||
/* init struct to search next oid */
|
||||
snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(result_temp));
|
||||
|
||||
/* iterate over all possible OIDs to find the next one */
|
||||
pcb = tcp_listen_pcbs.listen_pcbs;
|
||||
while (pcb != NULL) {
|
||||
u8_t idx = 0;
|
||||
u32_t test_oid[LWIP_ARRAYSIZE(result_temp)];
|
||||
|
||||
/* tcpListenerLocalAddressType + tcpListenerLocalAddress + tcpListenerLocalPort */
|
||||
idx += snmp_ip_port_to_oid(&pcb->local_ip, pcb->local_port, &test_oid[idx]);
|
||||
|
||||
/* check generated OID: is it a candidate for the next one? */
|
||||
snmp_next_oid_check(&state, test_oid, idx, NULL);
|
||||
|
||||
pcb = pcb->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 tcp_ListenerTable_get_cell_value_core(column, value);
|
||||
} else {
|
||||
/* not found */
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct snmp_scalar_node tcp_RtoAlgorithm = SNMP_SCALAR_CREATE_NODE_READONLY(1, SNMP_ASN1_TYPE_INTEGER, tcp_get_value);
|
||||
static const struct snmp_scalar_node tcp_RtoMin = SNMP_SCALAR_CREATE_NODE_READONLY(2, SNMP_ASN1_TYPE_INTEGER, tcp_get_value);
|
||||
static const struct snmp_scalar_node tcp_RtoMax = SNMP_SCALAR_CREATE_NODE_READONLY(3, SNMP_ASN1_TYPE_INTEGER, tcp_get_value);
|
||||
static const struct snmp_scalar_node tcp_MaxConn = SNMP_SCALAR_CREATE_NODE_READONLY(4, SNMP_ASN1_TYPE_INTEGER, tcp_get_value);
|
||||
static const struct snmp_scalar_node tcp_ActiveOpens = SNMP_SCALAR_CREATE_NODE_READONLY(5, SNMP_ASN1_TYPE_COUNTER, tcp_get_value);
|
||||
static const struct snmp_scalar_node tcp_PassiveOpens = SNMP_SCALAR_CREATE_NODE_READONLY(6, SNMP_ASN1_TYPE_COUNTER, tcp_get_value);
|
||||
static const struct snmp_scalar_node tcp_AttemptFails = SNMP_SCALAR_CREATE_NODE_READONLY(7, SNMP_ASN1_TYPE_COUNTER, tcp_get_value);
|
||||
static const struct snmp_scalar_node tcp_EstabResets = SNMP_SCALAR_CREATE_NODE_READONLY(8, SNMP_ASN1_TYPE_COUNTER, tcp_get_value);
|
||||
static const struct snmp_scalar_node tcp_CurrEstab = SNMP_SCALAR_CREATE_NODE_READONLY(9, SNMP_ASN1_TYPE_GAUGE, tcp_get_value);
|
||||
static const struct snmp_scalar_node tcp_InSegs = SNMP_SCALAR_CREATE_NODE_READONLY(10, SNMP_ASN1_TYPE_COUNTER, tcp_get_value);
|
||||
static const struct snmp_scalar_node tcp_OutSegs = SNMP_SCALAR_CREATE_NODE_READONLY(11, SNMP_ASN1_TYPE_COUNTER, tcp_get_value);
|
||||
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[] = {
|
||||
{ 1, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* tcpConnState */
|
||||
{ 2, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* tcpConnLocalAddress */
|
||||
{ 3, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* tcpConnLocalPort */
|
||||
{ 4, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* tcpConnRemAddress */
|
||||
{ 5, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 } /* tcpConnRemPort */
|
||||
};
|
||||
|
||||
static const struct snmp_table_simple_node tcp_ConnTable = SNMP_TABLE_CREATE_SIMPLE(13, tcp_ConnTable_columns, tcp_ConnTable_get_cell_value, tcp_ConnTable_get_next_cell_instance_and_value);
|
||||
#endif /* LWIP_IPV4 */
|
||||
|
||||
static const struct snmp_table_simple_col_def tcp_ConnectionTable_columns[] = {
|
||||
/* all items except tcpConnectionState and tcpConnectionProcess are declared as not-accessible */
|
||||
{ 7, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* tcpConnectionState */
|
||||
{ 8, SNMP_ASN1_TYPE_UNSIGNED32, SNMP_VARIANT_VALUE_TYPE_U32 } /* tcpConnectionProcess */
|
||||
};
|
||||
|
||||
static const struct snmp_table_simple_node tcp_ConnectionTable = SNMP_TABLE_CREATE_SIMPLE(19, tcp_ConnectionTable_columns, tcp_ConnectionTable_get_cell_value, tcp_ConnectionTable_get_next_cell_instance_and_value);
|
||||
|
||||
|
||||
static const struct snmp_table_simple_col_def tcp_ListenerTable_columns[] = {
|
||||
/* all items except tcpListenerProcess are declared as not-accessible */
|
||||
{ 4, SNMP_ASN1_TYPE_UNSIGNED32, SNMP_VARIANT_VALUE_TYPE_U32 } /* tcpListenerProcess */
|
||||
};
|
||||
|
||||
static const struct snmp_table_simple_node tcp_ListenerTable = SNMP_TABLE_CREATE_SIMPLE(20, tcp_ListenerTable_columns, tcp_ListenerTable_get_cell_value, tcp_ListenerTable_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 */
|
||||
CREATE_LWIP_SYNC_NODE( 1, tcp_RtoAlgorithm)
|
||||
CREATE_LWIP_SYNC_NODE( 2, tcp_RtoMin)
|
||||
CREATE_LWIP_SYNC_NODE( 3, tcp_RtoMax)
|
||||
CREATE_LWIP_SYNC_NODE( 4, tcp_MaxConn)
|
||||
CREATE_LWIP_SYNC_NODE( 5, tcp_ActiveOpens)
|
||||
CREATE_LWIP_SYNC_NODE( 6, tcp_PassiveOpens)
|
||||
CREATE_LWIP_SYNC_NODE( 7, tcp_AttemptFails)
|
||||
CREATE_LWIP_SYNC_NODE( 8, tcp_EstabResets)
|
||||
CREATE_LWIP_SYNC_NODE( 9, tcp_CurrEstab)
|
||||
CREATE_LWIP_SYNC_NODE(10, tcp_InSegs)
|
||||
CREATE_LWIP_SYNC_NODE(11, tcp_OutSegs)
|
||||
CREATE_LWIP_SYNC_NODE(12, tcp_RetransSegs)
|
||||
#if LWIP_IPV4
|
||||
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[] = {
|
||||
&SYNC_NODE_NAME(tcp_RtoAlgorithm).node.node,
|
||||
&SYNC_NODE_NAME(tcp_RtoMin).node.node,
|
||||
&SYNC_NODE_NAME(tcp_RtoMax).node.node,
|
||||
&SYNC_NODE_NAME(tcp_MaxConn).node.node,
|
||||
&SYNC_NODE_NAME(tcp_ActiveOpens).node.node,
|
||||
&SYNC_NODE_NAME(tcp_PassiveOpens).node.node,
|
||||
&SYNC_NODE_NAME(tcp_AttemptFails).node.node,
|
||||
&SYNC_NODE_NAME(tcp_EstabResets).node.node,
|
||||
&SYNC_NODE_NAME(tcp_CurrEstab).node.node,
|
||||
&SYNC_NODE_NAME(tcp_InSegs).node.node,
|
||||
&SYNC_NODE_NAME(tcp_OutSegs).node.node,
|
||||
&SYNC_NODE_NAME(tcp_RetransSegs).node.node,
|
||||
#if LWIP_IPV4
|
||||
&SYNC_NODE_NAME(tcp_ConnTable).node.node,
|
||||
#endif /* LWIP_IPV4 */
|
||||
&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
|
||||
};
|
||||
|
||||
const struct snmp_tree_node snmp_mib2_tcp_root = SNMP_CREATE_TREE_NODE(6, tcp_nodes);
|
||||
#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_TCP */
|
||||
372
src/apps/snmp/snmp_mib2_udp.c
Normal file
372
src/apps/snmp/snmp_mib2_udp.c
Normal file
@@ -0,0 +1,372 @@
|
||||
/**
|
||||
* @file
|
||||
* Management Information Base II (RFC1213) UDP objects and functions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
|
||||
* 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: Dirk Ziegelmeier <dziegel@gmx.de>
|
||||
* Christiaan Simons <christiaan.simons@axon.tv>
|
||||
*/
|
||||
|
||||
#include "lwip/snmp.h"
|
||||
#include "lwip/apps/snmp.h"
|
||||
#include "lwip/apps/snmp_core.h"
|
||||
#include "lwip/apps/snmp_mib2.h"
|
||||
#include "lwip/apps/snmp_table.h"
|
||||
#include "lwip/apps/snmp_scalar.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/stats.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_UDP
|
||||
|
||||
#if SNMP_USE_NETCONN
|
||||
#define SYNC_NODE_NAME(node_name) node_name ## _synced
|
||||
#define CREATE_LWIP_SYNC_NODE(oid, node_name) \
|
||||
static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks);
|
||||
#else
|
||||
#define SYNC_NODE_NAME(node_name) node_name
|
||||
#define CREATE_LWIP_SYNC_NODE(oid, node_name)
|
||||
#endif
|
||||
|
||||
/* --- udp .1.3.6.1.2.1.7 ----------------------------------------------------- */
|
||||
|
||||
static s16_t
|
||||
udp_get_value(struct snmp_node_instance *instance, void *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);
|
||||
#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;
|
||||
}
|
||||
|
||||
/* --- udpEndpointTable --- */
|
||||
|
||||
static snmp_err_t
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
ip_addr_t local_ip, remote_ip;
|
||||
u16_t local_port, remote_port;
|
||||
struct udp_pcb *pcb;
|
||||
u8_t idx = 0;
|
||||
|
||||
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);
|
||||
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);
|
||||
if (idx == 0) {
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
/* udpEndpointInstance */
|
||||
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)) {
|
||||
/* fill in object properties */
|
||||
return udp_endpointTable_get_cell_value_core(column, value);
|
||||
}
|
||||
pcb = pcb->next;
|
||||
}
|
||||
|
||||
/* not found */
|
||||
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)
|
||||
{
|
||||
struct udp_pcb *pcb;
|
||||
struct snmp_next_oid_state state;
|
||||
/* 1x udpEndpointLocalAddressType + 1x OID len + 16x udpEndpointLocalAddress + 1x udpEndpointLocalPort +
|
||||
* 1x udpEndpointRemoteAddressType + 1x OID len + 16x udpEndpointRemoteAddress + 1x udpEndpointRemotePort +
|
||||
* 1x udpEndpointInstance = 39
|
||||
*/
|
||||
u32_t result_temp[39];
|
||||
|
||||
LWIP_UNUSED_ARG(value_len);
|
||||
|
||||
/* init struct to search next oid */
|
||||
snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(result_temp));
|
||||
|
||||
/* iterate over all possible OIDs to find the next one */
|
||||
pcb = udp_pcbs;
|
||||
while (pcb != NULL) {
|
||||
u32_t test_oid[LWIP_ARRAYSIZE(result_temp)];
|
||||
u8_t idx = 0;
|
||||
|
||||
/* udpEndpointLocalAddressType + udpEndpointLocalAddress + udpEndpointLocalPort */
|
||||
idx += snmp_ip_port_to_oid(&pcb->local_ip, pcb->local_port, &test_oid[idx]);
|
||||
|
||||
/* udpEndpointRemoteAddressType + udpEndpointRemoteAddress + udpEndpointRemotePort */
|
||||
idx += snmp_ip_port_to_oid(&pcb->remote_ip, pcb->remote_port, &test_oid[idx]);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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 udp_endpointTable_get_cell_value_core(column, value);
|
||||
} else {
|
||||
/* not found */
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
/* --- udpTable --- */
|
||||
|
||||
#if LWIP_IPV4
|
||||
|
||||
/* list of allowed value ranges for incoming OID */
|
||||
static const struct snmp_oid_range udp_Table_oid_ranges[] = {
|
||||
{ 0, 0xff }, /* IP A */
|
||||
{ 0, 0xff }, /* IP B */
|
||||
{ 0, 0xff }, /* IP C */
|
||||
{ 0, 0xff }, /* IP D */
|
||||
{ 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
ip4_addr_t ip;
|
||||
u16_t port;
|
||||
struct udp_pcb *pcb;
|
||||
|
||||
/* check if incoming OID length and if values are in plausible range */
|
||||
if (!snmp_oid_in_range(row_oid, row_oid_len, udp_Table_oid_ranges, LWIP_ARRAYSIZE(udp_Table_oid_ranges))) {
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
/* get IP and port from incoming OID */
|
||||
snmp_oid_to_ip4(&row_oid[0], &ip); /* we know it succeeds because of oid_in_range check above */
|
||||
port = (u16_t)row_oid[4];
|
||||
|
||||
/* find udp_pcb with requested ip and port*/
|
||||
pcb = udp_pcbs;
|
||||
while (pcb != NULL) {
|
||||
if (IP_IS_V4_VAL(pcb->local_ip)) {
|
||||
if (ip4_addr_cmp(&ip, ip_2_ip4(&pcb->local_ip)) && (port == pcb->local_port)) {
|
||||
/* fill in object properties */
|
||||
return udp_Table_get_cell_value_core(pcb, column, value, value_len);
|
||||
}
|
||||
}
|
||||
pcb = pcb->next;
|
||||
}
|
||||
|
||||
/* not found */
|
||||
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)
|
||||
{
|
||||
struct udp_pcb *pcb;
|
||||
struct snmp_next_oid_state state;
|
||||
u32_t result_temp[LWIP_ARRAYSIZE(udp_Table_oid_ranges)];
|
||||
|
||||
/* init struct to search next oid */
|
||||
snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(udp_Table_oid_ranges));
|
||||
|
||||
/* iterate over all possible OIDs to find the next one */
|
||||
pcb = udp_pcbs;
|
||||
while (pcb != NULL) {
|
||||
u32_t test_oid[LWIP_ARRAYSIZE(udp_Table_oid_ranges)];
|
||||
|
||||
if (IP_IS_V4_VAL(pcb->local_ip)) {
|
||||
snmp_ip4_to_oid(ip_2_ip4(&pcb->local_ip), &test_oid[0]);
|
||||
test_oid[4] = pcb->local_port;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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 udp_Table_get_cell_value_core((struct udp_pcb *)state.reference, column, value, value_len);
|
||||
} else {
|
||||
/* not found */
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* LWIP_IPV4 */
|
||||
|
||||
static const struct snmp_scalar_node udp_inDatagrams = SNMP_SCALAR_CREATE_NODE_READONLY(1, SNMP_ASN1_TYPE_COUNTER, udp_get_value);
|
||||
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[] = {
|
||||
{ 1, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* udpLocalAddress */
|
||||
{ 2, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 } /* udpLocalPort */
|
||||
};
|
||||
static const struct snmp_table_simple_node udp_Table = SNMP_TABLE_CREATE_SIMPLE(5, udp_Table_columns, udp_Table_get_cell_value, udp_Table_get_next_cell_instance_and_value);
|
||||
#endif /* LWIP_IPV4 */
|
||||
|
||||
static const struct snmp_table_simple_col_def udp_endpointTable_columns[] = {
|
||||
/* 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 */
|
||||
CREATE_LWIP_SYNC_NODE(1, udp_inDatagrams)
|
||||
CREATE_LWIP_SYNC_NODE(2, udp_noPorts)
|
||||
CREATE_LWIP_SYNC_NODE(3, udp_inErrors)
|
||||
CREATE_LWIP_SYNC_NODE(4, udp_outDatagrams)
|
||||
#if LWIP_IPV4
|
||||
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[] = {
|
||||
&SYNC_NODE_NAME(udp_inDatagrams).node.node,
|
||||
&SYNC_NODE_NAME(udp_noPorts).node.node,
|
||||
&SYNC_NODE_NAME(udp_inErrors).node.node,
|
||||
&SYNC_NODE_NAME(udp_outDatagrams).node.node,
|
||||
#if LWIP_IPV4
|
||||
&SYNC_NODE_NAME(udp_Table).node.node,
|
||||
#endif /* LWIP_IPV4 */
|
||||
&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);
|
||||
#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_UDP */
|
||||
1951
src/apps/snmp/snmp_msg.c
Normal file
1951
src/apps/snmp/snmp_msg.c
Normal file
File diff suppressed because it is too large
Load Diff
185
src/apps/snmp/snmp_msg.h
Normal file
185
src/apps/snmp/snmp_msg.h
Normal file
@@ -0,0 +1,185 @@
|
||||
/**
|
||||
* @file
|
||||
* SNMP Agent message handling structures (internal API, do not use in client code).
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
|
||||
* 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: Christiaan Simons <christiaan.simons@axon.tv>
|
||||
* Martin Hentschel <info@cl-soft.de>
|
||||
* Elias Oenal <lwip@eliasoenal.com>
|
||||
*/
|
||||
|
||||
#ifndef LWIP_HDR_APPS_SNMP_MSG_H
|
||||
#define LWIP_HDR_APPS_SNMP_MSG_H
|
||||
|
||||
#include "lwip/apps/snmp_opts.h"
|
||||
|
||||
#if LWIP_SNMP
|
||||
|
||||
#include "lwip/apps/snmp.h"
|
||||
#include "lwip/apps/snmp_core.h"
|
||||
#include "snmp_pbuf_stream.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/err.h"
|
||||
|
||||
#if LWIP_SNMP_V3
|
||||
#include "snmpv3_priv.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#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_pbuf_stream pbuf_stream;
|
||||
u16_t varbind_count;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
SNMP_VB_ENUMERATOR_ERR_OK = 0,
|
||||
SNMP_VB_ENUMERATOR_ERR_EOVB = 1,
|
||||
SNMP_VB_ENUMERATOR_ERR_ASN1ERROR = 2,
|
||||
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);
|
||||
|
||||
struct snmp_request {
|
||||
/* Communication handle */
|
||||
void *handle;
|
||||
/* source IP address */
|
||||
const ip_addr_t *source_ip;
|
||||
/* source UDP port */
|
||||
u16_t source_port;
|
||||
/* incoming snmp version */
|
||||
u8_t version;
|
||||
/* community name (zero terminated) */
|
||||
u8_t community[SNMP_MAX_COMMUNITY_STR_LEN + 1];
|
||||
/* community string length (exclusive zero term) */
|
||||
u16_t community_strlen;
|
||||
/* request type */
|
||||
u8_t request_type;
|
||||
/* request ID */
|
||||
s32_t request_id;
|
||||
/* error status */
|
||||
s32_t error_status;
|
||||
/* error index */
|
||||
s32_t error_index;
|
||||
/* non-repeaters (getBulkRequest (SNMPv2c)) */
|
||||
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;
|
||||
u8_t msg_flags;
|
||||
s32_t msg_security_model;
|
||||
u8_t msg_authoritative_engine_id[SNMP_V3_MAX_ENGINE_ID_LENGTH];
|
||||
u8_t msg_authoritative_engine_id_len;
|
||||
s32_t msg_authoritative_engine_boots;
|
||||
s32_t msg_authoritative_engine_time;
|
||||
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];
|
||||
u8_t context_name_len;
|
||||
#endif
|
||||
|
||||
struct pbuf *inbound_pbuf;
|
||||
struct snmp_varbind_enumerator inbound_varbind_enumerator;
|
||||
u16_t inbound_varbind_offset;
|
||||
u16_t inbound_varbind_len;
|
||||
u16_t inbound_padding_len;
|
||||
|
||||
struct pbuf *outbound_pbuf;
|
||||
struct snmp_pbuf_stream outbound_pbuf_stream;
|
||||
u16_t outbound_pdu_offset;
|
||||
u16_t outbound_error_status_offset;
|
||||
u16_t outbound_error_index_offset;
|
||||
u16_t outbound_varbind_offset;
|
||||
#if LWIP_SNMP_V3
|
||||
u16_t outbound_msg_global_data_offset;
|
||||
u16_t outbound_msg_global_data_end;
|
||||
u16_t outbound_msg_security_parameters_str_offset;
|
||||
u16_t outbound_msg_security_parameters_seq_offset;
|
||||
u16_t outbound_msg_security_parameters_end;
|
||||
u16_t outbound_msg_authentication_parameters_offset;
|
||||
u16_t outbound_scoped_pdu_seq_offset;
|
||||
u16_t outbound_scoped_pdu_string_offset;
|
||||
#endif
|
||||
|
||||
u8_t value_buffer[SNMP_MAX_VALUE_SIZE];
|
||||
};
|
||||
|
||||
/** A helper struct keeping length information about varbinds */
|
||||
struct snmp_varbind_len {
|
||||
u8_t vb_len_len;
|
||||
u16_t vb_value_len;
|
||||
u8_t oid_len_len;
|
||||
u16_t oid_value_len;
|
||||
u8_t value_len_len;
|
||||
u16_t value_value_len;
|
||||
};
|
||||
|
||||
/** Agent community string */
|
||||
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;
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LWIP_SNMP */
|
||||
|
||||
#endif /* LWIP_HDR_APPS_SNMP_MSG_H */
|
||||
123
src/apps/snmp/snmp_netconn.c
Normal file
123
src/apps/snmp/snmp_netconn.c
Normal file
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* @file
|
||||
* SNMP netconn frontend.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Author: Dirk Ziegelmeier <dziegel@gmx.de>
|
||||
*/
|
||||
|
||||
#include "lwip/apps/snmp_opts.h"
|
||||
|
||||
#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
|
||||
snmp_netconn_thread(void *arg)
|
||||
{
|
||||
struct netconn *conn;
|
||||
struct netbuf *buf;
|
||||
err_t err;
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
|
||||
/* Bind to SNMP port with default IP address */
|
||||
#if LWIP_IPV6
|
||||
conn = netconn_new(NETCONN_UDP_IPV6);
|
||||
netconn_bind(conn, IP6_ADDR_ANY, LWIP_IANA_PORT_SNMP);
|
||||
#else /* LWIP_IPV6 */
|
||||
conn = netconn_new(NETCONN_UDP);
|
||||
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 {
|
||||
err = netconn_recv(conn, &buf);
|
||||
|
||||
if (err == ERR_OK) {
|
||||
snmp_receive(conn, buf->p, &buf->addr, buf->port);
|
||||
}
|
||||
|
||||
if (buf != NULL) {
|
||||
netbuf_delete(buf);
|
||||
}
|
||||
} while (1);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
u8_t
|
||||
snmp_get_local_ip_for_dst(void *handle, const ip_addr_t *dst, ip_addr_t *result)
|
||||
{
|
||||
struct netconn *conn = (struct netconn *)handle;
|
||||
struct netif *dst_if;
|
||||
const ip_addr_t *dst_ip;
|
||||
|
||||
LWIP_UNUSED_ARG(conn); /* unused in case of IPV4 only configuration */
|
||||
|
||||
ip_route_get_local_ip(&conn->pcb.udp->local_ip, dst, dst_if, dst_ip);
|
||||
|
||||
if ((dst_if != NULL) && (dst_ip != NULL)) {
|
||||
ip_addr_copy(*result, *dst_ip);
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts SNMP Agent.
|
||||
*/
|
||||
void
|
||||
snmp_init(void)
|
||||
{
|
||||
LWIP_ASSERT_CORE_LOCKED();
|
||||
sys_thread_new("snmp_netconn", snmp_netconn_thread, NULL, SNMP_STACK_SIZE, SNMP_THREAD_PRIO);
|
||||
}
|
||||
|
||||
#endif /* LWIP_SNMP && SNMP_USE_NETCONN */
|
||||
156
src/apps/snmp/snmp_pbuf_stream.c
Normal file
156
src/apps/snmp/snmp_pbuf_stream.c
Normal file
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
* @file
|
||||
* SNMP pbuf stream wrapper implementation (internal API, do not use in client code).
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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: Martin Hentschel <info@cl-soft.de>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lwip/apps/snmp_opts.h"
|
||||
|
||||
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "snmp_pbuf_stream.h"
|
||||
#include "lwip/def.h"
|
||||
#include <string.h>
|
||||
|
||||
err_t
|
||||
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;
|
||||
pbuf_stream->pbuf = p;
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
err_t
|
||||
snmp_pbuf_stream_read(struct snmp_pbuf_stream *pbuf_stream, u8_t *data)
|
||||
{
|
||||
if (pbuf_stream->length == 0) {
|
||||
return ERR_BUF;
|
||||
}
|
||||
|
||||
if (pbuf_copy_partial(pbuf_stream->pbuf, data, 1, pbuf_stream->offset) == 0) {
|
||||
return ERR_BUF;
|
||||
}
|
||||
|
||||
pbuf_stream->offset++;
|
||||
pbuf_stream->length--;
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
err_t
|
||||
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)
|
||||
{
|
||||
if (pbuf_stream->length < buf_len) {
|
||||
return ERR_BUF;
|
||||
}
|
||||
|
||||
if (pbuf_take_at(pbuf_stream->pbuf, buf, buf_len, pbuf_stream->offset) != ERR_OK) {
|
||||
return ERR_BUF;
|
||||
}
|
||||
|
||||
pbuf_stream->offset += buf_len;
|
||||
pbuf_stream->length -= buf_len;
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
err_t
|
||||
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)) {
|
||||
return ERR_ARG;
|
||||
}
|
||||
if ((len > pbuf_stream->length) || (len > target_pbuf_stream->length)) {
|
||||
return ERR_ARG;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
len = LWIP_MIN(pbuf_stream->length, target_pbuf_stream->length);
|
||||
}
|
||||
|
||||
while (len > 0) {
|
||||
u16_t chunk_len;
|
||||
err_t err;
|
||||
u16_t 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);
|
||||
if (err != ERR_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
pbuf_stream->offset += chunk_len;
|
||||
pbuf_stream->length -= chunk_len;
|
||||
len -= chunk_len;
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
err_t
|
||||
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 */
|
||||
return ERR_ARG;
|
||||
}
|
||||
|
||||
pbuf_stream->offset += (u16_t)offset;
|
||||
pbuf_stream->length -= (u16_t)offset;
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
err_t
|
||||
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);
|
||||
}
|
||||
|
||||
#endif /* LWIP_SNMP */
|
||||
72
src/apps/snmp/snmp_pbuf_stream.h
Normal file
72
src/apps/snmp/snmp_pbuf_stream.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* @file
|
||||
* SNMP pbuf stream wrapper (internal API, do not use in client code).
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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: Martin Hentschel <info@cl-soft.de>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LWIP_HDR_APPS_SNMP_PBUF_STREAM_H
|
||||
#define LWIP_HDR_APPS_SNMP_PBUF_STREAM_H
|
||||
|
||||
#include "lwip/apps/snmp_opts.h"
|
||||
|
||||
#if LWIP_SNMP
|
||||
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/pbuf.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LWIP_SNMP */
|
||||
|
||||
#endif /* LWIP_HDR_APPS_SNMP_PBUF_STREAM_H */
|
||||
103
src/apps/snmp/snmp_raw.c
Normal file
103
src/apps/snmp/snmp_raw.c
Normal file
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* @file
|
||||
* SNMP RAW API frontend.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Author: Dirk Ziegelmeier <dziegel@gmx.de>
|
||||
*/
|
||||
|
||||
#include "lwip/apps/snmp_opts.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
|
||||
#if LWIP_SNMP && SNMP_USE_RAW
|
||||
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/prot/iana.h"
|
||||
#include "snmp_msg.h"
|
||||
|
||||
/* lwIP UDP receive callback function */
|
||||
static void
|
||||
snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
|
||||
snmp_receive(pcb, p, addr, port);
|
||||
|
||||
pbuf_free(p);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
u8_t
|
||||
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 netif *dst_if;
|
||||
const ip_addr_t *dst_ip;
|
||||
|
||||
LWIP_UNUSED_ARG(udp_pcb); /* unused in case of IPV4 only configuration */
|
||||
|
||||
ip_route_get_local_ip(&udp_pcb->local_ip, dst, dst_if, dst_ip);
|
||||
|
||||
if ((dst_if != NULL) && (dst_ip != NULL)) {
|
||||
ip_addr_copy(*result, *dst_ip);
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup snmp_core
|
||||
* Starts SNMP Agent.
|
||||
* Allocates UDP pcb and binds it to IP_ANY_TYPE port 161.
|
||||
*/
|
||||
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, 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;);
|
||||
}
|
||||
|
||||
#endif /* LWIP_SNMP && SNMP_USE_RAW */
|
||||
232
src/apps/snmp/snmp_scalar.c
Normal file
232
src/apps/snmp/snmp_scalar.c
Normal file
@@ -0,0 +1,232 @@
|
||||
/**
|
||||
* @file
|
||||
* SNMP scalar node support implementation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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: Martin Hentschel <info@cl-soft.de>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lwip/apps/snmp_opts.h"
|
||||
|
||||
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#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);
|
||||
|
||||
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;
|
||||
|
||||
LWIP_UNUSED_ARG(root_oid);
|
||||
LWIP_UNUSED_ARG(root_oid_len);
|
||||
|
||||
/* scalar only has one dedicated instance: .0 */
|
||||
if ((instance->instance_oid.len != 1) || (instance->instance_oid.id[0] != 0)) {
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
instance->access = scalar_node->access;
|
||||
instance->asn1_type = scalar_node->asn1_type;
|
||||
instance->get_value = scalar_node->get_value;
|
||||
instance->set_test = scalar_node->set_test;
|
||||
instance->set_value = scalar_node->set_value;
|
||||
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)
|
||||
{
|
||||
/* 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) {
|
||||
instance->instance_oid.len = 1;
|
||||
instance->instance_oid.id[0] = 0;
|
||||
|
||||
return snmp_scalar_get_instance(root_oid, root_oid_len, instance);
|
||||
}
|
||||
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
|
||||
snmp_err_t
|
||||
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;
|
||||
u32_t i = 0;
|
||||
|
||||
while (i < array_node->array_node_count) {
|
||||
if (array_node_def->oid == instance->instance_oid.id[0]) {
|
||||
break;
|
||||
}
|
||||
|
||||
array_node_def++;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i < array_node->array_node_count) {
|
||||
instance->access = array_node_def->access;
|
||||
instance->asn1_type = array_node_def->asn1_type;
|
||||
instance->get_value = snmp_scalar_array_get_value;
|
||||
instance->set_test = snmp_scalar_array_set_test;
|
||||
instance->set_value = snmp_scalar_array_set_value;
|
||||
instance->reference.const_ptr = array_node_def;
|
||||
|
||||
return SNMP_ERR_NOERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
snmp_err_t
|
||||
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;
|
||||
|
||||
LWIP_UNUSED_ARG(root_oid);
|
||||
LWIP_UNUSED_ARG(root_oid_len);
|
||||
|
||||
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++;
|
||||
|
||||
for (i = 1; i < array_node->array_node_count; i++) {
|
||||
if (array_node_def->oid < result->oid) {
|
||||
result = array_node_def;
|
||||
}
|
||||
array_node_def++;
|
||||
}
|
||||
} 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 */
|
||||
u16_t i = 0;
|
||||
while (i < array_node->array_node_count) {
|
||||
if (array_node_def->oid == instance->instance_oid.id[0]) {
|
||||
result = array_node_def;
|
||||
break;
|
||||
}
|
||||
|
||||
array_node_def++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (result == NULL) {
|
||||
u32_t oid_dist = 0xFFFFFFFFUL;
|
||||
u16_t i = 0;
|
||||
array_node_def = array_node->array_nodes; /* may be already at the end when if case before was executed without result -> reinitialize to start */
|
||||
while (i < array_node->array_node_count) {
|
||||
if ((array_node_def->oid > instance->instance_oid.id[0]) &&
|
||||
((u32_t)(array_node_def->oid - instance->instance_oid.id[0]) < oid_dist)) {
|
||||
result = array_node_def;
|
||||
oid_dist = array_node_def->oid - instance->instance_oid.id[0];
|
||||
}
|
||||
|
||||
array_node_def++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result == NULL) {
|
||||
/* nothing to return */
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
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;
|
||||
instance->set_test = snmp_scalar_array_set_test;
|
||||
instance->set_value = snmp_scalar_array_set_value;
|
||||
instance->reference.const_ptr = result;
|
||||
|
||||
return SNMP_ERR_NOERROR;
|
||||
}
|
||||
|
||||
static s16_t
|
||||
snmp_scalar_array_get_value(struct snmp_node_instance *instance, void *value)
|
||||
{
|
||||
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;
|
||||
|
||||
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_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;
|
||||
|
||||
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_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;
|
||||
|
||||
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 */
|
||||
342
src/apps/snmp/snmp_table.c
Normal file
342
src/apps/snmp/snmp_table.c
Normal file
@@ -0,0 +1,342 @@
|
||||
/**
|
||||
* @file
|
||||
* SNMP table support implementation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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: Martin Hentschel <info@cl-soft.de>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lwip/apps/snmp_opts.h"
|
||||
|
||||
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/apps/snmp_core.h"
|
||||
#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 ret = SNMP_ERR_NOSUCHINSTANCE;
|
||||
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);
|
||||
|
||||
/* check min. length (fixed row entry definition, column, row instance oid with at least one entry */
|
||||
/* 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;
|
||||
u16_t i = table_node->column_count;
|
||||
while (i > 0) {
|
||||
if (col_def->index == instance->instance_oid.id[1]) {
|
||||
break;
|
||||
}
|
||||
|
||||
col_def++;
|
||||
i--;
|
||||
}
|
||||
|
||||
if (i > 0) {
|
||||
/* everything may be overwritten by get_cell_instance_method() in order to implement special handling for single columns/cells */
|
||||
instance->asn1_type = col_def->asn1_type;
|
||||
instance->access = col_def->access;
|
||||
instance->get_value = table_node->get_value;
|
||||
instance->set_test = table_node->set_test;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
LWIP_UNUSED_ARG(root_oid);
|
||||
LWIP_UNUSED_ARG(root_oid_len);
|
||||
|
||||
/* check that first part of id is 0 or 1, referencing fixed row entry */
|
||||
if ((instance->instance_oid.len > 0) && (instance->instance_oid.id[0] > 1)) {
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
if (instance->instance_oid.len > 1) {
|
||||
column = instance->instance_oid.id[1];
|
||||
}
|
||||
if (instance->instance_oid.len > 2) {
|
||||
snmp_oid_assign(&row_oid, &(instance->instance_oid.id[2]), instance->instance_oid.len - 2);
|
||||
} else {
|
||||
row_oid.len = 0;
|
||||
}
|
||||
|
||||
instance->get_value = table_node->get_value;
|
||||
instance->set_test = table_node->set_test;
|
||||
instance->set_value = table_node->set_value;
|
||||
|
||||
/* resolve column and value */
|
||||
do {
|
||||
u16_t i;
|
||||
const struct snmp_table_col_def *next_col_def = NULL;
|
||||
col_def = table_node->columns;
|
||||
|
||||
for (i = 0; i < table_node->column_count; i++) {
|
||||
if (col_def->index == column) {
|
||||
next_col_def = col_def;
|
||||
break;
|
||||
} else if ((col_def->index > column) && ((next_col_def == NULL) || (col_def->index < next_col_def->index))) {
|
||||
next_col_def = col_def;
|
||||
}
|
||||
col_def++;
|
||||
}
|
||||
|
||||
if (next_col_def == NULL) {
|
||||
/* no further column found */
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
instance->asn1_type = next_col_def->asn1_type;
|
||||
instance->access = next_col_def->access;
|
||||
|
||||
result = table_node->get_next_cell_instance(
|
||||
&next_col_def->index,
|
||||
&row_oid,
|
||||
instance);
|
||||
|
||||
if (result == SNMP_ERR_NOERROR) {
|
||||
col_def = next_col_def;
|
||||
break;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/* build resulting oid */
|
||||
instance->instance_oid.len = 2;
|
||||
instance->instance_oid.id[0] = 1;
|
||||
instance->instance_oid.id[1] = col_def->index;
|
||||
snmp_oid_append(&instance->instance_oid, row_oid.id, row_oid.len);
|
||||
|
||||
return SNMP_ERR_NOERROR;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
LWIP_UNUSED_ARG(root_oid);
|
||||
LWIP_UNUSED_ARG(root_oid_len);
|
||||
|
||||
/* check min. length (fixed row entry definition, column, row instance oid with at least one entry */
|
||||
/* 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);
|
||||
|
||||
if (ret == SNMP_ERR_NOERROR) {
|
||||
/* search column */
|
||||
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]) {
|
||||
break;
|
||||
}
|
||||
|
||||
col_def++;
|
||||
i--;
|
||||
}
|
||||
|
||||
if (i > 0) {
|
||||
instance->asn1_type = col_def->asn1_type;
|
||||
instance->access = SNMP_NODE_INSTANCE_READ_ONLY;
|
||||
instance->set_test = NULL;
|
||||
instance->set_value = NULL;
|
||||
|
||||
switch (col_def->data_type) {
|
||||
case SNMP_VARIANT_VALUE_TYPE_U32:
|
||||
instance->get_value = snmp_table_extract_value_from_u32ref;
|
||||
break;
|
||||
case SNMP_VARIANT_VALUE_TYPE_S32:
|
||||
instance->get_value = snmp_table_extract_value_from_s32ref;
|
||||
break;
|
||||
case SNMP_VARIANT_VALUE_TYPE_PTR: /* fall through */
|
||||
case SNMP_VARIANT_VALUE_TYPE_CONST_PTR:
|
||||
instance->get_value = snmp_table_extract_value_from_refconstptr;
|
||||
break;
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
LWIP_UNUSED_ARG(root_oid);
|
||||
LWIP_UNUSED_ARG(root_oid_len);
|
||||
|
||||
/* check that first part of id is 0 or 1, referencing fixed row entry */
|
||||
if ((instance->instance_oid.len > 0) && (instance->instance_oid.id[0] > 1)) {
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
if (instance->instance_oid.len > 1) {
|
||||
column = instance->instance_oid.id[1];
|
||||
}
|
||||
if (instance->instance_oid.len > 2) {
|
||||
snmp_oid_assign(&row_oid, &(instance->instance_oid.id[2]), instance->instance_oid.len - 2);
|
||||
} else {
|
||||
row_oid.len = 0;
|
||||
}
|
||||
|
||||
/* resolve column and value */
|
||||
do {
|
||||
u32_t i;
|
||||
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++) {
|
||||
if (col_def->index == column) {
|
||||
next_col_def = col_def;
|
||||
break;
|
||||
} else if ((col_def->index > column) && ((next_col_def == NULL) ||
|
||||
(col_def->index < next_col_def->index))) {
|
||||
next_col_def = col_def;
|
||||
}
|
||||
col_def++;
|
||||
}
|
||||
|
||||
if (next_col_def == NULL) {
|
||||
/* no further column found */
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
result = table_node->get_next_cell_instance_and_value(
|
||||
&next_col_def->index,
|
||||
&row_oid,
|
||||
&instance->reference,
|
||||
&instance->reference_len);
|
||||
|
||||
if (result == SNMP_ERR_NOERROR) {
|
||||
col_def = next_col_def;
|
||||
break;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
instance->asn1_type = col_def->asn1_type;
|
||||
instance->access = SNMP_NODE_INSTANCE_READ_ONLY;
|
||||
instance->set_test = NULL;
|
||||
instance->set_value = NULL;
|
||||
|
||||
switch (col_def->data_type) {
|
||||
case SNMP_VARIANT_VALUE_TYPE_U32:
|
||||
instance->get_value = snmp_table_extract_value_from_u32ref;
|
||||
break;
|
||||
case SNMP_VARIANT_VALUE_TYPE_S32:
|
||||
instance->get_value = snmp_table_extract_value_from_s32ref;
|
||||
break;
|
||||
case SNMP_VARIANT_VALUE_TYPE_PTR: /* fall through */
|
||||
case SNMP_VARIANT_VALUE_TYPE_CONST_PTR:
|
||||
instance->get_value = snmp_table_extract_value_from_refconstptr;
|
||||
break;
|
||||
default:
|
||||
LWIP_DEBUGF(SNMP_DEBUG, ("snmp_table_simple_get_instance(): unknown column data_type: %d\n", col_def->data_type));
|
||||
return SNMP_ERR_GENERROR;
|
||||
}
|
||||
|
||||
/* build resulting oid */
|
||||
instance->instance_oid.len = 2;
|
||||
instance->instance_oid.id[0] = 1;
|
||||
instance->instance_oid.id[1] = col_def->index;
|
||||
snmp_oid_append(&instance->instance_oid, row_oid.id, row_oid.len);
|
||||
|
||||
return SNMP_ERR_NOERROR;
|
||||
}
|
||||
|
||||
|
||||
s16_t
|
||||
snmp_table_extract_value_from_s32ref(struct snmp_node_instance *instance, void *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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
MEMCPY(value, instance->reference.const_ptr, instance->reference_len);
|
||||
return (u16_t)instance->reference_len;
|
||||
}
|
||||
|
||||
#endif /* LWIP_SNMP */
|
||||
231
src/apps/snmp/snmp_threadsync.c
Normal file
231
src/apps/snmp/snmp_threadsync.c
Normal file
@@ -0,0 +1,231 @@
|
||||
/**
|
||||
* @file
|
||||
* SNMP thread synchronization implementation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Author: Dirk Ziegelmeier <dziegel@gmx.de>
|
||||
*/
|
||||
|
||||
#include "lwip/apps/snmp_opts.h"
|
||||
|
||||
#if LWIP_SNMP && (NO_SYS == 0) /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/apps/snmp_threadsync.h"
|
||||
#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)
|
||||
{
|
||||
sys_mutex_lock(&call_data->threadsync_node->instance->sem_usage_mutex);
|
||||
call_data->threadsync_node->instance->sync_fn(fn, call_data);
|
||||
sys_sem_wait(&call_data->threadsync_node->instance->sem);
|
||||
sys_mutex_unlock(&call_data->threadsync_node->instance->sem_usage_mutex);
|
||||
}
|
||||
|
||||
static void
|
||||
threadsync_get_value_synced(void *ctx)
|
||||
{
|
||||
struct threadsync_data *call_data = (struct threadsync_data *)ctx;
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
return call_data->retval.s16;
|
||||
}
|
||||
|
||||
static void
|
||||
threadsync_set_test_synced(void *ctx)
|
||||
{
|
||||
struct threadsync_data *call_data = (struct threadsync_data *)ctx;
|
||||
|
||||
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)
|
||||
{
|
||||
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_test_synced);
|
||||
|
||||
return call_data->retval.err;
|
||||
}
|
||||
|
||||
static void
|
||||
threadsync_set_value_synced(void *ctx)
|
||||
{
|
||||
struct threadsync_data *call_data = (struct threadsync_data *)ctx;
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
static void
|
||||
threadsync_release_instance(struct snmp_node_instance *instance)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
sys_sem_signal(&call_data->threadsync_node->instance->sem);
|
||||
}
|
||||
|
||||
static void
|
||||
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;
|
||||
|
||||
call_data->retval.err = leaf->get_next_instance(call_data->arg1.root_oid, call_data->arg2.root_oid_len, &call_data->proxy_instance);
|
||||
|
||||
sys_sem_signal(&call_data->threadsync_node->instance->sem);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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) {
|
||||
LWIP_DEBUGF(SNMP_DEBUG, ("Sync node OID does not match target node OID"));
|
||||
return SNMP_ERR_NOSUCHINSTANCE;
|
||||
}
|
||||
|
||||
memset(&call_data->proxy_instance, 0, sizeof(call_data->proxy_instance));
|
||||
|
||||
instance->reference.ptr = call_data;
|
||||
snmp_oid_assign(&call_data->proxy_instance.instance_oid, instance->instance_oid.id, instance->instance_oid.len);
|
||||
|
||||
call_data->proxy_instance.node = &threadsync_node->target->node;
|
||||
call_data->threadsync_node = threadsync_node;
|
||||
|
||||
call_data->arg1.root_oid = root_oid;
|
||||
call_data->arg2.root_oid_len = root_oid_len;
|
||||
call_synced_function(call_data, fn);
|
||||
|
||||
if (call_data->retval.err == SNMP_ERR_NOERROR) {
|
||||
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;
|
||||
snmp_oid_assign(&instance->instance_oid, call_data->proxy_instance.instance_oid.id, call_data->proxy_instance.instance_oid.len);
|
||||
}
|
||||
|
||||
return call_data->retval.err;
|
||||
}
|
||||
|
||||
snmp_err_t
|
||||
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)
|
||||
{
|
||||
return do_sync(root_oid, root_oid_len, instance, get_next_instance_synced);
|
||||
}
|
||||
|
||||
/** Initializes thread synchronization instance */
|
||||
void snmp_threadsync_init(struct snmp_threadsync_instance *instance, snmp_threadsync_synchronizer_fn sync_fn)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
#endif /* LWIP_SNMP */
|
||||
458
src/apps/snmp/snmp_traps.c
Normal file
458
src/apps/snmp/snmp_traps.c
Normal file
@@ -0,0 +1,458 @@
|
||||
/**
|
||||
* @file
|
||||
* SNMPv1 traps implementation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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: Martin Hentschel
|
||||
* Christiaan Simons <christiaan.simons@axon.tv>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lwip/apps/snmp_opts.h"
|
||||
|
||||
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "lwip/snmp.h"
|
||||
#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 {
|
||||
/* source enterprise ID (sysObjectID) */
|
||||
const struct snmp_obj_id *enterprise;
|
||||
/* source IP address, raw network order format */
|
||||
ip_addr_t sip;
|
||||
/* generic trap code */
|
||||
u32_t gen_trap;
|
||||
/* specific trap code */
|
||||
u32_t spc_trap;
|
||||
/* timestamp */
|
||||
u32_t ts;
|
||||
/* snmp_version */
|
||||
u32_t snmp_version;
|
||||
|
||||
/* output trap lengths used in ASN encoding */
|
||||
/* encoding pdu length */
|
||||
u16_t pdulen;
|
||||
/* encoding community length */
|
||||
u16_t comlen;
|
||||
/* encoding sequence length */
|
||||
u16_t seqlen;
|
||||
/* encoding varbinds sequence length */
|
||||
u16_t vbseqlen;
|
||||
};
|
||||
|
||||
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 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;
|
||||
|
||||
struct snmp_trap_dst {
|
||||
/* destination IP address in network order */
|
||||
ip_addr_t dip;
|
||||
/* set to 0 when disabled, >0 when enabled */
|
||||
u8_t enable;
|
||||
};
|
||||
static struct snmp_trap_dst trap_dst[SNMP_TRAP_DESTINATIONS];
|
||||
|
||||
static u8_t snmp_auth_traps_enabled = 0;
|
||||
|
||||
/**
|
||||
* @ingroup snmp_traps
|
||||
* Sets enable switch for this trap destination.
|
||||
* @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1
|
||||
* @param enable switch if 0 destination is disabled >0 enabled.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup snmp_traps
|
||||
* Sets IPv4 address for this trap destination.
|
||||
* @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1
|
||||
* @param dst IPv4 address in host order.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup snmp_traps
|
||||
* Enable/disable authentication traps
|
||||
*/
|
||||
void
|
||||
snmp_set_auth_traps_enabled(u8_t enable)
|
||||
{
|
||||
snmp_auth_traps_enabled = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup snmp_traps
|
||||
* Get authentication traps enabled state
|
||||
*/
|
||||
u8_t
|
||||
snmp_get_auth_traps_enabled(void)
|
||||
{
|
||||
return snmp_auth_traps_enabled;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @ingroup snmp_traps
|
||||
* Sends a generic or enterprise specific trap message.
|
||||
*
|
||||
* @param eoid points to enterprise object identifier
|
||||
* @param generic_trap is the trap code
|
||||
* @param specific_trap used for enterprise traps when generic_trap == 6
|
||||
* @param varbinds linked list of varbinds to be sent
|
||||
* @return ERR_OK when success, ERR_MEM if we're out of memory
|
||||
*
|
||||
* @note the use of the enterprise identifier field
|
||||
* is per RFC1215.
|
||||
* Use .iso.org.dod.internet.mgmt.mib-2.snmp for generic traps
|
||||
* and .iso.org.dod.internet.private.enterprises.yourenterprise
|
||||
* (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)
|
||||
{
|
||||
struct snmp_msg_trap trap_msg;
|
||||
struct snmp_trap_dst *td;
|
||||
struct pbuf *p;
|
||||
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++) {
|
||||
if ((td->enable != 0) && !ip_addr_isany(&td->dip)) {
|
||||
/* lookup current source address for this dst */
|
||||
if (snmp_get_local_ip_for_dst(snmp_traps_handle, &td->dip, &trap_msg.sip)) {
|
||||
if (eoid == NULL) {
|
||||
trap_msg.enterprise = snmp_get_device_enterprise_oid();
|
||||
} else {
|
||||
trap_msg.enterprise = eoid;
|
||||
}
|
||||
|
||||
trap_msg.gen_trap = generic_trap;
|
||||
if (generic_trap == SNMP_GENTRAP_ENTERPRISE_SPECIFIC) {
|
||||
trap_msg.spc_trap = specific_trap;
|
||||
} else {
|
||||
trap_msg.spc_trap = 0;
|
||||
}
|
||||
|
||||
MIB2_COPY_SYSUPTIME_TO(&trap_msg.ts);
|
||||
|
||||
/* pass 0, calculate length fields */
|
||||
tot_len = snmp_trap_varbind_sum(&trap_msg, varbinds);
|
||||
tot_len = snmp_trap_header_sum(&trap_msg, tot_len);
|
||||
|
||||
/* allocate pbuf(s) */
|
||||
p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_RAM);
|
||||
if (p != NULL) {
|
||||
struct snmp_pbuf_stream pbuf_stream;
|
||||
snmp_pbuf_stream_init(&pbuf_stream, p, 0, tot_len);
|
||||
|
||||
/* 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);
|
||||
|
||||
snmp_stats.outtraps++;
|
||||
snmp_stats.outpkts++;
|
||||
|
||||
/** send to the TRAP destination */
|
||||
snmp_sendto(snmp_traps_handle, p, &td->dip, LWIP_IANA_PORT_SNMP_TRAP);
|
||||
pbuf_free(p);
|
||||
} else {
|
||||
err = ERR_MEM;
|
||||
}
|
||||
} else {
|
||||
/* routing error */
|
||||
err = ERR_RTE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup snmp_traps
|
||||
* Send generic SNMP trap
|
||||
*/
|
||||
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 } };
|
||||
return snmp_send_trap(&oid, generic_trap, 0, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup snmp_traps
|
||||
* Send specific SNMP trap with variable bindings
|
||||
*/
|
||||
err_t
|
||||
snmp_send_trap_specific(s32_t specific_trap, struct snmp_varbind *varbinds)
|
||||
{
|
||||
return snmp_send_trap(NULL, SNMP_GENTRAP_ENTERPRISE_SPECIFIC, specific_trap, varbinds);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup snmp_traps
|
||||
* Send coldstart trap
|
||||
*/
|
||||
void
|
||||
snmp_coldstart_trap(void)
|
||||
{
|
||||
snmp_send_trap_generic(SNMP_GENTRAP_COLDSTART);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup snmp_traps
|
||||
* Send authentication failure trap (used internally by agent)
|
||||
*/
|
||||
void
|
||||
snmp_authfail_trap(void)
|
||||
{
|
||||
if (snmp_auth_traps_enabled != 0) {
|
||||
snmp_send_trap_generic(SNMP_GENTRAP_AUTH_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
static u16_t
|
||||
snmp_trap_varbind_sum(struct snmp_msg_trap *trap, struct snmp_varbind *varbinds)
|
||||
{
|
||||
struct snmp_varbind *varbind;
|
||||
u16_t tot_len;
|
||||
u8_t tot_len_len;
|
||||
|
||||
tot_len = 0;
|
||||
varbind = varbinds;
|
||||
while (varbind != NULL) {
|
||||
struct snmp_varbind_len len;
|
||||
|
||||
if (snmp_varbind_length(varbind, &len) == ERR_OK) {
|
||||
tot_len += 1 + len.vb_len_len + len.vb_value_len;
|
||||
}
|
||||
|
||||
varbind = varbind->next;
|
||||
}
|
||||
|
||||
trap->vbseqlen = tot_len;
|
||||
snmp_asn1_enc_length_cnt(trap->vbseqlen, &tot_len_len);
|
||||
tot_len += 1 + tot_len_len;
|
||||
|
||||
return tot_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sums trap header field lengths from tail to head and
|
||||
* returns trap_header_lengths for second encoding pass.
|
||||
*
|
||||
* @param trap Trap message
|
||||
* @param vb_len varbind-list length
|
||||
* @return the required length for encoding the trap header
|
||||
*/
|
||||
static u16_t
|
||||
snmp_trap_header_sum(struct snmp_msg_trap *trap, u16_t vb_len)
|
||||
{
|
||||
u16_t tot_len;
|
||||
u16_t len;
|
||||
u8_t lenlen;
|
||||
|
||||
tot_len = vb_len;
|
||||
|
||||
snmp_asn1_enc_u32t_cnt(trap->ts, &len);
|
||||
snmp_asn1_enc_length_cnt(len, &lenlen);
|
||||
tot_len += 1 + len + lenlen;
|
||||
|
||||
snmp_asn1_enc_s32t_cnt(trap->spc_trap, &len);
|
||||
snmp_asn1_enc_length_cnt(len, &lenlen);
|
||||
tot_len += 1 + len + lenlen;
|
||||
|
||||
snmp_asn1_enc_s32t_cnt(trap->gen_trap, &len);
|
||||
snmp_asn1_enc_length_cnt(len, &lenlen);
|
||||
tot_len += 1 + len + lenlen;
|
||||
|
||||
if (IP_IS_V6_VAL(trap->sip)) {
|
||||
#if LWIP_IPV6
|
||||
len = sizeof(ip_2_ip6(&trap->sip)->addr);
|
||||
#endif
|
||||
} else {
|
||||
#if LWIP_IPV4
|
||||
len = sizeof(ip_2_ip4(&trap->sip)->addr);
|
||||
#endif
|
||||
}
|
||||
snmp_asn1_enc_length_cnt(len, &lenlen);
|
||||
tot_len += 1 + len + lenlen;
|
||||
|
||||
snmp_asn1_enc_oid_cnt(trap->enterprise->id, trap->enterprise->len, &len);
|
||||
snmp_asn1_enc_length_cnt(len, &lenlen);
|
||||
tot_len += 1 + len + lenlen;
|
||||
|
||||
trap->pdulen = tot_len;
|
||||
snmp_asn1_enc_length_cnt(trap->pdulen, &lenlen);
|
||||
tot_len += 1 + lenlen;
|
||||
|
||||
trap->comlen = (u16_t)LWIP_MIN(strlen(snmp_community_trap), 0xFFFF);
|
||||
snmp_asn1_enc_length_cnt(trap->comlen, &lenlen);
|
||||
tot_len += 1 + lenlen + trap->comlen;
|
||||
|
||||
snmp_asn1_enc_s32t_cnt(trap->snmp_version, &len);
|
||||
snmp_asn1_enc_length_cnt(len, &lenlen);
|
||||
tot_len += 1 + len + lenlen;
|
||||
|
||||
trap->seqlen = tot_len;
|
||||
snmp_asn1_enc_length_cnt(trap->seqlen, &lenlen);
|
||||
tot_len += 1 + lenlen;
|
||||
|
||||
return tot_len;
|
||||
}
|
||||
|
||||
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;
|
||||
struct snmp_varbind *varbind;
|
||||
|
||||
varbind = varbinds;
|
||||
|
||||
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 0, trap->vbseqlen);
|
||||
BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
|
||||
|
||||
while (varbind != NULL) {
|
||||
BUILD_EXEC( snmp_append_outbound_varbind(pbuf_stream, varbind) );
|
||||
|
||||
varbind = varbind->next;
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes trap header from head to tail.
|
||||
*/
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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));
|
||||
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));
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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 */
|
||||
136
src/apps/snmp/snmpv3.c
Normal file
136
src/apps/snmp/snmpv3.c
Normal file
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* @file
|
||||
* Additional SNMPv3 functionality RFC3414 and RFC3826.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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>
|
||||
*/
|
||||
|
||||
#include "snmpv3_priv.h"
|
||||
#include "lwip/apps/snmpv3.h"
|
||||
#include "lwip/sys.h"
|
||||
#include <string.h>
|
||||
|
||||
#if LWIP_SNMP && LWIP_SNMP_V3
|
||||
|
||||
#ifdef LWIP_SNMPV3_INCLUDE_ENGINE
|
||||
#include LWIP_SNMPV3_INCLUDE_ENGINE
|
||||
#endif
|
||||
|
||||
#define SNMP_MAX_TIME_BOOT 2147483647UL
|
||||
|
||||
/** Call this if engine has been changed. Has to reset boots, see below */
|
||||
void
|
||||
snmpv3_engine_id_changed(void)
|
||||
{
|
||||
snmpv3_set_engine_boots(0);
|
||||
}
|
||||
|
||||
/** According to RFC3414 2.2.2.
|
||||
*
|
||||
* The number of times that the SNMP engine has
|
||||
* (re-)initialized itself since snmpEngineID
|
||||
* was last configured.
|
||||
*/
|
||||
s32_t
|
||||
snmpv3_get_engine_boots_internal(void)
|
||||
{
|
||||
if (snmpv3_get_engine_boots() == 0 ||
|
||||
snmpv3_get_engine_boots() < SNMP_MAX_TIME_BOOT) {
|
||||
return snmpv3_get_engine_boots();
|
||||
}
|
||||
|
||||
snmpv3_set_engine_boots(SNMP_MAX_TIME_BOOT);
|
||||
return snmpv3_get_engine_boots();
|
||||
}
|
||||
|
||||
/** RFC3414 2.2.2.
|
||||
*
|
||||
* Once the timer reaches 2147483647 it gets reset to zero and the
|
||||
* engine boot ups get incremented.
|
||||
*/
|
||||
s32_t
|
||||
snmpv3_get_engine_time_internal(void)
|
||||
{
|
||||
if (snmpv3_get_engine_time() >= SNMP_MAX_TIME_BOOT) {
|
||||
snmpv3_reset_engine_time();
|
||||
|
||||
if (snmpv3_get_engine_boots() < SNMP_MAX_TIME_BOOT - 1) {
|
||||
snmpv3_set_engine_boots(snmpv3_get_engine_boots() + 1);
|
||||
} else {
|
||||
snmpv3_set_engine_boots(SNMP_MAX_TIME_BOOT);
|
||||
}
|
||||
}
|
||||
|
||||
return snmpv3_get_engine_time();
|
||||
}
|
||||
|
||||
#if LWIP_SNMP_V3_CRYPTO
|
||||
|
||||
/* This function ignores the byte order suggestion in RFC3414
|
||||
* since it simply doesn't influence the effectiveness of an IV.
|
||||
*
|
||||
* Implementing RFC3826 priv param algorithm if LWIP_RAND is available.
|
||||
*
|
||||
* @todo: This is a potential thread safety issue.
|
||||
*/
|
||||
err_t
|
||||
snmpv3_build_priv_param(u8_t *priv_param)
|
||||
{
|
||||
#ifdef LWIP_RAND /* Based on RFC3826 */
|
||||
static u8_t init;
|
||||
static u32_t priv1, priv2;
|
||||
|
||||
/* Lazy initialisation */
|
||||
if (init == 0) {
|
||||
init = 1;
|
||||
priv1 = LWIP_RAND();
|
||||
priv2 = LWIP_RAND();
|
||||
}
|
||||
|
||||
SMEMCPY(&priv_param[0], &priv1, sizeof(priv1));
|
||||
SMEMCPY(&priv_param[4], &priv2, sizeof(priv2));
|
||||
|
||||
/* Emulate 64bit increment */
|
||||
priv1++;
|
||||
if (!priv1) { /* Overflow */
|
||||
priv2++;
|
||||
}
|
||||
#else /* Based on RFC3414 */
|
||||
static u32_t ctr;
|
||||
u32_t boots = snmpv3_get_engine_boots_internal();
|
||||
SMEMCPY(&priv_param[0], &boots, 4);
|
||||
SMEMCPY(&priv_param[4], &ctr, 4);
|
||||
ctr++;
|
||||
#endif
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif /* LWIP_SNMP_V3_CRYPTO */
|
||||
|
||||
#endif
|
||||
342
src/apps/snmp/snmpv3_mbedtls.c
Normal file
342
src/apps/snmp/snmpv3_mbedtls.c
Normal file
@@ -0,0 +1,342 @@
|
||||
/**
|
||||
* @file
|
||||
* SNMPv3 crypto/auth functions implemented for ARM mbedtls.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2016 Elias Oenal and Dirk Ziegelmeier.
|
||||
* 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 "lwip/arch.h"
|
||||
#include "snmp_msg.h"
|
||||
#include "lwip/sys.h"
|
||||
#include <string.h>
|
||||
|
||||
#if LWIP_SNMP && LWIP_SNMP_V3 && LWIP_SNMP_V3_MBEDTLS
|
||||
|
||||
#include "mbedtls/md.h"
|
||||
#include "mbedtls/cipher.h"
|
||||
|
||||
#include "mbedtls/md5.h"
|
||||
#include "mbedtls/sha1.h"
|
||||
|
||||
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)
|
||||
{
|
||||
u32_t i;
|
||||
u8_t key_len;
|
||||
const mbedtls_md_info_t *md_info;
|
||||
mbedtls_md_context_t ctx;
|
||||
struct snmp_pbuf_stream read_stream;
|
||||
snmp_pbuf_stream_init(&read_stream, stream->pbuf, stream->offset, stream->length);
|
||||
|
||||
if (algo == SNMP_V3_AUTH_ALGO_MD5) {
|
||||
md_info = mbedtls_md_info_from_type(MBEDTLS_MD_MD5);
|
||||
key_len = SNMP_V3_MD5_LEN;
|
||||
} else if (algo == SNMP_V3_AUTH_ALGO_SHA) {
|
||||
md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
|
||||
key_len = SNMP_V3_SHA_LEN;
|
||||
} else {
|
||||
return ERR_ARG;
|
||||
}
|
||||
|
||||
mbedtls_md_init(&ctx);
|
||||
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;
|
||||
}
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
u8_t byte;
|
||||
|
||||
if (snmp_pbuf_stream_read(&read_stream, &byte)) {
|
||||
goto free_md;
|
||||
}
|
||||
|
||||
if (mbedtls_md_hmac_update(&ctx, &byte, 1) != 0) {
|
||||
goto free_md;
|
||||
}
|
||||
}
|
||||
|
||||
if (mbedtls_md_hmac_finish(&ctx, hmac_out) != 0) {
|
||||
goto free_md;
|
||||
}
|
||||
|
||||
mbedtls_md_free(&ctx);
|
||||
return ERR_OK;
|
||||
|
||||
free_md:
|
||||
mbedtls_md_free(&ctx);
|
||||
return ERR_ARG;
|
||||
}
|
||||
|
||||
#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, snmpv3_priv_algo_t algo, snmpv3_priv_mode_t mode)
|
||||
{
|
||||
size_t i;
|
||||
mbedtls_cipher_context_t ctx;
|
||||
const mbedtls_cipher_info_t *cipher_info;
|
||||
|
||||
struct snmp_pbuf_stream read_stream;
|
||||
struct snmp_pbuf_stream write_stream;
|
||||
snmp_pbuf_stream_init(&read_stream, stream->pbuf, stream->offset, stream->length);
|
||||
snmp_pbuf_stream_init(&write_stream, stream->pbuf, stream->offset, stream->length);
|
||||
mbedtls_cipher_init(&ctx);
|
||||
|
||||
if (algo == SNMP_V3_PRIV_ALGO_DES) {
|
||||
u8_t iv_local[8];
|
||||
u8_t out_bytes[8];
|
||||
size_t out_len;
|
||||
|
||||
/* RFC 3414 mandates padding for DES */
|
||||
if ((length & 0x07) != 0) {
|
||||
return ERR_ARG;
|
||||
}
|
||||
|
||||
cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_DES_CBC);
|
||||
if (mbedtls_cipher_setup(&ctx, cipher_info) != 0) {
|
||||
return ERR_ARG;
|
||||
}
|
||||
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) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i = 0; i < length; i += 8) {
|
||||
size_t j;
|
||||
u8_t in_bytes[8];
|
||||
out_len = LWIP_ARRAYSIZE(out_bytes) ;
|
||||
|
||||
for (j = 0; j < LWIP_ARRAYSIZE(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) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
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) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (snmp_pbuf_stream_writebuf(&write_stream, out_bytes, (u16_t)out_len) != ERR_OK) {
|
||||
goto error;
|
||||
}
|
||||
} 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) {
|
||||
return ERR_ARG;
|
||||
}
|
||||
if (mbedtls_cipher_setkey(&ctx, key, 16 * 8, (mode == SNMP_V3_PRIV_MODE_ENCRYPT) ? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT) != 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* IV is the big endian concatenation of boots,
|
||||
* uptime and priv param - see RFC3826.
|
||||
*/
|
||||
iv_local[0 + 0] = (engine_boots >> 24) & 0xFF;
|
||||
iv_local[0 + 1] = (engine_boots >> 16) & 0xFF;
|
||||
iv_local[0 + 2] = (engine_boots >> 8) & 0xFF;
|
||||
iv_local[0 + 3] = (engine_boots >> 0) & 0xFF;
|
||||
iv_local[4 + 0] = (engine_time >> 24) & 0xFF;
|
||||
iv_local[4 + 1] = (engine_time >> 16) & 0xFF;
|
||||
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) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
u8_t in_byte;
|
||||
u8_t out_byte;
|
||||
size_t out_len = sizeof(out_byte);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return ERR_ARG;
|
||||
}
|
||||
|
||||
mbedtls_cipher_free(&ctx);
|
||||
return ERR_OK;
|
||||
|
||||
error:
|
||||
mbedtls_cipher_free(&ctx);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
#endif /* LWIP_SNMP_V3_CRYPTO */
|
||||
|
||||
/* A.2.1. Password to Key Sample Code for MD5 */
|
||||
void
|
||||
snmpv3_password_to_key_md5(
|
||||
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];
|
||||
u32_t password_index = 0;
|
||||
u8_t i;
|
||||
u32_t count = 0;
|
||||
|
||||
mbedtls_md5_init(&MD); /* initialize MD5 */
|
||||
mbedtls_md5_starts(&MD);
|
||||
|
||||
/**********************************************/
|
||||
/* Use while loop until we've done 1 Megabyte */
|
||||
/**********************************************/
|
||||
while (count < 1048576) {
|
||||
cp = password_buf;
|
||||
for (i = 0; i < 64; i++) {
|
||||
/*************************************************/
|
||||
/* Take the next octet of the password, wrapping */
|
||||
/* to the beginning of the password as necessary.*/
|
||||
/*************************************************/
|
||||
*cp++ = password[password_index++ % passwordlen];
|
||||
}
|
||||
mbedtls_md5_update(&MD, password_buf, 64);
|
||||
count += 64;
|
||||
}
|
||||
mbedtls_md5_finish(&MD, key); /* tell MD5 we're done */
|
||||
|
||||
/*****************************************************/
|
||||
/* Now localize the key with the engineID and pass */
|
||||
/* through MD5 to produce final key */
|
||||
/* May want to ensure that engineLength <= 32, */
|
||||
/* otherwise need to use a buffer larger than 64 */
|
||||
/*****************************************************/
|
||||
SMEMCPY(password_buf, key, 16);
|
||||
MEMCPY(password_buf + 16, engineID, engineLength);
|
||||
SMEMCPY(password_buf + 16 + engineLength, key, 16);
|
||||
|
||||
mbedtls_md5_starts(&MD);
|
||||
mbedtls_md5_update(&MD, password_buf, 32 + engineLength);
|
||||
mbedtls_md5_finish(&MD, key);
|
||||
|
||||
mbedtls_md5_free(&MD);
|
||||
return;
|
||||
}
|
||||
|
||||
/* A.2.2. Password to Key Sample Code for SHA */
|
||||
void
|
||||
snmpv3_password_to_key_sha(
|
||||
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];
|
||||
u32_t password_index = 0;
|
||||
u8_t i;
|
||||
u32_t count = 0;
|
||||
|
||||
mbedtls_sha1_init(&SH); /* initialize SHA */
|
||||
mbedtls_sha1_starts(&SH);
|
||||
|
||||
/**********************************************/
|
||||
/* Use while loop until we've done 1 Megabyte */
|
||||
/**********************************************/
|
||||
while (count < 1048576) {
|
||||
cp = password_buf;
|
||||
for (i = 0; i < 64; i++) {
|
||||
/*************************************************/
|
||||
/* Take the next octet of the password, wrapping */
|
||||
/* to the beginning of the password as necessary.*/
|
||||
/*************************************************/
|
||||
*cp++ = password[password_index++ % passwordlen];
|
||||
}
|
||||
mbedtls_sha1_update(&SH, password_buf, 64);
|
||||
count += 64;
|
||||
}
|
||||
mbedtls_sha1_finish(&SH, key); /* tell SHA we're done */
|
||||
|
||||
/*****************************************************/
|
||||
/* Now localize the key with the engineID and pass */
|
||||
/* through SHA to produce final key */
|
||||
/* May want to ensure that engineLength <= 32, */
|
||||
/* otherwise need to use a buffer larger than 72 */
|
||||
/*****************************************************/
|
||||
SMEMCPY(password_buf, key, 20);
|
||||
MEMCPY(password_buf + 20, engineID, engineLength);
|
||||
SMEMCPY(password_buf + 20 + engineLength, key, 20);
|
||||
|
||||
mbedtls_sha1_starts(&SH);
|
||||
mbedtls_sha1_update(&SH, password_buf, 40 + engineLength);
|
||||
mbedtls_sha1_finish(&SH, key);
|
||||
|
||||
mbedtls_sha1_free(&SH);
|
||||
return;
|
||||
}
|
||||
|
||||
#endif /* LWIP_SNMP && LWIP_SNMP_V3 && LWIP_SNMP_V3_MBEDTLS */
|
||||
69
src/apps/snmp/snmpv3_priv.h
Normal file
69
src/apps/snmp/snmpv3_priv.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @file
|
||||
* Additional SNMPv3 functionality RFC3414 and RFC3826 (internal API, do not use in client code).
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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>
|
||||
*/
|
||||
|
||||
#ifndef LWIP_HDR_APPS_SNMP_V3_PRIV_H
|
||||
#define LWIP_HDR_APPS_SNMP_V3_PRIV_H
|
||||
|
||||
#include "lwip/apps/snmp_opts.h"
|
||||
|
||||
#if LWIP_SNMP && LWIP_SNMP_V3
|
||||
|
||||
#include "lwip/apps/snmpv3.h"
|
||||
#include "snmp_pbuf_stream.h"
|
||||
|
||||
/* According to RFC 3411 */
|
||||
#define SNMP_V3_MAX_ENGINE_ID_LENGTH 32
|
||||
#define SNMP_V3_MAX_USER_LENGTH 32
|
||||
|
||||
#define SNMP_V3_MAX_AUTH_PARAM_LENGTH 12
|
||||
#define SNMP_V3_MAX_PRIV_PARAM_LENGTH 8
|
||||
|
||||
#define SNMP_V3_MD5_LEN 16
|
||||
#define SNMP_V3_SHA_LEN 20
|
||||
|
||||
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
|
||||
|
||||
#endif /* LWIP_HDR_APPS_SNMP_V3_PRIV_H */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user